From 630fced69db6c40ced8ab6717517fcf9284d21bf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 00:12:15 +0200 Subject: [PATCH 0001/4212] begin experiement: move cdist-dir to core lib Signed-off-by: Nico Schottelius --- bin/cdist-dir => core/__cdist_dir | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename bin/cdist-dir => core/__cdist_dir (100%) diff --git a/bin/cdist-dir b/core/__cdist_dir similarity index 100% rename from bin/cdist-dir rename to core/__cdist_dir From abe6e695bc76cb4c10c0fb309082fc23884afe03 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 00:17:31 +0200 Subject: [PATCH 0002/4212] load __cdist_dir from core Signed-off-by: Nico Schottelius --- bin/cdist-config | 15 +++++++++++++++ core/__cdist_dir | 46 ++++++++++++++++++++++++---------------------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/bin/cdist-config b/bin/cdist-config index f7fb5ac0..de21d717 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -111,6 +111,7 @@ __cdist_tmp_file=$(mktemp "$__cdist_tmp_dir/cdist.XXXXXXXXXXXX") : ${__cdist_local_base_cache_dir:=$__cdist_abs_mydir/../$__cdist_name_cache} : ${__cdist_conf_dir:="$(cd "$__cdist_abs_mydir/../conf" && pwd -P)"} +: ${__cdist_core_dir:="$(cd "$__cdist_abs_mydir/../core" && pwd -P)"} : ${__cdist_explorer_dir:=$__cdist_conf_dir/$__cdist_name_explorer} : ${__cdist_manifest_dir:=$__cdist_conf_dir/$__cdist_name_manifest} @@ -149,6 +150,15 @@ __cdist_tmp_file=$(mktemp "$__cdist_tmp_dir/cdist.XXXXXXXXXXXX") ################################################################################ # Internal functions # + +# *NEW* Load functions from library +for __cdist_lib in $__cdist_core_dir/*; do + echo Loading $__cdist_lib ... + . "$__cdist_lib" +done + +exit 0 + __cdist_echo() { __cdist_echo_type="$1"; shift @@ -208,6 +218,11 @@ __cdist_usage() __cdist_exit_err "$__cdist_myname: $@" } +___cdist_lib_path() +{ + echo $_ +} + __cdist_init_deploy() { __cdist_echo info "Creating clean directory structure " diff --git a/core/__cdist_dir b/core/__cdist_dir index 0d30e14a..7799d03e 100755 --- a/core/__cdist_dir +++ b/core/__cdist_dir @@ -24,28 +24,30 @@ # -. cdist-config -[ $# -eq 4 ] || __cdist_usage " " -set -ue +__cdist_dir() +{ + [ $# -eq 4 ] || __cdist_usage " " + set -ue -__cdist_action="$1"; shift -__cdist_target_host="$1"; shift -__cdist_src_dir="$1"; shift -__cdist_dst_dir="$1"; shift + __cdist_action="$1"; shift + __cdist_target_host="$1"; shift + __cdist_src_dir="$1"; shift + __cdist_dst_dir="$1"; shift -# This will be the destination directory, so no subdirectories -# of the same name are created, if the directory is already existing -__cdist_top_dir="${__cdist_dst_dir%/*}" + # This will be the destination directory, so no subdirectories + # of the same name are created, if the directory is already existing + __cdist_top_dir="${__cdist_dst_dir%/*}" -if [ "$__cdist_action" = "push" ]; then - ssh "${__cdist_remote_user}@${__cdist_target_host}" \ - "mkdir -p \"${__cdist_dst_dir}\"" - scp -qr "$__cdist_src_dir" \ - "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_top_dir}" -elif [ "$__cdist_action" = "pull" ]; then - mkdir -p "${__cdist_dst_dir}" - scp -qr "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_src_dir}" \ - "${__cdist_top_dir}" -else - __cdist_exit_err "Unknown action $__cdist_action" -fi + if [ "$__cdist_action" = "push" ]; then + ssh "${__cdist_remote_user}@${__cdist_target_host}" \ + "mkdir -p \"${__cdist_dst_dir}\"" + scp -qr "$__cdist_src_dir" \ + "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_top_dir}" + elif [ "$__cdist_action" = "pull" ]; then + mkdir -p "${__cdist_dst_dir}" + scp -qr "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_src_dir}" \ + "${__cdist_top_dir}" + else + __cdist_exit_err "Unknown action $__cdist_action" + fi +} From e6d2a301c9bd35ae20725d721a3080e47ba8df79 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 00:19:57 +0200 Subject: [PATCH 0003/4212] replace usage of cdist-dir and use new syntax Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 3 +-- bin/cdist-explorer-run-global | 6 ++---- bin/cdist-object-explorer-run | 7 +++---- bin/cdist-object-push | 3 +-- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index bf5614bc..b28afbf2 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -48,8 +48,7 @@ __cdist_init_deploy "$__cdist_target_host" # Transfer cdist executables __cdist_echo info "Transferring cdist binaries to the target host " -cdist-dir push "$__cdist_target_host" \ - "${__cdist_abs_mydir}" "${__cdist_remote_bin_dir}" +__cdist_dir push "${__cdist_abs_mydir}" "${__cdist_remote_bin_dir}" cdist-explorer-run-global "$__cdist_target_host" cdist-manifest-run-init "$__cdist_target_host" cdist-object-all "$__cdist_target_host" cdist-object-prepare diff --git a/bin/cdist-explorer-run-global b/bin/cdist-explorer-run-global index b0c024f2..09b088f5 100755 --- a/bin/cdist-explorer-run-global +++ b/bin/cdist-explorer-run-global @@ -30,8 +30,7 @@ __cdist_target_host="$1"; shift __cdist_echo info "Running global explorers " # copy the explorers -cdist-dir push "$__cdist_target_host" \ - "${__cdist_explorer_dir}" "${__cdist_remote_explorer_dir}" +__cdist_dir push "${__cdist_explorer_dir}" "${__cdist_remote_explorer_dir}" # run the initial explorers remotely cdist-run-remote "${__cdist_target_host}" cdist-remote-explorer-run \ @@ -39,5 +38,4 @@ cdist-run-remote "${__cdist_target_host}" cdist-remote-explorer-run \ "$__cdist_remote_out_explorer_dir" # retrieve the results -cdist-dir pull "$__cdist_target_host" \ - "${__cdist_remote_out_explorer_dir}" "${__cdist_out_explorer_dir}" +__cdist_dir pull "${__cdist_remote_out_explorer_dir}" "${__cdist_out_explorer_dir}" diff --git a/bin/cdist-object-explorer-run b/bin/cdist-object-explorer-run index b65c5cc1..8bdf50ce 100755 --- a/bin/cdist-object-explorer-run +++ b/bin/cdist-object-explorer-run @@ -40,13 +40,13 @@ if [ "$__cdist_has_explorer" ]; then src_dir="$(__cdist_type_explorer_dir "$__cdist_type")" dst_dir="$(__cdist_remote_type_explorer_dir "$__cdist_type")" __cdist_echo info "Transfering explorers for $__cdist_type " - cdist-dir push "$__cdist_target_host" "$src_dir" "$dst_dir" + __cdist_dir push "$src_dir" "$dst_dir" __cdist_type_explorer_pushed_add "$__cdist_type" fi __cdist_echo info "Running explorers" # Copy object parameters - cdist-dir push "$__cdist_target_host" \ + __cdist_dir push \ "$(__cdist_object_parameter_dir "$__cdist_object_self")" \ "$(__cdist_remote_object_parameter_dir "$__cdist_object_self")" @@ -61,7 +61,6 @@ if [ "$__cdist_has_explorer" ]; then "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" # Copy back results - cdist-dir pull "$__cdist_target_host" \ - "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" \ + __cdist_dir pull "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" \ "$(__cdist_object_type_explorer_dir "$__cdist_object_self")" fi diff --git a/bin/cdist-object-push b/bin/cdist-object-push index 62b00cb2..8c2c935c 100755 --- a/bin/cdist-object-push +++ b/bin/cdist-object-push @@ -30,6 +30,5 @@ __cdist_target_host="$1"; shift __cdist_object_self="$1"; shift __cdist_echo info "Transferring object" -cdist-dir push "$__cdist_target_host" \ - "$(__cdist_object_dir "$__cdist_object_self")" \ +__cdist_dir push "$(__cdist_object_dir "$__cdist_object_self")" \ "$(__cdist_remote_object_dir "$__cdist_object_self")" From 7fbc4b8b77238fd17f46abc477f2ae6b25ea9b16 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 00:20:51 +0200 Subject: [PATCH 0004/4212] introduce first (and only?) global variable __cdist_target_host Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-06-14.library_for_user | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/dev/logs/2011-06-14.library_for_user b/doc/dev/logs/2011-06-14.library_for_user index 325150e2..5c0eb6f0 100644 --- a/doc/dev/logs/2011-06-14.library_for_user +++ b/doc/dev/logs/2011-06-14.library_for_user @@ -17,3 +17,6 @@ run_code_from_user() load_lib . file_from_user } + +Introduce global variables: + __cdist_target_host From 6a500d55702c7b462c272211742af1dfa6218b83 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 00:21:15 +0200 Subject: [PATCH 0005/4212] and run again Signed-off-by: Nico Schottelius --- bin/cdist-config | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/cdist-config b/bin/cdist-config index de21d717..13d2c0a4 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -157,8 +157,6 @@ for __cdist_lib in $__cdist_core_dir/*; do . "$__cdist_lib" done -exit 0 - __cdist_echo() { __cdist_echo_type="$1"; shift From cf88f9cacb51a89748d556994c441882978bd276 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 00:28:08 +0200 Subject: [PATCH 0006/4212] finished migration of cdist-dir to __cdist_dir Signed-off-by: Nico Schottelius --- bin/cdist-config | 4 +++- bin/cdist-deploy-to | 7 ++++++- core/__cdist_dir | 30 ++++++++++++++---------------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/bin/cdist-config b/bin/cdist-config index 13d2c0a4..942b4ea7 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -44,6 +44,7 @@ __cdist_abs_myname="$__cdist_abs_mydir/$__cdist_myname" : ${__cdist_name_cache:=cache} : ${__cdist_name_code:=code} : ${__cdist_name_conf_dir:=conf} +: ${__cdist_name_core_dir:=core} : ${__cdist_name_dot_cdist:=.cdist} : ${__cdist_name_explorer:=explorer} : ${__cdist_name_gencode:=gencode} @@ -111,7 +112,7 @@ __cdist_tmp_file=$(mktemp "$__cdist_tmp_dir/cdist.XXXXXXXXXXXX") : ${__cdist_local_base_cache_dir:=$__cdist_abs_mydir/../$__cdist_name_cache} : ${__cdist_conf_dir:="$(cd "$__cdist_abs_mydir/../conf" && pwd -P)"} -: ${__cdist_core_dir:="$(cd "$__cdist_abs_mydir/../core" && pwd -P)"} +: ${__cdist_core_dir:="$(cd "$__cdist_abs_mydir/../$__cdist_name_core_dir" && pwd -P)"} : ${__cdist_explorer_dir:=$__cdist_conf_dir/$__cdist_name_explorer} : ${__cdist_manifest_dir:=$__cdist_conf_dir/$__cdist_name_manifest} @@ -135,6 +136,7 @@ __cdist_tmp_file=$(mktemp "$__cdist_tmp_dir/cdist.XXXXXXXXXXXX") : ${__cdist_remote_base_dir:=/var/lib/cdist} : ${__cdist_remote_bin_dir:=$__cdist_remote_base_dir/$__cdist_name_bin} : ${__cdist_remote_conf_dir:=$__cdist_remote_base_dir/$__cdist_name_conf_dir} +: ${__cdist_remote_core_dir:=$__cdist_remote_base_dir/$__cdist_name_core_dir} : ${__cdist_remote_explorer_dir:=$__cdist_remote_conf_dir/$__cdist_name_explorer} : ${__cdist_remote_type_dir:=$__cdist_remote_conf_dir/$__cdist_name_type} diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index b28afbf2..d94cf460 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -37,6 +37,9 @@ export $__cdist_name_var_target_user="$__cdist_remote_user" # Export variables for core, which others do not reset export __cdist_local_base_dir +# Load library always from the checkout +export __cdist_core_dir + __cdist_echo info "cdist $__cdist_version: Configuring $__cdist_target_host " ################################################################################ @@ -47,8 +50,10 @@ __cdist_echo info "cdist $__cdist_version: Configuring $__cdist_target_host " __cdist_init_deploy "$__cdist_target_host" # Transfer cdist executables -__cdist_echo info "Transferring cdist binaries to the target host " +__cdist_echo info "Transferring cdist binaries/functions to the target host " __cdist_dir push "${__cdist_abs_mydir}" "${__cdist_remote_bin_dir}" +__cdist_dir push "${__cdist_core_dir}" "${__cdist_remote_core_dir}" + cdist-explorer-run-global "$__cdist_target_host" cdist-manifest-run-init "$__cdist_target_host" cdist-object-all "$__cdist_target_host" cdist-object-prepare diff --git a/core/__cdist_dir b/core/__cdist_dir index 7799d03e..2f08a95c 100755 --- a/core/__cdist_dir +++ b/core/__cdist_dir @@ -26,28 +26,26 @@ __cdist_dir() { - [ $# -eq 4 ] || __cdist_usage " " - set -ue + [ $# -eq 3 ] || __cdist_usage " " - __cdist_action="$1"; shift - __cdist_target_host="$1"; shift - __cdist_src_dir="$1"; shift - __cdist_dst_dir="$1"; shift + __cdist_dir_action="$1"; shift + __cdist_dir_src="$1"; shift + __cdist_dir_dst="$1"; shift # This will be the destination directory, so no subdirectories # of the same name are created, if the directory is already existing - __cdist_top_dir="${__cdist_dst_dir%/*}" + __cdist_dir_top="${__cdist_dir_dst%/*}" - if [ "$__cdist_action" = "push" ]; then + if [ "$__cdist_dir_action" = "push" ]; then ssh "${__cdist_remote_user}@${__cdist_target_host}" \ - "mkdir -p \"${__cdist_dst_dir}\"" - scp -qr "$__cdist_src_dir" \ - "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_top_dir}" - elif [ "$__cdist_action" = "pull" ]; then - mkdir -p "${__cdist_dst_dir}" - scp -qr "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_src_dir}" \ - "${__cdist_top_dir}" + "mkdir -p \"${__cdist_dir_dst}\"" + scp -qr "$__cdist_dir_src" \ + "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_dir_top}" + elif [ "$__cdist_dir_action" = "pull" ]; then + mkdir -p "${__cdist_dir_dst}" + scp -qr "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_dir_src}" \ + "${__cdist_dir_top}" else - __cdist_exit_err "Unknown action $__cdist_action" + __cdist_exit_err "Unknown action $__cdist_dir_action" fi } From 0603322bbd7f78de715f55337ca8a07e4e7451be Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 00:30:22 +0200 Subject: [PATCH 0007/4212] begin to make cdist-object-gencode-run a function Signed-off-by: Nico Schottelius --- bin/cdist-object-gencode-run => core/__cdist_object_gencode_run | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename bin/cdist-object-gencode-run => core/__cdist_object_gencode_run (100%) diff --git a/bin/cdist-object-gencode-run b/core/__cdist_object_gencode_run similarity index 100% rename from bin/cdist-object-gencode-run rename to core/__cdist_object_gencode_run From 152cc930e1ba3eab0b634beacdb37230cbd9124d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 00:41:52 +0200 Subject: [PATCH 0008/4212] also migrate cdist-object-gencode Signed-off-by: Nico Schottelius --- bin/cdist-config | 2 +- bin/cdist-object-gencode | 62 ------------------------------ bin/cdist-object-run | 2 +- core/__cdist_object_gencode | 67 +++++++++++++++++++++++++++++++++ core/__cdist_object_gencode_run | 20 +++++----- 5 files changed, 78 insertions(+), 75 deletions(-) delete mode 100755 bin/cdist-object-gencode create mode 100755 core/__cdist_object_gencode diff --git a/bin/cdist-config b/bin/cdist-config index 942b4ea7..b120392e 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -82,7 +82,7 @@ __cdist_abs_myname="$__cdist_abs_mydir/$__cdist_myname" ################################################################################ -# Exported variable names (usable for non core +# Exported variable names (usable for non core) # : ${__cdist_name_var_explorer:=__$__cdist_name_explorer} : ${__cdist_name_var_type_explorer:=__$__cdist_name_type_explorer} diff --git a/bin/cdist-object-gencode b/bin/cdist-object-gencode deleted file mode 100755 index e21568a3..00000000 --- a/bin/cdist-object-gencode +++ /dev/null @@ -1,62 +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 . -# -# -# Generate code from one object (object must be relative path!) -# WARNING: OUTPUT ON STDOUT, ERRORS NEED TO BE ON STDERR! -# - -. cdist-config -[ $# -eq 3 ] || __cdist_usage "" "" "" -set -eu - -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift -__cdist_gencode_type="$1"; shift - -__cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" -__cdist_type_gencode="$(__cdist_type_gencode "$__cdist_type" "$__cdist_gencode_type")" -__cdist_code_output="$(__cdist_object_code "$__cdist_object_self" "$__cdist_gencode_type")" - -# export variables for the gencode script -export __object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" -export __object="$(__cdist_object_dir "$__cdist_object_self")" -export __global="$__cdist_out_dir" - -if [ -x "$__cdist_type_gencode" ]; then - __cdist_exec_fail_on_error "$__cdist_type_gencode" > "$__cdist_tmp_file" -else - if [ -e "$__cdist_type_gencode" ]; then - __cdist_exit_err "$__cdist_type_gencode exists, but is not executable" - fi - - # Ensure it's empty, if there is no gencode - : > "$__cdist_tmp_file" -fi - -# Only create code, if gencode created output -if [ "$(wc -l < "$__cdist_tmp_file")" -gt 0 ]; then - cat - "$__cdist_tmp_file" << eof > "$__cdist_code_output" -# -# The following code was generated by $__cdist_type_gencode -# - -eof - chmod u+x "${__cdist_code_output}" -fi diff --git a/bin/cdist-object-run b/bin/cdist-object-run index 4f40e7c1..f96462d7 100755 --- a/bin/cdist-object-run +++ b/bin/cdist-object-run @@ -56,7 +56,7 @@ if [ ! -f "$__cdist_object_finished" ]; then done fi - cdist-object-gencode-run "$__cdist_target_host" "$__cdist_object_self" + __cdist_object_gencode_run "$__cdist_object_self" cdist-object-push "$__cdist_target_host" "$__cdist_object_self" cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" diff --git a/core/__cdist_object_gencode b/core/__cdist_object_gencode new file mode 100755 index 00000000..585c9d9d --- /dev/null +++ b/core/__cdist_object_gencode @@ -0,0 +1,67 @@ +#!/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 . +# +# +# Generate code from one object (object must be relative path!) +# WARNING: OUTPUT ON STDOUT, ERRORS NEED TO BE ON STDERR! +# + +# FIXME: check variable names: +# either prefix or use global or use functions directly +# functions looks good, they are cheap anyway! + +__cdist_object_gencode() +{ + __cdist_myname="foo" + [ $# -eq 2 ] || __cdist_usage "" "" + + __cdist_object_self="$1"; shift + __cdist_gencode_type="$1"; shift + + __cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" + __cdist_type_gencode="$(__cdist_type_gencode "$__cdist_type" "$__cdist_gencode_type")" + __cdist_code_output="$(__cdist_object_code "$__cdist_object_self" "$__cdist_gencode_type")" + + # export variables for the gencode script + export __object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" + export __object="$(__cdist_object_dir "$__cdist_object_self")" + export __global="$__cdist_out_dir" + + if [ -x "$__cdist_type_gencode" ]; then + __cdist_exec_fail_on_error "$__cdist_type_gencode" > "$__cdist_tmp_file" + else + if [ -e "$__cdist_type_gencode" ]; then + __cdist_exit_err "$__cdist_type_gencode exists, but is not executable" + fi + + # Ensure it's empty, if there is no gencode + : > "$__cdist_tmp_file" + fi + + # Only create code, if gencode created output + if [ "$(wc -l < "$__cdist_tmp_file")" -gt 0 ]; then + cat - "$__cdist_tmp_file" << eof > "$__cdist_code_output" +# +# The following code was generated by $__cdist_type_gencode +# + +eof + chmod u+x "${__cdist_code_output}" + fi +} diff --git a/core/__cdist_object_gencode_run b/core/__cdist_object_gencode_run index 254ac1e4..308f5f33 100755 --- a/core/__cdist_object_gencode_run +++ b/core/__cdist_object_gencode_run @@ -22,17 +22,15 @@ # For the given object create the code to be executed on the target. # -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu +__cdist_object_gencode_run() +{ + __cdist_object_gencode_run_object="$1"; shift -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift + __cdist_echo info "Generating local code " + __cdist_object_gencode "$__cdist_object_gencode_run_object" \ + "${__cdist_name_gencode_local}" -__cdist_echo info "Generating local code " -cdist-object-gencode "$__cdist_target_host" "$__cdist_object_self" \ - "${__cdist_name_gencode_local}" - -__cdist_echo info "Generating remote code " -cdist-object-gencode "$__cdist_target_host" "$__cdist_object_self" \ + __cdist_echo info "Generating remote code " + __cdist_object_gencode "$__cdist_object_gencode_run_object" \ "${__cdist_name_gencode_remote}" +} From 580b5da688cfcc21bc25ac3285552e8dae7b9a04 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 00:47:24 +0200 Subject: [PATCH 0009/4212] remove obsolete cdist-object-push Signed-off-by: Nico Schottelius --- bin/cdist-object-push | 34 ---------------------------------- bin/cdist-object-run | 3 ++- 2 files changed, 2 insertions(+), 35 deletions(-) delete mode 100755 bin/cdist-object-push diff --git a/bin/cdist-object-push b/bin/cdist-object-push deleted file mode 100755 index 8c2c935c..00000000 --- a/bin/cdist-object-push +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# 2010 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# Transfer the given object to the target host. -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu - -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift - -__cdist_echo info "Transferring object" -__cdist_dir push "$(__cdist_object_dir "$__cdist_object_self")" \ - "$(__cdist_remote_object_dir "$__cdist_object_self")" diff --git a/bin/cdist-object-run b/bin/cdist-object-run index f96462d7..012be584 100755 --- a/bin/cdist-object-run +++ b/bin/cdist-object-run @@ -57,7 +57,8 @@ if [ ! -f "$__cdist_object_finished" ]; then fi __cdist_object_gencode_run "$__cdist_object_self" - cdist-object-push "$__cdist_target_host" "$__cdist_object_self" + __cdist_dir push "$(__cdist_object_dir "$__cdist_object_self")" \ + "$(__cdist_remote_object_dir "$__cdist_object_self")" cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" # Mark this object as done From 9e246b18ed1e5d9270047ae6210200a1b8f8003b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 00:48:07 +0200 Subject: [PATCH 0010/4212] -debug message for library loading Signed-off-by: Nico Schottelius --- bin/cdist-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist-config b/bin/cdist-config index b120392e..fb5b4be9 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -155,7 +155,7 @@ __cdist_tmp_file=$(mktemp "$__cdist_tmp_dir/cdist.XXXXXXXXXXXX") # *NEW* Load functions from library for __cdist_lib in $__cdist_core_dir/*; do - echo Loading $__cdist_lib ... + # echo Loading $__cdist_lib ... . "$__cdist_lib" done From 27a810705e3863c18c355b1bbf76baed1a8814fe Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 00:54:52 +0200 Subject: [PATCH 0011/4212] cdist-object-code-run -> ../core/__cdist_object_code_run Signed-off-by: Nico Schottelius --- bin/cdist-object-run | 2 +- .../__cdist_object_code_run | 21 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) rename bin/cdist-object-code-run => core/__cdist_object_code_run (67%) diff --git a/bin/cdist-object-run b/bin/cdist-object-run index 012be584..737c962b 100755 --- a/bin/cdist-object-run +++ b/bin/cdist-object-run @@ -59,7 +59,7 @@ if [ ! -f "$__cdist_object_finished" ]; then __cdist_object_gencode_run "$__cdist_object_self" __cdist_dir push "$(__cdist_object_dir "$__cdist_object_self")" \ "$(__cdist_remote_object_dir "$__cdist_object_self")" - cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" + __cdist_object_code_run "$__cdist_object_self" # Mark this object as done touch "$__cdist_object_finished" diff --git a/bin/cdist-object-code-run b/core/__cdist_object_code_run similarity index 67% rename from bin/cdist-object-code-run rename to core/__cdist_object_code_run index fa63aaba..cecb6659 100755 --- a/bin/cdist-object-code-run +++ b/core/__cdist_object_code_run @@ -22,17 +22,16 @@ # Exec the code for the given object locally and remote # -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -e +__cdist_object_code_run() +{ -__cdist_target_host="$1"; shift -__cdist_object="$1"; shift + __cdist_object_code_run_object="$1"; shift -# Code local -export __cdist_out_object_dir="$__cdist_out_object_dir" -cdist-code-run "$__cdist_object" "${__cdist_name_gencode_local}" + # Code local + export __cdist_out_object_dir="$__cdist_out_object_dir" + cdist-code-run "$__cdist_object_code_run_object" "${__cdist_name_gencode_local}" -# Code remote -cdist-run-remote "$__cdist_target_host" \ - "cdist-code-run" "$__cdist_object" "${__cdist_name_gencode_remote}" + # Code remote + cdist-run-remote "$__cdist_target_host" \ + "cdist-code-run" "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}" +} From ef2336cb1e6c64ce641b1f8d5a5bbfc44b42e2a8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:00:55 +0200 Subject: [PATCH 0012/4212] cdist-object-run -> ../core/__cdist_object_run Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 2 +- bin/cdist-object-run | 66 ----------------------------------------- core/__cdist_object_run | 66 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 67 deletions(-) delete mode 100755 bin/cdist-object-run create mode 100755 core/__cdist_object_run diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index d94cf460..c512bd88 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -57,7 +57,7 @@ __cdist_dir push "${__cdist_core_dir}" "${__cdist_remote_core_dir}" cdist-explorer-run-global "$__cdist_target_host" cdist-manifest-run-init "$__cdist_target_host" cdist-object-all "$__cdist_target_host" cdist-object-prepare -cdist-object-all "$__cdist_target_host" cdist-object-run +cdist-object-all "$__cdist_target_host" __cdist_object_run cdist-cache "$__cdist_target_host" __cdist_echo info "cdist $__cdist_version: Successfully finished run" diff --git a/bin/cdist-object-run b/bin/cdist-object-run deleted file mode 100755 index 737c962b..00000000 --- a/bin/cdist-object-run +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/sh -# -# 2011 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# For the given object: -# - run type explorers -# - run type manifest -# - generate code -# - copy object to target -# - execute code on target -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu - -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift -__cdist_object_dir="$(__cdist_object_dir "$__cdist_object_self")" -[ -d "$__cdist_object_dir" ] || __cdist_exit_err "Object undefined" - -# Export to non-core for use in manifest and gencode scripts -export $__cdist_name_var_self=$__cdist_object_self - -__cdist_object_finished="$(__cdist_object_finished "$__cdist_object_self")" -if [ ! -f "$__cdist_object_finished" ]; then - # Resolve dependencies, if any - __cdist_object_require="$(__cdist_object_require "$__cdist_object_self")" - if [ -f "$__cdist_object_require" ]; then - # NEED TO CREATE ARRAY, SSH DESTROYS WHILE READ LOOP - while read __cdist_requirement; do - set -- "$@" "$__cdist_requirement" - done < "$__cdist_object_require" - - while [ $# -gt 0 ]; do - __cdist_requirement="$1"; shift - __cdist_echo info "Resolving requirement $__cdist_requirement" - cdist-object-run "$__cdist_target_host" "$__cdist_requirement" - done - fi - - __cdist_object_gencode_run "$__cdist_object_self" - __cdist_dir push "$(__cdist_object_dir "$__cdist_object_self")" \ - "$(__cdist_remote_object_dir "$__cdist_object_self")" - __cdist_object_code_run "$__cdist_object_self" - - # Mark this object as done - touch "$__cdist_object_finished" -fi diff --git a/core/__cdist_object_run b/core/__cdist_object_run new file mode 100755 index 00000000..5da7aa1e --- /dev/null +++ b/core/__cdist_object_run @@ -0,0 +1,66 @@ +#!/bin/sh +# +# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 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 . +# +# +# For the given object: +# - run type explorers +# - run type manifest +# - generate code +# - copy object to target +# - execute code on target +# + +__cdist_object_run() +{ + [ $# -eq 1 ] || __cdist_usage "" + + __cdist_object_self="$1"; shift + __cdist_object_dir="$(__cdist_object_dir "$__cdist_object_self")" + [ -d "$__cdist_object_dir" ] || __cdist_exit_err "Object undefined" + + # Export to non-core for use in manifest and gencode scripts + export $__cdist_name_var_self=$__cdist_object_self + + __cdist_object_finished="$(__cdist_object_finished "$__cdist_object_self")" + if [ ! -f "$__cdist_object_finished" ]; then + # Resolve dependencies, if any + __cdist_object_require="$(__cdist_object_require "$__cdist_object_self")" + if [ -f "$__cdist_object_require" ]; then + # NEED TO CREATE ARRAY, SSH DESTROYS WHILE READ LOOP + while read __cdist_requirement; do + set -- "$@" "$__cdist_requirement" + done < "$__cdist_object_require" + + while [ $# -gt 0 ]; do + __cdist_requirement="$1"; shift + __cdist_echo info "Resolving requirement $__cdist_requirement" + __cdist_object_run "$__cdist_target_host" "$__cdist_requirement" + done + fi + + __cdist_object_gencode_run "$__cdist_object_self" + __cdist_dir push "$(__cdist_object_dir "$__cdist_object_self")" \ + "$(__cdist_remote_object_dir "$__cdist_object_self")" + __cdist_object_code_run "$__cdist_object_self" + + # Mark this object as done + touch "$__cdist_object_finished" + fi +} From cc7da0c264786051611244f54d2813b0508bdaeb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:05:26 +0200 Subject: [PATCH 0013/4212] ../bin/cdist-object-all -> __cdist_object_all Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 4 +-- bin/cdist-object-all | 56 ----------------------------------------- core/__cdist_object_all | 56 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 58 deletions(-) delete mode 100755 bin/cdist-object-all create mode 100755 core/__cdist_object_all diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index c512bd88..3711fac5 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -56,8 +56,8 @@ __cdist_dir push "${__cdist_core_dir}" "${__cdist_remote_core_dir}" cdist-explorer-run-global "$__cdist_target_host" cdist-manifest-run-init "$__cdist_target_host" -cdist-object-all "$__cdist_target_host" cdist-object-prepare -cdist-object-all "$__cdist_target_host" __cdist_object_run +__cdist_object_all cdist-object-prepare +__cdist_object_all __cdist_object_run cdist-cache "$__cdist_target_host" __cdist_echo info "cdist $__cdist_version: Successfully finished run" diff --git a/bin/cdist-object-all b/bin/cdist-object-all deleted file mode 100755 index 391c9cc7..00000000 --- a/bin/cdist-object-all +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh -# -# 2011 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# Run the given command for each created object. -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu - -__cdist_target_host="$1"; shift -__cdist_command="$1"; shift - -__cdist_objects="$__cdist_tmp_dir/objects" - -# Ensure object dir exists, so marker can be created -mkdir -p "${__cdist_out_object_dir}" - -# Loop until we do not create new objects anymore -# which is equal to all objects have been run -touch "$__cdist_objects_created" -while [ -f "$__cdist_objects_created" ]; do - # Assume we're done after this run - rm "$__cdist_objects_created" - - # Get listing of objects - __cdist_object_list "$__cdist_out_object_dir" > "$__cdist_objects" - - # NEED TO CREATE ARRAY, SSH DESTROYS WHILE READ LOOP - while read __cdist_object; do - set -- "$@" "$__cdist_object" - done < "$__cdist_objects" - - while [ $# -gt 0 ]; do - __cdist_object="$1"; shift - $__cdist_command "$__cdist_target_host" "$__cdist_object" - done -done diff --git a/core/__cdist_object_all b/core/__cdist_object_all new file mode 100755 index 00000000..52661073 --- /dev/null +++ b/core/__cdist_object_all @@ -0,0 +1,56 @@ +#!/bin/sh +# +# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 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 . +# +# +# Run the given command for each created object. +# + +__cdist_object_all() +{ + [ $# -eq 1 ] || __cdist_usage "" + + __cdist_command="$1"; shift + + __cdist_objects="$__cdist_tmp_dir/objects" + + # Ensure object dir exists, so marker can be created + mkdir -p "${__cdist_out_object_dir}" + + # Loop until we do not create new objects anymore + # which is equal to all objects have been run + touch "$__cdist_objects_created" + while [ -f "$__cdist_objects_created" ]; do + # Assume we're done after this run + rm "$__cdist_objects_created" + + # Get listing of objects + __cdist_object_list "$__cdist_out_object_dir" > "$__cdist_objects" + + # NEED TO CREATE ARRAY, SSH DESTROYS WHILE READ LOOP + while read __cdist_object; do + set -- "$@" "$__cdist_object" + done < "$__cdist_objects" + + while [ $# -gt 0 ]; do + __cdist_object="$1"; shift + $__cdist_command "$__cdist_object" + done + done +} From 0e2c221b43d9c3bf8c56880d2a194f602289f53d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:07:56 +0200 Subject: [PATCH 0014/4212] ../bin/cdist-object-prepare -> __cdist_object_prepare Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 4 +-- .../__cdist_object_prepare | 36 ++++++++++--------- 2 files changed, 21 insertions(+), 19 deletions(-) rename bin/cdist-object-prepare => core/__cdist_object_prepare (50%) diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index 3711fac5..9d5573f3 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -56,8 +56,8 @@ __cdist_dir push "${__cdist_core_dir}" "${__cdist_remote_core_dir}" cdist-explorer-run-global "$__cdist_target_host" cdist-manifest-run-init "$__cdist_target_host" -__cdist_object_all cdist-object-prepare -__cdist_object_all __cdist_object_run +__cdist_object_all __cdist_object_prepare +__cdist_object_all __cdist_object_run cdist-cache "$__cdist_target_host" __cdist_echo info "cdist $__cdist_version: Successfully finished run" diff --git a/bin/cdist-object-prepare b/core/__cdist_object_prepare similarity index 50% rename from bin/cdist-object-prepare rename to core/__cdist_object_prepare index d21d8a63..edb38e12 100755 --- a/bin/cdist-object-prepare +++ b/core/__cdist_object_prepare @@ -24,24 +24,26 @@ # - run type manifest # -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu +__cdist_object_prepare() +{ + [ $# -eq 1 ] || __cdist_usage "" + set -eu -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift -__cdist_object_dir="$(__cdist_object_dir "$__cdist_object_self")" -[ -d "$__cdist_object_dir" ] || __cdist_exit_err "Object undefined" + __cdist_target_host="$1"; shift + __cdist_object_self="$1"; shift + __cdist_object_dir="$(__cdist_object_dir "$__cdist_object_self")" + [ -d "$__cdist_object_dir" ] || __cdist_exit_err "Object undefined" -# Export to non-core for use in manifest and gencode scripts -export $__cdist_name_var_self=$__cdist_object_self + # Export to non-core for use in manifest and gencode scripts + export $__cdist_name_var_self=$__cdist_object_self -__cdist_object_prepared="$(__cdist_object_prepared "$__cdist_object_self")" -if [ ! -f "$__cdist_object_prepared" ]; then - __cdist_echo info "Preparing object" - cdist-object-explorer-run "$__cdist_target_host" "$__cdist_object_self" - cdist-object-manifest-run "$__cdist_target_host" "$__cdist_object_self" + __cdist_object_prepared="$(__cdist_object_prepared "$__cdist_object_self")" + if [ ! -f "$__cdist_object_prepared" ]; then + __cdist_echo info "Preparing object" + cdist-object-explorer-run "$__cdist_target_host" "$__cdist_object_self" + cdist-object-manifest-run "$__cdist_target_host" "$__cdist_object_self" - # Mark this object as prepared - touch "$__cdist_object_prepared" -fi + # Mark this object as prepared + touch "$__cdist_object_prepared" + fi +} From 95ce60637ca36956d43f0719ba10b0d8de5a0148 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:08:52 +0200 Subject: [PATCH 0015/4212] enhance for use as function cdist-deploy-to localhost 1.38s user 1.28s system 69% cpu 3.842 total Signed-off-by: Nico Schottelius --- core/__cdist_object_prepare | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/__cdist_object_prepare b/core/__cdist_object_prepare index edb38e12..e2c682b1 100755 --- a/core/__cdist_object_prepare +++ b/core/__cdist_object_prepare @@ -27,9 +27,7 @@ __cdist_object_prepare() { [ $# -eq 1 ] || __cdist_usage "" - set -eu - __cdist_target_host="$1"; shift __cdist_object_self="$1"; shift __cdist_object_dir="$(__cdist_object_dir "$__cdist_object_self")" [ -d "$__cdist_object_dir" ] || __cdist_exit_err "Object undefined" From 5c378dcb1bdfef02ac4af3d53f16549a6c5d8805 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:11:12 +0200 Subject: [PATCH 0016/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index d626493d..c4da3df3 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -5,6 +5,8 @@ Feel free to pick one! CORE ---- +- Fix warnings / __cdist_usage in core/* + -> __cdist_usage prints $0! not function name! - Inconsistent error messages if object is not existing! -> always use "Object undefined" - Add echo function / beautify output From f7138c292130670f16255e0f5e450bcecb577b70 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:13:01 +0200 Subject: [PATCH 0017/4212] bin/cdist-object-explorer-run -> core/__cdist_object_explorer_run Signed-off-by: Nico Schottelius --- bin/cdist-object-explorer-run | 66 -------------------------------- core/__cdist_object_explorer_run | 65 +++++++++++++++++++++++++++++++ core/__cdist_object_prepare | 2 +- 3 files changed, 66 insertions(+), 67 deletions(-) delete mode 100755 bin/cdist-object-explorer-run create mode 100755 core/__cdist_object_explorer_run diff --git a/bin/cdist-object-explorer-run b/bin/cdist-object-explorer-run deleted file mode 100755 index 8bdf50ce..00000000 --- a/bin/cdist-object-explorer-run +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# Run the explorers for the given object on the target host. -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu - -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift - -__cdist_object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" -__cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" - -# Check if type of object has >= 1 explorer -__cdist_has_explorer="$(__cdist_type_has_explorer "$__cdist_type")" -# Run the type explorers for the current object if any -if [ "$__cdist_has_explorer" ]; then - if ! __cdist_type_explorer_pushed "$__cdist_type"; then - src_dir="$(__cdist_type_explorer_dir "$__cdist_type")" - dst_dir="$(__cdist_remote_type_explorer_dir "$__cdist_type")" - __cdist_echo info "Transfering explorers for $__cdist_type " - __cdist_dir push "$src_dir" "$dst_dir" - __cdist_type_explorer_pushed_add "$__cdist_type" - fi - - __cdist_echo info "Running explorers" - # Copy object parameters - __cdist_dir push \ - "$(__cdist_object_parameter_dir "$__cdist_object_self")" \ - "$(__cdist_remote_object_parameter_dir "$__cdist_object_self")" - - # Execute explorers - cdist-run-remote "$__cdist_target_host" \ - "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" \ - "$__cdist_name_var_object_id=\"$__cdist_object_id\"" \ - "$__cdist_name_var_self=\"$__cdist_object_self\"" \ - cdist-remote-explorer-run \ - "$__cdist_name_var_type_explorer" \ - "$(__cdist_remote_type_explorer_dir "$__cdist_type")" \ - "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" - - # Copy back results - __cdist_dir pull "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" \ - "$(__cdist_object_type_explorer_dir "$__cdist_object_self")" -fi diff --git a/core/__cdist_object_explorer_run b/core/__cdist_object_explorer_run new file mode 100755 index 00000000..f11c6786 --- /dev/null +++ b/core/__cdist_object_explorer_run @@ -0,0 +1,65 @@ +#!/bin/sh +# +# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 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 . +# +# +# Run the explorers for the given object on the target host. +# + +__cdist_object_explorer_run() +{ + __cdist_object_self="$1"; shift + + __cdist_object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" + __cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" + + # Check if type of object has >= 1 explorer + __cdist_has_explorer="$(__cdist_type_has_explorer "$__cdist_type")" + # Run the type explorers for the current object if any + if [ "$__cdist_has_explorer" ]; then + if ! __cdist_type_explorer_pushed "$__cdist_type"; then + # FIXME: variables! + src_dir="$(__cdist_type_explorer_dir "$__cdist_type")" + dst_dir="$(__cdist_remote_type_explorer_dir "$__cdist_type")" + __cdist_echo info "Transfering explorers for $__cdist_type " + __cdist_dir push "$src_dir" "$dst_dir" + __cdist_type_explorer_pushed_add "$__cdist_type" + fi + + __cdist_echo info "Running explorers" + # Copy object parameters + __cdist_dir push \ + "$(__cdist_object_parameter_dir "$__cdist_object_self")" \ + "$(__cdist_remote_object_parameter_dir "$__cdist_object_self")" + + # Execute explorers + cdist-run-remote "$__cdist_target_host" \ + "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" \ + "$__cdist_name_var_object_id=\"$__cdist_object_id\"" \ + "$__cdist_name_var_self=\"$__cdist_object_self\"" \ + cdist-remote-explorer-run \ + "$__cdist_name_var_type_explorer" \ + "$(__cdist_remote_type_explorer_dir "$__cdist_type")" \ + "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" + + # Copy back results + __cdist_dir pull "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" \ + "$(__cdist_object_type_explorer_dir "$__cdist_object_self")" + fi +} diff --git a/core/__cdist_object_prepare b/core/__cdist_object_prepare index e2c682b1..53616487 100755 --- a/core/__cdist_object_prepare +++ b/core/__cdist_object_prepare @@ -38,7 +38,7 @@ __cdist_object_prepare() __cdist_object_prepared="$(__cdist_object_prepared "$__cdist_object_self")" if [ ! -f "$__cdist_object_prepared" ]; then __cdist_echo info "Preparing object" - cdist-object-explorer-run "$__cdist_target_host" "$__cdist_object_self" + __cdist_object_explorer_run "$__cdist_object_self" cdist-object-manifest-run "$__cdist_target_host" "$__cdist_object_self" # Mark this object as prepared From 5dff2157e2a550165c2da438f26c61468bc48fca Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:15:50 +0200 Subject: [PATCH 0018/4212] bin/cdist-object-manifest-run -> core/__cdist_object_manifest_run Signed-off-by: Nico Schottelius --- bin/cdist-object-manifest-run | 58 ------------------------------- core/__cdist_object_manifest_run | 59 ++++++++++++++++++++++++++++++++ core/__cdist_object_prepare | 2 +- 3 files changed, 60 insertions(+), 59 deletions(-) delete mode 100755 bin/cdist-object-manifest-run create mode 100755 core/__cdist_object_manifest_run diff --git a/bin/cdist-object-manifest-run b/bin/cdist-object-manifest-run deleted file mode 100755 index 34d4f867..00000000 --- a/bin/cdist-object-manifest-run +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/sh -# -# 2010 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# Run the manifest for the given object. -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu - -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift - -# FIXME: rename to __cdist_object_dir (everywhere!) -__cdist_cur_object_dir="$(__cdist_object_dir "$__cdist_object_self")" -__cdist_object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" - -__cdist_echo info "Checking manifest " - -__cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" -__cdist_manifest="$(__cdist_type_manifest "$__cdist_type")" - -if [ -f "$__cdist_manifest" ]; then - if [ -x "$__cdist_manifest" ]; then - # Make __cdist_manifest available for cdist-type-emulator - export __cdist_manifest - - __cdist_echo info "Executing manifest " - export $__cdist_name_var_object="$__cdist_cur_object_dir" - export $__cdist_name_var_object_id="$__cdist_object_id" - export $__cdist_name_var_type="$(__cdist_type_dir "$__cdist_type")" - - cdist-manifest-run "$__cdist_target_host" "$__cdist_manifest" - - # Tell cdist-object-run-all that there may be new objects - touch "$__cdist_objects_created" - else - __cdist_exit_err "${__cdist_manifest} needs to be executable." - fi -fi diff --git a/core/__cdist_object_manifest_run b/core/__cdist_object_manifest_run new file mode 100755 index 00000000..630d5d8b --- /dev/null +++ b/core/__cdist_object_manifest_run @@ -0,0 +1,59 @@ +#!/bin/sh +# +# 2010 Nico Schottelius (nico-cdist at schottelius.org) +# 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 . +# +# +# Run the manifest for the given object. +# + + +__cdist_object_manifest_run() +{ + [ $# -eq 1 ] || __cdist_usage "" + + __cdist_object_self="$1"; shift + + # FIXME: rename to __cdist_object_dir (everywhere!) + __cdist_cur_object_dir="$(__cdist_object_dir "$__cdist_object_self")" + __cdist_object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" + + __cdist_echo info "Checking manifest " + + __cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" + __cdist_manifest="$(__cdist_type_manifest "$__cdist_type")" + + if [ -f "$__cdist_manifest" ]; then + if [ -x "$__cdist_manifest" ]; then + # Make __cdist_manifest available for cdist-type-emulator + export __cdist_manifest + + __cdist_echo info "Executing manifest " + export $__cdist_name_var_object="$__cdist_cur_object_dir" + export $__cdist_name_var_object_id="$__cdist_object_id" + export $__cdist_name_var_type="$(__cdist_type_dir "$__cdist_type")" + + cdist-manifest-run "$__cdist_target_host" "$__cdist_manifest" + + # Tell cdist-object-run-all that there may be new objects + touch "$__cdist_objects_created" + else + __cdist_exit_err "${__cdist_manifest} needs to be executable." + fi + fi +} diff --git a/core/__cdist_object_prepare b/core/__cdist_object_prepare index 53616487..24039be0 100755 --- a/core/__cdist_object_prepare +++ b/core/__cdist_object_prepare @@ -39,7 +39,7 @@ __cdist_object_prepare() if [ ! -f "$__cdist_object_prepared" ]; then __cdist_echo info "Preparing object" __cdist_object_explorer_run "$__cdist_object_self" - cdist-object-manifest-run "$__cdist_target_host" "$__cdist_object_self" + __cdist_object_manifest_run "$__cdist_object_self" # Mark this object as prepared touch "$__cdist_object_prepared" From 0167f4a9f3264e8f47321325ac63b1432d82ec63 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:18:55 +0200 Subject: [PATCH 0019/4212] ../core/__cdist_manifest_run Signed-off-by: Nico Schottelius --- bin/cdist-manifest-run | 56 ------------------------------ bin/cdist-manifest-run-init | 2 +- core/__cdist_manifest_run | 58 ++++++++++++++++++++++++++++++++ core/__cdist_object_manifest_run | 2 +- 4 files changed, 60 insertions(+), 58 deletions(-) delete mode 100755 bin/cdist-manifest-run create mode 100755 core/__cdist_manifest_run diff --git a/bin/cdist-manifest-run b/bin/cdist-manifest-run deleted file mode 100755 index d4ea18bb..00000000 --- a/bin/cdist-manifest-run +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh -# -# 2010 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's build a cconfig tree from a configuration -# And save it into the cache tree -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -u - -__cdist_target_host="$1"; shift -__cdist_manifest="$1"; shift - -################################################################################ -# Export information for cdist-type-emulator or manifest -# - -# Config dir should not get reset - FIXME: why did I do this? -export __cdist_conf_dir - -# Used to record the source in the object -export __cdist_manifest - -# Export information for manifests - __cdist_out_dir comes from cdist-config -export __global="$__cdist_out_dir" - -################################################################################ -# The actual run -# - -# Ensure binaries exist and are up-to-date -cdist-type-build-emulation "${__cdist_out_type_bin_dir}" \ - || __cdist_exit_err "Failed to build type emulation binaries" - -# prepend our path, so all cdist tools come before other tools -export PATH="${__cdist_out_type_bin_dir}:$PATH" - -__cdist_exec_fail_on_error "${__cdist_manifest}" diff --git a/bin/cdist-manifest-run-init b/bin/cdist-manifest-run-init index 28acc623..787d2315 100755 --- a/bin/cdist-manifest-run-init +++ b/bin/cdist-manifest-run-init @@ -31,4 +31,4 @@ __cdist_target_host="$1"; shift eval export $__cdist_name_var_manifest=\"\$__cdist_manifest_dir\" __cdist_echo info "Running initial manifest for $__cdist_target_host " -cdist-manifest-run "$__cdist_target_host" "$__cdist_manifest_init" +__cdist_manifest_run "$__cdist_manifest_init" diff --git a/core/__cdist_manifest_run b/core/__cdist_manifest_run new file mode 100755 index 00000000..f2283f85 --- /dev/null +++ b/core/__cdist_manifest_run @@ -0,0 +1,58 @@ +#!/bin/sh +# +# 2010 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's build a cconfig tree from a configuration +# And save it into the cache tree +# + +__cdist_manifest_run() +{ + + [ $# -eq 1 ] || __cdist_usage "" + set -u + + __cdist_manifest="$1"; shift + + ################################################################################ + # Export information for cdist-type-emulator or manifest + # + + # Config dir should not get reset - FIXME: why did I do this? + export __cdist_conf_dir + + # Used to record the source in the object + export __cdist_manifest + + # Export information for manifests - __cdist_out_dir comes from cdist-config + export __global="$__cdist_out_dir" + + ################################################################################ + # The actual run + # + + # Ensure binaries exist and are up-to-date + cdist-type-build-emulation "${__cdist_out_type_bin_dir}" \ + || __cdist_exit_err "Failed to build type emulation binaries" + + # prepend our path, so all cdist tools come before other tools + export PATH="${__cdist_out_type_bin_dir}:$PATH" + + __cdist_exec_fail_on_error "${__cdist_manifest}" +} diff --git a/core/__cdist_object_manifest_run b/core/__cdist_object_manifest_run index 630d5d8b..40413726 100755 --- a/core/__cdist_object_manifest_run +++ b/core/__cdist_object_manifest_run @@ -48,7 +48,7 @@ __cdist_object_manifest_run() export $__cdist_name_var_object_id="$__cdist_object_id" export $__cdist_name_var_type="$(__cdist_type_dir "$__cdist_type")" - cdist-manifest-run "$__cdist_target_host" "$__cdist_manifest" + __cdist_manifest_run "$__cdist_target_host" "$__cdist_manifest" # Tell cdist-object-run-all that there may be new objects touch "$__cdist_objects_created" From da9974b9ce921e37239f5d2d44ca427ddfdf1e69 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:19:58 +0200 Subject: [PATCH 0020/4212] -bug :-) Signed-off-by: Nico Schottelius --- core/__cdist_object_manifest_run | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/__cdist_object_manifest_run b/core/__cdist_object_manifest_run index 40413726..efc85539 100755 --- a/core/__cdist_object_manifest_run +++ b/core/__cdist_object_manifest_run @@ -48,7 +48,7 @@ __cdist_object_manifest_run() export $__cdist_name_var_object_id="$__cdist_object_id" export $__cdist_name_var_type="$(__cdist_type_dir "$__cdist_type")" - __cdist_manifest_run "$__cdist_target_host" "$__cdist_manifest" + __cdist_manifest_run "$__cdist_manifest" # Tell cdist-object-run-all that there may be new objects touch "$__cdist_objects_created" From 47c32d1b535db2e53acdfd985e630c01d28cb2c0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:22:51 +0200 Subject: [PATCH 0021/4212] ../core/__cdist_manifest_run_init Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 2 +- core/__cdist_manifest_run | 2 -- .../__cdist_manifest_run_init | 15 ++++++--------- 3 files changed, 7 insertions(+), 12 deletions(-) rename bin/cdist-manifest-run-init => core/__cdist_manifest_run_init (74%) diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index 9d5573f3..6b3f2ee1 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -55,7 +55,7 @@ __cdist_dir push "${__cdist_abs_mydir}" "${__cdist_remote_bin_dir}" __cdist_dir push "${__cdist_core_dir}" "${__cdist_remote_core_dir}" cdist-explorer-run-global "$__cdist_target_host" -cdist-manifest-run-init "$__cdist_target_host" +__cdist_manifest_run_init "$__cdist_target_host" __cdist_object_all __cdist_object_prepare __cdist_object_all __cdist_object_run cdist-cache "$__cdist_target_host" diff --git a/core/__cdist_manifest_run b/core/__cdist_manifest_run index f2283f85..0ba5f515 100755 --- a/core/__cdist_manifest_run +++ b/core/__cdist_manifest_run @@ -24,9 +24,7 @@ __cdist_manifest_run() { - [ $# -eq 1 ] || __cdist_usage "" - set -u __cdist_manifest="$1"; shift diff --git a/bin/cdist-manifest-run-init b/core/__cdist_manifest_run_init similarity index 74% rename from bin/cdist-manifest-run-init rename to core/__cdist_manifest_run_init index 787d2315..2d694900 100755 --- a/bin/cdist-manifest-run-init +++ b/core/__cdist_manifest_run_init @@ -22,13 +22,10 @@ # And save it into the cache tree # -. cdist-config -[ $# -eq 1 ] || __cdist_usage "" -set -e +__cdist_manifest_run_init() +{ + eval export $__cdist_name_var_manifest=\"\$__cdist_manifest_dir\" -__cdist_target_host="$1"; shift - -eval export $__cdist_name_var_manifest=\"\$__cdist_manifest_dir\" - -__cdist_echo info "Running initial manifest for $__cdist_target_host " -__cdist_manifest_run "$__cdist_manifest_init" + __cdist_echo info "Running initial manifest for $__cdist_target_host " + __cdist_manifest_run "$__cdist_manifest_init" +} From 9a86b392dca714e31497f9f39db9b54789dc49a3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:27:53 +0200 Subject: [PATCH 0022/4212] ../core/__cdist_code_run and ../core/__cdist_type_build_emulation Signed-off-by: Nico Schottelius --- bin/cdist-code-run => core/__cdist_code_run | 40 ++++++++++--------- core/__cdist_manifest_run | 3 +- core/__cdist_object_code_run | 2 +- .../__cdist_type_build_emulation | 34 ++++++++-------- 4 files changed, 41 insertions(+), 38 deletions(-) rename bin/cdist-code-run => core/__cdist_code_run (50%) rename bin/cdist-type-build-emulation => core/__cdist_type_build_emulation (57%) diff --git a/bin/cdist-code-run b/core/__cdist_code_run similarity index 50% rename from bin/cdist-code-run rename to core/__cdist_code_run index 3d7499bf..6a1b916b 100755 --- a/bin/cdist-code-run +++ b/core/__cdist_code_run @@ -21,30 +21,32 @@ # This binary is executed on the remote side to execute code # -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -ue +__cdist_code_run() +{ -__cdist_object_self="$1"; shift -__cdist_code_type="$1"; shift + [ $# -eq 2 ] || __cdist_usage " " -if [ ! -d "$(__cdist_object_dir "$__cdist_object_self")" ]; then - __cdist_exit_err "Object undefined" -fi + __cdist_object_self="$1"; shift + __cdist_code_type="$1"; shift -__cdist_code="$(__cdist_object_code "$__cdist_object_self" "${__cdist_code_type}")" + if [ ! -d "$(__cdist_object_dir "$__cdist_object_self")" ]; then + __cdist_exit_err "Object undefined" + fi -__cdist_echo info "Checking code-${__cdist_code_type}" + __cdist_code="$(__cdist_object_code "$__cdist_object_self" "${__cdist_code_type}")" -if [ -e "$__cdist_code" ]; then - if [ -f "$__cdist_code" ]; then - if [ -x "$__cdist_code" ]; then - __cdist_echo info "Executing code-${__cdist_code_type}" - __cdist_exec_fail_on_error "$__cdist_code" + __cdist_echo info "Checking code-${__cdist_code_type}" + + if [ -e "$__cdist_code" ]; then + if [ -f "$__cdist_code" ]; then + if [ -x "$__cdist_code" ]; then + __cdist_echo info "Executing code-${__cdist_code_type}" + __cdist_exec_fail_on_error "$__cdist_code" + else + __cdist_exit_err "$__cdist_code exists, but is not executable." + fi else - __cdist_exit_err "$__cdist_code exists, but is not executable." + __cdist_exit_err "$__cdist_code exists, but is not a file." fi - else - __cdist_exit_err "$__cdist_code exists, but is not a file." fi -fi +} diff --git a/core/__cdist_manifest_run b/core/__cdist_manifest_run index 0ba5f515..76d0a934 100755 --- a/core/__cdist_manifest_run +++ b/core/__cdist_manifest_run @@ -46,7 +46,8 @@ __cdist_manifest_run() # # Ensure binaries exist and are up-to-date - cdist-type-build-emulation "${__cdist_out_type_bin_dir}" \ + # FIXME: do only once! no need to check for every manifest! + __cdist_type_build_emulation "${__cdist_out_type_bin_dir}" \ || __cdist_exit_err "Failed to build type emulation binaries" # prepend our path, so all cdist tools come before other tools diff --git a/core/__cdist_object_code_run b/core/__cdist_object_code_run index cecb6659..d25d1dca 100755 --- a/core/__cdist_object_code_run +++ b/core/__cdist_object_code_run @@ -29,7 +29,7 @@ __cdist_object_code_run() # Code local export __cdist_out_object_dir="$__cdist_out_object_dir" - cdist-code-run "$__cdist_object_code_run_object" "${__cdist_name_gencode_local}" + __cdist_code_run "$__cdist_object_code_run_object" "${__cdist_name_gencode_local}" # Code remote cdist-run-remote "$__cdist_target_host" \ diff --git a/bin/cdist-type-build-emulation b/core/__cdist_type_build_emulation similarity index 57% rename from bin/cdist-type-build-emulation rename to core/__cdist_type_build_emulation index 51c2f5b4..a6cfcaa6 100755 --- a/bin/cdist-type-build-emulation +++ b/core/__cdist_type_build_emulation @@ -20,24 +20,24 @@ # Build pseudo binaries for type emulation # -. cdist-config -[ $# -eq 1 ] || __cdist_usage "" -set -eu +__cdist_type_build_emulation() +{ + [ $# -eq 1 ] || __cdist_usage "" -__cdist_output_dir="$1"; shift + __cdist_output_dir="$1"; shift + __cdist_type_emulator="$__cdist_abs_mydir/cdist-type-emulator" -__cdist_type_emulator="$__cdist_abs_mydir/cdist-type-emulator" + if [ ! -d "${__cdist_type_dir}" ]; then + __cdist_exit_err "$__cdist_type_dir must exist and contain available types" + fi -if [ ! -d "${__cdist_type_dir}" ]; then - __cdist_exit_err "$__cdist_type_dir must exist and contain available types" -fi + # Get Types + cd "${__cdist_type_dir}" + ls -1 > "${__cdist_tmp_file}" -# Get Types -cd "${__cdist_type_dir}" -ls -1 > "${__cdist_tmp_file}" - -# Create binaries -mkdir -p "${__cdist_output_dir}" -while read type; do - ln -sf "${__cdist_type_emulator}" "${__cdist_output_dir}/${type}" -done < "${__cdist_tmp_file}" + # Create binaries + mkdir -p "${__cdist_output_dir}" + while read type; do + ln -sf "${__cdist_type_emulator}" "${__cdist_output_dir}/${type}" + done < "${__cdist_tmp_file}" +} From 1565c73559e834cfa031db24e98050de0150079b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:36:13 +0200 Subject: [PATCH 0023/4212] no target host needed anymore Signed-off-by: Nico Schottelius --- core/__cdist_object_run | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/__cdist_object_run b/core/__cdist_object_run index 5da7aa1e..07461b23 100755 --- a/core/__cdist_object_run +++ b/core/__cdist_object_run @@ -51,7 +51,7 @@ __cdist_object_run() while [ $# -gt 0 ]; do __cdist_requirement="$1"; shift __cdist_echo info "Resolving requirement $__cdist_requirement" - __cdist_object_run "$__cdist_target_host" "$__cdist_requirement" + __cdist_object_run "$__cdist_requirement" done fi From 2f5b416a33d5a9bb959e58c7380f65c07c8dce0a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:37:52 +0200 Subject: [PATCH 0024/4212] +marker Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 5ba529ad..ce89c643 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1 +1,5 @@ +- run-remote does not work anymore, because there is no binary :-) + either make functions available on the other side or + put logic on the server side. + Catch broken instances in cdist-mass-deploy -p and report broken deployements at the end! From 188afa2777615335c42e1a2498ef8779cd8f4ab6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:44:40 +0200 Subject: [PATCH 0025/4212] add wrapper script to execute functions remotely Signed-off-by: Nico Schottelius --- bin/cdist-remote | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100755 bin/cdist-remote diff --git a/bin/cdist-remote b/bin/cdist-remote new file mode 100755 index 00000000..d95913ba --- /dev/null +++ b/bin/cdist-remote @@ -0,0 +1,68 @@ +#!/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 . +# +# +# This binary is executed on the remote side to execute explorers +# +# It supports different variables names to be used, so __explorers +# and __type_explorers can be submitted :-) +# + +. cdist-config +[ $# -eq 3 ] || __cdist_usage " " +set -ue + +# Variable that defines the home of the explorers +__cdist_variable_name="$1"; shift + +# Find explorers here +__cdist_explorer_dir="$1"; shift + +# Write output here +__cdist_my_out_dir="$1"; shift + +# Setup environment +export $__cdist_variable_name="$__cdist_explorer_dir" +export __global="$__cdist_remote_out_dir" + +mkdir -p "$__cdist_my_out_dir" + +# Ensure there is at least one explorer +num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" +if [ "$num" -lt 1 ]; then + __cdist_exit_err "${__cdist_explorer_dir}: Contains no explorers" +fi + +# Execute all explorers +for explorer in "$__cdist_explorer_dir/"*; do + explorer_name="${explorer##*/}" + + if [ -f "$explorer" ]; then + if [ ! -x "$explorer" ]; then + __cdist_exit_err "Explorer \"$explorer\" exists, but is not executable." + fi + + # Execute explorers and save results in remote destination directory + "$explorer" > "${__cdist_my_out_dir}/$explorer_name" + else + if [ -e "$explorer" ]; then + __cdist_exit_err "Explorer \"$explorer\" exists, but is not a file." + fi + fi +done From 9e94bb56a2f333fdda4239a73d46e92b26113fcf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:47:26 +0200 Subject: [PATCH 0026/4212] core/__cdist_run_remote Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 4 +- bin/cdist-explorer-run-global | 3 +- bin/cdist-remote | 46 +------------------ core/__cdist_object_code_run | 4 +- core/__cdist_object_explorer_run | 2 +- .../__cdist_run_remote | 18 ++++---- 6 files changed, 18 insertions(+), 59 deletions(-) rename bin/cdist-run-remote => core/__cdist_run_remote (70%) diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index 6b3f2ee1..baeff220 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -55,9 +55,9 @@ __cdist_dir push "${__cdist_abs_mydir}" "${__cdist_remote_bin_dir}" __cdist_dir push "${__cdist_core_dir}" "${__cdist_remote_core_dir}" cdist-explorer-run-global "$__cdist_target_host" -__cdist_manifest_run_init "$__cdist_target_host" +__cdist_manifest_run_init __cdist_object_all __cdist_object_prepare __cdist_object_all __cdist_object_run -cdist-cache "$__cdist_target_host" +__cdist_cache __cdist_echo info "cdist $__cdist_version: Successfully finished run" diff --git a/bin/cdist-explorer-run-global b/bin/cdist-explorer-run-global index 09b088f5..51052627 100755 --- a/bin/cdist-explorer-run-global +++ b/bin/cdist-explorer-run-global @@ -33,9 +33,10 @@ __cdist_echo info "Running global explorers " __cdist_dir push "${__cdist_explorer_dir}" "${__cdist_remote_explorer_dir}" # run the initial explorers remotely -cdist-run-remote "${__cdist_target_host}" cdist-remote-explorer-run \ +__cdist_run_remote "${__cdist_target_host}" cdist-remote-explorer-run \ "$__cdist_name_var_explorer" "$__cdist_remote_explorer_dir" \ "$__cdist_remote_out_explorer_dir" + # retrieve the results __cdist_dir pull "${__cdist_remote_out_explorer_dir}" "${__cdist_out_explorer_dir}" diff --git a/bin/cdist-remote b/bin/cdist-remote index d95913ba..0a730a6e 100755 --- a/bin/cdist-remote +++ b/bin/cdist-remote @@ -18,51 +18,9 @@ # along with cdist. If not, see . # # -# This binary is executed on the remote side to execute explorers -# -# It supports different variables names to be used, so __explorers -# and __type_explorers can be submitted :-) +# This scripts runs functions or binaries remotely # . cdist-config -[ $# -eq 3 ] || __cdist_usage " " -set -ue -# Variable that defines the home of the explorers -__cdist_variable_name="$1"; shift - -# Find explorers here -__cdist_explorer_dir="$1"; shift - -# Write output here -__cdist_my_out_dir="$1"; shift - -# Setup environment -export $__cdist_variable_name="$__cdist_explorer_dir" -export __global="$__cdist_remote_out_dir" - -mkdir -p "$__cdist_my_out_dir" - -# Ensure there is at least one explorer -num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" -if [ "$num" -lt 1 ]; then - __cdist_exit_err "${__cdist_explorer_dir}: Contains no explorers" -fi - -# Execute all explorers -for explorer in "$__cdist_explorer_dir/"*; do - explorer_name="${explorer##*/}" - - if [ -f "$explorer" ]; then - if [ ! -x "$explorer" ]; then - __cdist_exit_err "Explorer \"$explorer\" exists, but is not executable." - fi - - # Execute explorers and save results in remote destination directory - "$explorer" > "${__cdist_my_out_dir}/$explorer_name" - else - if [ -e "$explorer" ]; then - __cdist_exit_err "Explorer \"$explorer\" exists, but is not a file." - fi - fi -done +"$@" diff --git a/core/__cdist_object_code_run b/core/__cdist_object_code_run index d25d1dca..c07505fe 100755 --- a/core/__cdist_object_code_run +++ b/core/__cdist_object_code_run @@ -32,6 +32,6 @@ __cdist_object_code_run() __cdist_code_run "$__cdist_object_code_run_object" "${__cdist_name_gencode_local}" # Code remote - cdist-run-remote "$__cdist_target_host" \ - "cdist-code-run" "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}" + __cdist_run_remote "$__cdist_target_host" \ + "__cdist_code_run" "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}" } diff --git a/core/__cdist_object_explorer_run b/core/__cdist_object_explorer_run index f11c6786..eb62401e 100755 --- a/core/__cdist_object_explorer_run +++ b/core/__cdist_object_explorer_run @@ -49,7 +49,7 @@ __cdist_object_explorer_run() "$(__cdist_remote_object_parameter_dir "$__cdist_object_self")" # Execute explorers - cdist-run-remote "$__cdist_target_host" \ + __cdist_run_remote \ "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" \ "$__cdist_name_var_object_id=\"$__cdist_object_id\"" \ "$__cdist_name_var_self=\"$__cdist_object_self\"" \ diff --git a/bin/cdist-run-remote b/core/__cdist_run_remote similarity index 70% rename from bin/cdist-run-remote rename to core/__cdist_run_remote index 4a4452a2..697a1d68 100755 --- a/bin/cdist-run-remote +++ b/core/__cdist_run_remote @@ -21,13 +21,13 @@ # Run a cdist binary on the remote side # -. cdist-config -[ $# -ge 2 ] || __cdist_usage " [opts]" -set -ue +__cdist_run_remote() +{ + [ $# -ge 1 ] || __cdist_usage " [opts]" -__cdist_target_host="$1"; shift - -ssh "${__cdist_remote_user}@${__cdist_target_host}" \ - "export PATH=\"${__cdist_remote_bin_dir}:\$PATH\";" \ - "export __cdist_out_object_dir=\"$__cdist_remote_out_object_dir\";" \ - "$@" + ssh "${__cdist_remote_user}@${__cdist_target_host}" \ + "export PATH=\"${__cdist_remote_bin_dir}:\$PATH\";" \ + "export __cdist_out_object_dir=\"$__cdist_remote_out_object_dir\";" \ + ". cdist-config;" \ + "$@" +} From 00bbadef789c99ed03ad7494e32b9d1996ce703f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 01:49:43 +0200 Subject: [PATCH 0027/4212] fix first bugs in remotely running code Signed-off-by: Nico Schottelius --- bin/cdist-explorer-run-global | 2 +- core/__cdist_object_code_run | 4 ++-- core/__cdist_run_remote | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/bin/cdist-explorer-run-global b/bin/cdist-explorer-run-global index 51052627..b13b898f 100755 --- a/bin/cdist-explorer-run-global +++ b/bin/cdist-explorer-run-global @@ -33,7 +33,7 @@ __cdist_echo info "Running global explorers " __cdist_dir push "${__cdist_explorer_dir}" "${__cdist_remote_explorer_dir}" # run the initial explorers remotely -__cdist_run_remote "${__cdist_target_host}" cdist-remote-explorer-run \ +__cdist_run_remote cdist-remote-explorer-run \ "$__cdist_name_var_explorer" "$__cdist_remote_explorer_dir" \ "$__cdist_remote_out_explorer_dir" diff --git a/core/__cdist_object_code_run b/core/__cdist_object_code_run index c07505fe..48b6514d 100755 --- a/core/__cdist_object_code_run +++ b/core/__cdist_object_code_run @@ -32,6 +32,6 @@ __cdist_object_code_run() __cdist_code_run "$__cdist_object_code_run_object" "${__cdist_name_gencode_local}" # Code remote - __cdist_run_remote "$__cdist_target_host" \ - "__cdist_code_run" "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}" + __cdist_run_remote "__cdist_code_run" \ + "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}" } diff --git a/core/__cdist_run_remote b/core/__cdist_run_remote index 697a1d68..3af7c540 100755 --- a/core/__cdist_run_remote +++ b/core/__cdist_run_remote @@ -28,6 +28,5 @@ __cdist_run_remote() ssh "${__cdist_remote_user}@${__cdist_target_host}" \ "export PATH=\"${__cdist_remote_bin_dir}:\$PATH\";" \ "export __cdist_out_object_dir=\"$__cdist_remote_out_object_dir\";" \ - ". cdist-config;" \ - "$@" + "cdist-remote" "$@" } From 022db229246322f3f2c0213272c5576981afd102 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 10:57:33 +0200 Subject: [PATCH 0028/4212] +debug Signed-off-by: Nico Schottelius --- bin/cdist-remote-explorer-run | 73 +++++++++++++++++++---------------- core/__cdist_code_run | 4 +- core/__cdist_object_gencode | 1 - core/__cdist_object_run | 5 +++ 4 files changed, 47 insertions(+), 36 deletions(-) diff --git a/bin/cdist-remote-explorer-run b/bin/cdist-remote-explorer-run index d95913ba..040e36a2 100755 --- a/bin/cdist-remote-explorer-run +++ b/bin/cdist-remote-explorer-run @@ -24,45 +24,50 @@ # and __type_explorers can be submitted :-) # -. cdist-config -[ $# -eq 3 ] || __cdist_usage " " -set -ue +# FIXME: cleanup! +__cdist_remote_explorer_run() +{ + [ $# -eq 3 ] || __cdist_usage " " + set -ue -# Variable that defines the home of the explorers -__cdist_variable_name="$1"; shift + "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" -# Find explorers here -__cdist_explorer_dir="$1"; shift + # Variable that defines the home of the explorers + __cdist_variable_name="$1"; shift -# Write output here -__cdist_my_out_dir="$1"; shift + # Find explorers here + __cdist_explorer_dir="$1"; shift -# Setup environment -export $__cdist_variable_name="$__cdist_explorer_dir" -export __global="$__cdist_remote_out_dir" + # Write output here + __cdist_my_out_dir="$1"; shift -mkdir -p "$__cdist_my_out_dir" + # Setup environment + export $__cdist_variable_name="$__cdist_explorer_dir" + export __global="$__cdist_remote_out_dir" -# Ensure there is at least one explorer -num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" -if [ "$num" -lt 1 ]; then - __cdist_exit_err "${__cdist_explorer_dir}: Contains no explorers" -fi + mkdir -p "$__cdist_my_out_dir" -# Execute all explorers -for explorer in "$__cdist_explorer_dir/"*; do - explorer_name="${explorer##*/}" - - if [ -f "$explorer" ]; then - if [ ! -x "$explorer" ]; then - __cdist_exit_err "Explorer \"$explorer\" exists, but is not executable." - fi - - # Execute explorers and save results in remote destination directory - "$explorer" > "${__cdist_my_out_dir}/$explorer_name" - else - if [ -e "$explorer" ]; then - __cdist_exit_err "Explorer \"$explorer\" exists, but is not a file." - fi + # Ensure there is at least one explorer + num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" + if [ "$num" -lt 1 ]; then + __cdist_exit_err "${__cdist_explorer_dir}: Contains no explorers" fi -done + + # Execute all explorers + for explorer in "$__cdist_explorer_dir/"*; do + explorer_name="${explorer##*/}" + + if [ -f "$explorer" ]; then + if [ ! -x "$explorer" ]; then + __cdist_exit_err "Explorer \"$explorer\" exists, but is not executable." + fi + + # Execute explorers and save results in remote destination directory + "$explorer" > "${__cdist_my_out_dir}/$explorer_name" + else + if [ -e "$explorer" ]; then + __cdist_exit_err "Explorer \"$explorer\" exists, but is not a file." + fi + fi + done +} diff --git a/core/__cdist_code_run b/core/__cdist_code_run index 6a1b916b..ca73b02d 100755 --- a/core/__cdist_code_run +++ b/core/__cdist_code_run @@ -23,7 +23,6 @@ __cdist_code_run() { - [ $# -eq 2 ] || __cdist_usage " " __cdist_object_self="$1"; shift @@ -49,4 +48,7 @@ __cdist_code_run() __cdist_exit_err "$__cdist_code exists, but is not a file." fi fi + + # Exit gracefully if nothing is todo + true } diff --git a/core/__cdist_object_gencode b/core/__cdist_object_gencode index 585c9d9d..1024f2c5 100755 --- a/core/__cdist_object_gencode +++ b/core/__cdist_object_gencode @@ -28,7 +28,6 @@ __cdist_object_gencode() { - __cdist_myname="foo" [ $# -eq 2 ] || __cdist_usage "" "" __cdist_object_self="$1"; shift diff --git a/core/__cdist_object_run b/core/__cdist_object_run index 07461b23..7f08f192 100755 --- a/core/__cdist_object_run +++ b/core/__cdist_object_run @@ -38,6 +38,8 @@ __cdist_object_run() # Export to non-core for use in manifest and gencode scripts export $__cdist_name_var_self=$__cdist_object_self + # FIXME: BUG: should be named differently! + # FIXME: BUG: I can be called recursively! -> variables are probably already set / overwritten! __cdist_object_finished="$(__cdist_object_finished "$__cdist_object_self")" if [ ! -f "$__cdist_object_finished" ]; then # Resolve dependencies, if any @@ -52,9 +54,12 @@ __cdist_object_run() __cdist_requirement="$1"; shift __cdist_echo info "Resolving requirement $__cdist_requirement" __cdist_object_run "$__cdist_requirement" + echo "done run" done fi + echo "after done" + __cdist_object_gencode_run "$__cdist_object_self" __cdist_dir push "$(__cdist_object_dir "$__cdist_object_self")" \ "$(__cdist_remote_object_dir "$__cdist_object_self")" From cda6c24799dea202e135498fbee0058adbb49d2a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 11:10:58 +0200 Subject: [PATCH 0029/4212] new: core/__cdist_remote_explorer_run Signed-off-by: Nico Schottelius --- bin/cdist-explorer-run-global | 4 ++-- .../__cdist_remote_explorer_run | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) rename bin/cdist-remote-explorer-run => core/__cdist_remote_explorer_run (98%) diff --git a/bin/cdist-explorer-run-global b/bin/cdist-explorer-run-global index b13b898f..5e9c5a09 100755 --- a/bin/cdist-explorer-run-global +++ b/bin/cdist-explorer-run-global @@ -23,7 +23,7 @@ . cdist-config [ $# -eq 1 ] || __cdist_usage "" -set -ue +set -uex __cdist_target_host="$1"; shift @@ -33,7 +33,7 @@ __cdist_echo info "Running global explorers " __cdist_dir push "${__cdist_explorer_dir}" "${__cdist_remote_explorer_dir}" # run the initial explorers remotely -__cdist_run_remote cdist-remote-explorer-run \ +__cdist_run_remote __cdist_remote_explorer_run \ "$__cdist_name_var_explorer" "$__cdist_remote_explorer_dir" \ "$__cdist_remote_out_explorer_dir" diff --git a/bin/cdist-remote-explorer-run b/core/__cdist_remote_explorer_run similarity index 98% rename from bin/cdist-remote-explorer-run rename to core/__cdist_remote_explorer_run index 040e36a2..a7958a41 100755 --- a/bin/cdist-remote-explorer-run +++ b/core/__cdist_remote_explorer_run @@ -24,11 +24,9 @@ # and __type_explorers can be submitted :-) # -# FIXME: cleanup! __cdist_remote_explorer_run() { [ $# -eq 3 ] || __cdist_usage " " - set -ue "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" From 0e7d822d16959581789e75a73649b8500bd86d3c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jun 2011 11:14:24 +0200 Subject: [PATCH 0030/4212] re-add set -e to cdist-config Signed-off-by: Nico Schottelius --- bin/cdist-config | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/cdist-config b/bin/cdist-config index fb5b4be9..dc901295 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -24,6 +24,9 @@ __cdist_version="1.7.0" # Fail if something bogus is going on set -u +# Fail if exited non-zero as well +set -e + ################################################################################ # cconf standard vars prefixed with cdist From 0fa95a5adcbe1ee02945f35c41055f1a52ebec20 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 16 Jun 2011 23:58:31 +0200 Subject: [PATCH 0031/4212] more to fix Signed-off-by: Nico Schottelius --- bin/cdist-explorer-run-global | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist-explorer-run-global b/bin/cdist-explorer-run-global index 5e9c5a09..d578fece 100755 --- a/bin/cdist-explorer-run-global +++ b/bin/cdist-explorer-run-global @@ -33,7 +33,7 @@ __cdist_echo info "Running global explorers " __cdist_dir push "${__cdist_explorer_dir}" "${__cdist_remote_explorer_dir}" # run the initial explorers remotely -__cdist_run_remote __cdist_remote_explorer_run \ +__cdist_run_remote __cdist_remote_explorer_run # FIXME: add object_self!!!! \ "$__cdist_name_var_explorer" "$__cdist_remote_explorer_dir" \ "$__cdist_remote_out_explorer_dir" From 7050342d90eca2e46a3f9ee52310df017e7d3ecb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 10:30:23 +0200 Subject: [PATCH 0032/4212] ../bin/cdist-cache -> __cdist_cache Signed-off-by: Nico Schottelius --- bin/cdist-cache => core/__cdist_cache | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) rename bin/cdist-cache => core/__cdist_cache (60%) diff --git a/bin/cdist-cache b/core/__cdist_cache similarity index 60% rename from bin/cdist-cache rename to core/__cdist_cache index ee27ffb4..44c60125 100755 --- a/bin/cdist-cache +++ b/core/__cdist_cache @@ -18,22 +18,17 @@ # along with cdist. If not, see . # # -# Let's build a cconfig tree from a configuration -# And save it into the cache tree +# Save the configuration tree into the local cache # -. cdist-config -[ $# -eq 1 ] || __cdist_usage "" -set -u +__cdist_cache() +{ + # Create base to move into + mkdir -p "${__cdist_local_base_cache_dir}" -__cdist_target_host="$1"; shift - -# Create base to move into -mkdir -p "${__cdist_local_base_cache_dir}" - -# Now determine absolute path -__cdist_ddir="$(__cdist_host_cache_dir "$__cdist_target_host")" - -__cdist_echo info "Saving cache to $__cdist_ddir " -rm -rf "$__cdist_ddir" -mv "$__cdist_local_base_dir" "$__cdist_ddir" + __cdist_echo info \ + "Saving cache to $(__cdist_host_cache_dir "$__cdist_target_host")" + rm -rf "$(__cdist_host_cache_dir "$__cdist_target_host")" + mv "$__cdist_local_base_dir" \ + "$(__cdist_host_cache_dir "$__cdist_target_host")" +} From 1132ec875603e3148a2d9b938461e590a1d73f29 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 10:32:09 +0200 Subject: [PATCH 0033/4212] cdist-explorer-run-global -> ../core/__cdist_explorer_run_global Signed-off-by: Nico Schottelius --- .../__cdist_explorer_run_global | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) rename bin/cdist-explorer-run-global => core/__cdist_explorer_run_global (57%) diff --git a/bin/cdist-explorer-run-global b/core/__cdist_explorer_run_global similarity index 57% rename from bin/cdist-explorer-run-global rename to core/__cdist_explorer_run_global index d578fece..8a590164 100755 --- a/bin/cdist-explorer-run-global +++ b/core/__cdist_explorer_run_global @@ -21,22 +21,19 @@ # Copy & run the global explorers, i.e. not bound to types # -. cdist-config -[ $# -eq 1 ] || __cdist_usage "" -set -uex +__cdist_explorer_run_global() +{ + __cdist_echo info "Running global explorers " -__cdist_target_host="$1"; shift + # copy the explorers + __cdist_dir push "${__cdist_explorer_dir}" "${__cdist_remote_explorer_dir}" -__cdist_echo info "Running global explorers " - -# copy the explorers -__cdist_dir push "${__cdist_explorer_dir}" "${__cdist_remote_explorer_dir}" - -# run the initial explorers remotely -__cdist_run_remote __cdist_remote_explorer_run # FIXME: add object_self!!!! \ - "$__cdist_name_var_explorer" "$__cdist_remote_explorer_dir" \ - "$__cdist_remote_out_explorer_dir" + # run the initial explorers remotely + __cdist_run_remote __cdist_remote_explorer_run # FIXME: add object_self!!!! \ + "$__cdist_name_var_explorer" "$__cdist_remote_explorer_dir" \ + "$__cdist_remote_out_explorer_dir" -# retrieve the results -__cdist_dir pull "${__cdist_remote_out_explorer_dir}" "${__cdist_out_explorer_dir}" + # retrieve the results + __cdist_dir pull "${__cdist_remote_out_explorer_dir}" "${__cdist_out_explorer_dir}" +} From d680c8a5f1474426a924b59c2ff0ffbc1905cdcd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 10:34:52 +0200 Subject: [PATCH 0034/4212] corelib will go into cdist 1.8.0, if at all Signed-off-by: Nico Schottelius --- bin/cdist-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist-config b/bin/cdist-config index dc901295..84593948 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -19,7 +19,7 @@ # # -__cdist_version="1.7.0" +__cdist_version="1.8.0" # Fail if something bogus is going on set -u From 7d6b1b523612a9550d46124d17374c17c0e958d5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 10:36:44 +0200 Subject: [PATCH 0035/4212] ../bin/cdist-config -> core/__cdist_init_deploy Signed-off-by: Nico Schottelius --- bin/cdist-config | 15 --------------- core/__cdist_init_deploy | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 15 deletions(-) create mode 100755 core/__cdist_init_deploy diff --git a/bin/cdist-config b/bin/cdist-config index 84593948..13cba8c5 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -226,21 +226,6 @@ ___cdist_lib_path() echo $_ } -__cdist_init_deploy() -{ - __cdist_echo info "Creating clean directory structure " - - # Ensure there is no old stuff, neither local nor remote - rm -rf "$__cdist_local_base_dir" - ssh "${__cdist_remote_user}@$1" "rm -rf ${__cdist_remote_base_dir}" - - # Init base - mkdir -p "$__cdist_local_base_dir" - ssh "${__cdist_remote_user}@$1" "mkdir -p ${__cdist_remote_base_dir}" - - # Link configuration source directory - consistent with remote - ln -sf "$__cdist_conf_dir" "$__cdist_local_base_dir/$__cdist_name_conf_dir" -} ################################################################################ # Cache diff --git a/core/__cdist_init_deploy b/core/__cdist_init_deploy new file mode 100755 index 00000000..88545f59 --- /dev/null +++ b/core/__cdist_init_deploy @@ -0,0 +1,38 @@ +#!/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 . +# +# +# Prepare deployment +# + +__cdist_init_deploy() +{ + __cdist_echo info "Creating clean directory structure " + + # Ensure there is no old stuff, neither local nor remote + rm -rf "$__cdist_local_base_dir" + ssh "${__cdist_remote_user}@$1" "rm -rf ${__cdist_remote_base_dir}" + + # Init base + mkdir -p "$__cdist_local_base_dir" + ssh "${__cdist_remote_user}@$1" "mkdir -p ${__cdist_remote_base_dir}" + + # Link configuration source directory - consistent with remote + ln -sf "$__cdist_conf_dir" "$__cdist_local_base_dir/$__cdist_name_conf_dir" +} From 75bff0b13fa7fcbe50d217af08d3c964788f8b28 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 10:40:28 +0200 Subject: [PATCH 0036/4212] +cleanup Signed-off-by: Nico Schottelius --- core/__cdist_init_deploy | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/__cdist_init_deploy b/core/__cdist_init_deploy index 88545f59..4ac3168c 100755 --- a/core/__cdist_init_deploy +++ b/core/__cdist_init_deploy @@ -27,11 +27,13 @@ __cdist_init_deploy() # Ensure there is no old stuff, neither local nor remote rm -rf "$__cdist_local_base_dir" - ssh "${__cdist_remote_user}@$1" "rm -rf ${__cdist_remote_base_dir}" + ssh "${__cdist_remote_user}@${__cdist_target_host}" \ + "rm -rf ${__cdist_remote_base_dir}" # Init base mkdir -p "$__cdist_local_base_dir" - ssh "${__cdist_remote_user}@$1" "mkdir -p ${__cdist_remote_base_dir}" + ssh "${__cdist_remote_user}@${__cdist_target_host}" \ + "mkdir -p ${__cdist_remote_base_dir}" # Link configuration source directory - consistent with remote ln -sf "$__cdist_conf_dir" "$__cdist_local_base_dir/$__cdist_name_conf_dir" From f3a88ef98d156bbbbc5fa5f07fc71cef7e58d9e5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 12:31:00 +0200 Subject: [PATCH 0037/4212] ../bin/cdist-config -> __cdist_echo Signed-off-by: Nico Schottelius --- bin/cdist-config | 35 --------------------------- bin/cdist-deploy-to | 4 ++-- core/__cdist_echo | 58 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 37 deletions(-) create mode 100755 core/__cdist_echo diff --git a/bin/cdist-config b/bin/cdist-config index 13cba8c5..74d9eed7 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -162,41 +162,6 @@ for __cdist_lib in $__cdist_core_dir/*; do . "$__cdist_lib" done -__cdist_echo() -{ - __cdist_echo_type="$1"; shift - - set +u - if [ "$__cdist_object_self" ]; then - __cdist_echo_prefix="${__cdist_object_self}:" - else - __cdist_echo_prefix="core: " - fi - set -u - - case "$__cdist_echo_type" in - debug) - set +u - if [ "$__cdist_debug" ]; then - echo $__cdist_echo_prefix "Debug: $@" - fi - set -u - ;; - info) - echo $__cdist_echo_prefix "$@" - ;; - warn) - echo $__cdist_echo_prefix "Warning: $@" - ;; - error) - echo $__cdist_echo_prefix "Error: $@" >&2 - ;; - *) - echo "CORE BUG, who created the broken commit in $0?" >&2 - exit 23 - ;; - esac -} __cdist_exec_fail_on_error() { diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index baeff220..cf286564 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -36,8 +36,6 @@ export $__cdist_name_var_target_user="$__cdist_remote_user" # Export variables for core, which others do not reset export __cdist_local_base_dir - -# Load library always from the checkout export __cdist_core_dir __cdist_echo info "cdist $__cdist_version: Configuring $__cdist_target_host " @@ -49,6 +47,8 @@ __cdist_echo info "cdist $__cdist_version: Configuring $__cdist_target_host " # Prepare local and remote directories __cdist_init_deploy "$__cdist_target_host" +FIXME: stopped here! + # Transfer cdist executables __cdist_echo info "Transferring cdist binaries/functions to the target host " __cdist_dir push "${__cdist_abs_mydir}" "${__cdist_remote_bin_dir}" diff --git a/core/__cdist_echo b/core/__cdist_echo new file mode 100755 index 00000000..2fcc93f0 --- /dev/null +++ b/core/__cdist_echo @@ -0,0 +1,58 @@ +#!/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 . +# +# +# echo / syslog alike function +# + +__cdist_echo() +{ + __cdist_echo_type="$1"; shift + + set +u + if [ "$__cdist_object_self" ]; then + __cdist_echo_prefix="${__cdist_object_self}:" + else + __cdist_echo_prefix="core: " + fi + set -u + + case "$__cdist_echo_type" in + debug) + set +u + if [ "$__cdist_debug" ]; then + echo $__cdist_echo_prefix "Debug: $@" + fi + set -u + ;; + info) + echo $__cdist_echo_prefix "$@" + ;; + warn) + echo $__cdist_echo_prefix "Warning: $@" + ;; + error) + echo $__cdist_echo_prefix "Error: $@" >&2 + ;; + *) + echo "CORE BUG, who created the broken commit in $0?" >&2 + exit 23 + ;; + esac +} From c474317a6aee84152a7b39762c3bc070225d89e6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 12:34:40 +0200 Subject: [PATCH 0038/4212] migrate more stuff from cdist-config to core/ Signed-off-by: Nico Schottelius --- bin/cdist-config | 24 ---------------------- core/__cdist_exec_fail_on_error | 35 +++++++++++++++++++++++++++++++++ core/__cdist_exit_err | 28 ++++++++++++++++++++++++++ core/__cdist_usage | 27 +++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 24 deletions(-) create mode 100755 core/__cdist_exec_fail_on_error create mode 100755 core/__cdist_exit_err create mode 100755 core/__cdist_usage diff --git a/bin/cdist-config b/bin/cdist-config index 74d9eed7..a8f32dc1 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -162,30 +162,6 @@ for __cdist_lib in $__cdist_core_dir/*; do . "$__cdist_lib" done - -__cdist_exec_fail_on_error() -{ - set +e - sh -e "$@" - if [ "$?" -ne 0 ]; then - __cdist_echo error "$1 exited non-zero" - __cdist_echo warn "Faulty code:" - cat "$1" - __cdist_exit_err "Aborting due to non-zero exit code." - fi -} - -__cdist_exit_err() -{ - __cdist_echo error "$@" - exit 1 -} - -__cdist_usage() -{ - __cdist_exit_err "$__cdist_myname: $@" -} - ___cdist_lib_path() { echo $_ diff --git a/core/__cdist_exec_fail_on_error b/core/__cdist_exec_fail_on_error new file mode 100755 index 00000000..96e5f056 --- /dev/null +++ b/core/__cdist_exec_fail_on_error @@ -0,0 +1,35 @@ +#!/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 . +# +# +# Exit if an error occurs +# + +__cdist_exec_fail_on_error() +{ + set +e + sh -e "$@" + if [ "$?" -ne 0 ]; then + __cdist_echo error "$1 exited non-zero" + __cdist_echo warn "Faulty code:" + cat "$1" + __cdist_exit_err "Aborting due to non-zero exit code." + fi + set -e +} diff --git a/core/__cdist_exit_err b/core/__cdist_exit_err new file mode 100755 index 00000000..303dbf20 --- /dev/null +++ b/core/__cdist_exit_err @@ -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 . +# +# +# Print error and exit (perror() alike) +# + +__cdist_exit_err() +{ + __cdist_echo error "$@" + exit 1 +} diff --git a/core/__cdist_usage b/core/__cdist_usage new file mode 100755 index 00000000..9dfa30e4 --- /dev/null +++ b/core/__cdist_usage @@ -0,0 +1,27 @@ +#!/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 . +# +# +# Print error and exit (perror() alike) +# + +__cdist_usage() +{ + __cdist_exit_err "$__cdist_myname: $@" +} From 29450e5e99ca4d7ece84d93aa863b52dfd0376cf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 12:49:02 +0200 Subject: [PATCH 0039/4212] add __cdist_explorer_run, which should replace __cdist_remote_explorer_run Signed-off-by: Nico Schottelius --- core/__cdist_explorer_run | 71 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100755 core/__cdist_explorer_run diff --git a/core/__cdist_explorer_run b/core/__cdist_explorer_run new file mode 100755 index 00000000..a7958a41 --- /dev/null +++ b/core/__cdist_explorer_run @@ -0,0 +1,71 @@ +#!/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 . +# +# +# This binary is executed on the remote side to execute explorers +# +# It supports different variables names to be used, so __explorers +# and __type_explorers can be submitted :-) +# + +__cdist_remote_explorer_run() +{ + [ $# -eq 3 ] || __cdist_usage " " + + "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" + + # Variable that defines the home of the explorers + __cdist_variable_name="$1"; shift + + # Find explorers here + __cdist_explorer_dir="$1"; shift + + # Write output here + __cdist_my_out_dir="$1"; shift + + # Setup environment + export $__cdist_variable_name="$__cdist_explorer_dir" + export __global="$__cdist_remote_out_dir" + + mkdir -p "$__cdist_my_out_dir" + + # Ensure there is at least one explorer + num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" + if [ "$num" -lt 1 ]; then + __cdist_exit_err "${__cdist_explorer_dir}: Contains no explorers" + fi + + # Execute all explorers + for explorer in "$__cdist_explorer_dir/"*; do + explorer_name="${explorer##*/}" + + if [ -f "$explorer" ]; then + if [ ! -x "$explorer" ]; then + __cdist_exit_err "Explorer \"$explorer\" exists, but is not executable." + fi + + # Execute explorers and save results in remote destination directory + "$explorer" > "${__cdist_my_out_dir}/$explorer_name" + else + if [ -e "$explorer" ]; then + __cdist_exit_err "Explorer \"$explorer\" exists, but is not a file." + fi + fi + done +} From a277d5a4d4e00f57628227fc24f2d982952768d4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 13:00:50 +0200 Subject: [PATCH 0040/4212] some ideas about future design Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-06-17.design-ideas | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 doc/dev/logs/2011-06-17.design-ideas diff --git a/doc/dev/logs/2011-06-17.design-ideas b/doc/dev/logs/2011-06-17.design-ideas new file mode 100644 index 00000000..0a59b743 --- /dev/null +++ b/doc/dev/logs/2011-06-17.design-ideas @@ -0,0 +1,7 @@ +Should __run_remote be used or should the workflow more be +"I'm working here, part of it is executed remote?" + +Indirect call to functions like __cdist_remote_explorer_run are +partly hard to debug / think about. + +Setting up variables is needed for non-core (i.e. explorers) From 4fbe2a26766ebd30380b22e2a4de3a21b25d7bba Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 13:01:03 +0200 Subject: [PATCH 0041/4212] begin work on __cdist_explorer_run Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 4 +--- core/__cdist_explorer_run | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index cf286564..dc20b971 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -47,14 +47,12 @@ __cdist_echo info "cdist $__cdist_version: Configuring $__cdist_target_host " # Prepare local and remote directories __cdist_init_deploy "$__cdist_target_host" -FIXME: stopped here! - # Transfer cdist executables __cdist_echo info "Transferring cdist binaries/functions to the target host " __cdist_dir push "${__cdist_abs_mydir}" "${__cdist_remote_bin_dir}" __cdist_dir push "${__cdist_core_dir}" "${__cdist_remote_core_dir}" -cdist-explorer-run-global "$__cdist_target_host" +__cdist_explorer_run_global __cdist_manifest_run_init __cdist_object_all __cdist_object_prepare __cdist_object_all __cdist_object_run diff --git a/core/__cdist_explorer_run b/core/__cdist_explorer_run index a7958a41..4a6a011d 100755 --- a/core/__cdist_explorer_run +++ b/core/__cdist_explorer_run @@ -24,7 +24,7 @@ # and __type_explorers can be submitted :-) # -__cdist_remote_explorer_run() +__cdist_explorer_run() { [ $# -eq 3 ] || __cdist_usage " " From 6a37d58cc8d109fe6aec92026a087541ea416be8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 14:13:12 +0200 Subject: [PATCH 0042/4212] more thoughts Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-06-17.design-ideas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/logs/2011-06-17.design-ideas b/doc/dev/logs/2011-06-17.design-ideas index 0a59b743..26845360 100644 --- a/doc/dev/logs/2011-06-17.design-ideas +++ b/doc/dev/logs/2011-06-17.design-ideas @@ -5,3 +5,5 @@ Indirect call to functions like __cdist_remote_explorer_run are partly hard to debug / think about. Setting up variables is needed for non-core (i.e. explorers) + + From 141b80860367e070ae756122a188983dfb0e03eb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 14:16:43 +0200 Subject: [PATCH 0043/4212] do not use cdist-remote always Signed-off-by: Nico Schottelius --- core/__cdist_run_remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/__cdist_run_remote b/core/__cdist_run_remote index 3af7c540..17074049 100755 --- a/core/__cdist_run_remote +++ b/core/__cdist_run_remote @@ -28,5 +28,5 @@ __cdist_run_remote() ssh "${__cdist_remote_user}@${__cdist_target_host}" \ "export PATH=\"${__cdist_remote_bin_dir}:\$PATH\";" \ "export __cdist_out_object_dir=\"$__cdist_remote_out_object_dir\";" \ - "cdist-remote" "$@" + "$@" } From 3c903fae678a1fc783ad6f1052515b5adb98c41b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 14:27:50 +0200 Subject: [PATCH 0044/4212] abort execution until global explorers work Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index dc20b971..c48eba57 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -53,6 +53,8 @@ __cdist_dir push "${__cdist_abs_mydir}" "${__cdist_remote_bin_dir}" __cdist_dir push "${__cdist_core_dir}" "${__cdist_remote_core_dir}" __cdist_explorer_run_global +exit 1 + __cdist_manifest_run_init __cdist_object_all __cdist_object_prepare __cdist_object_all __cdist_object_run From 83e75666c32d0ced699fa1966475d2f75a796ccb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 14:28:10 +0200 Subject: [PATCH 0045/4212] begin integration of type|global support Signed-off-by: Nico Schottelius --- core/__cdist_explorer_run | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/core/__cdist_explorer_run b/core/__cdist_explorer_run index 4a6a011d..6a580af3 100755 --- a/core/__cdist_explorer_run +++ b/core/__cdist_explorer_run @@ -18,20 +18,24 @@ # along with cdist. If not, see . # # -# This binary is executed on the remote side to execute explorers -# -# It supports different variables names to be used, so __explorers -# and __type_explorers can be submitted :-) +# Run explorers # __cdist_explorer_run() { - [ $# -eq 3 ] || __cdist_usage " " + [ $# -eq 3 ] || __cdist_usage " " + + case "$1" in + global) + type) + "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" + *) + ;; + esac - "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" # Variable that defines the home of the explorers - __cdist_variable_name="$1"; shift + # __cdist_variable_name="$1"; shift # Find explorers here __cdist_explorer_dir="$1"; shift @@ -39,11 +43,11 @@ __cdist_explorer_run() # Write output here __cdist_my_out_dir="$1"; shift - # Setup environment + # Setup remote environment export $__cdist_variable_name="$__cdist_explorer_dir" export __global="$__cdist_remote_out_dir" - mkdir -p "$__cdist_my_out_dir" + # mkdir -p "$__cdist_my_out_dir" # Ensure there is at least one explorer num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" From a5b97139869203439f9fd4e60b8399e111412bb0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 14:28:45 +0200 Subject: [PATCH 0046/4212] ++todo, use new function Signed-off-by: Nico Schottelius --- core/__cdist_explorer_run_global | 6 ++---- doc/dev/logs/2011-06-14.timing | 6 ++++++ doc/dev/todo/niconext | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 doc/dev/logs/2011-06-14.timing diff --git a/core/__cdist_explorer_run_global b/core/__cdist_explorer_run_global index 8a590164..dfbeb6ac 100755 --- a/core/__cdist_explorer_run_global +++ b/core/__cdist_explorer_run_global @@ -28,12 +28,10 @@ __cdist_explorer_run_global() # copy the explorers __cdist_dir push "${__cdist_explorer_dir}" "${__cdist_remote_explorer_dir}" - # run the initial explorers remotely - __cdist_run_remote __cdist_remote_explorer_run # FIXME: add object_self!!!! \ - "$__cdist_name_var_explorer" "$__cdist_remote_explorer_dir" \ + # run the global explorers remotely + __cdist_explorer_run global "$__cdist_remote_explorer_dir" \ "$__cdist_remote_out_explorer_dir" - # retrieve the results __cdist_dir pull "${__cdist_remote_out_explorer_dir}" "${__cdist_out_explorer_dir}" } diff --git a/doc/dev/logs/2011-06-14.timing b/doc/dev/logs/2011-06-14.timing new file mode 100644 index 00000000..dcfd4884 --- /dev/null +++ b/doc/dev/logs/2011-06-14.timing @@ -0,0 +1,6 @@ +ikq04: + +cdist-deploy-to ikq04.ethz.ch 35.44s user 30.65s system 34% cpu 3:11.45 total # also migrate cdist-object-gencode +cdist-deploy-to ikq04.ethz.ch 23.56s user 22.44s system 35% cpu 2:09.78 total # ../bin/cdist-object-all -> __cdist_object_all +cdist-deploy-to ikq04.ethz.ch 17.35s user 16.83s system 30% cpu 1:53.69 total # bin/cdist-object-manifest-run -> core/__cdist_object_manifest_run +cdist-deploy-to ikq04.ethz.ch 19.76s user 23.58s system 35% cpu 2:03.33 total # ../core/__cdist_manifest_run_init diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index ce89c643..1ed887d5 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -2,4 +2,19 @@ either make functions available on the other side or put logic on the server side. + - trying to run global explorers nicely from local side + + + - Both type and global have... + - local sourcedir + - remote destination dir + - remote out dir + - local out dir + + - Differences are in... + - variables exposed / submitted + + + + Catch broken instances in cdist-mass-deploy -p and report broken deployements at the end! From 29e029a2ebd60084eb447561509a249e15fdd888 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 14:37:36 +0200 Subject: [PATCH 0047/4212] replace __cdist_type_has_explorer with __cdist_dir_listing Signed-off-by: Nico Schottelius --- bin/cdist-config | 9 --------- core/__cdist_dir_listing | 30 ++++++++++++++++++++++++++++++ core/__cdist_object_explorer_run | 2 +- 3 files changed, 31 insertions(+), 10 deletions(-) create mode 100755 core/__cdist_dir_listing diff --git a/bin/cdist-config b/bin/cdist-config index a8f32dc1..bed9e6b4 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -330,15 +330,6 @@ __cdist_type_from_object() echo "${1%%/*}" } -__cdist_type_has_explorer() -{ - # We only create output, if there's at least one explorer - # and can thus be used as a boolean ;-) - if [ -d "$(__cdist_type_explorer_dir "$1")" ]; then - ls -1 "$(__cdist_type_explorer_dir "$1")" - fi -} - __cdist_type_explorer_pushed() { [ -f "${__cdist_out_type_dir}/${__cdist_name_type_explorer_pushed}" ] \ diff --git a/core/__cdist_dir_listing b/core/__cdist_dir_listing new file mode 100755 index 00000000..f4aa2320 --- /dev/null +++ b/core/__cdist_dir_listing @@ -0,0 +1,30 @@ +#!/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 . +# +# +# List files in a directory, if it exists +# +# We only create output, if there's at least one entry +# and can thus be used as a boolean ;-) +# + +__cdist_dir_listing() +{ + [ -d "$1" ] && ls -1 "$1" +} diff --git a/core/__cdist_object_explorer_run b/core/__cdist_object_explorer_run index eb62401e..45ca3379 100755 --- a/core/__cdist_object_explorer_run +++ b/core/__cdist_object_explorer_run @@ -30,7 +30,7 @@ __cdist_object_explorer_run() __cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" # Check if type of object has >= 1 explorer - __cdist_has_explorer="$(__cdist_type_has_explorer "$__cdist_type")" + __cdist_has_explorer="$(__cdist_dir_listing "$(__cdist_type_explorer_dir "$__cdist_type")")" # Run the type explorers for the current object if any if [ "$__cdist_has_explorer" ]; then if ! __cdist_type_explorer_pushed "$__cdist_type"; then From 390d527515c1bd1828d76ebd1ab0a613ea3046a6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 14:51:32 +0200 Subject: [PATCH 0048/4212] global explorers work again Signed-off-by: Nico Schottelius --- core/__cdist_explorer_run | 40 +++++++++++++++++++++++++------- core/__cdist_explorer_run_global | 9 +++---- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/core/__cdist_explorer_run b/core/__cdist_explorer_run index 6a580af3..a5545faf 100755 --- a/core/__cdist_explorer_run +++ b/core/__cdist_explorer_run @@ -23,15 +23,38 @@ __cdist_explorer_run() { - [ $# -eq 3 ] || __cdist_usage " " + # [ $# -eq 3 ] || __cdist_usage " " + [ $# -eq 5 ] || __cdist_usage " " + set -x - case "$1" in - global) - type) - "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" - *) - ;; - esac + # Only do something, if there's at least one entry + [ "$(__cdist_dir_listing "$2")" ] || return + + # Transfer explorers + __cdist_dir push "$2" "$3" + + # Create output directory + __cdist_run_remote mkdir -p "$4" + + # Execute all explorers + cd "$2"; + for __cdist_explorer_run_explorer in *; do + __cdist_run_remote "$3/$__cdist_explorer_run_explorer" ">" \ + "$4/$__cdist_explorer_run_explorer" + done + + # Transfer results back + __cdist_dir pull "$4" "$5" + + return + +# case "$1" in +# global) +# type) +# "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" +# *) +# ;; +# esac # Variable that defines the home of the explorers @@ -47,7 +70,6 @@ __cdist_explorer_run() export $__cdist_variable_name="$__cdist_explorer_dir" export __global="$__cdist_remote_out_dir" - # mkdir -p "$__cdist_my_out_dir" # Ensure there is at least one explorer num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" diff --git a/core/__cdist_explorer_run_global b/core/__cdist_explorer_run_global index dfbeb6ac..7265aee1 100755 --- a/core/__cdist_explorer_run_global +++ b/core/__cdist_explorer_run_global @@ -26,12 +26,13 @@ __cdist_explorer_run_global() __cdist_echo info "Running global explorers " # copy the explorers - __cdist_dir push "${__cdist_explorer_dir}" "${__cdist_remote_explorer_dir}" +# __cdist_dir push "${__cdist_explorer_dir}" "${__cdist_remote_explorer_dir}" # run the global explorers remotely - __cdist_explorer_run global "$__cdist_remote_explorer_dir" \ - "$__cdist_remote_out_explorer_dir" + __cdist_explorer_run global \ + "$__cdist_explorer_dir" "$__cdist_remote_explorer_dir" \ + "$__cdist_remote_out_explorer_dir" "$__cdist_out_explorer_dir" # retrieve the results - __cdist_dir pull "${__cdist_remote_out_explorer_dir}" "${__cdist_out_explorer_dir}" +# __cdist_dir pull "${__cdist_remote_out_explorer_dir}" "${__cdist_out_explorer_dir}" } From bb06a69bd5ecf3b8adc1cadbe082394eead8924b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 14:52:06 +0200 Subject: [PATCH 0049/4212] cleanup Signed-off-by: Nico Schottelius --- core/__cdist_explorer_run_global | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/__cdist_explorer_run_global b/core/__cdist_explorer_run_global index 7265aee1..27359713 100755 --- a/core/__cdist_explorer_run_global +++ b/core/__cdist_explorer_run_global @@ -25,14 +25,8 @@ __cdist_explorer_run_global() { __cdist_echo info "Running global explorers " - # copy the explorers -# __cdist_dir push "${__cdist_explorer_dir}" "${__cdist_remote_explorer_dir}" - # run the global explorers remotely __cdist_explorer_run global \ "$__cdist_explorer_dir" "$__cdist_remote_explorer_dir" \ "$__cdist_remote_out_explorer_dir" "$__cdist_out_explorer_dir" - - # retrieve the results -# __cdist_dir pull "${__cdist_remote_out_explorer_dir}" "${__cdist_out_explorer_dir}" } From f544fc5c42d81d7aadb3d528c80a07119b9f434d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jun 2011 15:01:31 +0200 Subject: [PATCH 0050/4212] next todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 1ed887d5..7c91d865 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -2,7 +2,10 @@ either make functions available on the other side or put logic on the server side. - - trying to run global explorers nicely from local side + - trying to run type explorers nicely from local side + - must check whether type directory has been transmitted before! + +-------------------------------------------------------------------------------- - Both type and global have... From eeaab438c25f8d707ef67f8f0e205e7fdd48efeb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 21 Jun 2011 12:34:18 +0200 Subject: [PATCH 0051/4212] logfile Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-06-21.execute_remote | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 doc/dev/logs/2011-06-21.execute_remote diff --git a/doc/dev/logs/2011-06-21.execute_remote b/doc/dev/logs/2011-06-21.execute_remote new file mode 100644 index 00000000..61292688 --- /dev/null +++ b/doc/dev/logs/2011-06-21.execute_remote @@ -0,0 +1,38 @@ +Steven, Nico: + +Problem: + How to execute a function instead of binary + +Solutions: + + 1) + ( + cat $lib/* + cat bin/cdist-config + echo $function $args + ) | ssh foo + + 2) + scp $dir/lib.sh root@foo:/tmp/lib.sh + cat << DONE | ssh root@foo sh + source /tmp/lib.sh + DONE + + 3) follow up to 1) + __run_remote() + { + cat << eof | ssh foo + + . /cdist-config + "$@" # NOT USABLE, no export = export = lines possible! + + eof + + +Problems found and solved: + + - remote shell cannot work due to multi line variable export + - caching library directory with scp + - create function for every remote action + -> prepares environment + From a53782805dd9a811cbff53d340d1af47a717dc74 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 23 Jun 2011 12:13:46 +0200 Subject: [PATCH 0052/4212] ++log Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-06-21.execute_remote | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/doc/dev/logs/2011-06-21.execute_remote b/doc/dev/logs/2011-06-21.execute_remote index 61292688..a9c88df2 100644 --- a/doc/dev/logs/2011-06-21.execute_remote +++ b/doc/dev/logs/2011-06-21.execute_remote @@ -12,12 +12,19 @@ Solutions: echo $function $args ) | ssh foo + Works partly, does not work for export = ... + Needs to copy over lib every time again! + 2) scp $dir/lib.sh root@foo:/tmp/lib.sh cat << DONE | ssh root@foo sh source /tmp/lib.sh + export foo=bla + function args DONE + Caches lib directory + 3) follow up to 1) __run_remote() { @@ -28,6 +35,22 @@ Solutions: eof + 4) final solution + - write for every remote job a new function + - this functions prepares env + reuses ssh header + + __cdist_remote_explorer() + { + cat << eof + $__cdist_remote_header + export foo1=bar + export foo2=bar + export foo3=bar + + "$@" + eof | __cdist_ssh + } + Problems found and solved: From 4a9456787cec785dfb5e728e8f1251f4490cb5c0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 24 Jun 2011 15:02:20 +0200 Subject: [PATCH 0053/4212] +log cinst preos Signed-off-by: Steven Armstrong --- doc/dev/logs/2011-06-24.cinst_preos | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 doc/dev/logs/2011-06-24.cinst_preos diff --git a/doc/dev/logs/2011-06-24.cinst_preos b/doc/dev/logs/2011-06-24.cinst_preos new file mode 100644 index 00000000..c366c963 --- /dev/null +++ b/doc/dev/logs/2011-06-24.cinst_preos @@ -0,0 +1,10 @@ +- new executable cinst-deploy-to +- types used by cinst are marked as such ('cinst-only') +- cdist-deploy-to and cinst-deploy-to read the same manifest +- cdist ignores types marked as 'cinst-only' +- cinst ignores types not marked as 'cinst-only' + +- update $__explorer/os to recognize preos + +- cinst types only do something if $__explorer/os == 'preos' + From bf0acc2e3128f6236816c9966ab0ccb145a70963 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 24 Jun 2011 15:07:29 +0200 Subject: [PATCH 0054/4212] +correction Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-06-24.cinst_preos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dev/logs/2011-06-24.cinst_preos b/doc/dev/logs/2011-06-24.cinst_preos index c366c963..309c3778 100644 --- a/doc/dev/logs/2011-06-24.cinst_preos +++ b/doc/dev/logs/2011-06-24.cinst_preos @@ -6,5 +6,5 @@ - update $__explorer/os to recognize preos -- cinst types only do something if $__explorer/os == 'preos' +- cinst types will ONLY BE CALLED if $__explorer/os == 'preos' From 51da953e4903ea9b870bd6e9e99367b061d2b1fa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 24 Jun 2011 15:25:11 +0200 Subject: [PATCH 0055/4212] detect pre-os in explorer Signed-off-by: Nico Schottelius --- conf/explorer/os | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/conf/explorer/os b/conf/explorer/os index 6684ff78..e922c067 100755 --- a/conf/explorer/os +++ b/conf/explorer/os @@ -65,6 +65,11 @@ if [ -f /etc/SuSE-release ]; then exit 0 fi +if [ -f /etc/cdist-preos ]; then + echo preos + exit 0 +fi + uname_s="$(uname -s)" # Assume there is no tr on the client -> do lower case ourselves From 27966c058bb5e07ce96787916c09724bfdfed3b2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 24 Jun 2011 15:38:34 +0200 Subject: [PATCH 0056/4212] +ideas for types Signed-off-by: Steven Armstrong --- doc/dev/logs/2011-06-24.cinst_preos | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/dev/logs/2011-06-24.cinst_preos b/doc/dev/logs/2011-06-24.cinst_preos index 309c3778..892ee5f7 100644 --- a/doc/dev/logs/2011-06-24.cinst_preos +++ b/doc/dev/logs/2011-06-24.cinst_preos @@ -8,3 +8,13 @@ - cinst types will ONLY BE CALLED if $__explorer/os == 'preos' +-------------------------------------------------------------------------------- +cinst types: +__partition_msdos /dev/sda1 --type 83 --size 100M --bootable +__partition_msdos /dev/sda2 --type 82 --size 512M +__fs_jfs /dev/sda1 --args "-c -q" +__fstab_entry /dev/sda1 --type jfs --mountpoint / --options noatime --freq 0 --passno 0 +__fstab_entry /dev/sda2 --type swap + + + From dd949d5984aa826d9827d4dde133e33e7a86df64 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 1 Jul 2011 13:14:26 +0200 Subject: [PATCH 0057/4212] explorers for types with clashing names not pushed to target Thorsten Steenbock reported a bug where types with similar names, e.g __first __first_second would interfere when transfering explorers to the target host. Signed-off-by: Steven Armstrong --- bin/cdist-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist-config b/bin/cdist-config index f7fb5ac0..88e3068f 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -398,7 +398,7 @@ __cdist_type_has_explorer() __cdist_type_explorer_pushed() { [ -f "${__cdist_out_type_dir}/${__cdist_name_type_explorer_pushed}" ] \ - && grep -q "$1" "${__cdist_out_type_dir}/${__cdist_name_type_explorer_pushed}" + && grep -x -q "$1" "${__cdist_out_type_dir}/${__cdist_name_type_explorer_pushed}" } __cdist_type_explorer_pushed_add() From 0736f7dfd3d0c2a1978c87e27d1e69d42e4cedf4 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 1 Jul 2011 14:42:17 +0200 Subject: [PATCH 0058/4212] ideas for type improvements Signed-off-by: Steven Armstrong --- doc/dev/logs/2011-07-01.type-gencode | 9 ++++++++ doc/dev/logs/2011-07-01.type-global-explorers | 22 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 doc/dev/logs/2011-07-01.type-gencode create mode 100644 doc/dev/logs/2011-07-01.type-global-explorers diff --git a/doc/dev/logs/2011-07-01.type-gencode b/doc/dev/logs/2011-07-01.type-gencode new file mode 100644 index 00000000..cafa8ef2 --- /dev/null +++ b/doc/dev/logs/2011-07-01.type-gencode @@ -0,0 +1,9 @@ +when all objects of a type are applied, then run the types gencode-{local,remote} scripts + +-------------------------------------------------------------------------------- + +__mein_type/ + type/ # executed when all objects of this type have been applied + gencode-local + gencode-remote + diff --git a/doc/dev/logs/2011-07-01.type-global-explorers b/doc/dev/logs/2011-07-01.type-global-explorers new file mode 100644 index 00000000..302c2866 --- /dev/null +++ b/doc/dev/logs/2011-07-01.type-global-explorers @@ -0,0 +1,22 @@ +types can contribute global explorers +-------------------------------------------------------------------------------- + +__mein_type/ + global/ + explorer/ + status-von-foo + anderer + +$out/explorer/ + hostname + os + ... + __mein_type/ + status-von-foo + anderer + + +todos: +- cdist scans types for global/explorer's +- when executing explorers, create the types namespace folder before running type gobal explorers + From aa6b655cd3758bddd6b2b371590738cb445174e7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 1 Jul 2011 16:02:03 +0200 Subject: [PATCH 0059/4212] new executable that uses its stdin as the initial manifest Signed-off-by: Steven Armstrong --- bin/cdist-deploy-stdin-to | 36 +++++++++++++++++++++++++ doc/man/man1/cdist-deploy-stdin-to.text | 30 +++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100755 bin/cdist-deploy-stdin-to create mode 100644 doc/man/man1/cdist-deploy-stdin-to.text diff --git a/bin/cdist-deploy-stdin-to b/bin/cdist-deploy-stdin-to new file mode 100755 index 00000000..391dd431 --- /dev/null +++ b/bin/cdist-deploy-stdin-to @@ -0,0 +1,36 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Use stdin as the manifest to deploy on the given host. +# + +. cdist-config +[ $# -eq 1 ] || __cdist_usage "" +set -eu + +__cdist_target_host="$1" +shift + +cat >> "$__cdist_tmp_file" + +chmod +x "$__cdist_tmp_file" + +export __cdist_manifest_init="$__cdist_tmp_file" +cdist-deploy-to "$__cdist_target_host" diff --git a/doc/man/man1/cdist-deploy-stdin-to.text b/doc/man/man1/cdist-deploy-stdin-to.text new file mode 100644 index 00000000..14f19478 --- /dev/null +++ b/doc/man/man1/cdist-deploy-stdin-to.text @@ -0,0 +1,30 @@ +cdist-deploy-stdin-to(1) +======================== +Steven Armstrong + + +NAME +---- +cdist-deploy-stdin-to - Deploy the configuration given on stdin to host + + +SYNOPSIS +-------- +echo "__file /tmp/whatever" | cdist-deploy-stdin-to HOSTNAME + + +DESCRIPTION +----------- +Use stdin as the manifest for cdist-deploy-to. + + +SEE ALSO +-------- +- cdist(7) +- cdist-deploy-to(1) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). From 8dd994d1a65f336ffbe5142a804747e5b4eb8242 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 1 Jul 2011 15:37:09 +0200 Subject: [PATCH 0060/4212] new type: __apt_update_index Signed-off-by: Steven Armstrong --- conf/type/__apt_update_index/gencode-remote | 26 +++++++++++++ conf/type/__apt_update_index/man.text | 41 +++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100755 conf/type/__apt_update_index/gencode-remote create mode 100644 conf/type/__apt_update_index/man.text diff --git a/conf/type/__apt_update_index/gencode-remote b/conf/type/__apt_update_index/gencode-remote new file mode 100755 index 00000000..e66ff7a3 --- /dev/null +++ b/conf/type/__apt_update_index/gencode-remote @@ -0,0 +1,26 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# run 'apt-get update' if anything in /etc/apt is newer then /var/lib/apt/lists +cat << DONE +if find /etc/apt -cnewer /var/lib/apt/lists | grep . > /dev/null; then + apt-get update || apt-get update +fi +DONE diff --git a/conf/type/__apt_update_index/man.text b/conf/type/__apt_update_index/man.text new file mode 100644 index 00000000..778af508 --- /dev/null +++ b/conf/type/__apt_update_index/man.text @@ -0,0 +1,41 @@ +cdist-type__apt_update_index(7) +=============================== +Steven Armstrong + + +NAME +---- +cdist-type__apt_update_index - update apt's package index + + +DESCRIPTION +----------- +This cdist type runs apt-get update whenever any apt sources have changed. + + +REQUIRED PARAMETERS +------------------- +None. + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__apt_update_index +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). From 9c887319e64ae6c974049a1498d7c11d4d7813c7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 1 Jul 2011 15:38:06 +0200 Subject: [PATCH 0061/4212] use new type __apt_update_index Signed-off-by: Steven Armstrong --- conf/type/__apt_ppa/manifest | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/type/__apt_ppa/manifest b/conf/type/__apt_ppa/manifest index d5df9e23..5aa84931 100755 --- a/conf/type/__apt_ppa/manifest +++ b/conf/type/__apt_ppa/manifest @@ -27,3 +27,4 @@ require="__package/python-software-properties" \ --source "$__type/files/remove-apt-repository" \ --mode 0755 +require="$__self" __apt_update_index From ef393a5b8e72380732fc439b6b7539f12dfaeac7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 1 Jul 2011 16:15:08 +0200 Subject: [PATCH 0062/4212] make __apt_update_index a singleton Signed-off-by: Steven Armstrong --- conf/type/__apt_update_index/singleton | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 conf/type/__apt_update_index/singleton diff --git a/conf/type/__apt_update_index/singleton b/conf/type/__apt_update_index/singleton new file mode 100644 index 00000000..e69de29b From c631a609eddd2e84b7ca7b75480b1e7f26515314 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 1 Jul 2011 16:43:30 +0200 Subject: [PATCH 0063/4212] +docs Signed-off-by: Steven Armstrong --- conf/type/__package_apt/notes.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 conf/type/__package_apt/notes.txt diff --git a/conf/type/__package_apt/notes.txt b/conf/type/__package_apt/notes.txt new file mode 100644 index 00000000..4b89f9b3 --- /dev/null +++ b/conf/type/__package_apt/notes.txt @@ -0,0 +1,3 @@ +# All you ever wanted to know about apt/apt-get +http://wiki.ubuntuusers.de/apt-get + From 0d6171c69bbfd6af35fdc3c2affb1a721f54e2f6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 12 Jul 2011 14:15:39 +0200 Subject: [PATCH 0064/4212] start work on cinst partitioning Signed-off-by: Steven Armstrong --- .../__cinst_partition_msdos/gencode-remote | 20 ++++++ conf/type/__cinst_partition_msdos/man.text | 63 +++++++++++++++++++ conf/type/__cinst_partition_msdos/manifest | 25 ++++++++ .../parameter/optional | 3 + .../parameter/required | 1 + 5 files changed, 112 insertions(+) create mode 100755 conf/type/__cinst_partition_msdos/gencode-remote create mode 100644 conf/type/__cinst_partition_msdos/man.text create mode 100755 conf/type/__cinst_partition_msdos/manifest create mode 100644 conf/type/__cinst_partition_msdos/parameter/optional create mode 100644 conf/type/__cinst_partition_msdos/parameter/required diff --git a/conf/type/__cinst_partition_msdos/gencode-remote b/conf/type/__cinst_partition_msdos/gencode-remote new file mode 100755 index 00000000..211bc1db --- /dev/null +++ b/conf/type/__cinst_partition_msdos/gencode-remote @@ -0,0 +1,20 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + diff --git a/conf/type/__cinst_partition_msdos/man.text b/conf/type/__cinst_partition_msdos/man.text new file mode 100644 index 00000000..2203c2d3 --- /dev/null +++ b/conf/type/__cinst_partition_msdos/man.text @@ -0,0 +1,63 @@ +cdist-type__cinst_partition_msdos(7) +==================================== +Steven Armstrong + + +NAME +---- +cdist-type__cinst_partition_msdos - creates msdos partitions + + +DESCRIPTION +----------- +This cdist type allows you to create msdos paritions. + + +REQUIRED PARAMETERS +------------------- +type:: + the partition type used in fdisk (such as 82 or 83) or "extended" + + +OPTIONAL PARAMETERS +------------------- +device:: + defaults to object_id +bootable:: + mark partition as bootable, true or false +size:: + the size of the partition (such as 32MB or 15GB, whole numbers + only), '+' for remaining space, or 'n%' for percentage of remaining + (these should only be used after all specific partition sizes are + specified), leave blank if type is "extended". + Defaults to +. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# 128MB linux, bootable +__cinst_partition_msdos /dev/sda1 --type 83 --size 128M --bootable true +# 512MB swap +__cinst_partition_msdos /dev/sda2 --type 82 --size 512M +# extended +__cinst_partition_msdos /dev/sda3 --type extended +# 10GB, linux +__cinst_partition_msdos /dev/sda5 --type 82 --size 10G +# rest of disk, linux +__cinst_partition_msdos /dev/sda6 --type 82 --size + +# same thing as +__cinst_partition_msdos /dev/sda6 --type 82 +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__cinst_partition_msdos/manifest b/conf/type/__cinst_partition_msdos/manifest new file mode 100755 index 00000000..e5b04c02 --- /dev/null +++ b/conf/type/__cinst_partition_msdos/manifest @@ -0,0 +1,25 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +type + +device +bootable +size diff --git a/conf/type/__cinst_partition_msdos/parameter/optional b/conf/type/__cinst_partition_msdos/parameter/optional new file mode 100644 index 00000000..612fe769 --- /dev/null +++ b/conf/type/__cinst_partition_msdos/parameter/optional @@ -0,0 +1,3 @@ +device +bootable +size diff --git a/conf/type/__cinst_partition_msdos/parameter/required b/conf/type/__cinst_partition_msdos/parameter/required new file mode 100644 index 00000000..aa80e646 --- /dev/null +++ b/conf/type/__cinst_partition_msdos/parameter/required @@ -0,0 +1 @@ +type From 76f07511a9c13eb33565d4af11953a80be67987c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 18 Jul 2011 13:34:39 +0200 Subject: [PATCH 0065/4212] add --state parameter to __file type which allows removal of files Signed-off-by: Steven Armstrong --- conf/type/__file/gencode-local | 31 ++++++++++--------- conf/type/__file/gencode-remote | 46 +++++++++++++++++------------ conf/type/__file/man.text | 18 +++++++---- conf/type/__file/manifest | 27 +++++++++++++++++ conf/type/__file/parameter/optional | 1 + 5 files changed, 85 insertions(+), 38 deletions(-) create mode 100755 conf/type/__file/manifest diff --git a/conf/type/__file/gencode-local b/conf/type/__file/gencode-local index 1168919e..ee198fb1 100755 --- a/conf/type/__file/gencode-local +++ b/conf/type/__file/gencode-local @@ -22,23 +22,26 @@ # destination="/$__object_id" +state_should="$(cat "$__object/parameter/state")" -if [ -f "$__object/parameter/source" ]; then - source="$(cat "$__object/parameter/source")" +if [ "$state_should" = "present" ]; then + if [ -f "$__object/parameter/source" ]; then + source="$(cat "$__object/parameter/source")" - if [ -f "$source" ]; then - local_cksum="$(cksum < "$source")" - remote_cksum="$(cat "$__object/explorer/cksum")" + if [ -f "$source" ]; then + local_cksum="$(cksum < "$source")" + remote_cksum="$(cat "$__object/explorer/cksum")" - if [ "$local_cksum" != "$remote_cksum" ]; then - # FIXME: The username is ugly and hardcoded, replace after 1.0! - # Probably a better aproach is to have the user configured - # ~/.ssh/config to contain the right username - # Probably describe it in cdist-quickstart... - echo scp "$source" "root@${__target_host}:${destination}" + if [ "$local_cksum" != "$remote_cksum" ]; then + # FIXME: The username is ugly and hardcoded, replace after 1.0! + # Probably a better aproach is to have the user configured + # ~/.ssh/config to contain the right username + # Probably describe it in cdist-quickstart... + echo scp "$source" "root@${__target_host}:${destination}" + fi + else + echo "Source \"$source\" does not exist." >&2 + exit 1 fi - else - echo "Source \"$source\" does not exist." >&2 - exit 1 fi fi diff --git a/conf/type/__file/gencode-remote b/conf/type/__file/gencode-remote index 7c5cf7ce..b6e3c095 100755 --- a/conf/type/__file/gencode-remote +++ b/conf/type/__file/gencode-remote @@ -22,25 +22,33 @@ # destination="/$__object_id" +state_should="$(cat "$__object/parameter/state")" +exists="$(cat "$__object/explorer/exists")" -# No source? Create empty file -if [ ! -f "$__object/parameter/source" ]; then - if [ no = "$(cat "$__object/explorer/exists")" ]; then - echo touch \"$destination\" +if [ "$state_should" = "present" ]; then + # No source? Create empty file + if [ ! -f "$__object/parameter/source" ]; then + if [ "$exists" = "no" ]; then + echo touch \"$destination\" + fi + fi + + # Mode settings + if [ -f "$__object/parameter/mode" ]; then + echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" + 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 +elif [ "$state_should" = "absent" ]; then + if [ "$exists" = "yes" ]; then + echo rm \"$destination\" fi fi - -# Mode settings -if [ -f "$__object/parameter/mode" ]; then - echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" -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 diff --git a/conf/type/__file/man.text b/conf/type/__file/man.text index 67ab53d1..fa6b7644 100644 --- a/conf/type/__file/man.text +++ b/conf/type/__file/man.text @@ -5,21 +5,24 @@ Nico Schottelius NAME ---- -cdist-type__file - Create files +cdist-type__file - Manage files DESCRIPTION ----------- -This cdist type allows you to create files on the target. +This cdist type allows you to create files, remove files and set file +attributes on the target. REQUIRED PARAMETERS ------------------- None. - OPTIONAL PARAMETERS ------------------- +state:: + 'present' or 'absent', defaults to 'present' + group:: Group to chgrp to. @@ -40,13 +43,18 @@ EXAMPLES -------------------------------------------------------------------------------- # Create /etc/cdist-configured as an empty file __file /etc/cdist-configured +# The same thing +__file /etc/cdist-configured --ensure present +# Delete existing file +__file /etc/cdist-configured --ensure absent # Use __file from another type -__file /etc/issue --source "$__type/files/archlinux" +__file /etc/issue --source "$__type/files/archlinux" --ensure present # Supply some more settings __file /etc/shadow --source "$__type/files/shadow" \ - --owner root --group shadow --mode 0640 + --owner root --group shadow --mode 0640 \ + --ensure present -------------------------------------------------------------------------------- diff --git a/conf/type/__file/manifest b/conf/type/__file/manifest new file mode 100755 index 00000000..59f10e42 --- /dev/null +++ b/conf/type/__file/manifest @@ -0,0 +1,27 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +name="$__object_id" + +if [ -f "$__object/parameter/state" ]; then + state="$(cat "$__object/parameter/state")" +else + echo "present" > "$__object/parameter/state" +fi diff --git a/conf/type/__file/parameter/optional b/conf/type/__file/parameter/optional index 06120518..c696d592 100644 --- a/conf/type/__file/parameter/optional +++ b/conf/type/__file/parameter/optional @@ -1,3 +1,4 @@ +state group mode owner From 37612ff102f3b87dcce38af667bfb0c8d1a80a51 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 21 Jul 2011 23:06:13 +0200 Subject: [PATCH 0066/4212] add --state parameter to __directory type which allows removal of directories Signed-off-by: Steven Armstrong --- conf/type/__directory/gencode-remote | 76 ++++++++++++++---------- conf/type/__directory/man.text | 10 +++- conf/type/__directory/manifest | 25 ++++++++ conf/type/__directory/parameter/optional | 1 + 4 files changed, 80 insertions(+), 32 deletions(-) create mode 100755 conf/type/__directory/manifest diff --git a/conf/type/__directory/gencode-remote b/conf/type/__directory/gencode-remote index a5458b4b..7fd589be 100755 --- a/conf/type/__directory/gencode-remote +++ b/conf/type/__directory/gencode-remote @@ -25,39 +25,55 @@ # destination="/$__object_id" +state_should="$(cat "$__object/parameter/state")" -# Include parent directories? -if [ -f "$__object/parameter/parents" ]; then - parents="$(cat "$__object/parameter/parents")" - if [ yes = "$parents" ]; then - mkdiropt="-p" - else - mkdiropt="" - fi -fi +case "$state_should" in + present) + # Include parent directories? + if [ -f "$__object/parameter/parents" ]; then + parents="$(cat "$__object/parameter/parents")" + if [ yes = "$parents" ]; then + mkdiropt="-p" + else + mkdiropt="" + fi + fi -if [ -f "$__object/parameter/recursive" ]; then - if [ yes = "$(cat "$__object/parameter/recursive")" ]; then - recursive="-R" - fi -fi + if [ -f "$__object/parameter/recursive" ]; then + if [ yes = "$(cat "$__object/parameter/recursive")" ]; then + recursive="-R" + fi + fi -# Only create if not already existent -if [ no = "$(cat "$__object/explorer/exists")" ]; then - echo mkdir $mkdiropt \"$destination\" -fi + # Only create if not already existent + if [ no = "$(cat "$__object/explorer/exists")" ]; then + echo mkdir $mkdiropt \"$destination\" + fi -# Mode settings -if [ -f "$__object/parameter/mode" ]; then - echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" -fi + # Mode settings + if [ -f "$__object/parameter/mode" ]; then + echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" + fi -# Group -if [ -f "$__object/parameter/group" ]; then - echo chgrp $recursive \"$(cat "$__object/parameter/group")\" \"$destination\" -fi + # Group + if [ -f "$__object/parameter/group" ]; then + echo chgrp $recursive \"$(cat "$__object/parameter/group")\" \"$destination\" + fi -# Owner -if [ -f "$__object/parameter/owner" ]; then - echo chown $recursive \"$(cat "$__object/parameter/owner")\" \"$destination\" -fi + # Owner + if [ -f "$__object/parameter/owner" ]; then + echo chown $recursive \"$(cat "$__object/parameter/owner")\" \"$destination\" + fi + ;; + absent) + # Only delete if it exists + if [ yes = "$(cat "$__object/explorer/exists")" ]; then + echo rm -r \"$destination\" + fi + + ;; + *) + echo "Unknown state" >&2 + exit 1 + ;; +esac diff --git a/conf/type/__directory/man.text b/conf/type/__directory/man.text index e2201172..315d1fb9 100644 --- a/conf/type/__directory/man.text +++ b/conf/type/__directory/man.text @@ -5,12 +5,12 @@ Nico Schottelius NAME ---- -cdist-type__directory - Create a directory +cdist-type__directory - Manage a directory DESCRIPTION ----------- -This cdist type allows you to create directories on the target. +This cdist type allows you to create or remove directories on the target. REQUIRED PARAMETERS @@ -20,6 +20,9 @@ None. OPTIONAL PARAMETERS ------------------- +state:: + 'present' or 'absent', defaults to 'present' + group:: Group to chgrp to. @@ -45,6 +48,9 @@ EXAMPLES # A silly example __directory /tmp/foobar +# Remove a directory +__directory /tmp/foobar --ensure absent + # Ensure /etc exists correctly __directory /etc --owner root --group root --mode 0755 diff --git a/conf/type/__directory/manifest b/conf/type/__directory/manifest new file mode 100755 index 00000000..2fcc085d --- /dev/null +++ b/conf/type/__directory/manifest @@ -0,0 +1,25 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +if [ -f "$__object/parameter/state" ]; then + state="$(cat "$__object/parameter/state")" +else + echo "present" > "$__object/parameter/state" +fi diff --git a/conf/type/__directory/parameter/optional b/conf/type/__directory/parameter/optional index 247e2f64..27f9d76a 100644 --- a/conf/type/__directory/parameter/optional +++ b/conf/type/__directory/parameter/optional @@ -1,3 +1,4 @@ +state group mode owner From 65de5c18883d42844ccb54a4fd245157cb7b5f22 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 22 Jul 2011 00:28:41 +0200 Subject: [PATCH 0067/4212] add --state parameter to __link type which allows removal of links Signed-off-by: Steven Armstrong --- conf/type/__link/gencode-remote | 15 ++++++++++++++- conf/type/__link/man.text | 3 ++- conf/type/__link/manifest | 25 +++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100755 conf/type/__link/manifest diff --git a/conf/type/__link/gencode-remote b/conf/type/__link/gencode-remote index 07da987c..3bfa90d8 100755 --- a/conf/type/__link/gencode-remote +++ b/conf/type/__link/gencode-remote @@ -39,4 +39,17 @@ case "$type" in ;; esac -echo ln ${lnopt} -f \"$source\" \"$destination\" +state_should="$(cat "$__object/parameter/state")" +case "$state_should" in + present) + echo ln ${lnopt} -f \"$source\" \"$destination\" + ;; + absent) + echo rm \"$destination\" + ;; + *) + echo "Unknown state" >&2 + exit 1 + ;; +esac + diff --git a/conf/type/__link/man.text b/conf/type/__link/man.text index fb914298..a7d33c59 100644 --- a/conf/type/__link/man.text +++ b/conf/type/__link/man.text @@ -25,7 +25,8 @@ type:: OPTIONAL PARAMETERS ------------------- -None. +state:: + 'present' or 'absent', defaults to 'present' EXAMPLES diff --git a/conf/type/__link/manifest b/conf/type/__link/manifest new file mode 100755 index 00000000..2fcc085d --- /dev/null +++ b/conf/type/__link/manifest @@ -0,0 +1,25 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +if [ -f "$__object/parameter/state" ]; then + state="$(cat "$__object/parameter/state")" +else + echo "present" > "$__object/parameter/state" +fi From 71c33f4483c1dc89591b070e6b557a08236c3ca1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 22 Jul 2011 00:33:06 +0200 Subject: [PATCH 0068/4212] add forgotten parameter Signed-off-by: Steven Armstrong --- conf/type/__link/parameter/optional | 1 + 1 file changed, 1 insertion(+) create mode 100644 conf/type/__link/parameter/optional diff --git a/conf/type/__link/parameter/optional b/conf/type/__link/parameter/optional new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/conf/type/__link/parameter/optional @@ -0,0 +1 @@ +state From 4836504ad677553abb6eb0ebb804e56dc7e50776 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 22 Jul 2011 00:41:37 +0200 Subject: [PATCH 0069/4212] ignore nonexistent files when deleting Signed-off-by: Steven Armstrong --- conf/type/__file/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__file/gencode-remote b/conf/type/__file/gencode-remote index b6e3c095..ef42dd54 100755 --- a/conf/type/__file/gencode-remote +++ b/conf/type/__file/gencode-remote @@ -49,6 +49,6 @@ if [ "$state_should" = "present" ]; then fi elif [ "$state_should" = "absent" ]; then if [ "$exists" = "yes" ]; then - echo rm \"$destination\" + echo rm -f \"$destination\" fi fi From 2b8d0731a147206fd3e43937e1058a86a5164f67 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 22 Jul 2011 00:42:12 +0200 Subject: [PATCH 0070/4212] ignore nonexistent files when deleting Signed-off-by: Steven Armstrong --- conf/type/__link/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__link/gencode-remote b/conf/type/__link/gencode-remote index 3bfa90d8..bb43de2e 100755 --- a/conf/type/__link/gencode-remote +++ b/conf/type/__link/gencode-remote @@ -45,7 +45,7 @@ case "$state_should" in echo ln ${lnopt} -f \"$source\" \"$destination\" ;; absent) - echo rm \"$destination\" + echo rm -f \"$destination\" ;; *) echo "Unknown state" >&2 From b06f6be5a6d52d9737a0cec37445d423bd4d70d6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 26 Jul 2011 23:39:53 +0200 Subject: [PATCH 0071/4212] begin to re-do __explorer and __global on remote side with functions Signed-off-by: Nico Schottelius --- core/__cdist_explorer_run | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/__cdist_explorer_run b/core/__cdist_explorer_run index a5545faf..db5f2e2c 100755 --- a/core/__cdist_explorer_run +++ b/core/__cdist_explorer_run @@ -39,8 +39,13 @@ __cdist_explorer_run() # Execute all explorers cd "$2"; for __cdist_explorer_run_explorer in *; do - __cdist_run_remote "$3/$__cdist_explorer_run_explorer" ">" \ - "$4/$__cdist_explorer_run_explorer" + #BUG: need to export __explorer to remote side! + #exit 23 + __cdist_run_remote \ + "export $__cdist_name_var_explorer=\"$__cdist_remote_explorer_dir\";" \ + "export $__cdist_name_var_global=\"$__cdist_remote_out_dir\";" \ + "$3/$__cdist_explorer_run_explorer" > \ + "$4/$__cdist_explorer_run_explorer" done # Transfer results back From 666744209e32f7706631b1dc8c3bad1bd96785bd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 26 Jul 2011 23:42:09 +0200 Subject: [PATCH 0072/4212] running explorers works again Signed-off-by: Nico Schottelius --- core/__cdist_explorer_run | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/__cdist_explorer_run b/core/__cdist_explorer_run index db5f2e2c..51e606b1 100755 --- a/core/__cdist_explorer_run +++ b/core/__cdist_explorer_run @@ -41,10 +41,12 @@ __cdist_explorer_run() for __cdist_explorer_run_explorer in *; do #BUG: need to export __explorer to remote side! #exit 23 + # BUG: no need for remote out dir probably? + # or should we leave it and continue using __cdist_dir pull? __cdist_run_remote \ "export $__cdist_name_var_explorer=\"$__cdist_remote_explorer_dir\";" \ "export $__cdist_name_var_global=\"$__cdist_remote_out_dir\";" \ - "$3/$__cdist_explorer_run_explorer" > \ + "$3/$__cdist_explorer_run_explorer" ">" \ "$4/$__cdist_explorer_run_explorer" done From 4a5c161e96a6d0806cfd00923df969cd0cf4de09 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 26 Jul 2011 23:46:05 +0200 Subject: [PATCH 0073/4212] ideas of unit testing Signed-off-by: Nico Schottelius --- test/README | 4 ++++ test/fail_if_explorer_fails.sh | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 test/README create mode 100755 test/fail_if_explorer_fails.sh diff --git a/test/README b/test/README new file mode 100644 index 00000000..ce5cde4d --- /dev/null +++ b/test/README @@ -0,0 +1,4 @@ +This directory should contain unit tests. + +I have not yet searched (or found) a good way to implement this for cdist, +feel free to take the hat. diff --git a/test/fail_if_explorer_fails.sh b/test/fail_if_explorer_fails.sh new file mode 100755 index 00000000..3acfdbeb --- /dev/null +++ b/test/fail_if_explorer_fails.sh @@ -0,0 +1,25 @@ +#!/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 . +# +# + +. cdist-config + +mkdir -p /tmp/cdist/... +__cdist_explorer_run global From cfd0f776c901e47cd317553e2065956ed5db7236 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 27 Jul 2011 00:00:31 +0200 Subject: [PATCH 0074/4212] disable removal of temp data for debugging Signed-off-by: Nico Schottelius --- bin/cdist-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist-config b/bin/cdist-config index bed9e6b4..0c72727f 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -296,7 +296,7 @@ __cdist_remote_type_explorer_dir() # __cdist_tmp_removal() { - rm -rf "${__cdist_tmp_dir}" + echo rm -rf "${__cdist_tmp_dir}" } # Does not work in children, will be called again in every script! From 197fa583b58985505b0320e90355e8a766226d8f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 27 Jul 2011 00:06:24 +0200 Subject: [PATCH 0075/4212] finish global explorer part - works again! Signed-off-by: Nico Schottelius --- core/__cdist_explorer_run | 87 ++++++++++++++------------------------- 1 file changed, 32 insertions(+), 55 deletions(-) diff --git a/core/__cdist_explorer_run b/core/__cdist_explorer_run index 51e606b1..d6cd29c9 100755 --- a/core/__cdist_explorer_run +++ b/core/__cdist_explorer_run @@ -27,8 +27,21 @@ __cdist_explorer_run() [ $# -eq 5 ] || __cdist_usage " " set -x - # Only do something, if there's at least one entry - [ "$(__cdist_dir_listing "$2")" ] || return + # Ensure there is at least one explorer + num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" + if [ "$num" -lt 1 ]; then + __cdist_exit_err "${__cdist_explorer_dir}: Contains no explorers" + fi + + # Check whether to setup variable for type explorer + case "$1" in + global) + ;; + type) + # FIXME: think about how and where this gets setup! + "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" + ;; + esac # Transfer explorers __cdist_dir push "$2" "$3" @@ -38,67 +51,31 @@ __cdist_explorer_run() # Execute all explorers cd "$2"; + # FIXME: cleanup double variable, no need when in directory for __cdist_explorer_run_explorer in *; do - #BUG: need to export __explorer to remote side! - #exit 23 - # BUG: no need for remote out dir probably? + __cdist_explorer_explorer_name="${__cdist_explorer_run_explorer##*/}" + + if [ -f "$__cdist_explorer_run_explorer" ]; then + if [ ! -x "$__cdist_explorer_run_explorer" ]; then + __cdist_exit_err "Explorer \"$__cdist_explorer_run_explorer\" exists, but is not executable." + fi + + else + if [ -e "$__cdist_explorer_run_explorer" ]; then + __cdist_exit_err "Explorer \"$__cdist_explorer_run_explorer\" exists, but is not a file." + fi + fi + + # FIXME: no need for remote out dir probably? # or should we leave it and continue using __cdist_dir pull? __cdist_run_remote \ "export $__cdist_name_var_explorer=\"$__cdist_remote_explorer_dir\";" \ "export $__cdist_name_var_global=\"$__cdist_remote_out_dir\";" \ "$3/$__cdist_explorer_run_explorer" ">" \ - "$4/$__cdist_explorer_run_explorer" + "$4/$__cdist_explorer_run_explorer" || \ + __cdist_exit_err "Explorer $__cdist_explorer_run_explorer failed." done # Transfer results back __cdist_dir pull "$4" "$5" - - return - -# case "$1" in -# global) -# type) -# "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" -# *) -# ;; -# esac - - - # Variable that defines the home of the explorers - # __cdist_variable_name="$1"; shift - - # Find explorers here - __cdist_explorer_dir="$1"; shift - - # Write output here - __cdist_my_out_dir="$1"; shift - - # Setup remote environment - export $__cdist_variable_name="$__cdist_explorer_dir" - export __global="$__cdist_remote_out_dir" - - - # Ensure there is at least one explorer - num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" - if [ "$num" -lt 1 ]; then - __cdist_exit_err "${__cdist_explorer_dir}: Contains no explorers" - fi - - # Execute all explorers - for explorer in "$__cdist_explorer_dir/"*; do - explorer_name="${explorer##*/}" - - if [ -f "$explorer" ]; then - if [ ! -x "$explorer" ]; then - __cdist_exit_err "Explorer \"$explorer\" exists, but is not executable." - fi - - # Execute explorers and save results in remote destination directory - "$explorer" > "${__cdist_my_out_dir}/$explorer_name" - else - if [ -e "$explorer" ]; then - __cdist_exit_err "Explorer \"$explorer\" exists, but is not a file." - fi - fi - done } From 41a0c1dc8ae14964376f89090a3925654eeac025 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 27 Jul 2011 00:07:44 +0200 Subject: [PATCH 0076/4212] cleanup/continue Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 2 +- core/__cdist_explorer_run | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index c48eba57..67bc4ba0 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -53,9 +53,9 @@ __cdist_dir push "${__cdist_abs_mydir}" "${__cdist_remote_bin_dir}" __cdist_dir push "${__cdist_core_dir}" "${__cdist_remote_core_dir}" __cdist_explorer_run_global +__cdist_manifest_run_init exit 1 -__cdist_manifest_run_init __cdist_object_all __cdist_object_prepare __cdist_object_all __cdist_object_run __cdist_cache diff --git a/core/__cdist_explorer_run b/core/__cdist_explorer_run index d6cd29c9..c93b348f 100755 --- a/core/__cdist_explorer_run +++ b/core/__cdist_explorer_run @@ -23,9 +23,7 @@ __cdist_explorer_run() { - # [ $# -eq 3 ] || __cdist_usage " " [ $# -eq 5 ] || __cdist_usage " " - set -x # Ensure there is at least one explorer num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" From 67ba0f7e9ff856342d2048822f6a42af9daccddb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 27 Jul 2011 00:14:04 +0200 Subject: [PATCH 0077/4212] do not use __global directly; manifest run works Signed-off-by: Nico Schottelius --- core/__cdist_manifest_run | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/__cdist_manifest_run b/core/__cdist_manifest_run index 76d0a934..aa8c56e3 100755 --- a/core/__cdist_manifest_run +++ b/core/__cdist_manifest_run @@ -1,6 +1,6 @@ #!/bin/sh # -# 2010 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -39,7 +39,7 @@ __cdist_manifest_run() export __cdist_manifest # Export information for manifests - __cdist_out_dir comes from cdist-config - export __global="$__cdist_out_dir" + export $__cdist_name_var_global="$__cdist_out_dir" ################################################################################ # The actual run From 8ad8ce162fe66f72ccaf04b67ae59bc3e71214cb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 27 Jul 2011 01:03:51 +0200 Subject: [PATCH 0078/4212] -legacy Signed-off-by: Nico Schottelius --- core/__cdist_remote_explorer_run | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/__cdist_remote_explorer_run b/core/__cdist_remote_explorer_run index a7958a41..2fc0f999 100755 --- a/core/__cdist_remote_explorer_run +++ b/core/__cdist_remote_explorer_run @@ -39,10 +39,6 @@ __cdist_remote_explorer_run() # Write output here __cdist_my_out_dir="$1"; shift - # Setup environment - export $__cdist_variable_name="$__cdist_explorer_dir" - export __global="$__cdist_remote_out_dir" - mkdir -p "$__cdist_my_out_dir" # Ensure there is at least one explorer From 6d3053a9bc855e3c2413093a8af08ec3ff583422 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 27 Jul 2011 01:22:54 +0200 Subject: [PATCH 0079/4212] fix type explorer: working again Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 2 +- core/__cdist_object_explorer_run | 40 +++++++++++++++---- core/__cdist_remote_explorer_run | 67 -------------------------------- 3 files changed, 33 insertions(+), 76 deletions(-) delete mode 100755 core/__cdist_remote_explorer_run diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index 67bc4ba0..781c15c4 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -54,9 +54,9 @@ __cdist_dir push "${__cdist_core_dir}" "${__cdist_remote_core_dir}" __cdist_explorer_run_global __cdist_manifest_run_init +__cdist_object_all __cdist_object_prepare exit 1 -__cdist_object_all __cdist_object_prepare __cdist_object_all __cdist_object_run __cdist_cache diff --git a/core/__cdist_object_explorer_run b/core/__cdist_object_explorer_run index 45ca3379..1f266dca 100755 --- a/core/__cdist_object_explorer_run +++ b/core/__cdist_object_explorer_run @@ -22,6 +22,8 @@ # Run the explorers for the given object on the target host. # +# FIXME: many cleanups needed before going production! + __cdist_object_explorer_run() { __cdist_object_self="$1"; shift @@ -49,14 +51,36 @@ __cdist_object_explorer_run() "$(__cdist_remote_object_parameter_dir "$__cdist_object_self")" # Execute explorers - __cdist_run_remote \ - "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" \ - "$__cdist_name_var_object_id=\"$__cdist_object_id\"" \ - "$__cdist_name_var_self=\"$__cdist_object_self\"" \ - cdist-remote-explorer-run \ - "$__cdist_name_var_type_explorer" \ - "$(__cdist_remote_type_explorer_dir "$__cdist_type")" \ - "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" + # FIXME: STOPPED: + # - remove cdist-remote-explorer-run + # - problem: new variables / need to run explorer directly? + # -> or put logic into __cdist_explorer_run + # -> think about having _one_ wrapper script for remote to execute + # shell functions + + # Create remote output directory + __cdist_run_remote mkdir -p "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" + + cd "$(__cdist_type_explorer_dir "$__cdist_type")" + + + for __cdist_object_explorer_run_explorer in *; do + __cdist_run_remote \ + "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" \ + "$__cdist_name_var_object_id=\"$__cdist_object_id\"" \ + "$__cdist_name_var_self=\"$__cdist_object_self\"" \ + "$(__cdist_remote_type_explorer_dir "$__cdist_type")/$__cdist_object_explorer_run_explorer" \ + ">" "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")/$__cdist_object_explorer_run_explorer" + done + +# __cdist_run_remote \ +# "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" \ +# "$__cdist_name_var_object_id=\"$__cdist_object_id\"" \ +# "$__cdist_name_var_self=\"$__cdist_object_self\"" \ +# cdist-remote-explorer-run \ +# "$__cdist_name_var_type_explorer" \ +# "$(__cdist_remote_type_explorer_dir "$__cdist_type")" \ +# "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" # Copy back results __cdist_dir pull "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" \ diff --git a/core/__cdist_remote_explorer_run b/core/__cdist_remote_explorer_run deleted file mode 100755 index 2fc0f999..00000000 --- a/core/__cdist_remote_explorer_run +++ /dev/null @@ -1,67 +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 . -# -# -# This binary is executed on the remote side to execute explorers -# -# It supports different variables names to be used, so __explorers -# and __type_explorers can be submitted :-) -# - -__cdist_remote_explorer_run() -{ - [ $# -eq 3 ] || __cdist_usage " " - - "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" - - # Variable that defines the home of the explorers - __cdist_variable_name="$1"; shift - - # Find explorers here - __cdist_explorer_dir="$1"; shift - - # Write output here - __cdist_my_out_dir="$1"; shift - - mkdir -p "$__cdist_my_out_dir" - - # Ensure there is at least one explorer - num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" - if [ "$num" -lt 1 ]; then - __cdist_exit_err "${__cdist_explorer_dir}: Contains no explorers" - fi - - # Execute all explorers - for explorer in "$__cdist_explorer_dir/"*; do - explorer_name="${explorer##*/}" - - if [ -f "$explorer" ]; then - if [ ! -x "$explorer" ]; then - __cdist_exit_err "Explorer \"$explorer\" exists, but is not executable." - fi - - # Execute explorers and save results in remote destination directory - "$explorer" > "${__cdist_my_out_dir}/$explorer_name" - else - if [ -e "$explorer" ]; then - __cdist_exit_err "Explorer \"$explorer\" exists, but is not a file." - fi - fi - done -} From 3a1bf253981dec555038995a5d09d62bad58fc03 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 27 Jul 2011 01:27:05 +0200 Subject: [PATCH 0080/4212] do not exit if a type does not have explorer :-) Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 2 +- core/__cdist_object_explorer_run | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index 781c15c4..a2f7a2f1 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -55,9 +55,9 @@ __cdist_dir push "${__cdist_core_dir}" "${__cdist_remote_core_dir}" __cdist_explorer_run_global __cdist_manifest_run_init __cdist_object_all __cdist_object_prepare +__cdist_object_all __cdist_object_run exit 1 -__cdist_object_all __cdist_object_run __cdist_cache __cdist_echo info "cdist $__cdist_version: Successfully finished run" diff --git a/core/__cdist_object_explorer_run b/core/__cdist_object_explorer_run index 1f266dca..b082ce0b 100755 --- a/core/__cdist_object_explorer_run +++ b/core/__cdist_object_explorer_run @@ -26,15 +26,16 @@ __cdist_object_explorer_run() { + set -x __cdist_object_self="$1"; shift __cdist_object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" __cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" # Check if type of object has >= 1 explorer - __cdist_has_explorer="$(__cdist_dir_listing "$(__cdist_type_explorer_dir "$__cdist_type")")" + __cdist_has_explorer="$(__cdist_dir_listing "$(__cdist_type_explorer_dir "$__cdist_type")" | wc -l)" # Run the type explorers for the current object if any - if [ "$__cdist_has_explorer" ]; then + if [ "$__cdist_has_explorer" -ge 1 ]; then if ! __cdist_type_explorer_pushed "$__cdist_type"; then # FIXME: variables! src_dir="$(__cdist_type_explorer_dir "$__cdist_type")" From 0c00e4a0d2c07692a8edb069616e3e7e81c26891 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 28 Jul 2011 10:53:58 +0200 Subject: [PATCH 0081/4212] no need for eval here Signed-off-by: Nico Schottelius --- core/__cdist_manifest_run_init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/__cdist_manifest_run_init b/core/__cdist_manifest_run_init index 2d694900..18507252 100755 --- a/core/__cdist_manifest_run_init +++ b/core/__cdist_manifest_run_init @@ -24,7 +24,7 @@ __cdist_manifest_run_init() { - eval export $__cdist_name_var_manifest=\"\$__cdist_manifest_dir\" + export $__cdist_name_var_manifest="$__cdist_manifest_dir" __cdist_echo info "Running initial manifest for $__cdist_target_host " __cdist_manifest_run "$__cdist_manifest_init" From 815de25d9a4c67f89baa66ff463736079ecba12d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 28 Jul 2011 10:54:18 +0200 Subject: [PATCH 0082/4212] continue corelib Signed-off-by: Nico Schottelius --- core/__cdist_object_code_run | 2 +- core/__cdist_object_explorer_run | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/core/__cdist_object_code_run b/core/__cdist_object_code_run index 48b6514d..d2e3b4a3 100755 --- a/core/__cdist_object_code_run +++ b/core/__cdist_object_code_run @@ -24,7 +24,7 @@ __cdist_object_code_run() { - + set -x __cdist_object_code_run_object="$1"; shift # Code local diff --git a/core/__cdist_object_explorer_run b/core/__cdist_object_explorer_run index b082ce0b..da59d6c3 100755 --- a/core/__cdist_object_explorer_run +++ b/core/__cdist_object_explorer_run @@ -26,7 +26,6 @@ __cdist_object_explorer_run() { - set -x __cdist_object_self="$1"; shift __cdist_object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" From 5bb177eef99515d3e23e1c87586ef417ab140962 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 2 Aug 2011 12:05:02 +0200 Subject: [PATCH 0083/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 7c91d865..4198fe3f 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,3 +1,10 @@ +core/__cdist_object_code_run: + make remote run work again + +__cdist_code_run: + should be changed to run _all_ code (has nice checks) + +-------------------------------------------------------------------------------- - run-remote does not work anymore, because there is no binary :-) either make functions available on the other side or put logic on the server side. From 39f1c8a242767046382b17559431489c50b01631 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 2 Aug 2011 12:15:59 +0200 Subject: [PATCH 0084/4212] add two new wrapper to run code and shellcode Signed-off-by: Nico Schottelius --- ...__cdist_exec_fail_on_error => __cdist_run} | 11 +++--- core/__cdist_run_shell | 36 +++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) rename core/{__cdist_exec_fail_on_error => __cdist_run} (77%) create mode 100755 core/__cdist_run_shell diff --git a/core/__cdist_exec_fail_on_error b/core/__cdist_run similarity index 77% rename from core/__cdist_exec_fail_on_error rename to core/__cdist_run index 96e5f056..db9fd8d9 100755 --- a/core/__cdist_exec_fail_on_error +++ b/core/__cdist_run @@ -18,18 +18,15 @@ # along with cdist. If not, see . # # -# Exit if an error occurs +# Exit if an error occurs running something # -__cdist_exec_fail_on_error() +__cdist_run() { set +e - sh -e "$@" + "$@" if [ "$?" -ne 0 ]; then - __cdist_echo error "$1 exited non-zero" - __cdist_echo warn "Faulty code:" - cat "$1" - __cdist_exit_err "Aborting due to non-zero exit code." + __cdist_echo error "$1 exited non-zero, aborting." fi set -e } diff --git a/core/__cdist_run_shell b/core/__cdist_run_shell new file mode 100755 index 00000000..07fb3d65 --- /dev/null +++ b/core/__cdist_run_shell @@ -0,0 +1,36 @@ +#!/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 . +# +# +# Exit if an error occurs when running a shell script +# + +__cdist_run_shell() +{ + set +e + sh -e "$@" + if [ "$?" -ne 0 ]; then + __cdist_echo error "$1 exited non-zero, aborting." + # __cdist_echo error "$1 exited non-zero" + # __cdist_echo warn "Faulty code:" + # cat "$1" + # __cdist_exit_err "Aborting due to non-zero exit code." + fi + set -e +} From 7fab1c9dd91da5460900f3b2cb011a854c3f7d2e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 2 Aug 2011 12:17:48 +0200 Subject: [PATCH 0085/4212] use new wrapper __cdist_run_shell Signed-off-by: Nico Schottelius --- core/__cdist_code_run | 2 +- core/__cdist_manifest_run | 2 +- core/__cdist_object_gencode | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/__cdist_code_run b/core/__cdist_code_run index ca73b02d..eced45af 100755 --- a/core/__cdist_code_run +++ b/core/__cdist_code_run @@ -40,7 +40,7 @@ __cdist_code_run() if [ -f "$__cdist_code" ]; then if [ -x "$__cdist_code" ]; then __cdist_echo info "Executing code-${__cdist_code_type}" - __cdist_exec_fail_on_error "$__cdist_code" + __cdist_run_shell "$__cdist_code" else __cdist_exit_err "$__cdist_code exists, but is not executable." fi diff --git a/core/__cdist_manifest_run b/core/__cdist_manifest_run index aa8c56e3..8bf9cc51 100755 --- a/core/__cdist_manifest_run +++ b/core/__cdist_manifest_run @@ -53,5 +53,5 @@ __cdist_manifest_run() # prepend our path, so all cdist tools come before other tools export PATH="${__cdist_out_type_bin_dir}:$PATH" - __cdist_exec_fail_on_error "${__cdist_manifest}" + __cdist_run_shell "${__cdist_manifest}" } diff --git a/core/__cdist_object_gencode b/core/__cdist_object_gencode index 1024f2c5..08ef8b7d 100755 --- a/core/__cdist_object_gencode +++ b/core/__cdist_object_gencode @@ -43,7 +43,7 @@ __cdist_object_gencode() export __global="$__cdist_out_dir" if [ -x "$__cdist_type_gencode" ]; then - __cdist_exec_fail_on_error "$__cdist_type_gencode" > "$__cdist_tmp_file" + __cdist_run_shell "$__cdist_type_gencode" > "$__cdist_tmp_file" else if [ -e "$__cdist_type_gencode" ]; then __cdist_exit_err "$__cdist_type_gencode exists, but is not executable" From e97854238122a6dfd2db77a96569eb32154d2471 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 2 Aug 2011 15:20:32 +0200 Subject: [PATCH 0086/4212] safer quoting Signed-off-by: Steven Armstrong --- conf/type/__user/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/type/__user/gencode-remote b/conf/type/__user/gencode-remote index 31c93655..c4f9123a 100755 --- a/conf/type/__user/gencode-remote +++ b/conf/type/__user/gencode-remote @@ -55,7 +55,7 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then current_value="$(awk -F: '{ print $ENVIRON["field"] }' < "$file")" if [ "$new_value" != "$current_value" ]; then - set -- "$@" "--$property" \"$new_value\" + set -- "$@" "--$property" \'$new_value\' fi done @@ -67,7 +67,7 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then else for property in $(ls .); do new_value="$(cat "$property")" - set -- "$@" "--$property" \"$new_value\" + set -- "$@" "--$property" \'$new_value\' done echo useradd "$@" "$name" From 2926532560a27586d414371432ca8cc24d5d4adb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Aug 2011 17:14:38 +0200 Subject: [PATCH 0087/4212] begin to merge __cdist_object_code_run and __cdist_code_run Signed-off-by: Nico Schottelius --- core/__cdist_code_run | 54 ------------------------------- core/__cdist_object_code_run | 62 ++++++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 56 deletions(-) delete mode 100755 core/__cdist_code_run diff --git a/core/__cdist_code_run b/core/__cdist_code_run deleted file mode 100755 index eced45af..00000000 --- a/core/__cdist_code_run +++ /dev/null @@ -1,54 +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 . -# -# -# This binary is executed on the remote side to execute code -# - -__cdist_code_run() -{ - [ $# -eq 2 ] || __cdist_usage " " - - __cdist_object_self="$1"; shift - __cdist_code_type="$1"; shift - - if [ ! -d "$(__cdist_object_dir "$__cdist_object_self")" ]; then - __cdist_exit_err "Object undefined" - fi - - __cdist_code="$(__cdist_object_code "$__cdist_object_self" "${__cdist_code_type}")" - - __cdist_echo info "Checking code-${__cdist_code_type}" - - if [ -e "$__cdist_code" ]; then - if [ -f "$__cdist_code" ]; then - if [ -x "$__cdist_code" ]; then - __cdist_echo info "Executing code-${__cdist_code_type}" - __cdist_run_shell "$__cdist_code" - else - __cdist_exit_err "$__cdist_code exists, but is not executable." - fi - else - __cdist_exit_err "$__cdist_code exists, but is not a file." - fi - fi - - # Exit gracefully if nothing is todo - true -} diff --git a/core/__cdist_object_code_run b/core/__cdist_object_code_run index d2e3b4a3..42e28a6a 100755 --- a/core/__cdist_object_code_run +++ b/core/__cdist_object_code_run @@ -32,6 +32,64 @@ __cdist_object_code_run() __cdist_code_run "$__cdist_object_code_run_object" "${__cdist_name_gencode_local}" # Code remote - __cdist_run_remote "__cdist_code_run" \ - "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}" + #__cdist_run_remote "__cdist_code_run" \ + # "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}" + __cdist_run_remote "echo" "__cdist_code_run" \ + "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}; exit 1" +} + + +#!/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 . +# +# +# This binary is executed on the remote side to execute code +# + +__cdist_code_run() +{ + [ $# -eq 2 ] || __cdist_usage " " + + __cdist_object_self="$1"; shift + __cdist_code_type="$1"; shift + + if [ ! -d "$(__cdist_object_dir "$__cdist_object_self")" ]; then + __cdist_exit_err "Object undefined" + fi + + __cdist_code="$(__cdist_object_code "$__cdist_object_self" "${__cdist_code_type}")" + + __cdist_echo info "Checking code-${__cdist_code_type}" + + if [ -e "$__cdist_code" ]; then + if [ -f "$__cdist_code" ]; then + if [ -x "$__cdist_code" ]; then + __cdist_echo info "Executing code-${__cdist_code_type}" + __cdist_run_shell "$__cdist_code" + else + __cdist_exit_err "$__cdist_code exists, but is not executable." + fi + else + __cdist_exit_err "$__cdist_code exists, but is not a file." + fi + fi + + # Exit gracefully if nothing is todo + true } From 07dc79410a9762fed88aaee60c29929594c119f8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Aug 2011 17:18:35 +0200 Subject: [PATCH 0088/4212] add template for script that only runs if the file exists Signed-off-by: Nico Schottelius --- core/__cdist_run_if_exists | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100755 core/__cdist_run_if_exists diff --git a/core/__cdist_run_if_exists b/core/__cdist_run_if_exists new file mode 100755 index 00000000..d8c63d0d --- /dev/null +++ b/core/__cdist_run_if_exists @@ -0,0 +1,69 @@ +#!/bin/sh +# +# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 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 . +# +# +# Exec the code for the given object locally and remote +# + +__cdist_object_code_run() +{ + set -x + __cdist_object_code_run_object="$1"; shift + + # Code local + export __cdist_out_object_dir="$__cdist_out_object_dir" + __cdist_code_run "$__cdist_object_code_run_object" "${__cdist_name_gencode_local}" + + # Code remote + #__cdist_run_remote "__cdist_code_run" \ + # "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}" + __cdist_run_remote "echo" "__cdist_code_run" \ + "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}; exit 1" + + + # [ $# -eq 2 ] || __cdist_usage " " + + __cdist_object_code_run_object="$1"; shift + __cdist_code_type="$1"; shift + + if [ ! -d "$(__cdist_object_dir "$__cdist_object_code_run_object")" ]; then + __cdist_exit_err "Object undefined" + fi + + __cdist_code="$(__cdist_object_code "$__cdist_object_code_run_object" "${__cdist_code_type}")" + + __cdist_echo info "Checking code-${__cdist_code_type}" + + if [ -e "$__cdist_code" ]; then + if [ -f "$__cdist_code" ]; then + if [ -x "$__cdist_code" ]; then + __cdist_echo info "Executing code-${__cdist_code_type}" + __cdist_run_shell "$__cdist_code" + else + __cdist_exit_err "$__cdist_code exists, but is not executable." + fi + else + __cdist_exit_err "$__cdist_code exists, but is not a file." + fi + fi + + # Exit gracefully if nothing is todo + true +} From f6d7a3e4783a49e9451ede47442528e5d8f12e15 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Aug 2011 17:18:49 +0200 Subject: [PATCH 0089/4212] and give it a good name Signed-off-by: Nico Schottelius --- core/{__cdist_run_if_exists => __cdist_run_if_executable} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core/{__cdist_run_if_exists => __cdist_run_if_executable} (100%) diff --git a/core/__cdist_run_if_exists b/core/__cdist_run_if_executable similarity index 100% rename from core/__cdist_run_if_exists rename to core/__cdist_run_if_executable From bd39d5c185c9d23a78da8ae64f41d6d83e78959f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Aug 2011 17:23:05 +0200 Subject: [PATCH 0090/4212] finish __cdist_run_if_executable Signed-off-by: Nico Schottelius --- core/__cdist_run_if_executable | 46 ++++++++-------------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/core/__cdist_run_if_executable b/core/__cdist_run_if_executable index d8c63d0d..86732742 100755 --- a/core/__cdist_run_if_executable +++ b/core/__cdist_run_if_executable @@ -1,7 +1,6 @@ #!/bin/sh # -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -22,45 +21,22 @@ # Exec the code for the given object locally and remote # -__cdist_object_code_run() +__cdist_run_if_executable() { - set -x - __cdist_object_code_run_object="$1"; shift + [ $# -gt 1 ] || __cdist_exit_err " " - # Code local - export __cdist_out_object_dir="$__cdist_out_object_dir" - __cdist_code_run "$__cdist_object_code_run_object" "${__cdist_name_gencode_local}" + __cdist_run_if_executable_exec="$1"; shift - # Code remote - #__cdist_run_remote "__cdist_code_run" \ - # "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}" - __cdist_run_remote "echo" "__cdist_code_run" \ - "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}; exit 1" - - - # [ $# -eq 2 ] || __cdist_usage " " - - __cdist_object_code_run_object="$1"; shift - __cdist_code_type="$1"; shift - - if [ ! -d "$(__cdist_object_dir "$__cdist_object_code_run_object")" ]; then - __cdist_exit_err "Object undefined" - fi - - __cdist_code="$(__cdist_object_code "$__cdist_object_code_run_object" "${__cdist_code_type}")" - - __cdist_echo info "Checking code-${__cdist_code_type}" - - if [ -e "$__cdist_code" ]; then - if [ -f "$__cdist_code" ]; then - if [ -x "$__cdist_code" ]; then - __cdist_echo info "Executing code-${__cdist_code_type}" - __cdist_run_shell "$__cdist_code" + if [ -e "$__cdist_run_if_executable_exec" ]; then + if [ -f "$__cdist_run_if_executable_exec" ]; then + if [ -x "$__cdist_run_if_executable_exec" ]; then + __cdist_echo debug "Running $@ ..." + "$@" else - __cdist_exit_err "$__cdist_code exists, but is not executable." + __cdist_exit_err "$__cdist_run_if_executable_exec exists, but is not executable." fi else - __cdist_exit_err "$__cdist_code exists, but is not a file." + __cdist_exit_err "$__cdist_run_if_executable_exec exists, but is not a file." fi fi From 8daa07acbf10e3a5c8710d14d7743260659f2479 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Aug 2011 17:38:59 +0200 Subject: [PATCH 0091/4212] only check, do not run Signed-off-by: Nico Schottelius --- core/{__cdist_run_if_executable => __cdist_is_executable} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core/{__cdist_run_if_executable => __cdist_is_executable} (100%) diff --git a/core/__cdist_run_if_executable b/core/__cdist_is_executable similarity index 100% rename from core/__cdist_run_if_executable rename to core/__cdist_is_executable From 5c35cad4770e0ac36d631ce940170c6e1fbe1871 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Aug 2011 17:39:21 +0200 Subject: [PATCH 0092/4212] cleanups Signed-off-by: Nico Schottelius --- core/__cdist_is_executable | 26 ++++++------- core/__cdist_object_code_run | 75 +++++++----------------------------- core/__cdist_run_shell | 9 ++--- 3 files changed, 30 insertions(+), 80 deletions(-) diff --git a/core/__cdist_is_executable b/core/__cdist_is_executable index 86732742..f2907922 100755 --- a/core/__cdist_is_executable +++ b/core/__cdist_is_executable @@ -21,25 +21,23 @@ # Exec the code for the given object locally and remote # -__cdist_run_if_executable() +__cdist_is_executable() { - [ $# -gt 1 ] || __cdist_exit_err " " + [ $# -eq 1 ] || __cdist_exit_err "" - __cdist_run_if_executable_exec="$1"; shift - - if [ -e "$__cdist_run_if_executable_exec" ]; then - if [ -f "$__cdist_run_if_executable_exec" ]; then - if [ -x "$__cdist_run_if_executable_exec" ]; then - __cdist_echo debug "Running $@ ..." - "$@" + if [ -e "$1" ]; then + if [ -f "$1" ]; then + if [ -x "$1" ]; then + # Exists and is a correct executable + true else - __cdist_exit_err "$__cdist_run_if_executable_exec exists, but is not executable." + __cdist_exit_err "$1 exists, but is not executable." fi else - __cdist_exit_err "$__cdist_run_if_executable_exec exists, but is not a file." + __cdist_exit_err "$1 exists, but is not a file." fi + else + # Does not exist + false fi - - # Exit gracefully if nothing is todo - true } diff --git a/core/__cdist_object_code_run b/core/__cdist_object_code_run index 42e28a6a..53442bbe 100755 --- a/core/__cdist_object_code_run +++ b/core/__cdist_object_code_run @@ -24,72 +24,25 @@ __cdist_object_code_run() { + [ $# -eq 1 ] || __cdist_exit_err "" + set -x - __cdist_object_code_run_object="$1"; shift - # Code local - export __cdist_out_object_dir="$__cdist_out_object_dir" - __cdist_code_run "$__cdist_object_code_run_object" "${__cdist_name_gencode_local}" - - # Code remote - #__cdist_run_remote "__cdist_code_run" \ - # "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}" - __cdist_run_remote "echo" "__cdist_code_run" \ - "$__cdist_object_code_run_object" "${__cdist_name_gencode_remote}; exit 1" -} - - -#!/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 . -# -# -# This binary is executed on the remote side to execute code -# - -__cdist_code_run() -{ - [ $# -eq 2 ] || __cdist_usage " " - - __cdist_object_self="$1"; shift - __cdist_code_type="$1"; shift - - if [ ! -d "$(__cdist_object_dir "$__cdist_object_self")" ]; then + if [ ! -d "$(__cdist_object_dir "$1")" ]; then __cdist_exit_err "Object undefined" fi - __cdist_code="$(__cdist_object_code "$__cdist_object_self" "${__cdist_code_type}")" - - __cdist_echo info "Checking code-${__cdist_code_type}" - - if [ -e "$__cdist_code" ]; then - if [ -f "$__cdist_code" ]; then - if [ -x "$__cdist_code" ]; then - __cdist_echo info "Executing code-${__cdist_code_type}" - __cdist_run_shell "$__cdist_code" - else - __cdist_exit_err "$__cdist_code exists, but is not executable." - fi - else - __cdist_exit_err "$__cdist_code exists, but is not a file." - fi + # Code local + export __cdist_out_object_dir="$__cdist_out_object_dir" + if __cdist_is_executable \ + "$(__cdist_object_code "$1" "${__cdist_name_gencode_local}")"; then + __cdist_run_shell \ + "$(__cdist_object_code "$1" "${__cdist_name_gencode_local}")" fi - # Exit gracefully if nothing is todo - true + # Code remote + if __cdist_is_executable \ + "$(__cdist_object_code "$1" "${__cdist_name_gencode_remote}")"; then + + fi } diff --git a/core/__cdist_run_shell b/core/__cdist_run_shell index 07fb3d65..fecfba70 100755 --- a/core/__cdist_run_shell +++ b/core/__cdist_run_shell @@ -26,11 +26,10 @@ __cdist_run_shell() set +e sh -e "$@" if [ "$?" -ne 0 ]; then - __cdist_echo error "$1 exited non-zero, aborting." - # __cdist_echo error "$1 exited non-zero" - # __cdist_echo warn "Faulty code:" - # cat "$1" - # __cdist_exit_err "Aborting due to non-zero exit code." + __cdist_echo error "$1 exited non-zero" + __cdist_echo warn "Faulty code:" + cat "$1" + __cdist_exit_err "Aborting due to non-zero exit code." fi set -e } From f6fac37f1d81c603c7322ed5425413527048496c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Aug 2011 17:50:38 +0200 Subject: [PATCH 0093/4212] successfully run remote code! Signed-off-by: Nico Schottelius --- bin/cdist-config | 7 +++++++ core/__cdist_object_code_run | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/bin/cdist-config b/bin/cdist-config index 0c72727f..adfd7bd8 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -274,6 +274,13 @@ __cdist_remote_object_dir() echo "$(__cdist_remote_object_base_dir "$1")/${__cdist_name_dot_cdist}" } +__cdist_remote_object_code() +{ + # FIXME: this should probably be __cdist_name_CODE_remote instead, although + # they have the same name always + echo "$(__cdist_remote_object_dir "$1")/${__cdist_name_code}-${__cdist_name_gencode_remote}" +} + __cdist_remote_object_parameter_dir() { echo "$(__cdist_remote_object_dir "$1")/${__cdist_name_parameter}" diff --git a/core/__cdist_object_code_run b/core/__cdist_object_code_run index 53442bbe..734db5c9 100755 --- a/core/__cdist_object_code_run +++ b/core/__cdist_object_code_run @@ -26,7 +26,7 @@ __cdist_object_code_run() { [ $# -eq 1 ] || __cdist_exit_err "" - set -x + # set -x if [ ! -d "$(__cdist_object_dir "$1")" ]; then __cdist_exit_err "Object undefined" @@ -44,5 +44,7 @@ __cdist_object_code_run() if __cdist_is_executable \ "$(__cdist_object_code "$1" "${__cdist_name_gencode_remote}")"; then + __cdist_run_remote $(__cdist_remote_object_code "$1") fi + # set +x } From 765c3d152a6cee58ddf153fae040a019e360f508 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Aug 2011 17:51:51 +0200 Subject: [PATCH 0094/4212] allow cache to function again Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index a2f7a2f1..e76564f4 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -56,7 +56,6 @@ __cdist_explorer_run_global __cdist_manifest_run_init __cdist_object_all __cdist_object_prepare __cdist_object_all __cdist_object_run -exit 1 __cdist_cache From 4ab6c5bbc9d57b75ca925a79dbfe49ea336791b5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Aug 2011 17:53:25 +0200 Subject: [PATCH 0095/4212] cleanup object naming in cache handling Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index e76564f4..49c8a6fc 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -56,6 +56,7 @@ __cdist_explorer_run_global __cdist_manifest_run_init __cdist_object_all __cdist_object_prepare __cdist_object_all __cdist_object_run +unset __cdist_object_self __cdist_cache From 49bad52715626570cbe43ddb0878d9750c7c990e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Aug 2011 17:54:28 +0200 Subject: [PATCH 0096/4212] remove debug Signed-off-by: Nico Schottelius --- core/__cdist_object_run | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/__cdist_object_run b/core/__cdist_object_run index 7f08f192..0e0da80f 100755 --- a/core/__cdist_object_run +++ b/core/__cdist_object_run @@ -54,12 +54,9 @@ __cdist_object_run() __cdist_requirement="$1"; shift __cdist_echo info "Resolving requirement $__cdist_requirement" __cdist_object_run "$__cdist_requirement" - echo "done run" done fi - echo "after done" - __cdist_object_gencode_run "$__cdist_object_self" __cdist_dir push "$(__cdist_object_dir "$__cdist_object_self")" \ "$(__cdist_remote_object_dir "$__cdist_object_self")" From cb3b16d63fde03b162030c0e02fecf85598176bc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Aug 2011 08:45:44 +0200 Subject: [PATCH 0097/4212] -obsolete script Signed-off-by: Nico Schottelius --- bin/cdist-remote | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100755 bin/cdist-remote diff --git a/bin/cdist-remote b/bin/cdist-remote deleted file mode 100755 index 0a730a6e..00000000 --- a/bin/cdist-remote +++ /dev/null @@ -1,26 +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 . -# -# -# This scripts runs functions or binaries remotely -# - -. cdist-config - -"$@" From a4f45dfcf4555ea3e4b4a43fdea1e193ca15271a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Aug 2011 08:52:06 +0200 Subject: [PATCH 0098/4212] go back to production mode and enable rm -rf Signed-off-by: Nico Schottelius --- bin/cdist-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist-config b/bin/cdist-config index adfd7bd8..d10f1ac7 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -303,7 +303,7 @@ __cdist_remote_type_explorer_dir() # __cdist_tmp_removal() { - echo rm -rf "${__cdist_tmp_dir}" + rm -rf "${__cdist_tmp_dir}" } # Does not work in children, will be called again in every script! From c70bfb2e207631c9137e5c8dc89cb2c45f0ff2ae Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Aug 2011 15:55:55 +0200 Subject: [PATCH 0099/4212] cleanup for correct working in function environment Signed-off-by: Nico Schottelius --- core/__cdist_type_build_emulation | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/__cdist_type_build_emulation b/core/__cdist_type_build_emulation index a6cfcaa6..5457c99b 100755 --- a/core/__cdist_type_build_emulation +++ b/core/__cdist_type_build_emulation @@ -22,9 +22,8 @@ __cdist_type_build_emulation() { - [ $# -eq 1 ] || __cdist_usage "" + [ $# -eq 0 ] || __cdist_usage "No arguments" - __cdist_output_dir="$1"; shift __cdist_type_emulator="$__cdist_abs_mydir/cdist-type-emulator" if [ ! -d "${__cdist_type_dir}" ]; then @@ -32,12 +31,15 @@ __cdist_type_build_emulation() fi # Get Types - cd "${__cdist_type_dir}" - ls -1 > "${__cdist_tmp_file}" + ( + cd "${__cdist_type_dir}" + ls -1 > "${__cdist_tmp_file}" + ) # Create binaries - mkdir -p "${__cdist_output_dir}" - while read type; do - ln -sf "${__cdist_type_emulator}" "${__cdist_output_dir}/${type}" + mkdir -p "${__cdist_out_type_bin_dir}" + while read __cdist_type_build_emulation_type; do + ln -sf "${__cdist_type_emulator}" \ + "${__cdist_out_type_bin_dir}/${__cdist_type_build_emulation_type}" done < "${__cdist_tmp_file}" } From f8595793c194d6615afd8b69d2cfb7f8b82e9b28 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Aug 2011 16:00:06 +0200 Subject: [PATCH 0100/4212] cleanup caching function Signed-off-by: Nico Schottelius --- core/__cdist_cache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/__cdist_cache b/core/__cdist_cache index 44c60125..95764d3d 100755 --- a/core/__cdist_cache +++ b/core/__cdist_cache @@ -27,7 +27,7 @@ __cdist_cache() mkdir -p "${__cdist_local_base_cache_dir}" __cdist_echo info \ - "Saving cache to $(__cdist_host_cache_dir "$__cdist_target_host")" + "Caching to $(__cdist_host_cache_dir "$__cdist_target_host")" rm -rf "$(__cdist_host_cache_dir "$__cdist_target_host")" mv "$__cdist_local_base_dir" \ "$(__cdist_host_cache_dir "$__cdist_target_host")" From b5b8bdc016e5098dde77251462a3eb024c987bb9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Aug 2011 16:03:12 +0200 Subject: [PATCH 0101/4212] cleanup __cdist_dir Signed-off-by: Nico Schottelius --- core/__cdist_dir | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/core/__cdist_dir b/core/__cdist_dir index 2f08a95c..32ee0075 100755 --- a/core/__cdist_dir +++ b/core/__cdist_dir @@ -23,29 +23,24 @@ # Pull a directory from a target, both sides have the same name (i.e. explorers) # - __cdist_dir() { [ $# -eq 3 ] || __cdist_usage " " - __cdist_dir_action="$1"; shift - __cdist_dir_src="$1"; shift - __cdist_dir_dst="$1"; shift - - # This will be the destination directory, so no subdirectories + # ${3%/*} will be the destination directory, so no subdirectories # of the same name are created, if the directory is already existing - __cdist_dir_top="${__cdist_dir_dst%/*}" - if [ "$__cdist_dir_action" = "push" ]; then + if [ "$1" = "push" ]; then + # FIXME: add error handling with __cdist_run_remote_... or so ssh "${__cdist_remote_user}@${__cdist_target_host}" \ - "mkdir -p \"${__cdist_dir_dst}\"" - scp -qr "$__cdist_dir_src" \ - "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_dir_top}" - elif [ "$__cdist_dir_action" = "pull" ]; then - mkdir -p "${__cdist_dir_dst}" - scp -qr "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_dir_src}" \ - "${__cdist_dir_top}" + "mkdir -p \"$3\"" + scp -qr "$2" \ + "${__cdist_remote_user}@${__cdist_target_host}:${3%/*}" + elif [ "$1" = "pull" ]; then + mkdir -p "$3" + scp -qr "${__cdist_remote_user}@${__cdist_target_host}:$2" \ + "${3%/*}" else - __cdist_exit_err "Unknown action $__cdist_dir_action" + __cdist_exit_err "Unknown action $1" fi } From c9f4455677466aa09b3bc337c4207457e99344fa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Aug 2011 16:11:08 +0200 Subject: [PATCH 0102/4212] less todo Signed-off-by: Nico Schottelius --- core/__cdist_explorer_run | 4 ++-- doc/dev/todo/niconext | 33 --------------------------------- 2 files changed, 2 insertions(+), 35 deletions(-) diff --git a/core/__cdist_explorer_run b/core/__cdist_explorer_run index c93b348f..9e58fa09 100755 --- a/core/__cdist_explorer_run +++ b/core/__cdist_explorer_run @@ -18,7 +18,7 @@ # along with cdist. If not, see . # # -# Run explorers +# Run explorers - FIXME: this function is ugly # __cdist_explorer_run() @@ -47,7 +47,7 @@ __cdist_explorer_run() # Create output directory __cdist_run_remote mkdir -p "$4" - # Execute all explorers + # Execute all explorers - FIXME: isolate cd call? cd "$2"; # FIXME: cleanup double variable, no need when in directory for __cdist_explorer_run_explorer in *; do diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index d37658ea..3c3300e1 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,36 +1,3 @@ -core/__cdist_object_code_run: - make remote run work again - -__cdist_code_run: - should be changed to run _all_ code (has nice checks) - --------------------------------------------------------------------------------- -- run-remote does not work anymore, because there is no binary :-) - either make functions available on the other side or - put logic on the server side. - - - trying to run type explorers nicely from local side - - must check whether type directory has been transmitted before! - --------------------------------------------------------------------------------- - - - - Both type and global have... - - local sourcedir - - remote destination dir - - remote out dir - - local out dir - - - Differences are in... - - variables exposed / submitted - - - - -Catch broken instances in cdist-mass-deploy -p and report broken deployements at the end! - - --------------------------------------------------------------------------------- Bug with requirements when indirect requires is scheduled late: __package/collectd: Generating local code From 97e8c431af3dabc638835be38a3cc13fab9e5c95 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Aug 2011 16:15:10 +0200 Subject: [PATCH 0103/4212] only build emulator binaries once Signed-off-by: Nico Schottelius --- core/__cdist_type_build_emulation | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/__cdist_type_build_emulation b/core/__cdist_type_build_emulation index 5457c99b..3c7270ca 100755 --- a/core/__cdist_type_build_emulation +++ b/core/__cdist_type_build_emulation @@ -24,6 +24,8 @@ __cdist_type_build_emulation() { [ $# -eq 0 ] || __cdist_usage "No arguments" + [ -f "${__cdist_out_type_bin_dir}/.marker" ] && return 0 + __cdist_type_emulator="$__cdist_abs_mydir/cdist-type-emulator" if [ ! -d "${__cdist_type_dir}" ]; then @@ -42,4 +44,6 @@ __cdist_type_build_emulation() ln -sf "${__cdist_type_emulator}" \ "${__cdist_out_type_bin_dir}/${__cdist_type_build_emulation_type}" done < "${__cdist_tmp_file}" + + touch "${__cdist_out_type_bin_dir}/.marker" } From 160d85dee1e0bdc92a1cdecfe9259f139d0f5c87 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Aug 2011 16:17:15 +0200 Subject: [PATCH 0104/4212] only setup path when executing something, not generally Signed-off-by: Nico Schottelius --- core/__cdist_is_executable | 3 ++- core/__cdist_manifest_run | 6 +----- core/__cdist_run_shell | 3 ++- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/core/__cdist_is_executable b/core/__cdist_is_executable index f2907922..a7a6d174 100755 --- a/core/__cdist_is_executable +++ b/core/__cdist_is_executable @@ -18,7 +18,8 @@ # along with cdist. If not, see . # # -# Exec the code for the given object locally and remote +# Test whether something is executable (that should be executable) or +# is missing # __cdist_is_executable() diff --git a/core/__cdist_manifest_run b/core/__cdist_manifest_run index 8bf9cc51..60d3fea3 100755 --- a/core/__cdist_manifest_run +++ b/core/__cdist_manifest_run @@ -45,13 +45,9 @@ __cdist_manifest_run() # The actual run # - # Ensure binaries exist and are up-to-date - # FIXME: do only once! no need to check for every manifest! + # Ensure binaries are existing __cdist_type_build_emulation "${__cdist_out_type_bin_dir}" \ || __cdist_exit_err "Failed to build type emulation binaries" - # prepend our path, so all cdist tools come before other tools - export PATH="${__cdist_out_type_bin_dir}:$PATH" - __cdist_run_shell "${__cdist_manifest}" } diff --git a/core/__cdist_run_shell b/core/__cdist_run_shell index fecfba70..1d76e17b 100755 --- a/core/__cdist_run_shell +++ b/core/__cdist_run_shell @@ -24,7 +24,8 @@ __cdist_run_shell() { set +e - sh -e "$@" + # Prepend our path, so all cdist tools come before other tools + PATH="${__cdist_out_type_bin_dir}:$PATH" sh -e "$@" if [ "$?" -ne 0 ]; then __cdist_echo error "$1 exited non-zero" __cdist_echo warn "Faulty code:" From 8fe9e862541b336e5708bce4ca09531061aa800b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Aug 2011 16:18:20 +0200 Subject: [PATCH 0105/4212] add prefix to variable name Signed-off-by: Nico Schottelius --- core/__cdist_manifest_run_init | 1 + core/__cdist_object_all | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/__cdist_manifest_run_init b/core/__cdist_manifest_run_init index 18507252..e8fa63de 100755 --- a/core/__cdist_manifest_run_init +++ b/core/__cdist_manifest_run_init @@ -24,6 +24,7 @@ __cdist_manifest_run_init() { + # FIXME: probably do not export but always set explicitly? export $__cdist_name_var_manifest="$__cdist_manifest_dir" __cdist_echo info "Running initial manifest for $__cdist_target_host " diff --git a/core/__cdist_object_all b/core/__cdist_object_all index 52661073..f9c505ff 100755 --- a/core/__cdist_object_all +++ b/core/__cdist_object_all @@ -26,7 +26,7 @@ __cdist_object_all() { [ $# -eq 1 ] || __cdist_usage "" - __cdist_command="$1"; shift + __cdist_object_all_command="$1"; shift __cdist_objects="$__cdist_tmp_dir/objects" @@ -50,7 +50,7 @@ __cdist_object_all() while [ $# -gt 0 ]; do __cdist_object="$1"; shift - $__cdist_command "$__cdist_object" + $__cdist_object_all_command "$__cdist_object" done done } From 8dbe6f9c77d455ac2babb65e7c9ba83ad6c3cc67 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Aug 2011 16:20:24 +0200 Subject: [PATCH 0106/4212] add prefix to variable name [once more] Signed-off-by: Nico Schottelius --- core/__cdist_object_all | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/core/__cdist_object_all b/core/__cdist_object_all index f9c505ff..59457e3c 100755 --- a/core/__cdist_object_all +++ b/core/__cdist_object_all @@ -22,35 +22,36 @@ # Run the given command for each created object. # -__cdist_object_all() +__cdist_object_all_object_all() { [ $# -eq 1 ] || __cdist_usage "" - __cdist_object_all_command="$1"; shift + __cdist_object_all_object_all_command="$1"; shift - __cdist_objects="$__cdist_tmp_dir/objects" + __cdist_object_all_object_all_objects="$__cdist_tmp_dir/objects" # Ensure object dir exists, so marker can be created mkdir -p "${__cdist_out_object_dir}" # Loop until we do not create new objects anymore # which is equal to all objects have been run - touch "$__cdist_objects_created" - while [ -f "$__cdist_objects_created" ]; do + touch "$__cdist_object_all_object_all_objects_created" + while [ -f "$__cdist_object_all_object_all_objects_created" ]; do # Assume we're done after this run - rm "$__cdist_objects_created" + rm "$__cdist_object_all_object_all_objects_created" # Get listing of objects - __cdist_object_list "$__cdist_out_object_dir" > "$__cdist_objects" + __cdist_object_all_object_list "$__cdist_out_object_dir" > \ + "$__cdist_object_all_object_all_objects" # NEED TO CREATE ARRAY, SSH DESTROYS WHILE READ LOOP - while read __cdist_object; do - set -- "$@" "$__cdist_object" - done < "$__cdist_objects" + while read __cdist_object_all_object; do + set -- "$@" "$__cdist_object_all_object" + done < "$__cdist_object_all_object_all_objects" while [ $# -gt 0 ]; do - __cdist_object="$1"; shift - $__cdist_object_all_command "$__cdist_object" + __cdist_object_all_object="$1"; shift + $__cdist_object_all_object_all_command "$__cdist_object_all_object" done done } From bbe0d4a5db592d8fe2568314244d59250aed8f69 Mon Sep 17 00:00:00 2001 From: nuex Date: Wed, 17 Aug 2011 09:21:00 -0400 Subject: [PATCH 0107/4212] __package_rubygem --- .../__package_rubygem/explorer/pkg_status | 30 +++++++++++ conf/type/__package_rubygem/gencode-remote | 51 +++++++++++++++++++ conf/type/__package_rubygem/man.text | 49 ++++++++++++++++++ .../type/__package_rubygem/parameter/optional | 2 + .../type/__package_rubygem/parameter/required | 1 + 5 files changed, 133 insertions(+) create mode 100755 conf/type/__package_rubygem/explorer/pkg_status create mode 100755 conf/type/__package_rubygem/gencode-remote create mode 100644 conf/type/__package_rubygem/man.text create mode 100644 conf/type/__package_rubygem/parameter/optional create mode 100644 conf/type/__package_rubygem/parameter/required diff --git a/conf/type/__package_rubygem/explorer/pkg_status b/conf/type/__package_rubygem/explorer/pkg_status new file mode 100755 index 00000000..97620892 --- /dev/null +++ b/conf/type/__package_rubygem/explorer/pkg_status @@ -0,0 +1,30 @@ +#!/bin/sh +# +# 2011 Chase Allen James (nx-cdist@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 . +# +# Retrieve the status of a rubygem +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +# Except gem failing, if package is not known / installed +gem list -i "$name" 2>/dev/null || exit 0 diff --git a/conf/type/__package_rubygem/gencode-remote b/conf/type/__package_rubygem/gencode-remote new file mode 100755 index 00000000..dfc08781 --- /dev/null +++ b/conf/type/__package_rubygem/gencode-remote @@ -0,0 +1,51 @@ +#!/bin/sh +# +# 2011 Chase Allen James +# +# 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 Rubygem packages +# + + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +state="$(cat "$__object/parameter/state")" +is_installed="$(grep "true" "$__object/explorer/pkg_status" || true)" + +case "$state" in + installed) + # Install only if non-existent + if [ -z "$is_installed" ]; then + echo gem install \"$name\" --no-ri --no-rdoc + fi + ;; + removed) + # Remove only if existent + if [ -n "$is_installed" ]; then + echo gem uninstall \"$name\" + fi + ;; + *) + echo "Unknown state: $state" >&2 + exit 1 + ;; +esac diff --git a/conf/type/__package_rubygem/man.text b/conf/type/__package_rubygem/man.text new file mode 100644 index 00000000..00adc8c1 --- /dev/null +++ b/conf/type/__package_rubygem/man.text @@ -0,0 +1,49 @@ +cdist-type__package_rubygem(7) +============================= +Chase Allen James > + + +NAME +---- +cdist-type__package_rubygem - Manage rubygem packages + + +DESCRIPTION +----------- +Rubygems is the default package management system for the Ruby programming language. + + +REQUIRED PARAMETERS +------------------- +state:: + Either "installed" or "removed". + + +OPTIONAL PARAMETERS +------------------- +name:: + If supplied, use the name and not the object id as the package name. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure sinatra is installed +__package_rubygem sinatra --state installed + +# Remove package +__package_rubygem rails --state removed +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__package(7) + + +COPYING +------- +Copyright \(C) 2011 Chase Allen James. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__package_rubygem/parameter/optional b/conf/type/__package_rubygem/parameter/optional new file mode 100644 index 00000000..a52167d3 --- /dev/null +++ b/conf/type/__package_rubygem/parameter/optional @@ -0,0 +1,2 @@ +name +version diff --git a/conf/type/__package_rubygem/parameter/required b/conf/type/__package_rubygem/parameter/required new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/conf/type/__package_rubygem/parameter/required @@ -0,0 +1 @@ +state From b7deafc26d477e6318b27885081a7cba2637842e Mon Sep 17 00:00:00 2001 From: nuex Date: Wed, 17 Aug 2011 09:27:36 -0400 Subject: [PATCH 0108/4212] fix author email in gencode-remote --- conf/type/__package_rubygem/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__package_rubygem/gencode-remote b/conf/type/__package_rubygem/gencode-remote index dfc08781..daaba524 100755 --- a/conf/type/__package_rubygem/gencode-remote +++ b/conf/type/__package_rubygem/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Chase Allen James +# 2011 Chase Allen James # # This file is part of cdist. # From b82f2b0f23ba942f9607eacc4a08ca7feaf26354 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 20 Aug 2011 23:00:31 +0200 Subject: [PATCH 0109/4212] fixup manpage for cdist-type__package_rubygem Signed-off-by: Nico Schottelius --- conf/type/__package_rubygem/man.text | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/type/__package_rubygem/man.text b/conf/type/__package_rubygem/man.text index 00adc8c1..c6248ee3 100644 --- a/conf/type/__package_rubygem/man.text +++ b/conf/type/__package_rubygem/man.text @@ -1,6 +1,6 @@ cdist-type__package_rubygem(7) -============================= -Chase Allen James > +============================== +Chase Allen James NAME From 298784b12bef0600dd4df77a769b6039ea29bedd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 20 Aug 2011 23:02:53 +0200 Subject: [PATCH 0110/4212] __package_rubygem: remove optional parameter version, it is not used Signed-off-by: Nico Schottelius --- conf/type/__package_rubygem/parameter/optional | 1 - 1 file changed, 1 deletion(-) diff --git a/conf/type/__package_rubygem/parameter/optional b/conf/type/__package_rubygem/parameter/optional index a52167d3..f121bdbf 100644 --- a/conf/type/__package_rubygem/parameter/optional +++ b/conf/type/__package_rubygem/parameter/optional @@ -1,2 +1 @@ name -version From 96b164979b7c57dd92514fa5bb4d4e715c8a2f4a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 21 Aug 2011 15:14:33 +0200 Subject: [PATCH 0111/4212] changes for the next version Signed-off-by: Nico Schottelius --- doc/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/changelog b/doc/changelog index 82ae4b95..7e98277a 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,3 +1,6 @@ +next: + * New Type: __package_rubygem (Chase Allen James) + 1.7.1: 2011-07-26 * Documentation: Add explorers to reference * Documentation: Typo cleanup (Derek Brost) From 6886c2e6f11e73ddcb31fb0530ca17adca35a775 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 21 Aug 2011 15:18:41 +0200 Subject: [PATCH 0112/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 3c3300e1..c76bcae4 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -20,3 +20,15 @@ __file/etc/collectd/collectd.conf: Warning: Faulty code: scp /home/users/nico/oeffentlich/rechner/projekte/cdist-nutzung/conf/type/__ethz_collectd/files/collectd.conf.client root@shrek08:/etc/collectd/collectd.conf __file/etc/collectd/collectd.conf: Error: Aborting due to non-zero exit code. +-------------------------------------------------------------------------------- + +Bad error reporting in functions: + +[15:15] ikn:cdist-nutzung% cdist-deploy-to ikn +core: cdist 1.8.0: Configuring ikn +core: Creating clean directory structure +core: Transferring cdist binaries/functions to the target host +core: Running global explorers +core: Running initial manifest for ikn +core: Error: cdist-deploy-to: No arguments + From 98fba8f6bd86214f907341fd22808fe12b921959 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 31 Aug 2011 17:02:00 +0200 Subject: [PATCH 0113/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index abe98cb4..5ded4298 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -49,6 +49,7 @@ CORE wood # empty file - allow cdist to run without $PATH setup: ./bin/cdist-deploy-to +- use absent/present for state by default TYPES ------ From f65b61ee8f89ff576c09c61975f27abb3e9932c4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 5 Sep 2011 09:42:10 +0200 Subject: [PATCH 0114/4212] add debug via __cdist_debug variable Signed-off-by: Nico Schottelius --- bin/cdist-config | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/cdist-config b/bin/cdist-config index d10f1ac7..d5c0464c 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -27,6 +27,9 @@ set -u # Fail if exited non-zero as well set -e +# enable debugging +[ "$__cdist_debug" ] && set -x + ################################################################################ # cconf standard vars prefixed with cdist From cdc6f0d0c01906b7e12c51373d2f3e9f5f561e08 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 5 Sep 2011 09:43:26 +0200 Subject: [PATCH 0115/4212] fix wrong call to __cdist_type_build_emulation Signed-off-by: Nico Schottelius --- core/__cdist_manifest_run | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/__cdist_manifest_run b/core/__cdist_manifest_run index 60d3fea3..cf85d646 100755 --- a/core/__cdist_manifest_run +++ b/core/__cdist_manifest_run @@ -45,8 +45,8 @@ __cdist_manifest_run() # The actual run # - # Ensure binaries are existing - __cdist_type_build_emulation "${__cdist_out_type_bin_dir}" \ + # Ensure binaries are existing - FIXME: move error handling into __cdist_type_build_emulation + __cdist_type_build_emulation \ || __cdist_exit_err "Failed to build type emulation binaries" __cdist_run_shell "${__cdist_manifest}" From 86e30c7a8a19e14e6a4a7a708e2ed63de786dda7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 5 Sep 2011 09:47:58 +0200 Subject: [PATCH 0116/4212] re-rename variable, which got broken during core integration Signed-off-by: Nico Schottelius --- core/__cdist_object_all | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/core/__cdist_object_all b/core/__cdist_object_all index 59457e3c..abac594d 100755 --- a/core/__cdist_object_all +++ b/core/__cdist_object_all @@ -33,12 +33,19 @@ __cdist_object_all_object_all() # Ensure object dir exists, so marker can be created mkdir -p "${__cdist_out_object_dir}" + BUG: + - where does $__cdist_objects_created get setup? + - why do we use a file? + core/__cdist_object_manifest_run: touch "$__cdist_objects_created" + + + exit 23 # Loop until we do not create new objects anymore # which is equal to all objects have been run - touch "$__cdist_object_all_object_all_objects_created" - while [ -f "$__cdist_object_all_object_all_objects_created" ]; do + touch "$__cdist_objects_created" + while [ -f "$__cdist_objects_created" ]; do # Assume we're done after this run - rm "$__cdist_object_all_object_all_objects_created" + rm "$__cdist_objects_created" # Get listing of objects __cdist_object_all_object_list "$__cdist_out_object_dir" > \ From 444083865017c897f53d5212670fa50241b3dd27 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 5 Sep 2011 09:49:00 +0200 Subject: [PATCH 0117/4212] enable debugging before catching unset variables Signed-off-by: Nico Schottelius --- bin/cdist-config | 6 +++--- core/__cdist_object_all | 8 ++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/bin/cdist-config b/bin/cdist-config index d5c0464c..cff9b03a 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -21,15 +21,15 @@ __cdist_version="1.8.0" +# Enable debugging +[ "$__cdist_debug" ] && set -x + # Fail if something bogus is going on set -u # Fail if exited non-zero as well set -e -# enable debugging -[ "$__cdist_debug" ] && set -x - ################################################################################ # cconf standard vars prefixed with cdist diff --git a/core/__cdist_object_all b/core/__cdist_object_all index abac594d..0babdbf6 100755 --- a/core/__cdist_object_all +++ b/core/__cdist_object_all @@ -33,13 +33,9 @@ __cdist_object_all_object_all() # Ensure object dir exists, so marker can be created mkdir -p "${__cdist_out_object_dir}" - BUG: - - where does $__cdist_objects_created get setup? - - why do we use a file? - core/__cdist_object_manifest_run: touch "$__cdist_objects_created" + # FIXME: : - why do we use a file? + # core/__cdist_object_manifest_run: touch "$__cdist_objects_created" - - exit 23 # Loop until we do not create new objects anymore # which is equal to all objects have been run touch "$__cdist_objects_created" From bea7d5f828087a12f0a1fb6ee61ef151444831cb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 5 Sep 2011 09:51:38 +0200 Subject: [PATCH 0118/4212] also fix the function name :-) Signed-off-by: Nico Schottelius --- core/__cdist_object_all | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/__cdist_object_all b/core/__cdist_object_all index 0babdbf6..cdec7df4 100755 --- a/core/__cdist_object_all +++ b/core/__cdist_object_all @@ -22,7 +22,7 @@ # Run the given command for each created object. # -__cdist_object_all_object_all() +__cdist_object_all() { [ $# -eq 1 ] || __cdist_usage "" From f7f2194b8f8ad0c730e08d7528e29d34f98397db Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 5 Sep 2011 09:54:20 +0200 Subject: [PATCH 0119/4212] move __cdist_object_list into seperate file Signed-off-by: Nico Schottelius --- bin/cdist-config | 14 -------------- core/__cdist_object_list | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 14 deletions(-) create mode 100755 core/__cdist_object_list diff --git a/bin/cdist-config b/bin/cdist-config index cff9b03a..be65fed3 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -219,20 +219,6 @@ __cdist_object_id_from_object() echo "${1#*/}" } -# Find objects, remove ./ and /MARKER -__cdist_object_list() -{ - local basedir="$1"; shift - - # Use subshell to prevent changing cwd in program - ( - cd "${basedir}" - - find . -name "$__cdist_name_dot_cdist" | \ - sed -e 's;^./;;' -e "s;/${__cdist_name_dot_cdist}\$;;" - ) -} - __cdist_object_parameter_dir() { echo "$(__cdist_object_dir "$1")/${__cdist_name_parameter}" diff --git a/core/__cdist_object_list b/core/__cdist_object_list new file mode 100755 index 00000000..af209daa --- /dev/null +++ b/core/__cdist_object_list @@ -0,0 +1,36 @@ +#!/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 . +# +# +# Print error and exit (perror() alike) +# + +__cdist_object_list() +{ + # FIXME: no local in posix + local basedir="$1"; shift + + # Use subshell to prevent changing cwd in program + ( + cd "${basedir}" + + find . -name "$__cdist_name_dot_cdist" | \ + sed -e 's;^./;;' -e "s;/${__cdist_name_dot_cdist}\$;;" + ) +} From 368ea87b8961c907bfb3b38cc92afd657061b2aa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 5 Sep 2011 09:55:22 +0200 Subject: [PATCH 0120/4212] call to __cdist_object_list Signed-off-by: Nico Schottelius --- core/__cdist_object_all | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/__cdist_object_all b/core/__cdist_object_all index cdec7df4..965d08f6 100755 --- a/core/__cdist_object_all +++ b/core/__cdist_object_all @@ -44,7 +44,7 @@ __cdist_object_all() rm "$__cdist_objects_created" # Get listing of objects - __cdist_object_all_object_list "$__cdist_out_object_dir" > \ + __cdist_object_list "$__cdist_out_object_dir" > \ "$__cdist_object_all_object_all_objects" # NEED TO CREATE ARRAY, SSH DESTROYS WHILE READ LOOP From a5564850cef5834f9424e8aae44b51af177d6ec3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 5 Sep 2011 09:57:44 +0200 Subject: [PATCH 0121/4212] -whitespaces at the end of lines Signed-off-by: Nico Schottelius --- core/__cdist_object_list | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/__cdist_object_list b/core/__cdist_object_list index af209daa..f2785c30 100755 --- a/core/__cdist_object_list +++ b/core/__cdist_object_list @@ -27,10 +27,10 @@ __cdist_object_list() local basedir="$1"; shift # Use subshell to prevent changing cwd in program - ( + ( cd "${basedir}" - find . -name "$__cdist_name_dot_cdist" | \ + find . -name "$__cdist_name_dot_cdist" | \ sed -e 's;^./;;' -e "s;/${__cdist_name_dot_cdist}\$;;" - ) + ) } From 2b955b09bc92fbb88023ae5986b9d2ebb9360119 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 5 Sep 2011 10:01:56 +0200 Subject: [PATCH 0122/4212] move out all functions that do not only print a value from bin/cdist-config Signed-off-by: Nico Schottelius --- bin/cdist-config | 19 ------------------- core/__cdist_kill_on_interrupt | 31 +++++++++++++++++++++++++++++++ core/__cdist_tmp_removal | 27 +++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 19 deletions(-) create mode 100644 core/__cdist_kill_on_interrupt create mode 100755 core/__cdist_tmp_removal diff --git a/bin/cdist-config b/bin/cdist-config index be65fed3..87f24d06 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -165,11 +165,6 @@ for __cdist_lib in $__cdist_core_dir/*; do . "$__cdist_lib" done -___cdist_lib_path() -{ - echo $_ -} - ################################################################################ # Cache @@ -213,7 +208,6 @@ __cdist_object_base_dir() echo "${__cdist_out_object_dir}/$1" } - __cdist_object_id_from_object() { echo "${1#*/}" @@ -290,19 +284,6 @@ __cdist_remote_type_explorer_dir() ################################################################################ # Traps # -__cdist_tmp_removal() -{ - rm -rf "${__cdist_tmp_dir}" -} - -# Does not work in children, will be called again in every script! -# Use only in interactive "front end" scripts -__cdist_kill_on_interrupt() -{ - __cdist_tmp_removal - kill 0 - exit 1 -} # Remove tempfiles at normal exit trap __cdist_tmp_removal EXIT diff --git a/core/__cdist_kill_on_interrupt b/core/__cdist_kill_on_interrupt new file mode 100644 index 00000000..7cb711fa --- /dev/null +++ b/core/__cdist_kill_on_interrupt @@ -0,0 +1,31 @@ +#!/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 . +# +# +# Run the given command for each created object. +# + +# Does not work in children, will be called again in every script! +# Use only in interactive "front end" scripts +__cdist_kill_on_interrupt() +{ + __cdist_tmp_removal + kill 0 + exit 1 +} diff --git a/core/__cdist_tmp_removal b/core/__cdist_tmp_removal new file mode 100755 index 00000000..74d74936 --- /dev/null +++ b/core/__cdist_tmp_removal @@ -0,0 +1,27 @@ +#!/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 . +# +# +# Remove tmp dir +# + +__cdist_tmp_removal() +{ + rm -rf "${__cdist_tmp_dir}" +} From fe68c5b5566e16b01533a5091c220e7826a14c6e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Sep 2011 12:24:53 +0200 Subject: [PATCH 0123/4212] do not exit implicitly via set -e anymore Signed-off-by: Nico Schottelius --- bin/cdist-config | 3 --- 1 file changed, 3 deletions(-) diff --git a/bin/cdist-config b/bin/cdist-config index 87f24d06..bf3f5b24 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -27,9 +27,6 @@ __cdist_version="1.8.0" # Fail if something bogus is going on set -u -# Fail if exited non-zero as well -set -e - ################################################################################ # cconf standard vars prefixed with cdist From 74418c77e028c72c45bd95d4a803f56a893d5367 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Sep 2011 10:01:59 +0200 Subject: [PATCH 0124/4212] remove obsolete calls to set +e/-e Signed-off-by: Nico Schottelius --- core/__cdist_run | 7 +------ core/__cdist_run_shell | 2 -- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/core/__cdist_run b/core/__cdist_run index db9fd8d9..8febe550 100755 --- a/core/__cdist_run +++ b/core/__cdist_run @@ -23,10 +23,5 @@ __cdist_run() { - set +e - "$@" - if [ "$?" -ne 0 ]; then - __cdist_echo error "$1 exited non-zero, aborting." - fi - set -e + "$@" || __cdist_echo error "$1 exited non-zero, aborting." } diff --git a/core/__cdist_run_shell b/core/__cdist_run_shell index 1d76e17b..b6e0a57d 100755 --- a/core/__cdist_run_shell +++ b/core/__cdist_run_shell @@ -23,7 +23,6 @@ __cdist_run_shell() { - set +e # Prepend our path, so all cdist tools come before other tools PATH="${__cdist_out_type_bin_dir}:$PATH" sh -e "$@" if [ "$?" -ne 0 ]; then @@ -32,5 +31,4 @@ __cdist_run_shell() cat "$1" __cdist_exit_err "Aborting due to non-zero exit code." fi - set -e } From c3bf34bf3d9a59c8467f94e5830b6b2711f1b753 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Sep 2011 10:07:04 +0200 Subject: [PATCH 0125/4212] add support for __cdist_debug={0,1,2} Signed-off-by: Nico Schottelius --- bin/cdist-config | 12 ++++++++++-- core/__cdist_echo | 4 +--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/bin/cdist-config b/bin/cdist-config index bf3f5b24..b15d1f3e 100644 --- a/bin/cdist-config +++ b/bin/cdist-config @@ -21,8 +21,16 @@ __cdist_version="1.8.0" -# Enable debugging -[ "$__cdist_debug" ] && set -x +# +# Enable debugging: +# +# __cdist_debug unset -> no debug +# __cdist_debug = 1 -> debug via __cdist_echo +# __cdist_debug = 2 -> debug via set -x +# + +: ${__cdist_debug:=0} +[ "$__cdist_debug" = 2 ] && set -x # Fail if something bogus is going on set -u diff --git a/core/__cdist_echo b/core/__cdist_echo index 2fcc93f0..37d24dd6 100755 --- a/core/__cdist_echo +++ b/core/__cdist_echo @@ -35,11 +35,9 @@ __cdist_echo() case "$__cdist_echo_type" in debug) - set +u - if [ "$__cdist_debug" ]; then + if [ "$__cdist_debug" = 1 ]; then echo $__cdist_echo_prefix "Debug: $@" fi - set -u ;; info) echo $__cdist_echo_prefix "$@" From bd85d22a89d96348c17a6afb0a2b0d3406d84e59 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Sep 2011 10:09:19 +0200 Subject: [PATCH 0126/4212] +debugging of __cdist_object_run Signed-off-by: Nico Schottelius --- core/__cdist_object_run | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/__cdist_object_run b/core/__cdist_object_run index 0e0da80f..086bfb0b 100755 --- a/core/__cdist_object_run +++ b/core/__cdist_object_run @@ -57,9 +57,12 @@ __cdist_object_run() done fi + __cdist_echo debug "Before gencode" __cdist_object_gencode_run "$__cdist_object_self" + __cdist_echo debug "Before push" __cdist_dir push "$(__cdist_object_dir "$__cdist_object_self")" \ "$(__cdist_remote_object_dir "$__cdist_object_self")" + __cdist_echo debug "Before run" __cdist_object_code_run "$__cdist_object_self" # Mark this object as done From 68a51da380a153e9033cb5df009379c1939be9dc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Sep 2011 10:10:46 +0200 Subject: [PATCH 0127/4212] make debug more verbose Signed-off-by: Nico Schottelius --- core/__cdist_echo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/__cdist_echo b/core/__cdist_echo index 37d24dd6..a89d1821 100755 --- a/core/__cdist_echo +++ b/core/__cdist_echo @@ -36,7 +36,7 @@ __cdist_echo() case "$__cdist_echo_type" in debug) if [ "$__cdist_debug" = 1 ]; then - echo $__cdist_echo_prefix "Debug: $@" + echo $__cdist_echo_prefix "DEBUG: $@" fi ;; info) From 06a6bf1a0dfdc997413b6e63d77b4bb8dae40a16 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Sep 2011 10:12:40 +0200 Subject: [PATCH 0128/4212] debug object run Signed-off-by: Nico Schottelius --- core/__cdist_object_code_run | 4 ++-- core/__cdist_object_run | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/__cdist_object_code_run b/core/__cdist_object_code_run index 734db5c9..a932f655 100755 --- a/core/__cdist_object_code_run +++ b/core/__cdist_object_code_run @@ -26,7 +26,7 @@ __cdist_object_code_run() { [ $# -eq 1 ] || __cdist_exit_err "" - # set -x + set -x if [ ! -d "$(__cdist_object_dir "$1")" ]; then __cdist_exit_err "Object undefined" @@ -46,5 +46,5 @@ __cdist_object_code_run() __cdist_run_remote $(__cdist_remote_object_code "$1") fi - # set +x + set +x } diff --git a/core/__cdist_object_run b/core/__cdist_object_run index 086bfb0b..d122bdd4 100755 --- a/core/__cdist_object_run +++ b/core/__cdist_object_run @@ -64,6 +64,7 @@ __cdist_object_run() "$(__cdist_remote_object_dir "$__cdist_object_self")" __cdist_echo debug "Before run" __cdist_object_code_run "$__cdist_object_self" + __cdist_echo debug "Object run done # Mark this object as done touch "$__cdist_object_finished" From 512ff6957413077bd13a9355f89b1fd5fcb56c5d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Sep 2011 10:13:00 +0200 Subject: [PATCH 0129/4212] +" Signed-off-by: Nico Schottelius --- core/__cdist_object_run | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/__cdist_object_run b/core/__cdist_object_run index d122bdd4..7446c844 100755 --- a/core/__cdist_object_run +++ b/core/__cdist_object_run @@ -64,7 +64,7 @@ __cdist_object_run() "$(__cdist_remote_object_dir "$__cdist_object_self")" __cdist_echo debug "Before run" __cdist_object_code_run "$__cdist_object_self" - __cdist_echo debug "Object run done + __cdist_echo debug "Object run done" # Mark this object as done touch "$__cdist_object_finished" From 44586bc6f9dc9b1dc747365806ce40e6e8b8f8f1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Sep 2011 10:17:18 +0200 Subject: [PATCH 0130/4212] changes for 1.8.0 Signed-off-by: Nico Schottelius --- doc/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/changelog b/doc/changelog index 82ae4b95..a9a70afb 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,3 +1,6 @@ +1.8.0: + * Added debug (via __cdist_debug={1,2} environment variable) + 1.7.1: 2011-07-26 * Documentation: Add explorers to reference * Documentation: Typo cleanup (Derek Brost) From adf2e05a0805473f789ca7942d5691b4e6a52662 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Sep 2011 10:18:03 +0200 Subject: [PATCH 0131/4212] more changes for 1.8.0 Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index a9a70afb..a0d114a1 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,5 +1,6 @@ 1.8.0: * Added debug (via __cdist_debug={1,2} environment variable) + * Transformed shell script based approach to shell functions (performance improvement) 1.7.1: 2011-07-26 * Documentation: Add explorers to reference From 279d519dda0caa14f8488392675f6f411c0e8d99 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 00:10:53 +0200 Subject: [PATCH 0132/4212] debug for core/__cdist_object_code_run Signed-off-by: Nico Schottelius --- core/__cdist_object_code_run | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/__cdist_object_code_run b/core/__cdist_object_code_run index a932f655..26bf7ef8 100755 --- a/core/__cdist_object_code_run +++ b/core/__cdist_object_code_run @@ -26,7 +26,6 @@ __cdist_object_code_run() { [ $# -eq 1 ] || __cdist_exit_err "" - set -x if [ ! -d "$(__cdist_object_dir "$1")" ]; then __cdist_exit_err "Object undefined" @@ -34,6 +33,7 @@ __cdist_object_code_run() # Code local export __cdist_out_object_dir="$__cdist_out_object_dir" + __cdist_echo debug "Trying to run local code" if __cdist_is_executable \ "$(__cdist_object_code "$1" "${__cdist_name_gencode_local}")"; then __cdist_run_shell \ @@ -41,10 +41,10 @@ __cdist_object_code_run() fi # Code remote + __cdist_echo debug "Trying to run remote code" if __cdist_is_executable \ "$(__cdist_object_code "$1" "${__cdist_name_gencode_remote}")"; then __cdist_run_remote $(__cdist_remote_object_code "$1") fi - set +x } From 0b5e7b585522113d7b3a13e10fc515fe91201c25 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 00:17:28 +0200 Subject: [PATCH 0133/4212] debug log for code inserted Signed-off-by: Nico Schottelius --- core/__cdist_object_code_run | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/__cdist_object_code_run b/core/__cdist_object_code_run index 26bf7ef8..8af67ab8 100755 --- a/core/__cdist_object_code_run +++ b/core/__cdist_object_code_run @@ -38,6 +38,8 @@ __cdist_object_code_run() "$(__cdist_object_code "$1" "${__cdist_name_gencode_local}")"; then __cdist_run_shell \ "$(__cdist_object_code "$1" "${__cdist_name_gencode_local}")" + else + __cdist_echo debug "Local code: none" fi # Code remote @@ -46,5 +48,7 @@ __cdist_object_code_run() "$(__cdist_object_code "$1" "${__cdist_name_gencode_remote}")"; then __cdist_run_remote $(__cdist_remote_object_code "$1") + else + __cdist_echo debug "Remote code: none" fi } From 0ec3c2d017e5cc6f733b255350cc2588bbb221fc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 00:39:04 +0200 Subject: [PATCH 0134/4212] document bug Signed-off-by: Nico Schottelius --- core/__cdist_object_run | 2 ++ doc/dev/todo/niconext | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/core/__cdist_object_run b/core/__cdist_object_run index 7446c844..d2c7df6e 100755 --- a/core/__cdist_object_run +++ b/core/__cdist_object_run @@ -53,6 +53,8 @@ __cdist_object_run() while [ $# -gt 0 ]; do __cdist_requirement="$1"; shift __cdist_echo info "Resolving requirement $__cdist_requirement" + # FIXME: BUG: at this point, the other __cdist_object_run may have + # overwritten all our variables! __cdist_object_run "$__cdist_requirement" done fi diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index c76bcae4..cd4f8e70 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,3 +1,7 @@ +BUG in core/__cdist_object_run: each recursive call overwrites the variables! + +-------------------------------------------------------------------------------- + Bug with requirements when indirect requires is scheduled late: __package/collectd: Generating local code From 159ac76134a060469c6315600c67ccdbcd24c02f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 00:40:17 +0200 Subject: [PATCH 0135/4212] really do so Signed-off-by: Nico Schottelius --- BUG | 1 + 1 file changed, 1 insertion(+) create mode 100644 BUG diff --git a/BUG b/BUG new file mode 100644 index 00000000..9d57ee49 --- /dev/null +++ b/BUG @@ -0,0 +1 @@ +See core/__cdist_object_run. From 1b84a2851146c78fe1c122afc216ec0f8d7b4a07 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 00:41:37 +0200 Subject: [PATCH 0136/4212] add cdist Signed-off-by: Nico Schottelius --- bin/cdist | 438 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 438 insertions(+) create mode 100644 bin/cdist diff --git a/bin/cdist b/bin/cdist new file mode 100644 index 00000000..a70a11f8 --- /dev/null +++ b/bin/cdist @@ -0,0 +1,438 @@ +#!python3 +# +# 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 . +# +# + +__cdist_version="1.7.0" + +# Fail if something bogus is going on +set -u + +################################################################################ +# cconf standard vars prefixed with cdist + +__cdist_pwd="$(pwd -P)" +__cdist_mydir="${0%/*}"; +__cdist_abs_mydir="$(cd "$__cdist_mydir" && pwd -P)" +__cdist_myname=${0##*/}; +__cdist_abs_myname="$__cdist_abs_mydir/$__cdist_myname" + +################################################################################ +# Names / Constants +# +# Most values can be overriden from outside, so you can +# customise paths as you like (for distributors, geeks and hackers) +# + +: ${__cdist_name_bin:=bin} +: ${__cdist_name_cache:=cache} +: ${__cdist_name_code:=code} +: ${__cdist_name_conf_dir:=conf} +: ${__cdist_name_dot_cdist:=.cdist} +: ${__cdist_name_explorer:=explorer} +: ${__cdist_name_gencode:=gencode} +: ${__cdist_name_gencode_local:=local} +: ${__cdist_name_gencode_remote:=remote} +: ${__cdist_name_global:=global} +: ${__cdist_name_host:=host} +: ${__cdist_name_init:=init} +: ${__cdist_name_manifest:=manifest} +: ${__cdist_name_object:=object} +: ${__cdist_name_object_finished:=done} +: ${__cdist_name_object_prepared:=prepared} +: ${__cdist_name_object_id:=object_id} +: ${__cdist_name_object_source:=source} +: ${__cdist_name_objects_created:=.objects_created} +: ${__cdist_name_out_dir:=out} +: ${__cdist_name_parameter:=parameter} +: ${__cdist_name_parameter_required:=required} +: ${__cdist_name_parameter_optional:=optional} +: ${__cdist_name_require:=require} +: ${__cdist_name_self:=self} +: ${__cdist_name_singleton:=singleton} +: ${__cdist_name_target_host:=target_host} +: ${__cdist_name_target_user:=target_user} +: ${__cdist_name_type:=type} +: ${__cdist_name_type_bin:=type_bin} +: ${__cdist_name_type_explorer:=type_explorer} +: ${__cdist_name_type_explorer_pushed:=.explorer_pushed} + +# Used for IDs: Allow everything not starting with - and . +: ${__cdist_sane_regexp:=[^-\.].*} + +# Default remote user +: ${__cdist_remote_user:=root} + + +################################################################################ +# Exported variable names (usable for non core +# +: ${__cdist_name_var_explorer:=__$__cdist_name_explorer} +: ${__cdist_name_var_type_explorer:=__$__cdist_name_type_explorer} +: ${__cdist_name_var_global:=__$__cdist_name_global} +: ${__cdist_name_var_manifest:=__$__cdist_name_manifest} +: ${__cdist_name_var_target_host:=__$__cdist_name_target_host} +: ${__cdist_name_var_target_user:=__$__cdist_name_target_user} +: ${__cdist_name_var_object:=__$__cdist_name_object} +: ${__cdist_name_var_object_id:=__$__cdist_name_object_id} +: ${__cdist_name_var_self:=__$__cdist_name_self} +: ${__cdist_name_var_type:=__$__cdist_name_type} + + +################################################################################ +# Tempfiles +# +: ${__cdist_tmp_base_dir=/tmp} +__cdist_tmp_dir=$(mktemp -d "$__cdist_tmp_base_dir/cdist.XXXXXXXXXXXX") +__cdist_tmp_file=$(mktemp "$__cdist_tmp_dir/cdist.XXXXXXXXXXXX") + +################################################################################ +# Local Base +# +: ${__cdist_local_base_dir:=$__cdist_tmp_dir} + +# Cache may *NOT* be below __cdist_local_base_dir! +: ${__cdist_local_base_cache_dir:=$__cdist_abs_mydir/../$__cdist_name_cache} + +: ${__cdist_conf_dir:="$(cd "$__cdist_abs_mydir/../conf" && pwd -P)"} + +: ${__cdist_explorer_dir:=$__cdist_conf_dir/$__cdist_name_explorer} +: ${__cdist_manifest_dir:=$__cdist_conf_dir/$__cdist_name_manifest} +: ${__cdist_manifest_init:=$__cdist_manifest_dir/$__cdist_name_init} +: ${__cdist_type_dir:=$__cdist_conf_dir/$__cdist_name_type} + +################################################################################ +# Local output +# +: ${__cdist_out_dir:=$__cdist_local_base_dir/$__cdist_name_out_dir} +: ${__cdist_out_explorer_dir:=$__cdist_out_dir/$__cdist_name_explorer} +: ${__cdist_out_object_dir:=$__cdist_out_dir/$__cdist_name_object} +: ${__cdist_out_type_dir:=$__cdist_out_dir/$__cdist_name_type} +: ${__cdist_out_type_bin_dir:=$__cdist_out_dir/$__cdist_name_type_bin} + +: ${__cdist_objects_created:=$__cdist_out_object_dir/$__cdist_name_objects_created} + +################################################################################ +# Remote base +# +: ${__cdist_remote_base_dir:=/var/lib/cdist} +: ${__cdist_remote_bin_dir:=$__cdist_remote_base_dir/$__cdist_name_bin} +: ${__cdist_remote_conf_dir:=$__cdist_remote_base_dir/$__cdist_name_conf_dir} + +: ${__cdist_remote_explorer_dir:=$__cdist_remote_conf_dir/$__cdist_name_explorer} +: ${__cdist_remote_type_dir:=$__cdist_remote_conf_dir/$__cdist_name_type} + +################################################################################ +# Remote output +# +: ${__cdist_remote_out_dir:=$__cdist_remote_base_dir/$__cdist_name_out_dir} +: ${__cdist_remote_out_explorer_dir:=$__cdist_remote_out_dir/$__cdist_name_explorer} +: ${__cdist_remote_out_object_dir:=$__cdist_remote_out_dir/$__cdist_name_object} + + +################################################################################ +# Internal functions +# +__cdist_echo() +{ + __cdist_echo_type="$1"; shift + + set +u + if [ "$__cdist_object_self" ]; then + __cdist_echo_prefix="${__cdist_object_self}:" + else + __cdist_echo_prefix="core: " + fi + set -u + + case "$__cdist_echo_type" in + debug) + set +u + if [ "$__cdist_debug" ]; then + echo $__cdist_echo_prefix "Debug: $@" + fi + set -u + ;; + info) + echo $__cdist_echo_prefix "$@" + ;; + warn) + echo $__cdist_echo_prefix "Warning: $@" + ;; + error) + echo $__cdist_echo_prefix "Error: $@" >&2 + ;; + *) + echo "CORE BUG, who created the broken commit in $0?" >&2 + exit 23 + ;; + esac +} + +__cdist_exec_fail_on_error() +{ + set +e + sh -e "$@" + if [ "$?" -ne 0 ]; then + __cdist_echo error "$1 exited non-zero" + __cdist_echo warn "Faulty code:" + cat "$1" + __cdist_exit_err "Aborting due to non-zero exit code." + fi +} + +__cdist_exit_err() +{ + __cdist_echo error "$@" + exit 1 +} + +__cdist_usage() +{ + __cdist_exit_err "$__cdist_myname: $@" +} + +__cdist_init_deploy() +{ + __cdist_echo info "Creating clean directory structure " + + # Ensure there is no old stuff, neither local nor remote + rm -rf "$__cdist_local_base_dir" + ssh "${__cdist_remote_user}@$1" "rm -rf ${__cdist_remote_base_dir}" + + # Init base + mkdir -p "$__cdist_local_base_dir" + ssh "${__cdist_remote_user}@$1" "mkdir -p ${__cdist_remote_base_dir}" + + # Link configuration source directory - consistent with remote + ln -sf "$__cdist_conf_dir" "$__cdist_local_base_dir/$__cdist_name_conf_dir" +} + +################################################################################ +# Cache +# +__cdist_cache_dir() +{ + cd "${__cdist_local_base_cache_dir}" && pwd -P +} + +__cdist_host_cache_dir() +{ + echo "$(__cdist_cache_dir)/$1" +} + +################################################################################ +# Object +# + +__cdist_object_code() +{ + echo "$(__cdist_object_dir "$1")/${__cdist_name_code}-$2" +} + +__cdist_object_prepared() +{ + echo "$(__cdist_object_dir "$1")/${__cdist_name_object_prepared}" +} + +__cdist_object_finished() +{ + echo "$(__cdist_object_dir "$1")/${__cdist_name_object_finished}" +} + +__cdist_object_dir() +{ + echo "$(__cdist_object_base_dir "$1")/${__cdist_name_dot_cdist}" +} + +__cdist_object_base_dir() +{ + echo "${__cdist_out_object_dir}/$1" +} + + +__cdist_object_id_from_object() +{ + echo "${1#*/}" +} + +# Find objects, remove ./ and /MARKER +__cdist_object_list() +{ + local basedir="$1"; shift + + # Use subshell to prevent changing cwd in program + ( + cd "${basedir}" + + find . -name "$__cdist_name_dot_cdist" | \ + sed -e 's;^./;;' -e "s;/${__cdist_name_dot_cdist}\$;;" + ) +} + +__cdist_object_parameter_dir() +{ + echo "$(__cdist_object_dir "$1")/${__cdist_name_parameter}" +} + +__cdist_object_require() +{ + echo "$(__cdist_object_dir "$1")/${__cdist_name_require}" +} + +__cdist_object_source_name() +{ + echo "$1/${__cdist_name_object_source}" +} + +__cdist_object_source() +{ + cat "$(__cdist_object_source_name "$1")" +} + +__cdist_object_source_add() +{ + echo "$__cdist_manifest" >> "$(__cdist_object_source_name "$1")" +} + +__cdist_object_type_explorer_dir() +{ + echo "$(__cdist_object_dir "$1")/${__cdist_name_explorer}" +} + +################################################################################ +# Remote +# + +__cdist_remote_object_base_dir() +{ + echo "${__cdist_remote_out_object_dir}/$1" +} + +__cdist_remote_object_dir() +{ + echo "$(__cdist_remote_object_base_dir "$1")/${__cdist_name_dot_cdist}" +} + +__cdist_remote_object_parameter_dir() +{ + echo "$(__cdist_remote_object_dir "$1")/${__cdist_name_parameter}" +} + +__cdist_remote_object_type_explorer_dir() +{ + echo "$(__cdist_remote_object_dir "$1")/${__cdist_name_explorer}" +} + + +__cdist_remote_type_explorer_dir() +{ + echo "${__cdist_remote_type_dir}/$1/${__cdist_name_explorer}" +} + + +################################################################################ +# Traps +# +__cdist_tmp_removal() +{ + rm -rf "${__cdist_tmp_dir}" +} + +# Does not work in children, will be called again in every script! +# Use only in interactive "front end" scripts +__cdist_kill_on_interrupt() +{ + __cdist_tmp_removal + kill 0 + exit 1 +} + +# Remove tempfiles at normal exit +trap __cdist_tmp_removal EXIT + + +################################################################################ +# Type +# +__cdist_type_dir() +{ + echo "${__cdist_type_dir}/$1" +} + +__cdist_type_explorer_dir() +{ + echo "${__cdist_type_dir}/$1/${__cdist_name_explorer}" +} + +__cdist_type_from_object() +{ + echo "${1%%/*}" +} + +__cdist_type_has_explorer() +{ + # We only create output, if there's at least one explorer + # and can thus be used as a boolean ;-) + if [ -d "$(__cdist_type_explorer_dir "$1")" ]; then + ls -1 "$(__cdist_type_explorer_dir "$1")" + fi +} + +__cdist_type_explorer_pushed() +{ + [ -f "${__cdist_out_type_dir}/${__cdist_name_type_explorer_pushed}" ] \ + && grep -q "$1" "${__cdist_out_type_dir}/${__cdist_name_type_explorer_pushed}" +} + +__cdist_type_explorer_pushed_add() +{ + [ -d "$__cdist_out_type_dir" ] || mkdir "$__cdist_out_type_dir" + echo "$1" >> "${__cdist_out_type_dir}/${__cdist_name_type_explorer_pushed}" +} + +__cdist_type_gencode() +{ + echo "${__cdist_type_dir}/$1/${__cdist_name_gencode}-$2" +} + +__cdist_type_manifest() +{ + echo "${__cdist_type_dir}/$1/${__cdist_name_manifest}" +} + +__cdist_type_parameter_dir() +{ + echo "$(__cdist_type_dir "$1")/${__cdist_name_parameter}" +} + +__cdist_type_parameter_optional() +{ + echo "$(__cdist_type_parameter_dir "$1")/$__cdist_name_parameter_optional" +} + +__cdist_type_parameter_required() +{ + echo "$(__cdist_type_parameter_dir "$1")/$__cdist_name_parameter_required" +} + +__cdist_type_singleton() +{ + echo "${__cdist_type_dir}/$1/${__cdist_name_singleton}" +} From d359f69f4bd907e88103aa41217724707a9c0325 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 00:49:29 +0200 Subject: [PATCH 0137/4212] +minimal __cdist_echo Signed-off-by: Nico Schottelius --- core/__cdist_cache | 34 ++++++++++++ core/__cdist_dir | 46 ++++++++++++++++ core/__cdist_dir_listing | 30 +++++++++++ core/__cdist_echo | 56 +++++++++++++++++++ core/__cdist_exit_err | 28 ++++++++++ core/__cdist_explorer_run | 79 +++++++++++++++++++++++++++ core/__cdist_explorer_run_global | 32 +++++++++++ core/__cdist_init_deploy | 40 ++++++++++++++ core/__cdist_is_executable | 44 +++++++++++++++ core/__cdist_kill_on_interrupt | 31 +++++++++++ core/__cdist_manifest_run | 53 ++++++++++++++++++ core/__cdist_manifest_run_init | 32 +++++++++++ core/__cdist_object_all | 60 +++++++++++++++++++++ core/__cdist_object_code_run | 54 +++++++++++++++++++ core/__cdist_object_explorer_run | 89 +++++++++++++++++++++++++++++++ core/__cdist_object_gencode | 66 +++++++++++++++++++++++ core/__cdist_object_gencode_run | 36 +++++++++++++ core/__cdist_object_list | 36 +++++++++++++ core/__cdist_object_manifest_run | 59 ++++++++++++++++++++ core/__cdist_object_prepare | 47 ++++++++++++++++ core/__cdist_object_run | 74 +++++++++++++++++++++++++ core/__cdist_run | 27 ++++++++++ core/__cdist_run_remote | 32 +++++++++++ core/__cdist_run_shell | 34 ++++++++++++ core/__cdist_tmp_removal | 27 ++++++++++ core/__cdist_type_build_emulation | 49 +++++++++++++++++ core/__cdist_usage | 27 ++++++++++ 27 files changed, 1222 insertions(+) create mode 100755 core/__cdist_cache create mode 100755 core/__cdist_dir create mode 100755 core/__cdist_dir_listing create mode 100755 core/__cdist_echo create mode 100755 core/__cdist_exit_err create mode 100755 core/__cdist_explorer_run create mode 100755 core/__cdist_explorer_run_global create mode 100755 core/__cdist_init_deploy create mode 100755 core/__cdist_is_executable create mode 100644 core/__cdist_kill_on_interrupt create mode 100755 core/__cdist_manifest_run create mode 100755 core/__cdist_manifest_run_init create mode 100755 core/__cdist_object_all create mode 100755 core/__cdist_object_code_run create mode 100755 core/__cdist_object_explorer_run create mode 100755 core/__cdist_object_gencode create mode 100755 core/__cdist_object_gencode_run create mode 100755 core/__cdist_object_list create mode 100755 core/__cdist_object_manifest_run create mode 100755 core/__cdist_object_prepare create mode 100755 core/__cdist_object_run create mode 100755 core/__cdist_run create mode 100755 core/__cdist_run_remote create mode 100755 core/__cdist_run_shell create mode 100755 core/__cdist_tmp_removal create mode 100755 core/__cdist_type_build_emulation create mode 100755 core/__cdist_usage diff --git a/core/__cdist_cache b/core/__cdist_cache new file mode 100755 index 00000000..95764d3d --- /dev/null +++ b/core/__cdist_cache @@ -0,0 +1,34 @@ +#!/bin/sh +# +# 2010 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 . +# +# +# Save the configuration tree into the local cache +# + +__cdist_cache() +{ + # Create base to move into + mkdir -p "${__cdist_local_base_cache_dir}" + + __cdist_echo info \ + "Caching to $(__cdist_host_cache_dir "$__cdist_target_host")" + rm -rf "$(__cdist_host_cache_dir "$__cdist_target_host")" + mv "$__cdist_local_base_dir" \ + "$(__cdist_host_cache_dir "$__cdist_target_host")" +} diff --git a/core/__cdist_dir b/core/__cdist_dir new file mode 100755 index 00000000..32ee0075 --- /dev/null +++ b/core/__cdist_dir @@ -0,0 +1,46 @@ +#!/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 . +# +# +# 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) +# + +__cdist_dir() +{ + [ $# -eq 3 ] || __cdist_usage " " + + # ${3%/*} will be the destination directory, so no subdirectories + # of the same name are created, if the directory is already existing + + if [ "$1" = "push" ]; then + # FIXME: add error handling with __cdist_run_remote_... or so + ssh "${__cdist_remote_user}@${__cdist_target_host}" \ + "mkdir -p \"$3\"" + scp -qr "$2" \ + "${__cdist_remote_user}@${__cdist_target_host}:${3%/*}" + elif [ "$1" = "pull" ]; then + mkdir -p "$3" + scp -qr "${__cdist_remote_user}@${__cdist_target_host}:$2" \ + "${3%/*}" + else + __cdist_exit_err "Unknown action $1" + fi +} diff --git a/core/__cdist_dir_listing b/core/__cdist_dir_listing new file mode 100755 index 00000000..f4aa2320 --- /dev/null +++ b/core/__cdist_dir_listing @@ -0,0 +1,30 @@ +#!/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 . +# +# +# List files in a directory, if it exists +# +# We only create output, if there's at least one entry +# and can thus be used as a boolean ;-) +# + +__cdist_dir_listing() +{ + [ -d "$1" ] && ls -1 "$1" +} diff --git a/core/__cdist_echo b/core/__cdist_echo new file mode 100755 index 00000000..a89d1821 --- /dev/null +++ b/core/__cdist_echo @@ -0,0 +1,56 @@ +#!/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 . +# +# +# echo / syslog alike function +# + +__cdist_echo() +{ + __cdist_echo_type="$1"; shift + + set +u + if [ "$__cdist_object_self" ]; then + __cdist_echo_prefix="${__cdist_object_self}:" + else + __cdist_echo_prefix="core: " + fi + set -u + + case "$__cdist_echo_type" in + debug) + if [ "$__cdist_debug" = 1 ]; then + echo $__cdist_echo_prefix "DEBUG: $@" + fi + ;; + info) + echo $__cdist_echo_prefix "$@" + ;; + warn) + echo $__cdist_echo_prefix "Warning: $@" + ;; + error) + echo $__cdist_echo_prefix "Error: $@" >&2 + ;; + *) + echo "CORE BUG, who created the broken commit in $0?" >&2 + exit 23 + ;; + esac +} diff --git a/core/__cdist_exit_err b/core/__cdist_exit_err new file mode 100755 index 00000000..303dbf20 --- /dev/null +++ b/core/__cdist_exit_err @@ -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 . +# +# +# Print error and exit (perror() alike) +# + +__cdist_exit_err() +{ + __cdist_echo error "$@" + exit 1 +} diff --git a/core/__cdist_explorer_run b/core/__cdist_explorer_run new file mode 100755 index 00000000..9e58fa09 --- /dev/null +++ b/core/__cdist_explorer_run @@ -0,0 +1,79 @@ +#!/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 . +# +# +# Run explorers - FIXME: this function is ugly +# + +__cdist_explorer_run() +{ + [ $# -eq 5 ] || __cdist_usage " " + + # Ensure there is at least one explorer + num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" + if [ "$num" -lt 1 ]; then + __cdist_exit_err "${__cdist_explorer_dir}: Contains no explorers" + fi + + # Check whether to setup variable for type explorer + case "$1" in + global) + ;; + type) + # FIXME: think about how and where this gets setup! + "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" + ;; + esac + + # Transfer explorers + __cdist_dir push "$2" "$3" + + # Create output directory + __cdist_run_remote mkdir -p "$4" + + # Execute all explorers - FIXME: isolate cd call? + cd "$2"; + # FIXME: cleanup double variable, no need when in directory + for __cdist_explorer_run_explorer in *; do + __cdist_explorer_explorer_name="${__cdist_explorer_run_explorer##*/}" + + if [ -f "$__cdist_explorer_run_explorer" ]; then + if [ ! -x "$__cdist_explorer_run_explorer" ]; then + __cdist_exit_err "Explorer \"$__cdist_explorer_run_explorer\" exists, but is not executable." + fi + + else + if [ -e "$__cdist_explorer_run_explorer" ]; then + __cdist_exit_err "Explorer \"$__cdist_explorer_run_explorer\" exists, but is not a file." + fi + fi + + # FIXME: no need for remote out dir probably? + # or should we leave it and continue using __cdist_dir pull? + __cdist_run_remote \ + "export $__cdist_name_var_explorer=\"$__cdist_remote_explorer_dir\";" \ + "export $__cdist_name_var_global=\"$__cdist_remote_out_dir\";" \ + "$3/$__cdist_explorer_run_explorer" ">" \ + "$4/$__cdist_explorer_run_explorer" || \ + __cdist_exit_err "Explorer $__cdist_explorer_run_explorer failed." + done + + # Transfer results back + __cdist_dir pull "$4" "$5" +} diff --git a/core/__cdist_explorer_run_global b/core/__cdist_explorer_run_global new file mode 100755 index 00000000..27359713 --- /dev/null +++ b/core/__cdist_explorer_run_global @@ -0,0 +1,32 @@ +#!/bin/sh +# +# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Copy & run the global explorers, i.e. not bound to types +# + +__cdist_explorer_run_global() +{ + __cdist_echo info "Running global explorers " + + # run the global explorers remotely + __cdist_explorer_run global \ + "$__cdist_explorer_dir" "$__cdist_remote_explorer_dir" \ + "$__cdist_remote_out_explorer_dir" "$__cdist_out_explorer_dir" +} diff --git a/core/__cdist_init_deploy b/core/__cdist_init_deploy new file mode 100755 index 00000000..4ac3168c --- /dev/null +++ b/core/__cdist_init_deploy @@ -0,0 +1,40 @@ +#!/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 . +# +# +# Prepare deployment +# + +__cdist_init_deploy() +{ + __cdist_echo info "Creating clean directory structure " + + # Ensure there is no old stuff, neither local nor remote + rm -rf "$__cdist_local_base_dir" + ssh "${__cdist_remote_user}@${__cdist_target_host}" \ + "rm -rf ${__cdist_remote_base_dir}" + + # Init base + mkdir -p "$__cdist_local_base_dir" + ssh "${__cdist_remote_user}@${__cdist_target_host}" \ + "mkdir -p ${__cdist_remote_base_dir}" + + # Link configuration source directory - consistent with remote + ln -sf "$__cdist_conf_dir" "$__cdist_local_base_dir/$__cdist_name_conf_dir" +} diff --git a/core/__cdist_is_executable b/core/__cdist_is_executable new file mode 100755 index 00000000..a7a6d174 --- /dev/null +++ b/core/__cdist_is_executable @@ -0,0 +1,44 @@ +#!/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 . +# +# +# Test whether something is executable (that should be executable) or +# is missing +# + +__cdist_is_executable() +{ + [ $# -eq 1 ] || __cdist_exit_err "" + + if [ -e "$1" ]; then + if [ -f "$1" ]; then + if [ -x "$1" ]; then + # Exists and is a correct executable + true + else + __cdist_exit_err "$1 exists, but is not executable." + fi + else + __cdist_exit_err "$1 exists, but is not a file." + fi + else + # Does not exist + false + fi +} diff --git a/core/__cdist_kill_on_interrupt b/core/__cdist_kill_on_interrupt new file mode 100644 index 00000000..7cb711fa --- /dev/null +++ b/core/__cdist_kill_on_interrupt @@ -0,0 +1,31 @@ +#!/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 . +# +# +# Run the given command for each created object. +# + +# Does not work in children, will be called again in every script! +# Use only in interactive "front end" scripts +__cdist_kill_on_interrupt() +{ + __cdist_tmp_removal + kill 0 + exit 1 +} diff --git a/core/__cdist_manifest_run b/core/__cdist_manifest_run new file mode 100755 index 00000000..cf85d646 --- /dev/null +++ b/core/__cdist_manifest_run @@ -0,0 +1,53 @@ +#!/bin/sh +# +# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Let's build a cconfig tree from a configuration +# And save it into the cache tree +# + +__cdist_manifest_run() +{ + [ $# -eq 1 ] || __cdist_usage "" + + __cdist_manifest="$1"; shift + + ################################################################################ + # Export information for cdist-type-emulator or manifest + # + + # Config dir should not get reset - FIXME: why did I do this? + export __cdist_conf_dir + + # Used to record the source in the object + export __cdist_manifest + + # Export information for manifests - __cdist_out_dir comes from cdist-config + export $__cdist_name_var_global="$__cdist_out_dir" + + ################################################################################ + # The actual run + # + + # Ensure binaries are existing - FIXME: move error handling into __cdist_type_build_emulation + __cdist_type_build_emulation \ + || __cdist_exit_err "Failed to build type emulation binaries" + + __cdist_run_shell "${__cdist_manifest}" +} diff --git a/core/__cdist_manifest_run_init b/core/__cdist_manifest_run_init new file mode 100755 index 00000000..e8fa63de --- /dev/null +++ b/core/__cdist_manifest_run_init @@ -0,0 +1,32 @@ +#!/bin/sh +# +# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Let's build a cconfig tree from a configuration +# And save it into the cache tree +# + +__cdist_manifest_run_init() +{ + # FIXME: probably do not export but always set explicitly? + export $__cdist_name_var_manifest="$__cdist_manifest_dir" + + __cdist_echo info "Running initial manifest for $__cdist_target_host " + __cdist_manifest_run "$__cdist_manifest_init" +} diff --git a/core/__cdist_object_all b/core/__cdist_object_all new file mode 100755 index 00000000..965d08f6 --- /dev/null +++ b/core/__cdist_object_all @@ -0,0 +1,60 @@ +#!/bin/sh +# +# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 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 . +# +# +# Run the given command for each created object. +# + +__cdist_object_all() +{ + [ $# -eq 1 ] || __cdist_usage "" + + __cdist_object_all_object_all_command="$1"; shift + + __cdist_object_all_object_all_objects="$__cdist_tmp_dir/objects" + + # Ensure object dir exists, so marker can be created + mkdir -p "${__cdist_out_object_dir}" + + # FIXME: : - why do we use a file? + # core/__cdist_object_manifest_run: touch "$__cdist_objects_created" + + # Loop until we do not create new objects anymore + # which is equal to all objects have been run + touch "$__cdist_objects_created" + while [ -f "$__cdist_objects_created" ]; do + # Assume we're done after this run + rm "$__cdist_objects_created" + + # Get listing of objects + __cdist_object_list "$__cdist_out_object_dir" > \ + "$__cdist_object_all_object_all_objects" + + # NEED TO CREATE ARRAY, SSH DESTROYS WHILE READ LOOP + while read __cdist_object_all_object; do + set -- "$@" "$__cdist_object_all_object" + done < "$__cdist_object_all_object_all_objects" + + while [ $# -gt 0 ]; do + __cdist_object_all_object="$1"; shift + $__cdist_object_all_object_all_command "$__cdist_object_all_object" + done + done +} diff --git a/core/__cdist_object_code_run b/core/__cdist_object_code_run new file mode 100755 index 00000000..8af67ab8 --- /dev/null +++ b/core/__cdist_object_code_run @@ -0,0 +1,54 @@ +#!/bin/sh +# +# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 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 . +# +# +# Exec the code for the given object locally and remote +# + +__cdist_object_code_run() +{ + [ $# -eq 1 ] || __cdist_exit_err "" + + + if [ ! -d "$(__cdist_object_dir "$1")" ]; then + __cdist_exit_err "Object undefined" + fi + + # Code local + export __cdist_out_object_dir="$__cdist_out_object_dir" + __cdist_echo debug "Trying to run local code" + if __cdist_is_executable \ + "$(__cdist_object_code "$1" "${__cdist_name_gencode_local}")"; then + __cdist_run_shell \ + "$(__cdist_object_code "$1" "${__cdist_name_gencode_local}")" + else + __cdist_echo debug "Local code: none" + fi + + # Code remote + __cdist_echo debug "Trying to run remote code" + if __cdist_is_executable \ + "$(__cdist_object_code "$1" "${__cdist_name_gencode_remote}")"; then + + __cdist_run_remote $(__cdist_remote_object_code "$1") + else + __cdist_echo debug "Remote code: none" + fi +} diff --git a/core/__cdist_object_explorer_run b/core/__cdist_object_explorer_run new file mode 100755 index 00000000..da59d6c3 --- /dev/null +++ b/core/__cdist_object_explorer_run @@ -0,0 +1,89 @@ +#!/bin/sh +# +# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 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 . +# +# +# Run the explorers for the given object on the target host. +# + +# FIXME: many cleanups needed before going production! + +__cdist_object_explorer_run() +{ + __cdist_object_self="$1"; shift + + __cdist_object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" + __cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" + + # Check if type of object has >= 1 explorer + __cdist_has_explorer="$(__cdist_dir_listing "$(__cdist_type_explorer_dir "$__cdist_type")" | wc -l)" + # Run the type explorers for the current object if any + if [ "$__cdist_has_explorer" -ge 1 ]; then + if ! __cdist_type_explorer_pushed "$__cdist_type"; then + # FIXME: variables! + src_dir="$(__cdist_type_explorer_dir "$__cdist_type")" + dst_dir="$(__cdist_remote_type_explorer_dir "$__cdist_type")" + __cdist_echo info "Transfering explorers for $__cdist_type " + __cdist_dir push "$src_dir" "$dst_dir" + __cdist_type_explorer_pushed_add "$__cdist_type" + fi + + __cdist_echo info "Running explorers" + # Copy object parameters + __cdist_dir push \ + "$(__cdist_object_parameter_dir "$__cdist_object_self")" \ + "$(__cdist_remote_object_parameter_dir "$__cdist_object_self")" + + # Execute explorers + # FIXME: STOPPED: + # - remove cdist-remote-explorer-run + # - problem: new variables / need to run explorer directly? + # -> or put logic into __cdist_explorer_run + # -> think about having _one_ wrapper script for remote to execute + # shell functions + + # Create remote output directory + __cdist_run_remote mkdir -p "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" + + cd "$(__cdist_type_explorer_dir "$__cdist_type")" + + + for __cdist_object_explorer_run_explorer in *; do + __cdist_run_remote \ + "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" \ + "$__cdist_name_var_object_id=\"$__cdist_object_id\"" \ + "$__cdist_name_var_self=\"$__cdist_object_self\"" \ + "$(__cdist_remote_type_explorer_dir "$__cdist_type")/$__cdist_object_explorer_run_explorer" \ + ">" "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")/$__cdist_object_explorer_run_explorer" + done + +# __cdist_run_remote \ +# "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" \ +# "$__cdist_name_var_object_id=\"$__cdist_object_id\"" \ +# "$__cdist_name_var_self=\"$__cdist_object_self\"" \ +# cdist-remote-explorer-run \ +# "$__cdist_name_var_type_explorer" \ +# "$(__cdist_remote_type_explorer_dir "$__cdist_type")" \ +# "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" + + # Copy back results + __cdist_dir pull "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" \ + "$(__cdist_object_type_explorer_dir "$__cdist_object_self")" + fi +} diff --git a/core/__cdist_object_gencode b/core/__cdist_object_gencode new file mode 100755 index 00000000..08ef8b7d --- /dev/null +++ b/core/__cdist_object_gencode @@ -0,0 +1,66 @@ +#!/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 . +# +# +# Generate code from one object (object must be relative path!) +# WARNING: OUTPUT ON STDOUT, ERRORS NEED TO BE ON STDERR! +# + +# FIXME: check variable names: +# either prefix or use global or use functions directly +# functions looks good, they are cheap anyway! + +__cdist_object_gencode() +{ + [ $# -eq 2 ] || __cdist_usage "" "" + + __cdist_object_self="$1"; shift + __cdist_gencode_type="$1"; shift + + __cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" + __cdist_type_gencode="$(__cdist_type_gencode "$__cdist_type" "$__cdist_gencode_type")" + __cdist_code_output="$(__cdist_object_code "$__cdist_object_self" "$__cdist_gencode_type")" + + # export variables for the gencode script + export __object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" + export __object="$(__cdist_object_dir "$__cdist_object_self")" + export __global="$__cdist_out_dir" + + if [ -x "$__cdist_type_gencode" ]; then + __cdist_run_shell "$__cdist_type_gencode" > "$__cdist_tmp_file" + else + if [ -e "$__cdist_type_gencode" ]; then + __cdist_exit_err "$__cdist_type_gencode exists, but is not executable" + fi + + # Ensure it's empty, if there is no gencode + : > "$__cdist_tmp_file" + fi + + # Only create code, if gencode created output + if [ "$(wc -l < "$__cdist_tmp_file")" -gt 0 ]; then + cat - "$__cdist_tmp_file" << eof > "$__cdist_code_output" +# +# The following code was generated by $__cdist_type_gencode +# + +eof + chmod u+x "${__cdist_code_output}" + fi +} diff --git a/core/__cdist_object_gencode_run b/core/__cdist_object_gencode_run new file mode 100755 index 00000000..308f5f33 --- /dev/null +++ b/core/__cdist_object_gencode_run @@ -0,0 +1,36 @@ +#!/bin/sh +# +# 2010 Nico Schottelius (nico-cdist at schottelius.org) +# 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 . +# +# +# For the given object create the code to be executed on the target. +# + +__cdist_object_gencode_run() +{ + __cdist_object_gencode_run_object="$1"; shift + + __cdist_echo info "Generating local code " + __cdist_object_gencode "$__cdist_object_gencode_run_object" \ + "${__cdist_name_gencode_local}" + + __cdist_echo info "Generating remote code " + __cdist_object_gencode "$__cdist_object_gencode_run_object" \ + "${__cdist_name_gencode_remote}" +} diff --git a/core/__cdist_object_list b/core/__cdist_object_list new file mode 100755 index 00000000..f2785c30 --- /dev/null +++ b/core/__cdist_object_list @@ -0,0 +1,36 @@ +#!/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 . +# +# +# Print error and exit (perror() alike) +# + +__cdist_object_list() +{ + # FIXME: no local in posix + local basedir="$1"; shift + + # Use subshell to prevent changing cwd in program + ( + cd "${basedir}" + + find . -name "$__cdist_name_dot_cdist" | \ + sed -e 's;^./;;' -e "s;/${__cdist_name_dot_cdist}\$;;" + ) +} diff --git a/core/__cdist_object_manifest_run b/core/__cdist_object_manifest_run new file mode 100755 index 00000000..efc85539 --- /dev/null +++ b/core/__cdist_object_manifest_run @@ -0,0 +1,59 @@ +#!/bin/sh +# +# 2010 Nico Schottelius (nico-cdist at schottelius.org) +# 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 . +# +# +# Run the manifest for the given object. +# + + +__cdist_object_manifest_run() +{ + [ $# -eq 1 ] || __cdist_usage "" + + __cdist_object_self="$1"; shift + + # FIXME: rename to __cdist_object_dir (everywhere!) + __cdist_cur_object_dir="$(__cdist_object_dir "$__cdist_object_self")" + __cdist_object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" + + __cdist_echo info "Checking manifest " + + __cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" + __cdist_manifest="$(__cdist_type_manifest "$__cdist_type")" + + if [ -f "$__cdist_manifest" ]; then + if [ -x "$__cdist_manifest" ]; then + # Make __cdist_manifest available for cdist-type-emulator + export __cdist_manifest + + __cdist_echo info "Executing manifest " + export $__cdist_name_var_object="$__cdist_cur_object_dir" + export $__cdist_name_var_object_id="$__cdist_object_id" + export $__cdist_name_var_type="$(__cdist_type_dir "$__cdist_type")" + + __cdist_manifest_run "$__cdist_manifest" + + # Tell cdist-object-run-all that there may be new objects + touch "$__cdist_objects_created" + else + __cdist_exit_err "${__cdist_manifest} needs to be executable." + fi + fi +} diff --git a/core/__cdist_object_prepare b/core/__cdist_object_prepare new file mode 100755 index 00000000..24039be0 --- /dev/null +++ b/core/__cdist_object_prepare @@ -0,0 +1,47 @@ +#!/bin/sh +# +# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 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 . +# +# +# For the given object: +# - run type explorers +# - run type manifest +# + +__cdist_object_prepare() +{ + [ $# -eq 1 ] || __cdist_usage "" + + __cdist_object_self="$1"; shift + __cdist_object_dir="$(__cdist_object_dir "$__cdist_object_self")" + [ -d "$__cdist_object_dir" ] || __cdist_exit_err "Object undefined" + + # Export to non-core for use in manifest and gencode scripts + export $__cdist_name_var_self=$__cdist_object_self + + __cdist_object_prepared="$(__cdist_object_prepared "$__cdist_object_self")" + if [ ! -f "$__cdist_object_prepared" ]; then + __cdist_echo info "Preparing object" + __cdist_object_explorer_run "$__cdist_object_self" + __cdist_object_manifest_run "$__cdist_object_self" + + # Mark this object as prepared + touch "$__cdist_object_prepared" + fi +} diff --git a/core/__cdist_object_run b/core/__cdist_object_run new file mode 100755 index 00000000..d2c7df6e --- /dev/null +++ b/core/__cdist_object_run @@ -0,0 +1,74 @@ +#!/bin/sh +# +# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 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 . +# +# +# For the given object: +# - run type explorers +# - run type manifest +# - generate code +# - copy object to target +# - execute code on target +# + +__cdist_object_run() +{ + [ $# -eq 1 ] || __cdist_usage "" + + __cdist_object_self="$1"; shift + __cdist_object_dir="$(__cdist_object_dir "$__cdist_object_self")" + [ -d "$__cdist_object_dir" ] || __cdist_exit_err "Object undefined" + + # Export to non-core for use in manifest and gencode scripts + export $__cdist_name_var_self=$__cdist_object_self + + # FIXME: BUG: should be named differently! + # FIXME: BUG: I can be called recursively! -> variables are probably already set / overwritten! + __cdist_object_finished="$(__cdist_object_finished "$__cdist_object_self")" + if [ ! -f "$__cdist_object_finished" ]; then + # Resolve dependencies, if any + __cdist_object_require="$(__cdist_object_require "$__cdist_object_self")" + if [ -f "$__cdist_object_require" ]; then + # NEED TO CREATE ARRAY, SSH DESTROYS WHILE READ LOOP + while read __cdist_requirement; do + set -- "$@" "$__cdist_requirement" + done < "$__cdist_object_require" + + while [ $# -gt 0 ]; do + __cdist_requirement="$1"; shift + __cdist_echo info "Resolving requirement $__cdist_requirement" + # FIXME: BUG: at this point, the other __cdist_object_run may have + # overwritten all our variables! + __cdist_object_run "$__cdist_requirement" + done + fi + + __cdist_echo debug "Before gencode" + __cdist_object_gencode_run "$__cdist_object_self" + __cdist_echo debug "Before push" + __cdist_dir push "$(__cdist_object_dir "$__cdist_object_self")" \ + "$(__cdist_remote_object_dir "$__cdist_object_self")" + __cdist_echo debug "Before run" + __cdist_object_code_run "$__cdist_object_self" + __cdist_echo debug "Object run done" + + # Mark this object as done + touch "$__cdist_object_finished" + fi +} diff --git a/core/__cdist_run b/core/__cdist_run new file mode 100755 index 00000000..8febe550 --- /dev/null +++ b/core/__cdist_run @@ -0,0 +1,27 @@ +#!/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 . +# +# +# Exit if an error occurs running something +# + +__cdist_run() +{ + "$@" || __cdist_echo error "$1 exited non-zero, aborting." +} diff --git a/core/__cdist_run_remote b/core/__cdist_run_remote new file mode 100755 index 00000000..17074049 --- /dev/null +++ b/core/__cdist_run_remote @@ -0,0 +1,32 @@ +#!/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 . +# +# +# Run a cdist binary on the remote side +# + +__cdist_run_remote() +{ + [ $# -ge 1 ] || __cdist_usage " [opts]" + + ssh "${__cdist_remote_user}@${__cdist_target_host}" \ + "export PATH=\"${__cdist_remote_bin_dir}:\$PATH\";" \ + "export __cdist_out_object_dir=\"$__cdist_remote_out_object_dir\";" \ + "$@" +} diff --git a/core/__cdist_run_shell b/core/__cdist_run_shell new file mode 100755 index 00000000..b6e0a57d --- /dev/null +++ b/core/__cdist_run_shell @@ -0,0 +1,34 @@ +#!/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 . +# +# +# Exit if an error occurs when running a shell script +# + +__cdist_run_shell() +{ + # Prepend our path, so all cdist tools come before other tools + PATH="${__cdist_out_type_bin_dir}:$PATH" sh -e "$@" + if [ "$?" -ne 0 ]; then + __cdist_echo error "$1 exited non-zero" + __cdist_echo warn "Faulty code:" + cat "$1" + __cdist_exit_err "Aborting due to non-zero exit code." + fi +} diff --git a/core/__cdist_tmp_removal b/core/__cdist_tmp_removal new file mode 100755 index 00000000..74d74936 --- /dev/null +++ b/core/__cdist_tmp_removal @@ -0,0 +1,27 @@ +#!/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 . +# +# +# Remove tmp dir +# + +__cdist_tmp_removal() +{ + rm -rf "${__cdist_tmp_dir}" +} diff --git a/core/__cdist_type_build_emulation b/core/__cdist_type_build_emulation new file mode 100755 index 00000000..3c7270ca --- /dev/null +++ b/core/__cdist_type_build_emulation @@ -0,0 +1,49 @@ +#!/bin/sh +# +# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# Build pseudo binaries for type emulation +# + +__cdist_type_build_emulation() +{ + [ $# -eq 0 ] || __cdist_usage "No arguments" + + [ -f "${__cdist_out_type_bin_dir}/.marker" ] && return 0 + + __cdist_type_emulator="$__cdist_abs_mydir/cdist-type-emulator" + + if [ ! -d "${__cdist_type_dir}" ]; then + __cdist_exit_err "$__cdist_type_dir must exist and contain available types" + fi + + # Get Types + ( + cd "${__cdist_type_dir}" + ls -1 > "${__cdist_tmp_file}" + ) + + # Create binaries + mkdir -p "${__cdist_out_type_bin_dir}" + while read __cdist_type_build_emulation_type; do + ln -sf "${__cdist_type_emulator}" \ + "${__cdist_out_type_bin_dir}/${__cdist_type_build_emulation_type}" + done < "${__cdist_tmp_file}" + + touch "${__cdist_out_type_bin_dir}/.marker" +} diff --git a/core/__cdist_usage b/core/__cdist_usage new file mode 100755 index 00000000..9dfa30e4 --- /dev/null +++ b/core/__cdist_usage @@ -0,0 +1,27 @@ +#!/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 . +# +# +# Print error and exit (perror() alike) +# + +__cdist_usage() +{ + __cdist_exit_err "$__cdist_myname: $@" +} From 34bb39193707b4f8a6e84db36bcc38801fa3f954 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 01:01:25 +0200 Subject: [PATCH 0138/4212] +header Signed-off-by: Nico Schottelius --- bin/cdist | 425 ++---------------------------------------------------- 1 file changed, 13 insertions(+), 412 deletions(-) mode change 100644 => 100755 bin/cdist diff --git a/bin/cdist b/bin/cdist old mode 100644 new mode 100755 index a70a11f8..31d7411b --- a/bin/cdist +++ b/bin/cdist @@ -1,4 +1,4 @@ -#!python3 +#!/usr/bin/env python3 # # 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) # @@ -19,420 +19,21 @@ # # -__cdist_version="1.7.0" +import sys # argv -# Fail if something bogus is going on -set -u +__cdist_version="2.0.0" -################################################################################ -# cconf standard vars prefixed with cdist +def cdist_echo(type, *args): + """Ignore type for now, support later""" + print(*args) -__cdist_pwd="$(pwd -P)" -__cdist_mydir="${0%/*}"; -__cdist_abs_mydir="$(cd "$__cdist_mydir" && pwd -P)" -__cdist_myname=${0##*/}; -__cdist_abs_myname="$__cdist_abs_mydir/$__cdist_myname" +def cdist_deploy_to(hostname): + """Mimic the old deploy to: Deploy to one host""" + cdist_echo("info", "Deploying to host", hostname) -################################################################################ -# Names / Constants -# -# Most values can be overriden from outside, so you can -# customise paths as you like (for distributors, geeks and hackers) -# -: ${__cdist_name_bin:=bin} -: ${__cdist_name_cache:=cache} -: ${__cdist_name_code:=code} -: ${__cdist_name_conf_dir:=conf} -: ${__cdist_name_dot_cdist:=.cdist} -: ${__cdist_name_explorer:=explorer} -: ${__cdist_name_gencode:=gencode} -: ${__cdist_name_gencode_local:=local} -: ${__cdist_name_gencode_remote:=remote} -: ${__cdist_name_global:=global} -: ${__cdist_name_host:=host} -: ${__cdist_name_init:=init} -: ${__cdist_name_manifest:=manifest} -: ${__cdist_name_object:=object} -: ${__cdist_name_object_finished:=done} -: ${__cdist_name_object_prepared:=prepared} -: ${__cdist_name_object_id:=object_id} -: ${__cdist_name_object_source:=source} -: ${__cdist_name_objects_created:=.objects_created} -: ${__cdist_name_out_dir:=out} -: ${__cdist_name_parameter:=parameter} -: ${__cdist_name_parameter_required:=required} -: ${__cdist_name_parameter_optional:=optional} -: ${__cdist_name_require:=require} -: ${__cdist_name_self:=self} -: ${__cdist_name_singleton:=singleton} -: ${__cdist_name_target_host:=target_host} -: ${__cdist_name_target_user:=target_user} -: ${__cdist_name_type:=type} -: ${__cdist_name_type_bin:=type_bin} -: ${__cdist_name_type_explorer:=type_explorer} -: ${__cdist_name_type_explorer_pushed:=.explorer_pushed} +if __name__ == "__main__": + hostname=sys.argv[1] + cdist_echo("info", "cdist", __cdist_version, ": Configuring host", hostname) + cdist_deploy_to(hostname) -# Used for IDs: Allow everything not starting with - and . -: ${__cdist_sane_regexp:=[^-\.].*} - -# Default remote user -: ${__cdist_remote_user:=root} - - -################################################################################ -# Exported variable names (usable for non core -# -: ${__cdist_name_var_explorer:=__$__cdist_name_explorer} -: ${__cdist_name_var_type_explorer:=__$__cdist_name_type_explorer} -: ${__cdist_name_var_global:=__$__cdist_name_global} -: ${__cdist_name_var_manifest:=__$__cdist_name_manifest} -: ${__cdist_name_var_target_host:=__$__cdist_name_target_host} -: ${__cdist_name_var_target_user:=__$__cdist_name_target_user} -: ${__cdist_name_var_object:=__$__cdist_name_object} -: ${__cdist_name_var_object_id:=__$__cdist_name_object_id} -: ${__cdist_name_var_self:=__$__cdist_name_self} -: ${__cdist_name_var_type:=__$__cdist_name_type} - - -################################################################################ -# Tempfiles -# -: ${__cdist_tmp_base_dir=/tmp} -__cdist_tmp_dir=$(mktemp -d "$__cdist_tmp_base_dir/cdist.XXXXXXXXXXXX") -__cdist_tmp_file=$(mktemp "$__cdist_tmp_dir/cdist.XXXXXXXXXXXX") - -################################################################################ -# Local Base -# -: ${__cdist_local_base_dir:=$__cdist_tmp_dir} - -# Cache may *NOT* be below __cdist_local_base_dir! -: ${__cdist_local_base_cache_dir:=$__cdist_abs_mydir/../$__cdist_name_cache} - -: ${__cdist_conf_dir:="$(cd "$__cdist_abs_mydir/../conf" && pwd -P)"} - -: ${__cdist_explorer_dir:=$__cdist_conf_dir/$__cdist_name_explorer} -: ${__cdist_manifest_dir:=$__cdist_conf_dir/$__cdist_name_manifest} -: ${__cdist_manifest_init:=$__cdist_manifest_dir/$__cdist_name_init} -: ${__cdist_type_dir:=$__cdist_conf_dir/$__cdist_name_type} - -################################################################################ -# Local output -# -: ${__cdist_out_dir:=$__cdist_local_base_dir/$__cdist_name_out_dir} -: ${__cdist_out_explorer_dir:=$__cdist_out_dir/$__cdist_name_explorer} -: ${__cdist_out_object_dir:=$__cdist_out_dir/$__cdist_name_object} -: ${__cdist_out_type_dir:=$__cdist_out_dir/$__cdist_name_type} -: ${__cdist_out_type_bin_dir:=$__cdist_out_dir/$__cdist_name_type_bin} - -: ${__cdist_objects_created:=$__cdist_out_object_dir/$__cdist_name_objects_created} - -################################################################################ -# Remote base -# -: ${__cdist_remote_base_dir:=/var/lib/cdist} -: ${__cdist_remote_bin_dir:=$__cdist_remote_base_dir/$__cdist_name_bin} -: ${__cdist_remote_conf_dir:=$__cdist_remote_base_dir/$__cdist_name_conf_dir} - -: ${__cdist_remote_explorer_dir:=$__cdist_remote_conf_dir/$__cdist_name_explorer} -: ${__cdist_remote_type_dir:=$__cdist_remote_conf_dir/$__cdist_name_type} - -################################################################################ -# Remote output -# -: ${__cdist_remote_out_dir:=$__cdist_remote_base_dir/$__cdist_name_out_dir} -: ${__cdist_remote_out_explorer_dir:=$__cdist_remote_out_dir/$__cdist_name_explorer} -: ${__cdist_remote_out_object_dir:=$__cdist_remote_out_dir/$__cdist_name_object} - - -################################################################################ -# Internal functions -# -__cdist_echo() -{ - __cdist_echo_type="$1"; shift - - set +u - if [ "$__cdist_object_self" ]; then - __cdist_echo_prefix="${__cdist_object_self}:" - else - __cdist_echo_prefix="core: " - fi - set -u - - case "$__cdist_echo_type" in - debug) - set +u - if [ "$__cdist_debug" ]; then - echo $__cdist_echo_prefix "Debug: $@" - fi - set -u - ;; - info) - echo $__cdist_echo_prefix "$@" - ;; - warn) - echo $__cdist_echo_prefix "Warning: $@" - ;; - error) - echo $__cdist_echo_prefix "Error: $@" >&2 - ;; - *) - echo "CORE BUG, who created the broken commit in $0?" >&2 - exit 23 - ;; - esac -} - -__cdist_exec_fail_on_error() -{ - set +e - sh -e "$@" - if [ "$?" -ne 0 ]; then - __cdist_echo error "$1 exited non-zero" - __cdist_echo warn "Faulty code:" - cat "$1" - __cdist_exit_err "Aborting due to non-zero exit code." - fi -} - -__cdist_exit_err() -{ - __cdist_echo error "$@" - exit 1 -} - -__cdist_usage() -{ - __cdist_exit_err "$__cdist_myname: $@" -} - -__cdist_init_deploy() -{ - __cdist_echo info "Creating clean directory structure " - - # Ensure there is no old stuff, neither local nor remote - rm -rf "$__cdist_local_base_dir" - ssh "${__cdist_remote_user}@$1" "rm -rf ${__cdist_remote_base_dir}" - - # Init base - mkdir -p "$__cdist_local_base_dir" - ssh "${__cdist_remote_user}@$1" "mkdir -p ${__cdist_remote_base_dir}" - - # Link configuration source directory - consistent with remote - ln -sf "$__cdist_conf_dir" "$__cdist_local_base_dir/$__cdist_name_conf_dir" -} - -################################################################################ -# Cache -# -__cdist_cache_dir() -{ - cd "${__cdist_local_base_cache_dir}" && pwd -P -} - -__cdist_host_cache_dir() -{ - echo "$(__cdist_cache_dir)/$1" -} - -################################################################################ -# Object -# - -__cdist_object_code() -{ - echo "$(__cdist_object_dir "$1")/${__cdist_name_code}-$2" -} - -__cdist_object_prepared() -{ - echo "$(__cdist_object_dir "$1")/${__cdist_name_object_prepared}" -} - -__cdist_object_finished() -{ - echo "$(__cdist_object_dir "$1")/${__cdist_name_object_finished}" -} - -__cdist_object_dir() -{ - echo "$(__cdist_object_base_dir "$1")/${__cdist_name_dot_cdist}" -} - -__cdist_object_base_dir() -{ - echo "${__cdist_out_object_dir}/$1" -} - - -__cdist_object_id_from_object() -{ - echo "${1#*/}" -} - -# Find objects, remove ./ and /MARKER -__cdist_object_list() -{ - local basedir="$1"; shift - - # Use subshell to prevent changing cwd in program - ( - cd "${basedir}" - - find . -name "$__cdist_name_dot_cdist" | \ - sed -e 's;^./;;' -e "s;/${__cdist_name_dot_cdist}\$;;" - ) -} - -__cdist_object_parameter_dir() -{ - echo "$(__cdist_object_dir "$1")/${__cdist_name_parameter}" -} - -__cdist_object_require() -{ - echo "$(__cdist_object_dir "$1")/${__cdist_name_require}" -} - -__cdist_object_source_name() -{ - echo "$1/${__cdist_name_object_source}" -} - -__cdist_object_source() -{ - cat "$(__cdist_object_source_name "$1")" -} - -__cdist_object_source_add() -{ - echo "$__cdist_manifest" >> "$(__cdist_object_source_name "$1")" -} - -__cdist_object_type_explorer_dir() -{ - echo "$(__cdist_object_dir "$1")/${__cdist_name_explorer}" -} - -################################################################################ -# Remote -# - -__cdist_remote_object_base_dir() -{ - echo "${__cdist_remote_out_object_dir}/$1" -} - -__cdist_remote_object_dir() -{ - echo "$(__cdist_remote_object_base_dir "$1")/${__cdist_name_dot_cdist}" -} - -__cdist_remote_object_parameter_dir() -{ - echo "$(__cdist_remote_object_dir "$1")/${__cdist_name_parameter}" -} - -__cdist_remote_object_type_explorer_dir() -{ - echo "$(__cdist_remote_object_dir "$1")/${__cdist_name_explorer}" -} - - -__cdist_remote_type_explorer_dir() -{ - echo "${__cdist_remote_type_dir}/$1/${__cdist_name_explorer}" -} - - -################################################################################ -# Traps -# -__cdist_tmp_removal() -{ - rm -rf "${__cdist_tmp_dir}" -} - -# Does not work in children, will be called again in every script! -# Use only in interactive "front end" scripts -__cdist_kill_on_interrupt() -{ - __cdist_tmp_removal - kill 0 - exit 1 -} - -# Remove tempfiles at normal exit -trap __cdist_tmp_removal EXIT - - -################################################################################ -# Type -# -__cdist_type_dir() -{ - echo "${__cdist_type_dir}/$1" -} - -__cdist_type_explorer_dir() -{ - echo "${__cdist_type_dir}/$1/${__cdist_name_explorer}" -} - -__cdist_type_from_object() -{ - echo "${1%%/*}" -} - -__cdist_type_has_explorer() -{ - # We only create output, if there's at least one explorer - # and can thus be used as a boolean ;-) - if [ -d "$(__cdist_type_explorer_dir "$1")" ]; then - ls -1 "$(__cdist_type_explorer_dir "$1")" - fi -} - -__cdist_type_explorer_pushed() -{ - [ -f "${__cdist_out_type_dir}/${__cdist_name_type_explorer_pushed}" ] \ - && grep -q "$1" "${__cdist_out_type_dir}/${__cdist_name_type_explorer_pushed}" -} - -__cdist_type_explorer_pushed_add() -{ - [ -d "$__cdist_out_type_dir" ] || mkdir "$__cdist_out_type_dir" - echo "$1" >> "${__cdist_out_type_dir}/${__cdist_name_type_explorer_pushed}" -} - -__cdist_type_gencode() -{ - echo "${__cdist_type_dir}/$1/${__cdist_name_gencode}-$2" -} - -__cdist_type_manifest() -{ - echo "${__cdist_type_dir}/$1/${__cdist_name_manifest}" -} - -__cdist_type_parameter_dir() -{ - echo "$(__cdist_type_dir "$1")/${__cdist_name_parameter}" -} - -__cdist_type_parameter_optional() -{ - echo "$(__cdist_type_parameter_dir "$1")/$__cdist_name_parameter_optional" -} - -__cdist_type_parameter_required() -{ - echo "$(__cdist_type_parameter_dir "$1")/$__cdist_name_parameter_required" -} - -__cdist_type_singleton() -{ - echo "${__cdist_type_dir}/$1/${__cdist_name_singleton}" -} From 4f7fa6b8924ec1dc8651382a8d35fe532075f39e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 01:10:37 +0200 Subject: [PATCH 0139/4212] +/- todo Signed-off-by: Nico Schottelius --- core/__cdist_init_deploy | 40 ---------------------------------------- doc/dev/todo/niconext | 28 ++-------------------------- 2 files changed, 2 insertions(+), 66 deletions(-) delete mode 100755 core/__cdist_init_deploy diff --git a/core/__cdist_init_deploy b/core/__cdist_init_deploy deleted file mode 100755 index 4ac3168c..00000000 --- a/core/__cdist_init_deploy +++ /dev/null @@ -1,40 +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 . -# -# -# Prepare deployment -# - -__cdist_init_deploy() -{ - __cdist_echo info "Creating clean directory structure " - - # Ensure there is no old stuff, neither local nor remote - rm -rf "$__cdist_local_base_dir" - ssh "${__cdist_remote_user}@${__cdist_target_host}" \ - "rm -rf ${__cdist_remote_base_dir}" - - # Init base - mkdir -p "$__cdist_local_base_dir" - ssh "${__cdist_remote_user}@${__cdist_target_host}" \ - "mkdir -p ${__cdist_remote_base_dir}" - - # Link configuration source directory - consistent with remote - ln -sf "$__cdist_conf_dir" "$__cdist_local_base_dir/$__cdist_name_conf_dir" -} diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 28762ef4..a59f909f 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,26 +1,2 @@ -Catch broken instances in cdist-mass-deploy -p and report broken deployements at the end! - - --------------------------------------------------------------------------------- -Bug with requirements when indirect requires is scheduled late: - -__package/collectd: Generating local code -__package/collectd: Generating remote code -__package/collectd: Transferring object -__package/collectd: Checking code-local -__package/collectd: Checking code-remote -__file/etc/collectd/collectd.conf: Generating local code -__file/etc/collectd/collectd.conf: Generating remote code -__file/etc/collectd/collectd.conf: Transferring object -__file/etc/collectd/collectd.conf: Checking code-local -__file/etc/collectd/collectd.conf: Executing code-local -scp: /etc/collectd/collectd.conf: No such file or directory -__file/etc/collectd/collectd.conf: Error: /tmp/cdist.PYKFWmj9QknE/out/object/__file/etc/collectd/collectd.conf/.cdist/code-local exited non-zero -__file/etc/collectd/collectd.conf: Warning: Faulty code: -# -# The following code was generated by /home/users/nico/oeffentlich/rechner/projekte/cdist-nutzung/conf/type/__file/gencode-local -# - -scp /home/users/nico/oeffentlich/rechner/projekte/cdist-nutzung/conf/type/__ethz_collectd/files/collectd.conf.client root@shrek08:/etc/collectd/collectd.conf -__file/etc/collectd/collectd.conf: Error: Aborting due to non-zero exit code. - +- rewrite in python? +- support non-ssh access? From 9711a5612d359919ff0a254042c4fec4ba17f1ca Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 01:21:15 +0200 Subject: [PATCH 0140/4212] partly implement run_or_fail, init_deploy Signed-off-by: Nico Schottelius --- bin/cdist | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index 31d7411b..233e6fee 100755 --- a/bin/cdist +++ b/bin/cdist @@ -20,20 +20,51 @@ # import sys # argv +import subprocess # execute stuff __cdist_version="2.0.0" -def cdist_echo(type, *args): +def logger(type, *args): """Ignore type for now, support later""" print(*args) +def exit_error(*args): + logger(*args) + sys.exit(1) + + +def run_or_fail(*args): + try: + subprocess.check_call(*args) + except CalledProcessError: + exit_error("Command failed:", *args) + + def cdist_deploy_to(hostname): """Mimic the old deploy to: Deploy to one host""" - cdist_echo("info", "Deploying to host", hostname) + logger("info", "Deploying to host", hostname) + + +def init_deploy(): + logger("info", "Creating clean directory structure") + + # Ensure there is no old stuff, neither local nor remote + run_or_fail(["echo rm -rf", "$__cdist_local_base_dir"]) + +# ssh "${__cdist_remote_user}@${__cdist_target_host}" \ +# "rm -rf ${__cdist_remote_base_dir}" +# +# # Init base +# mkdir -p "$__cdist_local_base_dir" +# ssh "${__cdist_remote_user}@${__cdist_target_host}" \ +# "mkdir -p ${__cdist_remote_base_dir}" +# +# # Link configuraion source directory - consistent with remote +# ln -sf "$__cdist_conf_dir" "$__cdist_local_base_dir/$__cdist_name_conf_dir" if __name__ == "__main__": hostname=sys.argv[1] - cdist_echo("info", "cdist", __cdist_version, ": Configuring host", hostname) + logger("info", "cdist", __cdist_version, ": Configuring host", hostname) cdist_deploy_to(hostname) From a90751dcff360e6ba2ceb5902ba90f43bdc6686e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 01:36:22 +0200 Subject: [PATCH 0141/4212] begin to implmenent remote execution Signed-off-by: Nico Schottelius --- bin/cdist | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index 233e6fee..d680eaa6 100755 --- a/bin/cdist +++ b/bin/cdist @@ -34,25 +34,34 @@ def exit_error(*args): def run_or_fail(*args): + newargs = ["echo"] + newargs.extend(*args) + try: - subprocess.check_call(*args) + subprocess.check_call(newargs) except CalledProcessError: - exit_error("Command failed:", *args) + exit_error("Command failed:", newargs) + +def remote_run_or_fail(hostname, *args): + newargs = ["ssh", hostname] + newargs.extend(*args) + + run_or_fail(newargs) def cdist_deploy_to(hostname): """Mimic the old deploy to: Deploy to one host""" logger("info", "Deploying to host", hostname) + init_deploy(hostname) -def init_deploy(): +def init_deploy(hostname): logger("info", "Creating clean directory structure") # Ensure there is no old stuff, neither local nor remote - run_or_fail(["echo rm -rf", "$__cdist_local_base_dir"]) + run_or_fail(["echo", "rm -rf", "$__cdist_local_base_dir"]) -# ssh "${__cdist_remote_user}@${__cdist_target_host}" \ -# "rm -rf ${__cdist_remote_base_dir}" + remote_run_or_fail(hostname, ["rm -rf", "${__cdist_remote_base_dir}"]) # # # Init base # mkdir -p "$__cdist_local_base_dir" From 89964b32dd70c587f2b94ef9a4e027680ffb1274 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 01:41:54 +0200 Subject: [PATCH 0142/4212] in theory, init_deploy is done Signed-off-by: Nico Schottelius --- bin/cdist | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/bin/cdist b/bin/cdist index d680eaa6..2ff2e011 100755 --- a/bin/cdist +++ b/bin/cdist @@ -59,17 +59,16 @@ def init_deploy(hostname): logger("info", "Creating clean directory structure") # Ensure there is no old stuff, neither local nor remote - run_or_fail(["echo", "rm -rf", "$__cdist_local_base_dir"]) + run_or_fail(["rm -rf", "$__cdist_local_base_dir"]) remote_run_or_fail(hostname, ["rm -rf", "${__cdist_remote_base_dir}"]) -# -# # Init base -# mkdir -p "$__cdist_local_base_dir" -# ssh "${__cdist_remote_user}@${__cdist_target_host}" \ -# "mkdir -p ${__cdist_remote_base_dir}" -# -# # Link configuraion source directory - consistent with remote -# ln -sf "$__cdist_conf_dir" "$__cdist_local_base_dir/$__cdist_name_conf_dir" + + # Create base directories + run_or_fail(["mkdir -p", "$__cdist_local_base_dir"]) + remote_run_or_fail(hostname,["mkdir -p", "${__cdist_remote_base_dir}"]) + + # Link configuraion source directory - consistent with remote + run_or_fail(["ln -sf", "$__cdist_conf_dir", "$__cdist_local_base_dir/$__cdist_name_conf_dir"]) if __name__ == "__main__": From ffd7f4b251bb4a61239b6a5afa274a6d5061e70c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 01:48:23 +0200 Subject: [PATCH 0143/4212] --todo Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 7 ------- 1 file changed, 7 deletions(-) diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index bf5614bc..84181bbd 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -43,13 +43,6 @@ __cdist_echo info "cdist $__cdist_version: Configuring $__cdist_target_host " # See cdist-stages(7) # -# Prepare local and remote directories -__cdist_init_deploy "$__cdist_target_host" - -# Transfer cdist executables -__cdist_echo info "Transferring cdist binaries to the target host " -cdist-dir push "$__cdist_target_host" \ - "${__cdist_abs_mydir}" "${__cdist_remote_bin_dir}" cdist-explorer-run-global "$__cdist_target_host" cdist-manifest-run-init "$__cdist_target_host" cdist-object-all "$__cdist_target_host" cdist-object-prepare From c2873a8fa0b132003d1cd14b5bc53a6537360c71 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 02:12:48 +0200 Subject: [PATCH 0144/4212] ipmlement base_directory Signed-off-by: Nico Schottelius --- bin/cdist | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/bin/cdist b/bin/cdist index 2ff2e011..440ec459 100755 --- a/bin/cdist +++ b/bin/cdist @@ -21,6 +21,7 @@ import sys # argv import subprocess # execute stuff +import os __cdist_version="2.0.0" @@ -54,6 +55,20 @@ def cdist_deploy_to(hostname): logger("info", "Deploying to host", hostname) init_deploy(hostname) +def base_directory(): + """Returns the directory in which all cdist stuff is based in""" + os.chdir(os.path.join(os.path.dirname(__file__), os.pardir)) + return os.getcwd() + +def global_explorer_directory(): + """Returns path to directory containing the global explorers""" + +def list_global_explorers(): + """Return list of available explorers""" + os.listdir(path=global_explorer_directory()) + +def explore(hostname, type=''): + """Run explorers""" def init_deploy(hostname): logger("info", "Creating clean directory structure") @@ -75,4 +90,5 @@ if __name__ == "__main__": hostname=sys.argv[1] logger("info", "cdist", __cdist_version, ": Configuring host", hostname) cdist_deploy_to(hostname) + print(base_directory()) From 11750515e1bc1bbc821082bac1c901c4eac66ec6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 02:16:13 +0200 Subject: [PATCH 0145/4212] finish global_explorer_directory() Signed-off-by: Nico Schottelius --- bin/cdist | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 440ec459..2246f943 100755 --- a/bin/cdist +++ b/bin/cdist @@ -60,8 +60,13 @@ def base_directory(): os.chdir(os.path.join(os.path.dirname(__file__), os.pardir)) return os.getcwd() +def conf_directory(): + """Returns path to main configuration directory""" + return os.path.join(base_directory(), "conf") + def global_explorer_directory(): """Returns path to directory containing the global explorers""" + return os.path.join(conf_directory(), "explorer") def list_global_explorers(): """Return list of available explorers""" @@ -90,5 +95,5 @@ if __name__ == "__main__": hostname=sys.argv[1] logger("info", "cdist", __cdist_version, ": Configuring host", hostname) cdist_deploy_to(hostname) - print(base_directory()) + print(global_explorer_directory()) From 09c58e2327281d91354460012e94f8ab455a8ed0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 02:39:24 +0200 Subject: [PATCH 0146/4212] exit, if there are no global explorers Signed-off-by: Nico Schottelius --- bin/cdist | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/bin/cdist b/bin/cdist index 2246f943..1019726a 100755 --- a/bin/cdist +++ b/bin/cdist @@ -30,7 +30,7 @@ def logger(type, *args): print(*args) def exit_error(*args): - logger(*args) + logger("error", *args) sys.exit(1) @@ -50,13 +50,9 @@ def remote_run_or_fail(hostname, *args): run_or_fail(newargs) -def cdist_deploy_to(hostname): - """Mimic the old deploy to: Deploy to one host""" - logger("info", "Deploying to host", hostname) - init_deploy(hostname) - def base_directory(): """Returns the directory in which all cdist stuff is based in""" + print("Going to", __file__, os.path.join(os.path.dirname(__file__), os.pardir)) os.chdir(os.path.join(os.path.dirname(__file__), os.pardir)) return os.getcwd() @@ -70,10 +66,14 @@ def global_explorer_directory(): def list_global_explorers(): """Return list of available explorers""" - os.listdir(path=global_explorer_directory()) + return os.listdir(global_explorer_directory()) -def explore(hostname, type=''): - """Run explorers""" +def global_explore(hostname): + """Run global explorers""" + explorer = list_global_explorers() + if(len(explorer) == 0): + exit_error("No explorers found in", global_explorer_directory()) + def init_deploy(hostname): logger("info", "Creating clean directory structure") @@ -90,10 +90,16 @@ def init_deploy(hostname): # Link configuraion source directory - consistent with remote run_or_fail(["ln -sf", "$__cdist_conf_dir", "$__cdist_local_base_dir/$__cdist_name_conf_dir"]) +def cdist_deploy_to(hostname): + """Mimic the old deploy to: Deploy to one host""" + logger("info", "Deploying to host", hostname) + init_deploy(hostname) + global_explore(hostname) + if __name__ == "__main__": hostname=sys.argv[1] logger("info", "cdist", __cdist_version, ": Configuring host", hostname) cdist_deploy_to(hostname) - print(global_explorer_directory()) + print(list_global_explorers()) From 6e3c228a6f2c1b4603e29bf682608015cefab266 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 02:46:09 +0200 Subject: [PATCH 0147/4212] transfer_dir() added Signed-off-by: Nico Schottelius --- bin/cdist | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 1019726a..767d2fe9 100755 --- a/bin/cdist +++ b/bin/cdist @@ -36,6 +36,7 @@ def exit_error(*args): def run_or_fail(*args): newargs = ["echo"] + newargs = [] newargs.extend(*args) try: @@ -49,6 +50,8 @@ def remote_run_or_fail(hostname, *args): run_or_fail(newargs) +def transfer_dir(hostname, source, destination): + run_or_fail(["scp", "-r", source, hostname + ":" + destination]) def base_directory(): """Returns the directory in which all cdist stuff is based in""" @@ -64,16 +67,22 @@ def global_explorer_directory(): """Returns path to directory containing the global explorers""" return os.path.join(conf_directory(), "explorer") +def remote_global_explorer_directory(): + """Returns path to directory containing the global explorers""" + return os.path.join(conf_directory(), "explorer") + def list_global_explorers(): """Return list of available explorers""" return os.listdir(global_explorer_directory()) +def transfer_global_explorers(hostname): + transfer_dir(hostname, global_explorer_directory(), remote_global_explorer_directory()) + def global_explore(hostname): """Run global explorers""" explorer = list_global_explorers() if(len(explorer) == 0): exit_error("No explorers found in", global_explorer_directory()) - def init_deploy(hostname): logger("info", "Creating clean directory structure") From 94fc5b3c911de461e7437518433257e3073e431c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 02:51:45 +0200 Subject: [PATCH 0148/4212] add remove_remote_dir() Signed-off-by: Nico Schottelius --- bin/cdist | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/cdist b/bin/cdist index 767d2fe9..94154974 100755 --- a/bin/cdist +++ b/bin/cdist @@ -50,7 +50,11 @@ def remote_run_or_fail(hostname, *args): run_or_fail(newargs) +def remove_remote_dir(hostname, destination): + remote_run_or_fail(hostname, ["rm", "-rf", destination]) + def transfer_dir(hostname, source, destination): + remove_remote_dir(hostname, destination) run_or_fail(["scp", "-r", source, hostname + ":" + destination]) def base_directory(): From 78a5bbf6e89fad6850f2f1d435c081918ee8dd35 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 02:52:38 +0200 Subject: [PATCH 0149/4212] remove the currently broken init() Signed-off-by: Nico Schottelius --- bin/cdist | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/bin/cdist b/bin/cdist index 94154974..fb09e8b2 100755 --- a/bin/cdist +++ b/bin/cdist @@ -92,16 +92,16 @@ def init_deploy(hostname): logger("info", "Creating clean directory structure") # Ensure there is no old stuff, neither local nor remote - run_or_fail(["rm -rf", "$__cdist_local_base_dir"]) - - remote_run_or_fail(hostname, ["rm -rf", "${__cdist_remote_base_dir}"]) - - # Create base directories - run_or_fail(["mkdir -p", "$__cdist_local_base_dir"]) - remote_run_or_fail(hostname,["mkdir -p", "${__cdist_remote_base_dir}"]) - - # Link configuraion source directory - consistent with remote - run_or_fail(["ln -sf", "$__cdist_conf_dir", "$__cdist_local_base_dir/$__cdist_name_conf_dir"]) +# run_or_fail(["rm -rf", "$__cdist_local_base_dir"]) +# +# remote_run_or_fail(hostname, ["rm -rf", "${__cdist_remote_base_dir}"]) +# +# # Create base directories +# run_or_fail(["mkdir -p", "$__cdist_local_base_dir"]) +# remote_run_or_fail(hostname,["mkdir -p", "${__cdist_remote_base_dir}"]) +# +# # Link configuraion source directory - consistent with remote +# run_or_fail(["ln -sf", "$__cdist_conf_dir", "$__cdist_local_base_dir/$__cdist_name_conf_dir"]) def cdist_deploy_to(hostname): """Mimic the old deploy to: Deploy to one host""" From d0eeafd228fae25e1e8662311b7573022ab06be5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 02:56:02 +0200 Subject: [PATCH 0150/4212] also add some bugs Signed-off-by: Nico Schottelius --- bin/cdist | 11 +++++++++-- doc/dev/todo/niconext | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index fb09e8b2..5cabf17b 100755 --- a/bin/cdist +++ b/bin/cdist @@ -63,17 +63,24 @@ def base_directory(): os.chdir(os.path.join(os.path.dirname(__file__), os.pardir)) return os.getcwd() +def remote_base_directory(): + return "/var/lib/cdist" + def conf_directory(): """Returns path to main configuration directory""" return os.path.join(base_directory(), "conf") +def remote_conf_directory(): + """Returns path to remote main configuration directory""" + return os.path.join(remote_base_directory(), "conf") + def global_explorer_directory(): """Returns path to directory containing the global explorers""" return os.path.join(conf_directory(), "explorer") def remote_global_explorer_directory(): - """Returns path to directory containing the global explorers""" - return os.path.join(conf_directory(), "explorer") + """Returns path to the remote directory containing the global explorers""" + return os.path.join(remote_conf_directory(), "explorer") def list_global_explorers(): """Return list of available explorers""" diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index a59f909f..fce4033e 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,2 +1,4 @@ - rewrite in python? - support non-ssh access? + +- Bug: os.path.join() may be wrong for the remote side! From ef925714d5fc4aed09981d2c6de1a2088a24c881 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 02:57:47 +0200 Subject: [PATCH 0151/4212] transfer explorer Signed-off-by: Nico Schottelius --- bin/cdist | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 5cabf17b..7d28d112 100755 --- a/bin/cdist +++ b/bin/cdist @@ -45,7 +45,7 @@ def run_or_fail(*args): exit_error("Command failed:", newargs) def remote_run_or_fail(hostname, *args): - newargs = ["ssh", hostname] + newargs = ["ssh", "root@" + hostname] newargs.extend(*args) run_or_fail(newargs) @@ -55,7 +55,7 @@ def remove_remote_dir(hostname, destination): def transfer_dir(hostname, source, destination): remove_remote_dir(hostname, destination) - run_or_fail(["scp", "-r", source, hostname + ":" + destination]) + run_or_fail(["scp", "-r", source, "root@" + hostname + ":" + destination]) def base_directory(): """Returns the directory in which all cdist stuff is based in""" @@ -95,6 +95,8 @@ def global_explore(hostname): if(len(explorer) == 0): exit_error("No explorers found in", global_explorer_directory()) + transfer_global_explorers(hostname) + def init_deploy(hostname): logger("info", "Creating clean directory structure") From 85df71c9fa511b583076d500df25ab6cf384dc81 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 03:23:18 +0200 Subject: [PATCH 0152/4212] executing explorers works Signed-off-by: Nico Schottelius --- bin/cdist | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/bin/cdist b/bin/cdist index 7d28d112..d2a0abd9 100755 --- a/bin/cdist +++ b/bin/cdist @@ -30,14 +30,15 @@ def logger(type, *args): print(*args) def exit_error(*args): - logger("error", *args) + logger("error", args) sys.exit(1) def run_or_fail(*args): - newargs = ["echo"] + # newargs = ["echo"] newargs = [] newargs.extend(*args) + print(newargs) try: subprocess.check_call(newargs) @@ -45,9 +46,9 @@ def run_or_fail(*args): exit_error("Command failed:", newargs) def remote_run_or_fail(hostname, *args): + """Run something on the remote side and fail is something breaks""" newargs = ["ssh", "root@" + hostname] newargs.extend(*args) - run_or_fail(newargs) def remove_remote_dir(hostname, destination): @@ -82,6 +83,10 @@ def remote_global_explorer_directory(): """Returns path to the remote directory containing the global explorers""" return os.path.join(remote_conf_directory(), "explorer") +def remote_global_explorer_path(explorer): + """Returns path to the remote explorer""" + return os.path.join(remote_global_explorer_directory(), explorer) + def list_global_explorers(): """Return list of available explorers""" return os.listdir(global_explorer_directory()) @@ -91,11 +96,14 @@ def transfer_global_explorers(hostname): def global_explore(hostname): """Run global explorers""" - explorer = list_global_explorers() - if(len(explorer) == 0): + explorers = list_global_explorers() + if(len(explorers) == 0): exit_error("No explorers found in", global_explorer_directory()) transfer_global_explorers(hostname) + for explorer in explorers: + remote_run_or_fail(hostname, [remote_global_explorer_path(explorer)]) + def init_deploy(hostname): logger("info", "Creating clean directory structure") From 9036f8c4cce9edb5b353928855bdd995248cdb16 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 03:24:27 +0200 Subject: [PATCH 0153/4212] executing explorers works Signed-off-by: Nico Schottelius --- bin/cdist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/cdist b/bin/cdist index d2a0abd9..339349a3 100755 --- a/bin/cdist +++ b/bin/cdist @@ -103,6 +103,8 @@ def global_explore(hostname): transfer_global_explorers(hostname) for explorer in explorers: remote_run_or_fail(hostname, [remote_global_explorer_path(explorer)]) + + remote_run_or_fail(hostname, [remote_global_explorer_path("moo")]) def init_deploy(hostname): From ff2d5629d65a3bafe90df40718fd6ab393055527 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 03:28:06 +0200 Subject: [PATCH 0154/4212] submit string on failed error Signed-off-by: Nico Schottelius --- bin/cdist | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/bin/cdist b/bin/cdist index 339349a3..ab913541 100755 --- a/bin/cdist +++ b/bin/cdist @@ -30,7 +30,7 @@ def logger(type, *args): print(*args) def exit_error(*args): - logger("error", args) + logger("error", *args) sys.exit(1) @@ -42,8 +42,8 @@ def run_or_fail(*args): try: subprocess.check_call(newargs) - except CalledProcessError: - exit_error("Command failed:", newargs) + except subprocess.CalledProcessError: + exit_error("Command failed:", " ".join(newargs)) def remote_run_or_fail(hostname, *args): """Run something on the remote side and fail is something breaks""" @@ -104,8 +104,6 @@ def global_explore(hostname): for explorer in explorers: remote_run_or_fail(hostname, [remote_global_explorer_path(explorer)]) - remote_run_or_fail(hostname, [remote_global_explorer_path("moo")]) - def init_deploy(hostname): logger("info", "Creating clean directory structure") From 7a7413f1f48c9509bdd4e390f3d86017bf010ab7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 03:31:58 +0200 Subject: [PATCH 0155/4212] pause Signed-off-by: Nico Schottelius --- bin/cdist | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/cdist b/bin/cdist index ab913541..59d99040 100755 --- a/bin/cdist +++ b/bin/cdist @@ -75,6 +75,11 @@ def remote_conf_directory(): """Returns path to remote main configuration directory""" return os.path.join(remote_base_directory(), "conf") +def out_dir(): + FIXME: stopped - probably need static temp know! + """Local directory containing output""" + return os.path.join(base_directory(), "conf") + def global_explorer_directory(): """Returns path to directory containing the global explorers""" return os.path.join(conf_directory(), "explorer") From 572401e4f8010574df45423ccb1c21f056b719b9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 03:56:59 +0200 Subject: [PATCH 0156/4212] commit broken stuff Signed-off-by: Nico Schottelius --- bin/cdist | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index 59d99040..e1d62391 100755 --- a/bin/cdist +++ b/bin/cdist @@ -22,8 +22,22 @@ import sys # argv import subprocess # execute stuff import os +import tempfile +import shutil -__cdist_version="2.0.0" + +class Cdist: + """Cdist main class to hold arbitrary data""" + version="2.0.0" + + def __init__(self): + self.tempdir = tempfile.mkdtemp() + print(self.tempdir) + + def __del__(self): + print("Zerstoeren") + print(self.tempdir) + shutil.rmtree(self.tempdir) def logger(type, *args): """Ignore type for now, support later""" @@ -76,7 +90,7 @@ def remote_conf_directory(): return os.path.join(remote_base_directory(), "conf") def out_dir(): - FIXME: stopped - probably need static temp know! + # FIXME: stopped - probably need static temp know! """Local directory containing output""" return os.path.join(base_directory(), "conf") @@ -134,7 +148,9 @@ def cdist_deploy_to(hostname): if __name__ == "__main__": hostname=sys.argv[1] - logger("info", "cdist", __cdist_version, ": Configuring host", hostname) +# logger("info", "cdist", cdist_version, ": Configuring host", hostname) cdist_deploy_to(hostname) print(list_global_explorers()) + c = Cdist() + From e8a6d89e3c253897dd46863348a44eb606ad97cd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 04:22:21 +0200 Subject: [PATCH 0157/4212] wrap into a class Signed-off-by: Nico Schottelius --- bin/cdist | 187 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 98 insertions(+), 89 deletions(-) diff --git a/bin/cdist b/bin/cdist index e1d62391..53728648 100755 --- a/bin/cdist +++ b/bin/cdist @@ -30,127 +30,136 @@ class Cdist: """Cdist main class to hold arbitrary data""" version="2.0.0" - def __init__(self): + def __init__(self, hostname): self.tempdir = tempfile.mkdtemp() + self.hostname = hostname + print(self.hostname) print(self.tempdir) - def __del__(self): - print("Zerstoeren") + def cleanup(self): + # Do not use in __del__: + # http://docs.python.org/reference/datamodel.html#customization + # "other globals referenced by the __del__() method may already have been deleted + # or in the process of being torn down (e.g. the import machinery shutting down)" + # print(self.tempdir) shutil.rmtree(self.tempdir) -def logger(type, *args): - """Ignore type for now, support later""" - print(*args) + def out_dir(self): + # FIXME: stopped - probably need static temp know! + """Local directory containing output""" + return os.path.join(base_directory(), "conf") -def exit_error(*args): - logger("error", *args) - sys.exit(1) - + def logger(self,type, *args): + """Ignore type for now, support later""" + print(*args) -def run_or_fail(*args): - # newargs = ["echo"] - newargs = [] - newargs.extend(*args) - print(newargs) + def exit_error(self,*args): + self.logger("error", *args) + sys.exit(1) + - try: - subprocess.check_call(newargs) - except subprocess.CalledProcessError: - exit_error("Command failed:", " ".join(newargs)) + def run_or_fail(self,*args): + # newargs = ["echo"] + newargs = [] + newargs.extend(*args) + print(newargs) -def remote_run_or_fail(hostname, *args): - """Run something on the remote side and fail is something breaks""" - newargs = ["ssh", "root@" + hostname] - newargs.extend(*args) - run_or_fail(newargs) + try: + subprocess.check_call(newargs) + except subprocess.CalledProcessError: + self.exit_error("Command failed:", " ".join(newargs)) -def remove_remote_dir(hostname, destination): - remote_run_or_fail(hostname, ["rm", "-rf", destination]) + def remote_run_or_fail(self, *args): + """Run something on the remote side and fail is something breaks""" + newargs = ["ssh", "root@" + self.hostname] + newargs.extend(*args) + print(newargs, "bbbbb", self.hostname) + self.run_or_fail(newargs) -def transfer_dir(hostname, source, destination): - remove_remote_dir(hostname, destination) - run_or_fail(["scp", "-r", source, "root@" + hostname + ":" + destination]) + def remove_remote_dir(self, destination): + self.remote_run_or_fail(["rm", "-rf", destination]) -def base_directory(): - """Returns the directory in which all cdist stuff is based in""" - print("Going to", __file__, os.path.join(os.path.dirname(__file__), os.pardir)) - os.chdir(os.path.join(os.path.dirname(__file__), os.pardir)) - return os.getcwd() + def transfer_dir(self, source, destination): + self.remove_remote_dir(destination) + self.run_or_fail(["scp", "-qr", source, "root@" + self.hostname + ":" + destination]) -def remote_base_directory(): - return "/var/lib/cdist" + def base_directory(self): + """Returns the directory in which all cdist stuff is based in""" + print("Going to", __file__, os.path.join(os.path.dirname(__file__), os.pardir)) + os.chdir(os.path.join(os.path.dirname(__file__), os.pardir)) + return os.getcwd() -def conf_directory(): - """Returns path to main configuration directory""" - return os.path.join(base_directory(), "conf") + def remote_base_directory(self): + return "/var/lib/cdist" -def remote_conf_directory(): - """Returns path to remote main configuration directory""" - return os.path.join(remote_base_directory(), "conf") + def conf_directory(self): + """Returns path to main configuration directory""" + return os.path.join(self.base_directory(), "conf") -def out_dir(): - # FIXME: stopped - probably need static temp know! - """Local directory containing output""" - return os.path.join(base_directory(), "conf") + def remote_conf_directory(self): + """Returns path to remote main configuration directory""" + return os.path.join(self.remote_base_directory(), "conf") -def global_explorer_directory(): - """Returns path to directory containing the global explorers""" - return os.path.join(conf_directory(), "explorer") + def global_explorer_directory(self): + """Returns path to directory containing the global explorers""" + return os.path.join(self.conf_directory(), "explorer") -def remote_global_explorer_directory(): - """Returns path to the remote directory containing the global explorers""" - return os.path.join(remote_conf_directory(), "explorer") + def remote_global_explorer_directory(self): + """Returns path to the remote directory containing the global explorers""" + return os.path.join(self.remote_conf_directory(), "explorer") -def remote_global_explorer_path(explorer): - """Returns path to the remote explorer""" - return os.path.join(remote_global_explorer_directory(), explorer) + def remote_global_explorer_path(self,explorer): + """Returns path to the remote explorer""" + return os.path.join(self.remote_global_explorer_directory(), explorer) -def list_global_explorers(): - """Return list of available explorers""" - return os.listdir(global_explorer_directory()) + def list_global_explorers(self): + """Return list of available explorers""" + return os.listdir(self.global_explorer_directory()) -def transfer_global_explorers(hostname): - transfer_dir(hostname, global_explorer_directory(), remote_global_explorer_directory()) + def transfer_global_explorers(self): + self.transfer_dir(self.global_explorer_directory(), self.remote_global_explorer_directory()) -def global_explore(hostname): - """Run global explorers""" - explorers = list_global_explorers() - if(len(explorers) == 0): - exit_error("No explorers found in", global_explorer_directory()) + def global_explore(self): + """Run global explorers""" + explorers = self.list_global_explorers() + if(len(explorers) == 0): + self.exit_error("No explorers found in", self.global_explorer_directory()) - transfer_global_explorers(hostname) - for explorer in explorers: - remote_run_or_fail(hostname, [remote_global_explorer_path(explorer)]) + self.transfer_global_explorers() + for explorer in explorers: + self.remote_run_or_fail([self.remote_global_explorer_path(explorer)]) -def init_deploy(hostname): - logger("info", "Creating clean directory structure") + def init_deploy(self): + self.logger("info", "Creating clean directory structure") - # Ensure there is no old stuff, neither local nor remote -# run_or_fail(["rm -rf", "$__cdist_local_base_dir"]) -# -# remote_run_or_fail(hostname, ["rm -rf", "${__cdist_remote_base_dir}"]) -# -# # Create base directories -# run_or_fail(["mkdir -p", "$__cdist_local_base_dir"]) -# remote_run_or_fail(hostname,["mkdir -p", "${__cdist_remote_base_dir}"]) -# -# # Link configuraion source directory - consistent with remote -# run_or_fail(["ln -sf", "$__cdist_conf_dir", "$__cdist_local_base_dir/$__cdist_name_conf_dir"]) + # Ensure there is no old stuff, neither local nor remote + # run_or_fail(["rm -rf", "$__cdist_local_base_dir"]) + # + # remote_run_or_fail(hostname, ["rm -rf", "${__cdist_remote_base_dir}"]) + # + # # Create base directories + # run_or_fail(["mkdir -p", "$__cdist_local_base_dir"]) + # remote_run_or_fail(hostname,["mkdir -p", "${__cdist_remote_base_dir}"]) + # + # # Link configuraion source directory - consistent with remote + # run_or_fail(["ln -sf", "$__cdist_conf_dir", "$__cdist_local_base_dir/$__cdist_name_conf_dir"]) -def cdist_deploy_to(hostname): - """Mimic the old deploy to: Deploy to one host""" - logger("info", "Deploying to host", hostname) - init_deploy(hostname) - global_explore(hostname) + def deploy_to(self): + """Mimic the old deploy to: Deploy to one host""" + self.logger("info", "Deploying to host", self.hostname) + self.init_deploy() + self.global_explore() if __name__ == "__main__": hostname=sys.argv[1] # logger("info", "cdist", cdist_version, ": Configuring host", hostname) - cdist_deploy_to(hostname) - print(list_global_explorers()) - c = Cdist() + for host in sys.argv[1:]: + c = Cdist(host) + c.deploy_to() + print(c.list_global_explorers()) + c.cleanup() From 0dc6af251219e267791ec6d4f08667c38084f991 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 04:22:40 +0200 Subject: [PATCH 0158/4212] wrap into a class Signed-off-by: Nico Schottelius --- bin/cdist | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 53728648..6770c181 100755 --- a/bin/cdist +++ b/bin/cdist @@ -74,7 +74,6 @@ class Cdist: """Run something on the remote side and fail is something breaks""" newargs = ["ssh", "root@" + self.hostname] newargs.extend(*args) - print(newargs, "bbbbb", self.hostname) self.run_or_fail(newargs) def remove_remote_dir(self, destination): From e8360df96b6bb9ae4641046e862d1a414ebfc03c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 09:47:30 +0200 Subject: [PATCH 0159/4212] allow passing arguments to Popen() Signed-off-by: Nico Schottelius --- bin/cdist | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/cdist b/bin/cdist index 6770c181..39a0b80b 100755 --- a/bin/cdist +++ b/bin/cdist @@ -59,22 +59,22 @@ class Cdist: sys.exit(1) - def run_or_fail(self,*args): + def run_or_fail(self,*args, **kargs): # newargs = ["echo"] newargs = [] newargs.extend(*args) print(newargs) try: - subprocess.check_call(newargs) + subprocess.check_call(newargs, **kargs) except subprocess.CalledProcessError: self.exit_error("Command failed:", " ".join(newargs)) - def remote_run_or_fail(self, *args): + def remote_run_or_fail(self, *args, **kargs): """Run something on the remote side and fail is something breaks""" newargs = ["ssh", "root@" + self.hostname] newargs.extend(*args) - self.run_or_fail(newargs) + self.run_or_fail(newargs, **kargs) def remove_remote_dir(self, destination): self.remote_run_or_fail(["rm", "-rf", destination]) From 4c1939829e26ae8ba73f48793409daec8c5d0c3f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 11:08:44 +0200 Subject: [PATCH 0160/4212] import logging, begin to put constant stuff in module Signed-off-by: Nico Schottelius --- bin/cdist | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/bin/cdist b/bin/cdist index 39a0b80b..162bf1aa 100755 --- a/bin/cdist +++ b/bin/cdist @@ -19,22 +19,36 @@ # # -import sys # argv +import sys import subprocess # execute stuff import os import tempfile import shutil +import logging +BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) + +logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s') + class Cdist: """Cdist main class to hold arbitrary data""" version="2.0.0" def __init__(self, hostname): - self.tempdir = tempfile.mkdtemp() self.hostname = hostname - print(self.hostname) - print(self.tempdir) + + # Setup directory paths + self.temp_dir = tempfile.mkdtemp() + + self.out_dir = os.path.join(self.temp_dir, "out") + os.mkdir(self.out_dir) + + self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") + os.mkdir(self.global_explorer_out_dir) + + # Given paths from installation + self.conf_dir = os.path.join(self.base_dir, "conf") def cleanup(self): # Do not use in __del__: @@ -45,11 +59,6 @@ class Cdist: print(self.tempdir) shutil.rmtree(self.tempdir) - def out_dir(self): - # FIXME: stopped - probably need static temp know! - """Local directory containing output""" - return os.path.join(base_directory(), "conf") - def logger(self,type, *args): """Ignore type for now, support later""" print(*args) @@ -83,18 +92,9 @@ class Cdist: self.remove_remote_dir(destination) self.run_or_fail(["scp", "-qr", source, "root@" + self.hostname + ":" + destination]) - def base_directory(self): - """Returns the directory in which all cdist stuff is based in""" - print("Going to", __file__, os.path.join(os.path.dirname(__file__), os.pardir)) - os.chdir(os.path.join(os.path.dirname(__file__), os.pardir)) - return os.getcwd() - def remote_base_directory(self): return "/var/lib/cdist" - def conf_directory(self): - """Returns path to main configuration directory""" - return os.path.join(self.base_directory(), "conf") def remote_conf_directory(self): """Returns path to remote main configuration directory""" @@ -112,6 +112,10 @@ class Cdist: """Returns path to the remote explorer""" return os.path.join(self.remote_global_explorer_directory(), explorer) + def global_explorer_output_path(self, explorer): + """Returns path of the output for a global explorer""" + return os.path.join(self.global_explorer_out_dir, explorer) + def list_global_explorers(self): """Return list of available explorers""" return os.listdir(self.global_explorer_directory()) @@ -127,7 +131,10 @@ class Cdist: self.transfer_global_explorers() for explorer in explorers: - self.remote_run_or_fail([self.remote_global_explorer_path(explorer)]) + output = self.global_explorer_output_path(explorer) + output_fd = open(output, mode='w') + self.remote_run_or_fail([self.remote_global_explorer_path(explorer)], stdout=output_fd) + output_fd.close() def init_deploy(self): From 7d3c67c178a1996eb7a6633040c9a30668f56fda Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 11:44:04 +0200 Subject: [PATCH 0161/4212] make it work again :-) Signed-off-by: Nico Schottelius --- bin/cdist | 81 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/bin/cdist b/bin/cdist index 162bf1aa..c160b945 100755 --- a/bin/cdist +++ b/bin/cdist @@ -27,9 +27,37 @@ import shutil import logging +# Given paths from installation BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) +CONF_DIR = os.path.join(BASE_DIR, "conf") +GLOBAL_EXPLORER_DIR = os.path.join(CONF_DIR, "explorer") +REMOTE_BASE_DIR = "/var/lib/cdist" +REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") +REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") + + +#class Context(object): +# +# def __init__(self, target_host): +# self.target_host = target_host +# +# # class variable +# user_selber_shuld_wenn_aendert = 'bla' +# +# # read only, aber statisch +# @property +# def remote_base_directory(self): +# return "/var/lib/cdist" +# @property.setter +# +# @property +# def special_foo(self): +# return 'foo/{0}'.format(self.target_host) +# + logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s') +log = logging.getLogger() class Cdist: """Cdist main class to hold arbitrary data""" @@ -38,35 +66,27 @@ class Cdist: def __init__(self, hostname): self.hostname = hostname + # log.info("foobar") + # Setup directory paths self.temp_dir = tempfile.mkdtemp() - self.out_dir = os.path.join(self.temp_dir, "out") os.mkdir(self.out_dir) - self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") os.mkdir(self.global_explorer_out_dir) - # Given paths from installation - self.conf_dir = os.path.join(self.base_dir, "conf") - def cleanup(self): # Do not use in __del__: # http://docs.python.org/reference/datamodel.html#customization # "other globals referenced by the __del__() method may already have been deleted # or in the process of being torn down (e.g. the import machinery shutting down)" # - print(self.tempdir) - shutil.rmtree(self.tempdir) - - def logger(self,type, *args): - """Ignore type for now, support later""" - print(*args) + print(self.temp_dir) + shutil.rmtree(self.temp_dir) def exit_error(self,*args): - self.logger("error", *args) + log.error(args) sys.exit(1) - def run_or_fail(self,*args, **kargs): # newargs = ["echo"] @@ -92,42 +112,26 @@ class Cdist: self.remove_remote_dir(destination) self.run_or_fail(["scp", "-qr", source, "root@" + self.hostname + ":" + destination]) - def remote_base_directory(self): - return "/var/lib/cdist" - - - def remote_conf_directory(self): - """Returns path to remote main configuration directory""" - return os.path.join(self.remote_base_directory(), "conf") - - def global_explorer_directory(self): - """Returns path to directory containing the global explorers""" - return os.path.join(self.conf_directory(), "explorer") - - def remote_global_explorer_directory(self): - """Returns path to the remote directory containing the global explorers""" - return os.path.join(self.remote_conf_directory(), "explorer") - - def remote_global_explorer_path(self,explorer): - """Returns path to the remote explorer""" - return os.path.join(self.remote_global_explorer_directory(), explorer) - def global_explorer_output_path(self, explorer): """Returns path of the output for a global explorer""" return os.path.join(self.global_explorer_out_dir, explorer) + def remote_global_explorer_path(self, explorer): + """Returns path to the remote explorer""" + return os.path.join(REMOTE_GLOBAL_EXPLORER_DIR, explorer) + def list_global_explorers(self): """Return list of available explorers""" - return os.listdir(self.global_explorer_directory()) + return os.listdir(GLOBAL_EXPLORER_DIR) def transfer_global_explorers(self): - self.transfer_dir(self.global_explorer_directory(), self.remote_global_explorer_directory()) + self.transfer_dir(GLOBAL_EXPLORER_DIR, REMOTE_GLOBAL_EXPLORER_DIR) def global_explore(self): """Run global explorers""" explorers = self.list_global_explorers() if(len(explorers) == 0): - self.exit_error("No explorers found in", self.global_explorer_directory()) + self.exit_error("No explorers found in", GLOBAL_EXPLORER_DIR) self.transfer_global_explorers() for explorer in explorers: @@ -138,7 +142,7 @@ class Cdist: def init_deploy(self): - self.logger("info", "Creating clean directory structure") + log.info("Creating clean directory structure") # Ensure there is no old stuff, neither local nor remote # run_or_fail(["rm -rf", "$__cdist_local_base_dir"]) @@ -154,14 +158,13 @@ class Cdist: def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" - self.logger("info", "Deploying to host", self.hostname) + log.info("Deploying to host", self.hostname) self.init_deploy() self.global_explore() if __name__ == "__main__": hostname=sys.argv[1] -# logger("info", "cdist", cdist_version, ": Configuring host", hostname) for host in sys.argv[1:]: c = Cdist(host) From 8fa576152ee2666c24e6d53dd697a40d78940980 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 11:44:58 +0200 Subject: [PATCH 0162/4212] make it work again :-) Signed-off-by: Nico Schottelius --- bin/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index c160b945..1e2fe11e 100755 --- a/bin/cdist +++ b/bin/cdist @@ -158,7 +158,7 @@ class Cdist: def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to host", self.hostname) + log.info("Deploying to host" + self.hostname) self.init_deploy() self.global_explore() From 506e0e6c81d340f424cf589b16d7e8672a5d824f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 11:45:58 +0200 Subject: [PATCH 0163/4212] +better logging Signed-off-by: Nico Schottelius --- bin/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 1e2fe11e..56991d68 100755 --- a/bin/cdist +++ b/bin/cdist @@ -158,7 +158,7 @@ class Cdist: def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to host" + self.hostname) + log.info("Deploying to host " + self.hostname) self.init_deploy() self.global_explore() From 908d9d06f9737a37a1558313836c65b3a172fce2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 11:50:30 +0200 Subject: [PATCH 0164/4212] prepend __explorer on global explorer run Signed-off-by: Nico Schottelius --- bin/cdist | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index 56991d68..d6421161 100755 --- a/bin/cdist +++ b/bin/cdist @@ -81,8 +81,8 @@ class Cdist: # "other globals referenced by the __del__() method may already have been deleted # or in the process of being torn down (e.g. the import machinery shutting down)" # - print(self.temp_dir) - shutil.rmtree(self.temp_dir) + print("I should cleanup " + self.temp_dir) + # shutil.rmtree(self.temp_dir) def exit_error(self,*args): log.error(args) @@ -137,7 +137,11 @@ class Cdist: for explorer in explorers: output = self.global_explorer_output_path(explorer) output_fd = open(output, mode='w') - self.remote_run_or_fail([self.remote_global_explorer_path(explorer)], stdout=output_fd) + cmd = [] + cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append(self.remote_global_explorer_path(explorer)) + + self.remote_run_or_fail(cmd, stdout=output_fd) output_fd.close() @@ -145,12 +149,9 @@ class Cdist: log.info("Creating clean directory structure") # Ensure there is no old stuff, neither local nor remote - # run_or_fail(["rm -rf", "$__cdist_local_base_dir"]) - # # remote_run_or_fail(hostname, ["rm -rf", "${__cdist_remote_base_dir}"]) # # # Create base directories - # run_or_fail(["mkdir -p", "$__cdist_local_base_dir"]) # remote_run_or_fail(hostname,["mkdir -p", "${__cdist_remote_base_dir}"]) # # # Link configuraion source directory - consistent with remote From ddff3e8b571fd907e423ea8888c482eb1f4c05f6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 11:55:29 +0200 Subject: [PATCH 0165/4212] support changing the initial manifest Signed-off-by: Nico Schottelius --- bin/cdist | 14 +++++++++++++- bin/cdist-deploy-to | 1 - 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index d6421161..766a2acf 100755 --- a/bin/cdist +++ b/bin/cdist @@ -31,6 +31,8 @@ import logging BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) CONF_DIR = os.path.join(BASE_DIR, "conf") GLOBAL_EXPLORER_DIR = os.path.join(CONF_DIR, "explorer") +MANIFEST_DIR = os.path.join(CONF_DIR, "manifest") + REMOTE_BASE_DIR = "/var/lib/cdist" REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") @@ -63,7 +65,7 @@ class Cdist: """Cdist main class to hold arbitrary data""" version="2.0.0" - def __init__(self, hostname): + def __init__(self, hostname, initial_manifest=False): self.hostname = hostname # log.info("foobar") @@ -75,6 +77,12 @@ class Cdist: self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") os.mkdir(self.global_explorer_out_dir) + # Mostly static, but can be overwritten on user demand + if initial_manifest: + self.initial_manifest = initial_manifest + else: + self.initial_manifest = os.path.join(MANIFEST_DIR, "init") + def cleanup(self): # Do not use in __del__: # http://docs.python.org/reference/datamodel.html#customization @@ -157,11 +165,15 @@ class Cdist: # # Link configuraion source directory - consistent with remote # run_or_fail(["ln -sf", "$__cdist_conf_dir", "$__cdist_local_base_dir/$__cdist_name_conf_dir"]) + def initial_manifes(self): + """Run the initial manifest""" + def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" log.info("Deploying to host " + self.hostname) self.init_deploy() self.global_explore() + self.initial_manifest() if __name__ == "__main__": diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index 84181bbd..79f42931 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -43,7 +43,6 @@ __cdist_echo info "cdist $__cdist_version: Configuring $__cdist_target_host " # See cdist-stages(7) # -cdist-explorer-run-global "$__cdist_target_host" cdist-manifest-run-init "$__cdist_target_host" cdist-object-all "$__cdist_target_host" cdist-object-prepare cdist-object-all "$__cdist_target_host" cdist-object-run From 9533e579b390c171f8147211d63866935b2d683b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 14:04:30 +0200 Subject: [PATCH 0166/4212] finish run of initial manifest, finish shell_run_or_debug_fail() Signed-off-by: Nico Schottelius --- bin/cdist | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/bin/cdist b/bin/cdist index 766a2acf..594b5eea 100755 --- a/bin/cdist +++ b/bin/cdist @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# -*- coding: utf-8 -*- # # 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) # @@ -96,11 +97,23 @@ class Cdist: log.error(args) sys.exit(1) - def run_or_fail(self,*args, **kargs): + def shell_run_or_debug_fail(self, script, *args, **kargs): + kargs['shell'] = True + log.debug("Shell exec: " + " ".join(*args)) + + try: + subprocess.check_call(*args, **kargs) + except subprocess.CalledProcessError: + # FIXME: print out shell script! + script_fd = open(script) + log.error("Code that raised the error:\n" + script_fd.read()) + script_fd.close() + self.exit_error("Non-Zero exit code exit of " + " ".join(*args)) + + def run_or_fail(self, *args, **kargs): # newargs = ["echo"] newargs = [] newargs.extend(*args) - print(newargs) try: subprocess.check_call(newargs, **kargs) @@ -165,15 +178,18 @@ class Cdist: # # Link configuraion source directory - consistent with remote # run_or_fail(["ln -sf", "$__cdist_conf_dir", "$__cdist_local_base_dir/$__cdist_name_conf_dir"]) - def initial_manifes(self): + def run_initial_manifest(self): """Run the initial manifest""" + log.info("Running the initial manifest") + self.shell_run_or_debug_fail(self.initial_manifest, [self.initial_manifest]) + def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" log.info("Deploying to host " + self.hostname) self.init_deploy() self.global_explore() - self.initial_manifest() + self.run_initial_manifest() if __name__ == "__main__": From c5d960438cc111c5476b0261628b0ffcb1d25dbd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 14:05:20 +0200 Subject: [PATCH 0167/4212] import parser from steven Signed-off-by: Nico Schottelius --- bin/cdist | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/bin/cdist b/bin/cdist index 594b5eea..72e95e29 100755 --- a/bin/cdist +++ b/bin/cdist @@ -201,3 +201,41 @@ if __name__ == "__main__": print(c.list_global_explorers()) c.cleanup() + +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import logging +# TODO: configure logging based on config and/or user given arguments +logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') +log = logging.getLogger() + +import argparse +import sys + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Some helpfull blabla') + parser.add_argument('host', nargs='+', help='one or more hosts to operate on') + parser.add_argument('-i', '--initial-manifest', + help='path to a cdist manifest or - to read from stdin', + dest='manifest', required=True) + parser.add_argument('-p', '--parallel', + help='operate on multiple hosts in parallel', + action='store_true', dest='parallel') + parser.add_argument('-s', '--sequential', + help='operate on multiple hosts sequentially', + action='store_false', dest='parallel') + parser.add_argument('-d', '--debug', help='set log level to debug', + action='store_true') + + args = parser.parse_args(sys.argv[1:]) + if args.debug: + logging.root.setLevel(logging.DEBUG) + log.debug('Look ma, now whe\'re showing debug messages') + + try: + print(args) + #import cdist + #sys.exit(cdist.main(args)) + except KeyboardInterrupt: + sys.exit(0) From 979174a5685ae810327f98b04a8cf522c504f15c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 14:11:31 +0200 Subject: [PATCH 0168/4212] integrate parser Signed-off-by: Nico Schottelius --- bin/cdist | 86 +++++++++++++++++++++++-------------------------------- 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/bin/cdist b/bin/cdist index 72e95e29..a9b400ca 100755 --- a/bin/cdist +++ b/bin/cdist @@ -20,13 +20,13 @@ # # -import sys -import subprocess # execute stuff -import os -import tempfile -import shutil +import argparse import logging - +import os +import subprocess +import shutil +import sys +import tempfile # Given paths from installation BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) @@ -37,6 +37,7 @@ MANIFEST_DIR = os.path.join(CONF_DIR, "manifest") REMOTE_BASE_DIR = "/var/lib/cdist" REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") +VERSION = "2.0.0" #class Context(object): @@ -64,7 +65,6 @@ log = logging.getLogger() class Cdist: """Cdist main class to hold arbitrary data""" - version="2.0.0" def __init__(self, hostname, initial_manifest=False): self.hostname = hostname @@ -195,47 +195,33 @@ class Cdist: if __name__ == "__main__": hostname=sys.argv[1] - for host in sys.argv[1:]: - c = Cdist(host) - c.deploy_to() - print(c.list_global_explorers()) - c.cleanup() + parser = argparse.ArgumentParser(description='cdist ' + VERSION) + parser.add_argument('host', nargs='+', help='one or more hosts to operate on') + parser.add_argument('-d', '--debug', help='set log level to debug', + action='store_true') + parser.add_argument('-i', '--initial-manifest', + help='path to a cdist manifest or - to read from stdin', + dest='manifest', required=True) + parser.add_argument('-p', '--parallel', + help='operate on multiple hosts in parallel', + action='store_true', dest='parallel') + parser.add_argument('-s', '--sequential', + help='operate on multiple hosts sequentially', + action='store_false', dest='parallel') + + args = parser.parse_args(sys.argv[1:]) + if args.debug: + logging.root.setLevel(logging.DEBUG) + + try: + print(args) + import cdist + sys.exit(cdist.main(args)) - -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import logging -# TODO: configure logging based on config and/or user given arguments -logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') -log = logging.getLogger() - -import argparse -import sys - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Some helpfull blabla') - parser.add_argument('host', nargs='+', help='one or more hosts to operate on') - parser.add_argument('-i', '--initial-manifest', - help='path to a cdist manifest or - to read from stdin', - dest='manifest', required=True) - parser.add_argument('-p', '--parallel', - help='operate on multiple hosts in parallel', - action='store_true', dest='parallel') - parser.add_argument('-s', '--sequential', - help='operate on multiple hosts sequentially', - action='store_false', dest='parallel') - parser.add_argument('-d', '--debug', help='set log level to debug', - action='store_true') - - args = parser.parse_args(sys.argv[1:]) - if args.debug: - logging.root.setLevel(logging.DEBUG) - log.debug('Look ma, now whe\'re showing debug messages') - - try: - print(args) - #import cdist - #sys.exit(cdist.main(args)) - except KeyboardInterrupt: - sys.exit(0) + for host in sys.argv[1:]: + c = Cdist(host) + c.deploy_to() + print(c.list_global_explorers()) + c.cleanup() + except KeyboardInterrupt: + sys.exit(0) From 1d367d5f581e246793e44016ec1df0836b822e6e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 14:17:44 +0200 Subject: [PATCH 0169/4212] make cdist localhost work again Signed-off-by: Nico Schottelius --- bin/cdist | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/bin/cdist b/bin/cdist index a9b400ca..58ddcb3f 100755 --- a/bin/cdist +++ b/bin/cdist @@ -201,7 +201,7 @@ if __name__ == "__main__": action='store_true') parser.add_argument('-i', '--initial-manifest', help='path to a cdist manifest or - to read from stdin', - dest='manifest', required=True) + dest='manifest', required=False) parser.add_argument('-p', '--parallel', help='operate on multiple hosts in parallel', action='store_true', dest='parallel') @@ -214,11 +214,9 @@ if __name__ == "__main__": logging.root.setLevel(logging.DEBUG) try: - print(args) - import cdist - sys.exit(cdist.main(args)) + log.debug(args) - for host in sys.argv[1:]: + for host in args.host: c = Cdist(host) c.deploy_to() print(c.list_global_explorers()) From c8ce7e98ec2da0bfad43272adab71a2b43df2303 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 14:45:54 +0200 Subject: [PATCH 0170/4212] use -e to shell Signed-off-by: Nico Schottelius --- bin/cdist | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 58ddcb3f..a5902472 100755 --- a/bin/cdist +++ b/bin/cdist @@ -101,6 +101,10 @@ class Cdist: kargs['shell'] = True log.debug("Shell exec: " + " ".join(*args)) + # Fail if the script fails + args[0].insert(0,"-e") + print(args) + try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: @@ -219,7 +223,6 @@ if __name__ == "__main__": for host in args.host: c = Cdist(host) c.deploy_to() - print(c.list_global_explorers()) c.cleanup() except KeyboardInterrupt: sys.exit(0) From 1a96f886567f676f0ea149d73fc7ef9546496b55 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 14:50:45 +0200 Subject: [PATCH 0171/4212] name variable target_host for consistency and easy handling Signed-off-by: Nico Schottelius --- bin/cdist | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/bin/cdist b/bin/cdist index a5902472..323d2a96 100755 --- a/bin/cdist +++ b/bin/cdist @@ -66,8 +66,8 @@ log = logging.getLogger() class Cdist: """Cdist main class to hold arbitrary data""" - def __init__(self, hostname, initial_manifest=False): - self.hostname = hostname + def __init__(self, target_host, initial_manifest=False): + self.target_host = target_host # log.info("foobar") @@ -126,7 +126,7 @@ class Cdist: def remote_run_or_fail(self, *args, **kargs): """Run something on the remote side and fail is something breaks""" - newargs = ["ssh", "root@" + self.hostname] + newargs = ["ssh", "root@" + self.target_host] newargs.extend(*args) self.run_or_fail(newargs, **kargs) @@ -135,7 +135,7 @@ class Cdist: def transfer_dir(self, source, destination): self.remove_remote_dir(destination) - self.run_or_fail(["scp", "-qr", source, "root@" + self.hostname + ":" + destination]) + self.run_or_fail(["scp", "-qr", source, "root@" + self.target_host + ":" + destination]) def global_explorer_output_path(self, explorer): """Returns path of the output for a global explorer""" @@ -185,20 +185,23 @@ class Cdist: def run_initial_manifest(self): """Run the initial manifest""" log.info("Running the initial manifest") - self.shell_run_or_debug_fail(self.initial_manifest, [self.initial_manifest]) + env = os.environ.copy() + env['__target_host'] = self.target_host + + self.shell_run_or_debug_fail(self.initial_manifest, + [self.initial_manifest], + env=env) def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to host " + self.hostname) + log.info("Deploying to host " + self.target_host) self.init_deploy() self.global_explore() self.run_initial_manifest() if __name__ == "__main__": - hostname=sys.argv[1] - parser = argparse.ArgumentParser(description='cdist ' + VERSION) parser.add_argument('host', nargs='+', help='one or more hosts to operate on') parser.add_argument('-d', '--debug', help='set log level to debug', From 4fd8a16e6cd618ed61c9e312d5e3827bb4d15b2f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 14:52:42 +0200 Subject: [PATCH 0172/4212] use *args not args :-) Signed-off-by: Nico Schottelius --- bin/cdist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 323d2a96..7059f73b 100755 --- a/bin/cdist +++ b/bin/cdist @@ -93,8 +93,8 @@ class Cdist: print("I should cleanup " + self.temp_dir) # shutil.rmtree(self.temp_dir) - def exit_error(self,*args): - log.error(args) + def exit_error(self, *args): + log.error(*args) sys.exit(1) def shell_run_or_debug_fail(self, script, *args, **kargs): From 2c2a234c74ce1a5641d3683f6ef947627585b007 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 15:13:05 +0200 Subject: [PATCH 0173/4212] use sh -e instead of shipped shell=true (see included comment) Signed-off-by: Nico Schottelius --- bin/cdist | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/bin/cdist b/bin/cdist index 7059f73b..1216edab 100755 --- a/bin/cdist +++ b/bin/cdist @@ -98,13 +98,12 @@ class Cdist: sys.exit(1) def shell_run_or_debug_fail(self, script, *args, **kargs): - kargs['shell'] = True + # Manually execute /bin/sh, because sh -e does what we want + # and sh -c -e does not exit if /bin/false called + args[0].insert(0,"/bin/sh") + args[0].insert(1,"-e") log.debug("Shell exec: " + " ".join(*args)) - # Fail if the script fails - args[0].insert(0,"-e") - print(args) - try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: @@ -115,14 +114,12 @@ class Cdist: self.exit_error("Non-Zero exit code exit of " + " ".join(*args)) def run_or_fail(self, *args, **kargs): - # newargs = ["echo"] - newargs = [] - newargs.extend(*args) + log.debug("Exec: " + " ".join(*args)) try: - subprocess.check_call(newargs, **kargs) + subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: - self.exit_error("Command failed:", " ".join(newargs)) + self.exit_error("Command failed:", " ".join(*args)) def remote_run_or_fail(self, *args, **kargs): """Run something on the remote side and fail is something breaks""" From 97f7513f6eae5796fc9046530fe528d3e083dd6d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 15:14:28 +0200 Subject: [PATCH 0174/4212] -old fixme Signed-off-by: Nico Schottelius --- bin/cdist | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 1216edab..857e127d 100755 --- a/bin/cdist +++ b/bin/cdist @@ -107,7 +107,6 @@ class Cdist: try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: - # FIXME: print out shell script! script_fd = open(script) log.error("Code that raised the error:\n" + script_fd.read()) script_fd.close() From d6db6d0c7e22b45e970299bcfcbb641dfdcc774a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 15:20:25 +0200 Subject: [PATCH 0175/4212] begin move of cdist-type-emulator to lib/ and submit initial_manifest to cdist Signed-off-by: Nico Schottelius --- bin/cdist | 3 ++- {bin => lib}/cdist-type-emulator | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename {bin => lib}/cdist-type-emulator (100%) diff --git a/bin/cdist b/bin/cdist index 857e127d..6e13188d 100755 --- a/bin/cdist +++ b/bin/cdist @@ -32,6 +32,7 @@ import tempfile BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) CONF_DIR = os.path.join(BASE_DIR, "conf") GLOBAL_EXPLORER_DIR = os.path.join(CONF_DIR, "explorer") +LIB_DIR = os.path.join(BASE_DIR, "lib") MANIFEST_DIR = os.path.join(CONF_DIR, "manifest") REMOTE_BASE_DIR = "/var/lib/cdist" @@ -220,7 +221,7 @@ if __name__ == "__main__": log.debug(args) for host in args.host: - c = Cdist(host) + c = Cdist(host, initial_manifest=args.manifest) c.deploy_to() c.cleanup() except KeyboardInterrupt: diff --git a/bin/cdist-type-emulator b/lib/cdist-type-emulator similarity index 100% rename from bin/cdist-type-emulator rename to lib/cdist-type-emulator From 9ce26e5817907105c20ab9503933578717d14352 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 15:35:29 +0200 Subject: [PATCH 0176/4212] include cdist-type-emulator into path again Signed-off-by: Nico Schottelius --- bin/cdist | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/bin/cdist b/bin/cdist index 6e13188d..0cc4ac7f 100755 --- a/bin/cdist +++ b/bin/cdist @@ -34,6 +34,7 @@ CONF_DIR = os.path.join(BASE_DIR, "conf") GLOBAL_EXPLORER_DIR = os.path.join(CONF_DIR, "explorer") LIB_DIR = os.path.join(BASE_DIR, "lib") MANIFEST_DIR = os.path.join(CONF_DIR, "manifest") +TYPE_DIR = os.path.join(CONF_DIR, "type") REMOTE_BASE_DIR = "/var/lib/cdist" REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") @@ -64,6 +65,10 @@ VERSION = "2.0.0" logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s') log = logging.getLogger() +# List types +def list_types(): + return os.listdir(TYPE_DIR) + class Cdist: """Cdist main class to hold arbitrary data""" @@ -74,11 +79,18 @@ class Cdist: # Setup directory paths self.temp_dir = tempfile.mkdtemp() + self.out_dir = os.path.join(self.temp_dir, "out") os.mkdir(self.out_dir) + self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") os.mkdir(self.global_explorer_out_dir) + # Setup binary directory + contents + self.bin_dir = os.path.join(self.out_dir, "bin") + os.mkdir(self.bin_dir) + self.link_type_to_emulator() + # Mostly static, but can be overwritten on user demand if initial_manifest: self.initial_manifest = initial_manifest @@ -149,6 +161,14 @@ class Cdist: def transfer_global_explorers(self): self.transfer_dir(GLOBAL_EXPLORER_DIR, REMOTE_GLOBAL_EXPLORER_DIR) + def link_type_to_emulator(self): + """Link type names to cdist-type-emulator""" + for type in list_types(): + source = os.path.join(LIB_DIR, "cdist-type-emulator") + destination = os.path.join(self.bin_dir, type) + log.debug("Linking %s to %s", source, destination) + os.symlink(source, destination) + def global_explore(self): """Run global explorers""" explorers = self.list_global_explorers() @@ -184,6 +204,7 @@ class Cdist: log.info("Running the initial manifest") env = os.environ.copy() env['__target_host'] = self.target_host + env['PATH'] = self.bin_dir + ":" + env['PATH'] self.shell_run_or_debug_fail(self.initial_manifest, [self.initial_manifest], From bf0f2b8f12949bfcd988f95533987f23d54d9695 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 15:39:21 +0200 Subject: [PATCH 0177/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index fce4033e..972525aa 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,4 +1,5 @@ - rewrite in python? + - also do with cdist-type-emulator, which had quirks applied from outside to run - support non-ssh access? - Bug: os.path.join() may be wrong for the remote side! From dbbbf822fe55f714c115fa4e610b62361dfd614e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 15:52:34 +0200 Subject: [PATCH 0178/4212] make cdist-type-emulator work Signed-off-by: Nico Schottelius --- bin/cdist | 15 ++++++++++++--- bin/cdist-deploy-to | 1 - 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/bin/cdist b/bin/cdist index 0cc4ac7f..57df474d 100755 --- a/bin/cdist +++ b/bin/cdist @@ -169,7 +169,7 @@ class Cdist: log.debug("Linking %s to %s", source, destination) os.symlink(source, destination) - def global_explore(self): + def run_global_explores(self): """Run global explorers""" explorers = self.list_global_explorers() if(len(explorers) == 0): @@ -186,6 +186,7 @@ class Cdist: self.remote_run_or_fail(cmd, stdout=output_fd) output_fd.close() + # def run_type_explorer(self): def init_deploy(self): log.info("Creating clean directory structure") @@ -203,9 +204,17 @@ class Cdist: """Run the initial manifest""" log.info("Running the initial manifest") env = os.environ.copy() - env['__target_host'] = self.target_host env['PATH'] = self.bin_dir + ":" + env['PATH'] + env['__target_host'] = self.target_host + env['__global'] = self.out_dir + + # Legacy stuff to make cdist-type-emulator work + env['__cdist_conf_dir'] = CONF_DIR + env['__cdist_core_dir'] = os.path.join(BASE_DIR, "core") + env['__cdist_local_base_dir'] = self.temp_dir + env['__cdist_manifest'] = self.initial_manifest + self.shell_run_or_debug_fail(self.initial_manifest, [self.initial_manifest], env=env) @@ -215,7 +224,7 @@ class Cdist: """Mimic the old deploy to: Deploy to one host""" log.info("Deploying to host " + self.target_host) self.init_deploy() - self.global_explore() + self.run_global_explores() self.run_initial_manifest() diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index 79f42931..96650f90 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -43,7 +43,6 @@ __cdist_echo info "cdist $__cdist_version: Configuring $__cdist_target_host " # See cdist-stages(7) # -cdist-manifest-run-init "$__cdist_target_host" cdist-object-all "$__cdist_target_host" cdist-object-prepare cdist-object-all "$__cdist_target_host" cdist-object-run cdist-cache "$__cdist_target_host" From 0f36ddd649d5646e2955ff219524a31f1707f61e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 15:54:10 +0200 Subject: [PATCH 0179/4212] support object dir Signed-off-by: Nico Schottelius --- bin/cdist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/cdist b/bin/cdist index 57df474d..d7e2f697 100755 --- a/bin/cdist +++ b/bin/cdist @@ -86,6 +86,8 @@ class Cdist: self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") os.mkdir(self.global_explorer_out_dir) + self.object_dir = os.path.join(self.out_dir, "object") + # Setup binary directory + contents self.bin_dir = os.path.join(self.out_dir, "bin") os.mkdir(self.bin_dir) From 03e2db83cd1234e55ca2b4801f31e3094e3516b8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 17:01:22 +0200 Subject: [PATCH 0180/4212] implement list of objects Signed-off-by: Nico Schottelius --- bin/cdist | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/bin/cdist b/bin/cdist index d7e2f697..8655dcad 100755 --- a/bin/cdist +++ b/bin/cdist @@ -160,6 +160,44 @@ class Cdist: """Return list of available explorers""" return os.listdir(GLOBAL_EXPLORER_DIR) + def list_object_paths(self, starting_point = False): + """Return list of paths of existing objects""" + object_paths = [] + + if not starting_point: + starting_point = self.object_dir + + for content in os.listdir(starting_point): + full_path = os.path.join(starting_point, content) + print(full_path) + if os.path.isdir(full_path): + log.debug("Recursing for %s", full_path) + object_paths.extend(self.list_object_paths(starting_point = full_path)) + + # Directory contains .cdist -> is an object + if content == ".cdist": + log.debug("Adding Object Path %s", starting_point) + object_paths.append(starting_point) + + return object_paths + + def list_objects(self, starting_point = False): + """Return list of existing objects""" + + if not starting_point: + starting_point = self.object_dir + + object_paths = self.list_object_paths(starting_point) + objects = [] + log.debug("Paths recieved: %s", object_paths) + log.debug("And te starting point: %s", starting_point) + + for path in object_paths: + objects.append(os.path.relpath(path, starting_point)) + + return objects + + def transfer_global_explorers(self): self.transfer_dir(GLOBAL_EXPLORER_DIR, REMOTE_GLOBAL_EXPLORER_DIR) From 4d765a702406de7b351174421e6679cb6507cdd3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 17:45:07 +0200 Subject: [PATCH 0181/4212] begin type explorer transfer Signed-off-by: Nico Schottelius --- bin/cdist | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index 8655dcad..4e62bd64 100755 --- a/bin/cdist +++ b/bin/cdist @@ -38,7 +38,10 @@ TYPE_DIR = os.path.join(CONF_DIR, "type") REMOTE_BASE_DIR = "/var/lib/cdist" REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") +REMOTE_TYPE_DIR = os.path.join(REMOTE_CONF_DIR, "type") REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") + +DOT_CDIST = ".cdist" VERSION = "2.0.0" @@ -93,6 +96,9 @@ class Cdist: os.mkdir(self.bin_dir) self.link_type_to_emulator() + # List of type explorers transferred + self.type_explorers_transferred = {} + # Mostly static, but can be overwritten on user demand if initial_manifest: self.initial_manifest = initial_manifest @@ -175,12 +181,15 @@ class Cdist: object_paths.extend(self.list_object_paths(starting_point = full_path)) # Directory contains .cdist -> is an object - if content == ".cdist": + if content == DOT_CDIST: log.debug("Adding Object Path %s", starting_point) object_paths.append(starting_point) return object_paths + def get_type_from_object(cdist_object): + return cdist_object.split(os.sep)[0] + def list_objects(self, starting_point = False): """Return list of existing objects""" @@ -197,10 +206,20 @@ class Cdist: return objects - def transfer_global_explorers(self): self.transfer_dir(GLOBAL_EXPLORER_DIR, REMOTE_GLOBAL_EXPLORER_DIR) + def transfer_type_explorers(self, type): + """Transfer explorers of a type, but only once""" + if self.type_explorers_transferred[type] == 1 + return + else + self.type_explorers_transferred[type] = 1 + + src = os.path.join(TYPE_DIR, type) + dst = os.path.join(REMOTE_TYPE_DIR, type, "explorer") + self.transfer_dir(src, dst) + def link_type_to_emulator(self): """Link type names to cdist-type-emulator""" for type in list_types(): @@ -226,7 +245,11 @@ class Cdist: self.remote_run_or_fail(cmd, stdout=output_fd) output_fd.close() - # def run_type_explorer(self): + def run_type_explorer(self, object): + """Run type specific explorers for objects""" + # Based on bin/cdist-object-explorer-run + + # Transfering explorers for this type def init_deploy(self): log.info("Creating clean directory structure") From 97ac276433bd15722d3ada5891d47d00ddb90856 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 17:52:15 +0200 Subject: [PATCH 0182/4212] implement transfer of type explorers Signed-off-by: Nico Schottelius --- bin/cdist | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/bin/cdist b/bin/cdist index 4e62bd64..56327fb4 100755 --- a/bin/cdist +++ b/bin/cdist @@ -211,15 +211,20 @@ class Cdist: def transfer_type_explorers(self, type): """Transfer explorers of a type, but only once""" - if self.type_explorers_transferred[type] == 1 + if type in self.type_explorers_transferred: return - else - self.type_explorers_transferred[type] = 1 src = os.path.join(TYPE_DIR, type) - dst = os.path.join(REMOTE_TYPE_DIR, type, "explorer") + base = os.path.join(REMOTE_TYPE_DIR, type) + dst = os.path.join(base, "explorer") + + # Ensure the path path exists + self.remote_run_or_fail(["mkdir", "-p", base]) self.transfer_dir(src, dst) + # Do not retransfer + self.type_explorers_transferred[type] = 1 + def link_type_to_emulator(self): """Link type names to cdist-type-emulator""" for type in list_types(): From f31f33418ff646f9107e72c33dc87c1b4d51644e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 18:03:19 +0200 Subject: [PATCH 0183/4212] begin to actually prepare the object/type explorers Signed-off-by: Nico Schottelius --- bin/cdist | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 56327fb4..0a7011b4 100755 --- a/bin/cdist +++ b/bin/cdist @@ -187,7 +187,7 @@ class Cdist: return object_paths - def get_type_from_object(cdist_object): + def get_type_from_object(self, cdist_object): return cdist_object.split(os.sep)[0] def list_objects(self, starting_point = False): @@ -250,11 +250,13 @@ class Cdist: self.remote_run_or_fail(cmd, stdout=output_fd) output_fd.close() - def run_type_explorer(self, object): + def run_type_explorer(self, cdist_object): """Run type specific explorers for objects""" # Based on bin/cdist-object-explorer-run # Transfering explorers for this type + type = self.get_type_from_object(cdist_object) + self.transfer_type_explorers(type) def init_deploy(self): log.info("Creating clean directory structure") @@ -294,6 +296,11 @@ class Cdist: self.init_deploy() self.run_global_explores() self.run_initial_manifest() + + objects = self.list_objects() + + for cdist_object in objects: + self.run_type_explorer(cdist_object) if __name__ == "__main__": From ab0cd9430fc270f0f99d21e16c5360173db9b914 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 22:40:12 +0200 Subject: [PATCH 0184/4212] add support for the banner :-) Signed-off-by: Nico Schottelius --- bin/cdist | 61 ++++++++++++++++++++++++--- conf/type/__directory/explorer/exists | 30 ------------- 2 files changed, 56 insertions(+), 35 deletions(-) delete mode 100755 conf/type/__directory/explorer/exists diff --git a/bin/cdist b/bin/cdist index 0a7011b4..ad87b38c 100755 --- a/bin/cdist +++ b/bin/cdist @@ -28,6 +28,21 @@ import shutil import sys import tempfile +BANNER = """ + .. . .x+=:. s + dF @88> z` ^% :8 + '88bu. %8P . . -# -# -# Check whether file exists or not -# - -destination="/$__object_id" - -if [ -e "$destination" ]; then - echo yes -else - echo no -fi From 7e8362eeedd24f7df7c983d4e698dfdccb162f76 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 22:44:25 +0200 Subject: [PATCH 0185/4212] allow zero hosts to be specified, fixup exit_error Signed-off-by: Nico Schottelius --- bin/cdist | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index ad87b38c..8f556b1e 100755 --- a/bin/cdist +++ b/bin/cdist @@ -160,7 +160,7 @@ class Cdist: try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: - self.exit_error("Command failed:", " ".join(*args)) + self.exit_error("Command failed: " + " ".join(*args)) def remote_run_or_fail(self, *args, **kargs): """Run something on the remote side and fail is something breaks""" @@ -349,20 +349,20 @@ class Cdist: if __name__ == "__main__": parser = argparse.ArgumentParser(description='cdist ' + VERSION) - parser.add_argument('host', nargs='+', help='one or more hosts to operate on') + parser.add_argument('host', nargs='*', help='one or more hosts to operate on') parser.add_argument('-b', '--banner', help='Show cdist banner', action='store_true', dest='banner') - parser.add_argument('-d', '--debug', help='set log level to debug', + parser.add_argument('-d', '--debug', help='Set log level to debug', action='store_true') parser.add_argument('-i', '--initial-manifest', - help='path to a cdist manifest or - to read from stdin', + help='Path to a cdist manifest or - to read from stdin', dest='manifest', required=False) parser.add_argument('-p', '--parallel', - help='operate on multiple hosts in parallel', + help='Operate on multiple hosts in parallel', action='store_true', dest='parallel') parser.add_argument('-s', '--sequential', - help='operate on multiple hosts sequentially', + help='Operate on multiple hosts sequentially', action='store_false', dest='parallel') args = parser.parse_args(sys.argv[1:]) From cbdb5cd05d0ea4a98d54cc83d6b03f4be136cbc7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Sep 2011 23:01:11 +0200 Subject: [PATCH 0186/4212] fixup type explorer run Signed-off-by: Nico Schottelius --- bin/cdist | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/bin/cdist b/bin/cdist index 8f556b1e..3f57de40 100755 --- a/bin/cdist +++ b/bin/cdist @@ -189,7 +189,13 @@ class Cdist: def list_type_explorers(self, type): """Return list of available explorers for a specific type""" - return os.listdir(type_explorer_dir(type)) + dir = self.type_explorer_dir(type) + if os.path.isdir(dir): + list = os.listdir(dir) + else: + list = [] + + return list def list_object_paths(self, starting_point = False): """Return list of paths of existing objects""" @@ -234,7 +240,7 @@ class Cdist: """Return directory that holds the explorers of a type""" return os.path.join(TYPE_DIR, type, "explorer") - def remote_type_explorer_dir(type): + def remote_type_explorer_dir(self, type): """Return remote directory that holds the explorers of a type""" return os.path.join(REMOTE_TYPE_DIR, type, "explorer") @@ -246,17 +252,20 @@ class Cdist: if type in self.type_explorers_transferred: log.debug("Skipping retransfer for %s", type) return + else: + # Do not retransfer + self.type_explorers_transferred[type] = 1 src = self.type_explorer_dir(type) remote_base = os.path.join(REMOTE_TYPE_DIR, type) - dst = self.type_explorer_dir(type) + dst = self.remote_type_explorer_dir(type) - # Ensure the path path exists - self.remote_run_or_fail(["mkdir", "-p", remote_base]) - self.transfer_dir(src, dst) + # Only continue, if there is at least the directory + if os.path.isdir(src): + # Ensure that the path exists + self.remote_run_or_fail(["mkdir", "-p", remote_base]) + self.transfer_dir(src, dst) - # Do not retransfer - self.type_explorers_transferred[type] = 1 def link_type_to_emulator(self): """Link type names to cdist-type-emulator""" @@ -293,12 +302,12 @@ class Cdist: cmd = [] cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append("__type_explorer=" + remote_type_explorer_dir(type)) + cmd.append("__type_explorer=" + self.remote_type_explorer_dir(type)) - explorers = list_type_explorers(type) + explorers = self.list_type_explorers(type) for explorer in explorers: remote_cmd = cmd - remote_cmd.append(os.path.join(remote_type_explorer_dir(type), explorer)) + remote_cmd.append(os.path.join(self.remote_type_explorer_dir(type), explorer)) self.remote_run_or_fail(remote_cmd) From 8889e4a5b0b0e14ecfc6752edc000bcb917fb618 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Sep 2011 08:06:16 +0200 Subject: [PATCH 0187/4212] prepare saving output of type explorers Signed-off-by: Nico Schottelius --- bin/cdist | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 3f57de40..b35b8c17 100755 --- a/bin/cdist +++ b/bin/cdist @@ -309,7 +309,12 @@ class Cdist: remote_cmd = cmd remote_cmd.append(os.path.join(self.remote_type_explorer_dir(type), explorer)) - self.remote_run_or_fail(remote_cmd) + output = self.type_explorer_output_path(cdist_object) + output_fd = open(output, mode='w') + + self.remote_run_or_fail(remote_cmd, stdout=output_fd) + + output_fd.close() def init_deploy(self): log.info("Creating clean directory structure") From 894c39cd210ea0d312cd07aaf3f01d6e99ca0144 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Sep 2011 12:18:25 +0200 Subject: [PATCH 0188/4212] store results of type explorer Signed-off-by: Nico Schottelius --- bin/cdist | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index b35b8c17..e2e53c9d 100755 --- a/bin/cdist +++ b/bin/cdist @@ -179,6 +179,14 @@ class Cdist: """Returns path of the output for a global explorer""" return os.path.join(self.global_explorer_out_dir, explorer) + def type_explorer_output_dir(self, cdist_object): + """Returns and creates dir of the output for a type explorer""" + dir = os.path.join(self.object_full_path(cdist_object), DOT_CDIST, "explorer") + if not os.path.isdir(dir): + os.mkdir(dir) + + return dir + def remote_global_explorer_path(self, explorer): """Returns path to the remote explorer""" return os.path.join(REMOTE_GLOBAL_EXPLORER_DIR, explorer) @@ -219,8 +227,13 @@ class Cdist: return object_paths def get_type_from_object(self, cdist_object): + """Returns the first part (i.e. type) of an object""" return cdist_object.split(os.sep)[0] + def object_full_path(self, cdist_object): + """Returns the full path to the object (""" + return os.path.join(self.object_dir, cdist_object) + def list_objects(self, starting_point = False): """Return list of existing objects""" @@ -304,12 +317,15 @@ class Cdist: cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) cmd.append("__type_explorer=" + self.remote_type_explorer_dir(type)) + # FIXME: need to transfer object before as well! + cmd.append("__object=" + self.remote_type_explorer_dir(type)) + explorers = self.list_type_explorers(type) for explorer in explorers: remote_cmd = cmd remote_cmd.append(os.path.join(self.remote_type_explorer_dir(type), explorer)) - output = self.type_explorer_output_path(cdist_object) + output = os.path.join(self.type_explorer_output_dir(cdist_object), explorer) output_fd = open(output, mode='w') self.remote_run_or_fail(remote_cmd, stdout=output_fd) From b2d1d1bee703e177a952e80660782cf06df5e782 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Sep 2011 14:21:16 +0200 Subject: [PATCH 0189/4212] begin to modify tuple (bad idea) Signed-off-by: Nico Schottelius --- bin/cdist | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/bin/cdist b/bin/cdist index e2e53c9d..0772c703 100755 --- a/bin/cdist +++ b/bin/cdist @@ -157,19 +157,29 @@ class Cdist: def run_or_fail(self, *args, **kargs): log.debug("Exec: " + " ".join(*args)) + if "remote" in kargs: + log.debug("Remote found") + if kargs["remote"]: + # Replace the list found in the tuple at position 0 + cmd = ["ssh", "root@" + self.target_host] + cmd.extend(args[0]) + args[0] = cmd + print(newargs) + + del kargs["remote"] + + log.debug(newargs) try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: - self.exit_error("Command failed: " + " ".join(*args)) + self.exit_error("Command failed: " + " ".join(*newargs)) - def remote_run_or_fail(self, *args, **kargs): - """Run something on the remote side and fail is something breaks""" - newargs = ["ssh", "root@" + self.target_host] - newargs.extend(*args) - self.run_or_fail(newargs, **kargs) +# def remote_run_or_fail(self, *args, **kargs): +# """Run something on the remote side and fail is something breaks""" +# self.run_or_fail(newargs, **kargs) def remove_remote_dir(self, destination): - self.remote_run_or_fail(["rm", "-rf", destination]) + self.run_or_fail(["rm", "-rf", destination], remote=True) def transfer_dir(self, source, destination): self.remove_remote_dir(destination) From c1ad93bccc6cf93b3a5129914624ec3350ca9b14 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Sep 2011 14:27:54 +0200 Subject: [PATCH 0190/4212] extend run_or_fail to include remote exec Signed-off-by: Nico Schottelius --- bin/cdist | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/bin/cdist b/bin/cdist index 0772c703..5227dc06 100755 --- a/bin/cdist +++ b/bin/cdist @@ -155,20 +155,14 @@ class Cdist: self.exit_error("Non-Zero exit code exit of " + " ".join(*args)) def run_or_fail(self, *args, **kargs): - log.debug("Exec: " + " ".join(*args)) - if "remote" in kargs: log.debug("Remote found") if kargs["remote"]: - # Replace the list found in the tuple at position 0 - cmd = ["ssh", "root@" + self.target_host] - cmd.extend(args[0]) - args[0] = cmd - print(newargs) + args[0][:0] = ["ssh", "root@" + self.target_host] del kargs["remote"] - log.debug(newargs) + log.debug("Exec: " + " ".join(*args)) try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: From 20aafe62f578bf51512507d53d9f385e1b94dba7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Sep 2011 14:30:53 +0200 Subject: [PATCH 0191/4212] make use of remote=True flag Signed-off-by: Nico Schottelius --- bin/cdist | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/bin/cdist b/bin/cdist index 5227dc06..68424cfd 100755 --- a/bin/cdist +++ b/bin/cdist @@ -168,10 +168,6 @@ class Cdist: except subprocess.CalledProcessError: self.exit_error("Command failed: " + " ".join(*newargs)) -# def remote_run_or_fail(self, *args, **kargs): -# """Run something on the remote side and fail is something breaks""" -# self.run_or_fail(newargs, **kargs) - def remove_remote_dir(self, destination): self.run_or_fail(["rm", "-rf", destination], remote=True) @@ -280,7 +276,7 @@ class Cdist: # Only continue, if there is at least the directory if os.path.isdir(src): # Ensure that the path exists - self.remote_run_or_fail(["mkdir", "-p", remote_base]) + self.run_or_fail(["mkdir", "-p", remote_base], remote=True) self.transfer_dir(src, dst) @@ -306,7 +302,7 @@ class Cdist: cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) cmd.append(self.remote_global_explorer_path(explorer)) - self.remote_run_or_fail(cmd, stdout=output_fd) + self.run_or_fail(cmd, stdout=output_fd, remote=True) output_fd.close() def run_type_explorer(self, cdist_object): @@ -332,7 +328,7 @@ class Cdist: output = os.path.join(self.type_explorer_output_dir(cdist_object), explorer) output_fd = open(output, mode='w') - self.remote_run_or_fail(remote_cmd, stdout=output_fd) + self.run_or_fail(remote_cmd, stdout=output_fd, remote=True) output_fd.close() From f21ce6a0db1f778fba8c3726155fa7562c3a4635 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Sep 2011 14:51:25 +0200 Subject: [PATCH 0192/4212] commit broken code Signed-off-by: Nico Schottelius --- bin/cdist | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/bin/cdist b/bin/cdist index 68424cfd..a0189fbe 100755 --- a/bin/cdist +++ b/bin/cdist @@ -98,6 +98,7 @@ class Cdist: def __init__(self, target_host, initial_manifest=False): self.target_host = target_host + self.remote_prefix = ["ssh", "root@" + self.target_host] # log.info("foobar") @@ -139,26 +140,47 @@ class Cdist: log.error(*args) sys.exit(1) + def remote_cat(filename): + cmd = self.remote_prefix + cmd.append("cat") + cmd.append(filename) + try: + subprocess.call(cmd) + except subprocess.CalledProcessError: + log.error("Remote cat failed") + def shell_run_or_debug_fail(self, script, *args, **kargs): # Manually execute /bin/sh, because sh -e does what we want # and sh -c -e does not exit if /bin/false called - args[0].insert(0,"/bin/sh") - args[0].insert(1,"-e") - log.debug("Shell exec: " + " ".join(*args)) + args[0][:0] = [ "/bin/sh", "-e" ] + if "remote" in kargs: + log.debug("Remote found") + if kargs["remote"]: + args[0][:0] = self.remote_prefix + remote = true + + del kargs["remote"] + + log.debug("Shell exec: " + " ".join(*args)) try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: - script_fd = open(script) - log.error("Code that raised the error:\n" + script_fd.read()) - script_fd.close() + log.error("Code that raised the error:\n") + if remote: + remote_cat(script) + else: + script_fd = open(script) + print(script_fd.read()) + script_fd.close() + self.exit_error("Non-Zero exit code exit of " + " ".join(*args)) def run_or_fail(self, *args, **kargs): if "remote" in kargs: log.debug("Remote found") if kargs["remote"]: - args[0][:0] = ["ssh", "root@" + self.target_host] + args[0][:0] = self.remote_prefix del kargs["remote"] @@ -166,7 +188,7 @@ class Cdist: try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: - self.exit_error("Command failed: " + " ".join(*newargs)) + self.exit_error("Command failed: " + " ".join(*args)) def remove_remote_dir(self, destination): self.run_or_fail(["rm", "-rf", destination], remote=True) @@ -322,6 +344,7 @@ class Cdist: explorers = self.list_type_explorers(type) for explorer in explorers: + # THIS IS A BUG, because remote_cmd is NOT a copy remote_cmd = cmd remote_cmd.append(os.path.join(self.remote_type_explorer_dir(type), explorer)) From 2c15069d96e0e35cffc7e4523f7ddf85d7d87212 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Sep 2011 14:56:51 +0200 Subject: [PATCH 0193/4212] make remote_cmd a new list Signed-off-by: Nico Schottelius --- bin/cdist | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index a0189fbe..70df214c 100755 --- a/bin/cdist +++ b/bin/cdist @@ -344,9 +344,7 @@ class Cdist: explorers = self.list_type_explorers(type) for explorer in explorers: - # THIS IS A BUG, because remote_cmd is NOT a copy - remote_cmd = cmd - remote_cmd.append(os.path.join(self.remote_type_explorer_dir(type), explorer)) + remote_cmd = cmd + os.path.join(self.remote_type_explorer_dir(type), explorer) output = os.path.join(self.type_explorer_output_dir(cdist_object), explorer) output_fd = open(output, mode='w') From 6d5a53b7ad9368c2ee3bc704a7068fad5b52ee9c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Sep 2011 15:00:09 +0200 Subject: [PATCH 0194/4212] fixup list bug by creating a new one Signed-off-by: Nico Schottelius --- bin/cdist | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index 70df214c..80d9f525 100755 --- a/bin/cdist +++ b/bin/cdist @@ -155,7 +155,6 @@ class Cdist: args[0][:0] = [ "/bin/sh", "-e" ] if "remote" in kargs: - log.debug("Remote found") if kargs["remote"]: args[0][:0] = self.remote_prefix remote = true @@ -178,7 +177,6 @@ class Cdist: def run_or_fail(self, *args, **kargs): if "remote" in kargs: - log.debug("Remote found") if kargs["remote"]: args[0][:0] = self.remote_prefix @@ -344,13 +342,10 @@ class Cdist: explorers = self.list_type_explorers(type) for explorer in explorers: - remote_cmd = cmd + os.path.join(self.remote_type_explorer_dir(type), explorer) - + remote_cmd = cmd + [os.path.join(self.remote_type_explorer_dir(type), explorer)] output = os.path.join(self.type_explorer_output_dir(cdist_object), explorer) output_fd = open(output, mode='w') - self.run_or_fail(remote_cmd, stdout=output_fd, remote=True) - output_fd.close() def init_deploy(self): From 722339f3e1164b0aac1d2e54904a2f2a510d5548 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Sep 2011 15:16:47 +0200 Subject: [PATCH 0195/4212] support getting paths of objects and their parameters Signed-off-by: Nico Schottelius --- bin/cdist | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index 80d9f525..302e21be 100755 --- a/bin/cdist +++ b/bin/cdist @@ -53,6 +53,7 @@ TYPE_DIR = os.path.join(CONF_DIR, "type") REMOTE_BASE_DIR = "/var/lib/cdist" REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") +REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") REMOTE_TYPE_DIR = os.path.join(REMOTE_CONF_DIR, "type") REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") @@ -100,8 +101,6 @@ class Cdist: self.target_host = target_host self.remote_prefix = ["ssh", "root@" + self.target_host] - # log.info("foobar") - # Setup directory paths self.temp_dir = tempfile.mkdtemp() @@ -192,6 +191,7 @@ class Cdist: self.run_or_fail(["rm", "-rf", destination], remote=True) def transfer_dir(self, source, destination): + """Transfer directory and previously delete the remote destination""" self.remove_remote_dir(destination) self.run_or_fail(["scp", "-qr", source, "root@" + self.target_host + ":" + destination]) @@ -201,7 +201,7 @@ class Cdist: def type_explorer_output_dir(self, cdist_object): """Returns and creates dir of the output for a type explorer""" - dir = os.path.join(self.object_full_path(cdist_object), DOT_CDIST, "explorer") + dir = os.path.join(self.object_dir(cdist_object), "explorer") if not os.path.isdir(dir): os.mkdir(dir) @@ -250,9 +250,21 @@ class Cdist: """Returns the first part (i.e. type) of an object""" return cdist_object.split(os.sep)[0] - def object_full_path(self, cdist_object): - """Returns the full path to the object (""" - return os.path.join(self.object_dir, cdist_object) + def object_dir(self, cdist_object): + """Returns the full path to the object (including .cdist)""" + return os.path.join(self.object_dir, cdist_object, DOT_CDIST) + + def remote_object_dir(self, cdist_object): + """Returns the remote full path to the object (including .cdist)""" + return os.path.join(REMOTE_OBJECT_DIR, cdist_object, DOT_CDIST) + + def object_parameter_dir(self, cdist_object): + """Returns the dir to the object parameter""" + return os.path.join(object_dir(cdist_object), "parameter") + + def remote_object_parameter_dir(self, cdist_object): + """Returns the remote dir to the object parameter""" + return os.path.join(remote_object_dir(cdist_object), "parameter") def list_objects(self, starting_point = False): """Return list of existing objects""" @@ -277,6 +289,9 @@ class Cdist: """Return remote directory that holds the explorers of a type""" return os.path.join(REMOTE_TYPE_DIR, type, "explorer") + def transfer_object_parameter(self, cdist_object): + self.transfer_dir(object_dir(cdist_object), ) + def transfer_global_explorers(self): self.transfer_dir(GLOBAL_EXPLORER_DIR, REMOTE_GLOBAL_EXPLORER_DIR) From db2562303ade41004fe9849074410caa18840376 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Sep 2011 15:28:38 +0200 Subject: [PATCH 0196/4212] in theory transfer the object parameters Signed-off-by: Nico Schottelius --- bin/cdist | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/bin/cdist b/bin/cdist index 302e21be..b2f10ba1 100755 --- a/bin/cdist +++ b/bin/cdist @@ -110,7 +110,7 @@ class Cdist: self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") os.mkdir(self.global_explorer_out_dir) - self.object_dir = os.path.join(self.out_dir, "object") + self.object_base_dir = os.path.join(self.out_dir, "object") # Setup binary directory + contents self.bin_dir = os.path.join(self.out_dir, "bin") @@ -230,7 +230,7 @@ class Cdist: object_paths = [] if not starting_point: - starting_point = self.object_dir + starting_point = self.object_base_dir for content in os.listdir(starting_point): full_path = os.path.join(starting_point, content) @@ -252,7 +252,7 @@ class Cdist: def object_dir(self, cdist_object): """Returns the full path to the object (including .cdist)""" - return os.path.join(self.object_dir, cdist_object, DOT_CDIST) + return os.path.join(self.object_base_dir, cdist_object, DOT_CDIST) def remote_object_dir(self, cdist_object): """Returns the remote full path to the object (including .cdist)""" @@ -260,17 +260,17 @@ class Cdist: def object_parameter_dir(self, cdist_object): """Returns the dir to the object parameter""" - return os.path.join(object_dir(cdist_object), "parameter") + return os.path.join(self.object_dir(cdist_object), "parameter") def remote_object_parameter_dir(self, cdist_object): """Returns the remote dir to the object parameter""" - return os.path.join(remote_object_dir(cdist_object), "parameter") + return os.path.join(self.remote_object_dir(cdist_object), "parameter") def list_objects(self, starting_point = False): """Return list of existing objects""" if not starting_point: - starting_point = self.object_dir + starting_point = self.object_base_dir object_paths = self.list_object_paths(starting_point) objects = [] @@ -290,9 +290,12 @@ class Cdist: return os.path.join(REMOTE_TYPE_DIR, type, "explorer") def transfer_object_parameter(self, cdist_object): - self.transfer_dir(object_dir(cdist_object), ) + """Transfer the object parameter to the remote destination""" + self.transfer_dir(self.object_parameter_dir(cdist_object), + self.remote_object_parameter_dir(cdist_object)) def transfer_global_explorers(self): + """Transfer the global explorers""" self.transfer_dir(GLOBAL_EXPLORER_DIR, REMOTE_GLOBAL_EXPLORER_DIR) def transfer_type_explorers(self, type): @@ -352,8 +355,9 @@ class Cdist: cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) cmd.append("__type_explorer=" + self.remote_type_explorer_dir(type)) - # FIXME: need to transfer object before as well! - cmd.append("__object=" + self.remote_type_explorer_dir(type)) + # Need to transfer at least the parameters for objects to be useful + self.transfer_object_parameter(cdist_object) + cmd.append("__object=" + self.remote_object_dir(cdist_object)) explorers = self.list_type_explorers(type) for explorer in explorers: From 14ac0e3ad166cc90a947d88e2b120f3746cd67b5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Sep 2011 20:53:09 +0200 Subject: [PATCH 0197/4212] introduce remote_mkdir() Signed-off-by: Nico Schottelius --- bin/cdist | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bin/cdist b/bin/cdist index b2f10ba1..30af2827 100755 --- a/bin/cdist +++ b/bin/cdist @@ -139,6 +139,10 @@ class Cdist: log.error(*args) sys.exit(1) + def remote_mkdir(directory): + """Create directory on remote side""" + self.run_or_fail(["mkdir", "-p", directory], remote=True) + def remote_cat(filename): cmd = self.remote_prefix cmd.append("cat") @@ -234,14 +238,11 @@ class Cdist: for content in os.listdir(starting_point): full_path = os.path.join(starting_point, content) - print(full_path) if os.path.isdir(full_path): - log.debug("Recursing for %s", full_path) object_paths.extend(self.list_object_paths(starting_point = full_path)) # Directory contains .cdist -> is an object if content == DOT_CDIST: - log.debug("Adding Object Path %s", starting_point) object_paths.append(starting_point) return object_paths @@ -314,7 +315,7 @@ class Cdist: # Only continue, if there is at least the directory if os.path.isdir(src): # Ensure that the path exists - self.run_or_fail(["mkdir", "-p", remote_base], remote=True) + self.remote_mkdir(remote_base) self.transfer_dir(src, dst) From 99268591c2e3eddbc49bb95f5b2fa31b7f8bd42f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Sep 2011 20:54:17 +0200 Subject: [PATCH 0198/4212] make more use of run_or_fail Signed-off-by: Nico Schottelius --- bin/cdist | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/bin/cdist b/bin/cdist index 30af2827..72b7a752 100755 --- a/bin/cdist +++ b/bin/cdist @@ -139,18 +139,13 @@ class Cdist: log.error(*args) sys.exit(1) - def remote_mkdir(directory): + def remote_mkdir(self, directory): """Create directory on remote side""" self.run_or_fail(["mkdir", "-p", directory], remote=True) def remote_cat(filename): - cmd = self.remote_prefix - cmd.append("cat") - cmd.append(filename) - try: - subprocess.call(cmd) - except subprocess.CalledProcessError: - log.error("Remote cat failed") + """Use cat on the remote side for output""" + self.run_or_fail(["cat", filename], remote=True) def shell_run_or_debug_fail(self, script, *args, **kargs): # Manually execute /bin/sh, because sh -e does what we want From 232618a675fc90accea25646171a9db30b54a2b9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 00:01:16 +0200 Subject: [PATCH 0199/4212] make manifest run more generic Signed-off-by: Nico Schottelius --- bin/cdist | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index 72b7a752..4f9e95de 100755 --- a/bin/cdist +++ b/bin/cdist @@ -287,6 +287,10 @@ class Cdist: def transfer_object_parameter(self, cdist_object): """Transfer the object parameter to the remote destination""" + # Create base path before using mkdir -p + self.remote_mkdir(self.remote_object_parameter_dir(cdist_object)) + + # Synchronise parameter dir afterwards self.transfer_dir(self.object_parameter_dir(cdist_object), self.remote_object_parameter_dir(cdist_object)) @@ -375,8 +379,13 @@ class Cdist: # # Link configuraion source directory - consistent with remote # run_or_fail(["ln -sf", "$__cdist_conf_dir", "$__cdist_local_base_dir/$__cdist_name_conf_dir"]) + # def run_object_manifest(self, cdist_object): def run_initial_manifest(self): """Run the initial manifest""" + self.run_manifest(self.initial_manifest) + + def run_manifest(self, manifest, extra_env=None): + """Run a manifest""" log.info("Running the initial manifest") env = os.environ.copy() env['PATH'] = self.bin_dir + ":" + env['PATH'] @@ -390,9 +399,11 @@ class Cdist: env['__cdist_local_base_dir'] = self.temp_dir env['__cdist_manifest'] = self.initial_manifest - self.shell_run_or_debug_fail(self.initial_manifest, - [self.initial_manifest], - env=env) + # Other environment stuff + if extra_env: + env.update(extra_env) + + self.shell_run_or_debug_fail(manifest, [manifest], env=env) def deploy_to(self): From 8dff399c9654b8983e2997f483253e162c839eb3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 00:09:57 +0200 Subject: [PATCH 0200/4212] reloop until no new objects are created anyomer Signed-off-by: Nico Schottelius --- bin/cdist | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index 4f9e95de..505bb012 100755 --- a/bin/cdist +++ b/bin/cdist @@ -379,11 +379,14 @@ class Cdist: # # Link configuraion source directory - consistent with remote # run_or_fail(["ln -sf", "$__cdist_conf_dir", "$__cdist_local_base_dir/$__cdist_name_conf_dir"]) - # def run_object_manifest(self, cdist_object): def run_initial_manifest(self): """Run the initial manifest""" self.run_manifest(self.initial_manifest) + def run_type_manifest(self, cdist_object): + """Run manifest for a specific object""" + self.run_manifest(self.initial_manifest) + def run_manifest(self, manifest, extra_env=None): """Run a manifest""" log.info("Running the initial manifest") @@ -413,10 +416,18 @@ class Cdist: self.run_global_explores() self.run_initial_manifest() + old_objects = [] objects = self.list_objects() - for cdist_object in objects: - self.run_type_explorer(cdist_object) + # Continue process until no new objects are created anymore + while not old_objects == objects: + old_objects = objects.copy() + for cdist_object in objects: + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + + objects = self.list_objects() + if __name__ == "__main__": From 13e3e27679443d558ddaa9846603c4da390cfb5e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 00:29:51 +0200 Subject: [PATCH 0201/4212] changes for next Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 7e98277a..6d25f234 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,5 +1,6 @@ next: * New Type: __package_rubygem (Chase Allen James) + * __self replaced by __object_fq (or so) 1.7.1: 2011-07-26 * Documentation: Add explorers to reference From 7eb418c3ab6db117db2de036226d05da3033b1cd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 00:40:45 +0200 Subject: [PATCH 0202/4212] correct env for the various stages Signed-off-by: Nico Schottelius --- bin/cdist | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/bin/cdist b/bin/cdist index 505bb012..af19a676 100755 --- a/bin/cdist +++ b/bin/cdist @@ -246,6 +246,10 @@ class Cdist: """Returns the first part (i.e. type) of an object""" return cdist_object.split(os.sep)[0] + def get_object_id_from_object(self, cdist_object): + """Returns everything but the first part (i.e. object_id) of an object""" + return os.sep.join(cdist_object.split(os.sep)[1:]) + def object_dir(self, cdist_object): """Returns the full path to the object (including .cdist)""" return os.path.join(self.object_base_dir, cdist_object, DOT_CDIST) @@ -281,6 +285,10 @@ class Cdist: """Return directory that holds the explorers of a type""" return os.path.join(TYPE_DIR, type, "explorer") + def type_manifest_path(self, type): + """Return path to manifest of type""" + return os.path.join(TYPE_DIR, type, "manifest") + def remote_type_explorer_dir(self, type): """Return remote directory that holds the explorers of a type""" return os.path.join(REMOTE_TYPE_DIR, type, "explorer") @@ -352,6 +360,7 @@ class Cdist: self.transfer_type_explorers(type) cmd = [] + # FIXME: __global::__object_id::__self:: cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) cmd.append("__type_explorer=" + self.remote_type_explorer_dir(type)) @@ -381,15 +390,27 @@ class Cdist: def run_initial_manifest(self): """Run the initial manifest""" - self.run_manifest(self.initial_manifest) + # FIXME: add support for __manifest:: + env = { "__manifest" : MANIFEST_DIR } + self.run_manifest(self.initial_manifest, extra_env=env) def run_type_manifest(self, cdist_object): """Run manifest for a specific object""" - self.run_manifest(self.initial_manifest) + type = self.get_type_from_object(cdist_object) + manifest = self.type_manifest_path(type) + + # FIXME: add more sensible checks for manifest + if os.path.exists(manifest): + env = { "__object" : self.object_dir(cdist_object), + "__object_id": self.get_object_id_from_object(cdist_object), + "__object_fq": cdist_object, + "__type": type + } + self.run_manifest(self.initial_manifest, extra_env=env) def run_manifest(self, manifest, extra_env=None): """Run a manifest""" - log.info("Running the initial manifest") + log.info("Running manifest %s", manifest) env = os.environ.copy() env['PATH'] = self.bin_dir + ":" + env['PATH'] @@ -420,8 +441,10 @@ class Cdist: objects = self.list_objects() # Continue process until no new objects are created anymore - while not old_objects == objects: - old_objects = objects.copy() + while old_objects != objects: + log.debug("Prepare stage") + old_objects = list(objects) + # FIXME: do not rerun existing objects! for cdist_object in objects: self.run_type_explorer(cdist_object) self.run_type_manifest(cdist_object) From 4e2e731374a55827e4670885b6c4bf6948c3a9d5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 00:43:28 +0200 Subject: [PATCH 0203/4212] execute the correct manifest for objects Signed-off-by: Nico Schottelius --- bin/cdist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index af19a676..ff114325 100755 --- a/bin/cdist +++ b/bin/cdist @@ -406,11 +406,11 @@ class Cdist: "__object_fq": cdist_object, "__type": type } - self.run_manifest(self.initial_manifest, extra_env=env) + self.run_manifest(manifest, extra_env=env) def run_manifest(self, manifest, extra_env=None): """Run a manifest""" - log.info("Running manifest %s", manifest) + log.info("Running manifest %s, env=%s", manifest, extra_env) env = os.environ.copy() env['PATH'] = self.bin_dir + ":" + env['PATH'] From bc6201102eb0b1d09f4328959b38f3608b7048ba Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 00:44:15 +0200 Subject: [PATCH 0204/4212] todo-- Signed-off-by: Nico Schottelius --- bin/cdist-deploy-to | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to index 96650f90..86e15800 100755 --- a/bin/cdist-deploy-to +++ b/bin/cdist-deploy-to @@ -43,7 +43,6 @@ __cdist_echo info "cdist $__cdist_version: Configuring $__cdist_target_host " # See cdist-stages(7) # -cdist-object-all "$__cdist_target_host" cdist-object-prepare cdist-object-all "$__cdist_target_host" cdist-object-run cdist-cache "$__cdist_target_host" From f5c2ae3049c48bb056fdc9570648f36a892045d1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 00:48:24 +0200 Subject: [PATCH 0205/4212] begin cleanup Signed-off-by: Nico Schottelius --- bin/cdist-cache | 39 -------------------------- bin/cdist-dir | 51 ---------------------------------- bin/cdist-run-remote | 33 ---------------------- bin/cdist-type-build-emulation | 43 ---------------------------- 4 files changed, 166 deletions(-) delete mode 100755 bin/cdist-cache delete mode 100755 bin/cdist-dir delete mode 100755 bin/cdist-run-remote delete mode 100755 bin/cdist-type-build-emulation diff --git a/bin/cdist-cache b/bin/cdist-cache deleted file mode 100755 index ee27ffb4..00000000 --- a/bin/cdist-cache +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh -# -# 2010 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's build a cconfig tree from a configuration -# And save it into the cache tree -# - -. cdist-config -[ $# -eq 1 ] || __cdist_usage "" -set -u - -__cdist_target_host="$1"; shift - -# Create base to move into -mkdir -p "${__cdist_local_base_cache_dir}" - -# Now determine absolute path -__cdist_ddir="$(__cdist_host_cache_dir "$__cdist_target_host")" - -__cdist_echo info "Saving cache to $__cdist_ddir " -rm -rf "$__cdist_ddir" -mv "$__cdist_local_base_dir" "$__cdist_ddir" diff --git a/bin/cdist-dir b/bin/cdist-dir deleted file mode 100755 index 0d30e14a..00000000 --- a/bin/cdist-dir +++ /dev/null @@ -1,51 +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 . -# -# -# 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) -# - - -. cdist-config -[ $# -eq 4 ] || __cdist_usage " " -set -ue - -__cdist_action="$1"; shift -__cdist_target_host="$1"; shift -__cdist_src_dir="$1"; shift -__cdist_dst_dir="$1"; shift - -# This will be the destination directory, so no subdirectories -# of the same name are created, if the directory is already existing -__cdist_top_dir="${__cdist_dst_dir%/*}" - -if [ "$__cdist_action" = "push" ]; then - ssh "${__cdist_remote_user}@${__cdist_target_host}" \ - "mkdir -p \"${__cdist_dst_dir}\"" - scp -qr "$__cdist_src_dir" \ - "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_top_dir}" -elif [ "$__cdist_action" = "pull" ]; then - mkdir -p "${__cdist_dst_dir}" - scp -qr "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_src_dir}" \ - "${__cdist_top_dir}" -else - __cdist_exit_err "Unknown action $__cdist_action" -fi diff --git a/bin/cdist-run-remote b/bin/cdist-run-remote deleted file mode 100755 index 4a4452a2..00000000 --- a/bin/cdist-run-remote +++ /dev/null @@ -1,33 +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 . -# -# -# Run a cdist binary on the remote side -# - -. cdist-config -[ $# -ge 2 ] || __cdist_usage " [opts]" -set -ue - -__cdist_target_host="$1"; shift - -ssh "${__cdist_remote_user}@${__cdist_target_host}" \ - "export PATH=\"${__cdist_remote_bin_dir}:\$PATH\";" \ - "export __cdist_out_object_dir=\"$__cdist_remote_out_object_dir\";" \ - "$@" diff --git a/bin/cdist-type-build-emulation b/bin/cdist-type-build-emulation deleted file mode 100755 index 51c2f5b4..00000000 --- a/bin/cdist-type-build-emulation +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# Build pseudo binaries for type emulation -# - -. cdist-config -[ $# -eq 1 ] || __cdist_usage "" -set -eu - -__cdist_output_dir="$1"; shift - -__cdist_type_emulator="$__cdist_abs_mydir/cdist-type-emulator" - -if [ ! -d "${__cdist_type_dir}" ]; then - __cdist_exit_err "$__cdist_type_dir must exist and contain available types" -fi - -# Get Types -cd "${__cdist_type_dir}" -ls -1 > "${__cdist_tmp_file}" - -# Create binaries -mkdir -p "${__cdist_output_dir}" -while read type; do - ln -sf "${__cdist_type_emulator}" "${__cdist_output_dir}/${type}" -done < "${__cdist_tmp_file}" From 74c280911bb1e3bca234d72236df9a584feb29c9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 00:53:10 +0200 Subject: [PATCH 0206/4212] begin run_object_gencode() and import missing FIXME bits deploy_to() Signed-off-by: Nico Schottelius --- bin/cdist | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/bin/cdist b/bin/cdist index ff114325..46422ce5 100755 --- a/bin/cdist +++ b/bin/cdist @@ -429,6 +429,23 @@ class Cdist: self.shell_run_or_debug_fail(manifest, [manifest], env=env) + def run_object_gencode(self, cdist_object): + """Run the gencode scripts for the object""" + log.info("Running manifest %s, env=%s", manifest, extra_env) + env = os.environ.copy() + + env['__target_host'] = self.target_host + env['__global'] = self.out_dir + + # FIXME: if -local, -remote... + + + # Other environment stuff + if extra_env: + env.update(extra_env) + + self.shell_run_or_debug_fail(manifest, [manifest], env=env) + def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" @@ -451,6 +468,17 @@ class Cdist: objects = self.list_objects() + # Now do the final steps over the existing objects + for cdist_object in objects: + # FIXME: Check requirements and execute those before + + # FIXME: to be implemented + # cdist-object-gencode-run "$__cdist_target_host" "$__cdist_object_self" + # cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" + + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + if __name__ == "__main__": From 99887fe20f3ca74d604172f83ec7a5c2498863e9 Mon Sep 17 00:00:00 2001 From: Andrew Schleifer Date: Fri, 9 Sep 2011 23:24:32 -0500 Subject: [PATCH 0207/4212] fix typo --- bin/cdist-quickstart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist-quickstart b/bin/cdist-quickstart index 4d89180c..e146f1a8 100755 --- a/bin/cdist-quickstart +++ b/bin/cdist-quickstart @@ -249,7 +249,7 @@ fi manifestinit="conf/manifest/init" cat << eof -I'll know setup $manifestinit, containing the following code: +I'll now setup $manifestinit, containing the following code: -------------------------------------------------------------------------------- # Every machine becomes a marker, so sysadmins know that automatic From 4a5100692ab2374fafcc7744ca3b21b855b2da5d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 10:12:01 +0200 Subject: [PATCH 0208/4212] add helper methods to get paths from code/gencode Signed-off-by: Nico Schottelius --- bin/cdist | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/bin/cdist b/bin/cdist index 46422ce5..9eaf39fe 100755 --- a/bin/cdist +++ b/bin/cdist @@ -266,6 +266,11 @@ class Cdist: """Returns the remote dir to the object parameter""" return os.path.join(self.remote_object_dir(cdist_object), "parameter") + def object_code_paths(self, cdist_object): + """Return paths to code scripts of object""" + return [os.path.join(object_dir(cdist_object), "code-local"), + os.path.join(object_dir(cdist_object), "code-remote")] + def list_objects(self, starting_point = False): """Return list of existing objects""" @@ -285,6 +290,11 @@ class Cdist: """Return directory that holds the explorers of a type""" return os.path.join(TYPE_DIR, type, "explorer") + def type_gencode_paths(self, type): + """Return paths to gencode scripts of type""" + return [os.path.join(TYPE_DIR, type, "gencode-local"), + os.path.join(TYPE_DIR, type, "gencode-remote")] + def type_manifest_path(self, type): """Return path to manifest of type""" return os.path.join(TYPE_DIR, type, "manifest") @@ -390,7 +400,6 @@ class Cdist: def run_initial_manifest(self): """Run the initial manifest""" - # FIXME: add support for __manifest:: env = { "__manifest" : MANIFEST_DIR } self.run_manifest(self.initial_manifest, extra_env=env) @@ -446,6 +455,26 @@ class Cdist: self.shell_run_or_debug_fail(manifest, [manifest], env=env) + def object_run(self, cdist_object, mode): + """Run gencode or code for an object""" + # FIXME: Check requirements and execute those before + requirements = list_object_requirements(cdist_object) + + for requirement in requirements: + object_run(requirement, mode=mode) + + # Find and run all available gencode scripts + if mode == "gencode": + base_path = object_dir + if mode == "code": + + # FIXME: to be implemented + # cdist-object-gencode-run "$__cdist_target_host" "$__cdist_object_self" + # cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" + + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" @@ -470,14 +499,9 @@ class Cdist: # Now do the final steps over the existing objects for cdist_object in objects: - # FIXME: Check requirements and execute those before + object_run(cdist_object, mode="gencode") + object_run(cdist_object, mode="code") - # FIXME: to be implemented - # cdist-object-gencode-run "$__cdist_target_host" "$__cdist_object_self" - # cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" - - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) From c516d8359eb5780a5b9b0f4d4c51208ef684f03c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 13:19:32 +0200 Subject: [PATCH 0209/4212] support __object_* in run_type_explorer() Signed-off-by: Nico Schottelius --- bin/cdist | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/bin/cdist b/bin/cdist index 9eaf39fe..b3397fb8 100755 --- a/bin/cdist +++ b/bin/cdist @@ -370,9 +370,11 @@ class Cdist: self.transfer_type_explorers(type) cmd = [] - # FIXME: __global::__object_id::__self:: - cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) cmd.append("__type_explorer=" + self.remote_type_explorer_dir(type)) + cmd.append("__global =" + self.out_dir) + cmd.append("__object_id=" + self.get_object_id_from_object(cdist_object)) + cmd.append("__object_fq=" + cdist_object) # Need to transfer at least the parameters for objects to be useful self.transfer_object_parameter(cdist_object) @@ -465,15 +467,20 @@ class Cdist: # Find and run all available gencode scripts if mode == "gencode": - base_path = object_dir + paths = self.type_gencode_paths(self.get_type_from_object(cdist_object)) if mode == "code": + paths = self.object_code_paths(cdist_object) # FIXME: to be implemented # cdist-object-gencode-run "$__cdist_target_host" "$__cdist_object_self" # cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) + for bin in paths: + if os.path.isfile(bin): + if mode == "gencode": + self.shell_run_or_debug_fail(manifest, [manifest], env=env) + if mode == "code": + self.run_or_fail(manifest, [manifest], env=env) def deploy_to(self): From beafb55e12b7df60f021183b38d0d4f001ec082a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 14:44:21 +0200 Subject: [PATCH 0210/4212] __global not available for type explorer (should it be?) Signed-off-by: Nico Schottelius --- doc/man/cdist-reference.text.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 90efc0f8..9ef7e9c2 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -164,7 +164,7 @@ __manifest:: Available for: initial manifest __global:: Directory that contains generic output like explorer. - Available for: initial manifest, type manifest, type explorer, type codegen + Available for: initial manifest, type manifest, type codegen __object:: Directory that contains the current object. Available for: type manifest, type explorer, type codegen From 636995f44ef76deaec2ef531f6d9ef86cb0f0119 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 14:45:59 +0200 Subject: [PATCH 0211/4212] add some meat to object_run() Signed-off-by: Nico Schottelius --- bin/cdist | 47 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/bin/cdist b/bin/cdist index b3397fb8..a13abcf4 100755 --- a/bin/cdist +++ b/bin/cdist @@ -372,13 +372,12 @@ class Cdist: cmd = [] cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) cmd.append("__type_explorer=" + self.remote_type_explorer_dir(type)) - cmd.append("__global =" + self.out_dir) + cmd.append("__object=" + self.remote_object_dir(cdist_object)) cmd.append("__object_id=" + self.get_object_id_from_object(cdist_object)) cmd.append("__object_fq=" + cdist_object) # Need to transfer at least the parameters for objects to be useful self.transfer_object_parameter(cdist_object) - cmd.append("__object=" + self.remote_object_dir(cdist_object)) explorers = self.list_type_explorers(type) for explorer in explorers: @@ -459,28 +458,29 @@ class Cdist: def object_run(self, cdist_object, mode): """Run gencode or code for an object""" - # FIXME: Check requirements and execute those before - requirements = list_object_requirements(cdist_object) + # FIXME: Check requirements and execute those before + requirements = self.list_object_requirements(cdist_object) - for requirement in requirements: - object_run(requirement, mode=mode) + for requirement in requirements: + self.object_run(requirement, mode=mode) - # Find and run all available gencode scripts - if mode == "gencode": - paths = self.type_gencode_paths(self.get_type_from_object(cdist_object)) - if mode == "code": - paths = self.object_code_paths(cdist_object) + # Find and run all available gencode scripts + if mode == "gencode": + paths = self.type_gencode_paths(self.get_type_from_object(cdist_object)) + if mode == "code": + paths = self.object_code_paths(cdist_object) - # FIXME: to be implemented - # cdist-object-gencode-run "$__cdist_target_host" "$__cdist_object_self" - # cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" + # FIXME: to be implemented + # cdist-object-gencode-run "$__cdist_target_host" "$__cdist_object_self" + # cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" - for bin in paths: - if os.path.isfile(bin): - if mode == "gencode": - self.shell_run_or_debug_fail(manifest, [manifest], env=env) - if mode == "code": - self.run_or_fail(manifest, [manifest], env=env) + for bin in paths: + FIXME + if os.path.isfile(bin): + if mode == "gencode": + self.shell_run_or_debug_fail(manifest, [manifest], env=env) + if mode == "code": + self.run_or_fail(manifest, [manifest], env=env) def deploy_to(self): @@ -506,11 +506,8 @@ class Cdist: # Now do the final steps over the existing objects for cdist_object in objects: - object_run(cdist_object, mode="gencode") - object_run(cdist_object, mode="code") - - - + self.object_run(cdist_object, mode="gencode") + self.object_run(cdist_object, mode="code") if __name__ == "__main__": parser = argparse.ArgumentParser(description='cdist ' + VERSION) From 5a765bfc761d9fda4f026376f470f8309af5786e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 15:09:09 +0200 Subject: [PATCH 0212/4212] codegen vs. gencode Signed-off-by: Nico Schottelius --- doc/man/cdist-reference.text.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 9ef7e9c2..a823891b 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -164,19 +164,19 @@ __manifest:: Available for: initial manifest __global:: Directory that contains generic output like explorer. - Available for: initial manifest, type manifest, type codegen + Available for: initial manifest, type manifest, type gencode __object:: Directory that contains the current object. - Available for: type manifest, type explorer, type codegen + Available for: type manifest, type explorer, type gencode __object_id:: The type unique object id. - Available for: type manifest, type explorer, type codegen + Available for: type manifest, type explorer, type gencode __self:: The full qualified name of the current object. - Available for: type manifest, type explorer, type codegen + Available for: type manifest, type explorer, type gencode __target_host:: The host we are deploying to. - Available for: initial manifest, type manifest, type codegen + Available for: initial manifest, type manifest, type gencode __target_user:: User to use for authentication on remote host. Currently static in core. From ca58841696d969db8c62c6eafd0840a895cca520 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 15:36:21 +0200 Subject: [PATCH 0213/4212] Broken code - it's too hot DEBUG: Shell exec: /bin/sh -e /home/users/nico/p/cdist/conf/type/__directory/gencode-remote Traceback (most recent call last): File "/home/users/nico/p/cdist/bin/cdist", line 557, in c.deploy_to() File "/home/users/nico/p/cdist/bin/cdist", line 523, in deploy_to self.object_run(cdist_object, mode="gencode") File "/home/users/nico/p/cdist/bin/cdist", line 491, in object_run self.shell_run_or_debug_fail(bin, [bin], env=env) File "/home/users/nico/p/cdist/bin/cdist", line 164, in shell_run_or_debug_fail subprocess.check_call(*args, **kargs) File "/usr/lib/python3.2/subprocess.py", line 480, in check_call retcode = call(*popenargs, **kwargs) File "/usr/lib/python3.2/subprocess.py", line 467, in call return Popen(*popenargs, **kwargs).wait() File "/usr/lib/python3.2/subprocess.py", line 741, in __init__ restore_signals, start_new_session) File "/usr/lib/python3.2/subprocess.py", line 1174, in _execute_child for k, v in env.items()] File "/usr/lib/python3.2/subprocess.py", line 1174, in for k, v in env.items()] File "/usr/lib/python3.2/os.py", line 581, in fsencode raise TypeError("expect bytes or str, not %s" % type(filename).__name__) TypeError: expect bytes or str, not tuple Signed-off-by: Nico Schottelius --- bin/cdist | 58 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/bin/cdist b/bin/cdist index a13abcf4..b9c071b5 100755 --- a/bin/cdist +++ b/bin/cdist @@ -268,8 +268,8 @@ class Cdist: def object_code_paths(self, cdist_object): """Return paths to code scripts of object""" - return [os.path.join(object_dir(cdist_object), "code-local"), - os.path.join(object_dir(cdist_object), "code-remote")] + return [os.path.join(self.object_dir(cdist_object), "code-local"), + os.path.join(self.object_dir(cdist_object), "code-remote")] def list_objects(self, starting_point = False): """Return list of existing objects""" @@ -279,7 +279,6 @@ class Cdist: object_paths = self.list_object_paths(starting_point) objects = [] - log.debug("Paths recieved: %s", object_paths) for path in object_paths: objects.append(os.path.relpath(path, starting_point)) @@ -439,22 +438,23 @@ class Cdist: self.shell_run_or_debug_fail(manifest, [manifest], env=env) - def run_object_gencode(self, cdist_object): - """Run the gencode scripts for the object""" - log.info("Running manifest %s, env=%s", manifest, extra_env) - env = os.environ.copy() + def list_object_requirements(self, cdist_object): + """Return list of requirements for specific object""" + file=os.path.join(self.object_dir(cdist_object), "require") - env['__target_host'] = self.target_host - env['__global'] = self.out_dir + if os.path.isfile(file): + file_fd = open(file, "r") + requirements = file_fd.readlines() + file_fd.close() - # FIXME: if -local, -remote... - + # Remove \n from all lines + requirements = map(lambda s: s.strip(), requirements) - # Other environment stuff - if extra_env: - env.update(extra_env) + log.debug(requirements) + else: + requirements = [] - self.shell_run_or_debug_fail(manifest, [manifest], env=env) + return requirements def object_run(self, cdist_object, mode): """Run gencode or code for an object""" @@ -470,18 +470,32 @@ class Cdist: if mode == "code": paths = self.object_code_paths(cdist_object) - # FIXME: to be implemented - # cdist-object-gencode-run "$__cdist_target_host" "$__cdist_object_self" - # cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" + # + # Setup env Variable: + # + env = os.environ.copy() + env['__target_host'] = self.target_host + env['__global'] = self.out_dir + env["__object"] = self.object_dir(cdist_object), + env["__object_id"] = self.get_object_id_from_object(cdist_object), + env["__object_fq"] = cdist_object for bin in paths: - FIXME + log.debug("object/bin: %s", bin) if os.path.isfile(bin): + # FIXME: to be implemented + # cdist-object-gencode-run "$__cdist_target_host" "$__cdist_object_self" if mode == "gencode": - self.shell_run_or_debug_fail(manifest, [manifest], env=env) + # __global::__object::__object_id::__self::__target_host:: + # + self.shell_run_or_debug_fail(bin, [bin], env=env) if mode == "code": - self.run_or_fail(manifest, [manifest], env=env) - + # FIXME: to be implemented + # cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" + log.debug("ERROR NOT IMPLEMENTED") + sys.exit(3) + # FIXME: transfer code and add remote path! + self.run_or_fail([bin], remote=True) def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" From 151022ffd1ef322b2e7fbeb4057630ab42d08f17 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Sep 2011 23:46:17 +0200 Subject: [PATCH 0214/4212] support file transfer and begin support for non root logins Signed-off-by: Nico Schottelius --- bin/cdist | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index b9c071b5..f34812d9 100755 --- a/bin/cdist +++ b/bin/cdist @@ -97,7 +97,7 @@ def banner(): class Cdist: """Cdist main class to hold arbitrary data""" - def __init__(self, target_host, initial_manifest=False): + def __init__(self, target_host, initial_manifest=False, remote_user="root"): self.target_host = target_host self.remote_prefix = ["ssh", "root@" + self.target_host] @@ -120,6 +120,8 @@ class Cdist: # List of type explorers transferred self.type_explorers_transferred = {} + self.remote_user = remote_user + # Mostly static, but can be overwritten on user demand if initial_manifest: self.initial_manifest = initial_manifest @@ -192,7 +194,17 @@ class Cdist: def transfer_dir(self, source, destination): """Transfer directory and previously delete the remote destination""" self.remove_remote_dir(destination) - self.run_or_fail(["scp", "-qr", source, "root@" + self.target_host + ":" + destination]) + self.run_or_fail(["scp", "-qr", source, + self.remote_user + "@" + + self.target_host + ":" + + destination]) + + def transfer_file(self, source, destination): + """Transfer file""" + self.run_or_fail(["scp", "-q", source, + self.remote_user + "@" + + self.target_host + ":" + + destination]) def global_explorer_output_path(self, explorer): """Returns path of the output for a global explorer""" @@ -311,6 +323,16 @@ class Cdist: self.transfer_dir(self.object_parameter_dir(cdist_object), self.remote_object_parameter_dir(cdist_object)) + def transfer_object_code(self, cdist_object): + FIXME + """Transfer the object code to the remote destination""" + # Create base path before using mkdir -p + self.remote_mkdir(self.remote_object_parameter_dir(cdist_object)) + + # Synchronise parameter dir afterwards + self.transfer_dir(self.object_parameter_dir(cdist_object), + self.remote_object_parameter_dir(cdist_object)) + def transfer_global_explorers(self): """Transfer the global explorers""" self.transfer_dir(GLOBAL_EXPLORER_DIR, REMOTE_GLOBAL_EXPLORER_DIR) From c147c74e1ed465e15e916b0af73cdb30d69a17c2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 13:11:45 +0200 Subject: [PATCH 0215/4212] begin to redo object_run() Signed-off-by: Nico Schottelius --- bin/cdist | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index f34812d9..eb1e9112 100755 --- a/bin/cdist +++ b/bin/cdist @@ -330,7 +330,7 @@ class Cdist: self.remote_mkdir(self.remote_object_parameter_dir(cdist_object)) # Synchronise parameter dir afterwards - self.transfer_dir(self.object_parameter_dir(cdist_object), + self.transfer_file(self.object_code_path(cdist_object), self.remote_object_parameter_dir(cdist_object)) def transfer_global_explorers(self): @@ -512,6 +512,9 @@ class Cdist: # self.shell_run_or_debug_fail(bin, [bin], env=env) if mode == "code": + local_dir = object_dir(cdist_object) + remote_dir = remote_object_dir(cdist_object) + # FIXME: to be implemented # cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" log.debug("ERROR NOT IMPLEMENTED") From c9c808a732e66210d2780fbfc533eec263bf660e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 13:55:40 +0200 Subject: [PATCH 0216/4212] cleanp Signed-off-by: Nico Schottelius --- bin/cdist | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/bin/cdist b/bin/cdist index eb1e9112..7c2de358 100755 --- a/bin/cdist +++ b/bin/cdist @@ -152,6 +152,7 @@ class Cdist: def shell_run_or_debug_fail(self, script, *args, **kargs): # Manually execute /bin/sh, because sh -e does what we want # and sh -c -e does not exit if /bin/false called + print(args) args[0][:0] = [ "/bin/sh", "-e" ] if "remote" in kargs: @@ -161,6 +162,8 @@ class Cdist: del kargs["remote"] + print(args) + print(*args) log.debug("Shell exec: " + " ".join(*args)) try: subprocess.check_call(*args, **kargs) @@ -472,7 +475,7 @@ class Cdist: # Remove \n from all lines requirements = map(lambda s: s.strip(), requirements) - log.debug(requirements) + log.debug("Requirements for %s: %s", cdist_object, requirements) else: requirements = [] @@ -480,18 +483,13 @@ class Cdist: def object_run(self, cdist_object, mode): """Run gencode or code for an object""" - # FIXME: Check requirements and execute those before + log.debug("Running %s from %s", mode, cdist_object) requirements = self.list_object_requirements(cdist_object) for requirement in requirements: + log.debug("Object %s requires %s", cdist_object, requirement) self.object_run(requirement, mode=mode) - # Find and run all available gencode scripts - if mode == "gencode": - paths = self.type_gencode_paths(self.get_type_from_object(cdist_object)) - if mode == "code": - paths = self.object_code_paths(cdist_object) - # # Setup env Variable: # @@ -502,26 +500,26 @@ class Cdist: env["__object_id"] = self.get_object_id_from_object(cdist_object), env["__object_fq"] = cdist_object - for bin in paths: - log.debug("object/bin: %s", bin) - if os.path.isfile(bin): - # FIXME: to be implemented - # cdist-object-gencode-run "$__cdist_target_host" "$__cdist_object_self" - if mode == "gencode": - # __global::__object::__object_id::__self::__target_host:: - # + if mode == "gencode": + paths = self.type_gencode_paths(self.get_type_from_object(cdist_object)) + for bin in paths: + if os.path.isfile(bin): + print(bin) self.shell_run_or_debug_fail(bin, [bin], env=env) - if mode == "code": - local_dir = object_dir(cdist_object) - remote_dir = remote_object_dir(cdist_object) - # FIXME: to be implemented - # cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" - log.debug("ERROR NOT IMPLEMENTED") - sys.exit(3) - # FIXME: transfer code and add remote path! - self.run_or_fail([bin], remote=True) + if mode == "code": +# paths = self.object_code_paths(cdist_object) + local_dir = self.object_dir(cdist_object) + remote_dir = self.remote_object_dir(cdist_object) + bin = os.path.join(local_dir, "code-local") + if os.path.isfile(bin): + self.run_or_fail([bin], remote=False) + + if os.path.isfile(os.path.join(local_dir, "code-remote")): + remote_code = os.path.join(remote_dir, "code-remote") + self.run_or_fail([remote_code], remote=True) + def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" log.info("Deploying to host " + self.target_host) @@ -542,9 +540,11 @@ class Cdist: self.run_type_manifest(cdist_object) objects = self.list_objects() - + + log.debug("Actual run objects") # Now do the final steps over the existing objects for cdist_object in objects: + log.debug("Run object: %s", cdist_object) self.object_run(cdist_object, mode="gencode") self.object_run(cdist_object, mode="code") From 5702706adf5badf120fc60d742164034ce934a76 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 14:11:54 +0200 Subject: [PATCH 0217/4212] fix not so obvious tuple/str error (trailing comma from c&p) Signed-off-by: Nico Schottelius --- bin/cdist | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index 7c2de358..7e6f6ddf 100755 --- a/bin/cdist +++ b/bin/cdist @@ -152,7 +152,6 @@ class Cdist: def shell_run_or_debug_fail(self, script, *args, **kargs): # Manually execute /bin/sh, because sh -e does what we want # and sh -c -e does not exit if /bin/false called - print(args) args[0][:0] = [ "/bin/sh", "-e" ] if "remote" in kargs: @@ -162,9 +161,8 @@ class Cdist: del kargs["remote"] - print(args) - print(*args) - log.debug("Shell exec: " + " ".join(*args)) + log.debug("Shell exec cmd: %s", args) + log.debug("Shell exec env: %s", kargs['env']) try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: @@ -496,8 +494,8 @@ class Cdist: env = os.environ.copy() env['__target_host'] = self.target_host env['__global'] = self.out_dir - env["__object"] = self.object_dir(cdist_object), - env["__object_id"] = self.get_object_id_from_object(cdist_object), + env["__object"] = self.object_dir(cdist_object) + env["__object_id"] = self.get_object_id_from_object(cdist_object) env["__object_fq"] = cdist_object if mode == "gencode": From c78ce344e73578eeba144b7a6eff6419df2e4e0e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 14:30:05 +0200 Subject: [PATCH 0218/4212] remove debug by default, switch to infolevel and verify -d works Signed-off-by: Nico Schottelius --- bin/cdist | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/bin/cdist b/bin/cdist index 7e6f6ddf..157b8d13 100755 --- a/bin/cdist +++ b/bin/cdist @@ -81,7 +81,7 @@ VERSION = "2.0.0" # -logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s') +logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') log = logging.getLogger() # List types @@ -406,6 +406,9 @@ class Cdist: remote_cmd = cmd + [os.path.join(self.remote_type_explorer_dir(type), explorer)] output = os.path.join(self.type_explorer_output_dir(cdist_object), explorer) output_fd = open(output, mode='w') + log.debug("%s exploring %s using %s storing to %s", + cdist_object, explorer, remote_cmd, output) + self.run_or_fail(remote_cmd, stdout=output_fd, remote=True) output_fd.close() @@ -431,18 +434,19 @@ class Cdist: type = self.get_type_from_object(cdist_object) manifest = self.type_manifest_path(type) + log.debug("%s: Running %s", cdist_object, manifest) # FIXME: add more sensible checks for manifest if os.path.exists(manifest): - env = { "__object" : self.object_dir(cdist_object), + env = { "__object" : self.object_dir(cdist_object), "__object_id": self.get_object_id_from_object(cdist_object), "__object_fq": cdist_object, - "__type": type + "__type": type } self.run_manifest(manifest, extra_env=env) def run_manifest(self, manifest, extra_env=None): """Run a manifest""" - log.info("Running manifest %s, env=%s", manifest, extra_env) + log.debug("Running manifest %s, env=%s", manifest, extra_env) env = os.environ.copy() env['PATH'] = self.bin_dir + ":" + env['PATH'] @@ -502,7 +506,6 @@ class Cdist: paths = self.type_gencode_paths(self.get_type_from_object(cdist_object)) for bin in paths: if os.path.isfile(bin): - print(bin) self.shell_run_or_debug_fail(bin, [bin], env=env) if mode == "code": @@ -546,6 +549,8 @@ class Cdist: self.object_run(cdist_object, mode="gencode") self.object_run(cdist_object, mode="code") + log.info("Finished run of %s", self.target_host) + if __name__ == "__main__": parser = argparse.ArgumentParser(description='cdist ' + VERSION) parser.add_argument('host', nargs='*', help='one or more hosts to operate on') From 6bd823995fff95414060ef4eca841f74733ecff4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 17:20:07 +0200 Subject: [PATCH 0219/4212] restore mistakenly deleted file Signed-off-by: Nico Schottelius --- conf/type/__directory/explorer/exists | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100755 conf/type/__directory/explorer/exists diff --git a/conf/type/__directory/explorer/exists b/conf/type/__directory/explorer/exists new file mode 100755 index 00000000..f8b85671 --- /dev/null +++ b/conf/type/__directory/explorer/exists @@ -0,0 +1,30 @@ +#!/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 yes +else + echo no +fi From 30a52cab0fe45d932d822ea7a28b6dfbfe5ef98a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 20:17:20 +0200 Subject: [PATCH 0220/4212] begin to save code and make it executable Signed-off-by: Nico Schottelius --- bin/cdist | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index 157b8d13..e76ecfc7 100755 --- a/bin/cdist +++ b/bin/cdist @@ -25,6 +25,7 @@ import logging import os import subprocess import shutil +import stat import sys import tempfile @@ -93,7 +94,6 @@ def banner(): print(BANNER) - class Cdist: """Cdist main class to hold arbitrary data""" @@ -235,6 +235,8 @@ class Cdist: else: list = [] + log.debug("Explorers for %s in %s: %s", type, dir, list) + return list def list_object_paths(self, starting_point = False): @@ -341,7 +343,7 @@ class Cdist: def transfer_type_explorers(self, type): """Transfer explorers of a type, but only once""" if type in self.type_explorers_transferred: - log.debug("Skipping retransfer for %s", type) + log.debug("Skipping retransfer for explorers of %s", type) return else: # Do not retransfer @@ -506,7 +508,19 @@ class Cdist: paths = self.type_gencode_paths(self.get_type_from_object(cdist_object)) for bin in paths: if os.path.isfile(bin): - self.shell_run_or_debug_fail(bin, [bin], env=env) + # omit "gen" from gencode and + outfile=os.path.join(self.object_dir(cdist_object), + os.path.basename(bin)[3:]) + + outfile_fd = open(outfile, "w") + self.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) + + a = outfile_fd + b = stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR + print(type(a), type(b)) + + os.fchmod(outfile_fd, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + outfile_fd.close() if mode == "code": # paths = self.object_code_paths(cdist_object) From 4e4d648593305836944dfa10811054df7ae7427e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 20:18:30 +0200 Subject: [PATCH 0221/4212] fchmod() does not work on object returned by open(), so use chmod Signed-off-by: Nico Schottelius --- bin/cdist | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index e76ecfc7..09cb9d45 100755 --- a/bin/cdist +++ b/bin/cdist @@ -514,14 +514,10 @@ class Cdist: outfile_fd = open(outfile, "w") self.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) - - a = outfile_fd - b = stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR - print(type(a), type(b)) - - os.fchmod(outfile_fd, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) outfile_fd.close() + os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + if mode == "code": # paths = self.object_code_paths(cdist_object) local_dir = self.object_dir(cdist_object) From 34ae8c292689780db3c18047bcd9d9493cf4f9be Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 20:41:39 +0200 Subject: [PATCH 0222/4212] make code execution happen in the end Signed-off-by: Nico Schottelius --- bin/cdist | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/bin/cdist b/bin/cdist index 09cb9d45..1fd3e116 100755 --- a/bin/cdist +++ b/bin/cdist @@ -516,7 +516,13 @@ class Cdist: self.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) outfile_fd.close() - os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + status = os.stat(outfile) + + # Remove output if empty, else make it executable + if status.st_size == 0: + os.unlink(outfile) + else: + os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) if mode == "code": # paths = self.object_code_paths(cdist_object) @@ -527,9 +533,12 @@ class Cdist: if os.path.isfile(bin): self.run_or_fail([bin], remote=False) - if os.path.isfile(os.path.join(local_dir, "code-remote")): - remote_code = os.path.join(remote_dir, "code-remote") - self.run_or_fail([remote_code], remote=True) + + local_remote_code = os.path.join(local_dir, "code-remote") + remote_remote_code = os.path.join(remote_dir, "code-remote") + if os.path.isfile(local_remote_code): + self.transfer_file(local_remote_code, remote_remote_code) + self.run_or_fail([remote_remote_code], remote=True) def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" From e56bbfea9ac0aba51f28200848d6bfa48ed28b49 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 20:45:54 +0200 Subject: [PATCH 0223/4212] less verbose output in default case Signed-off-by: Nico Schottelius --- bin/cdist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 1fd3e116..4267b3fa 100755 --- a/bin/cdist +++ b/bin/cdist @@ -415,7 +415,7 @@ class Cdist: output_fd.close() def init_deploy(self): - log.info("Creating clean directory structure") + log.debug("Creating clean directory structure") # Ensure there is no old stuff, neither local nor remote # remote_run_or_fail(hostname, ["rm -rf", "${__cdist_remote_base_dir}"]) @@ -542,7 +542,7 @@ class Cdist: def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to host " + self.target_host) + log.info("Deploying to " + self.target_host) self.init_deploy() self.run_global_explores() self.run_initial_manifest() From f9f874deed99b3ed7fe3488dc65d29f67e33e620 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 20:49:46 +0200 Subject: [PATCH 0224/4212] new features in 2.0.0 Signed-off-by: Nico Schottelius --- doc/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 6d25f234..50409cac 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,6 +1,7 @@ -next: +2.0.0: * New Type: __package_rubygem (Chase Allen James) * __self replaced by __object_fq (or so) + * Rewrote cdist in Python 1.7.1: 2011-07-26 * Documentation: Add explorers to reference From eb2512d4a2f176742102e8fd4750ade1e02f215d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 21:15:58 +0200 Subject: [PATCH 0225/4212] add timing information and setup remote = false by default Signed-off-by: Nico Schottelius --- bin/cdist | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 4267b3fa..1e6fc45b 100755 --- a/bin/cdist +++ b/bin/cdist @@ -21,6 +21,7 @@ # import argparse +import datetime import logging import os import subprocess @@ -154,6 +155,7 @@ class Cdist: # and sh -c -e does not exit if /bin/false called args[0][:0] = [ "/bin/sh", "-e" ] + remote = false if "remote" in kargs: if kargs["remote"]: args[0][:0] = self.remote_prefix @@ -543,6 +545,7 @@ class Cdist: def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" log.info("Deploying to " + self.target_host) + time_start = datetime.datetime.now() self.init_deploy() self.run_global_explores() self.run_initial_manifest() @@ -568,7 +571,11 @@ class Cdist: self.object_run(cdist_object, mode="gencode") self.object_run(cdist_object, mode="code") - log.info("Finished run of %s", self.target_host) + time_end = datetime.datetime.now() + duration = time_end - time_start + log.info("Finished run of %s in %s seconds", + self.target_host, + duration.total_seconds()) if __name__ == "__main__": parser = argparse.ArgumentParser(description='cdist ' + VERSION) From be2efbbb0db75fc0a437e4c81b79f355a4ce9b35 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 21:16:42 +0200 Subject: [PATCH 0226/4212] give me a big F Signed-off-by: Nico Schottelius --- bin/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 1e6fc45b..9f713ee3 100755 --- a/bin/cdist +++ b/bin/cdist @@ -155,7 +155,7 @@ class Cdist: # and sh -c -e does not exit if /bin/false called args[0][:0] = [ "/bin/sh", "-e" ] - remote = false + remote = False if "remote" in kargs: if kargs["remote"]: args[0][:0] = self.remote_prefix From b214fe54ddbd141c5d4a18d43c27ff4ea8a073b9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 21:22:51 +0200 Subject: [PATCH 0227/4212] add old benchmarks Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-04-27.benchmark | 56 ++++++++++++++++++++++++++ doc/dev/logs/2011-04-27.benchmark.dash | 9 +++++ 2 files changed, 65 insertions(+) create mode 100644 doc/dev/logs/2011-04-27.benchmark create mode 100644 doc/dev/logs/2011-04-27.benchmark.dash diff --git a/doc/dev/logs/2011-04-27.benchmark b/doc/dev/logs/2011-04-27.benchmark new file mode 100644 index 00000000..6f1f1e21 --- /dev/null +++ b/doc/dev/logs/2011-04-27.benchmark @@ -0,0 +1,56 @@ +% x200 +data = [ 1 104; 2 129; 6 249 ; 25 1267 ] + +% x201, 4.2.2.4 dns, eth +data = [ 1 143; 2 159; 3 198; 4 244; 5 299; 6 350; 7 435; 8 429 ]; + +% x201, von zuhause aus +data2 = [ 226 242 275 296 306 357 403 400 409 685 617 672 ] +plot(0:size(data)(2)-1, data) + + +hold off; +plot(data(:,1), data(:,2)) +% per host time: +data(:,2)' ./ data(:,1)' +hold on; +plot(data(:,1), data(:,2)' ./ data(:,1)') + + +Testing on + Intel(R) Core(TM)2 Duo CPU P8400 @ 2.26GHz + 4 GiB RAM + Intel Gbit Nic + +- 169 objects, all done (i.e. rerun) +- runs are cpu bound + +1 host: + +core: cdist 1.6.2: Successfully finished run +Run: 104s (1 minutes) + +2 hosts: + +[13:48] kr:cdist-nutzung% mytime cdist-mass-deploy -p ikq03.ethz.ch ikq04.ethz.ch +Run: 129s (2 minutes) + +6 hosts: (7 specified, but ikq01.ethz.ch is dead) +cdist-mass-deploy -p ikq01.ethz.ch ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch ikq05.ethz.ch ikq06.ethz.ch ikq07.ethz.ch +Run: 294s (4 minutes) + +25 hosts + +[13:58] kr:cdist-nutzung% mytime cdist-mass-deploy -p $(sed 's/^root@//' ~/.dsh/group/ikr) + +Run: 723s (12 minutes) + + +25 hosts without proxy command now: + +Run: 1267s (21 minutes) +Run: 1212s (20 minutes) + + +[14:11] kr:cdist-nutzung% mytime cdist-mass-deploy -p $(sed 's/^root@//' ~/.dsh/group/ikr) + diff --git a/doc/dev/logs/2011-04-27.benchmark.dash b/doc/dev/logs/2011-04-27.benchmark.dash new file mode 100644 index 00000000..635062e8 --- /dev/null +++ b/doc/dev/logs/2011-04-27.benchmark.dash @@ -0,0 +1,9 @@ +Run: 78s (1 minutes) +[13:25] kr:cdist-nutzung% mytime cdist-deploy-to ikq02.ethz.ch + +% mit dash, eth, x201, Mit Apr 27 13:41:49 CEST 2011 +data = [ 0 73 77 89 107 130 151 180 197 228 251 260 199 295 335 276 ] +plot(0:size(data2)(2)-1, data2) + + + From 5429022d617b9f0a989f2eda454527761b8e6165 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 21:23:10 +0200 Subject: [PATCH 0228/4212] add old debug Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-09-08 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 doc/dev/logs/2011-09-08 diff --git a/doc/dev/logs/2011-09-08 b/doc/dev/logs/2011-09-08 new file mode 100644 index 00000000..42413285 --- /dev/null +++ b/doc/dev/logs/2011-09-08 @@ -0,0 +1,4 @@ +Debugging cdist: + +[0:13] kr:cdist-nutzung% ./local/update-local-core && __cdist_debug=1 __cdist_local_base_dir=/tmp/cdist cdist-deploy-to ikq04.ethz.ch + From c5d88435f13e46a0b8066ce9cf904fafa7696050 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 21:24:23 +0200 Subject: [PATCH 0229/4212] add python link Signed-off-by: Nico Schottelius --- bin/cdist-code-run | 50 ----------------------- bin/cdist-deploy-to | 49 ----------------------- bin/cdist-env | 33 --------------- bin/cdist-explorer-run-global | 43 -------------------- bin/cdist-manifest-run | 56 -------------------------- bin/cdist-manifest-run-init | 34 ---------------- bin/cdist-mass-deploy | 75 ----------------------------------- bin/cdist-object-all | 56 -------------------------- bin/cdist-object-code-run | 38 ------------------ bin/cdist-object-explorer-run | 67 ------------------------------- bin/cdist-object-gencode | 62 ----------------------------- bin/cdist-object-gencode-run | 38 ------------------ bin/cdist-object-manifest-run | 58 --------------------------- bin/cdist-object-prepare | 47 ---------------------- bin/cdist-object-push | 35 ---------------- bin/cdist-object-run | 65 ------------------------------ bin/cdist-remote-explorer-run | 68 ------------------------------- bin/cdist.py | 1 + 18 files changed, 1 insertion(+), 874 deletions(-) delete mode 100755 bin/cdist-code-run delete mode 100755 bin/cdist-deploy-to delete mode 100755 bin/cdist-env delete mode 100755 bin/cdist-explorer-run-global delete mode 100755 bin/cdist-manifest-run delete mode 100755 bin/cdist-manifest-run-init delete mode 100755 bin/cdist-mass-deploy delete mode 100755 bin/cdist-object-all delete mode 100755 bin/cdist-object-code-run delete mode 100755 bin/cdist-object-explorer-run delete mode 100755 bin/cdist-object-gencode delete mode 100755 bin/cdist-object-gencode-run delete mode 100755 bin/cdist-object-manifest-run delete mode 100755 bin/cdist-object-prepare delete mode 100755 bin/cdist-object-push delete mode 100755 bin/cdist-object-run delete mode 100755 bin/cdist-remote-explorer-run create mode 120000 bin/cdist.py diff --git a/bin/cdist-code-run b/bin/cdist-code-run deleted file mode 100755 index 3d7499bf..00000000 --- a/bin/cdist-code-run +++ /dev/null @@ -1,50 +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 . -# -# -# This binary is executed on the remote side to execute code -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -ue - -__cdist_object_self="$1"; shift -__cdist_code_type="$1"; shift - -if [ ! -d "$(__cdist_object_dir "$__cdist_object_self")" ]; then - __cdist_exit_err "Object undefined" -fi - -__cdist_code="$(__cdist_object_code "$__cdist_object_self" "${__cdist_code_type}")" - -__cdist_echo info "Checking code-${__cdist_code_type}" - -if [ -e "$__cdist_code" ]; then - if [ -f "$__cdist_code" ]; then - if [ -x "$__cdist_code" ]; then - __cdist_echo info "Executing code-${__cdist_code_type}" - __cdist_exec_fail_on_error "$__cdist_code" - else - __cdist_exit_err "$__cdist_code exists, but is not executable." - fi - else - __cdist_exit_err "$__cdist_code exists, but is not a file." - fi -fi diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to deleted file mode 100755 index 86e15800..00000000 --- a/bin/cdist-deploy-to +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Deploy configuration to a host -# - -. cdist-config -[ $# -eq 1 ] || __cdist_usage "" -set -eu - -# Kill children on interrupt - only in interactive scripts -trap __cdist_kill_on_interrupt INT TERM - -__cdist_target_host="$1" - -# Make target host available for non-core -export $__cdist_name_var_target_host="$__cdist_target_host" -export $__cdist_name_var_target_user="$__cdist_remote_user" - -# Export variables for core, which others do not reset -export __cdist_local_base_dir - -__cdist_echo info "cdist $__cdist_version: Configuring $__cdist_target_host " - -################################################################################ -# See cdist-stages(7) -# - -cdist-object-all "$__cdist_target_host" cdist-object-run -cdist-cache "$__cdist_target_host" - -__cdist_echo info "cdist $__cdist_version: Successfully finished run" diff --git a/bin/cdist-env b/bin/cdist-env deleted file mode 100755 index 2aac5e6b..00000000 --- a/bin/cdist-env +++ /dev/null @@ -1,33 +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 . -# -# -# Setup environment for use with cdist - must be standalone! -# - -export PATH="$(cd "${0%/*}" && pwd -P):$PATH" -export MANPATH="$(cd "${0%/*}/../doc/man" && pwd -P):$MANPATH" - -if [ "$(echo ${SHELL##*/} | grep 'csh$')" ]; then - echo setenv PATH $PATH \; - echo setenv MANPATH $MANPATH -else - echo export PATH=$PATH - echo export MANPATH=$MANPATH -fi diff --git a/bin/cdist-explorer-run-global b/bin/cdist-explorer-run-global deleted file mode 100755 index b0c024f2..00000000 --- a/bin/cdist-explorer-run-global +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Copy & run the global explorers, i.e. not bound to types -# - -. cdist-config -[ $# -eq 1 ] || __cdist_usage "" -set -ue - -__cdist_target_host="$1"; shift - -__cdist_echo info "Running global explorers " - -# copy the explorers -cdist-dir push "$__cdist_target_host" \ - "${__cdist_explorer_dir}" "${__cdist_remote_explorer_dir}" - -# run the initial explorers remotely -cdist-run-remote "${__cdist_target_host}" cdist-remote-explorer-run \ - "$__cdist_name_var_explorer" "$__cdist_remote_explorer_dir" \ - "$__cdist_remote_out_explorer_dir" - -# retrieve the results -cdist-dir pull "$__cdist_target_host" \ - "${__cdist_remote_out_explorer_dir}" "${__cdist_out_explorer_dir}" diff --git a/bin/cdist-manifest-run b/bin/cdist-manifest-run deleted file mode 100755 index d4ea18bb..00000000 --- a/bin/cdist-manifest-run +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh -# -# 2010 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's build a cconfig tree from a configuration -# And save it into the cache tree -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -u - -__cdist_target_host="$1"; shift -__cdist_manifest="$1"; shift - -################################################################################ -# Export information for cdist-type-emulator or manifest -# - -# Config dir should not get reset - FIXME: why did I do this? -export __cdist_conf_dir - -# Used to record the source in the object -export __cdist_manifest - -# Export information for manifests - __cdist_out_dir comes from cdist-config -export __global="$__cdist_out_dir" - -################################################################################ -# The actual run -# - -# Ensure binaries exist and are up-to-date -cdist-type-build-emulation "${__cdist_out_type_bin_dir}" \ - || __cdist_exit_err "Failed to build type emulation binaries" - -# prepend our path, so all cdist tools come before other tools -export PATH="${__cdist_out_type_bin_dir}:$PATH" - -__cdist_exec_fail_on_error "${__cdist_manifest}" diff --git a/bin/cdist-manifest-run-init b/bin/cdist-manifest-run-init deleted file mode 100755 index 28acc623..00000000 --- a/bin/cdist-manifest-run-init +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Let's build a cconfig tree from a configuration -# And save it into the cache tree -# - -. cdist-config -[ $# -eq 1 ] || __cdist_usage "" -set -e - -__cdist_target_host="$1"; shift - -eval export $__cdist_name_var_manifest=\"\$__cdist_manifest_dir\" - -__cdist_echo info "Running initial manifest for $__cdist_target_host " -cdist-manifest-run "$__cdist_target_host" "$__cdist_manifest_init" diff --git a/bin/cdist-mass-deploy b/bin/cdist-mass-deploy deleted file mode 100755 index c2b6d6a5..00000000 --- a/bin/cdist-mass-deploy +++ /dev/null @@ -1,75 +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 . -# -# -# Deploy configuration to many hosts -# - -. cdist-config -[ $# -ge 1 ] || __cdist_usage "[-p] [target host ]" -set -u - -# Kill children on interrupt - only in interactive scripts -trap __cdist_kill_on_interrupt INT TERM - -filter() -{ - awk -v host=$1 '{ print "[" host "] " $0 }' -} - -parallel="" -if [ "$1" = "-p" ]; then - parallel=yes - shift -fi - -i=0 -while [ $# -gt 0 ]; do - if [ "$parallel" ]; then - cdist-deploy-to "$1" 2>&1 | filter "$1" & - # Record pid and host for use later - i=$((i+1)) - eval pid_$i=$! - eval host_$i=\$1 - else - cdist-deploy-to "$1" 2>&1 | filter "$1" - fi - shift -done - -e=0 -if [ "$parallel" ]; then - __cdist_echo info "Waiting for cdist-deploy-to jobs to finish" - while [ "$i" -gt 0 ]; do - eval pid=\$pid_$i - wait "$pid" - if [ $? -ne 0 ]; then - e=$((e+1)) - eval e_host_$e=\$host_$i - fi - i=$((i-1)) - done -fi - -# Display all failed hosts after all runs are done, so the sysadmin gets them -while [ "$e" -gt 0 ]; do - eval host=\$host_$e - __cdist_echo error "Configuration of host $host failed." - e=$((e-1)) -done diff --git a/bin/cdist-object-all b/bin/cdist-object-all deleted file mode 100755 index 391c9cc7..00000000 --- a/bin/cdist-object-all +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh -# -# 2011 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# Run the given command for each created object. -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu - -__cdist_target_host="$1"; shift -__cdist_command="$1"; shift - -__cdist_objects="$__cdist_tmp_dir/objects" - -# Ensure object dir exists, so marker can be created -mkdir -p "${__cdist_out_object_dir}" - -# Loop until we do not create new objects anymore -# which is equal to all objects have been run -touch "$__cdist_objects_created" -while [ -f "$__cdist_objects_created" ]; do - # Assume we're done after this run - rm "$__cdist_objects_created" - - # Get listing of objects - __cdist_object_list "$__cdist_out_object_dir" > "$__cdist_objects" - - # NEED TO CREATE ARRAY, SSH DESTROYS WHILE READ LOOP - while read __cdist_object; do - set -- "$@" "$__cdist_object" - done < "$__cdist_objects" - - while [ $# -gt 0 ]; do - __cdist_object="$1"; shift - $__cdist_command "$__cdist_target_host" "$__cdist_object" - done -done diff --git a/bin/cdist-object-code-run b/bin/cdist-object-code-run deleted file mode 100755 index fa63aaba..00000000 --- a/bin/cdist-object-code-run +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# Exec the code for the given object locally and remote -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -e - -__cdist_target_host="$1"; shift -__cdist_object="$1"; shift - -# Code local -export __cdist_out_object_dir="$__cdist_out_object_dir" -cdist-code-run "$__cdist_object" "${__cdist_name_gencode_local}" - -# Code remote -cdist-run-remote "$__cdist_target_host" \ - "cdist-code-run" "$__cdist_object" "${__cdist_name_gencode_remote}" diff --git a/bin/cdist-object-explorer-run b/bin/cdist-object-explorer-run deleted file mode 100755 index b65c5cc1..00000000 --- a/bin/cdist-object-explorer-run +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# Run the explorers for the given object on the target host. -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu - -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift - -__cdist_object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" -__cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" - -# Check if type of object has >= 1 explorer -__cdist_has_explorer="$(__cdist_type_has_explorer "$__cdist_type")" -# Run the type explorers for the current object if any -if [ "$__cdist_has_explorer" ]; then - if ! __cdist_type_explorer_pushed "$__cdist_type"; then - src_dir="$(__cdist_type_explorer_dir "$__cdist_type")" - dst_dir="$(__cdist_remote_type_explorer_dir "$__cdist_type")" - __cdist_echo info "Transfering explorers for $__cdist_type " - cdist-dir push "$__cdist_target_host" "$src_dir" "$dst_dir" - __cdist_type_explorer_pushed_add "$__cdist_type" - fi - - __cdist_echo info "Running explorers" - # Copy object parameters - cdist-dir push "$__cdist_target_host" \ - "$(__cdist_object_parameter_dir "$__cdist_object_self")" \ - "$(__cdist_remote_object_parameter_dir "$__cdist_object_self")" - - # Execute explorers - cdist-run-remote "$__cdist_target_host" \ - "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" \ - "$__cdist_name_var_object_id=\"$__cdist_object_id\"" \ - "$__cdist_name_var_self=\"$__cdist_object_self\"" \ - cdist-remote-explorer-run \ - "$__cdist_name_var_type_explorer" \ - "$(__cdist_remote_type_explorer_dir "$__cdist_type")" \ - "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" - - # Copy back results - cdist-dir pull "$__cdist_target_host" \ - "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" \ - "$(__cdist_object_type_explorer_dir "$__cdist_object_self")" -fi diff --git a/bin/cdist-object-gencode b/bin/cdist-object-gencode deleted file mode 100755 index e21568a3..00000000 --- a/bin/cdist-object-gencode +++ /dev/null @@ -1,62 +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 . -# -# -# Generate code from one object (object must be relative path!) -# WARNING: OUTPUT ON STDOUT, ERRORS NEED TO BE ON STDERR! -# - -. cdist-config -[ $# -eq 3 ] || __cdist_usage "" "" "" -set -eu - -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift -__cdist_gencode_type="$1"; shift - -__cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" -__cdist_type_gencode="$(__cdist_type_gencode "$__cdist_type" "$__cdist_gencode_type")" -__cdist_code_output="$(__cdist_object_code "$__cdist_object_self" "$__cdist_gencode_type")" - -# export variables for the gencode script -export __object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" -export __object="$(__cdist_object_dir "$__cdist_object_self")" -export __global="$__cdist_out_dir" - -if [ -x "$__cdist_type_gencode" ]; then - __cdist_exec_fail_on_error "$__cdist_type_gencode" > "$__cdist_tmp_file" -else - if [ -e "$__cdist_type_gencode" ]; then - __cdist_exit_err "$__cdist_type_gencode exists, but is not executable" - fi - - # Ensure it's empty, if there is no gencode - : > "$__cdist_tmp_file" -fi - -# Only create code, if gencode created output -if [ "$(wc -l < "$__cdist_tmp_file")" -gt 0 ]; then - cat - "$__cdist_tmp_file" << eof > "$__cdist_code_output" -# -# The following code was generated by $__cdist_type_gencode -# - -eof - chmod u+x "${__cdist_code_output}" -fi diff --git a/bin/cdist-object-gencode-run b/bin/cdist-object-gencode-run deleted file mode 100755 index 254ac1e4..00000000 --- a/bin/cdist-object-gencode-run +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# -# 2010 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# For the given object create the code to be executed on the target. -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu - -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift - -__cdist_echo info "Generating local code " -cdist-object-gencode "$__cdist_target_host" "$__cdist_object_self" \ - "${__cdist_name_gencode_local}" - -__cdist_echo info "Generating remote code " -cdist-object-gencode "$__cdist_target_host" "$__cdist_object_self" \ - "${__cdist_name_gencode_remote}" diff --git a/bin/cdist-object-manifest-run b/bin/cdist-object-manifest-run deleted file mode 100755 index 34d4f867..00000000 --- a/bin/cdist-object-manifest-run +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/sh -# -# 2010 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# Run the manifest for the given object. -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu - -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift - -# FIXME: rename to __cdist_object_dir (everywhere!) -__cdist_cur_object_dir="$(__cdist_object_dir "$__cdist_object_self")" -__cdist_object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" - -__cdist_echo info "Checking manifest " - -__cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" -__cdist_manifest="$(__cdist_type_manifest "$__cdist_type")" - -if [ -f "$__cdist_manifest" ]; then - if [ -x "$__cdist_manifest" ]; then - # Make __cdist_manifest available for cdist-type-emulator - export __cdist_manifest - - __cdist_echo info "Executing manifest " - export $__cdist_name_var_object="$__cdist_cur_object_dir" - export $__cdist_name_var_object_id="$__cdist_object_id" - export $__cdist_name_var_type="$(__cdist_type_dir "$__cdist_type")" - - cdist-manifest-run "$__cdist_target_host" "$__cdist_manifest" - - # Tell cdist-object-run-all that there may be new objects - touch "$__cdist_objects_created" - else - __cdist_exit_err "${__cdist_manifest} needs to be executable." - fi -fi diff --git a/bin/cdist-object-prepare b/bin/cdist-object-prepare deleted file mode 100755 index d21d8a63..00000000 --- a/bin/cdist-object-prepare +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh -# -# 2011 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# For the given object: -# - run type explorers -# - run type manifest -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu - -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift -__cdist_object_dir="$(__cdist_object_dir "$__cdist_object_self")" -[ -d "$__cdist_object_dir" ] || __cdist_exit_err "Object undefined" - -# Export to non-core for use in manifest and gencode scripts -export $__cdist_name_var_self=$__cdist_object_self - -__cdist_object_prepared="$(__cdist_object_prepared "$__cdist_object_self")" -if [ ! -f "$__cdist_object_prepared" ]; then - __cdist_echo info "Preparing object" - cdist-object-explorer-run "$__cdist_target_host" "$__cdist_object_self" - cdist-object-manifest-run "$__cdist_target_host" "$__cdist_object_self" - - # Mark this object as prepared - touch "$__cdist_object_prepared" -fi diff --git a/bin/cdist-object-push b/bin/cdist-object-push deleted file mode 100755 index 62b00cb2..00000000 --- a/bin/cdist-object-push +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh -# -# 2010 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# Transfer the given object to the target host. -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu - -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift - -__cdist_echo info "Transferring object" -cdist-dir push "$__cdist_target_host" \ - "$(__cdist_object_dir "$__cdist_object_self")" \ - "$(__cdist_remote_object_dir "$__cdist_object_self")" diff --git a/bin/cdist-object-run b/bin/cdist-object-run deleted file mode 100755 index 4f40e7c1..00000000 --- a/bin/cdist-object-run +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/sh -# -# 2011 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# For the given object: -# - run type explorers -# - run type manifest -# - generate code -# - copy object to target -# - execute code on target -# - -. cdist-config -[ $# -eq 2 ] || __cdist_usage " " -set -eu - -__cdist_target_host="$1"; shift -__cdist_object_self="$1"; shift -__cdist_object_dir="$(__cdist_object_dir "$__cdist_object_self")" -[ -d "$__cdist_object_dir" ] || __cdist_exit_err "Object undefined" - -# Export to non-core for use in manifest and gencode scripts -export $__cdist_name_var_self=$__cdist_object_self - -__cdist_object_finished="$(__cdist_object_finished "$__cdist_object_self")" -if [ ! -f "$__cdist_object_finished" ]; then - # Resolve dependencies, if any - __cdist_object_require="$(__cdist_object_require "$__cdist_object_self")" - if [ -f "$__cdist_object_require" ]; then - # NEED TO CREATE ARRAY, SSH DESTROYS WHILE READ LOOP - while read __cdist_requirement; do - set -- "$@" "$__cdist_requirement" - done < "$__cdist_object_require" - - while [ $# -gt 0 ]; do - __cdist_requirement="$1"; shift - __cdist_echo info "Resolving requirement $__cdist_requirement" - cdist-object-run "$__cdist_target_host" "$__cdist_requirement" - done - fi - - cdist-object-gencode-run "$__cdist_target_host" "$__cdist_object_self" - cdist-object-push "$__cdist_target_host" "$__cdist_object_self" - cdist-object-code-run "$__cdist_target_host" "$__cdist_object_self" - - # Mark this object as done - touch "$__cdist_object_finished" -fi diff --git a/bin/cdist-remote-explorer-run b/bin/cdist-remote-explorer-run deleted file mode 100755 index d95913ba..00000000 --- a/bin/cdist-remote-explorer-run +++ /dev/null @@ -1,68 +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 . -# -# -# This binary is executed on the remote side to execute explorers -# -# It supports different variables names to be used, so __explorers -# and __type_explorers can be submitted :-) -# - -. cdist-config -[ $# -eq 3 ] || __cdist_usage " " -set -ue - -# Variable that defines the home of the explorers -__cdist_variable_name="$1"; shift - -# Find explorers here -__cdist_explorer_dir="$1"; shift - -# Write output here -__cdist_my_out_dir="$1"; shift - -# Setup environment -export $__cdist_variable_name="$__cdist_explorer_dir" -export __global="$__cdist_remote_out_dir" - -mkdir -p "$__cdist_my_out_dir" - -# Ensure there is at least one explorer -num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" -if [ "$num" -lt 1 ]; then - __cdist_exit_err "${__cdist_explorer_dir}: Contains no explorers" -fi - -# Execute all explorers -for explorer in "$__cdist_explorer_dir/"*; do - explorer_name="${explorer##*/}" - - if [ -f "$explorer" ]; then - if [ ! -x "$explorer" ]; then - __cdist_exit_err "Explorer \"$explorer\" exists, but is not executable." - fi - - # Execute explorers and save results in remote destination directory - "$explorer" > "${__cdist_my_out_dir}/$explorer_name" - else - if [ -e "$explorer" ]; then - __cdist_exit_err "Explorer \"$explorer\" exists, but is not a file." - fi - fi -done diff --git a/bin/cdist.py b/bin/cdist.py new file mode 120000 index 00000000..9a039b33 --- /dev/null +++ b/bin/cdist.py @@ -0,0 +1 @@ +cdist \ No newline at end of file From 264a76ca2f0eb41c234be3882287c5c7676b20f6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 21:29:05 +0200 Subject: [PATCH 0230/4212] more stuff to ignore Signed-off-by: Nico Schottelius --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 10d98990..d606aec7 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ doc/man/man*/docbook-xsl.css # Ignore cache for version control cache/ + +# Python +bin/__pycache__/ From c0ab4cdd8de653e36ff8c77dd1eb072325435382 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 21:34:24 +0200 Subject: [PATCH 0231/4212] remove now obsolete core directory Signed-off-by: Nico Schottelius --- core/__cdist_cache | 34 ------------ core/__cdist_dir | 46 ---------------- core/__cdist_dir_listing | 30 ----------- core/__cdist_echo | 56 ------------------- core/__cdist_exit_err | 28 ---------- core/__cdist_explorer_run | 79 --------------------------- core/__cdist_explorer_run_global | 32 ----------- core/__cdist_is_executable | 44 --------------- core/__cdist_kill_on_interrupt | 31 ----------- core/__cdist_manifest_run | 53 ------------------ core/__cdist_manifest_run_init | 32 ----------- core/__cdist_object_all | 60 --------------------- core/__cdist_object_code_run | 54 ------------------- core/__cdist_object_explorer_run | 89 ------------------------------- core/__cdist_object_gencode | 66 ----------------------- core/__cdist_object_gencode_run | 36 ------------- core/__cdist_object_list | 36 ------------- core/__cdist_object_manifest_run | 59 -------------------- core/__cdist_object_prepare | 47 ---------------- core/__cdist_object_run | 74 ------------------------- core/__cdist_run | 27 ---------- core/__cdist_run_remote | 32 ----------- core/__cdist_run_shell | 34 ------------ core/__cdist_tmp_removal | 27 ---------- core/__cdist_type_build_emulation | 49 ----------------- core/__cdist_usage | 27 ---------- 26 files changed, 1182 deletions(-) delete mode 100755 core/__cdist_cache delete mode 100755 core/__cdist_dir delete mode 100755 core/__cdist_dir_listing delete mode 100755 core/__cdist_echo delete mode 100755 core/__cdist_exit_err delete mode 100755 core/__cdist_explorer_run delete mode 100755 core/__cdist_explorer_run_global delete mode 100755 core/__cdist_is_executable delete mode 100644 core/__cdist_kill_on_interrupt delete mode 100755 core/__cdist_manifest_run delete mode 100755 core/__cdist_manifest_run_init delete mode 100755 core/__cdist_object_all delete mode 100755 core/__cdist_object_code_run delete mode 100755 core/__cdist_object_explorer_run delete mode 100755 core/__cdist_object_gencode delete mode 100755 core/__cdist_object_gencode_run delete mode 100755 core/__cdist_object_list delete mode 100755 core/__cdist_object_manifest_run delete mode 100755 core/__cdist_object_prepare delete mode 100755 core/__cdist_object_run delete mode 100755 core/__cdist_run delete mode 100755 core/__cdist_run_remote delete mode 100755 core/__cdist_run_shell delete mode 100755 core/__cdist_tmp_removal delete mode 100755 core/__cdist_type_build_emulation delete mode 100755 core/__cdist_usage diff --git a/core/__cdist_cache b/core/__cdist_cache deleted file mode 100755 index 95764d3d..00000000 --- a/core/__cdist_cache +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# 2010 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 . -# -# -# Save the configuration tree into the local cache -# - -__cdist_cache() -{ - # Create base to move into - mkdir -p "${__cdist_local_base_cache_dir}" - - __cdist_echo info \ - "Caching to $(__cdist_host_cache_dir "$__cdist_target_host")" - rm -rf "$(__cdist_host_cache_dir "$__cdist_target_host")" - mv "$__cdist_local_base_dir" \ - "$(__cdist_host_cache_dir "$__cdist_target_host")" -} diff --git a/core/__cdist_dir b/core/__cdist_dir deleted file mode 100755 index 32ee0075..00000000 --- a/core/__cdist_dir +++ /dev/null @@ -1,46 +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 . -# -# -# 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) -# - -__cdist_dir() -{ - [ $# -eq 3 ] || __cdist_usage " " - - # ${3%/*} will be the destination directory, so no subdirectories - # of the same name are created, if the directory is already existing - - if [ "$1" = "push" ]; then - # FIXME: add error handling with __cdist_run_remote_... or so - ssh "${__cdist_remote_user}@${__cdist_target_host}" \ - "mkdir -p \"$3\"" - scp -qr "$2" \ - "${__cdist_remote_user}@${__cdist_target_host}:${3%/*}" - elif [ "$1" = "pull" ]; then - mkdir -p "$3" - scp -qr "${__cdist_remote_user}@${__cdist_target_host}:$2" \ - "${3%/*}" - else - __cdist_exit_err "Unknown action $1" - fi -} diff --git a/core/__cdist_dir_listing b/core/__cdist_dir_listing deleted file mode 100755 index f4aa2320..00000000 --- a/core/__cdist_dir_listing +++ /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 . -# -# -# List files in a directory, if it exists -# -# We only create output, if there's at least one entry -# and can thus be used as a boolean ;-) -# - -__cdist_dir_listing() -{ - [ -d "$1" ] && ls -1 "$1" -} diff --git a/core/__cdist_echo b/core/__cdist_echo deleted file mode 100755 index a89d1821..00000000 --- a/core/__cdist_echo +++ /dev/null @@ -1,56 +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 . -# -# -# echo / syslog alike function -# - -__cdist_echo() -{ - __cdist_echo_type="$1"; shift - - set +u - if [ "$__cdist_object_self" ]; then - __cdist_echo_prefix="${__cdist_object_self}:" - else - __cdist_echo_prefix="core: " - fi - set -u - - case "$__cdist_echo_type" in - debug) - if [ "$__cdist_debug" = 1 ]; then - echo $__cdist_echo_prefix "DEBUG: $@" - fi - ;; - info) - echo $__cdist_echo_prefix "$@" - ;; - warn) - echo $__cdist_echo_prefix "Warning: $@" - ;; - error) - echo $__cdist_echo_prefix "Error: $@" >&2 - ;; - *) - echo "CORE BUG, who created the broken commit in $0?" >&2 - exit 23 - ;; - esac -} diff --git a/core/__cdist_exit_err b/core/__cdist_exit_err deleted file mode 100755 index 303dbf20..00000000 --- a/core/__cdist_exit_err +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# 2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Print error and exit (perror() alike) -# - -__cdist_exit_err() -{ - __cdist_echo error "$@" - exit 1 -} diff --git a/core/__cdist_explorer_run b/core/__cdist_explorer_run deleted file mode 100755 index 9e58fa09..00000000 --- a/core/__cdist_explorer_run +++ /dev/null @@ -1,79 +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 . -# -# -# Run explorers - FIXME: this function is ugly -# - -__cdist_explorer_run() -{ - [ $# -eq 5 ] || __cdist_usage " " - - # Ensure there is at least one explorer - num="$(ls -1 "$__cdist_explorer_dir" | wc -l)" - if [ "$num" -lt 1 ]; then - __cdist_exit_err "${__cdist_explorer_dir}: Contains no explorers" - fi - - # Check whether to setup variable for type explorer - case "$1" in - global) - ;; - type) - # FIXME: think about how and where this gets setup! - "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" - ;; - esac - - # Transfer explorers - __cdist_dir push "$2" "$3" - - # Create output directory - __cdist_run_remote mkdir -p "$4" - - # Execute all explorers - FIXME: isolate cd call? - cd "$2"; - # FIXME: cleanup double variable, no need when in directory - for __cdist_explorer_run_explorer in *; do - __cdist_explorer_explorer_name="${__cdist_explorer_run_explorer##*/}" - - if [ -f "$__cdist_explorer_run_explorer" ]; then - if [ ! -x "$__cdist_explorer_run_explorer" ]; then - __cdist_exit_err "Explorer \"$__cdist_explorer_run_explorer\" exists, but is not executable." - fi - - else - if [ -e "$__cdist_explorer_run_explorer" ]; then - __cdist_exit_err "Explorer \"$__cdist_explorer_run_explorer\" exists, but is not a file." - fi - fi - - # FIXME: no need for remote out dir probably? - # or should we leave it and continue using __cdist_dir pull? - __cdist_run_remote \ - "export $__cdist_name_var_explorer=\"$__cdist_remote_explorer_dir\";" \ - "export $__cdist_name_var_global=\"$__cdist_remote_out_dir\";" \ - "$3/$__cdist_explorer_run_explorer" ">" \ - "$4/$__cdist_explorer_run_explorer" || \ - __cdist_exit_err "Explorer $__cdist_explorer_run_explorer failed." - done - - # Transfer results back - __cdist_dir pull "$4" "$5" -} diff --git a/core/__cdist_explorer_run_global b/core/__cdist_explorer_run_global deleted file mode 100755 index 27359713..00000000 --- a/core/__cdist_explorer_run_global +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Copy & run the global explorers, i.e. not bound to types -# - -__cdist_explorer_run_global() -{ - __cdist_echo info "Running global explorers " - - # run the global explorers remotely - __cdist_explorer_run global \ - "$__cdist_explorer_dir" "$__cdist_remote_explorer_dir" \ - "$__cdist_remote_out_explorer_dir" "$__cdist_out_explorer_dir" -} diff --git a/core/__cdist_is_executable b/core/__cdist_is_executable deleted file mode 100755 index a7a6d174..00000000 --- a/core/__cdist_is_executable +++ /dev/null @@ -1,44 +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 . -# -# -# Test whether something is executable (that should be executable) or -# is missing -# - -__cdist_is_executable() -{ - [ $# -eq 1 ] || __cdist_exit_err "" - - if [ -e "$1" ]; then - if [ -f "$1" ]; then - if [ -x "$1" ]; then - # Exists and is a correct executable - true - else - __cdist_exit_err "$1 exists, but is not executable." - fi - else - __cdist_exit_err "$1 exists, but is not a file." - fi - else - # Does not exist - false - fi -} diff --git a/core/__cdist_kill_on_interrupt b/core/__cdist_kill_on_interrupt deleted file mode 100644 index 7cb711fa..00000000 --- a/core/__cdist_kill_on_interrupt +++ /dev/null @@ -1,31 +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 . -# -# -# Run the given command for each created object. -# - -# Does not work in children, will be called again in every script! -# Use only in interactive "front end" scripts -__cdist_kill_on_interrupt() -{ - __cdist_tmp_removal - kill 0 - exit 1 -} diff --git a/core/__cdist_manifest_run b/core/__cdist_manifest_run deleted file mode 100755 index cf85d646..00000000 --- a/core/__cdist_manifest_run +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Let's build a cconfig tree from a configuration -# And save it into the cache tree -# - -__cdist_manifest_run() -{ - [ $# -eq 1 ] || __cdist_usage "" - - __cdist_manifest="$1"; shift - - ################################################################################ - # Export information for cdist-type-emulator or manifest - # - - # Config dir should not get reset - FIXME: why did I do this? - export __cdist_conf_dir - - # Used to record the source in the object - export __cdist_manifest - - # Export information for manifests - __cdist_out_dir comes from cdist-config - export $__cdist_name_var_global="$__cdist_out_dir" - - ################################################################################ - # The actual run - # - - # Ensure binaries are existing - FIXME: move error handling into __cdist_type_build_emulation - __cdist_type_build_emulation \ - || __cdist_exit_err "Failed to build type emulation binaries" - - __cdist_run_shell "${__cdist_manifest}" -} diff --git a/core/__cdist_manifest_run_init b/core/__cdist_manifest_run_init deleted file mode 100755 index e8fa63de..00000000 --- a/core/__cdist_manifest_run_init +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Let's build a cconfig tree from a configuration -# And save it into the cache tree -# - -__cdist_manifest_run_init() -{ - # FIXME: probably do not export but always set explicitly? - export $__cdist_name_var_manifest="$__cdist_manifest_dir" - - __cdist_echo info "Running initial manifest for $__cdist_target_host " - __cdist_manifest_run "$__cdist_manifest_init" -} diff --git a/core/__cdist_object_all b/core/__cdist_object_all deleted file mode 100755 index 965d08f6..00000000 --- a/core/__cdist_object_all +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh -# -# 2011 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# Run the given command for each created object. -# - -__cdist_object_all() -{ - [ $# -eq 1 ] || __cdist_usage "" - - __cdist_object_all_object_all_command="$1"; shift - - __cdist_object_all_object_all_objects="$__cdist_tmp_dir/objects" - - # Ensure object dir exists, so marker can be created - mkdir -p "${__cdist_out_object_dir}" - - # FIXME: : - why do we use a file? - # core/__cdist_object_manifest_run: touch "$__cdist_objects_created" - - # Loop until we do not create new objects anymore - # which is equal to all objects have been run - touch "$__cdist_objects_created" - while [ -f "$__cdist_objects_created" ]; do - # Assume we're done after this run - rm "$__cdist_objects_created" - - # Get listing of objects - __cdist_object_list "$__cdist_out_object_dir" > \ - "$__cdist_object_all_object_all_objects" - - # NEED TO CREATE ARRAY, SSH DESTROYS WHILE READ LOOP - while read __cdist_object_all_object; do - set -- "$@" "$__cdist_object_all_object" - done < "$__cdist_object_all_object_all_objects" - - while [ $# -gt 0 ]; do - __cdist_object_all_object="$1"; shift - $__cdist_object_all_object_all_command "$__cdist_object_all_object" - done - done -} diff --git a/core/__cdist_object_code_run b/core/__cdist_object_code_run deleted file mode 100755 index 8af67ab8..00000000 --- a/core/__cdist_object_code_run +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# Exec the code for the given object locally and remote -# - -__cdist_object_code_run() -{ - [ $# -eq 1 ] || __cdist_exit_err "" - - - if [ ! -d "$(__cdist_object_dir "$1")" ]; then - __cdist_exit_err "Object undefined" - fi - - # Code local - export __cdist_out_object_dir="$__cdist_out_object_dir" - __cdist_echo debug "Trying to run local code" - if __cdist_is_executable \ - "$(__cdist_object_code "$1" "${__cdist_name_gencode_local}")"; then - __cdist_run_shell \ - "$(__cdist_object_code "$1" "${__cdist_name_gencode_local}")" - else - __cdist_echo debug "Local code: none" - fi - - # Code remote - __cdist_echo debug "Trying to run remote code" - if __cdist_is_executable \ - "$(__cdist_object_code "$1" "${__cdist_name_gencode_remote}")"; then - - __cdist_run_remote $(__cdist_remote_object_code "$1") - else - __cdist_echo debug "Remote code: none" - fi -} diff --git a/core/__cdist_object_explorer_run b/core/__cdist_object_explorer_run deleted file mode 100755 index da59d6c3..00000000 --- a/core/__cdist_object_explorer_run +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# Run the explorers for the given object on the target host. -# - -# FIXME: many cleanups needed before going production! - -__cdist_object_explorer_run() -{ - __cdist_object_self="$1"; shift - - __cdist_object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" - __cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" - - # Check if type of object has >= 1 explorer - __cdist_has_explorer="$(__cdist_dir_listing "$(__cdist_type_explorer_dir "$__cdist_type")" | wc -l)" - # Run the type explorers for the current object if any - if [ "$__cdist_has_explorer" -ge 1 ]; then - if ! __cdist_type_explorer_pushed "$__cdist_type"; then - # FIXME: variables! - src_dir="$(__cdist_type_explorer_dir "$__cdist_type")" - dst_dir="$(__cdist_remote_type_explorer_dir "$__cdist_type")" - __cdist_echo info "Transfering explorers for $__cdist_type " - __cdist_dir push "$src_dir" "$dst_dir" - __cdist_type_explorer_pushed_add "$__cdist_type" - fi - - __cdist_echo info "Running explorers" - # Copy object parameters - __cdist_dir push \ - "$(__cdist_object_parameter_dir "$__cdist_object_self")" \ - "$(__cdist_remote_object_parameter_dir "$__cdist_object_self")" - - # Execute explorers - # FIXME: STOPPED: - # - remove cdist-remote-explorer-run - # - problem: new variables / need to run explorer directly? - # -> or put logic into __cdist_explorer_run - # -> think about having _one_ wrapper script for remote to execute - # shell functions - - # Create remote output directory - __cdist_run_remote mkdir -p "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" - - cd "$(__cdist_type_explorer_dir "$__cdist_type")" - - - for __cdist_object_explorer_run_explorer in *; do - __cdist_run_remote \ - "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" \ - "$__cdist_name_var_object_id=\"$__cdist_object_id\"" \ - "$__cdist_name_var_self=\"$__cdist_object_self\"" \ - "$(__cdist_remote_type_explorer_dir "$__cdist_type")/$__cdist_object_explorer_run_explorer" \ - ">" "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")/$__cdist_object_explorer_run_explorer" - done - -# __cdist_run_remote \ -# "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\"" \ -# "$__cdist_name_var_object_id=\"$__cdist_object_id\"" \ -# "$__cdist_name_var_self=\"$__cdist_object_self\"" \ -# cdist-remote-explorer-run \ -# "$__cdist_name_var_type_explorer" \ -# "$(__cdist_remote_type_explorer_dir "$__cdist_type")" \ -# "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" - - # Copy back results - __cdist_dir pull "$(__cdist_remote_object_type_explorer_dir "$__cdist_object_self")" \ - "$(__cdist_object_type_explorer_dir "$__cdist_object_self")" - fi -} diff --git a/core/__cdist_object_gencode b/core/__cdist_object_gencode deleted file mode 100755 index 08ef8b7d..00000000 --- a/core/__cdist_object_gencode +++ /dev/null @@ -1,66 +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 . -# -# -# Generate code from one object (object must be relative path!) -# WARNING: OUTPUT ON STDOUT, ERRORS NEED TO BE ON STDERR! -# - -# FIXME: check variable names: -# either prefix or use global or use functions directly -# functions looks good, they are cheap anyway! - -__cdist_object_gencode() -{ - [ $# -eq 2 ] || __cdist_usage "" "" - - __cdist_object_self="$1"; shift - __cdist_gencode_type="$1"; shift - - __cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" - __cdist_type_gencode="$(__cdist_type_gencode "$__cdist_type" "$__cdist_gencode_type")" - __cdist_code_output="$(__cdist_object_code "$__cdist_object_self" "$__cdist_gencode_type")" - - # export variables for the gencode script - export __object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" - export __object="$(__cdist_object_dir "$__cdist_object_self")" - export __global="$__cdist_out_dir" - - if [ -x "$__cdist_type_gencode" ]; then - __cdist_run_shell "$__cdist_type_gencode" > "$__cdist_tmp_file" - else - if [ -e "$__cdist_type_gencode" ]; then - __cdist_exit_err "$__cdist_type_gencode exists, but is not executable" - fi - - # Ensure it's empty, if there is no gencode - : > "$__cdist_tmp_file" - fi - - # Only create code, if gencode created output - if [ "$(wc -l < "$__cdist_tmp_file")" -gt 0 ]; then - cat - "$__cdist_tmp_file" << eof > "$__cdist_code_output" -# -# The following code was generated by $__cdist_type_gencode -# - -eof - chmod u+x "${__cdist_code_output}" - fi -} diff --git a/core/__cdist_object_gencode_run b/core/__cdist_object_gencode_run deleted file mode 100755 index 308f5f33..00000000 --- a/core/__cdist_object_gencode_run +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -# -# 2010 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# For the given object create the code to be executed on the target. -# - -__cdist_object_gencode_run() -{ - __cdist_object_gencode_run_object="$1"; shift - - __cdist_echo info "Generating local code " - __cdist_object_gencode "$__cdist_object_gencode_run_object" \ - "${__cdist_name_gencode_local}" - - __cdist_echo info "Generating remote code " - __cdist_object_gencode "$__cdist_object_gencode_run_object" \ - "${__cdist_name_gencode_remote}" -} diff --git a/core/__cdist_object_list b/core/__cdist_object_list deleted file mode 100755 index f2785c30..00000000 --- a/core/__cdist_object_list +++ /dev/null @@ -1,36 +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 . -# -# -# Print error and exit (perror() alike) -# - -__cdist_object_list() -{ - # FIXME: no local in posix - local basedir="$1"; shift - - # Use subshell to prevent changing cwd in program - ( - cd "${basedir}" - - find . -name "$__cdist_name_dot_cdist" | \ - sed -e 's;^./;;' -e "s;/${__cdist_name_dot_cdist}\$;;" - ) -} diff --git a/core/__cdist_object_manifest_run b/core/__cdist_object_manifest_run deleted file mode 100755 index efc85539..00000000 --- a/core/__cdist_object_manifest_run +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/sh -# -# 2010 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# Run the manifest for the given object. -# - - -__cdist_object_manifest_run() -{ - [ $# -eq 1 ] || __cdist_usage "" - - __cdist_object_self="$1"; shift - - # FIXME: rename to __cdist_object_dir (everywhere!) - __cdist_cur_object_dir="$(__cdist_object_dir "$__cdist_object_self")" - __cdist_object_id="$(__cdist_object_id_from_object "$__cdist_object_self")" - - __cdist_echo info "Checking manifest " - - __cdist_type="$(__cdist_type_from_object "$__cdist_object_self")" - __cdist_manifest="$(__cdist_type_manifest "$__cdist_type")" - - if [ -f "$__cdist_manifest" ]; then - if [ -x "$__cdist_manifest" ]; then - # Make __cdist_manifest available for cdist-type-emulator - export __cdist_manifest - - __cdist_echo info "Executing manifest " - export $__cdist_name_var_object="$__cdist_cur_object_dir" - export $__cdist_name_var_object_id="$__cdist_object_id" - export $__cdist_name_var_type="$(__cdist_type_dir "$__cdist_type")" - - __cdist_manifest_run "$__cdist_manifest" - - # Tell cdist-object-run-all that there may be new objects - touch "$__cdist_objects_created" - else - __cdist_exit_err "${__cdist_manifest} needs to be executable." - fi - fi -} diff --git a/core/__cdist_object_prepare b/core/__cdist_object_prepare deleted file mode 100755 index 24039be0..00000000 --- a/core/__cdist_object_prepare +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh -# -# 2011 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# For the given object: -# - run type explorers -# - run type manifest -# - -__cdist_object_prepare() -{ - [ $# -eq 1 ] || __cdist_usage "" - - __cdist_object_self="$1"; shift - __cdist_object_dir="$(__cdist_object_dir "$__cdist_object_self")" - [ -d "$__cdist_object_dir" ] || __cdist_exit_err "Object undefined" - - # Export to non-core for use in manifest and gencode scripts - export $__cdist_name_var_self=$__cdist_object_self - - __cdist_object_prepared="$(__cdist_object_prepared "$__cdist_object_self")" - if [ ! -f "$__cdist_object_prepared" ]; then - __cdist_echo info "Preparing object" - __cdist_object_explorer_run "$__cdist_object_self" - __cdist_object_manifest_run "$__cdist_object_self" - - # Mark this object as prepared - touch "$__cdist_object_prepared" - fi -} diff --git a/core/__cdist_object_run b/core/__cdist_object_run deleted file mode 100755 index d2c7df6e..00000000 --- a/core/__cdist_object_run +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/sh -# -# 2011 Nico Schottelius (nico-cdist at schottelius.org) -# 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 . -# -# -# For the given object: -# - run type explorers -# - run type manifest -# - generate code -# - copy object to target -# - execute code on target -# - -__cdist_object_run() -{ - [ $# -eq 1 ] || __cdist_usage "" - - __cdist_object_self="$1"; shift - __cdist_object_dir="$(__cdist_object_dir "$__cdist_object_self")" - [ -d "$__cdist_object_dir" ] || __cdist_exit_err "Object undefined" - - # Export to non-core for use in manifest and gencode scripts - export $__cdist_name_var_self=$__cdist_object_self - - # FIXME: BUG: should be named differently! - # FIXME: BUG: I can be called recursively! -> variables are probably already set / overwritten! - __cdist_object_finished="$(__cdist_object_finished "$__cdist_object_self")" - if [ ! -f "$__cdist_object_finished" ]; then - # Resolve dependencies, if any - __cdist_object_require="$(__cdist_object_require "$__cdist_object_self")" - if [ -f "$__cdist_object_require" ]; then - # NEED TO CREATE ARRAY, SSH DESTROYS WHILE READ LOOP - while read __cdist_requirement; do - set -- "$@" "$__cdist_requirement" - done < "$__cdist_object_require" - - while [ $# -gt 0 ]; do - __cdist_requirement="$1"; shift - __cdist_echo info "Resolving requirement $__cdist_requirement" - # FIXME: BUG: at this point, the other __cdist_object_run may have - # overwritten all our variables! - __cdist_object_run "$__cdist_requirement" - done - fi - - __cdist_echo debug "Before gencode" - __cdist_object_gencode_run "$__cdist_object_self" - __cdist_echo debug "Before push" - __cdist_dir push "$(__cdist_object_dir "$__cdist_object_self")" \ - "$(__cdist_remote_object_dir "$__cdist_object_self")" - __cdist_echo debug "Before run" - __cdist_object_code_run "$__cdist_object_self" - __cdist_echo debug "Object run done" - - # Mark this object as done - touch "$__cdist_object_finished" - fi -} diff --git a/core/__cdist_run b/core/__cdist_run deleted file mode 100755 index 8febe550..00000000 --- a/core/__cdist_run +++ /dev/null @@ -1,27 +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 . -# -# -# Exit if an error occurs running something -# - -__cdist_run() -{ - "$@" || __cdist_echo error "$1 exited non-zero, aborting." -} diff --git a/core/__cdist_run_remote b/core/__cdist_run_remote deleted file mode 100755 index 17074049..00000000 --- a/core/__cdist_run_remote +++ /dev/null @@ -1,32 +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 . -# -# -# Run a cdist binary on the remote side -# - -__cdist_run_remote() -{ - [ $# -ge 1 ] || __cdist_usage " [opts]" - - ssh "${__cdist_remote_user}@${__cdist_target_host}" \ - "export PATH=\"${__cdist_remote_bin_dir}:\$PATH\";" \ - "export __cdist_out_object_dir=\"$__cdist_remote_out_object_dir\";" \ - "$@" -} diff --git a/core/__cdist_run_shell b/core/__cdist_run_shell deleted file mode 100755 index b6e0a57d..00000000 --- a/core/__cdist_run_shell +++ /dev/null @@ -1,34 +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 . -# -# -# Exit if an error occurs when running a shell script -# - -__cdist_run_shell() -{ - # Prepend our path, so all cdist tools come before other tools - PATH="${__cdist_out_type_bin_dir}:$PATH" sh -e "$@" - if [ "$?" -ne 0 ]; then - __cdist_echo error "$1 exited non-zero" - __cdist_echo warn "Faulty code:" - cat "$1" - __cdist_exit_err "Aborting due to non-zero exit code." - fi -} diff --git a/core/__cdist_tmp_removal b/core/__cdist_tmp_removal deleted file mode 100755 index 74d74936..00000000 --- a/core/__cdist_tmp_removal +++ /dev/null @@ -1,27 +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 . -# -# -# Remove tmp dir -# - -__cdist_tmp_removal() -{ - rm -rf "${__cdist_tmp_dir}" -} diff --git a/core/__cdist_type_build_emulation b/core/__cdist_type_build_emulation deleted file mode 100755 index 3c7270ca..00000000 --- a/core/__cdist_type_build_emulation +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# Build pseudo binaries for type emulation -# - -__cdist_type_build_emulation() -{ - [ $# -eq 0 ] || __cdist_usage "No arguments" - - [ -f "${__cdist_out_type_bin_dir}/.marker" ] && return 0 - - __cdist_type_emulator="$__cdist_abs_mydir/cdist-type-emulator" - - if [ ! -d "${__cdist_type_dir}" ]; then - __cdist_exit_err "$__cdist_type_dir must exist and contain available types" - fi - - # Get Types - ( - cd "${__cdist_type_dir}" - ls -1 > "${__cdist_tmp_file}" - ) - - # Create binaries - mkdir -p "${__cdist_out_type_bin_dir}" - while read __cdist_type_build_emulation_type; do - ln -sf "${__cdist_type_emulator}" \ - "${__cdist_out_type_bin_dir}/${__cdist_type_build_emulation_type}" - done < "${__cdist_tmp_file}" - - touch "${__cdist_out_type_bin_dir}/.marker" -} diff --git a/core/__cdist_usage b/core/__cdist_usage deleted file mode 100755 index 9dfa30e4..00000000 --- a/core/__cdist_usage +++ /dev/null @@ -1,27 +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 . -# -# -# Print error and exit (perror() alike) -# - -__cdist_usage() -{ - __cdist_exit_err "$__cdist_myname: $@" -} From 47c5ebcf3f34de77f35904c90b96c2f1f44eb733 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 21:37:40 +0200 Subject: [PATCH 0232/4212] remove parallel and sequential args, until they are working Signed-off-by: Nico Schottelius --- bin/cdist | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index 9f713ee3..a04575a8 100755 --- a/bin/cdist +++ b/bin/cdist @@ -588,12 +588,12 @@ if __name__ == "__main__": parser.add_argument('-i', '--initial-manifest', help='Path to a cdist manifest or - to read from stdin', dest='manifest', required=False) - parser.add_argument('-p', '--parallel', - help='Operate on multiple hosts in parallel', - action='store_true', dest='parallel') - parser.add_argument('-s', '--sequential', - help='Operate on multiple hosts sequentially', - action='store_false', dest='parallel') +# parser.add_argument('-p', '--parallel', +# help='Operate on multiple hosts in parallel', +# action='store_true', dest='parallel') +# parser.add_argument('-s', '--sequential', +# help='Operate on multiple hosts sequentially', +# action='store_false', dest='parallel') args = parser.parse_args(sys.argv[1:]) if args.debug: From 326f2644c7a9d7471a73b55403c97b620f28b570 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 21:41:56 +0200 Subject: [PATCH 0233/4212] introduce type_dir() and use it :-) Signed-off-by: Nico Schottelius --- bin/cdist | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index a04575a8..5b2b8d88 100755 --- a/bin/cdist +++ b/bin/cdist @@ -302,9 +302,13 @@ class Cdist: return objects + def type_dir(self, type): + """Return directory the type""" + return os.path.join(TYPE_DIR, type) + def type_explorer_dir(self, type): """Return directory that holds the explorers of a type""" - return os.path.join(TYPE_DIR, type, "explorer") + return os.path.join(self.type_dir(type), "explorer") def type_gencode_paths(self, type): """Return paths to gencode scripts of type""" @@ -444,7 +448,7 @@ class Cdist: env = { "__object" : self.object_dir(cdist_object), "__object_id": self.get_object_id_from_object(cdist_object), "__object_fq": cdist_object, - "__type": type + "__type": self.type_dir(type) } self.run_manifest(manifest, extra_env=env) From 0d1f121e2153b92aa6166279d10a2765e9999c8f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 22:21:46 +0200 Subject: [PATCH 0234/4212] do not fail without objects Signed-off-by: Nico Schottelius --- bin/cdist | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/bin/cdist b/bin/cdist index 5b2b8d88..7a4d3186 100755 --- a/bin/cdist +++ b/bin/cdist @@ -121,6 +121,9 @@ class Cdist: # List of type explorers transferred self.type_explorers_transferred = {} + # objects + self.objects_prepared = [] + self.remote_user = remote_user # Mostly static, but can be overwritten on user demand @@ -241,13 +244,10 @@ class Cdist: return list - def list_object_paths(self, starting_point = False): + def list_object_paths(self, starting_point): """Return list of paths of existing objects""" object_paths = [] - if not starting_point: - starting_point = self.object_base_dir - for content in os.listdir(starting_point): full_path = os.path.join(starting_point, content) if os.path.isdir(full_path): @@ -288,17 +288,15 @@ class Cdist: return [os.path.join(self.object_dir(cdist_object), "code-local"), os.path.join(self.object_dir(cdist_object), "code-remote")] - def list_objects(self, starting_point = False): + def list_objects(self): """Return list of existing objects""" - if not starting_point: - starting_point = self.object_base_dir - - object_paths = self.list_object_paths(starting_point) objects = [] + if os.path.isdir(self.object_base_dir): + object_paths = self.list_object_paths(self.object_base_dir) - for path in object_paths: - objects.append(os.path.relpath(path, starting_point)) + for path in object_paths: + objects.append(os.path.relpath(path, self.object_base_dir)) return objects @@ -561,10 +559,14 @@ class Cdist: while old_objects != objects: log.debug("Prepare stage") old_objects = list(objects) - # FIXME: do not rerun existing objects! for cdist_object in objects: - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) + if cdist_object in self.objects_prepared: + log.debug("Skipping rerun of object %s", cdist_object) + continue + else: + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + self.objects_prepared.append(cdist_object) objects = self.list_objects() From db658328d219b524b493bb5810c79ca27fbaf163 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 23:11:27 +0200 Subject: [PATCH 0235/4212] add sh -e header to code to avoid OSError: [Errno 8] Exec format error Signed-off-by: Nico Schottelius --- bin/cdist | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 7a4d3186..bb6e38fa 100755 --- a/bin/cdist +++ b/bin/cdist @@ -59,6 +59,7 @@ REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") REMOTE_TYPE_DIR = os.path.join(REMOTE_CONF_DIR, "type") REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") +CODE_HEADER = "#!/bin/sh -e" DOT_CDIST = ".cdist" VERSION = "2.0.0" @@ -517,15 +518,18 @@ class Cdist: os.path.basename(bin)[3:]) outfile_fd = open(outfile, "w") + outfile_fd.write(CODE_HEADER) + self.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) outfile_fd.close() status = os.stat(outfile) # Remove output if empty, else make it executable - if status.st_size == 0: + if status.st_size == len(CODE_HEADER): os.unlink(outfile) else: + # Add header and make executable os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) if mode == "code": From 9a0b57c4b5266a39bcbbf9e44e9efa3ddcfa8ad2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 23:41:46 +0200 Subject: [PATCH 0236/4212] update todos Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 36 +++++++----------------------------- doc/dev/todo/niconext | 5 +---- 2 files changed, 8 insertions(+), 33 deletions(-) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 5ded4298..e67469ce 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -5,26 +5,13 @@ Feel free to pick one! CORE ---- -- Inconsistent error messages if object is not existing! - -> always use "Object undefined" -- Add echo function / beautify output - __cdist_echo [level] [messages...] - level := syslog alike: - debug, notice, err - Include object_self prefixing, if given! -- Think about moving cdist-type-build-emulation out of cdist-manifest-run to - cdist-deploy-to: more dependency of cdist-manifest-run, but a lot of - less cycles consumed - -- cdist-object-gencode: remove code if output empty? - - also take care of that in cdist-code-run! -- Remove cdist-object-push, covers only one line and is used only once: - [20:22] kr:bin% grep cdist-object-push * - cdist-object-run: cdist-object-push "$__cdist_target_host" "$__cdist_object" - [20:22] kr:bin% - - probably remove or improve cdist-type-template -- add $__tmp? +- allow cdist to run without $PATH setup: ./bin/cdist-deploy-to +- support non-ssh access? + +USER INTERFACE +-------------- +- add support $__tmp? - for use in manifest, code, etc.? - for creating temporary files, etc. @@ -36,20 +23,11 @@ CORE -> for current host -> add function to cdist-config, import from cdist-cache -- check all all internal variables are prefixed with __cdist - Define / document "this is what should be on host X" and have it parsable by different (shinken) tool -> given after manifest run already! -- Allow types to have parameters without values (boolean flags). - e.g. __chair fancychair --pink --wood - would result in: - $__object/parameter/ - pink # empty file - wood # empty file - -- allow cdist to run without $PATH setup: ./bin/cdist-deploy-to -- use absent/present for state by default +- use absent/present for state by default? TYPES ------ diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 972525aa..a4c23e8b 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,5 +1,2 @@ -- rewrite in python? - - also do with cdist-type-emulator, which had quirks applied from outside to run -- support non-ssh access? - - Bug: os.path.join() may be wrong for the remote side! + -> does not matter for now! From 2490b983ba5e7b76504de5fc6bae3a5e542c8974 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 23:42:53 +0200 Subject: [PATCH 0237/4212] ++todo Signed-off-by: Nico Schottelius --- bin/cdist | 7 +++++-- doc/dev/todo/TAKEME | 2 -- doc/dev/todo/niconext | 4 ++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/bin/cdist b/bin/cdist index bb6e38fa..6da7d04c 100755 --- a/bin/cdist +++ b/bin/cdist @@ -99,7 +99,7 @@ def banner(): class Cdist: """Cdist main class to hold arbitrary data""" - def __init__(self, target_host, initial_manifest=False, remote_user="root"): + def __init__(self, target_host, initial_manifest=False, remote_user="root", home=None): self.target_host = target_host self.remote_prefix = ["ssh", "root@" + self.target_host] @@ -593,6 +593,9 @@ if __name__ == "__main__": parser.add_argument('-b', '--banner', help='Show cdist banner', action='store_true', dest='banner') + parser.add_argument('-c', '--cdist-home', + help='Change cdist home (default: .. from bin directory)', + action='store_true', dest='cdist_home') parser.add_argument('-d', '--debug', help='Set log level to debug', action='store_true') parser.add_argument('-i', '--initial-manifest', @@ -617,7 +620,7 @@ if __name__ == "__main__": log.debug(args) for host in args.host: - c = Cdist(host, initial_manifest=args.manifest) + c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home) c.deploy_to() c.cleanup() except KeyboardInterrupt: diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index e67469ce..5439a1b9 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -44,5 +44,3 @@ DOCUMENTATION - asciidoc interprets __, which we use for variables names -> seek through docs and replace with \_\_! - reference explorers in cdist-reference! -- compare running times: - one, 5, 10, 50, 100, 1000 hosts => how does cdist scale? diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index a4c23e8b..f8535c07 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,2 +1,6 @@ +- Remove all FIXME entries +- Write cdist-manpage +- Remove obsolete manpages +- Support different home instead of ../ - Bug: os.path.join() may be wrong for the remote side! -> does not matter for now! From 1598e18c28b30643d4191fbcbfefa913ef48bdb6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 23:54:18 +0200 Subject: [PATCH 0238/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index f8535c07..3968b0ef 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -4,3 +4,7 @@ - Support different home instead of ../ - Bug: os.path.join() may be wrong for the remote side! -> does not matter for now! + +- Rewrite cdist-type-emulator + - Remove legacy code in cdist + - Remove cdist-config From 1cc7600c9c10125e8b415368b155c4054bf6b1cf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Sep 2011 23:54:34 +0200 Subject: [PATCH 0239/4212] begin to make home configurable Signed-off-by: Nico Schottelius --- bin/cdist | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/bin/cdist b/bin/cdist index 6da7d04c..3361d5da 100755 --- a/bin/cdist +++ b/bin/cdist @@ -46,13 +46,6 @@ BANNER = """ """ # Given paths from installation -BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) -CONF_DIR = os.path.join(BASE_DIR, "conf") -GLOBAL_EXPLORER_DIR = os.path.join(CONF_DIR, "explorer") -LIB_DIR = os.path.join(BASE_DIR, "lib") -MANIFEST_DIR = os.path.join(CONF_DIR, "manifest") -TYPE_DIR = os.path.join(CONF_DIR, "type") - REMOTE_BASE_DIR = "/var/lib/cdist" REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") @@ -87,10 +80,6 @@ VERSION = "2.0.0" logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') log = logging.getLogger() -# List types -def list_types(): - return os.listdir(TYPE_DIR) - def banner(): """Guess what :-)""" print(BANNER) @@ -106,6 +95,17 @@ class Cdist: # Setup directory paths self.temp_dir = tempfile.mkdtemp() + + if home: + self.base_dir = home + else: + self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) + self.conf_dir = os.path.join(self.base_dir, "conf") + self.global_explorer_dir = os.path.join(self.conf_dir, "explorer") + self.lib_dir = os.path.join(self.base_dir, "lib") + self.manifest_dir = os.path.join(self.conf_dir, "manifest") + self.type_base_dir = os.path.join(self.conf_dir, "type") + self.out_dir = os.path.join(self.temp_dir, "out") os.mkdir(self.out_dir) @@ -131,7 +131,7 @@ class Cdist: if initial_manifest: self.initial_manifest = initial_manifest else: - self.initial_manifest = os.path.join(MANIFEST_DIR, "init") + self.initial_manifest = os.path.join(self.manifest_dir, "init") def cleanup(self): # Do not use in __del__: @@ -231,7 +231,7 @@ class Cdist: def list_global_explorers(self): """Return list of available explorers""" - return os.listdir(GLOBAL_EXPLORER_DIR) + return os.listdir(self.global_explorer_dir) def list_type_explorers(self, type): """Return list of available explorers for a specific type""" @@ -245,6 +245,9 @@ class Cdist: return list + def list_types(self): + return os.listdir(self.type_base_dir) + def list_object_paths(self, starting_point): """Return list of paths of existing objects""" object_paths = [] @@ -303,7 +306,7 @@ class Cdist: def type_dir(self, type): """Return directory the type""" - return os.path.join(TYPE_DIR, type) + return os.path.join(self.type_base_dir, type) def type_explorer_dir(self, type): """Return directory that holds the explorers of a type""" @@ -311,12 +314,12 @@ class Cdist: def type_gencode_paths(self, type): """Return paths to gencode scripts of type""" - return [os.path.join(TYPE_DIR, type, "gencode-local"), - os.path.join(TYPE_DIR, type, "gencode-remote")] + return [os.path.join(self.type_base_dir, type, "gencode-local"), + os.path.join(self.type_base_dir, type, "gencode-remote")] def type_manifest_path(self, type): """Return path to manifest of type""" - return os.path.join(TYPE_DIR, type, "manifest") + return os.path.join(self.type_base_dir, type, "manifest") def remote_type_explorer_dir(self, type): """Return remote directory that holds the explorers of a type""" @@ -343,7 +346,7 @@ class Cdist: def transfer_global_explorers(self): """Transfer the global explorers""" - self.transfer_dir(GLOBAL_EXPLORER_DIR, REMOTE_GLOBAL_EXPLORER_DIR) + self.transfer_dir(self.global_explorer_dir, REMOTE_GLOBAL_EXPLORER_DIR) def transfer_type_explorers(self, type): """Transfer explorers of a type, but only once""" @@ -367,8 +370,8 @@ class Cdist: def link_type_to_emulator(self): """Link type names to cdist-type-emulator""" - for type in list_types(): - source = os.path.join(LIB_DIR, "cdist-type-emulator") + for type in self.list_types(): + source = os.path.join(self.lib_dir, "cdist-type-emulator") destination = os.path.join(self.bin_dir, type) log.debug("Linking %s to %s", source, destination) os.symlink(source, destination) @@ -377,7 +380,7 @@ class Cdist: """Run global explorers""" explorers = self.list_global_explorers() if(len(explorers) == 0): - self.exit_error("No explorers found in", GLOBAL_EXPLORER_DIR) + self.exit_error("No explorers found in", self.global_explorer_dir) self.transfer_global_explorers() for explorer in explorers: @@ -433,7 +436,7 @@ class Cdist: def run_initial_manifest(self): """Run the initial manifest""" - env = { "__manifest" : MANIFEST_DIR } + env = { "__manifest" : self.manifest_dir } self.run_manifest(self.initial_manifest, extra_env=env) def run_type_manifest(self, cdist_object): @@ -461,8 +464,8 @@ class Cdist: env['__global'] = self.out_dir # Legacy stuff to make cdist-type-emulator work - env['__cdist_conf_dir'] = CONF_DIR - env['__cdist_core_dir'] = os.path.join(BASE_DIR, "core") + env['__cdist_conf_dir'] = self.conf_dir + env['__cdist_core_dir'] = os.path.join(self.base_dir, "core") env['__cdist_local_base_dir'] = self.temp_dir env['__cdist_manifest'] = self.initial_manifest From 5260f230e503dbf72122802d700b484c44afce48 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 00:06:59 +0200 Subject: [PATCH 0240/4212] support -V, --version Signed-off-by: Nico Schottelius --- bin/cdist | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bin/cdist b/bin/cdist index 3361d5da..7a702c41 100755 --- a/bin/cdist +++ b/bin/cdist @@ -100,6 +100,7 @@ class Cdist: self.base_dir = home else: self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) + self.conf_dir = os.path.join(self.base_dir, "conf") self.global_explorer_dir = os.path.join(self.conf_dir, "explorer") self.lib_dir = os.path.join(self.base_dir, "lib") @@ -611,10 +612,16 @@ if __name__ == "__main__": # help='Operate on multiple hosts sequentially', # action='store_false', dest='parallel') + parser.add_argument('-V', '--version', help='Show version', + action='version', version='%(prog)s ' + VERSION) + args = parser.parse_args(sys.argv[1:]) if args.debug: logging.root.setLevel(logging.DEBUG) + print(args) + sys.exit(1) + if args.banner: banner() sys.exit(0) From 8f34f8659bfc971620de62ba32e846c28823ce9b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 00:08:30 +0200 Subject: [PATCH 0241/4212] support -V, --version Signed-off-by: Nico Schottelius --- bin/cdist | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/cdist b/bin/cdist index 7a702c41..5656ce62 100755 --- a/bin/cdist +++ b/bin/cdist @@ -614,6 +614,7 @@ if __name__ == "__main__": parser.add_argument('-V', '--version', help='Show version', action='version', version='%(prog)s ' + VERSION) + arser.add_argument('--foo', nargs=2) args = parser.parse_args(sys.argv[1:]) if args.debug: From c5355ca10478810e246dfc8615dc777a370d99cd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 00:16:18 +0200 Subject: [PATCH 0242/4212] fixup -c option Signed-off-by: Nico Schottelius --- bin/cdist | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/bin/cdist b/bin/cdist index 5656ce62..dca36b5f 100755 --- a/bin/cdist +++ b/bin/cdist @@ -599,7 +599,7 @@ if __name__ == "__main__": action='store_true', dest='banner') parser.add_argument('-c', '--cdist-home', help='Change cdist home (default: .. from bin directory)', - action='store_true', dest='cdist_home') + action='store') parser.add_argument('-d', '--debug', help='Set log level to debug', action='store_true') parser.add_argument('-i', '--initial-manifest', @@ -614,22 +614,17 @@ if __name__ == "__main__": parser.add_argument('-V', '--version', help='Show version', action='version', version='%(prog)s ' + VERSION) - arser.add_argument('--foo', nargs=2) args = parser.parse_args(sys.argv[1:]) + log.debug(args) if args.debug: logging.root.setLevel(logging.DEBUG) - print(args) - sys.exit(1) - if args.banner: banner() sys.exit(0) try: - log.debug(args) - for host in args.host: c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home) c.deploy_to() From 1a790edbf6cbeff0a7517eaeb38312637145d164 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 00:20:06 +0200 Subject: [PATCH 0243/4212] remove context class until we need it Signed-off-by: Nico Schottelius --- bin/cdist | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/bin/cdist b/bin/cdist index dca36b5f..5eb678be 100755 --- a/bin/cdist +++ b/bin/cdist @@ -56,27 +56,6 @@ CODE_HEADER = "#!/bin/sh -e" DOT_CDIST = ".cdist" VERSION = "2.0.0" - -#class Context(object): -# -# def __init__(self, target_host): -# self.target_host = target_host -# -# # class variable -# user_selber_shuld_wenn_aendert = 'bla' -# -# # read only, aber statisch -# @property -# def remote_base_directory(self): -# return "/var/lib/cdist" -# @property.setter -# -# @property -# def special_foo(self): -# return 'foo/{0}'.format(self.target_host) -# - - logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') log = logging.getLogger() From 3cf203a668d8a2642033113d659d74f71dab9255 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 00:30:07 +0200 Subject: [PATCH 0244/4212] begin to remove obsolete documentation Signed-off-by: Nico Schottelius --- doc/man/man1/cdist-cache.text | 31 -------------- doc/man/man1/cdist-code-run.text | 34 ---------------- doc/man/man1/cdist-deploy-to.text | 43 -------------------- doc/man/man1/cdist-dir.text | 38 ----------------- doc/man/man1/cdist-explorer-run-global.text | 31 -------------- doc/man/man1/cdist-manifest-run-init.text | 32 --------------- doc/man/man1/cdist-manifest-run.text | 31 -------------- doc/man/man1/cdist-mass-deploy.text | 41 ------------------- doc/man/man1/cdist-object-all.text | 31 -------------- doc/man/man1/cdist-object-code-run.text | 32 --------------- doc/man/man1/cdist-object-explorer-run.text | 31 -------------- doc/man/man1/cdist-object-gencode-run.text | 32 --------------- doc/man/man1/cdist-object-gencode.text | 33 --------------- doc/man/man1/cdist-object-manifest-run.text | 31 -------------- doc/man/man1/cdist-object-prepare.text | 35 ---------------- doc/man/man1/cdist-object-push.text | 31 -------------- doc/man/man1/cdist-object-run.text | 36 ---------------- doc/man/man1/cdist-remote-explorer-run.text | 33 --------------- doc/man/man1/cdist-run-remote.text | 33 --------------- doc/man/man1/cdist-type-build-emulation.text | 33 --------------- 20 files changed, 672 deletions(-) delete mode 100644 doc/man/man1/cdist-cache.text delete mode 100644 doc/man/man1/cdist-code-run.text delete mode 100644 doc/man/man1/cdist-deploy-to.text delete mode 100644 doc/man/man1/cdist-dir.text delete mode 100644 doc/man/man1/cdist-explorer-run-global.text delete mode 100644 doc/man/man1/cdist-manifest-run-init.text delete mode 100644 doc/man/man1/cdist-manifest-run.text delete mode 100644 doc/man/man1/cdist-mass-deploy.text delete mode 100644 doc/man/man1/cdist-object-all.text delete mode 100644 doc/man/man1/cdist-object-code-run.text delete mode 100644 doc/man/man1/cdist-object-explorer-run.text delete mode 100644 doc/man/man1/cdist-object-gencode-run.text delete mode 100644 doc/man/man1/cdist-object-gencode.text delete mode 100644 doc/man/man1/cdist-object-manifest-run.text delete mode 100644 doc/man/man1/cdist-object-prepare.text delete mode 100644 doc/man/man1/cdist-object-push.text delete mode 100644 doc/man/man1/cdist-object-run.text delete mode 100644 doc/man/man1/cdist-remote-explorer-run.text delete mode 100644 doc/man/man1/cdist-run-remote.text delete mode 100644 doc/man/man1/cdist-type-build-emulation.text diff --git a/doc/man/man1/cdist-cache.text b/doc/man/man1/cdist-cache.text deleted file mode 100644 index 54619199..00000000 --- a/doc/man/man1/cdist-cache.text +++ /dev/null @@ -1,31 +0,0 @@ -cdist-cache(1) -============== -Nico Schottelius - - -NAME ----- -cdist-cache - Cache output of last run - - -SYNOPSIS --------- -cdist-cache TARGET_HOST - - -DESCRIPTION ------------ -cdist-cache moves away the objects created during last run so the -next run can use the previous information and compare them with -the current status. - - -SEE ALSO --------- -cdist(7) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-code-run.text b/doc/man/man1/cdist-code-run.text deleted file mode 100644 index e5d8c976..00000000 --- a/doc/man/man1/cdist-code-run.text +++ /dev/null @@ -1,34 +0,0 @@ -cdist-code-run(1) -================= -Nico Schottelius - - -NAME ----- -cdist-code-run - Run explorer remotely - - -SYNOPSIS --------- -cdist-code-run OBJECT_DIR OBJECT TYPE - - -DESCRIPTION ------------ -cdist-code-run executes generated code from a given OBJECT. -The OBJECT must be located below OBJECT_DIR. -TYPE must be either local or remote and determines which -code part is to be executed. - - -SEE ALSO --------- -- cdist(7) -- cdist-object-gencode(1) -- cdist-object-gencode-all(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-deploy-to.text b/doc/man/man1/cdist-deploy-to.text deleted file mode 100644 index f42a0509..00000000 --- a/doc/man/man1/cdist-deploy-to.text +++ /dev/null @@ -1,43 +0,0 @@ -cdist-deploy-to(1) -================== -Nico Schottelius - - -NAME ----- -cdist-deploy-to - Deploy configuration to host - - -SYNOPSIS --------- -cdist-deploy-to HOSTNAME - - -DESCRIPTION ------------ -Deploy configurations to the specified host, as configured in the initial -manifest. This script triggers the execution of several other scripts, in so -called stages. It is intented to run either from the command line or from cron. - - -ENVIRONMENT ------------ -If the environment variable **__cdist_conf_dir** is not set, the -configuration is read from /conf. The local output directory can -be changed by the variable **__cdist_local_base_dir**. All environment -variables are handled by cdist-config. - - -SEE ALSO --------- -- cdist(7) -- cdist-config(1) -- cdist-mass-deploy(1) -- cdist-reference(7) -- cdist-stages(7) - - -COPYING -------- -Copyright \(C) 2010-2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-dir.text b/doc/man/man1/cdist-dir.text deleted file mode 100644 index 223bc779..00000000 --- a/doc/man/man1/cdist-dir.text +++ /dev/null @@ -1,38 +0,0 @@ -cdist-dir(1) -============ -Nico Schottelius - - -NAME ----- -cdist-dir - Poor man's directory synchronisation - - -SYNOPSIS --------- -cdist-dir TARGET_HOST SRC_DIR DST_DIR - - -DESCRIPTION ------------ -cdist-dir either pushes a local directory to the target host -or pulls a remote directory from a target host to the local host. - -In the push case SRC_DIR is local, in the pull case remote. -In the push case DST_DIR is remote, in the pull case local. - -cdist-dir does not cleanup DST_DIR and thus it may contain old -stuff if used multiple times. - -cdist-dir does not rely on rsync or other high level tools, because -it cannot expect its existence on the local or target host. - -SEE ALSO --------- -cdist(7) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-explorer-run-global.text b/doc/man/man1/cdist-explorer-run-global.text deleted file mode 100644 index f4b32dfb..00000000 --- a/doc/man/man1/cdist-explorer-run-global.text +++ /dev/null @@ -1,31 +0,0 @@ -cdist-explorer-run-global(1) -============================ -Nico Schottelius - - -NAME ----- -cdist-explorer-run-global - Run the global explorers - - -SYNOPSIS --------- -cdist-explorer-run-global HOSTNAME - - -DESCRIPTION ------------ -Transfer the global explorers to HOSTNAME, execute them and transfer -back the results. - - -SEE ALSO --------- -- cdist(7) -- cdist-deploy-to(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-manifest-run-init.text b/doc/man/man1/cdist-manifest-run-init.text deleted file mode 100644 index 3a3265dc..00000000 --- a/doc/man/man1/cdist-manifest-run-init.text +++ /dev/null @@ -1,32 +0,0 @@ -cdist-manifest-run-init(1) -========================== -Nico Schottelius - - -NAME ----- -cdist-manifest-run-init - Run the initial manifest - - -SYNOPSIS --------- -cdist-manifest-run-init HOSTNAME - - -DESCRIPTION ------------ -cdist-manifest-run-init executes the initial manifest, which creates -the first objects. - - -SEE ALSO --------- -- cdist(7) -- cdist-deploy-to(1) -- cdist-manifest-run-all(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-manifest-run.text b/doc/man/man1/cdist-manifest-run.text deleted file mode 100644 index 8cd6b513..00000000 --- a/doc/man/man1/cdist-manifest-run.text +++ /dev/null @@ -1,31 +0,0 @@ -cdist-manifest-run(1) -===================== -Nico Schottelius - - -NAME ----- -cdist-manifest-run - Run a given manifest - - -SYNOPSIS --------- -cdist-manifest-run HOSTNAME MANIFEST - - -DESCRIPTION ------------ -cdist-manifest-run executes the given MANIFEST. - - -SEE ALSO --------- -- cdist(7) -- cdist-deploy-to(1) -- cdist-manifest-run-init(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-mass-deploy.text b/doc/man/man1/cdist-mass-deploy.text deleted file mode 100644 index ac495b21..00000000 --- a/doc/man/man1/cdist-mass-deploy.text +++ /dev/null @@ -1,41 +0,0 @@ -cdist-mass-deploy(1) -==================== -Nico Schottelius - - -NAME ----- -cdist-mass-deploy - Deploy configuration to many hosts - - -SYNOPSIS --------- -cdist-mass-deploy [-p] HOSTNAME [HOSTNAME ...] - - -DESCRIPTION ------------ -cdist-mass-deploy is essentially a wrapper around cdist-deploy-to to -be able to deploy to many hosts on one command line. - - -EXAMPLES --------- -Deploy in parallel to all hosts specfied in the dsh group configuration ikr, -which is prefixed by "root@": - --------------------------------------------------------------------------------- -cdist-mass-deploy -p $(cat ~/.dsh/group/ikr | sed 's/^root@//') --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist(7) -- cdist-deploy-to(1) - - -COPYING -------- -Copyright \(C) 2010-2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-object-all.text b/doc/man/man1/cdist-object-all.text deleted file mode 100644 index 06d45268..00000000 --- a/doc/man/man1/cdist-object-all.text +++ /dev/null @@ -1,31 +0,0 @@ -cdist-object-all(1) -=================== -Steven Armstrong - - -NAME ----- -cdist-object-all - Run the given command on all objects - - -SYNOPSIS --------- -cdist-object-all HOSTNAME COMMAND - - -DESCRIPTION ------------ -Iterates over all defined objects and executes the given command on each -of them. - - -SEE ALSO --------- -- cdist(7) -- cdist-type(1) - - -COPYING -------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-object-code-run.text b/doc/man/man1/cdist-object-code-run.text deleted file mode 100644 index f8bae6a4..00000000 --- a/doc/man/man1/cdist-object-code-run.text +++ /dev/null @@ -1,32 +0,0 @@ -cdist-object-code-run(1) -======================== -Nico Schottelius - - -NAME ----- -cdist-object-code-run - Execute the generated code for a object - - -SYNOPSIS --------- -cdist-object-code-run HOSTNAME OBJECT - - -DESCRIPTION ------------ -Execute the local and remote code for the given object. - - -SEE ALSO --------- -- cdist(7) -- cdist-object-run(1) -- cdist-code-run(1) -- cdist-run-remote(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius, Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-object-explorer-run.text b/doc/man/man1/cdist-object-explorer-run.text deleted file mode 100644 index a791681e..00000000 --- a/doc/man/man1/cdist-object-explorer-run.text +++ /dev/null @@ -1,31 +0,0 @@ -cdist-object-explorer-run(1) -============================ -Nico Schottelius - - -NAME ----- -cdist-object-explorer-run - Run type explorers for a object - - -SYNOPSIS --------- -cdist-object-explorer-run HOSTNAME OBJECT - - -DESCRIPTION ------------ -Runs the explorers for the given object on the target host. - - -SEE ALSO --------- -- cdist(7) -- cdist-deploy-to(1) -- cdist-remote-explorer-run(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius, Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-object-gencode-run.text b/doc/man/man1/cdist-object-gencode-run.text deleted file mode 100644 index 7705815c..00000000 --- a/doc/man/man1/cdist-object-gencode-run.text +++ /dev/null @@ -1,32 +0,0 @@ -cdist-object-gencode-run(1) -=========================== -Nico Schottelius - - -NAME ----- -cdist-object-gencode-run - Generate code for a object - - -SYNOPSIS --------- -cdist-object-gencode-run HOSTNAME OBJECT - - -DESCRIPTION ------------ -For the given object, generate the code for local and remote execution. - - -SEE ALSO --------- -- cdist(7) -- cdist-code-run(1) -- cdist-object-run(1) -- cdist-object-gencode(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius, Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-object-gencode.text b/doc/man/man1/cdist-object-gencode.text deleted file mode 100644 index 83f4b4c1..00000000 --- a/doc/man/man1/cdist-object-gencode.text +++ /dev/null @@ -1,33 +0,0 @@ -cdist-object-gencode(1) -======================= -Nico Schottelius - - -NAME ----- -cdist-object-gencode - Generate code for a given object - - -SYNOPSIS --------- -cdist-object-gencode HOSTNAME OBJECT - - -DESCRIPTION ------------ -For the given object, run the gencode executable. The output of this -executable on stdout will be used by cdist-object-gencode-all(1). - - -SEE ALSO --------- -- cdist(7) -- cdist-code-run(1) -- cdist-deploy-to(1) -- cdist-object-gencode-all(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-object-manifest-run.text b/doc/man/man1/cdist-object-manifest-run.text deleted file mode 100644 index a6f12f78..00000000 --- a/doc/man/man1/cdist-object-manifest-run.text +++ /dev/null @@ -1,31 +0,0 @@ -cdist-object-manifest-run(1) -============================ -Nico Schottelius - - -NAME ----- -cdist-object-manifest-run - Run an objects manifest - - -SYNOPSIS --------- -cdist-object-manifest-run HOSTNAME OBJECT - - -DESCRIPTION ------------ -Run the manifest for the given object. - - -SEE ALSO --------- -- cdist(7) -- cdist-deploy-to(1) -- cdist-manifest-run(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius, Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-object-prepare.text b/doc/man/man1/cdist-object-prepare.text deleted file mode 100644 index c91a7b2e..00000000 --- a/doc/man/man1/cdist-object-prepare.text +++ /dev/null @@ -1,35 +0,0 @@ -cdist-object-prepare(1) -======================= -Steven Armstrong - - -NAME ----- -cdist-object-prepare - Prepare an object - - -SYNOPSIS --------- -cdist-object-prepare HOSTNAME OBJECT - - -DESCRIPTION ------------ -Prepare the given object by running it through stage 3 (object information -retrieval) and stage 4 (run the object manifest). -See related man pages for details. - - -SEE ALSO --------- -- cdist(7) -- cdist-stages(7) -- cdist-object-explorer-run(1) -- cdist-object-manifest-run(1) -- cdist-type(1) - - -COPYING -------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is granted -under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-object-push.text b/doc/man/man1/cdist-object-push.text deleted file mode 100644 index 4c960eaa..00000000 --- a/doc/man/man1/cdist-object-push.text +++ /dev/null @@ -1,31 +0,0 @@ -cdist-object-push(1) -==================== -Nico Schottelius - - -NAME ----- -cdist-object-push - Transfer a object to the target host - - -SYNOPSIS --------- -cdist-object-push HOSTNAME OBJECT - - -DESCRIPTION ------------ -Transfers the given object to the target host. - - -SEE ALSO --------- -- cdist(7) -- cdist-object-run(1) -- cdist-type(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius, Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-object-run.text b/doc/man/man1/cdist-object-run.text deleted file mode 100644 index fc85a05f..00000000 --- a/doc/man/man1/cdist-object-run.text +++ /dev/null @@ -1,36 +0,0 @@ -cdist-object-run(1) -=================== -Steven Armstrong - - -NAME ----- -cdist-object-run - Run an object - - -SYNOPSIS --------- -cdist-object-run HOSTNAME OBJECT - - -DESCRIPTION ------------ -Applies the given object on the target host by running it through stage 5 -(code generation) and stage 6 (code execution). -See related man pages for details. - - -SEE ALSO --------- -- cdist(7) -- cdist-stages(7) -- cdist-object-gencode-run(1) -- cdist-object-push(1) -- cdist-object-code-run(1) -- cdist-type(1) - - -COPYING -------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-remote-explorer-run.text b/doc/man/man1/cdist-remote-explorer-run.text deleted file mode 100644 index 64951e2c..00000000 --- a/doc/man/man1/cdist-remote-explorer-run.text +++ /dev/null @@ -1,33 +0,0 @@ -cdist-remote-explorer-run(1) -============================ -Nico Schottelius - - -NAME ----- -cdist-remote-explorer-run - Run explorer remotely - - -SYNOPSIS --------- -cdist-remote-explorer-run VARIABLE_NAME EXPLORER_DIR OUT_DIR - - -DESCRIPTION ------------ -cdist-remote-explorer-run is executed on the target. -It sets up the variable VARIABLE_NAME to point to the given -EXPLORER_DIR and runs all explorer found in EXPLORER_DIR. -The output of every run explorer is saved into OUT_DIR. - - -SEE ALSO --------- -- cdist(7) -- cdist-explorer-run-global(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-run-remote.text b/doc/man/man1/cdist-run-remote.text deleted file mode 100644 index ee7a6337..00000000 --- a/doc/man/man1/cdist-run-remote.text +++ /dev/null @@ -1,33 +0,0 @@ -cdist-run-remote(1) -=================== -Nico Schottelius - - -NAME ----- -cdist-run-remote - Execute something on the target - - -SYNOPSIS --------- -cdist-run-remote HOSTNAME EXECUTABLE [ARGUMENTS FOR EXECUTABLE] - - -DESCRIPTION ------------ -cdist-run-remote runs the given executable on the remote host. -It ensures PATH is setup correctly on the target side. - - -SEE ALSO --------- -- cdist(7) -- cdist-object-code-run(1) -- cdist-deploy-to(1) -- cdist-remote-code-run-all(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-type-build-emulation.text b/doc/man/man1/cdist-type-build-emulation.text deleted file mode 100644 index 81c56e7c..00000000 --- a/doc/man/man1/cdist-type-build-emulation.text +++ /dev/null @@ -1,33 +0,0 @@ -cdist-type-build-emulation(1) -============================= -Nico Schottelius - - -NAME ----- -cdist-type-build-emulation - Build executables for types - - -SYNOPSIS --------- -cdist-type-build-emulation OUT_DIR - - -DESCRIPTION ------------ -cdist-type-build-emulation creates a link to cdist-type-emulator -for every TYPE. These links are placed in a OUT_DIR, which -is prepended into $PATH. This way the user can use TYPE in the -manifests like any other executable. - - -SEE ALSO --------- -- cdist(7) -- cdist-type-emulator(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). From 4aff17610619bf7f8c8d53319f30bc4daab31d22 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 00:30:45 +0200 Subject: [PATCH 0245/4212] flush and also append \n to header Signed-off-by: Nico Schottelius --- bin/cdist | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 5eb678be..0e85a79c 100755 --- a/bin/cdist +++ b/bin/cdist @@ -52,7 +52,7 @@ REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") REMOTE_TYPE_DIR = os.path.join(REMOTE_CONF_DIR, "type") REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") -CODE_HEADER = "#!/bin/sh -e" +CODE_HEADER = "#!/bin/sh -e\n" DOT_CDIST = ".cdist" VERSION = "2.0.0" @@ -501,7 +501,10 @@ class Cdist: os.path.basename(bin)[3:]) outfile_fd = open(outfile, "w") + + # Need to flush to ensure our write is done before stdout write outfile_fd.write(CODE_HEADER) + outfile_fd.flush() self.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) outfile_fd.close() From e07328f569fbea0130442a71a22b976317306bf2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 01:14:35 +0200 Subject: [PATCH 0246/4212] initial support for parallel running Signed-off-by: Nico Schottelius --- bin/cdist | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/bin/cdist b/bin/cdist index 0e85a79c..c50775f8 100755 --- a/bin/cdist +++ b/bin/cdist @@ -23,6 +23,7 @@ import argparse import datetime import logging +import multiprocessing import os import subprocess import shutil @@ -573,6 +574,15 @@ class Cdist: self.target_host, duration.total_seconds()) + def deploy_and_cleanup(self): + """Do what is most often done: deploy & cleanup""" + self.deploy_to() + self.cleanup() + + +def foo(): + print("test") + if __name__ == "__main__": parser = argparse.ArgumentParser(description='cdist ' + VERSION) parser.add_argument('host', nargs='*', help='one or more hosts to operate on') @@ -587,13 +597,12 @@ if __name__ == "__main__": parser.add_argument('-i', '--initial-manifest', help='Path to a cdist manifest or - to read from stdin', dest='manifest', required=False) -# parser.add_argument('-p', '--parallel', -# help='Operate on multiple hosts in parallel', -# action='store_true', dest='parallel') -# parser.add_argument('-s', '--sequential', -# help='Operate on multiple hosts sequentially', -# action='store_false', dest='parallel') - + parser.add_argument('-p', '--parallel', + help='Operate on multiple hosts in parallel', + action='store_true', dest='parallel') + parser.add_argument('-s', '--sequential', + help='Operate on multiple hosts sequentially', + action='store_false', dest='parallel') parser.add_argument('-V', '--version', help='Show version', action='version', version='%(prog)s ' + VERSION) @@ -606,10 +615,26 @@ if __name__ == "__main__": banner() sys.exit(0) + process = {} + time_start = datetime.datetime.now() try: for host in args.host: c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home) - c.deploy_to() - c.cleanup() + if args.parallel: + log.info("Starting child process for %s", host) + process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) + process[host].start() + log.debug("After process for %s", host) + else: + c.deploy_and_cleanup() + + if args.parallel: + for p in process.keys(): + log.debug("Joining %s", p) + process[p].join() + + time_end = datetime.datetime.now() + log.info("Total processing time: %s", (time_end - time_start).total_seconds()) + except KeyboardInterrupt: sys.exit(0) From 5ba6e0bb142edf0f0fc54c9eedcf0a4a933f2355 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 01:38:51 +0200 Subject: [PATCH 0247/4212] more hints on parallel running Signed-off-by: Nico Schottelius --- bin/cdist | 3 ++- doc/dev/todo/niconext | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index c50775f8..f8500ca7 100755 --- a/bin/cdist +++ b/bin/cdist @@ -618,10 +618,11 @@ if __name__ == "__main__": process = {} time_start = datetime.datetime.now() try: + log.info("Deploying to %s hosts", len(args.host)) for host in args.host: c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home) if args.parallel: - log.info("Starting child process for %s", host) + log.debug("Starting child process for %s", host) process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) process[host].start() log.debug("After process for %s", host) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 3968b0ef..2321bf03 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,4 +1,6 @@ - Remove all FIXME entries +- Support parallel execution + - and maximum number of parallel runs (-p X) - Write cdist-manpage - Remove obsolete manpages - Support different home instead of ../ From 25190e86a37f47bd889948e6bb0d13bfc80f4d69 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 01:39:56 +0200 Subject: [PATCH 0248/4212] todo for 2.0.0 Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 2321bf03..2b1bb703 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,8 +1,13 @@ -- Remove all FIXME entries +For 2.0.0: + + - Write cdist-manpage + - Remove all FIXME entries + - Remove obsolete manpages + +-------------------------------------------------------------------------------- + - Support parallel execution - and maximum number of parallel runs (-p X) -- Write cdist-manpage -- Remove obsolete manpages - Support different home instead of ../ - Bug: os.path.join() may be wrong for the remote side! -> does not matter for now! From 7de51e8d45c43d43ab3f97aec53016562ae47d87 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 10:52:04 +0200 Subject: [PATCH 0249/4212] print help in case no hosts are given Signed-off-by: Nico Schottelius --- bin/cdist | 11 ++++++++--- doc/dev/todo/niconext | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index f8500ca7..628cbca4 100755 --- a/bin/cdist +++ b/bin/cdist @@ -616,9 +616,13 @@ if __name__ == "__main__": sys.exit(0) process = {} - time_start = datetime.datetime.now() try: - log.info("Deploying to %s hosts", len(args.host)) + if len(args.host) == 0: + parser.print_help() + sys.exit(1) + + time_start = datetime.datetime.now() + for host in args.host: c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home) if args.parallel: @@ -635,7 +639,8 @@ if __name__ == "__main__": process[p].join() time_end = datetime.datetime.now() - log.info("Total processing time: %s", (time_end - time_start).total_seconds()) + log.info("Total processing time for %s host(s): %s", len(args.host), + (time_end - time_start).total_seconds()) except KeyboardInterrupt: sys.exit(0) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 2b1bb703..ef861cec 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -8,6 +8,7 @@ For 2.0.0: - Support parallel execution - and maximum number of parallel runs (-p X) + - error handling / report failed hosts - Support different home instead of ../ - Bug: os.path.join() may be wrong for the remote side! -> does not matter for now! From 1742936dc9a6fc8a4273bc3f3b7a8e98a1faec64 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 10:58:10 +0200 Subject: [PATCH 0250/4212] add initial version of manpage for cdist Signed-off-by: Nico Schottelius --- doc/man/man1/cdist.text | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 doc/man/man1/cdist.text diff --git a/doc/man/man1/cdist.text b/doc/man/man1/cdist.text new file mode 100644 index 00000000..368d9097 --- /dev/null +++ b/doc/man/man1/cdist.text @@ -0,0 +1,63 @@ +cdist(1) +======== +Nico Schottelius + + +NAME +---- +cdist - Configuration management + + +SYNOPSIS +-------- +cdist [-h] [-b] [-c CDIST_HOME] [-d] [-i MANIFEST] [-p] [-s] [-V] [host [host ...]] + + +DESCRIPTION +----------- +cdist is the frontend executable to the cdist configuration management. + + +OPTIONS +------- +-h, --help:: + Show the help screen + +-d, --debug:: + Enable debug output + +-p, --parallel:: + Parallelise backup processes + +-V, --version:: + Show version and exit + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Configure ikq05.ethz.ch with debug enabled +cdist -d ikq05.ethz.ch + +__motd +-------------------------------------------------------------------------------- + +In both cases, cdist-type-emulator is called instead of a real type. +In the first case, the object id "/tmp/linetest" is recorded and the +parameter "line" stored with the content "test". + +In the second case, __motd must be decleared as a singleton, as the +object id is missing. + + +SEE ALSO +-------- +- cdist(7) +- cdist-type-build-emulation(1) + + +COPYING +------- +Copyright \(C) 2011 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). From b470a47b15a4b5f77e7a73514f972aedb05f8e8c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 11:18:18 +0200 Subject: [PATCH 0251/4212] add working cdist manpage Signed-off-by: Nico Schottelius --- bin/cdist | 2 +- doc/man/man1/cdist.text | 30 +++++++++++++++++++++--------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/bin/cdist b/bin/cdist index 628cbca4..7fb73e65 100755 --- a/bin/cdist +++ b/bin/cdist @@ -601,7 +601,7 @@ if __name__ == "__main__": help='Operate on multiple hosts in parallel', action='store_true', dest='parallel') parser.add_argument('-s', '--sequential', - help='Operate on multiple hosts sequentially', + help='Operate on multiple hosts sequentially (default)', action='store_false', dest='parallel') parser.add_argument('-V', '--version', help='Show version', action='version', version='%(prog)s ' + VERSION) diff --git a/doc/man/man1/cdist.text b/doc/man/man1/cdist.text index 368d9097..f45d4495 100644 --- a/doc/man/man1/cdist.text +++ b/doc/man/man1/cdist.text @@ -23,11 +23,24 @@ OPTIONS -h, --help:: Show the help screen +-b, --banner:: + Show cdist banner + +-c CDIST_HOME, --cdist-home CDIST_HOME:: + Instead of using the parent of the bin directory as cdist home, + use the specified directory + -d, --debug:: Enable debug output +-i MANIFEST, --initial-manifest MANIFEST:: + Path to a cdist manifest or - to read from stdin + -p, --parallel:: - Parallelise backup processes + Operate on multiple hosts in parallel + +-s, --sequential:: + Operate on multiple hosts sequentially -V, --version:: Show version and exit @@ -40,16 +53,15 @@ EXAMPLES # Configure ikq05.ethz.ch with debug enabled cdist -d ikq05.ethz.ch -__motd +# Configure hosts in parallel and use a different home directory +cdist -c ~/p/cdist-nutzung -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch + +# Does not need a comment, plain works +cdist --banner +cdist --help +cdist --version -------------------------------------------------------------------------------- -In both cases, cdist-type-emulator is called instead of a real type. -In the first case, the object id "/tmp/linetest" is recorded and the -parameter "line" stored with the content "test". - -In the second case, __motd must be decleared as a singleton, as the -object id is missing. - SEE ALSO -------- From 4e95535b7c9912729b50a97156e27399f046843b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 11:27:20 +0200 Subject: [PATCH 0252/4212] definitely cleanup remote directory first, so we see more bugs :-) Signed-off-by: Nico Schottelius --- bin/cdist | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index 7fb73e65..98e92c9a 100755 --- a/bin/cdist +++ b/bin/cdist @@ -327,6 +327,7 @@ class Cdist: def transfer_global_explorers(self): """Transfer the global explorers""" + self.remote_mkdir(REMOTE_GLOBAL_EXPLORER_DIR) self.transfer_dir(self.global_explorer_dir, REMOTE_GLOBAL_EXPLORER_DIR) def transfer_type_explorers(self, type): @@ -406,12 +407,9 @@ class Cdist: def init_deploy(self): log.debug("Creating clean directory structure") - # Ensure there is no old stuff, neither local nor remote - # remote_run_or_fail(hostname, ["rm -rf", "${__cdist_remote_base_dir}"]) - # - # # Create base directories - # remote_run_or_fail(hostname,["mkdir -p", "${__cdist_remote_base_dir}"]) - # + self.remove_remote_dir(REMOTE_BASE_DIR) + self.remote_mkdir(REMOTE_BASE_DIR) + # # Link configuraion source directory - consistent with remote # run_or_fail(["ln -sf", "$__cdist_conf_dir", "$__cdist_local_base_dir/$__cdist_name_conf_dir"]) From 8b37daf5ff291d0857f9ebb7e3388c532179ea07 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 11:27:30 +0200 Subject: [PATCH 0253/4212] --todo for 2.0.0 Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index ef861cec..22f9f7b7 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,6 +1,5 @@ For 2.0.0: - - Write cdist-manpage - Remove all FIXME entries - Remove obsolete manpages From a09a618c781327b36aa7303a7acdff4f3c488a58 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Sep 2011 11:37:20 +0200 Subject: [PATCH 0254/4212] prepare cdist-type-emulator transformation Signed-off-by: Nico Schottelius --- bin/cdist | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/bin/cdist b/bin/cdist index 98e92c9a..dc6a5a5f 100755 --- a/bin/cdist +++ b/bin/cdist @@ -65,6 +65,34 @@ def banner(): print(BANNER) +class TypeEmulator: + + def type_emulator(): + type = basename(sys.argv[0]) + + type_is_singleton(type) + + # Check object id + + # Prevent double slash if id begins with / + + # Record parameter: opt_file="${opt#--}" + # [ $# -ge 1 ] || __cdist_usage "Missing value for $opt" + # echo "${value}" > "${__cdist_parameter_dir}/${opt_file}" + + # Record requirements + # echo $requirement >> "$(__cdist_object_require "$__cdist_object_self")" + + # Ensure required parameters are given + # Ensure that only optional or required parameters are given + # [ "$is_valid" ] || __cdist_usage "Unknown parameter $parameter" + + # Merge object (creating twice with the same parameter + requirements == allowed) + + # diff -ru "${__cdist_new_object_dir}/${__cdist_name_parameter} + # # Add "I was here message" + # _cdist_object_source_add "${__cdist_object_dir}" + class Cdist: """Cdist main class to hold arbitrary data""" From 99b3b0789bbc7385a2882dbcba52514d6baa4782 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 00:02:04 +0200 Subject: [PATCH 0255/4212] remove tmpdir, keep it only if debug is enabled Signed-off-by: Nico Schottelius --- bin/cdist | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/bin/cdist b/bin/cdist index dc6a5a5f..e20a9f49 100755 --- a/bin/cdist +++ b/bin/cdist @@ -66,8 +66,12 @@ def banner(): class TypeEmulator: + def __init__(self, name): + self.name = name + self.type = os.path.basename(name) - def type_emulator(): + + def type_emulator(self): type = basename(sys.argv[0]) type_is_singleton(type) @@ -96,13 +100,16 @@ class TypeEmulator: class Cdist: """Cdist main class to hold arbitrary data""" - def __init__(self, target_host, initial_manifest=False, remote_user="root", home=None): + def __init__(self, target_host, + initial_manifest=False, remote_user="root", + home=None, debug=False): self.target_host = target_host self.remote_prefix = ["ssh", "root@" + self.target_host] # Setup directory paths self.temp_dir = tempfile.mkdtemp() + self.debug = debug if home: self.base_dir = home @@ -148,8 +155,10 @@ class Cdist: # "other globals referenced by the __del__() method may already have been deleted # or in the process of being torn down (e.g. the import machinery shutting down)" # - print("I should cleanup " + self.temp_dir) - # shutil.rmtree(self.temp_dir) + if self.debug: + log.debug("Skipping removal of " + self.temp_dir) + else: + shutil.rmtree(self.temp_dir) def exit_error(self, *args): log.error(*args) @@ -650,7 +659,7 @@ if __name__ == "__main__": time_start = datetime.datetime.now() for host in args.host: - c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home) + c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) if args.parallel: log.debug("Starting child process for %s", host) process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) From 4e3fec1e9e6acb8874ca7aee5573f91555c3a796 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 16:10:03 +0200 Subject: [PATCH 0256/4212] add hint to pythons octal mode Signed-off-by: Nico Schottelius --- bin/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index e20a9f49..f50bb1fb 100755 --- a/bin/cdist +++ b/bin/cdist @@ -551,7 +551,7 @@ class Cdist: if status.st_size == len(CODE_HEADER): os.unlink(outfile) else: - # Add header and make executable + # Add header and make executable - identically to 0o700 os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) if mode == "code": From a43474cd68ba1256db5389d7f8c7301c9527f29d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 16:10:46 +0200 Subject: [PATCH 0257/4212] add logfiles Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-09-12 | 67 +++++++++++++++++++++++++++++++++++++++++ doc/dev/logs/2011-09-13 | 3 ++ 2 files changed, 70 insertions(+) create mode 100644 doc/dev/logs/2011-09-12 create mode 100644 doc/dev/logs/2011-09-13 diff --git a/doc/dev/logs/2011-09-12 b/doc/dev/logs/2011-09-12 new file mode 100644 index 00000000..391b836f --- /dev/null +++ b/doc/dev/logs/2011-09-12 @@ -0,0 +1,67 @@ +Benchmark from home/X201 (2 cores, 4 threads): + + ikq (1): 72.192397 + ikq (2): INFO: Total processing time for 2 hosts: 74.1845 + ikq* (6): INFO: Total processing time: 117.572312 + ikq* + ikr3 (9): INFO: Total processing time: 120.307662 + ikq* + ikr (14): INFO: Total processing time: 139.769807 + ikq* + ikr (18): INFO: Total processing time: 186.354398 + ikq* + ikr (22): INFO: Total processing time: 225.793533 + ikq* + ikr (26): INFO: Total processing time: 237.06687 + ikq* + ikr (31): INFO: Total processing time: 276.912414 + + +ikr07.ethz.ch ikr09.ethz.ch ikr10.ethz.ch ikr11.ethz.ch +ikr13.ethz.ch ikr14.ethz.ch ikr15.ethz.ch ikr16.ethz.ch +ikr17.ethz.ch ikr19.ethz.ch ikr20.ethz.ch ikr21.ethz.ch +ikr23.ethz.ch ikr24.ethz.ch ikr25.ethz.ch ikr26.ethz.ch +ikr27.ethz.ch ikr28.ethz.ch ikr29.ethz.ch ikr30.ethz.ch +ikr31.ethz.ch + +cdist -c ~/p/cdist-nutzung -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch ikq05.ethz.ch ikq06.ethz.ch ikq07.ethz.ch ikr01.ethz.ch ikr02.ethz.ch ikr03.ethz.ch ikr05.ethz.ch ikr07.ethz.ch ikr09.ethz.ch ikr10.ethz.ch ikr11.ethz.ch ikr13.ethz.ch ikr14.ethz.ch ikr15.ethz.ch ikr16.ethz.ch ikr17.ethz.ch ikr19.ethz.ch ikr20.ethz.ch ikr21.ethz.ch + + +-------------------------------------------------------------------------------- +INFO: Total processing time for 1 hosts: 72.166661 +INFO: Total processing time for 2 hosts: 76.633228 +INFO: Total processing time for 3 host(s): 77.199817 +INFO: Total processing time for 4 host(s): 94.045175 +INFO: Total processing time for 5 host(s): 103.226354 +INFO: Total processing time for 6 host(s): 107.76097 +INFO: Total processing time for 7 host(s): 101.571705 +INFO: Total processing time for 8 host(s): 107.600093 +INFO: Total processing time for 9 host(s): 116.500371 +INFO: Total processing time for 10 host(s): 119.445805 +INFO: Total processing time for 11 host(s): 123.944385 +INFO: Total processing time for 12 host(s): 130.499098 +INFO: Total processing time for 13 host(s): 137.250861 +INFO: Total processing time for 14 host(s): 154.9841 +INFO: Total processing time for 15 host(s): 139.659637 +INFO: Total processing time for 16 host(s): 142.70005 +INFO: Total processing time for 17 host(s): 148.541452 +INFO: Total processing time for 18 host(s): 159.360809 +INFO: Total processing time for 19 host(s): 171.907864 +INFO: Total processing time for 20 host(s): 178.76695 +INFO: Total processing time for 21 host(s): 183.856671 +INFO: Total processing time for 22 host(s): 194.504221 +INFO: Total processing time for 23 host(s): 207.314842 +INFO: Total processing time for 24 host(s): 215.846502 +INFO: Total processing time for 25 host(s): 217.223581 +INFO: Total processing time for 26 host(s): 238.591705 +INFO: Total processing time for 27 host(s): 238.478493 +INFO: Total processing time for 28 host(s): 246.058718 +INFO: Total processing time for 29 host(s): 264.208372 +INFO: Total processing time for 30 host(s): 265.560685 +INFO: Total processing time for 31 host(s): 282.264488 + +-------------------------------------------------------------------------------- +Use: + grep "^INFO: Total processing time" doc/dev/logs/2011-09-12 | sed 's/.*: //' + octave + times = [ /* paste here ] + plot(times) + # keep the graph + hold on + # Scale linearly with the single host value + plot((1:31)*times(1)) + diff --git a/doc/dev/logs/2011-09-13 b/doc/dev/logs/2011-09-13 new file mode 100644 index 00000000..b55a2d4e --- /dev/null +++ b/doc/dev/logs/2011-09-13 @@ -0,0 +1,3 @@ +Name for installer: + installer (flag) + $__installer (variable) - gesetzt oder nicht From a5b56f0c4111d28a1614db9d01ea321725694b19 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 16:19:43 +0200 Subject: [PATCH 0258/4212] remove useless function Signed-off-by: Nico Schottelius --- bin/cdist | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/bin/cdist b/bin/cdist index f50bb1fb..fda94888 100755 --- a/bin/cdist +++ b/bin/cdist @@ -352,16 +352,6 @@ class Cdist: self.transfer_dir(self.object_parameter_dir(cdist_object), self.remote_object_parameter_dir(cdist_object)) - def transfer_object_code(self, cdist_object): - FIXME - """Transfer the object code to the remote destination""" - # Create base path before using mkdir -p - self.remote_mkdir(self.remote_object_parameter_dir(cdist_object)) - - # Synchronise parameter dir afterwards - self.transfer_file(self.object_code_path(cdist_object), - self.remote_object_parameter_dir(cdist_object)) - def transfer_global_explorers(self): """Transfer the global explorers""" self.remote_mkdir(REMOTE_GLOBAL_EXPLORER_DIR) @@ -555,7 +545,6 @@ class Cdist: os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) if mode == "code": -# paths = self.object_code_paths(cdist_object) local_dir = self.object_dir(cdist_object) remote_dir = self.remote_object_dir(cdist_object) From 59afce35b53419a20aac42d73d7f563fd71e8e85 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 16:25:39 +0200 Subject: [PATCH 0259/4212] do not do more checks on the manifest, current ones are good Signed-off-by: Nico Schottelius --- bin/cdist | 1 - doc/dev/todo/niconext | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index fda94888..873fbb1a 100755 --- a/bin/cdist +++ b/bin/cdist @@ -451,7 +451,6 @@ class Cdist: manifest = self.type_manifest_path(type) log.debug("%s: Running %s", cdist_object, manifest) - # FIXME: add more sensible checks for manifest if os.path.exists(manifest): env = { "__object" : self.object_dir(cdist_object), "__object_id": self.get_object_id_from_object(cdist_object), diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 22f9f7b7..738cd692 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -2,6 +2,8 @@ For 2.0.0: - Remove all FIXME entries - Remove obsolete manpages + - support subcommands! + deploy? config? -------------------------------------------------------------------------------- @@ -15,3 +17,4 @@ For 2.0.0: - Rewrite cdist-type-emulator - Remove legacy code in cdist - Remove cdist-config + From f4faff6b33a05fb2887d521651e705208e928431 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 16:29:33 +0200 Subject: [PATCH 0260/4212] --todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 738cd692..b1b77a27 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,7 +1,5 @@ For 2.0.0: - - Remove all FIXME entries - - Remove obsolete manpages - support subcommands! deploy? config? @@ -17,4 +15,6 @@ For 2.0.0: - Rewrite cdist-type-emulator - Remove legacy code in cdist - Remove cdist-config + - Remove man1/cdist-type-emulator.text +- Replace bin/cdist-type-template From 5cbe34ee336ee51c5666b774654afcd706f61579 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 17:40:28 +0200 Subject: [PATCH 0261/4212] begin to implement subcommand handling Signed-off-by: Nico Schottelius --- bin/cdist | 98 ++++++++++++++++++++++++++----------------- doc/dev/todo/niconext | 3 +- 2 files changed, 61 insertions(+), 40 deletions(-) diff --git a/bin/cdist b/bin/cdist index 873fbb1a..99bc775f 100755 --- a/bin/cdist +++ b/bin/cdist @@ -60,10 +60,6 @@ VERSION = "2.0.0" logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') log = logging.getLogger() -def banner(): - """Guess what :-)""" - print(BANNER) - class TypeEmulator: def __init__(self, name): @@ -602,42 +598,13 @@ class Cdist: self.deploy_to() self.cleanup() +def banner(*args): + """Guess what :-)""" + print(BANNER) + sys.exit(0) -def foo(): - print("test") - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='cdist ' + VERSION) - parser.add_argument('host', nargs='*', help='one or more hosts to operate on') - parser.add_argument('-b', '--banner', - help='Show cdist banner', - action='store_true', dest='banner') - parser.add_argument('-c', '--cdist-home', - help='Change cdist home (default: .. from bin directory)', - action='store') - parser.add_argument('-d', '--debug', help='Set log level to debug', - action='store_true') - parser.add_argument('-i', '--initial-manifest', - help='Path to a cdist manifest or - to read from stdin', - dest='manifest', required=False) - parser.add_argument('-p', '--parallel', - help='Operate on multiple hosts in parallel', - action='store_true', dest='parallel') - parser.add_argument('-s', '--sequential', - help='Operate on multiple hosts sequentially (default)', - action='store_false', dest='parallel') - parser.add_argument('-V', '--version', help='Show version', - action='version', version='%(prog)s ' + VERSION) - - args = parser.parse_args(sys.argv[1:]) - log.debug(args) - if args.debug: - logging.root.setLevel(logging.DEBUG) - - if args.banner: - banner() - sys.exit(0) - +def config(*args, **kargs): + """Configure remote system""" process = {} try: if len(args.host) == 0: @@ -667,3 +634,56 @@ if __name__ == "__main__": except KeyboardInterrupt: sys.exit(0) + +if __name__ == "__main__": + # Construct parser others can reuse + parser = {} + # Options _all_ parsers have in common + parser['most'] = argparse.ArgumentParser(add_help=False) + parser['most'].add_argument('-d', '--debug', + help='Set log level to debug', + action='store_true') + parser['most'].add_argument('-V', '--version', + help='Show version', + action='version', + version='%(prog)s ' + VERSION) + + # Main subcommand parser + parser['main'] = argparse.ArgumentParser(description='cdist ' + VERSION) + parser['sub'] = parser['main'].add_subparsers() + + + parser['banner'] = parser['sub'].add_parser('banner') +# parser['banner'].add_argument('all', nargs='*', +# help='Show cdist banner') + parser['banner'].set_defaults(func=banner) + + parser['config'] = parser['sub'].add_parser('config', + aliases=['deploy'], + parents=[parser['most']]) + parser['config'].add_argument('host', nargs='*', + help='one or more hosts to operate on') + parser['config'].add_argument('-c', '--cdist-home', + help='Change cdist home (default: .. from bin directory)', + action='store') + parser['config'].add_argument('-i', '--initial-manifest', + help='Path to a cdist manifest or - to read from stdin', + dest='manifest', required=False) + parser['config'].add_argument('-p', '--parallel', + help='Operate on multiple hosts in parallel', + action='store_true', dest='parallel') + parser['config'].add_argument('-s', '--sequential', + help='Operate on multiple hosts sequentially (default)', + action='store_false', dest='parallel') + parser['config'].set_defaults(func=config) + + + args = parser['main'].parse_args(sys.argv[1:]) + + # Most subcommands to have --debug, so handle it here + if 'debug' in args: + if args.debug: + logging.root.setLevel(logging.DEBUG) + log.debug(args) + + args.func(args) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index b1b77a27..6b87b8fe 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,7 +1,8 @@ For 2.0.0: - support subcommands! - deploy? config? + config (deploy) + install (provision) -------------------------------------------------------------------------------- From df7f27f94b881f5e5b4dbc03f0393c74434dc148 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 17:42:43 +0200 Subject: [PATCH 0262/4212] catch keyboard interrupt for all subcommands Signed-off-by: Nico Schottelius --- bin/cdist | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/bin/cdist b/bin/cdist index 99bc775f..fad85dca 100755 --- a/bin/cdist +++ b/bin/cdist @@ -603,10 +603,10 @@ def banner(*args): print(BANNER) sys.exit(0) -def config(*args, **kargs): +def config(*args): """Configure remote system""" + print(*args) process = {} - try: if len(args.host) == 0: parser.print_help() sys.exit(1) @@ -632,8 +632,6 @@ def config(*args, **kargs): log.info("Total processing time for %s host(s): %s", len(args.host), (time_end - time_start).total_seconds()) - except KeyboardInterrupt: - sys.exit(0) if __name__ == "__main__": # Construct parser others can reuse @@ -652,10 +650,7 @@ if __name__ == "__main__": parser['main'] = argparse.ArgumentParser(description='cdist ' + VERSION) parser['sub'] = parser['main'].add_subparsers() - parser['banner'] = parser['sub'].add_parser('banner') -# parser['banner'].add_argument('all', nargs='*', -# help='Show cdist banner') parser['banner'].set_defaults(func=banner) parser['config'] = parser['sub'].add_parser('config', @@ -677,7 +672,6 @@ if __name__ == "__main__": action='store_false', dest='parallel') parser['config'].set_defaults(func=config) - args = parser['main'].parse_args(sys.argv[1:]) # Most subcommands to have --debug, so handle it here @@ -686,4 +680,7 @@ if __name__ == "__main__": logging.root.setLevel(logging.DEBUG) log.debug(args) - args.func(args) + try: + args.func(args) + except KeyboardInterrupt: + sys.exit(0) From 8d1b4236d4b822a8cf2774020cedf5434769a9b9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 17:59:11 +0200 Subject: [PATCH 0263/4212] fixup most arguments for config Signed-off-by: Nico Schottelius --- bin/cdist | 55 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/bin/cdist b/bin/cdist index fad85dca..339ecfa8 100755 --- a/bin/cdist +++ b/bin/cdist @@ -598,46 +598,48 @@ class Cdist: self.deploy_to() self.cleanup() -def banner(*args): +def banner(args): """Guess what :-)""" print(BANNER) sys.exit(0) -def config(*args): +def config(args): """Configure remote system""" - print(*args) + print(args) process = {} - if len(args.host) == 0: - parser.print_help() - sys.exit(1) - time_start = datetime.datetime.now() + if len(args.host) == 0: + parser.print_help() + sys.exit(1) - for host in args.host: - c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) - if args.parallel: - log.debug("Starting child process for %s", host) - process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) - process[host].start() - log.debug("After process for %s", host) - else: - c.deploy_and_cleanup() + time_start = datetime.datetime.now() + for host in args.host: + c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) if args.parallel: - for p in process.keys(): - log.debug("Joining %s", p) - process[p].join() + log.debug("Starting child process for %s", host) + process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) + process[host].start() + log.debug("After process for %s", host) + else: + c.deploy_and_cleanup() - time_end = datetime.datetime.now() - log.info("Total processing time for %s host(s): %s", len(args.host), - (time_end - time_start).total_seconds()) + if args.parallel: + for p in process.keys(): + log.debug("Joining %s", p) + process[p].join() + + time_end = datetime.datetime.now() + log.info("Total processing time for %s host(s): %s", len(args.host), + (time_end - time_start).total_seconds()) if __name__ == "__main__": # Construct parser others can reuse parser = {} # Options _all_ parsers have in common - parser['most'] = argparse.ArgumentParser(add_help=False) + parser['most'] = argparse.ArgumentParser(add_help=False, + epilog="Get cdist at http://www.nico.schottelius.org/software/cdist/") parser['most'].add_argument('-d', '--debug', help='Set log level to debug', action='store_true') @@ -645,9 +647,12 @@ if __name__ == "__main__": help='Show version', action='version', version='%(prog)s ' + VERSION) + #version='%(prog)s ' + VERSION) + # Main subcommand parser - parser['main'] = argparse.ArgumentParser(description='cdist ' + VERSION) + parser['main'] = argparse.ArgumentParser(description='cdist ' + VERSION, + parents=[parser['most']]) parser['sub'] = parser['main'].add_subparsers() parser['banner'] = parser['sub'].add_parser('banner') @@ -656,7 +661,7 @@ if __name__ == "__main__": parser['config'] = parser['sub'].add_parser('config', aliases=['deploy'], parents=[parser['most']]) - parser['config'].add_argument('host', nargs='*', + parser['config'].add_argument('host', nargs='+', help='one or more hosts to operate on') parser['config'].add_argument('-c', '--cdist-home', help='Change cdist home (default: .. from bin directory)', From 4d065443da3e9f676ff8b0973b2073243d664d76 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 18:00:41 +0200 Subject: [PATCH 0264/4212] remove alias deploy for config, does not make things better Signed-off-by: Nico Schottelius --- bin/cdist | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 339ecfa8..7e3e9a1c 100755 --- a/bin/cdist +++ b/bin/cdist @@ -659,7 +659,6 @@ if __name__ == "__main__": parser['banner'].set_defaults(func=banner) parser['config'] = parser['sub'].add_parser('config', - aliases=['deploy'], parents=[parser['most']]) parser['config'].add_argument('host', nargs='+', help='one or more hosts to operate on') From 581562aae96890c027fe367478ea429ff0b122d9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 18:05:15 +0200 Subject: [PATCH 0265/4212] cleanups Signed-off-by: Nico Schottelius --- bin/cdist | 22 +++++++--------------- doc/dev/todo/niconext | 10 ++-------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/bin/cdist b/bin/cdist index 7e3e9a1c..42838093 100755 --- a/bin/cdist +++ b/bin/cdist @@ -428,14 +428,12 @@ class Cdist: output_fd.close() def init_deploy(self): + """Ensure the base directories are cleaned up""" log.debug("Creating clean directory structure") self.remove_remote_dir(REMOTE_BASE_DIR) self.remote_mkdir(REMOTE_BASE_DIR) - # # Link configuraion source directory - consistent with remote - # run_or_fail(["ln -sf", "$__cdist_conf_dir", "$__cdist_local_base_dir/$__cdist_name_conf_dir"]) - def run_initial_manifest(self): """Run the initial manifest""" env = { "__manifest" : self.manifest_dir } @@ -605,7 +603,6 @@ def banner(args): def config(args): """Configure remote system""" - print(args) process = {} if len(args.host) == 0: @@ -633,7 +630,6 @@ def config(args): log.info("Total processing time for %s host(s): %s", len(args.host), (time_end - time_start).total_seconds()) - if __name__ == "__main__": # Construct parser others can reuse parser = {} @@ -641,14 +637,10 @@ if __name__ == "__main__": parser['most'] = argparse.ArgumentParser(add_help=False, epilog="Get cdist at http://www.nico.schottelius.org/software/cdist/") parser['most'].add_argument('-d', '--debug', - help='Set log level to debug', - action='store_true') + help='Set log level to debug', action='store_true') parser['most'].add_argument('-V', '--version', - help='Show version', - action='version', - version='%(prog)s ' + VERSION) - #version='%(prog)s ' + VERSION) - + help='Show version', action='version', + version='%(prog)s ' + VERSION) # Main subcommand parser parser['main'] = argparse.ArgumentParser(description='cdist ' + VERSION, @@ -659,14 +651,14 @@ if __name__ == "__main__": parser['banner'].set_defaults(func=banner) parser['config'] = parser['sub'].add_parser('config', - parents=[parser['most']]) + parents=[parser['most']]) parser['config'].add_argument('host', nargs='+', help='one or more hosts to operate on') parser['config'].add_argument('-c', '--cdist-home', help='Change cdist home (default: .. from bin directory)', action='store') parser['config'].add_argument('-i', '--initial-manifest', - help='Path to a cdist manifest or - to read from stdin', + help='Path to a cdist manifest', dest='manifest', required=False) parser['config'].add_argument('-p', '--parallel', help='Operate on multiple hosts in parallel', @@ -678,7 +670,7 @@ if __name__ == "__main__": args = parser['main'].parse_args(sys.argv[1:]) - # Most subcommands to have --debug, so handle it here + # Most subcommands have --debug, so handle it here if 'debug' in args: if args.debug: logging.root.setLevel(logging.DEBUG) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 6b87b8fe..63f9b629 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,11 +1,3 @@ -For 2.0.0: - - - support subcommands! - config (deploy) - install (provision) - --------------------------------------------------------------------------------- - - Support parallel execution - and maximum number of parallel runs (-p X) - error handling / report failed hosts @@ -19,3 +11,5 @@ For 2.0.0: - Remove man1/cdist-type-emulator.text - Replace bin/cdist-type-template + +- Allow manifest to be read from stdin From 780fd5625e2efdfa86bbafe766186143bcb9ce76 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 18:15:04 +0200 Subject: [PATCH 0266/4212] re-implement correct caching Signed-off-by: Nico Schottelius --- bin/cdist | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bin/cdist b/bin/cdist index 42838093..530618f1 100755 --- a/bin/cdist +++ b/bin/cdist @@ -113,6 +113,8 @@ class Cdist: self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) self.conf_dir = os.path.join(self.base_dir, "conf") + self.cache_base_dir = os.path.join(self.base_dir, "cache") + self.cache_dir = os.path.join(self.cache_base_dir, self.target_host) self.global_explorer_dir = os.path.join(self.conf_dir, "explorer") self.lib_dir = os.path.join(self.base_dir, "lib") self.manifest_dir = os.path.join(self.conf_dir, "manifest") @@ -151,10 +153,11 @@ class Cdist: # "other globals referenced by the __del__() method may already have been deleted # or in the process of being torn down (e.g. the import machinery shutting down)" # - if self.debug: - log.debug("Skipping removal of " + self.temp_dir) - else: - shutil.rmtree(self.temp_dir) + log.debug("Saving" + self.temp_dir + "to " + self.cache_dir) + # Remove previous cache + if os.path.exists(self.cache_dir): + shutil.rmtree(self.cache_dir) + os.rename(self.temp_dir, self.cache_dir) def exit_error(self, *args): log.error(*args) From 7e9d2342197d3b8f6564a27aed61cc7aa505df1a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 18:18:12 +0200 Subject: [PATCH 0267/4212] remove obsolete length check Signed-off-by: Nico Schottelius --- bin/cdist | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bin/cdist b/bin/cdist index 530618f1..a468e2fc 100755 --- a/bin/cdist +++ b/bin/cdist @@ -608,10 +608,6 @@ def config(args): """Configure remote system""" process = {} - if len(args.host) == 0: - parser.print_help() - sys.exit(1) - time_start = datetime.datetime.now() for host in args.host: From e1421280d4700f505f320e126abc4de8bafab347 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 18:18:56 +0200 Subject: [PATCH 0268/4212] remove debug Signed-off-by: Nico Schottelius --- bin/cdist | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index a468e2fc..ad5584af 100755 --- a/bin/cdist +++ b/bin/cdist @@ -613,10 +613,9 @@ def config(args): for host in args.host: c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) if args.parallel: - log.debug("Starting child process for %s", host) + log.debug("Creating child process for %s", host) process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) process[host].start() - log.debug("After process for %s", host) else: c.deploy_and_cleanup() From 9f6a3933c7eb535f751f85ad64d013615976e441 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 18:24:24 +0200 Subject: [PATCH 0269/4212] remove obsolete HACKERS_README, we are stable now Signed-off-by: Nico Schottelius --- HACKERS_README | 40 ---------------------------------------- 1 file changed, 40 deletions(-) delete mode 100755 HACKERS_README diff --git a/HACKERS_README b/HACKERS_README deleted file mode 100755 index ad3fe3fd..00000000 --- a/HACKERS_README +++ /dev/null @@ -1,40 +0,0 @@ -cat << eof - -Hey hackers, - -this README is for you, for those who want to dig into cdist, hack it or try -to get a deeper understanding. Please read doc/man/man7/cdist-hacker.text. - -I hope you have a lot of fun with cdist, because it was also a lot of fun to -develop it! - - -- Nico, 20110324 - -## Running cdist when developing - -This file is suitable for execution and saving the objects and -explorers from cdist. I usually do it like this: - - % ./HACKERS_README - -################################################################################ -eof - -set -x -# Tell the user what we do, so this script makes sense during execution - -# prepare use (only from top level directory) -export PATH="$(pwd -P)/bin:$PATH" -export __cdist_conf_dir="$(pwd -P)/conf" - -# Allow user to supply hostname -target="${1:-localhost}" - -# And use hostname as basedir (dangerous, but hackers know what they do) -export __cdist_local_base_dir="/tmp/$target" - -# Run the real script -cdist-deploy-to "$target" - -# Display results -find "${__cdist_local_base_dir}" From 90bdf0433672456653d2d3425b5c0689bb52135b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 21:30:17 +0200 Subject: [PATCH 0270/4212] add epilog to parsers, make it look beautiful Signed-off-by: Nico Schottelius --- bin/cdist | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/bin/cdist b/bin/cdist index ad5584af..5333cb3a 100755 --- a/bin/cdist +++ b/bin/cdist @@ -632,20 +632,20 @@ if __name__ == "__main__": # Construct parser others can reuse parser = {} # Options _all_ parsers have in common - parser['most'] = argparse.ArgumentParser(add_help=False, - epilog="Get cdist at http://www.nico.schottelius.org/software/cdist/") + parser['most'] = argparse.ArgumentParser(add_help=False) parser['most'].add_argument('-d', '--debug', help='Set log level to debug', action='store_true') - parser['most'].add_argument('-V', '--version', - help='Show version', action='version', - version='%(prog)s ' + VERSION) # Main subcommand parser - parser['main'] = argparse.ArgumentParser(description='cdist ' + VERSION, - parents=[parser['most']]) + parser['main'] = argparse.ArgumentParser(description='cdist ' + VERSION) + + parser['main'].add_argument('-V', '--version', + help='Show version', action='version', + version='%(prog)s ' + VERSION) parser['sub'] = parser['main'].add_subparsers() - parser['banner'] = parser['sub'].add_parser('banner') + parser['banner'] = parser['sub'].add_parser('banner', + add_help=False) parser['banner'].set_defaults(func=banner) parser['config'] = parser['sub'].add_parser('config', @@ -666,6 +666,9 @@ if __name__ == "__main__": action='store_false', dest='parallel') parser['config'].set_defaults(func=config) + for p in parser: + parser[p].epilog = "Get cdist at http://www.nico.schottelius.org/software/cdist/" + args = parser['main'].parse_args(sys.argv[1:]) # Most subcommands have --debug, so handle it here From 9b18b3d79e93b2b0aef84e102c0f39962b7e9801 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 21:35:57 +0200 Subject: [PATCH 0271/4212] update manpage and support commands title Signed-off-by: Nico Schottelius --- bin/cdist | 5 +++-- doc/man/man1/cdist.text | 38 ++++++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/bin/cdist b/bin/cdist index 5333cb3a..21a35c22 100755 --- a/bin/cdist +++ b/bin/cdist @@ -638,16 +638,17 @@ if __name__ == "__main__": # Main subcommand parser parser['main'] = argparse.ArgumentParser(description='cdist ' + VERSION) - parser['main'].add_argument('-V', '--version', help='Show version', action='version', version='%(prog)s ' + VERSION) - parser['sub'] = parser['main'].add_subparsers() + parser['sub'] = parser['main'].add_subparsers(title="Commands") + # Banner parser['banner'] = parser['sub'].add_parser('banner', add_help=False) parser['banner'].set_defaults(func=banner) + # Config parser['config'] = parser['sub'].add_parser('config', parents=[parser['most']]) parser['config'].add_argument('host', nargs='+', diff --git a/doc/man/man1/cdist.text b/doc/man/man1/cdist.text index f45d4495..7f585953 100644 --- a/doc/man/man1/cdist.text +++ b/doc/man/man1/cdist.text @@ -10,22 +10,34 @@ cdist - Configuration management SYNOPSIS -------- -cdist [-h] [-b] [-c CDIST_HOME] [-d] [-i MANIFEST] [-p] [-s] [-V] [host [host ...]] +cdist [-V|--version] +cdist banner +cdist config [-h] [-d] [-V] [-c CDIST_HOME] [-i MANIFEST] [-p] [-s] host [host ...] + DESCRIPTION ----------- cdist is the frontend executable to the cdist configuration management. +cdist supports different as explained below. The options to the main +program are: + +-V, --version:: + Show version and exit -OPTIONS +BANNER ------- +Displays the cdist banner. + + +CONFIG +------ +Configure a system + -h, --help:: Show the help screen --b, --banner:: - Show cdist banner - -c CDIST_HOME, --cdist-home CDIST_HOME:: Instead of using the parent of the bin directory as cdist home, use the specified directory @@ -42,23 +54,25 @@ OPTIONS -s, --sequential:: Operate on multiple hosts sequentially --V, --version:: - Show version and exit - EXAMPLES -------- -------------------------------------------------------------------------------- # Configure ikq05.ethz.ch with debug enabled -cdist -d ikq05.ethz.ch +cdist config -d ikq05.ethz.ch # Configure hosts in parallel and use a different home directory -cdist -c ~/p/cdist-nutzung -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch +cdist config -c ~/p/cdist-nutzung \ + -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch -# Does not need a comment, plain works -cdist --banner +# Display banner +cdist banner + +# Show help cdist --help + +# Show Version cdist --version -------------------------------------------------------------------------------- From c8b238df064df105f032237d52738c4a8936ceb5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 22:07:21 +0200 Subject: [PATCH 0272/4212] update cdist homepage Signed-off-by: Nico Schottelius --- README | 11 +++++++---- doc/dev/todo/niconext | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/README b/README index 295b9152..521d70a2 100644 --- a/README +++ b/README @@ -38,13 +38,13 @@ Design | Define target state, do not focus on methods or scripts Design | Push architecture: Instantly apply your changes Small core | cdist's core is very small - less code, less bugs Fast development | Focus on straightforwardness of type creation is a main development objective +Modern Programming Language | cdist is written in Python Requirements, Scalability | No central server needed, cdist operates in push mode and can be run from any computer Requirements, Scalability, Upgrade | cdist only needs to be updated on the master, not on the target hosts Requirements, Security | Uses well-know [SSH](http://www.openssh.com/) as transport protocol Requirements, Simplicity | Requires only shell and SSH server on the target UNIX | Reuse of existing tools like cat, find, mv, ... UNIX, familar environment, documentation | Is available as manpages and HTML -UNIX, simplicity, familar environment | cdist is written in POSIX shell UNIX, simplicity, familar environment | cdist is configured in POSIX shell """]] @@ -76,6 +76,7 @@ cdist was tested or is know to run on at least ### Server * A posix like shell + * Python (>= 3.2 required) * SSH-Client ### Client ("target host") @@ -110,10 +111,11 @@ how to use cdist. There are at least the following branches available: * Development: master - * Current Stable: 1.7 (Bugfixes, cleanups, new type and explorer rename) + * 2.0: Python rewrite Old versions: + * 1.7: Bugfixes, cleanups, new type and explorer rename * 1.6: New types, cleaned up \_\_package* types, internal cleanup * 1.5: Focus on object orientation instead of global stage orientation * 1.4: Support for redefiniton of objects (if equal) @@ -129,13 +131,12 @@ may vanish at any point. To select a specific branch use git checkout -b origin/ # Stay on a specific version - version=1.7 + version=2.0 git checkout -b $version origin/$version ### Mirrors * git://github.com/telmich/cdist.git ([github](https://github.com/telmich/cdist)) - * git://git.sans.ethz.ch/cdist ([sans](http://git.sans.ethz.ch/?p=cdist;a=summary)) ## Update @@ -151,6 +152,8 @@ 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. +### Upgrading from 1.7 to 2.0 + ### Upgrading from 1.6 to 1.7 * If you used the global explorer **hardware_type**, you need to change diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 63f9b629..accef050 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -13,3 +13,5 @@ - Replace bin/cdist-type-template - Allow manifest to be read from stdin +- Create new video for cdist 2.0.0 + http://www.youtube.com/watch?v=PRMjzy48eTI From 2f30ebf1f0c7da3284071e17ab0ee123036bd882 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 22:11:51 +0200 Subject: [PATCH 0273/4212] more todo, yeah! Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index accef050..beae3cb2 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -9,6 +9,7 @@ - Remove legacy code in cdist - Remove cdist-config - Remove man1/cdist-type-emulator.text + - Remove the PATH=... part from the README - Replace bin/cdist-type-template From 24cbc1b717442000e1831281b1c0e932b2981b46 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 22:23:28 +0200 Subject: [PATCH 0274/4212] changes for 2.0 Signed-off-by: Nico Schottelius --- README | 5 +++++ doc/man/cdist-reference.text.sh | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README b/README index 521d70a2..3808faac 100644 --- a/README +++ b/README @@ -154,6 +154,11 @@ working, break your setup or eat the tree in your garden. ### Upgrading from 1.7 to 2.0 +* Ensure python (>= 3.2) is installed on the server +* Use "cdist config host" instead of "cdist-deploy-to host" +* Use "cdist config -p host1 host2" instead of "cdist-mass-deploy" +* Use **\_\_object_fq** instead of **\_\_self** in manifests + ### Upgrading from 1.6 to 1.7 * If you used the global explorer **hardware_type**, you need to change diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index a823891b..218b0f57 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -171,7 +171,7 @@ __object:: __object_id:: The type unique object id. Available for: type manifest, type explorer, type gencode -__self:: +__object_fq:: The full qualified name of the current object. Available for: type manifest, type explorer, type gencode __target_host:: From 159ace1ea2bee34919c6806e7dc1aeaf73713df4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 22:40:10 +0200 Subject: [PATCH 0275/4212] more important changes for 2.0 Signed-off-by: Nico Schottelius --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index 3808faac..3e00b497 100644 --- a/README +++ b/README @@ -157,6 +157,7 @@ working, break your setup or eat the tree in your garden. * Ensure python (>= 3.2) is installed on the server * Use "cdist config host" instead of "cdist-deploy-to host" * Use "cdist config -p host1 host2" instead of "cdist-mass-deploy" +* Use "cdist banner" for fun * Use **\_\_object_fq** instead of **\_\_self** in manifests ### Upgrading from 1.6 to 1.7 From fece6ddd6aaee0a0fdc82fee6fa7f195537b4f9d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 22:42:47 +0200 Subject: [PATCH 0276/4212] create subdirs man1 and man7 on the web Signed-off-by: Nico Schottelius --- build.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index a6897d49..8ebfa168 100755 --- a/build.sh +++ b/build.sh @@ -96,10 +96,14 @@ case "$1" in web) cp README ${WEBDIR}/${WEBPAGE} - rm -rf ${WEBDIR}/${WEBBASE}/man && mkdir ${WEBDIR}/${WEBBASE}/man + rm -rf ${WEBDIR}/${WEBBASE}/man + mkdir ${WEBDIR}/${WEBBASE}/man/man1 + mkdir ${WEBDIR}/${WEBBASE}/man/man7 + rm -rf ${WEBDIR}/${WEBBASE}/speeches && mkdir ${WEBDIR}/${WEBBASE}/speeches - cp ${MAN1DSTDIR}/*.html ${MAN7DSTDIR}/*.html ${WEBDIR}/${WEBBASE}/man + cp ${MAN1DSTDIR}/*.html ${WEBDIR}/${WEBBASE}/man/man1 + cp ${MAN7DSTDIR}/*.html ${WEBDIR}/${WEBBASE}/man/man7 cp ${SPEECHESDIR}/*.pdf ${WEBDIR}/${WEBBASE}/speeches git describe > ${WEBDIR}/${WEBBASE}/man/VERSION From a0058a181827d1122c76fef71efa1449950b49d0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 22:46:15 +0200 Subject: [PATCH 0277/4212] really create the directories Signed-off-by: Nico Schottelius --- build.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.sh b/build.sh index 8ebfa168..bef4393b 100755 --- a/build.sh +++ b/build.sh @@ -97,8 +97,7 @@ case "$1" in web) cp README ${WEBDIR}/${WEBPAGE} rm -rf ${WEBDIR}/${WEBBASE}/man - mkdir ${WEBDIR}/${WEBBASE}/man/man1 - mkdir ${WEBDIR}/${WEBBASE}/man/man7 + mkdir -p ${WEBDIR}/${WEBBASE}/man/man1 ${WEBDIR}/${WEBBASE}/man/man7 rm -rf ${WEBDIR}/${WEBBASE}/speeches && mkdir ${WEBDIR}/${WEBBASE}/speeches From 2e96ba793a1fe85cd10b7ae4a6ac694c47e1e4d7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 22:48:14 +0200 Subject: [PATCH 0278/4212] reformat cdist manpage Signed-off-by: Nico Schottelius --- doc/man/man1/cdist.text | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/man/man1/cdist.text b/doc/man/man1/cdist.text index 7f585953..104163af 100644 --- a/doc/man/man1/cdist.text +++ b/doc/man/man1/cdist.text @@ -10,8 +10,10 @@ cdist - Configuration management SYNOPSIS -------- -cdist [-V|--version] +cdist [-h] [-V] + cdist banner + cdist config [-h] [-d] [-V] [-c CDIST_HOME] [-i MANIFEST] [-p] [-s] host [host ...] @@ -22,6 +24,9 @@ cdist is the frontend executable to the cdist configuration management. cdist supports different as explained below. The options to the main program are: +-h, --help:: + Show the help screen + -V, --version:: Show version and exit From 41099a35960f0f97c4b8f5e7bbb7da8b8f77b20d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Sep 2011 22:49:42 +0200 Subject: [PATCH 0279/4212] update references Signed-off-by: Nico Schottelius --- doc/man/man1/cdist.text | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/man/man1/cdist.text b/doc/man/man1/cdist.text index 104163af..5a45b8c1 100644 --- a/doc/man/man1/cdist.text +++ b/doc/man/man1/cdist.text @@ -85,7 +85,8 @@ cdist --version SEE ALSO -------- - cdist(7) -- cdist-type-build-emulation(1) +- cdist-type-emulator(1) +- cdist-reference(7) COPYING From 9b3a95e244c4624cdd1c1268a47cf73a842f5a98 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 14 Sep 2011 01:49:00 +0200 Subject: [PATCH 0280/4212] ++logs +beginning of benchmark Signed-off-by: Nico Schottelius --- doc/dev/benchmark-parallel-deploy | 12 ++++++ ...11-09-08 => 2011-09-08.obsolete_debugging} | 0 doc/dev/logs/2011-09-12 | 43 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100755 doc/dev/benchmark-parallel-deploy rename doc/dev/logs/{2011-09-08 => 2011-09-08.obsolete_debugging} (100%) diff --git a/doc/dev/benchmark-parallel-deploy b/doc/dev/benchmark-parallel-deploy new file mode 100755 index 00000000..82d2240c --- /dev/null +++ b/doc/dev/benchmark-parallel-deploy @@ -0,0 +1,12 @@ +#!/bin/sh + +outfile="$1"; shift + +( + for host in "$@"; do + hosts="$hosts $host" + cdist config -c ~/p/cdist-nutzung -p $hosts + done +) | tee "$outfile" +echo "----------" +grep 'INFO: Total processing time for' "$outfile" | sed 's/.*: //' diff --git a/doc/dev/logs/2011-09-08 b/doc/dev/logs/2011-09-08.obsolete_debugging similarity index 100% rename from doc/dev/logs/2011-09-08 rename to doc/dev/logs/2011-09-08.obsolete_debugging diff --git a/doc/dev/logs/2011-09-12 b/doc/dev/logs/2011-09-12 index 391b836f..1ace466f 100644 --- a/doc/dev/logs/2011-09-12 +++ b/doc/dev/logs/2011-09-12 @@ -65,3 +65,46 @@ Use: # Scale linearly with the single host value plot((1:31)*times(1)) +-------------------------------------------------------------------------------- +code: + +octave +time = [ +72.166661 +76.633228 +77.199817 +94.045175 +103.226354 +107.76097 +101.571705 +107.600093 +116.500371 +119.445805 +123.944385 +130.499098 +137.250861 +154.9841 +139.659637 +142.70005 +148.541452 +159.360809 +171.907864 +178.76695 +183.856671 +194.504221 +207.314842 +215.846502 +217.223581 +238.591705 +238.478493 +246.058718 +264.208372 +265.560685 +282.264488 +] +plot(times, "-;cdist;", times(1)*[1:length(times)]', "-;linear;") +title("Configuration duration (cdist-2.0.0-rc4)") +ylabel("Number of hosts") +xlabel("Time in seconds") +print('cdist-2.0.0-rc4.png', '-dpng') + From 03e312dcb7de0da7a24a185150fd0870bc07e054 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 14 Sep 2011 01:50:18 +0200 Subject: [PATCH 0281/4212] use shutil.move() instead of os.rename() to avoid OSError: [Errno 18] Invalid cross-device link Signed-off-by: Nico Schottelius --- bin/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 21a35c22..92161908 100755 --- a/bin/cdist +++ b/bin/cdist @@ -157,7 +157,7 @@ class Cdist: # Remove previous cache if os.path.exists(self.cache_dir): shutil.rmtree(self.cache_dir) - os.rename(self.temp_dir, self.cache_dir) + shutil.move(self.temp_dir, self.cache_dir) def exit_error(self, *args): log.error(*args) From b76c4a5105d21cc76caa9d4ecf3980e1afe6bfc5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 14 Sep 2011 08:45:55 +0200 Subject: [PATCH 0282/4212] make shell exec error and normal error look the same for easier grepping in logfiles Signed-off-by: Nico Schottelius --- bin/cdist | 2 +- doc/dev/benchmark-parallel-deploy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 92161908..f7ad2f72 100755 --- a/bin/cdist +++ b/bin/cdist @@ -197,7 +197,7 @@ class Cdist: print(script_fd.read()) script_fd.close() - self.exit_error("Non-Zero exit code exit of " + " ".join(*args)) + self.exit_error("Command failed (shell): " + " ".join(*args)) def run_or_fail(self, *args, **kargs): if "remote" in kargs: diff --git a/doc/dev/benchmark-parallel-deploy b/doc/dev/benchmark-parallel-deploy index 82d2240c..0e7c4a2f 100755 --- a/doc/dev/benchmark-parallel-deploy +++ b/doc/dev/benchmark-parallel-deploy @@ -5,7 +5,7 @@ outfile="$1"; shift ( for host in "$@"; do hosts="$hosts $host" - cdist config -c ~/p/cdist-nutzung -p $hosts + cdist config -c ~/p/cdist-nutzung -p $hosts 2>&1 done ) | tee "$outfile" echo "----------" From 1f9ae130779903302d3bf56929c25a515f75b279 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 12:09:22 +0200 Subject: [PATCH 0283/4212] only the core is python, not the manifests Signed-off-by: Nico Schottelius --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 3e00b497..5e60a093 100644 --- a/README +++ b/README @@ -111,7 +111,7 @@ how to use cdist. There are at least the following branches available: * Development: master - * 2.0: Python rewrite + * 2.0: Python rewrite of cdist core Old versions: From b6738aaf60054beecdca9105250c80d51ebfb338 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 16 Sep 2011 12:19:09 +0200 Subject: [PATCH 0284/4212] rename __cinst_partition_msdos __partition_msdos Signed-off-by: Steven Armstrong --- .../gencode-remote | 0 .../man.text | 27 ++++++++++--------- .../manifest | 0 .../parameter/optional | 0 .../parameter/required | 0 5 files changed, 14 insertions(+), 13 deletions(-) rename conf/type/{__cinst_partition_msdos => __partition_msdos}/gencode-remote (100%) rename conf/type/{__cinst_partition_msdos => __partition_msdos}/man.text (59%) rename conf/type/{__cinst_partition_msdos => __partition_msdos}/manifest (100%) rename conf/type/{__cinst_partition_msdos => __partition_msdos}/parameter/optional (100%) rename conf/type/{__cinst_partition_msdos => __partition_msdos}/parameter/required (100%) diff --git a/conf/type/__cinst_partition_msdos/gencode-remote b/conf/type/__partition_msdos/gencode-remote similarity index 100% rename from conf/type/__cinst_partition_msdos/gencode-remote rename to conf/type/__partition_msdos/gencode-remote diff --git a/conf/type/__cinst_partition_msdos/man.text b/conf/type/__partition_msdos/man.text similarity index 59% rename from conf/type/__cinst_partition_msdos/man.text rename to conf/type/__partition_msdos/man.text index 2203c2d3..611451ed 100644 --- a/conf/type/__cinst_partition_msdos/man.text +++ b/conf/type/__partition_msdos/man.text @@ -1,11 +1,11 @@ -cdist-type__cinst_partition_msdos(7) -==================================== +cdist-type__partition_msdos(7) +============================== Steven Armstrong NAME ---- -cdist-type__cinst_partition_msdos - creates msdos partitions +cdist-type__partition_msdos - creates msdos partitions DESCRIPTION @@ -24,13 +24,12 @@ OPTIONAL PARAMETERS device:: defaults to object_id bootable:: - mark partition as bootable, true or false + mark partition as bootable, true or false, defaults to false size:: - the size of the partition (such as 32MB or 15GB, whole numbers + the size of the partition (such as 32M or 15G, whole numbers only), '+' for remaining space, or 'n%' for percentage of remaining (these should only be used after all specific partition sizes are - specified), leave blank if type is "extended". - Defaults to +. + specified). Defaults to +. EXAMPLES @@ -38,17 +37,19 @@ EXAMPLES -------------------------------------------------------------------------------- # 128MB linux, bootable -__cinst_partition_msdos /dev/sda1 --type 83 --size 128M --bootable true +__partition_msdos /dev/sda1 --type 83 --size 128M --bootable true # 512MB swap -__cinst_partition_msdos /dev/sda2 --type 82 --size 512M +__partition_msdos /dev/sda2 --type 82 --size 512M # extended -__cinst_partition_msdos /dev/sda3 --type extended +__partition_msdos /dev/sda3 --type extended --size 100G # 10GB, linux -__cinst_partition_msdos /dev/sda5 --type 82 --size 10G +__partition_msdos /dev/sda5 --type 83 --size 10G +# 50% of free space, linux +__partition_msdos /dev/sda6 --type 83 --size 50% # rest of disk, linux -__cinst_partition_msdos /dev/sda6 --type 82 --size + +__partition_msdos /dev/sda7 --type 83 --size + # same thing as -__cinst_partition_msdos /dev/sda6 --type 82 +__partition_msdos /dev/sda7 --type 83 -------------------------------------------------------------------------------- diff --git a/conf/type/__cinst_partition_msdos/manifest b/conf/type/__partition_msdos/manifest similarity index 100% rename from conf/type/__cinst_partition_msdos/manifest rename to conf/type/__partition_msdos/manifest diff --git a/conf/type/__cinst_partition_msdos/parameter/optional b/conf/type/__partition_msdos/parameter/optional similarity index 100% rename from conf/type/__cinst_partition_msdos/parameter/optional rename to conf/type/__partition_msdos/parameter/optional diff --git a/conf/type/__cinst_partition_msdos/parameter/required b/conf/type/__partition_msdos/parameter/required similarity index 100% rename from conf/type/__cinst_partition_msdos/parameter/required rename to conf/type/__partition_msdos/parameter/required From 88c1be4b1b0caa38e4d9b6fc72b2c30d62cc96f4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 13:00:02 +0200 Subject: [PATCH 0285/4212] add benchmark results Signed-off-by: Nico Schottelius --- ...011-09-16.benchmark-r815-no-control-socket | 63 + ...benchmark-r815-no-control-socket.dmidecode | 1373 +++++++++++++++++ 2 files changed, 1436 insertions(+) create mode 100644 doc/dev/logs/2011-09-16.benchmark-r815-no-control-socket create mode 100644 doc/dev/logs/2011-09-16.benchmark-r815-no-control-socket.dmidecode diff --git a/doc/dev/logs/2011-09-16.benchmark-r815-no-control-socket b/doc/dev/logs/2011-09-16.benchmark-r815-no-control-socket new file mode 100644 index 00000000..315ebf75 --- /dev/null +++ b/doc/dev/logs/2011-09-16.benchmark-r815-no-control-socket @@ -0,0 +1,63 @@ +48 core +model name : AMD Opteron(tm) Processor 6174 +128 GB RAM +Dell PowerEdge R815 + +root@sgs-r815-01:~/cdist-nutzung# grep "Total processing time for" deploy-all-benchmark-noikr13 +INFO: Total processing time for 1 host(s): 257.641541 +INFO: Total processing time for 2 host(s): 257.025783 +INFO: Total processing time for 3 host(s): 258.933088 +INFO: Total processing time for 4 host(s): 259.253074 +INFO: Total processing time for 5 host(s): 260.331896 +INFO: Total processing time for 6 host(s): 262.051349 +INFO: Total processing time for 7 host(s): 323.820878 +INFO: Total processing time for 8 host(s): 329.081856 +INFO: Total processing time for 9 host(s): 333.346278 +INFO: Total processing time for 10 host(s): 334.832419 +INFO: Total processing time for 11 host(s): 330.572375 +INFO: Total processing time for 12 host(s): 331.726628 +INFO: Total processing time for 13 host(s): 331.740591 +INFO: Total processing time for 14 host(s): 331.237139 +INFO: Total processing time for 15 host(s): 331.718861 +INFO: Total processing time for 16 host(s): 332.374645 +INFO: Total processing time for 17 host(s): 331.510445 +INFO: Total processing time for 18 host(s): 332.030743 +INFO: Total processing time for 19 host(s): 332.193198 +INFO: Total processing time for 20 host(s): 333.933765 +INFO: Total processing time for 21 host(s): 335.292953 +INFO: Total processing time for 22 host(s): 337.253608 +INFO: Total processing time for 23 host(s): 337.831493 +INFO: Total processing time for 24 host(s): 339.024737 +INFO: Total processing time for 25 host(s): 343.515044 +INFO: Total processing time for 26 host(s): 339.759678 +INFO: Total processing time for 27 host(s): 339.378998 +INFO: Total processing time for 28 host(s): 339.640378 +INFO: Total processing time for 29 host(s): 340.885614 +INFO: Total processing time for 30 host(s): 341.836923 +INFO: Total processing time for 31 host(s): 343.825758 +INFO: Total processing time for 32 host(s): 344.176089 +INFO: Total processing time for 33 host(s): 345.408518 +INFO: Total processing time for 34 host(s): 347.15322 +INFO: Total processing time for 35 host(s): 351.330649 +INFO: Total processing time for 36 host(s): 347.640758 +INFO: Total processing time for 37 host(s): 347.381126 +INFO: Total processing time for 38 host(s): 347.053406 +INFO: Total processing time for 39 host(s): 347.453166 +INFO: Total processing time for 40 host(s): 347.84804 +INFO: Total processing time for 41 host(s): 349.035272 +INFO: Total processing time for 42 host(s): 349.41507 +INFO: Total processing time for 43 host(s): 351.208072 +INFO: Total processing time for 44 host(s): 351.788401 +INFO: Total processing time for 45 host(s): 351.730259 +INFO: Total processing time for 46 host(s): 515.693497 +INFO: Total processing time for 47 host(s): 352.702677 +INFO: Total processing time for 48 host(s): 353.418003 +INFO: Total processing time for 49 host(s): 355.07111 +INFO: Total processing time for 50 host(s): 354.622388 +INFO: Total processing time for 51 host(s): 355.192521 +INFO: Total processing time for 52 host(s): 355.283238 +INFO: Total processing time for 53 host(s): 358.112329 +INFO: Total processing time for 54 host(s): 357.717426 +INFO: Total processing time for 55 host(s): 357.748707 +INFO: Total processing time for 56 host(s): 358.902118 +INFO: Total processing time for 57 host(s): 367.817594 diff --git a/doc/dev/logs/2011-09-16.benchmark-r815-no-control-socket.dmidecode b/doc/dev/logs/2011-09-16.benchmark-r815-no-control-socket.dmidecode new file mode 100644 index 00000000..f96db8b3 --- /dev/null +++ b/doc/dev/logs/2011-09-16.benchmark-r815-no-control-socket.dmidecode @@ -0,0 +1,1373 @@ +# dmidecode 2.9 +SMBIOS 2.6 present. +101 structures occupying 5955 bytes. +Table at 0xDF79C000. + +Handle 0xDA00, DMI type 218, 11 bytes +OEM-specific Type + Header and Data: + DA 0B 00 DA B0 00 17 00 0E 20 00 + +Handle 0x0000, DMI type 0, 24 bytes +BIOS Information + Vendor: Dell Inc. + Version: 1.0.0 + Release Date: 04/08/2010 + Address: 0xF0000 + Runtime Size: 64 kB + ROM Size: 4096 kB + Characteristics: + ISA is supported + PCI is supported + PNP is supported + BIOS is upgradeable + BIOS shadowing is allowed + Boot from CD is supported + Selectable boot is supported + EDD is supported + Japanese floppy for Toshiba 1.2 MB is supported (int 13h) + 5.25"/360 KB floppy services are supported (int 13h) + 5.25"/1.2 MB floppy services are supported (int 13h) + 3.5"/720 KB floppy services are supported (int 13h) + 8042 keyboard services are supported (int 9h) + Serial services are supported (int 14h) + CGA/mono video services are supported (int 10h) + ACPI is supported + USB legacy is supported + BIOS boot specification is supported + Function key-initiated network boot is supported + Targeted content distribution is supported + BIOS Revision: 1.0 + +Handle 0x0100, DMI type 1, 27 bytes +System Information + Manufacturer: Dell Inc. + Product Name: PowerEdge R815 + Version: Not Specified + Serial Number: HYGTS4J + UUID: 44454C4C-5900-1047-8054-C8C04F53344A + Wake-up Type: Power Switch + SKU Number: Not Specified + Family: Not Specified + +Handle 0x0200, DMI type 2, 9 bytes +Base Board Information + Manufacturer: Dell Inc. + Product Name: 06JC9T + Version: A00 + Serial Number: ..CN7475104Q0184. + +Handle 0x0300, DMI type 3, 21 bytes +Chassis Information + Manufacturer: Dell Inc. + Type: Rack Mount Chassis + Lock: Present + Version: Not Specified + Serial Number: HYGTS4J + Asset Tag: Not Specified + Boot-up State: Safe + Power Supply State: Safe + Thermal State: Safe + Security Status: Unknown + OEM Information: 0x00000000 + Height: 2 U + Number Of Power Cords: Unspecified + Contained Elements: 0 + +Handle 0x0400, DMI type 4, 40 bytes +Processor Information + Socket Designation: CPU1 + Type: Central Processor + Family: + Manufacturer: AMD + ID: 91 0F 10 00 FF FB 8B 17 + Version: AMD Opteron(tm) Processor 6174 + Voltage: 1.1 V + External Clock: 3200 MHz + Max Speed: 3600 MHz + Current Speed: 2200 MHz + Status: Populated, Enabled + Upgrade: + L1 Cache Handle: 0x0700 + L2 Cache Handle: 0x0701 + L3 Cache Handle: 0x0702 + Serial Number: Not Specified + Asset Tag: Not Specified + Part Number: Not Specified + Core Count: 12 + Core Enabled: 12 + Thread Count: 12 + Characteristics: + 64-bit capable + +Handle 0x0401, DMI type 4, 40 bytes +Processor Information + Socket Designation: CPU2 + Type: Central Processor + Family: + Manufacturer: AMD + ID: 91 0F 10 00 FF FB 8B 17 + Version: AMD Opteron(tm) Processor 6174 + Voltage: 1.1 V + External Clock: 3200 MHz + Max Speed: 3600 MHz + Current Speed: 2200 MHz + Status: Populated, Idle + Upgrade: + L1 Cache Handle: 0x0703 + L2 Cache Handle: 0x0704 + L3 Cache Handle: 0x0705 + Serial Number: Not Specified + Asset Tag: Not Specified + Part Number: Not Specified + Core Count: 12 + Core Enabled: 12 + Thread Count: 12 + Characteristics: + 64-bit capable + +Handle 0x0402, DMI type 4, 40 bytes +Processor Information + Socket Designation: CPU3 + Type: Central Processor + Family: + Manufacturer: AMD + ID: 91 0F 10 00 FF FB 8B 17 + Version: AMD Opteron(tm) Processor 6174 + Voltage: 1.1 V + External Clock: 3200 MHz + Max Speed: 3600 MHz + Current Speed: 2200 MHz + Status: Populated, Idle + Upgrade: + L1 Cache Handle: 0x0706 + L2 Cache Handle: 0x0707 + L3 Cache Handle: 0x0708 + Serial Number: Not Specified + Asset Tag: Not Specified + Part Number: Not Specified + Core Count: 12 + Core Enabled: 12 + Thread Count: 12 + Characteristics: + 64-bit capable + +Handle 0x0403, DMI type 4, 40 bytes +Processor Information + Socket Designation: CPU4 + Type: Central Processor + Family: + Manufacturer: AMD + ID: 91 0F 10 00 FF FB 8B 17 + Version: AMD Opteron(tm) Processor 6174 + Voltage: 1.1 V + External Clock: 3200 MHz + Max Speed: 3600 MHz + Current Speed: 2200 MHz + Status: Populated, Idle + Upgrade: + L1 Cache Handle: 0x0709 + L2 Cache Handle: 0x070A + L3 Cache Handle: 0x070B + Serial Number: Not Specified + Asset Tag: Not Specified + Part Number: Not Specified + Core Count: 12 + Core Enabled: 12 + Thread Count: 12 + Characteristics: + 64-bit capable + +Handle 0x0700, DMI type 7, 19 bytes +Cache Information + Socket Designation: Not Specified + Configuration: Enabled, Not Socketed, Level 1 + Operational Mode: Write Back + Location: Internal + Installed Size: 768 KB + Maximum Size: 768 KB + Supported SRAM Types: + Unknown + Installed SRAM Type: Unknown + Speed: Unknown + Error Correction Type: Multi-bit ECC + System Type: Unified + Associativity: 2-way Set-associative + +Handle 0x0701, DMI type 7, 19 bytes +Cache Information + Socket Designation: Not Specified + Configuration: Enabled, Not Socketed, Level 2 + Operational Mode: Write Back + Location: Internal + Installed Size: 6144 KB + Maximum Size: 6144 KB + Supported SRAM Types: + Unknown + Installed SRAM Type: Unknown + Speed: Unknown + Error Correction Type: Multi-bit ECC + System Type: Unified + Associativity: 16-way Set-associative + +Handle 0x0702, DMI type 7, 19 bytes +Cache Information + Socket Designation: Not Specified + Configuration: Enabled, Not Socketed, Level 3 + Operational Mode: Write Back + Location: Internal + Installed Size: 10240 KB + Maximum Size: 10240 KB + Supported SRAM Types: + Unknown + Installed SRAM Type: Unknown + Speed: Unknown + Error Correction Type: Multi-bit ECC + System Type: Unified + Associativity: Other + +Handle 0x0703, DMI type 7, 19 bytes +Cache Information + Socket Designation: Not Specified + Configuration: Enabled, Not Socketed, Level 1 + Operational Mode: Write Back + Location: Internal + Installed Size: 768 KB + Maximum Size: 768 KB + Supported SRAM Types: + Unknown + Installed SRAM Type: Unknown + Speed: Unknown + Error Correction Type: Multi-bit ECC + System Type: Unified + Associativity: 2-way Set-associative + +Handle 0x0704, DMI type 7, 19 bytes +Cache Information + Socket Designation: Not Specified + Configuration: Enabled, Not Socketed, Level 2 + Operational Mode: Write Back + Location: Internal + Installed Size: 6144 KB + Maximum Size: 6144 KB + Supported SRAM Types: + Unknown + Installed SRAM Type: Unknown + Speed: Unknown + Error Correction Type: Multi-bit ECC + System Type: Unified + Associativity: 16-way Set-associative + +Handle 0x0705, DMI type 7, 19 bytes +Cache Information + Socket Designation: Not Specified + Configuration: Enabled, Not Socketed, Level 3 + Operational Mode: Write Back + Location: Internal + Installed Size: 10240 KB + Maximum Size: 10240 KB + Supported SRAM Types: + Unknown + Installed SRAM Type: Unknown + Speed: Unknown + Error Correction Type: Multi-bit ECC + System Type: Unified + Associativity: Other + +Handle 0x0706, DMI type 7, 19 bytes +Cache Information + Socket Designation: Not Specified + Configuration: Enabled, Not Socketed, Level 1 + Operational Mode: Write Back + Location: Internal + Installed Size: 768 KB + Maximum Size: 768 KB + Supported SRAM Types: + Unknown + Installed SRAM Type: Unknown + Speed: Unknown + Error Correction Type: Multi-bit ECC + System Type: Unified + Associativity: 2-way Set-associative + +Handle 0x0707, DMI type 7, 19 bytes +Cache Information + Socket Designation: Not Specified + Configuration: Enabled, Not Socketed, Level 2 + Operational Mode: Write Back + Location: Internal + Installed Size: 6144 KB + Maximum Size: 6144 KB + Supported SRAM Types: + Unknown + Installed SRAM Type: Unknown + Speed: Unknown + Error Correction Type: Multi-bit ECC + System Type: Unified + Associativity: 16-way Set-associative + +Handle 0x0708, DMI type 7, 19 bytes +Cache Information + Socket Designation: Not Specified + Configuration: Enabled, Not Socketed, Level 3 + Operational Mode: Write Back + Location: Internal + Installed Size: 10240 KB + Maximum Size: 10240 KB + Supported SRAM Types: + Unknown + Installed SRAM Type: Unknown + Speed: Unknown + Error Correction Type: Multi-bit ECC + System Type: Unified + Associativity: Other + +Handle 0x0709, DMI type 7, 19 bytes +Cache Information + Socket Designation: Not Specified + Configuration: Enabled, Not Socketed, Level 1 + Operational Mode: Write Back + Location: Internal + Installed Size: 768 KB + Maximum Size: 768 KB + Supported SRAM Types: + Unknown + Installed SRAM Type: Unknown + Speed: Unknown + Error Correction Type: Multi-bit ECC + System Type: Unified + Associativity: 2-way Set-associative + +Handle 0x070A, DMI type 7, 19 bytes +Cache Information + Socket Designation: Not Specified + Configuration: Enabled, Not Socketed, Level 2 + Operational Mode: Write Back + Location: Internal + Installed Size: 6144 KB + Maximum Size: 6144 KB + Supported SRAM Types: + Unknown + Installed SRAM Type: Unknown + Speed: Unknown + Error Correction Type: Multi-bit ECC + System Type: Unified + Associativity: 16-way Set-associative + +Handle 0x070B, DMI type 7, 19 bytes +Cache Information + Socket Designation: Not Specified + Configuration: Enabled, Not Socketed, Level 3 + Operational Mode: Write Back + Location: Internal + Installed Size: 10240 KB + Maximum Size: 10240 KB + Supported SRAM Types: + Unknown + Installed SRAM Type: Unknown + Speed: Unknown + Error Correction Type: Multi-bit ECC + System Type: Unified + Associativity: Other + +Handle 0x0800, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: Not Specified + Internal Connector Type: None + External Reference Designator: Not Specified + External Connector Type: DB-15 female + Port Type: Video Port + +Handle 0x0801, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: Not Specified + Internal Connector Type: None + External Reference Designator: Not Specified + External Connector Type: DB-15 female + Port Type: Video Port + +Handle 0x0802, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: Not Specified + Internal Connector Type: None + External Reference Designator: Not Specified + External Connector Type: Access Bus (USB) + Port Type: USB + +Handle 0x0803, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: Not Specified + Internal Connector Type: None + External Reference Designator: Not Specified + External Connector Type: Access Bus (USB) + Port Type: USB + +Handle 0x0804, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: Not Specified + Internal Connector Type: None + External Reference Designator: Not Specified + External Connector Type: Access Bus (USB) + Port Type: USB + +Handle 0x0805, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: Not Specified + Internal Connector Type: None + External Reference Designator: Not Specified + External Connector Type: Access Bus (USB) + Port Type: USB + +Handle 0x0806, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: Not Specified + Internal Connector Type: None + External Reference Designator: Not Specified + External Connector Type: Access Bus (USB) + Port Type: USB + +Handle 0x0807, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: Not Specified + Internal Connector Type: None + External Reference Designator: Not Specified + External Connector Type: Access Bus (USB) + Port Type: USB + +Handle 0x0808, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: INT_USB + Internal Connector Type: Access Bus (USB) + External Reference Designator: Not Specified + External Connector Type: None + Port Type: USB + +Handle 0x0809, DMI type 126, 9 bytes +Inactive + +Handle 0x080A, DMI type 126, 9 bytes +Inactive + +Handle 0x080B, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: Not Specified + Internal Connector Type: None + External Reference Designator: Not Specified + External Connector Type: RJ-45 + Port Type: Network Port + +Handle 0x080C, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: Not Specified + Internal Connector Type: None + External Reference Designator: Not Specified + External Connector Type: RJ-45 + Port Type: Network Port + +Handle 0x080D, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: Not Specified + Internal Connector Type: None + External Reference Designator: Not Specified + External Connector Type: RJ-45 + Port Type: Network Port + +Handle 0x080E, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: Not Specified + Internal Connector Type: None + External Reference Designator: Not Specified + External Connector Type: RJ-45 + Port Type: Network Port + +Handle 0x080F, DMI type 8, 9 bytes +Port Connector Information + Internal Reference Designator: Not Specified + Internal Connector Type: None + External Reference Designator: Not Specified + External Connector Type: DB-9 male + Port Type: Serial Port 16550A Compatible + +Handle 0x0900, DMI type 9, 17 bytes +System Slot Information + Designation: PCI1 + Type: x8 + Current Usage: Available + Length: Long + Characteristics: + 3.3 V is provided + PME signal is supported + +Handle 0x0901, DMI type 9, 17 bytes +System Slot Information + Designation: PCI2 + Type: x4 + Current Usage: Available + Length: Short + Characteristics: + 3.3 V is provided + PME signal is supported + +Handle 0x0902, DMI type 9, 17 bytes +System Slot Information + Designation: PCI3 + Type: x8 + Current Usage: Available + Length: Short + Characteristics: + 3.3 V is provided + PME signal is supported + +Handle 0x0903, DMI type 9, 17 bytes +System Slot Information + Designation: PCI4 + Type: x8 + Current Usage: Available + Length: Short + Characteristics: + 3.3 V is provided + PME signal is supported + +Handle 0x0904, DMI type 9, 17 bytes +System Slot Information + Designation: PCI5 + Type: x8 + Current Usage: Available + Length: Long + Characteristics: + 3.3 V is provided + PME signal is supported + +Handle 0x0905, DMI type 9, 17 bytes +System Slot Information + Designation: PCI6 + Type: x8 + Current Usage: Available + Length: Long + Characteristics: + 3.3 V is provided + PME signal is supported + +Handle 0x0A00, DMI type 10, 16 bytes +On Board Device 1 Information + Type: Video + Status: Enabled + Description: Embedded Matrox G200 Video +On Board Device 2 Information + Type: Ethernet + Status: Enabled + Description: Embedded Broadcom 5709C NIC 1 +On Board Device 3 Information + Type: Ethernet + Status: Enabled + Description: Embedded Broadcom 5709C NIC 2 +On Board Device 4 Information + Type: Ethernet + Status: Enabled + Description: Embedded Broadcom 5709C NIC 3 +On Board Device 5 Information + Type: Ethernet + Status: Enabled + Description: Embedded Broadcom 5709C NIC 4 +On Board Device 6 Information + Type: SAS Controller + Status: Enabled + Description: Integrated SAS Controller + +Handle 0x0B00, DMI type 11, 5 bytes +OEM Strings + String 1: Dell System + String 2: 5[0000] + +Handle 0x7E00, DMI type 126, 154 bytes +Inactive + +Handle 0x0C00, DMI type 12, 5 bytes +System Configuration Options + Option 1: NVRAM_CLR: Clear user settable NVRAM areas and set defaults + Option 2: PWRD_EN: Close to enable password + +Handle 0x0D00, DMI type 13, 22 bytes +BIOS Language Information + Installable Languages: 1 + en|US|iso8859-1 + Currently Installed Language: en|US|iso8859-1 + +Handle 0x1000, DMI type 16, 15 bytes +Physical Memory Array + Location: System Board Or Motherboard + Use: System Memory + Error Correction Type: Multi-bit ECC + Maximum Capacity: 256 GB + Error Information Handle: Not Provided + Number Of Devices: 32 + +Handle 0x1100, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 1 + Locator: DIMM_A1 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBE6 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1101, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 1 + Locator: DIMM_A2 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBC6 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1102, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 2 + Locator: DIMM_A3 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBFF + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1103, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 2 + Locator: DIMM_A4 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFC05 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1104, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 3 + Locator: DIMM_A5 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBB0 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1105, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 3 + Locator: DIMM_A6 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBED + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1106, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 4 + Locator: DIMM_A7 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFC06 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1107, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 4 + Locator: DIMM_A8 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBF7 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1108, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 5 + Locator: DIMM_B1 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFB92 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1109, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 5 + Locator: DIMM_B2 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBF4 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x110A, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 6 + Locator: DIMM_B3 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBC7 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x110B, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 6 + Locator: DIMM_B4 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFC26 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x110C, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 7 + Locator: DIMM_B5 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBE4 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x110D, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 7 + Locator: DIMM_B6 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBA4 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x110E, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 8 + Locator: DIMM_B7 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBB6 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x110F, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 8 + Locator: DIMM_B8 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFB0D + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1110, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 9 + Locator: DIMM_C1 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFC37 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1111, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 9 + Locator: DIMM_C2 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFC23 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1112, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 10 + Locator: DIMM_C3 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFB0E + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1113, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 10 + Locator: DIMM_C4 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFB04 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1114, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 11 + Locator: DIMM_C5 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBF6 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1115, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 11 + Locator: DIMM_C6 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFC21 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1116, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 12 + Locator: DIMM_C7 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFC28 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1117, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 12 + Locator: DIMM_C8 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBAC + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1118, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 13 + Locator: DIMM_D1 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBCD + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1119, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 13 + Locator: DIMM_D2 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBBD + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x111A, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 14 + Locator: DIMM_D3 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFAD0 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x111B, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 14 + Locator: DIMM_D4 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBBC + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x111C, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 15 + Locator: DIMM_D5 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFB2A + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x111D, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 15 + Locator: DIMM_D6 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBEB + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x111E, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 16 + Locator: DIMM_D7 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFADB + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x111F, DMI type 17, 28 bytes +Memory Device + Array Handle: 0x1000 + Error Information Handle: Not Provided + Total Width: 72 bits + Data Width: 64 bits + Size: 4096 MB + Form Factor: DIMM + Set: 16 + Locator: DIMM_D8 + Bank Locator: Not Specified + Type: + Type Detail: Synchronous + Speed: 1333 MHz (0.8 ns) + Manufacturer: 80CE80B380CE + Serial Number: 851CFBC9 + Asset Tag: 02101861 + Part Number: M393B5170EH1-CH9 + +Handle 0x1300, DMI type 19, 15 bytes +Memory Array Mapped Address + Starting Address: 0x00000000000 + Ending Address: 0x000DFFFFFFF + Range Size: 3584 MB + Physical Array Handle: 0x1000 + Partition Width: 0 + +Handle 0x1301, DMI type 19, 15 bytes +Memory Array Mapped Address + Starting Address: 0x00100000000 + Ending Address: 0x0201FFFFFFF + Range Size: 127488 MB + Physical Array Handle: 0x1000 + Partition Width: 0 + +Handle 0x2000, DMI type 32, 11 bytes +System Boot Information + Status: No errors detected + +Handle 0x2600, DMI type 38, 18 bytes +IPMI Device Information + Interface Type: KCS (Keyboard Control Style) + Specification Version: 2.0 + I2C Slave Address: 0x10 + NV Storage Device: Not Present + Base Address: 0x0000000000000CA8 (I/O) + Register Spacing: 32-bit Boundaries + +Handle 0x2900, DMI type 41, 11 bytes +Unknown Type + Header and Data: + 29 0B 00 29 01 85 01 00 00 01 00 + Strings: + Embedded NIC 1 + +Handle 0x2901, DMI type 41, 11 bytes +Unknown Type + Header and Data: + 29 0B 01 29 01 85 02 00 00 01 01 + Strings: + Embedded NIC 2 + +Handle 0x2902, DMI type 41, 11 bytes +Unknown Type + Header and Data: + 29 0B 02 29 01 85 03 00 00 02 00 + Strings: + Embedded NIC 3 + +Handle 0x2903, DMI type 41, 11 bytes +Unknown Type + Header and Data: + 29 0B 03 29 01 85 04 00 00 02 01 + Strings: + Embedded NIC 4 + +Handle 0x2904, DMI type 41, 11 bytes +Unknown Type + Header and Data: + 29 0B 04 29 01 8A 04 00 00 05 00 + Strings: + Integrated SAS + +Handle 0x2905, DMI type 126, 11 bytes +Inactive + +Handle 0x2906, DMI type 41, 11 bytes +Unknown Type + Header and Data: + 29 0B 06 29 01 83 04 00 00 0A 18 + Strings: + Embedded Video + +Handle 0xD000, DMI type 208, 16 bytes +OEM-specific Type + Header and Data: + D0 10 00 D0 02 00 FE 00 44 04 00 00 01 01 00 00 + +Handle 0xD200, DMI type 210, 12 bytes +OEM-specific Type + Header and Data: + D2 0C 00 D2 F8 03 04 03 06 80 04 05 + +Handle 0xD400, DMI type 212, 127 bytes +OEM-specific Type + Header and Data: + D4 7F 00 D4 70 00 71 00 00 10 2D 2E 42 00 11 FE + 01 43 00 11 FE 00 70 01 11 9F 20 6F 01 11 9F 00 + 00 00 11 9F 20 00 00 11 9F 00 31 40 11 FB 00 32 + 40 11 FB 04 9D 00 11 FD 02 9E 00 11 FD 00 9F 00 + 26 FE 01 A0 00 26 FE 00 28 40 26 DF 20 29 40 26 + DF 00 38 02 27 BF 40 39 02 27 BF 00 F1 01 27 FC + 01 F2 01 27 FC 02 F3 01 27 FC 03 F5 01 27 F3 04 + F6 01 27 F3 08 F7 01 27 F3 0C FF FF 00 00 00 + +Handle 0xD401, DMI type 212, 252 bytes +OEM-specific Type + Header and Data: + D4 FC 01 D4 70 00 71 00 03 40 5A 6D 5C 00 78 BF + 40 5D 00 78 BF 00 6C 01 57 FC 00 6B 01 57 FC 01 + 6A 01 57 FC 02 12 02 57 EF 00 11 02 57 EF 10 00 + 00 5B FB 04 00 00 5B FB 00 77 01 54 FC 00 78 01 + 54 FC 01 79 01 54 FC 02 7A 01 54 FC 03 33 40 54 + CF 00 34 40 54 CF 10 35 40 54 CF 20 36 40 54 CF + 30 1A 40 54 FB 04 1B 40 54 FB 00 1C 40 54 F7 08 + 1D 40 54 F7 00 43 40 58 DF 20 42 40 58 DF 00 24 + 40 58 BF 40 25 40 58 BF 00 6E 00 58 FC 01 2D 00 + 58 FC 02 DA 01 58 FC 03 22 40 58 EF 10 23 40 58 + EF 00 BB 00 58 F3 04 BC 00 58 F3 08 DB 01 58 F3 + 0C 2D 02 55 FE 01 2E 02 55 FE 00 D8 00 55 7F 80 + D9 00 55 7F 00 54 02 56 DF 00 57 02 56 DF 20 4D + 02 56 BF 00 4E 02 56 BF 40 2D 01 56 7F 80 2E 01 + 56 7F 00 00 C0 5C 00 0A 03 C0 67 00 05 83 00 76 + 00 00 84 00 77 00 00 FF FF 00 00 00 + +Handle 0xD402, DMI type 212, 177 bytes +OEM-specific Type + Header and Data: + D4 B1 02 D4 72 00 73 00 00 C0 DD DE D3 00 80 00 + 02 D4 00 82 00 02 D5 00 84 00 02 D6 00 86 00 02 + 4A 01 C6 BF 40 4B 01 C6 BF 00 00 90 AC 00 00 01 + 90 AD 00 00 00 00 C9 EB 14 00 00 C9 EF 10 DA 00 + C9 FB 04 00 00 C9 EB 00 00 00 C9 7F 00 00 00 C9 + 7F 80 CA 00 C9 FC 00 CB 00 C9 FC 01 00 00 C9 FC + 02 DE 00 E3 FE 01 26 40 C2 FE 01 27 40 C2 FE 00 + 17 01 CA FE 00 18 01 CA FE 01 00 00 CA FD 00 00 + 00 CA FD 02 35 01 CB FC 00 37 01 CB FC 01 02 40 + C6 DF 00 01 40 C6 DF 20 FC 01 C5 BF 00 FD 01 C5 + BF 40 00 00 C5 7F 80 00 00 C5 7F 00 FF FF 00 00 + 00 + +Handle 0xD403, DMI type 212, 132 bytes +OEM-specific Type + Header and Data: + D4 84 03 D4 72 00 73 00 00 C0 DD DE 32 02 C0 07 + 10 31 02 C0 07 20 6F 02 C0 07 30 70 02 C0 07 40 + 71 02 C0 07 50 72 02 C0 07 60 6E 02 C0 07 00 00 + 00 C6 FE 00 00 00 C6 FE 01 40 01 C7 EF 10 41 01 + C7 EF 00 C4 01 D0 FE 00 C5 01 D0 FE 01 73 01 D0 + BF 40 74 01 D0 BF 00 AB 02 D0 DF 20 AC 02 D0 DF + 00 A9 02 D0 EF 10 AA 02 D0 EF 00 6A 02 DB FE 00 + 6B 02 DB FE 01 7B 02 DB FD 00 7C 02 DB FD 02 FF + FF 00 00 00 + +Handle 0xD800, DMI type 216, 9 bytes +OEM-specific Type + Header and Data: + D8 09 00 D8 01 02 01 00 00 + Strings: + MATROX + VGA/VBE BIOS, Version V3.8WO + +Handle 0xDE00, DMI type 222, 16 bytes +OEM-specific Type + Header and Data: + DE 10 00 DE 01 08 FF FF 00 00 00 00 00 00 00 01 + +Handle 0x7F00, DMI type 127, 4 bytes +End Of Table + From 7c566309246bba675f17f82378cd596f53ecd5cc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 13:13:56 +0200 Subject: [PATCH 0286/4212] prepare installation routine Signed-off-by: Nico Schottelius --- bin/cdist | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/bin/cdist b/bin/cdist index f7ad2f72..49985c01 100755 --- a/bin/cdist +++ b/bin/cdist @@ -604,6 +604,10 @@ def banner(args): print(BANNER) sys.exit(0) +def install(args): + """Install remote system""" + process = {} + def config(args): """Configure remote system""" process = {} @@ -648,25 +652,33 @@ if __name__ == "__main__": add_help=False) parser['banner'].set_defaults(func=banner) - # Config - parser['config'] = parser['sub'].add_parser('config', - parents=[parser['most']]) - parser['config'].add_argument('host', nargs='+', + # Config and install (common stuff) + parser['configinstall'] = argparse.ArgumentParser(add_help=False) + parser['configinstall'].add_argument('host', nargs='+', help='one or more hosts to operate on') - parser['config'].add_argument('-c', '--cdist-home', + parser['configinstall'].add_argument('-c', '--cdist-home', help='Change cdist home (default: .. from bin directory)', action='store') - parser['config'].add_argument('-i', '--initial-manifest', + parser['configinstall'].add_argument('-i', '--initial-manifest', help='Path to a cdist manifest', dest='manifest', required=False) - parser['config'].add_argument('-p', '--parallel', + parser['configinstall'].add_argument('-p', '--parallel', help='Operate on multiple hosts in parallel', action='store_true', dest='parallel') - parser['config'].add_argument('-s', '--sequential', + parser['configinstall'].add_argument('-s', '--sequential', help='Operate on multiple hosts sequentially (default)', action='store_false', dest='parallel') + + # Config + parser['config'] = parser['sub'].add_parser('config', + parents=[parser['most'], parser['configinstall']]) parser['config'].set_defaults(func=config) + # Install + parser['install'] = parser['sub'].add_parser('install', + parents=[parser['most'], 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/" From b2546fb236c1608a3d01840992d5330a0959b35f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 13:24:40 +0200 Subject: [PATCH 0287/4212] split deploy to into two stages Signed-off-by: Nico Schottelius --- bin/cdist | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index 49985c01..a4570a34 100755 --- a/bin/cdist +++ b/bin/cdist @@ -555,10 +555,8 @@ class Cdist: self.transfer_file(local_remote_code, remote_remote_code) self.run_or_fail([remote_remote_code], remote=True) - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to " + self.target_host) - time_start = datetime.datetime.now() + def stage_prepare(self): + """Do everything for a deploy, minus the actual code stage""" self.init_deploy() self.run_global_explores() self.run_initial_manifest() @@ -580,14 +578,24 @@ class Cdist: self.objects_prepared.append(cdist_object) objects = self.list_objects() - + + def stage_run(self): + """The final (and real) step of deployment""" log.debug("Actual run objects") # Now do the final steps over the existing objects - for cdist_object in objects: + for cdist_object in self.list_objects(): log.debug("Run object: %s", cdist_object) self.object_run(cdist_object, mode="gencode") self.object_run(cdist_object, mode="code") + def deploy_to(self): + """Mimic the old deploy to: Deploy to one host""" + log.info("Deploying to " + self.target_host) + time_start = datetime.datetime.now() + + self.stage_prepare() + self.stage_run() + time_end = datetime.datetime.now() duration = time_end - time_start log.info("Finished run of %s in %s seconds", From 182074bb9d2908cdd16b2ce8d70fd4797843058a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 13:34:10 +0200 Subject: [PATCH 0288/4212] remove unused type template (to be reimported, if someone has a use for it) Signed-off-by: Nico Schottelius --- bin/cdist-type-template | 83 --------------------------- doc/man/man1/cdist-type-template.text | 30 ---------- 2 files changed, 113 deletions(-) delete mode 100755 bin/cdist-type-template delete mode 100644 doc/man/man1/cdist-type-template.text diff --git a/bin/cdist-type-template b/bin/cdist-type-template deleted file mode 100755 index 6d8a3f15..00000000 --- a/bin/cdist-type-template +++ /dev/null @@ -1,83 +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 . -# -# -# Create a new type from scratch -# - -. cdist-config -[ $# -eq 1 ] || __cdist_usage "" -set -eu - -__cdist_type="$1"; shift -__cdist_my_type_dir="$(__cdist_type_dir "$__cdist_type")" - -if [ -d "$__cdist_my_type_dir" ]; then - __cdist_usage "Type $__cdist_type already exists" -fi - -echo "Creating type $__cdist_type in $__cdist_my_type_dir ..." -# Base -mkdir -p "$__cdist_my_type_dir" - -# Parameter -mkdir -p "$(__cdist_type_parameter_dir "$__cdist_type")" -touch "$(__cdist_type_parameter_dir "$__cdist_type")/${__cdist_name_parameter_required}" -touch "$(__cdist_type_parameter_dir "$__cdist_type")/${__cdist_name_parameter_optional}" - -# Manifest -cat "$__cdist_abs_mydir/../doc/dev/header" - << eof > "$__cdist_my_type_dir/${__cdist_name_manifest}" - -# -# This is the manifest, which can be used to create other objects like this: -# __file /path/to/destination --source /from/where/ -# -# To tell cdist to make use of it, you need to make it executable (chmod +x) -# -# - -eof - -# Gencode remote -cat "$__cdist_abs_mydir/../doc/dev/header" - << eof > "$(__cdist_type_dir "$__cdist_type")/${__cdist_name_gencode}-${__cdist_name_gencode_remote}" - -# -# This file should generate code on stdout, which will be collected by cdist -# and run on the target. -# -# To tell cdist to make use of it, you need to make it executable (chmod +x) -# -# - -eof - -cat "$__cdist_abs_mydir/../doc/dev/header" - << eof > "$(__cdist_type_dir "$__cdist_type")/${__cdist_name_gencode}-${__cdist_name_gencode_local}" - -# -# This file should generate code on stdout, which will be collected by cdist -# and run on the same machine cdist-deploy-to is executed. -# -# To tell cdist to make use of it, you need to make it executable (chmod +x) -# -# - -eof - -# Explorer -mkdir -p "$__cdist_my_type_dir/${__cdist_name_explorer}" diff --git a/doc/man/man1/cdist-type-template.text b/doc/man/man1/cdist-type-template.text deleted file mode 100644 index bbd31409..00000000 --- a/doc/man/man1/cdist-type-template.text +++ /dev/null @@ -1,30 +0,0 @@ -cdist-type-template(1) -====================== -Nico Schottelius - - -NAME ----- -cdist-type-template - Create a new type - - -SYNOPSIS --------- -cdist-type-template NAME - - -DESCRIPTION ------------ -cdist-type-template creates a new type and adds the usual files to it. -It is thought to be helpful when writing new types. - - -SEE ALSO --------- -cdist(7) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). From d0abfbf01b31ba1573783d0c6f78241a2ac4268a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 14:17:45 +0200 Subject: [PATCH 0289/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index beae3cb2..deab8801 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,9 +1,20 @@ +- Initial install support + - setup $__install = "" for + manifest(s) + + - run standard manifest (?) + - creates initial objects + - only those having the installer flag? + - requires changegs to cdist-type-emulator! + - Goto Rewrite cdist-type-emulator + + - run all other manifests + - creates all objects + - what about type explorer? + - Support parallel execution - and maximum number of parallel runs (-p X) - error handling / report failed hosts -- Support different home instead of ../ -- Bug: os.path.join() may be wrong for the remote side! - -> does not matter for now! - Rewrite cdist-type-emulator - Remove legacy code in cdist @@ -11,8 +22,6 @@ - Remove man1/cdist-type-emulator.text - Remove the PATH=... part from the README -- Replace bin/cdist-type-template - - Allow manifest to be read from stdin - Create new video for cdist 2.0.0 http://www.youtube.com/watch?v=PRMjzy48eTI From 76f3792885ed008523fa044b7657465552f6edf3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 14:47:50 +0200 Subject: [PATCH 0290/4212] prepare argv[0] parsing for emulator use Signed-off-by: Nico Schottelius --- bin/cdist | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index a4570a34..327d86be 100755 --- a/bin/cdist +++ b/bin/cdist @@ -25,6 +25,7 @@ import datetime import logging import multiprocessing import os +import re import subprocess import shutil import stat @@ -55,12 +56,12 @@ REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") CODE_HEADER = "#!/bin/sh -e\n" DOT_CDIST = ".cdist" +TYPE_PREFIX = "__" VERSION = "2.0.0" logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') log = logging.getLogger() - class TypeEmulator: def __init__(self, name): self.name = name @@ -612,10 +613,6 @@ def banner(args): print(BANNER) sys.exit(0) -def install(args): - """Install remote system""" - process = {} - def config(args): """Configure remote system""" process = {} @@ -640,7 +637,16 @@ def config(args): log.info("Total processing time for %s host(s): %s", len(args.host), (time_end - time_start).total_seconds()) -if __name__ == "__main__": +def install(args): + """Install remote system""" + process = {} + +def emulator(): + """Emulate type commands (i.e. __file and co)""" + process = {} + +def commandline(): + """Parse command line""" # Construct parser others can reuse parser = {} # Options _all_ parsers have in common @@ -702,3 +708,9 @@ if __name__ == "__main__": args.func(args) except KeyboardInterrupt: sys.exit(0) + +if __name__ == "__main__": + if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): + emulator() + else: + commandline() From 4956c015c15d7284c00a0e8962e79001d396f25f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 14:50:43 +0200 Subject: [PATCH 0291/4212] make __type available for type gencode Signed-off-by: Nico Schottelius --- bin/cdist | 1 + doc/man/cdist-reference.text.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 327d86be..40b8dd5e 100755 --- a/bin/cdist +++ b/bin/cdist @@ -514,6 +514,7 @@ class Cdist: env["__object"] = self.object_dir(cdist_object) env["__object_id"] = self.get_object_id_from_object(cdist_object) env["__object_fq"] = cdist_object + env["__type"] = self.type_dir(get_type_from_object(cdist_object)) if mode == "gencode": paths = self.type_gencode_paths(self.get_type_from_object(cdist_object)) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 218b0f57..e38f157d 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -182,7 +182,7 @@ __target_user:: Currently static in core. __type:: Path to the current type. - Available for: type manifest + Available for: type manifest, type gencode __type_explorer:: Directory that contains the type explorers. Available for: type explorer From dadc3ffe941dd115bc4a77ec68e07279041cce5f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 15:01:33 +0200 Subject: [PATCH 0292/4212] self.... Signed-off-by: Nico Schottelius --- bin/cdist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 40b8dd5e..05eb8c00 100755 --- a/bin/cdist +++ b/bin/cdist @@ -514,7 +514,7 @@ class Cdist: env["__object"] = self.object_dir(cdist_object) env["__object_id"] = self.get_object_id_from_object(cdist_object) env["__object_fq"] = cdist_object - env["__type"] = self.type_dir(get_type_from_object(cdist_object)) + env["__type"] = self.type_dir(self.get_type_from_object(cdist_object)) if mode == "gencode": paths = self.type_gencode_paths(self.get_type_from_object(cdist_object)) @@ -644,7 +644,7 @@ def install(args): def emulator(): """Emulate type commands (i.e. __file and co)""" - process = {} + type = os.path.basename(sys.argv[0]) def commandline(): """Parse command line""" From eb3982b059f70ef3460c3ab796cae3a89469923b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 15:10:24 +0200 Subject: [PATCH 0293/4212] introduce more generic type_attribute_path() and replace type_manifest_path() Signed-off-by: Nico Schottelius --- bin/cdist | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/cdist b/bin/cdist index 05eb8c00..3708e6a6 100755 --- a/bin/cdist +++ b/bin/cdist @@ -335,9 +335,9 @@ class Cdist: return [os.path.join(self.type_base_dir, type, "gencode-local"), os.path.join(self.type_base_dir, type, "gencode-remote")] - def type_manifest_path(self, type): - """Return path to manifest of type""" - return os.path.join(self.type_base_dir, type, "manifest") + def type_attribute_path(self, type, attribute): + """Return path of an attribute of a type""" + return os.path.join(self.type_base_dir, type, attribute) def remote_type_explorer_dir(self, type): """Return remote directory that holds the explorers of a type""" @@ -446,7 +446,7 @@ class Cdist: def run_type_manifest(self, cdist_object): """Run manifest for a specific object""" type = self.get_type_from_object(cdist_object) - manifest = self.type_manifest_path(type) + manifest = self.type_attribute_path(type, "manifest") log.debug("%s: Running %s", cdist_object, manifest) if os.path.exists(manifest): From d979bdc5149fee855edfafb7a26445ceec73f5d9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 15:12:12 +0200 Subject: [PATCH 0294/4212] also replace self.type_explorer_dir Signed-off-by: Nico Schottelius --- bin/cdist | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index 3708e6a6..2e094fcf 100755 --- a/bin/cdist +++ b/bin/cdist @@ -253,7 +253,7 @@ class Cdist: def list_type_explorers(self, type): """Return list of available explorers for a specific type""" - dir = self.type_explorer_dir(type) + dir = self.type_attribute_path(type, "explorer") if os.path.isdir(dir): list = os.listdir(dir) else: @@ -326,10 +326,6 @@ class Cdist: """Return directory the type""" return os.path.join(self.type_base_dir, type) - def type_explorer_dir(self, type): - """Return directory that holds the explorers of a type""" - return os.path.join(self.type_dir(type), "explorer") - def type_gencode_paths(self, type): """Return paths to gencode scripts of type""" return [os.path.join(self.type_base_dir, type, "gencode-local"), @@ -366,7 +362,7 @@ class Cdist: # Do not retransfer self.type_explorers_transferred[type] = 1 - src = self.type_explorer_dir(type) + src = self.type_attribute_path(type, attribute) remote_base = os.path.join(REMOTE_TYPE_DIR, type) dst = self.remote_type_explorer_dir(type) From 40d494ace28023ba7c42a6bdef5baef2abab79c5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 15:20:59 +0200 Subject: [PATCH 0295/4212] and now replace the new cool function type_attribute_path() with easy type_dir Signed-off-by: Nico Schottelius --- bin/cdist | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/bin/cdist b/bin/cdist index 2e094fcf..39452352 100755 --- a/bin/cdist +++ b/bin/cdist @@ -253,7 +253,7 @@ class Cdist: def list_type_explorers(self, type): """Return list of available explorers for a specific type""" - dir = self.type_attribute_path(type, "explorer") + dir = self.type_dir(type, "explorer") if os.path.isdir(dir): list = os.listdir(dir) else: @@ -322,18 +322,9 @@ class Cdist: return objects - def type_dir(self, type): + def type_dir(self, type, *args): """Return directory the type""" - return os.path.join(self.type_base_dir, type) - - def type_gencode_paths(self, type): - """Return paths to gencode scripts of type""" - return [os.path.join(self.type_base_dir, type, "gencode-local"), - os.path.join(self.type_base_dir, type, "gencode-remote")] - - def type_attribute_path(self, type, attribute): - """Return path of an attribute of a type""" - return os.path.join(self.type_base_dir, type, attribute) + return os.path.join(self.type_base_dir, type, *args) def remote_type_explorer_dir(self, type): """Return remote directory that holds the explorers of a type""" @@ -362,7 +353,7 @@ class Cdist: # Do not retransfer self.type_explorers_transferred[type] = 1 - src = self.type_attribute_path(type, attribute) + src = self.type_dir(type, "explorer") remote_base = os.path.join(REMOTE_TYPE_DIR, type) dst = self.remote_type_explorer_dir(type) @@ -442,7 +433,7 @@ class Cdist: def run_type_manifest(self, cdist_object): """Run manifest for a specific object""" type = self.get_type_from_object(cdist_object) - manifest = self.type_attribute_path(type, "manifest") + manifest = self.type_dir(type, "manifest") log.debug("%s: Running %s", cdist_object, manifest) if os.path.exists(manifest): @@ -496,6 +487,7 @@ class Cdist: """Run gencode or code for an object""" log.debug("Running %s from %s", mode, cdist_object) requirements = self.list_object_requirements(cdist_object) + type = self.get_type_from_object(cdist_object) for requirement in requirements: log.debug("Object %s requires %s", cdist_object, requirement) @@ -510,10 +502,13 @@ class Cdist: env["__object"] = self.object_dir(cdist_object) env["__object_id"] = self.get_object_id_from_object(cdist_object) env["__object_fq"] = cdist_object - env["__type"] = self.type_dir(self.get_type_from_object(cdist_object)) + env["__type"] = self.type_dir(type) if mode == "gencode": - paths = self.type_gencode_paths(self.get_type_from_object(cdist_object)) + paths = [ + self.type_dir(type, "gencode-local"), + self.type_dir(type, "gencode-remote") + ] for bin in paths: if os.path.isfile(bin): # omit "gen" from gencode and From 1b0d85dcbe0ceac565c17109c4f9fa2f813f72a4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 15:29:56 +0200 Subject: [PATCH 0296/4212] link type emulator to ourself Signed-off-by: Nico Schottelius --- bin/cdist | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 39452352..e28a14c4 100755 --- a/bin/cdist +++ b/bin/cdist @@ -367,7 +367,7 @@ class Cdist: def link_type_to_emulator(self): """Link type names to cdist-type-emulator""" for type in self.list_types(): - source = os.path.join(self.lib_dir, "cdist-type-emulator") + source = sys.argv[0] destination = os.path.join(self.bin_dir, type) log.debug("Linking %s to %s", source, destination) os.symlink(source, destination) @@ -637,6 +637,18 @@ def emulator(): """Emulate type commands (i.e. __file and co)""" type = os.path.basename(sys.argv[0]) + + parser = argparse.ArgumentParser(add_help=False) + + print("Oh, noe") + sys.exit(1) + + # Setup optional parameters + # Setup required parameters + # Setup positional parameter, if not singleton + + + def commandline(): """Parse command line""" # Construct parser others can reuse From f720ce92435b126f65241d1497d1f53a8244494f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 15:46:02 +0200 Subject: [PATCH 0297/4212] ++todo Signed-off-by: Nico Schottelius --- bin/cdist | 14 +++++++++----- doc/dev/todo/niconext | 8 ++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/bin/cdist b/bin/cdist index e28a14c4..ee5b72c1 100755 --- a/bin/cdist +++ b/bin/cdist @@ -454,11 +454,13 @@ class Cdist: env['__global'] = self.out_dir # Legacy stuff to make cdist-type-emulator work - env['__cdist_conf_dir'] = self.conf_dir env['__cdist_core_dir'] = os.path.join(self.base_dir, "core") env['__cdist_local_base_dir'] = self.temp_dir env['__cdist_manifest'] = self.initial_manifest + # Submit information to new type emulator + env['__cdist_type_base_dir'] = self.type_base_dir + # Other environment stuff if extra_env: env.update(extra_env) @@ -636,17 +638,19 @@ def install(args): def emulator(): """Emulate type commands (i.e. __file and co)""" type = os.path.basename(sys.argv[0]) - + type_dir = os.environ['__cdist_type_base_dir'] parser = argparse.ArgumentParser(add_help=False) - print("Oh, noe") - sys.exit(1) - # Setup optional parameters + if os.path.isfile(os.path.join(type_dir, "parameter", "optional"): + __cdist_type_base_dir # Setup required parameters # Setup positional parameter, if not singleton + print("Oh, noe") + sys.exit(1) + def commandline(): diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index deab8801..3ec5ae96 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -22,6 +22,14 @@ - Remove man1/cdist-type-emulator.text - Remove the PATH=... part from the README + - basename(argv0) == type + - how to get to type dir? + - dependent on -c to cdist! + - submit via internal env! + - need to build parameter parser + - need to read file + - refactor list_object_requirements + - Allow manifest to be read from stdin - Create new video for cdist 2.0.0 http://www.youtube.com/watch?v=PRMjzy48eTI From 75510d88c925f4fbae3f931195bc3a354b2e633f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 16:08:25 +0200 Subject: [PATCH 0298/4212] first new type emulator parameter support in cdist Signed-off-by: Nico Schottelius --- bin/cdist | 55 +++++++++++++++++++++++++------------------ doc/dev/todo/niconext | 5 ++-- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/bin/cdist b/bin/cdist index ee5b72c1..34c89d86 100755 --- a/bin/cdist +++ b/bin/cdist @@ -62,6 +62,21 @@ VERSION = "2.0.0" logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') log = logging.getLogger() + +def file_to_list(filename): + """Return list from \n seperated file""" + if os.path.isfile(filename): + file_fd = open(filename, "r") + lines = file_fd.readlines() + file_fd.close() + + # Remove \n from all lines + lines = map(lambda s: s.strip(), lines) + else: + lines = [] + + return lines + class TypeEmulator: def __init__(self, name): self.name = name @@ -467,28 +482,11 @@ class Cdist: self.shell_run_or_debug_fail(manifest, [manifest], env=env) - def list_object_requirements(self, cdist_object): - """Return list of requirements for specific object""" - file=os.path.join(self.object_dir(cdist_object), "require") - - if os.path.isfile(file): - file_fd = open(file, "r") - requirements = file_fd.readlines() - file_fd.close() - - # Remove \n from all lines - requirements = map(lambda s: s.strip(), requirements) - - log.debug("Requirements for %s: %s", cdist_object, requirements) - else: - requirements = [] - - return requirements - def object_run(self, cdist_object, mode): """Run gencode or code for an object""" log.debug("Running %s from %s", mode, cdist_object) - requirements = self.list_object_requirements(cdist_object) + file=os.path.join(self.object_dir(cdist_object), "require") + requirements = file_to_list(file) type = self.get_type_from_object(cdist_object) for requirement in requirements: @@ -638,21 +636,32 @@ def install(args): def emulator(): """Emulate type commands (i.e. __file and co)""" type = os.path.basename(sys.argv[0]) - type_dir = os.environ['__cdist_type_base_dir'] + type_dir = os.path.join(os.environ['__cdist_type_base_dir'], type) + param_dir = os.path.join(type_dir, "parameter") parser = argparse.ArgumentParser(add_help=False) # Setup optional parameters - if os.path.isfile(os.path.join(type_dir, "parameter", "optional"): - __cdist_type_base_dir + for parameter in file_to_list(os.path.join(param_dir, "optional")): + argument = "--" + parameter + print("Adding" + argument) + parser.add_argument(argument, action='store', required=False) + # Setup required parameters + for parameter in file_to_list(os.path.join(param_dir, "required")): + argument = "--" + parameter + print("Adding" + argument) + parser.add_argument(argument, action='store', required=True) + # Setup positional parameter, if not singleton + # And finally verify parameter + args = parser.parse_args(sys.argv[1:]) + print("Oh, noe") sys.exit(1) - def commandline(): """Parse command line""" # Construct parser others can reuse diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 3ec5ae96..83b18dd9 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -27,8 +27,9 @@ - dependent on -c to cdist! - submit via internal env! - need to build parameter parser - - need to read file - - refactor list_object_requirements + + Test: + __cdist_type_base_dir=$(pwd -P)/conf/type __file - Allow manifest to be read from stdin - Create new video for cdist 2.0.0 From b4a431a03b5a406c8d1ff374dce60256c403e4f2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 17:08:39 +0200 Subject: [PATCH 0299/4212] more todo for soon Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 83b18dd9..c9fd6c0d 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,6 +1,6 @@ - Initial install support - - setup $__install = "" for - manifest(s) + - setup $__install = "yes" for + manifest(s), gencode-* - run standard manifest (?) - creates initial objects @@ -11,6 +11,8 @@ - run all other manifests - creates all objects - what about type explorer? + - do not run, create empty output (types should be able + to handle this!) - Support parallel execution - and maximum number of parallel runs (-p X) From 6485299a7cd2a9cbdfa10d6e52b23bd8f7d22536 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 17:08:59 +0200 Subject: [PATCH 0300/4212] prepare source records, cleanup Signed-off-by: Nico Schottelius --- bin/cdist | 57 ++++++++++++++++++++----------------------------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/bin/cdist b/bin/cdist index 34c89d86..032b078d 100755 --- a/bin/cdist +++ b/bin/cdist @@ -77,37 +77,6 @@ def file_to_list(filename): return lines -class TypeEmulator: - def __init__(self, name): - self.name = name - self.type = os.path.basename(name) - - - def type_emulator(self): - type = basename(sys.argv[0]) - - type_is_singleton(type) - - # Check object id - - # Prevent double slash if id begins with / - - # Record parameter: opt_file="${opt#--}" - # [ $# -ge 1 ] || __cdist_usage "Missing value for $opt" - # echo "${value}" > "${__cdist_parameter_dir}/${opt_file}" - - # Record requirements - # echo $requirement >> "$(__cdist_object_require "$__cdist_object_self")" - - # Ensure required parameters are given - # Ensure that only optional or required parameters are given - # [ "$is_valid" ] || __cdist_usage "Unknown parameter $parameter" - - # Merge object (creating twice with the same parameter + requirements == allowed) - - # diff -ru "${__cdist_new_object_dir}/${__cdist_name_parameter} - # # Add "I was here message" - # _cdist_object_source_add "${__cdist_object_dir}" class Cdist: """Cdist main class to hold arbitrary data""" @@ -471,9 +440,9 @@ class Cdist: # Legacy stuff to make cdist-type-emulator work env['__cdist_core_dir'] = os.path.join(self.base_dir, "core") env['__cdist_local_base_dir'] = self.temp_dir - env['__cdist_manifest'] = self.initial_manifest # Submit information to new type emulator + env['__cdist_manifest'] = manifest env['__cdist_type_base_dir'] = self.type_base_dir # Other environment stuff @@ -644,22 +613,38 @@ def emulator(): # Setup optional parameters for parameter in file_to_list(os.path.join(param_dir, "optional")): argument = "--" + parameter - print("Adding" + argument) parser.add_argument(argument, action='store', required=False) # Setup required parameters for parameter in file_to_list(os.path.join(param_dir, "required")): argument = "--" + parameter - print("Adding" + argument) parser.add_argument(argument, action='store', required=True) # Setup positional parameter, if not singleton + if not os.path.isfile(os.path.join(type_dir, "singleton")): + parser.add_argument("object_id", nargs=1) + else: + print("singleton") + # And finally verify parameter args = parser.parse_args(sys.argv[1:]) - print("Oh, noe") - sys.exit(1) + # Record parameter + # wh + print(args) + + # Record requirements + if "__require" in os.environ: + requirements = os.environ['__require'] + + # Merge / mv object into tree + + # Record / Append source + source = os.environ['__cdist_manifest'] + # write to .source? + + # sys.exit(1) def commandline(): From 5cefeb25fc89cb25eb40853ba898fc46978bf0b8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 18:26:18 +0200 Subject: [PATCH 0301/4212] +/- todo, improve argument handling Signed-off-by: Nico Schottelius --- bin/cdist | 14 ++++++++++++-- doc/dev/todo/niconext | 26 +++++++++++--------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/bin/cdist b/bin/cdist index 032b078d..8d5e9342 100755 --- a/bin/cdist +++ b/bin/cdist @@ -434,6 +434,7 @@ class Cdist: env = os.environ.copy() env['PATH'] = self.bin_dir + ":" + env['PATH'] + # Information required in every manifest env['__target_host'] = self.target_host env['__global'] = self.out_dir @@ -630,10 +631,19 @@ def emulator(): # And finally verify parameter args = parser.parse_args(sys.argv[1:]) - # Record parameter - # wh + object_id = args.object_id + + del args.object_id print(args) + # Record parameter + params = vars(args) + for param in params: + value = getattr(args, param) + if value: + print("Writing " + param + " = " + value) + + # Record requirements if "__require" in os.environ: requirements = os.environ['__require'] diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index c9fd6c0d..bd30c08d 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,3 +1,14 @@ +- Rewrite cdist-type-emulator + - Remove legacy code in cdist + - Remove cdist-config + - Remove man1/cdist-type-emulator.text + - Remove the PATH=... part from the README + + - how to access output dir? + + Test: + __cdist_type_base_dir=$(pwd -P)/conf/type __file + - Initial install support - setup $__install = "yes" for manifest(s), gencode-* @@ -18,21 +29,6 @@ - and maximum number of parallel runs (-p X) - error handling / report failed hosts -- Rewrite cdist-type-emulator - - Remove legacy code in cdist - - Remove cdist-config - - Remove man1/cdist-type-emulator.text - - Remove the PATH=... part from the README - - - basename(argv0) == type - - how to get to type dir? - - dependent on -c to cdist! - - submit via internal env! - - need to build parameter parser - - Test: - __cdist_type_base_dir=$(pwd -P)/conf/type __file - - Allow manifest to be read from stdin - Create new video for cdist 2.0.0 http://www.youtube.com/watch?v=PRMjzy48eTI From 8838d5df11ce3febbeb6d55b993804c236294683 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Sep 2011 19:06:43 +0200 Subject: [PATCH 0302/4212] begin writing params Signed-off-by: Nico Schottelius --- bin/cdist | 22 +++++++++++++++++----- doc/dev/todo/niconext | 1 + 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/bin/cdist b/bin/cdist index 8d5e9342..ad8add02 100755 --- a/bin/cdist +++ b/bin/cdist @@ -608,6 +608,7 @@ def emulator(): type = os.path.basename(sys.argv[0]) type_dir = os.path.join(os.environ['__cdist_type_base_dir'], type) param_dir = os.path.join(type_dir, "parameter") + global_dir = os.environ['__global'] parser = argparse.ArgumentParser(add_help=False) @@ -625,23 +626,34 @@ def emulator(): if not os.path.isfile(os.path.join(type_dir, "singleton")): parser.add_argument("object_id", nargs=1) - else: - print("singleton") # And finally verify parameter args = parser.parse_args(sys.argv[1:]) - object_id = args.object_id + # Setup object_id + if os.path.isfile(os.path.join(type_dir, "singleton")): + object_id = "singleton" + else: + object_id = args.object_id + del args.object_id - del args.object_id print(args) + print(object_id) + param_out_dir = os.path.join(global_dir, type, + object_id, DOT_CDIST, "parameter") + # Record parameter params = vars(args) for param in params: value = getattr(args, param) if value: - print("Writing " + param + " = " + value) + file = os.path.join(param_out_dir, param) + print(file + "<-" + param + " = " + value) + param_fd = open(file) + param_fd.writelines(value) + param_fd.close() + # Record requirements diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index bd30c08d..a74862f4 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -24,6 +24,7 @@ - what about type explorer? - do not run, create empty output (types should be able to handle this!) + via __global/ - Support parallel execution - and maximum number of parallel runs (-p X) From 31e9937098ebbcd9dd0b8535bb68c94bbb56b0eb Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 17 Sep 2011 06:53:18 +0200 Subject: [PATCH 0303/4212] finish new type for partition definition Signed-off-by: Steven Armstrong --- conf/type/__partition_msdos/gencode-remote | 20 ---------------- conf/type/__partition_msdos/man.text | 2 +- conf/type/__partition_msdos/manifest | 24 +++++++++++++++---- .../type/__partition_msdos/parameter/optional | 2 +- 4 files changed, 22 insertions(+), 26 deletions(-) delete mode 100755 conf/type/__partition_msdos/gencode-remote diff --git a/conf/type/__partition_msdos/gencode-remote b/conf/type/__partition_msdos/gencode-remote deleted file mode 100755 index 211bc1db..00000000 --- a/conf/type/__partition_msdos/gencode-remote +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -# -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# - diff --git a/conf/type/__partition_msdos/man.text b/conf/type/__partition_msdos/man.text index 611451ed..c9ef0cf1 100644 --- a/conf/type/__partition_msdos/man.text +++ b/conf/type/__partition_msdos/man.text @@ -21,7 +21,7 @@ type:: OPTIONAL PARAMETERS ------------------- -device:: +partition:: defaults to object_id bootable:: mark partition as bootable, true or false, defaults to false diff --git a/conf/type/__partition_msdos/manifest b/conf/type/__partition_msdos/manifest index e5b04c02..0d73c405 100755 --- a/conf/type/__partition_msdos/manifest +++ b/conf/type/__partition_msdos/manifest @@ -18,8 +18,24 @@ # along with cdist. If not, see . # -type +# set defaults +if [ -f "$__object/parameter/partition" ]; then + partition="(cat "$__object/parameter/partition")" +else + partition="/$__object_id" + echo "$partition" > "$__object/parameter/partition" +fi +device="$(echo "$partition" | sed 's/[0-9]//g')" +echo "$device" > "$__object/parameter/device" +minor="$(echo "$partition" | sed 's/[^0-9]//g')" +echo "$minor" > "$__object/parameter/minor" -device -bootable -size +if [ ! -f "$__object/parameter/bootable" ]; then + echo "false" > "$__object/parameter/bootable" +fi +if [ ! -f "$__object/parameter/size" ]; then + echo "+" > "$__object/parameter/size" +fi + +# pull in the type that actually does something with the above parameters +require="$__self" __partition_msdos_apply diff --git a/conf/type/__partition_msdos/parameter/optional b/conf/type/__partition_msdos/parameter/optional index 612fe769..b2b0a4c2 100644 --- a/conf/type/__partition_msdos/parameter/optional +++ b/conf/type/__partition_msdos/parameter/optional @@ -1,3 +1,3 @@ -device +partition bootable size From 9d3fa5d4c7468142aca958a684c1425f663e2dc6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 17 Sep 2011 08:55:24 +0200 Subject: [PATCH 0304/4212] new type __partition_msdos_apply Signed-off-by: Steven Armstrong --- .../explorer/partitions | 3 + .../type/__partition_msdos_apply/files/lib.sh | 58 +++++++++++ .../__partition_msdos_apply/gencode-remote | 99 +++++++++++++++++++ conf/type/__partition_msdos_apply/man.text | 42 ++++++++ conf/type/__partition_msdos_apply/singleton | 0 5 files changed, 202 insertions(+) create mode 100755 conf/type/__partition_msdos_apply/explorer/partitions create mode 100644 conf/type/__partition_msdos_apply/files/lib.sh create mode 100755 conf/type/__partition_msdos_apply/gencode-remote create mode 100644 conf/type/__partition_msdos_apply/man.text create mode 100644 conf/type/__partition_msdos_apply/singleton diff --git a/conf/type/__partition_msdos_apply/explorer/partitions b/conf/type/__partition_msdos_apply/explorer/partitions new file mode 100755 index 00000000..6be61af4 --- /dev/null +++ b/conf/type/__partition_msdos_apply/explorer/partitions @@ -0,0 +1,3 @@ +#!/bin/sh + +cat /proc/partitions diff --git a/conf/type/__partition_msdos_apply/files/lib.sh b/conf/type/__partition_msdos_apply/files/lib.sh new file mode 100644 index 00000000..944533a6 --- /dev/null +++ b/conf/type/__partition_msdos_apply/files/lib.sh @@ -0,0 +1,58 @@ +die() { + echo "[__partition_msdos_apply] $@" >&2 + exit 1 +} +debug() { + echo "[__partition_msdos_apply] $@" >&2 +} + +fdisk_command() { + local device=$1 + local cmd=$2 + + debug fdisk_command "running fdisk command '${cmd}' on device ${device}" + #echo -en "${cmd}\nw\n" | fdisk -c -u "$device" + return $? +} + +create_disklabel() { + local device=$1 + + debug create_disklabel "creating new msdos disklabel" + fdisk_command ${device} "o" + return $? +} + +create_partition() { + local device=$1 + local minor=$2 + local size=$3 + local type=$4 + local primary_count=$5 + + if [ "$type" = "extended" -o "$type" = "5" ]; then + # Extended partition + primary_extended="e\n" + first_minor="${minor}\n" + [ "${minor}" = "4" ] && first_minor="" + type_minor="${minor}\n" + [ "${minor}" = "1" ] && type_minor="" + type="5" + elif [ "${minor}" -lt "5" ]; then + primary_extended="p\n" + first_minor="${minor}\n" + [ "${minor}" = "4" ] && first_minor="" + type_minor="${minor}\n" + [ "${minor}" = "1" ] && type_minor="" + else + # Logical partitions + first_minor="${minor}\n" + type_minor="${minor}\n" + primary_extended="l\n" + [ "$primary_count" > "3" ] && primary_extended="" + fi + [ -n "${size}" ] && size="+${size}M" + fdisk_command ${device} "n\n${primary_extended}${first_minor}\n${size}\nt\n${type_minor}${type}\n" + return $? +} + diff --git a/conf/type/__partition_msdos_apply/gencode-remote b/conf/type/__partition_msdos_apply/gencode-remote new file mode 100755 index 00000000..faa712e7 --- /dev/null +++ b/conf/type/__partition_msdos_apply/gencode-remote @@ -0,0 +1,99 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +die() { + echo "[__partition_msdos_apply] $@" >&2 + exit 1 +} +debug() { + echo "[__partition_msdos_apply] $@" >&2 +} + +# Convert a size specifier 1G 100M or 50% into the corresponding numeric MB. +size_to_mb() { + local size=$1 + local available_size="$2" + + local number_suffix="$(echo ${size} | sed -e 's:\.[0-9]\+::' -e 's:\([0-9]\+\)\([MmGg%]\)[Bb]\?:\1|\2:')" + local number="$(echo ${number_suffix} | cut -d '|' -f1)" + local suffix="$(echo ${number_suffix} | cut -d '|' -f2)" + + case "$suffix" in + M|m) + size="$number" + ;; + G|g) + size="$(( $number * 1024 ))" + ;; + %) + size="$(( $available_size * $number / 100 ))" + ;; + *) + size="-1" + esac + echo "$size" +} + +# include function library for use on target +cat "$__type/files/lib.sh" + +partitions="$__object/explorer/partitions" +objects=$(find "$__global/object/__partition_msdos" -path "*.cdist") +current_device="" +available_size= +primary_count=0 +for object in $objects; do + device="$(cat "$object/parameter/device")" + if [ "$current_device" != "$device" ]; + echo "create_disklabel $device" + current_device="$device" + device_name=$(echo ${device} | sed -e 's:^/dev/::;s:/:\\/:g') + available_size=$(( $(awk "/${device_name}\$/ { print $3; }" "$partitions") / 1024)) + # make sure we don't go past the end of the drive + available_size=$((device_size - 2)) + primary_count=0 + fi + + type="$(cat "$object/parameter/type")" + partition="$(cat "$object/parameter/partition")" + minor="$(cat "$object/parameter/minor")" + + if [ "${minor}" -lt "5" ]; then + primary_count=$(( $primary_count + 1 )) + fi + bootable="$(cat "$object/parameter/bootable")" + size="$(cat "$object/parameter/size")" + if [ "$size" = "+" ]; then + # use rest of device + partition_size="" + available_size=0 + else + partition_size=$(size_to_mb "$size" "$available_size") + available_size="$(( $available_size - $partition_size ))" + fi + + [ "$partition_size" = "-1" ] && die "could not translate size '$size' to a usable value" + debug "primary_count=$primary_count" + debug "available_size=$available_size" + debug "current_device=$current_device" + + echo "create_partition $device $minor $partition_size $type $primary_count" +done + diff --git a/conf/type/__partition_msdos_apply/man.text b/conf/type/__partition_msdos_apply/man.text new file mode 100644 index 00000000..4d4f127c --- /dev/null +++ b/conf/type/__partition_msdos_apply/man.text @@ -0,0 +1,42 @@ +cdist-type__partition_msdos_apply(7) +==================================== +Steven Armstrong + + +NAME +---- +cdist-type__partition_msdos_apply + + +DESCRIPTION +----------- +Create the partitions defined with __partition_msdos + + +REQUIRED PARAMETERS +------------------- +None + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__partition_msdos_apply +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__partition_msdos_apply(7) + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__partition_msdos_apply/singleton b/conf/type/__partition_msdos_apply/singleton new file mode 100644 index 00000000..e69de29b From 16d86dcf04712d2d1fe7f4e7fe123190e6c7f198 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 17 Sep 2011 09:26:09 +0200 Subject: [PATCH 0305/4212] +debug, -type, -bug Signed-off-by: Steven Armstrong --- .../__partition_msdos_apply/gencode-remote | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/conf/type/__partition_msdos_apply/gencode-remote b/conf/type/__partition_msdos_apply/gencode-remote index faa712e7..d352abdb 100755 --- a/conf/type/__partition_msdos_apply/gencode-remote +++ b/conf/type/__partition_msdos_apply/gencode-remote @@ -61,14 +61,17 @@ available_size= primary_count=0 for object in $objects; do device="$(cat "$object/parameter/device")" - if [ "$current_device" != "$device" ]; + if [ "$current_device" != "$device" ]; then echo "create_disklabel $device" current_device="$device" device_name=$(echo ${device} | sed -e 's:^/dev/::;s:/:\\/:g') - available_size=$(( $(awk "/${device_name}\$/ { print $3; }" "$partitions") / 1024)) + available_size=$(( $(awk "/${device_name}\$/ { print \$3; }" "$partitions") / 1024)) # make sure we don't go past the end of the drive - available_size=$((device_size - 2)) + available_size=$((available_size - 2)) primary_count=0 + debug "----- $device" + debug "current_device=$current_device" + debug "available_size=$available_size" fi type="$(cat "$object/parameter/type")" @@ -90,9 +93,17 @@ for object in $objects; do fi [ "$partition_size" = "-1" ] && die "could not translate size '$size' to a usable value" + debug "----- $partition" debug "primary_count=$primary_count" - debug "available_size=$available_size" debug "current_device=$current_device" + debug "device=$device" + debug "type=$type" + debug "partition=$partition" + debug "minor=$minor" + debug "bootable=$bootable" + debug "size=$size" + debug "partition_size=$partition_size" + debug "available_size=$available_size" echo "create_partition $device $minor $partition_size $type $primary_count" done From a3086ae79580f8633c986e133cccb8d01a3ab142 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 17 Sep 2011 09:27:19 +0200 Subject: [PATCH 0306/4212] make it actually write the partition Signed-off-by: Steven Armstrong --- conf/type/__partition_msdos_apply/files/lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__partition_msdos_apply/files/lib.sh b/conf/type/__partition_msdos_apply/files/lib.sh index 944533a6..0e9705d9 100644 --- a/conf/type/__partition_msdos_apply/files/lib.sh +++ b/conf/type/__partition_msdos_apply/files/lib.sh @@ -11,7 +11,7 @@ fdisk_command() { local cmd=$2 debug fdisk_command "running fdisk command '${cmd}' on device ${device}" - #echo -en "${cmd}\nw\n" | fdisk -c -u "$device" + echo -en "${cmd}\nw\n" | fdisk -c -u "$device" return $? } From a9bcec7fbe9f4ca7ad901cfc3e14dc6a640640cc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 18 Sep 2011 20:50:07 +0200 Subject: [PATCH 0307/4212] also catch OSError from subprocess Signed-off-by: Nico Schottelius --- bin/cdist | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/cdist b/bin/cdist index f7ad2f72..fce96099 100755 --- a/bin/cdist +++ b/bin/cdist @@ -198,6 +198,8 @@ class Cdist: script_fd.close() self.exit_error("Command failed (shell): " + " ".join(*args)) + except OSError as error: + self.exit_error(" ".join(*args) + ": " + error.args[1]) def run_or_fail(self, *args, **kargs): if "remote" in kargs: @@ -211,6 +213,9 @@ class Cdist: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: self.exit_error("Command failed: " + " ".join(*args)) + except OSError as error: + self.exit_error(" ".join(*args) + ": " + error.args[1]) + def remove_remote_dir(self, destination): self.run_or_fail(["rm", "-rf", destination], remote=True) From 606c47906708731f8b351ff5249e71d185d7d4b6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 18 Sep 2011 20:57:13 +0200 Subject: [PATCH 0308/4212] changes for 2.0.1 Signed-off-by: Nico Schottelius --- doc/changelog | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/changelog b/doc/changelog index 50409cac..cc6aa78b 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,6 +1,9 @@ -2.0.0: +2.0.1: + * Bugfix cdist: Always print source of error in case of exec errors + +2.0.0: 2011-09-16 * New Type: __package_rubygem (Chase Allen James) - * __self replaced by __object_fq (or so) + * __self replaced by __object_fq * Rewrote cdist in Python 1.7.1: 2011-07-26 From e0030947e4b3bd6e01264919b27a81dc79a79be7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 18 Sep 2011 21:04:23 +0200 Subject: [PATCH 0309/4212] document TMP variable Signed-off-by: Nico Schottelius --- doc/man/man1/cdist.text | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/man/man1/cdist.text b/doc/man/man1/cdist.text index 5a45b8c1..c43e4e1c 100644 --- a/doc/man/man1/cdist.text +++ b/doc/man/man1/cdist.text @@ -82,6 +82,14 @@ cdist --version -------------------------------------------------------------------------------- +ENVIRONMENT +----------- +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. + SEE ALSO -------- - cdist(7) From 9de1d9ce2017e27776fe817a8a55952b769586ea Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Sep 2011 00:24:17 +0200 Subject: [PATCH 0310/4212] write parameters to object Signed-off-by: Nico Schottelius --- bin/cdist | 46 +++++++++++++++++++++++++++---------------- doc/dev/todo/niconext | 2 ++ 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/bin/cdist b/bin/cdist index 9094a5f8..1d130eca 100755 --- a/bin/cdist +++ b/bin/cdist @@ -77,6 +77,9 @@ def file_to_list(filename): return lines +def exit_error(*args): + log.error(*args) + sys.exit(1) class Cdist: """Cdist main class to hold arbitrary data""" @@ -144,10 +147,6 @@ class Cdist: shutil.rmtree(self.cache_dir) shutil.move(self.temp_dir, self.cache_dir) - def exit_error(self, *args): - log.error(*args) - sys.exit(1) - def remote_mkdir(self, directory): """Create directory on remote side""" self.run_or_fail(["mkdir", "-p", directory], remote=True) @@ -182,9 +181,9 @@ class Cdist: print(script_fd.read()) script_fd.close() - self.exit_error("Command failed (shell): " + " ".join(*args)) + exit_error("Command failed (shell): " + " ".join(*args)) except OSError as error: - self.exit_error(" ".join(*args) + ": " + error.args[1]) + exit_error(" ".join(*args) + ": " + error.args[1]) def run_or_fail(self, *args, **kargs): if "remote" in kargs: @@ -197,9 +196,9 @@ class Cdist: try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: - self.exit_error("Command failed: " + " ".join(*args)) + exit_error("Command failed: " + " ".join(*args)) except OSError as error: - self.exit_error(" ".join(*args) + ": " + error.args[1]) + exit_error(" ".join(*args) + ": " + error.args[1]) def remove_remote_dir(self, destination): @@ -365,7 +364,7 @@ class Cdist: """Run global explorers""" explorers = self.list_global_explorers() if(len(explorers) == 0): - self.exit_error("No explorers found in", self.global_explorer_dir) + exit_error("No explorers found in", self.global_explorer_dir) self.transfer_global_explorers() for explorer in explorers: @@ -639,14 +638,23 @@ def emulator(): if os.path.isfile(os.path.join(type_dir, "singleton")): object_id = "singleton" else: - object_id = args.object_id + object_id = args.object_id[0] del args.object_id - print(args) + # FIXME: / hardcoded - better portable solution available? + if object_id[0] == '/': + object_id = object_id[1:] - print(object_id) - param_out_dir = os.path.join(global_dir, type, - object_id, DOT_CDIST, "parameter") + log.debug(args) + + object_dir = os.path.join(global_dir, type, + object_id, DOT_CDIST) + param_out_dir = os.path.join(object_dir, "parameter") + + try: + os.makedirs(param_out_dir, exist_ok=True) + except OSError as error: + exit_error(param_out_dir + ": " + error.args[1]) # Record parameter params = vars(args) @@ -654,16 +662,19 @@ def emulator(): value = getattr(args, param) if value: file = os.path.join(param_out_dir, param) - print(file + "<-" + param + " = " + value) - param_fd = open(file) + log.debug(file + "<-" + param + " = " + value) + param_fd = open(file, "w") param_fd.writelines(value) param_fd.close() - # Record requirements if "__require" in os.environ: requirements = os.environ['__require'] + print(object_id + ":Writing requirements: " + requirements) + require_fd = open(os.path.join(object_dir, "require"), "a") + require_fd.writelines(requirements.split(" ")) + require_fd.close() # Merge / mv object into tree @@ -672,6 +683,7 @@ def emulator(): # write to .source? # sys.exit(1) + print("Finished " + type + "/" + object_id + repr(params)) def commandline(): diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index a74862f4..231489e9 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -33,3 +33,5 @@ - Allow manifest to be read from stdin - Create new video for cdist 2.0.0 http://www.youtube.com/watch?v=PRMjzy48eTI + +- Setup __debug, if -d is given, so other tools can reuse it From b7b48414e1b3a2684dc731208bc0924671f01a4b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Sep 2011 00:32:33 +0200 Subject: [PATCH 0311/4212] use subdirectory, record source Signed-off-by: Nico Schottelius --- bin/cdist | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index 1d130eca..84ebd5f2 100755 --- a/bin/cdist +++ b/bin/cdist @@ -647,7 +647,7 @@ def emulator(): log.debug(args) - object_dir = os.path.join(global_dir, type, + object_dir = os.path.join(global_dir, "object", type, object_id, DOT_CDIST) param_out_dir = os.path.join(object_dir, "parameter") @@ -676,11 +676,13 @@ def emulator(): require_fd.writelines(requirements.split(" ")) require_fd.close() - # Merge / mv object into tree + # FIXME: Merge / mv object into tree # Record / Append source source = os.environ['__cdist_manifest'] - # write to .source? + source_fd = open(os.path.join(object_dir, "source"), "a") + source_fd.writelines(source) + source_fd.close() # sys.exit(1) print("Finished " + type + "/" + object_id + repr(params)) From 4e8f99b01daa49daa80a10da1546beeda799d23f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Sep 2011 00:36:35 +0200 Subject: [PATCH 0312/4212] almost completly implemented type emulator in python Signed-off-by: Nico Schottelius --- bin/cdist | 1 + lib/cdist-type-emulator | 182 ---------------------------------------- 2 files changed, 1 insertion(+), 182 deletions(-) delete mode 100755 lib/cdist-type-emulator diff --git a/bin/cdist b/bin/cdist index 84ebd5f2..57c889f1 100755 --- a/bin/cdist +++ b/bin/cdist @@ -645,6 +645,7 @@ def emulator(): if object_id[0] == '/': object_id = object_id[1:] + # FIXME: verify object id log.debug(args) object_dir = os.path.join(global_dir, "object", type, diff --git a/lib/cdist-type-emulator b/lib/cdist-type-emulator deleted file mode 100755 index 8ff190ad..00000000 --- a/lib/cdist-type-emulator +++ /dev/null @@ -1,182 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Wrapper script that generates cconfig from arguments -# -# This script will be called everytime the manifest decides to create -# a new type -# - -. cdist-config -set -u - -################################################################################ -# Prepare object and type -# - -__cdist_type="$__cdist_myname" - -# Find out whether type is a singleton or regular type -if [ -f "$(__cdist_type_singleton "$__cdist_type")" ]; then - __cdist_object_id="$__cdist_name_singleton" -else - [ $# -ge 1 ] || __cdist_usage " " - __cdist_object_id="$1"; shift -fi - -# Verify object id -__cdist_object_id_sane=$(echo "$__cdist_object_id" | grep "^${__cdist_sane_regexp}\$") -if [ -z "$__cdist_object_id_sane" ]; then - __cdist_usage "Insane object id, ${__cdist_object_id}." -fi - -# Prevent double slash if id begins with / -if [ "$(echo $__cdist_object_id | grep "^/")" ]; then - __cdist_object_self="${__cdist_type}${__cdist_object_id}" -else - __cdist_object_self="${__cdist_type}/${__cdist_object_id}" -fi -################################################################################ -# Internal quirks -# - -# Append id for error messages -__cdist_myname="$__cdist_myname ($__cdist_object_id)" - -################################################################################ -# Create object in tmpdir first -# - -# Save original destination -__cdist_out_object_dir_orig="$__cdist_out_object_dir" - -# Store to tmp now -__cdist_out_object_dir="$__cdist_tmp_dir" - -__cdist_new_object_dir="$(__cdist_object_dir "$__cdist_object_self")" - -# Initialise object -mkdir -p "${__cdist_new_object_dir}" - -# Record parameter -__cdist_parameter_dir="$(__cdist_object_parameter_dir "$__cdist_object_self")" -mkdir -p "${__cdist_parameter_dir}" - -while [ $# -gt 0 ]; do - opt="$1"; shift - - echo "$opt" | grep -q "^--${__cdist_sane_regexp}\$" || \ - __cdist_usage "Provide sane options" - - opt_file="${opt#--}" - - [ $# -ge 1 ] || __cdist_usage "Missing value for $opt" - - value="$1"; shift - - echo "${value}" > "${__cdist_parameter_dir}/${opt_file}" -done - -# Record requirements -# it's fine, if it's not set -set +u -for requirement in $require; do - echo $requirement >> "$(__cdist_object_require "$__cdist_object_self")" - __cdist_echo info "Recording requirement $requirement" -done -set -u - -################################################################################ -# Check newly created object -# - -# -# Ensure required parameters are given -# -if [ -f "$(__cdist_type_parameter_required "$__cdist_type")" ]; then - while read required; do - if [ ! -f "${__cdist_parameter_dir}/${required}" ]; then - __cdist_usage "Missing required parameter $required" - fi - done < "$(__cdist_type_parameter_required "$__cdist_type")" -fi - -# -# Ensure that only optional or required parameters are given -# - -if [ -f "$(__cdist_type_parameter_optional "$__cdist_type")" ]; then - cat "$(__cdist_type_parameter_optional "$__cdist_type")" > \ - "$__cdist_tmp_file" -fi - -if [ -f "$(__cdist_type_parameter_required "$__cdist_type")" ]; then - cat "$(__cdist_type_parameter_required "$__cdist_type")" >> \ - "$__cdist_tmp_file" -fi - -cd "$__cdist_parameter_dir" -for parameter in $(ls -1); do - is_valid=$(grep "^$parameter\$" "$__cdist_tmp_file") - - [ "$is_valid" ] || __cdist_usage "Unknown parameter $parameter" -done - -################################################################################ -# Merge object -# -# Restore original destination -__cdist_out_object_dir="$__cdist_out_object_dir_orig" - -__cdist_object_dir="$(__cdist_object_dir "$__cdist_object_self")" - -# -# If the object already exists and is exactly the same, merge it. Otherwise fail. -# -if [ -e "${__cdist_object_dir}" ]; then - # Allow diff to fail - set +e - diff -ru "${__cdist_new_object_dir}/${__cdist_name_parameter}" \ - "${__cdist_object_dir}/${__cdist_name_parameter}" \ - > "$__cdist_tmp_file"; ret=$? - set -e - - if [ "$ret" != 0 ]; then - # Go to standard error - exec >&2 - echo "${__cdist_object_self} already exists differently." - echo "Recorded source(s):" - __cdist_object_source "${__cdist_object_dir}" - echo "Differences:" - cat "$__cdist_tmp_file" - __cdist_exit_err "Aborting due to object conflict." - fi -else - # - # Move object into tree: - # Create full path minus .cdist and move .cdist - # - __cdist_new_object_base_dir="$(__cdist_object_base_dir "$__cdist_object_self")" - mkdir -p "$__cdist_new_object_base_dir" - mv "$__cdist_new_object_dir" "$__cdist_new_object_base_dir" -fi - -# Add "I was here message" -__cdist_object_source_add "${__cdist_object_dir}" From ce16725567b8733fa59a15d6e1745af8e1632c81 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Sep 2011 00:37:39 +0200 Subject: [PATCH 0313/4212] todo for 2.0.1 Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 231489e9..84745512 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,3 +1,5 @@ +2.0.1: + - Rewrite cdist-type-emulator - Remove legacy code in cdist - Remove cdist-config @@ -9,6 +11,10 @@ Test: __cdist_type_base_dir=$(pwd -P)/conf/type __file +- Fix / rewrite cdist-quickstart + +-------------------------------------------------------------------------------- + - Initial install support - setup $__install = "yes" for manifest(s), gencode-* From de2a216ee668b8815ebb731bc0f544a3b988bf49 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Sep 2011 00:39:43 +0200 Subject: [PATCH 0314/4212] cleanup bin/, move quickstart to mandir Signed-off-by: Nico Schottelius --- bin/cdist-config | 438 ------------------ .../man/man7/cdist-quickstart.text | 0 2 files changed, 438 deletions(-) delete mode 100644 bin/cdist-config rename bin/cdist-quickstart => doc/man/man7/cdist-quickstart.text (100%) diff --git a/bin/cdist-config b/bin/cdist-config deleted file mode 100644 index f7fb5ac0..00000000 --- a/bin/cdist-config +++ /dev/null @@ -1,438 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# - -__cdist_version="1.7.0" - -# Fail if something bogus is going on -set -u - -################################################################################ -# cconf standard vars prefixed with cdist - -__cdist_pwd="$(pwd -P)" -__cdist_mydir="${0%/*}"; -__cdist_abs_mydir="$(cd "$__cdist_mydir" && pwd -P)" -__cdist_myname=${0##*/}; -__cdist_abs_myname="$__cdist_abs_mydir/$__cdist_myname" - -################################################################################ -# Names / Constants -# -# Most values can be overriden from outside, so you can -# customise paths as you like (for distributors, geeks and hackers) -# - -: ${__cdist_name_bin:=bin} -: ${__cdist_name_cache:=cache} -: ${__cdist_name_code:=code} -: ${__cdist_name_conf_dir:=conf} -: ${__cdist_name_dot_cdist:=.cdist} -: ${__cdist_name_explorer:=explorer} -: ${__cdist_name_gencode:=gencode} -: ${__cdist_name_gencode_local:=local} -: ${__cdist_name_gencode_remote:=remote} -: ${__cdist_name_global:=global} -: ${__cdist_name_host:=host} -: ${__cdist_name_init:=init} -: ${__cdist_name_manifest:=manifest} -: ${__cdist_name_object:=object} -: ${__cdist_name_object_finished:=done} -: ${__cdist_name_object_prepared:=prepared} -: ${__cdist_name_object_id:=object_id} -: ${__cdist_name_object_source:=source} -: ${__cdist_name_objects_created:=.objects_created} -: ${__cdist_name_out_dir:=out} -: ${__cdist_name_parameter:=parameter} -: ${__cdist_name_parameter_required:=required} -: ${__cdist_name_parameter_optional:=optional} -: ${__cdist_name_require:=require} -: ${__cdist_name_self:=self} -: ${__cdist_name_singleton:=singleton} -: ${__cdist_name_target_host:=target_host} -: ${__cdist_name_target_user:=target_user} -: ${__cdist_name_type:=type} -: ${__cdist_name_type_bin:=type_bin} -: ${__cdist_name_type_explorer:=type_explorer} -: ${__cdist_name_type_explorer_pushed:=.explorer_pushed} - -# Used for IDs: Allow everything not starting with - and . -: ${__cdist_sane_regexp:=[^-\.].*} - -# Default remote user -: ${__cdist_remote_user:=root} - - -################################################################################ -# Exported variable names (usable for non core -# -: ${__cdist_name_var_explorer:=__$__cdist_name_explorer} -: ${__cdist_name_var_type_explorer:=__$__cdist_name_type_explorer} -: ${__cdist_name_var_global:=__$__cdist_name_global} -: ${__cdist_name_var_manifest:=__$__cdist_name_manifest} -: ${__cdist_name_var_target_host:=__$__cdist_name_target_host} -: ${__cdist_name_var_target_user:=__$__cdist_name_target_user} -: ${__cdist_name_var_object:=__$__cdist_name_object} -: ${__cdist_name_var_object_id:=__$__cdist_name_object_id} -: ${__cdist_name_var_self:=__$__cdist_name_self} -: ${__cdist_name_var_type:=__$__cdist_name_type} - - -################################################################################ -# Tempfiles -# -: ${__cdist_tmp_base_dir=/tmp} -__cdist_tmp_dir=$(mktemp -d "$__cdist_tmp_base_dir/cdist.XXXXXXXXXXXX") -__cdist_tmp_file=$(mktemp "$__cdist_tmp_dir/cdist.XXXXXXXXXXXX") - -################################################################################ -# Local Base -# -: ${__cdist_local_base_dir:=$__cdist_tmp_dir} - -# Cache may *NOT* be below __cdist_local_base_dir! -: ${__cdist_local_base_cache_dir:=$__cdist_abs_mydir/../$__cdist_name_cache} - -: ${__cdist_conf_dir:="$(cd "$__cdist_abs_mydir/../conf" && pwd -P)"} - -: ${__cdist_explorer_dir:=$__cdist_conf_dir/$__cdist_name_explorer} -: ${__cdist_manifest_dir:=$__cdist_conf_dir/$__cdist_name_manifest} -: ${__cdist_manifest_init:=$__cdist_manifest_dir/$__cdist_name_init} -: ${__cdist_type_dir:=$__cdist_conf_dir/$__cdist_name_type} - -################################################################################ -# Local output -# -: ${__cdist_out_dir:=$__cdist_local_base_dir/$__cdist_name_out_dir} -: ${__cdist_out_explorer_dir:=$__cdist_out_dir/$__cdist_name_explorer} -: ${__cdist_out_object_dir:=$__cdist_out_dir/$__cdist_name_object} -: ${__cdist_out_type_dir:=$__cdist_out_dir/$__cdist_name_type} -: ${__cdist_out_type_bin_dir:=$__cdist_out_dir/$__cdist_name_type_bin} - -: ${__cdist_objects_created:=$__cdist_out_object_dir/$__cdist_name_objects_created} - -################################################################################ -# Remote base -# -: ${__cdist_remote_base_dir:=/var/lib/cdist} -: ${__cdist_remote_bin_dir:=$__cdist_remote_base_dir/$__cdist_name_bin} -: ${__cdist_remote_conf_dir:=$__cdist_remote_base_dir/$__cdist_name_conf_dir} - -: ${__cdist_remote_explorer_dir:=$__cdist_remote_conf_dir/$__cdist_name_explorer} -: ${__cdist_remote_type_dir:=$__cdist_remote_conf_dir/$__cdist_name_type} - -################################################################################ -# Remote output -# -: ${__cdist_remote_out_dir:=$__cdist_remote_base_dir/$__cdist_name_out_dir} -: ${__cdist_remote_out_explorer_dir:=$__cdist_remote_out_dir/$__cdist_name_explorer} -: ${__cdist_remote_out_object_dir:=$__cdist_remote_out_dir/$__cdist_name_object} - - -################################################################################ -# Internal functions -# -__cdist_echo() -{ - __cdist_echo_type="$1"; shift - - set +u - if [ "$__cdist_object_self" ]; then - __cdist_echo_prefix="${__cdist_object_self}:" - else - __cdist_echo_prefix="core: " - fi - set -u - - case "$__cdist_echo_type" in - debug) - set +u - if [ "$__cdist_debug" ]; then - echo $__cdist_echo_prefix "Debug: $@" - fi - set -u - ;; - info) - echo $__cdist_echo_prefix "$@" - ;; - warn) - echo $__cdist_echo_prefix "Warning: $@" - ;; - error) - echo $__cdist_echo_prefix "Error: $@" >&2 - ;; - *) - echo "CORE BUG, who created the broken commit in $0?" >&2 - exit 23 - ;; - esac -} - -__cdist_exec_fail_on_error() -{ - set +e - sh -e "$@" - if [ "$?" -ne 0 ]; then - __cdist_echo error "$1 exited non-zero" - __cdist_echo warn "Faulty code:" - cat "$1" - __cdist_exit_err "Aborting due to non-zero exit code." - fi -} - -__cdist_exit_err() -{ - __cdist_echo error "$@" - exit 1 -} - -__cdist_usage() -{ - __cdist_exit_err "$__cdist_myname: $@" -} - -__cdist_init_deploy() -{ - __cdist_echo info "Creating clean directory structure " - - # Ensure there is no old stuff, neither local nor remote - rm -rf "$__cdist_local_base_dir" - ssh "${__cdist_remote_user}@$1" "rm -rf ${__cdist_remote_base_dir}" - - # Init base - mkdir -p "$__cdist_local_base_dir" - ssh "${__cdist_remote_user}@$1" "mkdir -p ${__cdist_remote_base_dir}" - - # Link configuration source directory - consistent with remote - ln -sf "$__cdist_conf_dir" "$__cdist_local_base_dir/$__cdist_name_conf_dir" -} - -################################################################################ -# Cache -# -__cdist_cache_dir() -{ - cd "${__cdist_local_base_cache_dir}" && pwd -P -} - -__cdist_host_cache_dir() -{ - echo "$(__cdist_cache_dir)/$1" -} - -################################################################################ -# Object -# - -__cdist_object_code() -{ - echo "$(__cdist_object_dir "$1")/${__cdist_name_code}-$2" -} - -__cdist_object_prepared() -{ - echo "$(__cdist_object_dir "$1")/${__cdist_name_object_prepared}" -} - -__cdist_object_finished() -{ - echo "$(__cdist_object_dir "$1")/${__cdist_name_object_finished}" -} - -__cdist_object_dir() -{ - echo "$(__cdist_object_base_dir "$1")/${__cdist_name_dot_cdist}" -} - -__cdist_object_base_dir() -{ - echo "${__cdist_out_object_dir}/$1" -} - - -__cdist_object_id_from_object() -{ - echo "${1#*/}" -} - -# Find objects, remove ./ and /MARKER -__cdist_object_list() -{ - local basedir="$1"; shift - - # Use subshell to prevent changing cwd in program - ( - cd "${basedir}" - - find . -name "$__cdist_name_dot_cdist" | \ - sed -e 's;^./;;' -e "s;/${__cdist_name_dot_cdist}\$;;" - ) -} - -__cdist_object_parameter_dir() -{ - echo "$(__cdist_object_dir "$1")/${__cdist_name_parameter}" -} - -__cdist_object_require() -{ - echo "$(__cdist_object_dir "$1")/${__cdist_name_require}" -} - -__cdist_object_source_name() -{ - echo "$1/${__cdist_name_object_source}" -} - -__cdist_object_source() -{ - cat "$(__cdist_object_source_name "$1")" -} - -__cdist_object_source_add() -{ - echo "$__cdist_manifest" >> "$(__cdist_object_source_name "$1")" -} - -__cdist_object_type_explorer_dir() -{ - echo "$(__cdist_object_dir "$1")/${__cdist_name_explorer}" -} - -################################################################################ -# Remote -# - -__cdist_remote_object_base_dir() -{ - echo "${__cdist_remote_out_object_dir}/$1" -} - -__cdist_remote_object_dir() -{ - echo "$(__cdist_remote_object_base_dir "$1")/${__cdist_name_dot_cdist}" -} - -__cdist_remote_object_parameter_dir() -{ - echo "$(__cdist_remote_object_dir "$1")/${__cdist_name_parameter}" -} - -__cdist_remote_object_type_explorer_dir() -{ - echo "$(__cdist_remote_object_dir "$1")/${__cdist_name_explorer}" -} - - -__cdist_remote_type_explorer_dir() -{ - echo "${__cdist_remote_type_dir}/$1/${__cdist_name_explorer}" -} - - -################################################################################ -# Traps -# -__cdist_tmp_removal() -{ - rm -rf "${__cdist_tmp_dir}" -} - -# Does not work in children, will be called again in every script! -# Use only in interactive "front end" scripts -__cdist_kill_on_interrupt() -{ - __cdist_tmp_removal - kill 0 - exit 1 -} - -# Remove tempfiles at normal exit -trap __cdist_tmp_removal EXIT - - -################################################################################ -# Type -# -__cdist_type_dir() -{ - echo "${__cdist_type_dir}/$1" -} - -__cdist_type_explorer_dir() -{ - echo "${__cdist_type_dir}/$1/${__cdist_name_explorer}" -} - -__cdist_type_from_object() -{ - echo "${1%%/*}" -} - -__cdist_type_has_explorer() -{ - # We only create output, if there's at least one explorer - # and can thus be used as a boolean ;-) - if [ -d "$(__cdist_type_explorer_dir "$1")" ]; then - ls -1 "$(__cdist_type_explorer_dir "$1")" - fi -} - -__cdist_type_explorer_pushed() -{ - [ -f "${__cdist_out_type_dir}/${__cdist_name_type_explorer_pushed}" ] \ - && grep -q "$1" "${__cdist_out_type_dir}/${__cdist_name_type_explorer_pushed}" -} - -__cdist_type_explorer_pushed_add() -{ - [ -d "$__cdist_out_type_dir" ] || mkdir "$__cdist_out_type_dir" - echo "$1" >> "${__cdist_out_type_dir}/${__cdist_name_type_explorer_pushed}" -} - -__cdist_type_gencode() -{ - echo "${__cdist_type_dir}/$1/${__cdist_name_gencode}-$2" -} - -__cdist_type_manifest() -{ - echo "${__cdist_type_dir}/$1/${__cdist_name_manifest}" -} - -__cdist_type_parameter_dir() -{ - echo "$(__cdist_type_dir "$1")/${__cdist_name_parameter}" -} - -__cdist_type_parameter_optional() -{ - echo "$(__cdist_type_parameter_dir "$1")/$__cdist_name_parameter_optional" -} - -__cdist_type_parameter_required() -{ - echo "$(__cdist_type_parameter_dir "$1")/$__cdist_name_parameter_required" -} - -__cdist_type_singleton() -{ - echo "${__cdist_type_dir}/$1/${__cdist_name_singleton}" -} diff --git a/bin/cdist-quickstart b/doc/man/man7/cdist-quickstart.text similarity index 100% rename from bin/cdist-quickstart rename to doc/man/man7/cdist-quickstart.text From 9e99d420b688200df9abf742a2d36444b86c13d5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Sep 2011 00:52:09 +0200 Subject: [PATCH 0315/4212] in theory implement double definition strategy in new type emulator Signed-off-by: Nico Schottelius --- bin/cdist | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/bin/cdist b/bin/cdist index 57c889f1..adb8bd78 100755 --- a/bin/cdist +++ b/bin/cdist @@ -613,6 +613,7 @@ def emulator(): type_dir = os.path.join(os.environ['__cdist_type_base_dir'], type) param_dir = os.path.join(type_dir, "parameter") global_dir = os.environ['__global'] + object_source = os.environ['__cdist_manifest'] parser = argparse.ArgumentParser(add_help=False) @@ -652,10 +653,20 @@ def emulator(): object_id, DOT_CDIST) param_out_dir = os.path.join(object_dir, "parameter") - try: - os.makedirs(param_out_dir, exist_ok=True) - except OSError as error: - exit_error(param_out_dir + ": " + error.args[1]) + object_source_file = os.path.join(object_dir, "source") + + if os.path.exists(param_out_dir): + object_exists = True + old_object_source_fd = open(object_source_file, "r") + old_object_source = old_object_source_fd.readlines() + old_object_source_fd.close() + + else: + object_exists = False + try: + os.makedirs(param_out_dir, exist_ok=True) + except OSError as error: + exit_error(param_out_dir + ": " + error.args[1]) # Record parameter params = vars(args) @@ -664,10 +675,26 @@ def emulator(): if value: file = os.path.join(param_out_dir, param) log.debug(file + "<-" + param + " = " + value) - param_fd = open(file, "w") - param_fd.writelines(value) - param_fd.close() + # Already exists, verify all parameter are the same + if object_exists: + if not os.path.isfile(file): + print("New parameter + " + param + "specified, aborting") + print("Source = " + old_object_source + "new =" + object_source) + sys.exit(1) + else: + param_fd = open(file, "r") + param_old = param_fd.realines() + param_fd.close() + + if(param_old != param): + print("Parameter differs: " + param_old + "vs," + param) + print("Source = " + old_object_source + "new =" + object_source) + sys.exit(1) + else: + param_fd = open(file, "w") + param_fd.writelines(value) + param_fd.close() # Record requirements if "__require" in os.environ: @@ -677,12 +704,9 @@ def emulator(): require_fd.writelines(requirements.split(" ")) require_fd.close() - # FIXME: Merge / mv object into tree - # Record / Append source - source = os.environ['__cdist_manifest'] source_fd = open(os.path.join(object_dir, "source"), "a") - source_fd.writelines(source) + source_fd.writelines(object_source) source_fd.close() # sys.exit(1) From f8c49708cf7cb24dc3e1afbce8ff103999b5ef71 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Sep 2011 00:53:06 +0200 Subject: [PATCH 0316/4212] contrib is not contrib but other stuff this also help tab expansion Signed-off-by: Nico Schottelius --- .../examples/nico/conf/type/__nico_afs/files/afs/CellServDB | 0 .../examples/nico/conf/type/__nico_afs/files/afs/ThisCell | 0 .../examples/nico/conf/type/__nico_afs/files/krb5/krb5.conf | 0 .../examples/nico/conf/type/__nico_afs/files/ssh/JAS.pub | 0 .../examples/nico/conf/type/__nico_afs/files/ssh/bugblue.pub | 0 .../examples/nico/conf/type/__nico_afs/files/ssh/docsteel.pub | 0 .../examples/nico/conf/type/__nico_afs/files/ssh/downhill.pub | 0 .../examples/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub | 0 {contrib => other}/examples/nico/conf/type/__nico_afs/manifest | 0 {contrib => other}/examples/nico/conf/type/__nico_afs/singleton | 0 .../examples/nico/conf/type/__nico_desktop/files/hostname | 0 .../examples/nico/conf/type/__nico_desktop/files/slim-preseed | 0 .../examples/nico/conf/type/__nico_desktop/manifest | 0 .../examples/nico/conf/type/__nico_desktop/parameter/required | 0 .../examples/nico/conf/type/__nico_desktop/singleton | 0 .../examples/nico/conf/type/__nico_mpd/files/slim-preseed | 0 {contrib => other}/examples/nico/conf/type/__nico_mpd/manifest | 0 .../examples/nico/conf/type/__nico_mpd/parameter/required | 0 {contrib => other}/examples/nico/conf/type/__nico_mpd/singleton | 0 .../examples/nico/conf/type/__nico_network/files/interfaces-eth0 | 0 .../examples/nico/conf/type/__nico_network/files/interfaces-wlan0 | 0 .../examples/nico/conf/type/__nico_network/manifest | 0 .../examples/nico/conf/type/__nico_network/parameter/required | 0 .../examples/nico/conf/type/__nico_network/singleton | 0 .../examples/nico/conf/type/__nico_nfs_client/files/slim-preseed | 0 .../examples/nico/conf/type/__nico_nfs_client/manifest | 0 .../examples/nico/conf/type/__nico_nfs_client/singleton | 0 .../examples/nico/conf/type/__nico_notebook/manifest | 0 .../examples/nico/conf/type/__nico_notebook/singleton | 0 .../examples/nico/conf/type/__nico_packages/manifest | 0 .../examples/nico/conf/type/__nico_packages/singleton | 0 .../examples/nico/conf/type/__nico_sudo/files/sudo-nico | 0 {contrib => other}/examples/nico/conf/type/__nico_sudo/manifest | 0 .../examples/nico/conf/type/__nico_sudo/parameter/gencode | 0 .../examples/nico/conf/type/__nico_sudo/parameter/manifest | 0 .../examples/nico/conf/type/__nico_sudo/parameter/optional | 0 .../examples/nico/conf/type/__nico_sudo/parameter/required | 0 {contrib => other}/examples/nico/conf/type/__nico_sudo/singleton | 0 .../examples/nico/conf/type/__nico_tee/files/99-apt-nico | 0 .../examples/nico/conf/type/__nico_tee/files/hostname | 0 {contrib => other}/examples/nico/conf/type/__nico_tee/manifest | 0 {contrib => other}/examples/nico/conf/type/__nico_tee/singleton | 0 .../types_pending_inclusion/__package_zypper/README | 0 .../types_pending_inclusion/__package_zypper/explorer/pkg_version | 0 .../types_pending_inclusion/__package_zypper/gencode-remote | 0 .../types_pending_inclusion/__package_zypper/man.text | 0 .../types_pending_inclusion/__package_zypper/parameter/optional | 0 .../types_pending_inclusion/__package_zypper/parameter/required | 0 48 files changed, 0 insertions(+), 0 deletions(-) rename {contrib => other}/examples/nico/conf/type/__nico_afs/files/afs/CellServDB (100%) rename {contrib => other}/examples/nico/conf/type/__nico_afs/files/afs/ThisCell (100%) rename {contrib => other}/examples/nico/conf/type/__nico_afs/files/krb5/krb5.conf (100%) rename {contrib => other}/examples/nico/conf/type/__nico_afs/files/ssh/JAS.pub (100%) rename {contrib => other}/examples/nico/conf/type/__nico_afs/files/ssh/bugblue.pub (100%) rename {contrib => other}/examples/nico/conf/type/__nico_afs/files/ssh/docsteel.pub (100%) rename {contrib => other}/examples/nico/conf/type/__nico_afs/files/ssh/downhill.pub (100%) rename {contrib => other}/examples/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub (100%) rename {contrib => other}/examples/nico/conf/type/__nico_afs/manifest (100%) rename {contrib => other}/examples/nico/conf/type/__nico_afs/singleton (100%) rename {contrib => other}/examples/nico/conf/type/__nico_desktop/files/hostname (100%) rename {contrib => other}/examples/nico/conf/type/__nico_desktop/files/slim-preseed (100%) rename {contrib => other}/examples/nico/conf/type/__nico_desktop/manifest (100%) rename {contrib => other}/examples/nico/conf/type/__nico_desktop/parameter/required (100%) rename {contrib => other}/examples/nico/conf/type/__nico_desktop/singleton (100%) rename {contrib => other}/examples/nico/conf/type/__nico_mpd/files/slim-preseed (100%) rename {contrib => other}/examples/nico/conf/type/__nico_mpd/manifest (100%) rename {contrib => other}/examples/nico/conf/type/__nico_mpd/parameter/required (100%) rename {contrib => other}/examples/nico/conf/type/__nico_mpd/singleton (100%) rename {contrib => other}/examples/nico/conf/type/__nico_network/files/interfaces-eth0 (100%) rename {contrib => other}/examples/nico/conf/type/__nico_network/files/interfaces-wlan0 (100%) rename {contrib => other}/examples/nico/conf/type/__nico_network/manifest (100%) rename {contrib => other}/examples/nico/conf/type/__nico_network/parameter/required (100%) rename {contrib => other}/examples/nico/conf/type/__nico_network/singleton (100%) rename {contrib => other}/examples/nico/conf/type/__nico_nfs_client/files/slim-preseed (100%) rename {contrib => other}/examples/nico/conf/type/__nico_nfs_client/manifest (100%) rename {contrib => other}/examples/nico/conf/type/__nico_nfs_client/singleton (100%) rename {contrib => other}/examples/nico/conf/type/__nico_notebook/manifest (100%) rename {contrib => other}/examples/nico/conf/type/__nico_notebook/singleton (100%) rename {contrib => other}/examples/nico/conf/type/__nico_packages/manifest (100%) rename {contrib => other}/examples/nico/conf/type/__nico_packages/singleton (100%) rename {contrib => other}/examples/nico/conf/type/__nico_sudo/files/sudo-nico (100%) rename {contrib => other}/examples/nico/conf/type/__nico_sudo/manifest (100%) rename {contrib => other}/examples/nico/conf/type/__nico_sudo/parameter/gencode (100%) rename {contrib => other}/examples/nico/conf/type/__nico_sudo/parameter/manifest (100%) rename {contrib => other}/examples/nico/conf/type/__nico_sudo/parameter/optional (100%) rename {contrib => other}/examples/nico/conf/type/__nico_sudo/parameter/required (100%) rename {contrib => other}/examples/nico/conf/type/__nico_sudo/singleton (100%) rename {contrib => other}/examples/nico/conf/type/__nico_tee/files/99-apt-nico (100%) rename {contrib => other}/examples/nico/conf/type/__nico_tee/files/hostname (100%) rename {contrib => other}/examples/nico/conf/type/__nico_tee/manifest (100%) rename {contrib => other}/examples/nico/conf/type/__nico_tee/singleton (100%) rename {contrib => other}/types_pending_inclusion/__package_zypper/README (100%) rename {contrib => other}/types_pending_inclusion/__package_zypper/explorer/pkg_version (100%) rename {contrib => other}/types_pending_inclusion/__package_zypper/gencode-remote (100%) rename {contrib => other}/types_pending_inclusion/__package_zypper/man.text (100%) rename {contrib => other}/types_pending_inclusion/__package_zypper/parameter/optional (100%) rename {contrib => other}/types_pending_inclusion/__package_zypper/parameter/required (100%) diff --git a/contrib/examples/nico/conf/type/__nico_afs/files/afs/CellServDB b/other/examples/nico/conf/type/__nico_afs/files/afs/CellServDB similarity index 100% rename from contrib/examples/nico/conf/type/__nico_afs/files/afs/CellServDB rename to other/examples/nico/conf/type/__nico_afs/files/afs/CellServDB diff --git a/contrib/examples/nico/conf/type/__nico_afs/files/afs/ThisCell b/other/examples/nico/conf/type/__nico_afs/files/afs/ThisCell similarity index 100% rename from contrib/examples/nico/conf/type/__nico_afs/files/afs/ThisCell rename to other/examples/nico/conf/type/__nico_afs/files/afs/ThisCell diff --git a/contrib/examples/nico/conf/type/__nico_afs/files/krb5/krb5.conf b/other/examples/nico/conf/type/__nico_afs/files/krb5/krb5.conf similarity index 100% rename from contrib/examples/nico/conf/type/__nico_afs/files/krb5/krb5.conf rename to other/examples/nico/conf/type/__nico_afs/files/krb5/krb5.conf diff --git a/contrib/examples/nico/conf/type/__nico_afs/files/ssh/JAS.pub b/other/examples/nico/conf/type/__nico_afs/files/ssh/JAS.pub similarity index 100% rename from contrib/examples/nico/conf/type/__nico_afs/files/ssh/JAS.pub rename to other/examples/nico/conf/type/__nico_afs/files/ssh/JAS.pub diff --git a/contrib/examples/nico/conf/type/__nico_afs/files/ssh/bugblue.pub b/other/examples/nico/conf/type/__nico_afs/files/ssh/bugblue.pub similarity index 100% rename from contrib/examples/nico/conf/type/__nico_afs/files/ssh/bugblue.pub rename to other/examples/nico/conf/type/__nico_afs/files/ssh/bugblue.pub diff --git a/contrib/examples/nico/conf/type/__nico_afs/files/ssh/docsteel.pub b/other/examples/nico/conf/type/__nico_afs/files/ssh/docsteel.pub similarity index 100% rename from contrib/examples/nico/conf/type/__nico_afs/files/ssh/docsteel.pub rename to other/examples/nico/conf/type/__nico_afs/files/ssh/docsteel.pub diff --git a/contrib/examples/nico/conf/type/__nico_afs/files/ssh/downhill.pub b/other/examples/nico/conf/type/__nico_afs/files/ssh/downhill.pub similarity index 100% rename from contrib/examples/nico/conf/type/__nico_afs/files/ssh/downhill.pub rename to other/examples/nico/conf/type/__nico_afs/files/ssh/downhill.pub diff --git a/contrib/examples/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub b/other/examples/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub similarity index 100% rename from contrib/examples/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub rename to other/examples/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub diff --git a/contrib/examples/nico/conf/type/__nico_afs/manifest b/other/examples/nico/conf/type/__nico_afs/manifest similarity index 100% rename from contrib/examples/nico/conf/type/__nico_afs/manifest rename to other/examples/nico/conf/type/__nico_afs/manifest diff --git a/contrib/examples/nico/conf/type/__nico_afs/singleton b/other/examples/nico/conf/type/__nico_afs/singleton similarity index 100% rename from contrib/examples/nico/conf/type/__nico_afs/singleton rename to other/examples/nico/conf/type/__nico_afs/singleton diff --git a/contrib/examples/nico/conf/type/__nico_desktop/files/hostname b/other/examples/nico/conf/type/__nico_desktop/files/hostname similarity index 100% rename from contrib/examples/nico/conf/type/__nico_desktop/files/hostname rename to other/examples/nico/conf/type/__nico_desktop/files/hostname diff --git a/contrib/examples/nico/conf/type/__nico_desktop/files/slim-preseed b/other/examples/nico/conf/type/__nico_desktop/files/slim-preseed similarity index 100% rename from contrib/examples/nico/conf/type/__nico_desktop/files/slim-preseed rename to other/examples/nico/conf/type/__nico_desktop/files/slim-preseed diff --git a/contrib/examples/nico/conf/type/__nico_desktop/manifest b/other/examples/nico/conf/type/__nico_desktop/manifest similarity index 100% rename from contrib/examples/nico/conf/type/__nico_desktop/manifest rename to other/examples/nico/conf/type/__nico_desktop/manifest diff --git a/contrib/examples/nico/conf/type/__nico_desktop/parameter/required b/other/examples/nico/conf/type/__nico_desktop/parameter/required similarity index 100% rename from contrib/examples/nico/conf/type/__nico_desktop/parameter/required rename to other/examples/nico/conf/type/__nico_desktop/parameter/required diff --git a/contrib/examples/nico/conf/type/__nico_desktop/singleton b/other/examples/nico/conf/type/__nico_desktop/singleton similarity index 100% rename from contrib/examples/nico/conf/type/__nico_desktop/singleton rename to other/examples/nico/conf/type/__nico_desktop/singleton diff --git a/contrib/examples/nico/conf/type/__nico_mpd/files/slim-preseed b/other/examples/nico/conf/type/__nico_mpd/files/slim-preseed similarity index 100% rename from contrib/examples/nico/conf/type/__nico_mpd/files/slim-preseed rename to other/examples/nico/conf/type/__nico_mpd/files/slim-preseed diff --git a/contrib/examples/nico/conf/type/__nico_mpd/manifest b/other/examples/nico/conf/type/__nico_mpd/manifest similarity index 100% rename from contrib/examples/nico/conf/type/__nico_mpd/manifest rename to other/examples/nico/conf/type/__nico_mpd/manifest diff --git a/contrib/examples/nico/conf/type/__nico_mpd/parameter/required b/other/examples/nico/conf/type/__nico_mpd/parameter/required similarity index 100% rename from contrib/examples/nico/conf/type/__nico_mpd/parameter/required rename to other/examples/nico/conf/type/__nico_mpd/parameter/required diff --git a/contrib/examples/nico/conf/type/__nico_mpd/singleton b/other/examples/nico/conf/type/__nico_mpd/singleton similarity index 100% rename from contrib/examples/nico/conf/type/__nico_mpd/singleton rename to other/examples/nico/conf/type/__nico_mpd/singleton diff --git a/contrib/examples/nico/conf/type/__nico_network/files/interfaces-eth0 b/other/examples/nico/conf/type/__nico_network/files/interfaces-eth0 similarity index 100% rename from contrib/examples/nico/conf/type/__nico_network/files/interfaces-eth0 rename to other/examples/nico/conf/type/__nico_network/files/interfaces-eth0 diff --git a/contrib/examples/nico/conf/type/__nico_network/files/interfaces-wlan0 b/other/examples/nico/conf/type/__nico_network/files/interfaces-wlan0 similarity index 100% rename from contrib/examples/nico/conf/type/__nico_network/files/interfaces-wlan0 rename to other/examples/nico/conf/type/__nico_network/files/interfaces-wlan0 diff --git a/contrib/examples/nico/conf/type/__nico_network/manifest b/other/examples/nico/conf/type/__nico_network/manifest similarity index 100% rename from contrib/examples/nico/conf/type/__nico_network/manifest rename to other/examples/nico/conf/type/__nico_network/manifest diff --git a/contrib/examples/nico/conf/type/__nico_network/parameter/required b/other/examples/nico/conf/type/__nico_network/parameter/required similarity index 100% rename from contrib/examples/nico/conf/type/__nico_network/parameter/required rename to other/examples/nico/conf/type/__nico_network/parameter/required diff --git a/contrib/examples/nico/conf/type/__nico_network/singleton b/other/examples/nico/conf/type/__nico_network/singleton similarity index 100% rename from contrib/examples/nico/conf/type/__nico_network/singleton rename to other/examples/nico/conf/type/__nico_network/singleton diff --git a/contrib/examples/nico/conf/type/__nico_nfs_client/files/slim-preseed b/other/examples/nico/conf/type/__nico_nfs_client/files/slim-preseed similarity index 100% rename from contrib/examples/nico/conf/type/__nico_nfs_client/files/slim-preseed rename to other/examples/nico/conf/type/__nico_nfs_client/files/slim-preseed diff --git a/contrib/examples/nico/conf/type/__nico_nfs_client/manifest b/other/examples/nico/conf/type/__nico_nfs_client/manifest similarity index 100% rename from contrib/examples/nico/conf/type/__nico_nfs_client/manifest rename to other/examples/nico/conf/type/__nico_nfs_client/manifest diff --git a/contrib/examples/nico/conf/type/__nico_nfs_client/singleton b/other/examples/nico/conf/type/__nico_nfs_client/singleton similarity index 100% rename from contrib/examples/nico/conf/type/__nico_nfs_client/singleton rename to other/examples/nico/conf/type/__nico_nfs_client/singleton diff --git a/contrib/examples/nico/conf/type/__nico_notebook/manifest b/other/examples/nico/conf/type/__nico_notebook/manifest similarity index 100% rename from contrib/examples/nico/conf/type/__nico_notebook/manifest rename to other/examples/nico/conf/type/__nico_notebook/manifest diff --git a/contrib/examples/nico/conf/type/__nico_notebook/singleton b/other/examples/nico/conf/type/__nico_notebook/singleton similarity index 100% rename from contrib/examples/nico/conf/type/__nico_notebook/singleton rename to other/examples/nico/conf/type/__nico_notebook/singleton diff --git a/contrib/examples/nico/conf/type/__nico_packages/manifest b/other/examples/nico/conf/type/__nico_packages/manifest similarity index 100% rename from contrib/examples/nico/conf/type/__nico_packages/manifest rename to other/examples/nico/conf/type/__nico_packages/manifest diff --git a/contrib/examples/nico/conf/type/__nico_packages/singleton b/other/examples/nico/conf/type/__nico_packages/singleton similarity index 100% rename from contrib/examples/nico/conf/type/__nico_packages/singleton rename to other/examples/nico/conf/type/__nico_packages/singleton diff --git a/contrib/examples/nico/conf/type/__nico_sudo/files/sudo-nico b/other/examples/nico/conf/type/__nico_sudo/files/sudo-nico similarity index 100% rename from contrib/examples/nico/conf/type/__nico_sudo/files/sudo-nico rename to other/examples/nico/conf/type/__nico_sudo/files/sudo-nico diff --git a/contrib/examples/nico/conf/type/__nico_sudo/manifest b/other/examples/nico/conf/type/__nico_sudo/manifest similarity index 100% rename from contrib/examples/nico/conf/type/__nico_sudo/manifest rename to other/examples/nico/conf/type/__nico_sudo/manifest diff --git a/contrib/examples/nico/conf/type/__nico_sudo/parameter/gencode b/other/examples/nico/conf/type/__nico_sudo/parameter/gencode similarity index 100% rename from contrib/examples/nico/conf/type/__nico_sudo/parameter/gencode rename to other/examples/nico/conf/type/__nico_sudo/parameter/gencode diff --git a/contrib/examples/nico/conf/type/__nico_sudo/parameter/manifest b/other/examples/nico/conf/type/__nico_sudo/parameter/manifest similarity index 100% rename from contrib/examples/nico/conf/type/__nico_sudo/parameter/manifest rename to other/examples/nico/conf/type/__nico_sudo/parameter/manifest diff --git a/contrib/examples/nico/conf/type/__nico_sudo/parameter/optional b/other/examples/nico/conf/type/__nico_sudo/parameter/optional similarity index 100% rename from contrib/examples/nico/conf/type/__nico_sudo/parameter/optional rename to other/examples/nico/conf/type/__nico_sudo/parameter/optional diff --git a/contrib/examples/nico/conf/type/__nico_sudo/parameter/required b/other/examples/nico/conf/type/__nico_sudo/parameter/required similarity index 100% rename from contrib/examples/nico/conf/type/__nico_sudo/parameter/required rename to other/examples/nico/conf/type/__nico_sudo/parameter/required diff --git a/contrib/examples/nico/conf/type/__nico_sudo/singleton b/other/examples/nico/conf/type/__nico_sudo/singleton similarity index 100% rename from contrib/examples/nico/conf/type/__nico_sudo/singleton rename to other/examples/nico/conf/type/__nico_sudo/singleton diff --git a/contrib/examples/nico/conf/type/__nico_tee/files/99-apt-nico b/other/examples/nico/conf/type/__nico_tee/files/99-apt-nico similarity index 100% rename from contrib/examples/nico/conf/type/__nico_tee/files/99-apt-nico rename to other/examples/nico/conf/type/__nico_tee/files/99-apt-nico diff --git a/contrib/examples/nico/conf/type/__nico_tee/files/hostname b/other/examples/nico/conf/type/__nico_tee/files/hostname similarity index 100% rename from contrib/examples/nico/conf/type/__nico_tee/files/hostname rename to other/examples/nico/conf/type/__nico_tee/files/hostname diff --git a/contrib/examples/nico/conf/type/__nico_tee/manifest b/other/examples/nico/conf/type/__nico_tee/manifest similarity index 100% rename from contrib/examples/nico/conf/type/__nico_tee/manifest rename to other/examples/nico/conf/type/__nico_tee/manifest diff --git a/contrib/examples/nico/conf/type/__nico_tee/singleton b/other/examples/nico/conf/type/__nico_tee/singleton similarity index 100% rename from contrib/examples/nico/conf/type/__nico_tee/singleton rename to other/examples/nico/conf/type/__nico_tee/singleton diff --git a/contrib/types_pending_inclusion/__package_zypper/README b/other/types_pending_inclusion/__package_zypper/README similarity index 100% rename from contrib/types_pending_inclusion/__package_zypper/README rename to other/types_pending_inclusion/__package_zypper/README diff --git a/contrib/types_pending_inclusion/__package_zypper/explorer/pkg_version b/other/types_pending_inclusion/__package_zypper/explorer/pkg_version similarity index 100% rename from contrib/types_pending_inclusion/__package_zypper/explorer/pkg_version rename to other/types_pending_inclusion/__package_zypper/explorer/pkg_version diff --git a/contrib/types_pending_inclusion/__package_zypper/gencode-remote b/other/types_pending_inclusion/__package_zypper/gencode-remote similarity index 100% rename from contrib/types_pending_inclusion/__package_zypper/gencode-remote rename to other/types_pending_inclusion/__package_zypper/gencode-remote diff --git a/contrib/types_pending_inclusion/__package_zypper/man.text b/other/types_pending_inclusion/__package_zypper/man.text similarity index 100% rename from contrib/types_pending_inclusion/__package_zypper/man.text rename to other/types_pending_inclusion/__package_zypper/man.text diff --git a/contrib/types_pending_inclusion/__package_zypper/parameter/optional b/other/types_pending_inclusion/__package_zypper/parameter/optional similarity index 100% rename from contrib/types_pending_inclusion/__package_zypper/parameter/optional rename to other/types_pending_inclusion/__package_zypper/parameter/optional diff --git a/contrib/types_pending_inclusion/__package_zypper/parameter/required b/other/types_pending_inclusion/__package_zypper/parameter/required similarity index 100% rename from contrib/types_pending_inclusion/__package_zypper/parameter/required rename to other/types_pending_inclusion/__package_zypper/parameter/required From 1745f0bbc36a8f6da4c11afda63c6a3747e092ae Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Sep 2011 08:31:14 +0200 Subject: [PATCH 0317/4212] also document TMPDIR and TEMP Signed-off-by: Nico Schottelius --- doc/man/man1/cdist.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man/man1/cdist.text b/doc/man/man1/cdist.text index c43e4e1c..03948036 100644 --- a/doc/man/man1/cdist.text +++ b/doc/man/man1/cdist.text @@ -84,7 +84,7 @@ cdist --version ENVIRONMENT ----------- -TMP:: +TMPDIR, TEMP, TMP:: Setup the base directory for the temporary directory. See http://docs.python.org/py3k/library/tempfile.html for more information. This is rather useful, if the standard From 2a5ee06b0e68537d8489300b652715430e58df9d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 19 Sep 2011 14:04:52 +0200 Subject: [PATCH 0318/4212] no need to redefine again and again inside loop Signed-off-by: Steven Armstrong --- bin/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index adb8bd78..6726295a 100755 --- a/bin/cdist +++ b/bin/cdist @@ -354,8 +354,8 @@ class Cdist: def link_type_to_emulator(self): """Link type names to cdist-type-emulator""" + source = sys.argv[0] for type in self.list_types(): - source = sys.argv[0] destination = os.path.join(self.bin_dir, type) log.debug("Linking %s to %s", source, destination) os.symlink(source, destination) From 1c1ebac90c22ade5a35310b92955230665984fdd Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 19 Sep 2011 14:05:31 +0200 Subject: [PATCH 0319/4212] dont break if sys.argv[0] is a relative path Signed-off-by: Steven Armstrong --- bin/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 6726295a..a5383524 100755 --- a/bin/cdist +++ b/bin/cdist @@ -354,7 +354,7 @@ class Cdist: def link_type_to_emulator(self): """Link type names to cdist-type-emulator""" - source = sys.argv[0] + source = os.path.abspath(sys.argv[0]) for type in self.list_types(): destination = os.path.join(self.bin_dir, type) log.debug("Linking %s to %s", source, destination) From de7123df792a0bba7ad0b92460c0a06a40578775 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Sep 2011 14:38:52 +0200 Subject: [PATCH 0320/4212] always catch KeyboardInterrupt Signed-off-by: Nico Schottelius --- bin/cdist | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bin/cdist b/bin/cdist index a5383524..5ce947ef 100755 --- a/bin/cdist +++ b/bin/cdist @@ -772,13 +772,13 @@ def commandline(): logging.root.setLevel(logging.DEBUG) log.debug(args) - try: - args.func(args) - except KeyboardInterrupt: - sys.exit(0) + args.func(args) if __name__ == "__main__": - if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): - emulator() - else: - commandline() + try: + if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): + emulator() + else: + commandline() + except KeyboardInterrupt: + sys.exit(0) From 20bb4d044b6162bc11cd035829f64e6562f644a5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 20 Sep 2011 13:29:08 +0200 Subject: [PATCH 0321/4212] --typo: .realines( vs. readlines( Signed-off-by: Nico Schottelius --- bin/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 5ce947ef..1f44ba2d 100755 --- a/bin/cdist +++ b/bin/cdist @@ -684,7 +684,7 @@ def emulator(): sys.exit(1) else: param_fd = open(file, "r") - param_old = param_fd.realines() + param_old = param_fd.readlines() param_fd.close() if(param_old != param): From e3849b917c29cf6a86241a1fb2b1403e28b5def5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 20 Sep 2011 14:34:19 +0200 Subject: [PATCH 0322/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 84745512..9e9ca0e7 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -13,6 +13,10 @@ - Fix / rewrite cdist-quickstart +- write tutorial!!!!!!!!! + - like ccollect! + - include ssh control master! + -------------------------------------------------------------------------------- - Initial install support From 143a3a62dda6c7e08c0f3a66dc359507d634744b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 20 Sep 2011 14:40:20 +0200 Subject: [PATCH 0323/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 9e9ca0e7..44829060 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -16,6 +16,7 @@ - write tutorial!!!!!!!!! - like ccollect! - include ssh control master! + - add local/ hint (and add to git) -------------------------------------------------------------------------------- From 12e6e9288e85fc16f84ccbd3eac73e7cd08ca3e3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 20 Sep 2011 14:45:19 +0200 Subject: [PATCH 0324/4212] ++tutorial Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 44829060..91dbc72f 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -17,6 +17,9 @@ - like ccollect! - include ssh control master! - add local/ hint (and add to git) + - add hint for ssh StrictHostKeyChecking no + - and that ssh will wait for answer of prompt + - nasty if used in parallel mode (scroll up!) -------------------------------------------------------------------------------- From 462ed49a74e2d8c512b85163d2cd2fafda4f4a09 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 22 Sep 2011 18:43:36 +0200 Subject: [PATCH 0325/4212] BUGFIX: TypeError: Can't convert 'list' object to str implicitly (in emulator) Signed-off-by: Nico Schottelius --- bin/cdist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 1f44ba2d..9a745251 100755 --- a/bin/cdist +++ b/bin/cdist @@ -688,8 +688,8 @@ def emulator(): param_fd.close() if(param_old != param): - print("Parameter differs: " + param_old + "vs," + param) - print("Source = " + old_object_source + "new =" + object_source) + print("Parameter " + param + " differs: " + " ".join(param_old) + " vs. " + param) + print("Sources: " + " ".join(old_object_source) + " and " + object_source) sys.exit(1) else: param_fd = open(file, "w") From 7a09266abf391a98c3a9f836af4176e6d99c62a9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 13:49:02 +0200 Subject: [PATCH 0326/4212] allow users to check whether an object changed Signed-off-by: Nico Schottelius --- bin/cdist | 6 +++++- doc/changelog | 4 +++- doc/man/cdist-reference.text.sh | 10 ++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 9a745251..e085a226 100755 --- a/bin/cdist +++ b/bin/cdist @@ -485,7 +485,7 @@ class Cdist: ] for bin in paths: if os.path.isfile(bin): - # omit "gen" from gencode and + # omit "gen" from gencode and use it for output base outfile=os.path.join(self.object_dir(cdist_object), os.path.basename(bin)[3:]) @@ -507,6 +507,10 @@ class Cdist: # Add header and make executable - identically to 0o700 os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + # Mark object as changed + open(os.path.join(self.object_dir(cdist_object), "changed"), "w").close() + + if mode == "code": local_dir = self.object_dir(cdist_object) remote_dir = self.remote_object_dir(cdist_object) diff --git a/doc/changelog b/doc/changelog index cc6aa78b..d69011ee 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,5 +1,7 @@ 2.0.1: - * Bugfix cdist: Always print source of error in case of exec errors + * Bugfix core: Always print source of error in case of exec errors + * Bugfix core: Various smaller bugs in string concatenation + * Feature: Add marker "changed" to changed objects 2.0.0: 2011-09-16 * New Type: __package_rubygem (Chase Allen James) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index e38f157d..c205bdcc 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -154,6 +154,16 @@ done cat << eof +OBJECTS +------- +For object to object communication and tests, the following paths are +usable within a object directory: + +changed:: + This empty file exists in an object directory, if the object has + code to be excuted (either remote or local) + + ENVIRONMENT VARIABLES --------------------- __explorer:: From ca3644b73a4ceb9ac0c156ca07d1b2b49851675d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 13:50:49 +0200 Subject: [PATCH 0327/4212] ++version Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index d69011ee..b1149eb1 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,4 +1,4 @@ -2.0.1: +2.0.1: 2011-09-23 * Bugfix core: Always print source of error in case of exec errors * Bugfix core: Various smaller bugs in string concatenation * Feature: Add marker "changed" to changed objects From 412778206c15d929f26c567b36bb85557818cef1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 14:21:33 +0200 Subject: [PATCH 0328/4212] and increment version Signed-off-by: Nico Schottelius --- bin/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index e085a226..30db1ec9 100755 --- a/bin/cdist +++ b/bin/cdist @@ -57,7 +57,7 @@ REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") CODE_HEADER = "#!/bin/sh -e\n" DOT_CDIST = ".cdist" TYPE_PREFIX = "__" -VERSION = "2.0.0" +VERSION = "2.0.1" logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') log = logging.getLogger() From 199245e6ce100718c47a40839930dd55ca1c9d21 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 14:54:39 +0200 Subject: [PATCH 0329/4212] ignore more pycache stuff Signed-off-by: Nico Schottelius --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d606aec7..259e3be3 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,4 @@ doc/man/man*/docbook-xsl.css cache/ # Python -bin/__pycache__/ +*/__pycache__/ From b8ff4c9609d61033deab83b4e3be082cde7b45fe Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 14:55:00 +0200 Subject: [PATCH 0330/4212] begin split into smaller files Signed-off-by: Nico Schottelius --- bin/cdist | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/cdist b/bin/cdist index 30db1ec9..fe3c17fd 100755 --- a/bin/cdist +++ b/bin/cdist @@ -62,6 +62,10 @@ VERSION = "2.0.1" logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') log = logging.getLogger() +# Begin to split into parts +sys.path.insert(0, + os.path.abspath(os.path.join(os.path.dirname(__file__), + '../lib/python'))) def file_to_list(filename): """Return list from \n seperated file""" From 211212e079fb1582658b4448e0c1ac2c0efdf0d1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 16:01:24 +0200 Subject: [PATCH 0331/4212] test template Signed-off-by: Nico Schottelius --- test/cdist.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 test/cdist.py diff --git a/test/cdist.py b/test/cdist.py new file mode 100644 index 00000000..3ccc69bc --- /dev/null +++ b/test/cdist.py @@ -0,0 +1,12 @@ +import cdist +import unittest + + +class CdistGeneric(unittest.TestCase): + + def test_initial_manifest(self): + self.assertEqual(numeral, result) + + +if __name__ == '__main__': + unittest.main() From 721119a34f5bf7a3267eb906e11a6ef7c009e200 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 23 Sep 2011 16:18:55 +0200 Subject: [PATCH 0332/4212] quote arguments Signed-off-by: Steven Armstrong --- conf/type/__partition_msdos_apply/files/lib.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/conf/type/__partition_msdos_apply/files/lib.sh b/conf/type/__partition_msdos_apply/files/lib.sh index 0e9705d9..e24c1cb7 100644 --- a/conf/type/__partition_msdos_apply/files/lib.sh +++ b/conf/type/__partition_msdos_apply/files/lib.sh @@ -7,8 +7,8 @@ debug() { } fdisk_command() { - local device=$1 - local cmd=$2 + local device="$1" + local cmd="$2" debug fdisk_command "running fdisk command '${cmd}' on device ${device}" echo -en "${cmd}\nw\n" | fdisk -c -u "$device" @@ -24,11 +24,11 @@ create_disklabel() { } create_partition() { - local device=$1 - local minor=$2 - local size=$3 - local type=$4 - local primary_count=$5 + local device="$1" + local minor="$2" + local size="$3" + local type="$4" + local primary_count="$5" if [ "$type" = "extended" -o "$type" = "5" ]; then # Extended partition From ef97849676d0a8ce8909ac138c2887b1e6b069ed Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 23 Sep 2011 16:20:26 +0200 Subject: [PATCH 0333/4212] distinguish between disk size and extended partition size Signed-off-by: Steven Armstrong --- .../__partition_msdos_apply/gencode-remote | 46 +++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/conf/type/__partition_msdos_apply/gencode-remote b/conf/type/__partition_msdos_apply/gencode-remote index d352abdb..1d5c33cb 100755 --- a/conf/type/__partition_msdos_apply/gencode-remote +++ b/conf/type/__partition_msdos_apply/gencode-remote @@ -23,7 +23,8 @@ die() { exit 1 } debug() { - echo "[__partition_msdos_apply] $@" >&2 + #echo "[__partition_msdos_apply] $@" >&2 + : } # Convert a size specifier 1G 100M or 50% into the corresponding numeric MB. @@ -57,32 +58,43 @@ cat "$__type/files/lib.sh" partitions="$__object/explorer/partitions" objects=$(find "$__global/object/__partition_msdos" -path "*.cdist") current_device="" +available_device_size= +available_extended_size= available_size= primary_count=0 for object in $objects; do device="$(cat "$object/parameter/device")" if [ "$current_device" != "$device" ]; then - echo "create_disklabel $device" + echo "create_disklabel \"$device\" || die 'Failed to create disklabel for $device'" current_device="$device" device_name=$(echo ${device} | sed -e 's:^/dev/::;s:/:\\/:g') - available_size=$(( $(awk "/${device_name}\$/ { print \$3; }" "$partitions") / 1024)) + available_device_size=$(( $(awk "/${device_name}\$/ { print \$3; }" "$partitions") / 1024)) # make sure we don't go past the end of the drive - available_size=$((available_size - 2)) + available_device_size=$((available_device_size - 2)) + available_extended_size=0 primary_count=0 debug "----- $device" debug "current_device=$current_device" - debug "available_size=$available_size" + debug "available_device_size=$available_device_size" fi type="$(cat "$object/parameter/type")" partition="$(cat "$object/parameter/partition")" minor="$(cat "$object/parameter/minor")" - if [ "${minor}" -lt "5" ]; then - primary_count=$(( $primary_count + 1 )) - fi bootable="$(cat "$object/parameter/bootable")" size="$(cat "$object/parameter/size")" + + + if [ "${minor}" -lt "5" ]; then + # Primary partitions + primary_count=$(( $primary_count + 1 )) + available_size=$available_device_size + else + # Logical partitions + available_size=$available_extended_size + fi + if [ "$size" = "+" ]; then # use rest of device partition_size="" @@ -92,6 +104,18 @@ for object in $objects; do available_size="$(( $available_size - $partition_size ))" fi + if [ "${minor}" -lt "5" ]; then + # Primary partitions + available_device_size=$available_size + if [ "$type" = "extended" -o "$type" = "5" ]; then + # Extended partition + available_extended_size=$partition_size + fi + else + # Logical paritions + available_extended_size=$available_size + fi + [ "$partition_size" = "-1" ] && die "could not translate size '$size' to a usable value" debug "----- $partition" debug "primary_count=$primary_count" @@ -104,7 +128,11 @@ for object in $objects; do debug "size=$size" debug "partition_size=$partition_size" debug "available_size=$available_size" + debug "available_device_size=$available_device_size" + debug "available_extended_size=$available_extended_size" + debug "----------" - echo "create_partition $device $minor $partition_size $type $primary_count" + echo "create_partition '$device' '$minor' '$partition_size' '$type' '$primary_count' \ + || die 'Failed to create partition: $partition'" done From ad5c33b7467e8224997183d48994b3b0de0ac9c4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 16:38:47 +0200 Subject: [PATCH 0334/4212] %s/\( \)/\1 /g + fix logo Signed-off-by: Nico Schottelius --- bin/cdist | 1348 ++++++++++++++++++++++++++--------------------------- 1 file changed, 674 insertions(+), 674 deletions(-) diff --git a/bin/cdist b/bin/cdist index fe3c17fd..2100bd4d 100755 --- a/bin/cdist +++ b/bin/cdist @@ -48,745 +48,745 @@ BANNER = """ """ # Given paths from installation -REMOTE_BASE_DIR = "/var/lib/cdist" -REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") -REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") -REMOTE_TYPE_DIR = os.path.join(REMOTE_CONF_DIR, "type") +REMOTE_BASE_DIR = "/var/lib/cdist" +REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") +REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") +REMOTE_TYPE_DIR = os.path.join(REMOTE_CONF_DIR, "type") REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") -CODE_HEADER = "#!/bin/sh -e\n" -DOT_CDIST = ".cdist" -TYPE_PREFIX = "__" -VERSION = "2.0.1" +CODE_HEADER = "#!/bin/sh -e\n" +DOT_CDIST = ".cdist" +TYPE_PREFIX = "__" +VERSION = "2.0.1" logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') log = logging.getLogger() # Begin to split into parts sys.path.insert(0, - os.path.abspath(os.path.join(os.path.dirname(__file__), - '../lib/python'))) + os.path.abspath(os.path.join(os.path.dirname(__file__), + '../lib/python'))) def file_to_list(filename): - """Return list from \n seperated file""" - if os.path.isfile(filename): - file_fd = open(filename, "r") - lines = file_fd.readlines() - file_fd.close() + """Return list from \n seperated file""" + if os.path.isfile(filename): + file_fd = open(filename, "r") + lines = file_fd.readlines() + file_fd.close() - # Remove \n from all lines - lines = map(lambda s: s.strip(), lines) - else: - lines = [] + # Remove \n from all lines + lines = map(lambda s: s.strip(), lines) + else: + lines = [] - return lines + return lines def exit_error(*args): - log.error(*args) - sys.exit(1) + log.error(*args) + sys.exit(1) class Cdist: - """Cdist main class to hold arbitrary data""" - - def __init__(self, target_host, - initial_manifest=False, remote_user="root", - home=None, debug=False): - self.target_host = target_host - self.remote_prefix = ["ssh", "root@" + self.target_host] - - # Setup directory paths - self.temp_dir = tempfile.mkdtemp() - - self.debug = debug - - if home: - self.base_dir = home - else: - self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) - - self.conf_dir = os.path.join(self.base_dir, "conf") - self.cache_base_dir = os.path.join(self.base_dir, "cache") - self.cache_dir = os.path.join(self.cache_base_dir, self.target_host) - self.global_explorer_dir = os.path.join(self.conf_dir, "explorer") - self.lib_dir = os.path.join(self.base_dir, "lib") - self.manifest_dir = os.path.join(self.conf_dir, "manifest") - self.type_base_dir = os.path.join(self.conf_dir, "type") - - self.out_dir = os.path.join(self.temp_dir, "out") - os.mkdir(self.out_dir) - - self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") - os.mkdir(self.global_explorer_out_dir) - - self.object_base_dir = os.path.join(self.out_dir, "object") - - # Setup binary directory + contents - self.bin_dir = os.path.join(self.out_dir, "bin") - os.mkdir(self.bin_dir) - self.link_type_to_emulator() - - # List of type explorers transferred - self.type_explorers_transferred = {} - - # objects - self.objects_prepared = [] - - self.remote_user = remote_user - - # Mostly static, but can be overwritten on user demand - if initial_manifest: - self.initial_manifest = initial_manifest - else: - self.initial_manifest = os.path.join(self.manifest_dir, "init") - - def cleanup(self): - # Do not use in __del__: - # http://docs.python.org/reference/datamodel.html#customization - # "other globals referenced by the __del__() method may already have been deleted - # or in the process of being torn down (e.g. the import machinery shutting down)" - # - log.debug("Saving" + self.temp_dir + "to " + self.cache_dir) - # Remove previous cache - if os.path.exists(self.cache_dir): - shutil.rmtree(self.cache_dir) - shutil.move(self.temp_dir, self.cache_dir) - - def remote_mkdir(self, directory): - """Create directory on remote side""" - self.run_or_fail(["mkdir", "-p", directory], remote=True) - - def remote_cat(filename): - """Use cat on the remote side for output""" - self.run_or_fail(["cat", filename], remote=True) - - def shell_run_or_debug_fail(self, script, *args, **kargs): - # Manually execute /bin/sh, because sh -e does what we want - # and sh -c -e does not exit if /bin/false called - args[0][:0] = [ "/bin/sh", "-e" ] - - remote = False - if "remote" in kargs: - if kargs["remote"]: - args[0][:0] = self.remote_prefix - remote = true - - del kargs["remote"] - - log.debug("Shell exec cmd: %s", args) - log.debug("Shell exec env: %s", kargs['env']) - try: - subprocess.check_call(*args, **kargs) - except subprocess.CalledProcessError: - log.error("Code that raised the error:\n") - if remote: - remote_cat(script) - else: - script_fd = open(script) - print(script_fd.read()) - script_fd.close() - - exit_error("Command failed (shell): " + " ".join(*args)) - except OSError as error: - exit_error(" ".join(*args) + ": " + error.args[1]) - - def run_or_fail(self, *args, **kargs): - if "remote" in kargs: - if kargs["remote"]: - args[0][:0] = self.remote_prefix - - del kargs["remote"] - - log.debug("Exec: " + " ".join(*args)) - try: - subprocess.check_call(*args, **kargs) - except subprocess.CalledProcessError: - exit_error("Command failed: " + " ".join(*args)) - except OSError as error: - exit_error(" ".join(*args) + ": " + error.args[1]) - - - def remove_remote_dir(self, destination): - self.run_or_fail(["rm", "-rf", destination], remote=True) - - def transfer_dir(self, source, destination): - """Transfer directory and previously delete the remote destination""" - self.remove_remote_dir(destination) - self.run_or_fail(["scp", "-qr", source, - self.remote_user + "@" + - self.target_host + ":" + - destination]) - - def transfer_file(self, source, destination): - """Transfer file""" - self.run_or_fail(["scp", "-q", source, - self.remote_user + "@" + - self.target_host + ":" + - destination]) - - def global_explorer_output_path(self, explorer): - """Returns path of the output for a global explorer""" - return os.path.join(self.global_explorer_out_dir, explorer) - - def type_explorer_output_dir(self, cdist_object): - """Returns and creates dir of the output for a type explorer""" - dir = os.path.join(self.object_dir(cdist_object), "explorer") - if not os.path.isdir(dir): - os.mkdir(dir) - - return dir - - def remote_global_explorer_path(self, explorer): - """Returns path to the remote explorer""" - return os.path.join(REMOTE_GLOBAL_EXPLORER_DIR, explorer) - - def list_global_explorers(self): - """Return list of available explorers""" - return os.listdir(self.global_explorer_dir) - - def list_type_explorers(self, type): - """Return list of available explorers for a specific type""" - dir = self.type_dir(type, "explorer") - if os.path.isdir(dir): - list = os.listdir(dir) - else: - list = [] - - log.debug("Explorers for %s in %s: %s", type, dir, list) - - return list - - def list_types(self): - return os.listdir(self.type_base_dir) - - def list_object_paths(self, starting_point): - """Return list of paths of existing objects""" - object_paths = [] - - for content in os.listdir(starting_point): - full_path = os.path.join(starting_point, content) - if os.path.isdir(full_path): - object_paths.extend(self.list_object_paths(starting_point = full_path)) - - # Directory contains .cdist -> is an object - if content == DOT_CDIST: - object_paths.append(starting_point) - - return object_paths - - def get_type_from_object(self, cdist_object): - """Returns the first part (i.e. type) of an object""" - return cdist_object.split(os.sep)[0] - - def get_object_id_from_object(self, cdist_object): - """Returns everything but the first part (i.e. object_id) of an object""" - return os.sep.join(cdist_object.split(os.sep)[1:]) - - def object_dir(self, cdist_object): - """Returns the full path to the object (including .cdist)""" - return os.path.join(self.object_base_dir, cdist_object, DOT_CDIST) - - def remote_object_dir(self, cdist_object): - """Returns the remote full path to the object (including .cdist)""" - return os.path.join(REMOTE_OBJECT_DIR, cdist_object, DOT_CDIST) - - def object_parameter_dir(self, cdist_object): - """Returns the dir to the object parameter""" - return os.path.join(self.object_dir(cdist_object), "parameter") - - def remote_object_parameter_dir(self, cdist_object): - """Returns the remote dir to the object parameter""" - return os.path.join(self.remote_object_dir(cdist_object), "parameter") - - def object_code_paths(self, cdist_object): - """Return paths to code scripts of object""" - return [os.path.join(self.object_dir(cdist_object), "code-local"), - os.path.join(self.object_dir(cdist_object), "code-remote")] - - def list_objects(self): - """Return list of existing objects""" - - objects = [] - if os.path.isdir(self.object_base_dir): - object_paths = self.list_object_paths(self.object_base_dir) - - for path in object_paths: - objects.append(os.path.relpath(path, self.object_base_dir)) - - return objects - - def type_dir(self, type, *args): - """Return directory the type""" - return os.path.join(self.type_base_dir, type, *args) - - def remote_type_explorer_dir(self, type): - """Return remote directory that holds the explorers of a type""" - return os.path.join(REMOTE_TYPE_DIR, type, "explorer") - - def transfer_object_parameter(self, cdist_object): - """Transfer the object parameter to the remote destination""" - # Create base path before using mkdir -p - self.remote_mkdir(self.remote_object_parameter_dir(cdist_object)) - - # Synchronise parameter dir afterwards - self.transfer_dir(self.object_parameter_dir(cdist_object), - self.remote_object_parameter_dir(cdist_object)) - - def transfer_global_explorers(self): - """Transfer the global explorers""" - self.remote_mkdir(REMOTE_GLOBAL_EXPLORER_DIR) - self.transfer_dir(self.global_explorer_dir, REMOTE_GLOBAL_EXPLORER_DIR) - - def transfer_type_explorers(self, type): - """Transfer explorers of a type, but only once""" - if type in self.type_explorers_transferred: - log.debug("Skipping retransfer for explorers of %s", type) - return - else: - # Do not retransfer - self.type_explorers_transferred[type] = 1 - - src = self.type_dir(type, "explorer") - remote_base = os.path.join(REMOTE_TYPE_DIR, type) - dst = self.remote_type_explorer_dir(type) - - # Only continue, if there is at least the directory - if os.path.isdir(src): - # Ensure that the path exists - self.remote_mkdir(remote_base) - self.transfer_dir(src, dst) - - - def link_type_to_emulator(self): - """Link type names to cdist-type-emulator""" - source = os.path.abspath(sys.argv[0]) - for type in self.list_types(): - destination = os.path.join(self.bin_dir, type) - log.debug("Linking %s to %s", source, destination) - os.symlink(source, destination) - - def run_global_explores(self): - """Run global explorers""" - explorers = self.list_global_explorers() - if(len(explorers) == 0): - exit_error("No explorers found in", self.global_explorer_dir) - - self.transfer_global_explorers() - for explorer in explorers: - output = self.global_explorer_output_path(explorer) - output_fd = open(output, mode='w') - cmd = [] - cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append(self.remote_global_explorer_path(explorer)) - - self.run_or_fail(cmd, stdout=output_fd, remote=True) - output_fd.close() - - def run_type_explorer(self, cdist_object): - """Run type specific explorers for objects""" - # Based on bin/cdist-object-explorer-run - - # Transfering explorers for this type - type = self.get_type_from_object(cdist_object) - self.transfer_type_explorers(type) - - cmd = [] - cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append("__type_explorer=" + self.remote_type_explorer_dir(type)) - cmd.append("__object=" + self.remote_object_dir(cdist_object)) - cmd.append("__object_id=" + self.get_object_id_from_object(cdist_object)) - cmd.append("__object_fq=" + cdist_object) - - # Need to transfer at least the parameters for objects to be useful - self.transfer_object_parameter(cdist_object) - - explorers = self.list_type_explorers(type) - for explorer in explorers: - remote_cmd = cmd + [os.path.join(self.remote_type_explorer_dir(type), explorer)] - output = os.path.join(self.type_explorer_output_dir(cdist_object), explorer) - output_fd = open(output, mode='w') - log.debug("%s exploring %s using %s storing to %s", - cdist_object, explorer, remote_cmd, output) - - self.run_or_fail(remote_cmd, stdout=output_fd, remote=True) - output_fd.close() - - def init_deploy(self): - """Ensure the base directories are cleaned up""" - log.debug("Creating clean directory structure") - - self.remove_remote_dir(REMOTE_BASE_DIR) - self.remote_mkdir(REMOTE_BASE_DIR) - - def run_initial_manifest(self): - """Run the initial manifest""" - env = { "__manifest" : self.manifest_dir } - self.run_manifest(self.initial_manifest, extra_env=env) - - def run_type_manifest(self, cdist_object): - """Run manifest for a specific object""" - type = self.get_type_from_object(cdist_object) - manifest = self.type_dir(type, "manifest") - - log.debug("%s: Running %s", cdist_object, manifest) - if os.path.exists(manifest): - env = { "__object" : self.object_dir(cdist_object), - "__object_id": self.get_object_id_from_object(cdist_object), - "__object_fq": cdist_object, - "__type": self.type_dir(type) - } - self.run_manifest(manifest, extra_env=env) - - def run_manifest(self, manifest, extra_env=None): - """Run a manifest""" - log.debug("Running manifest %s, env=%s", manifest, extra_env) - env = os.environ.copy() - env['PATH'] = self.bin_dir + ":" + env['PATH'] - - # Information required in every manifest - env['__target_host'] = self.target_host - env['__global'] = self.out_dir - - # Legacy stuff to make cdist-type-emulator work - env['__cdist_core_dir'] = os.path.join(self.base_dir, "core") - env['__cdist_local_base_dir'] = self.temp_dir - - # Submit information to new type emulator - env['__cdist_manifest'] = manifest - env['__cdist_type_base_dir'] = self.type_base_dir - - # Other environment stuff - if extra_env: - env.update(extra_env) - - self.shell_run_or_debug_fail(manifest, [manifest], env=env) - - def object_run(self, cdist_object, mode): - """Run gencode or code for an object""" - log.debug("Running %s from %s", mode, cdist_object) - file=os.path.join(self.object_dir(cdist_object), "require") - requirements = file_to_list(file) - type = self.get_type_from_object(cdist_object) - - for requirement in requirements: - log.debug("Object %s requires %s", cdist_object, requirement) - self.object_run(requirement, mode=mode) - - # - # Setup env Variable: - # - env = os.environ.copy() - env['__target_host'] = self.target_host - env['__global'] = self.out_dir - env["__object"] = self.object_dir(cdist_object) - env["__object_id"] = self.get_object_id_from_object(cdist_object) - env["__object_fq"] = cdist_object - env["__type"] = self.type_dir(type) - - if mode == "gencode": - paths = [ - self.type_dir(type, "gencode-local"), - self.type_dir(type, "gencode-remote") - ] - for bin in paths: - if os.path.isfile(bin): - # omit "gen" from gencode and use it for output base - outfile=os.path.join(self.object_dir(cdist_object), - os.path.basename(bin)[3:]) - - outfile_fd = open(outfile, "w") - - # Need to flush to ensure our write is done before stdout write - outfile_fd.write(CODE_HEADER) - outfile_fd.flush() - - self.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) - outfile_fd.close() - - status = os.stat(outfile) - - # Remove output if empty, else make it executable - if status.st_size == len(CODE_HEADER): - os.unlink(outfile) - else: - # Add header and make executable - identically to 0o700 - os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) - - # Mark object as changed - open(os.path.join(self.object_dir(cdist_object), "changed"), "w").close() - - - if mode == "code": - local_dir = self.object_dir(cdist_object) - remote_dir = self.remote_object_dir(cdist_object) - - bin = os.path.join(local_dir, "code-local") - if os.path.isfile(bin): - self.run_or_fail([bin], remote=False) - - - local_remote_code = os.path.join(local_dir, "code-remote") - remote_remote_code = os.path.join(remote_dir, "code-remote") - if os.path.isfile(local_remote_code): - self.transfer_file(local_remote_code, remote_remote_code) - self.run_or_fail([remote_remote_code], remote=True) - - def stage_prepare(self): - """Do everything for a deploy, minus the actual code stage""" - self.init_deploy() - self.run_global_explores() - self.run_initial_manifest() - - old_objects = [] - objects = self.list_objects() - - # Continue process until no new objects are created anymore - while old_objects != objects: - log.debug("Prepare stage") - old_objects = list(objects) - for cdist_object in objects: - if cdist_object in self.objects_prepared: - log.debug("Skipping rerun of object %s", cdist_object) - continue + """Cdist main class to hold arbitrary data""" + + def __init__(self, target_host, + initial_manifest=False, remote_user="root", + home=None, debug=False): + self.target_host = target_host + self.remote_prefix = ["ssh", "root@" + self.target_host] + + # Setup directory paths + self.temp_dir = tempfile.mkdtemp() + + self.debug = debug + + if home: + self.base_dir = home + else: + self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) + + self.conf_dir = os.path.join(self.base_dir, "conf") + self.cache_base_dir = os.path.join(self.base_dir, "cache") + self.cache_dir = os.path.join(self.cache_base_dir, self.target_host) + self.global_explorer_dir = os.path.join(self.conf_dir, "explorer") + self.lib_dir = os.path.join(self.base_dir, "lib") + self.manifest_dir = os.path.join(self.conf_dir, "manifest") + self.type_base_dir = os.path.join(self.conf_dir, "type") + + self.out_dir = os.path.join(self.temp_dir, "out") + os.mkdir(self.out_dir) + + self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") + os.mkdir(self.global_explorer_out_dir) + + self.object_base_dir = os.path.join(self.out_dir, "object") + + # Setup binary directory + contents + self.bin_dir = os.path.join(self.out_dir, "bin") + os.mkdir(self.bin_dir) + self.link_type_to_emulator() + + # List of type explorers transferred + self.type_explorers_transferred = {} + + # objects + self.objects_prepared = [] + + self.remote_user = remote_user + + # Mostly static, but can be overwritten on user demand + if initial_manifest: + self.initial_manifest = initial_manifest + else: + self.initial_manifest = os.path.join(self.manifest_dir, "init") + + def cleanup(self): + # Do not use in __del__: + # http://docs.python.org/reference/datamodel.html#customization + # "other globals referenced by the __del__() method may already have been deleted + # or in the process of being torn down (e.g. the import machinery shutting down)" + # + log.debug("Saving" + self.temp_dir + "to " + self.cache_dir) + # Remove previous cache + if os.path.exists(self.cache_dir): + shutil.rmtree(self.cache_dir) + shutil.move(self.temp_dir, self.cache_dir) + + def remote_mkdir(self, directory): + """Create directory on remote side""" + self.nun_or_fail(["mkdir", "-p", directory], remote=True) + + def remote_cat(filename): + """Use cat on the remote side for output""" + self.run_or_fail(["cat", filename], remote=True) + + def shell_run_or_debug_fail(self, script, *args, **kargs): + # Manually execute /bin/sh, because sh -e does what we want + # and sh -c -e does not exit if /bin/false called + args[0][:0] = [ "/bin/sh", "-e" ] + + remote = False + if "remote" in kargs: + if kargs["remote"]: + args[0][:0] = self.remote_prefix + remote = true + + del kargs["remote"] + + log.debug("Shell exec cmd: %s", args) + log.debug("Shell exec env: %s", kargs['env']) + try: + subprocess.check_call(*args, **kargs) + except subprocess.CalledProcessError: + log.error("Code that raised the error:\n") + if remote: + remote_cat(script) else: - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) - self.objects_prepared.append(cdist_object) + script_fd = open(script) + print(script_fd.read()) + script_fd.close() - objects = self.list_objects() + exit_error("Command failed (shell): " + " ".join(*args)) + except OSError as error: + exit_error(" ".join(*args) + ": " + error.args[1]) - def stage_run(self): - """The final (and real) step of deployment""" - log.debug("Actual run objects") - # Now do the final steps over the existing objects - for cdist_object in self.list_objects(): - log.debug("Run object: %s", cdist_object) - self.object_run(cdist_object, mode="gencode") - self.object_run(cdist_object, mode="code") + def run_or_fail(self, *args, **kargs): + if "remote" in kargs: + if kargs["remote"]: + args[0][:0] = self.remote_prefix - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to " + self.target_host) - time_start = datetime.datetime.now() + del kargs["remote"] - self.stage_prepare() - self.stage_run() + log.debug("Exec: " + " ".join(*args)) + try: + subprocess.check_call(*args, **kargs) + except subprocess.CalledProcessError: + exit_error("Command failed: " + " ".join(*args)) + except OSError as error: + exit_error(" ".join(*args) + ": " + error.args[1]) - time_end = datetime.datetime.now() - duration = time_end - time_start - log.info("Finished run of %s in %s seconds", - self.target_host, - duration.total_seconds()) - def deploy_and_cleanup(self): - """Do what is most often done: deploy & cleanup""" - self.deploy_to() - self.cleanup() + def remove_remote_dir(self, destination): + self.run_or_fail(["rm", "-rf", destination], remote=True) + + def transfer_dir(self, source, destination): + """Transfer directory and previously delete the remote destination""" + self.remove_remote_dir(destination) + self.run_or_fail(["scp", "-qr", source, + self.remote_user + "@" + + self.target_host + ":" + + destination]) + + def transfer_file(self, source, destination): + """Transfer file""" + self.run_or_fail(["scp", "-q", source, + self.remote_user + "@" + + self.target_host + ":" + + destination]) + + def global_explorer_output_path(self, explorer): + """Returns path of the output for a global explorer""" + return os.path.join(self.global_explorer_out_dir, explorer) + + def type_explorer_output_dir(self, cdist_object): + """Returns and creates dir of the output for a type explorer""" + dir = os.path.join(self.object_dir(cdist_object), "explorer") + if not os.path.isdir(dir): + os.mkdir(dir) + + return dir + + def remote_global_explorer_path(self, explorer): + """Returns path to the remote explorer""" + return os.path.join(REMOTE_GLOBAL_EXPLORER_DIR, explorer) + + def list_global_explorers(self): + """Return list of available explorers""" + return os.listdir(self.global_explorer_dir) + + def list_type_explorers(self, type): + """Return list of available explorers for a specific type""" + dir = self.type_dir(type, "explorer") + if os.path.isdir(dir): + list = os.listdir(dir) + else: + list = [] + + log.debug("Explorers for %s in %s: %s", type, dir, list) + + return list + + def list_types(self): + return os.listdir(self.type_base_dir) + + def list_object_paths(self, starting_point): + """Return list of paths of existing objects""" + object_paths = [] + + for content in os.listdir(starting_point): + full_path = os.path.join(starting_point, content) + if os.path.isdir(full_path): + object_paths.extend(self.list_object_paths(starting_point = full_path)) + + # Directory contains .cdist -> is an object + if content == DOT_CDIST: + object_paths.append(starting_point) + + return object_paths + + def get_type_from_object(self, cdist_object): + """Returns the first part (i.e. type) of an object""" + return cdist_object.split(os.sep)[0] + + def get_object_id_from_object(self, cdist_object): + """Returns everything but the first part (i.e. object_id) of an object""" + return os.sep.join(cdist_object.split(os.sep)[1:]) + + def object_dir(self, cdist_object): + """Returns the full path to the object (including .cdist)""" + return os.path.join(self.object_base_dir, cdist_object, DOT_CDIST) + + def remote_object_dir(self, cdist_object): + """Returns the remote full path to the object (including .cdist)""" + return os.path.join(REMOTE_OBJECT_DIR, cdist_object, DOT_CDIST) + + def object_parameter_dir(self, cdist_object): + """Returns the dir to the object parameter""" + return os.path.join(self.object_dir(cdist_object), "parameter") + + def remote_object_parameter_dir(self, cdist_object): + """Returns the remote dir to the object parameter""" + return os.path.join(self.remote_object_dir(cdist_object), "parameter") + + def object_code_paths(self, cdist_object): + """Return paths to code scripts of object""" + return [os.path.join(self.object_dir(cdist_object), "code-local"), + os.path.join(self.object_dir(cdist_object), "code-remote")] + + def list_objects(self): + """Return list of existing objects""" + + objects = [] + if os.path.isdir(self.object_base_dir): + object_paths = self.list_object_paths(self.object_base_dir) + + for path in object_paths: + objects.append(os.path.relpath(path, self.object_base_dir)) + + return objects + + def type_dir(self, type, *args): + """Return directory the type""" + return os.path.join(self.type_base_dir, type, *args) + + def remote_type_explorer_dir(self, type): + """Return remote directory that holds the explorers of a type""" + return os.path.join(REMOTE_TYPE_DIR, type, "explorer") + + def transfer_object_parameter(self, cdist_object): + """Transfer the object parameter to the remote destination""" + # Create base path before using mkdir -p + self.remote_mkdir(self.remote_object_parameter_dir(cdist_object)) + + # Synchronise parameter dir afterwards + self.transfer_dir(self.object_parameter_dir(cdist_object), + self.remote_object_parameter_dir(cdist_object)) + + def transfer_global_explorers(self): + """Transfer the global explorers""" + self.remote_mkdir(REMOTE_GLOBAL_EXPLORER_DIR) + self.transfer_dir(self.global_explorer_dir, REMOTE_GLOBAL_EXPLORER_DIR) + + def transfer_type_explorers(self, type): + """Transfer explorers of a type, but only once""" + if type in self.type_explorers_transferred: + log.debug("Skipping retransfer for explorers of %s", type) + return + else: + # Do not retransfer + self.type_explorers_transferred[type] = 1 + + src = self.type_dir(type, "explorer") + remote_base = os.path.join(REMOTE_TYPE_DIR, type) + dst = self.remote_type_explorer_dir(type) + + # Only continue, if there is at least the directory + if os.path.isdir(src): + # Ensure that the path exists + self.remote_mkdir(remote_base) + self.transfer_dir(src, dst) + + + def link_type_to_emulator(self): + """Link type names to cdist-type-emulator""" + source = os.path.abspath(sys.argv[0]) + for type in self.list_types(): + destination = os.path.join(self.bin_dir, type) + log.debug("Linking %s to %s", source, destination) + os.symlink(source, destination) + + def run_global_explores(self): + """Run global explorers""" + explorers = self.list_global_explorers() + if(len(explorers) == 0): + exit_error("No explorers found in", self.global_explorer_dir) + + self.transfer_global_explorers() + for explorer in explorers: + output = self.global_explorer_output_path(explorer) + output_fd = open(output, mode='w') + cmd = [] + cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append(self.remote_global_explorer_path(explorer)) + + self.run_or_fail(cmd, stdout=output_fd, remote=True) + output_fd.close() + + def run_type_explorer(self, cdist_object): + """Run type specific explorers for objects""" + # Based on bin/cdist-object-explorer-run + + # Transfering explorers for this type + type = self.get_type_from_object(cdist_object) + self.transfer_type_explorers(type) + + cmd = [] + cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append("__type_explorer=" + self.remote_type_explorer_dir(type)) + cmd.append("__object=" + self.remote_object_dir(cdist_object)) + cmd.append("__object_id=" + self.get_object_id_from_object(cdist_object)) + cmd.append("__object_fq=" + cdist_object) + + # Need to transfer at least the parameters for objects to be useful + self.transfer_object_parameter(cdist_object) + + explorers = self.list_type_explorers(type) + for explorer in explorers: + remote_cmd = cmd + [os.path.join(self.remote_type_explorer_dir(type), explorer)] + output = os.path.join(self.type_explorer_output_dir(cdist_object), explorer) + output_fd = open(output, mode='w') + log.debug("%s exploring %s using %s storing to %s", + cdist_object, explorer, remote_cmd, output) + + self.run_or_fail(remote_cmd, stdout=output_fd, remote=True) + output_fd.close() + + def init_deploy(self): + """Ensure the base directories are cleaned up""" + log.debug("Creating clean directory structure") + + self.remove_remote_dir(REMOTE_BASE_DIR) + self.remote_mkdir(REMOTE_BASE_DIR) + + def run_initial_manifest(self): + """Run the initial manifest""" + env = { "__manifest" : self.manifest_dir } + self.run_manifest(self.initial_manifest, extra_env=env) + + def run_type_manifest(self, cdist_object): + """Run manifest for a specific object""" + type = self.get_type_from_object(cdist_object) + manifest = self.type_dir(type, "manifest") + + log.debug("%s: Running %s", cdist_object, manifest) + if os.path.exists(manifest): + env = { "__object" : self.object_dir(cdist_object), + "__object_id": self.get_object_id_from_object(cdist_object), + "__object_fq": cdist_object, + "__type": self.type_dir(type) + } + self.run_manifest(manifest, extra_env=env) + + def run_manifest(self, manifest, extra_env=None): + """Run a manifest""" + log.debug("Running manifest %s, env=%s", manifest, extra_env) + env = os.environ.copy() + env['PATH'] = self.bin_dir + ":" + env['PATH'] + + # Information required in every manifest + env['__target_host'] = self.target_host + env['__global'] = self.out_dir + + # Legacy stuff to make cdist-type-emulator work + env['__cdist_core_dir'] = os.path.join(self.base_dir, "core") + env['__cdist_local_base_dir'] = self.temp_dir + + # Submit information to new type emulator + env['__cdist_manifest'] = manifest + env['__cdist_type_base_dir'] = self.type_base_dir + + # Other environment stuff + if extra_env: + env.update(extra_env) + + self.shell_run_or_debug_fail(manifest, [manifest], env=env) + + def object_run(self, cdist_object, mode): + """Run gencode or code for an object""" + log.debug("Running %s from %s", mode, cdist_object) + file=os.path.join(self.object_dir(cdist_object), "require") + requirements = file_to_list(file) + type = self.get_type_from_object(cdist_object) + + for requirement in requirements: + log.debug("Object %s requires %s", cdist_object, requirement) + self.object_run(requirement, mode=mode) + + # + # Setup env Variable: + # + env = os.environ.copy() + env['__target_host'] = self.target_host + env['__global'] = self.out_dir + env["__object"] = self.object_dir(cdist_object) + env["__object_id"] = self.get_object_id_from_object(cdist_object) + env["__object_fq"] = cdist_object + env["__type"] = self.type_dir(type) + + if mode == "gencode": + paths = [ + self.type_dir(type, "gencode-local"), + self.type_dir(type, "gencode-remote") + ] + for bin in paths: + if os.path.isfile(bin): + # omit "gen" from gencode and use it for output base + outfile=os.path.join(self.object_dir(cdist_object), + os.path.basename(bin)[3:]) + + outfile_fd = open(outfile, "w") + + # Need to flush to ensure our write is done before stdout write + outfile_fd.write(CODE_HEADER) + outfile_fd.flush() + + self.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) + outfile_fd.close() + + status = os.stat(outfile) + + # Remove output if empty, else make it executable + if status.st_size == len(CODE_HEADER): + os.unlink(outfile) + else: + # Add header and make executable - identically to 0o700 + os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + + # Mark object as changed + open(os.path.join(self.object_dir(cdist_object), "changed"), "w").close() + + + if mode == "code": + local_dir = self.object_dir(cdist_object) + remote_dir = self.remote_object_dir(cdist_object) + + bin = os.path.join(local_dir, "code-local") + if os.path.isfile(bin): + self.run_or_fail([bin], remote=False) + + + local_remote_code = os.path.join(local_dir, "code-remote") + remote_remote_code = os.path.join(remote_dir, "code-remote") + if os.path.isfile(local_remote_code): + self.transfer_file(local_remote_code, remote_remote_code) + self.run_or_fail([remote_remote_code], remote=True) + + def stage_prepare(self): + """Do everything for a deploy, minus the actual code stage""" + self.init_deploy() + self.run_global_explores() + self.run_initial_manifest() + + old_objects = [] + objects = self.list_objects() + + # Continue process until no new objects are created anymore + while old_objects != objects: + log.debug("Prepare stage") + old_objects = list(objects) + for cdist_object in objects: + if cdist_object in self.objects_prepared: + log.debug("Skipping rerun of object %s", cdist_object) + continue + else: + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + self.objects_prepared.append(cdist_object) + + objects = self.list_objects() + + def stage_run(self): + """The final (and real) step of deployment""" + log.debug("Actual run objects") + # Now do the final steps over the existing objects + for cdist_object in self.list_objects(): + log.debug("Run object: %s", cdist_object) + self.object_run(cdist_object, mode="gencode") + self.object_run(cdist_object, mode="code") + + def deploy_to(self): + """Mimic the old deploy to: Deploy to one host""" + log.info("Deploying to " + self.target_host) + time_start = datetime.datetime.now() + + self.stage_prepare() + self.stage_run() + + time_end = datetime.datetime.now() + duration = time_end - time_start + log.info("Finished run of %s in %s seconds", + self.target_host, + duration.total_seconds()) + + def deploy_and_cleanup(self): + """Do what is most often done: deploy & cleanup""" + self.deploy_to() + self.cleanup() def banner(args): - """Guess what :-)""" - print(BANNER) - sys.exit(0) + """Guess what :-)""" + print(BANNER) + sys.exit(0) def config(args): - """Configure remote system""" - process = {} + """Configure remote system""" + process = {} - time_start = datetime.datetime.now() + time_start = datetime.datetime.now() - for host in args.host: - c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) - if args.parallel: - log.debug("Creating child process for %s", host) - process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) - process[host].start() - else: - c.deploy_and_cleanup() + for host in args.host: + c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) + if args.parallel: + log.debug("Creating child process for %s", host) + process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) + process[host].start() + else: + c.deploy_and_cleanup() - if args.parallel: - for p in process.keys(): - log.debug("Joining %s", p) - process[p].join() + if args.parallel: + for p in process.keys(): + log.debug("Joining %s", p) + process[p].join() - time_end = datetime.datetime.now() - log.info("Total processing time for %s host(s): %s", len(args.host), - (time_end - time_start).total_seconds()) + time_end = datetime.datetime.now() + log.info("Total processing time for %s host(s): %s", len(args.host), + (time_end - time_start).total_seconds()) def install(args): - """Install remote system""" - process = {} + """Install remote system""" + process = {} def emulator(): - """Emulate type commands (i.e. __file and co)""" - type = os.path.basename(sys.argv[0]) - type_dir = os.path.join(os.environ['__cdist_type_base_dir'], type) - param_dir = os.path.join(type_dir, "parameter") - global_dir = os.environ['__global'] - object_source = os.environ['__cdist_manifest'] + """Emulate type commands (i.e. __file and co)""" + type = os.path.basename(sys.argv[0]) + type_dir = os.path.join(os.environ['__cdist_type_base_dir'], type) + param_dir = os.path.join(type_dir, "parameter") + global_dir = os.environ['__global'] + object_source = os.environ['__cdist_manifest'] - parser = argparse.ArgumentParser(add_help=False) + parser = argparse.ArgumentParser(add_help=False) - # Setup optional parameters - for parameter in file_to_list(os.path.join(param_dir, "optional")): - argument = "--" + parameter - parser.add_argument(argument, action='store', required=False) + # Setup optional parameters + for parameter in file_to_list(os.path.join(param_dir, "optional")): + argument = "--" + parameter + parser.add_argument(argument, action='store', required=False) - # Setup required parameters - for parameter in file_to_list(os.path.join(param_dir, "required")): - argument = "--" + parameter - parser.add_argument(argument, action='store', required=True) + # Setup required parameters + for parameter in file_to_list(os.path.join(param_dir, "required")): + argument = "--" + parameter + parser.add_argument(argument, action='store', required=True) - # Setup positional parameter, if not singleton + # Setup positional parameter, if not singleton - if not os.path.isfile(os.path.join(type_dir, "singleton")): - parser.add_argument("object_id", nargs=1) + if not os.path.isfile(os.path.join(type_dir, "singleton")): + parser.add_argument("object_id", nargs=1) - # And finally verify parameter - args = parser.parse_args(sys.argv[1:]) + # And finally verify parameter + args = parser.parse_args(sys.argv[1:]) - # Setup object_id - if os.path.isfile(os.path.join(type_dir, "singleton")): - object_id = "singleton" - else: - object_id = args.object_id[0] - del args.object_id + # Setup object_id + if os.path.isfile(os.path.join(type_dir, "singleton")): + object_id = "singleton" + else: + object_id = args.object_id[0] + del args.object_id - # FIXME: / hardcoded - better portable solution available? - if object_id[0] == '/': - object_id = object_id[1:] + # FIXME: / hardcoded - better portable solution available? + if object_id[0] == '/': + object_id = object_id[1:] - # FIXME: verify object id - log.debug(args) + # FIXME: verify object id + log.debug(args) - object_dir = os.path.join(global_dir, "object", type, - object_id, DOT_CDIST) - param_out_dir = os.path.join(object_dir, "parameter") + object_dir = os.path.join(global_dir, "object", type, + object_id, DOT_CDIST) + param_out_dir = os.path.join(object_dir, "parameter") - object_source_file = os.path.join(object_dir, "source") + object_source_file = os.path.join(object_dir, "source") - if os.path.exists(param_out_dir): - object_exists = True - old_object_source_fd = open(object_source_file, "r") - old_object_source = old_object_source_fd.readlines() - old_object_source_fd.close() + if os.path.exists(param_out_dir): + object_exists = True + old_object_source_fd = open(object_source_file, "r") + old_object_source = old_object_source_fd.readlines() + old_object_source_fd.close() - else: - object_exists = False - try: - os.makedirs(param_out_dir, exist_ok=True) - except OSError as error: - exit_error(param_out_dir + ": " + error.args[1]) + else: + object_exists = False + try: + os.makedirs(param_out_dir, exist_ok=True) + except OSError as error: + exit_error(param_out_dir + ": " + error.args[1]) - # Record parameter - params = vars(args) - for param in params: - value = getattr(args, param) - if value: - file = os.path.join(param_out_dir, param) - log.debug(file + "<-" + param + " = " + value) + # Record parameter + params = vars(args) + for param in params: + value = getattr(args, param) + if value: + file = os.path.join(param_out_dir, param) + log.debug(file + "<-" + param + " = " + value) - # Already exists, verify all parameter are the same - if object_exists: - if not os.path.isfile(file): - print("New parameter + " + param + "specified, aborting") - print("Source = " + old_object_source + "new =" + object_source) - sys.exit(1) + # Already exists, verify all parameter are the same + if object_exists: + if not os.path.isfile(file): + print("New parameter + " + param + "specified, aborting") + print("Source = " + old_object_source + "new =" + object_source) + sys.exit(1) + else: + param_fd = open(file, "r") + param_old = param_fd.readlines() + param_fd.close() + + if(param_old != param): + print("Parameter " + param + " differs: " + " ".join(param_old) + " vs. " + param) + print("Sources: " + " ".join(old_object_source) + " and " + object_source) + sys.exit(1) else: - param_fd = open(file, "r") - param_old = param_fd.readlines() - param_fd.close() - - if(param_old != param): - print("Parameter " + param + " differs: " + " ".join(param_old) + " vs. " + param) - print("Sources: " + " ".join(old_object_source) + " and " + object_source) - sys.exit(1) - else: - param_fd = open(file, "w") - param_fd.writelines(value) - param_fd.close() + param_fd = open(file, "w") + param_fd.writelines(value) + param_fd.close() - # Record requirements - if "__require" in os.environ: - requirements = os.environ['__require'] - print(object_id + ":Writing requirements: " + requirements) - require_fd = open(os.path.join(object_dir, "require"), "a") - require_fd.writelines(requirements.split(" ")) - require_fd.close() + # Record requirements + if "__require" in os.environ: + requirements = os.environ['__require'] + print(object_id + ":Writing requirements: " + requirements) + require_fd = open(os.path.join(object_dir, "require"), "a") + require_fd.writelines(requirements.split(" ")) + require_fd.close() - # Record / Append source - source_fd = open(os.path.join(object_dir, "source"), "a") - source_fd.writelines(object_source) - source_fd.close() + # Record / Append source + source_fd = open(os.path.join(object_dir, "source"), "a") + source_fd.writelines(object_source) + source_fd.close() - # sys.exit(1) - print("Finished " + type + "/" + object_id + repr(params)) + # sys.exit(1) + print("Finished " + type + "/" + object_id + repr(params)) def commandline(): - """Parse command line""" - # Construct parser others can reuse - parser = {} - # Options _all_ parsers have in common - parser['most'] = argparse.ArgumentParser(add_help=False) - parser['most'].add_argument('-d', '--debug', - help='Set log level to debug', action='store_true') + """Parse command line""" + # Construct parser others can reuse + parser = {} + # Options _all_ parsers have in common + parser['most'] = argparse.ArgumentParser(add_help=False) + parser['most'].add_argument('-d', '--debug', + help='Set log level to debug', action='store_true') - # Main subcommand parser - parser['main'] = argparse.ArgumentParser(description='cdist ' + VERSION) - parser['main'].add_argument('-V', '--version', - help='Show version', action='version', - version='%(prog)s ' + VERSION) - parser['sub'] = parser['main'].add_subparsers(title="Commands") + # Main subcommand parser + parser['main'] = argparse.ArgumentParser(description='cdist ' + VERSION) + parser['main'].add_argument('-V', '--version', + help='Show version', action='version', + version='%(prog)s ' + VERSION) + parser['sub'] = parser['main'].add_subparsers(title="Commands") - # Banner - parser['banner'] = parser['sub'].add_parser('banner', - add_help=False) - parser['banner'].set_defaults(func=banner) + # Banner + parser['banner'] = parser['sub'].add_parser('banner', + add_help=False) + parser['banner'].set_defaults(func=banner) - # Config and install (common stuff) - parser['configinstall'] = argparse.ArgumentParser(add_help=False) - parser['configinstall'].add_argument('host', nargs='+', - help='one or more hosts to operate on') - parser['configinstall'].add_argument('-c', '--cdist-home', - help='Change cdist home (default: .. from bin directory)', - action='store') - parser['configinstall'].add_argument('-i', '--initial-manifest', - help='Path to a cdist manifest', - dest='manifest', required=False) - parser['configinstall'].add_argument('-p', '--parallel', - help='Operate on multiple hosts in parallel', - action='store_true', dest='parallel') - parser['configinstall'].add_argument('-s', '--sequential', - help='Operate on multiple hosts sequentially (default)', - action='store_false', dest='parallel') + # Config and install (common stuff) + parser['configinstall'] = argparse.ArgumentParser(add_help=False) + parser['configinstall'].add_argument('host', nargs='+', + help='one or more hosts to operate on') + parser['configinstall'].add_argument('-c', '--cdist-home', + help='Change cdist home (default: .. from bin directory)', + action='store') + parser['configinstall'].add_argument('-i', '--initial-manifest', + help='Path to a cdist manifest', + dest='manifest', required=False) + parser['configinstall'].add_argument('-p', '--parallel', + help='Operate on multiple hosts in parallel', + action='store_true', dest='parallel') + parser['configinstall'].add_argument('-s', '--sequential', + help='Operate on multiple hosts sequentially (default)', + action='store_false', dest='parallel') - # Config - parser['config'] = parser['sub'].add_parser('config', - parents=[parser['most'], parser['configinstall']]) - parser['config'].set_defaults(func=config) + # Config + parser['config'] = parser['sub'].add_parser('config', + parents=[parser['most'], parser['configinstall']]) + parser['config'].set_defaults(func=config) - # Install - parser['install'] = parser['sub'].add_parser('install', - parents=[parser['most'], parser['configinstall']]) - parser['install'].set_defaults(func=install) + # Install + parser['install'] = parser['sub'].add_parser('install', + parents=[parser['most'], 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/" + for p in parser: + parser[p].epilog = "Get cdist at http://www.nico.schottelius.org/software/cdist/" - args = parser['main'].parse_args(sys.argv[1:]) + args = parser['main'].parse_args(sys.argv[1:]) - # Most subcommands have --debug, so handle it here - if 'debug' in args: - if args.debug: - logging.root.setLevel(logging.DEBUG) - log.debug(args) + # Most subcommands have --debug, so handle it here + if 'debug' in args: + if args.debug: + logging.root.setLevel(logging.DEBUG) + log.debug(args) - args.func(args) + args.func(args) if __name__ == "__main__": - try: - if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): - emulator() - else: - commandline() - except KeyboardInterrupt: - sys.exit(0) + try: + if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): + emulator() + else: + commandline() + except KeyboardInterrupt: + sys.exit(0) From f4da3b96d8a6fc97b241b43eb0c2520798507926 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 16:41:55 +0200 Subject: [PATCH 0335/4212] fix indentions Signed-off-by: Nico Schottelius --- bin/cdist | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/bin/cdist b/bin/cdist index 2100bd4d..f3b88fdd 100755 --- a/bin/cdist +++ b/bin/cdist @@ -48,16 +48,16 @@ BANNER = """ """ # Given paths from installation -REMOTE_BASE_DIR = "/var/lib/cdist" -REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") -REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") -REMOTE_TYPE_DIR = os.path.join(REMOTE_CONF_DIR, "type") -REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") +REMOTE_BASE_DIR = "/var/lib/cdist" +REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") +REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") +REMOTE_TYPE_DIR = os.path.join(REMOTE_CONF_DIR, "type") +REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") CODE_HEADER = "#!/bin/sh -e\n" -DOT_CDIST = ".cdist" +DOT_CDIST = ".cdist" TYPE_PREFIX = "__" -VERSION = "2.0.1" +VERSION = "2.0.1" logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') log = logging.getLogger() @@ -104,13 +104,13 @@ class Cdist: else: self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) - self.conf_dir = os.path.join(self.base_dir, "conf") - self.cache_base_dir = os.path.join(self.base_dir, "cache") - self.cache_dir = os.path.join(self.cache_base_dir, self.target_host) + self.conf_dir = os.path.join(self.base_dir, "conf") + self.cache_base_dir = os.path.join(self.base_dir, "cache") + self.cache_dir = os.path.join(self.cache_base_dir, self.target_host) self.global_explorer_dir = os.path.join(self.conf_dir, "explorer") - self.lib_dir = os.path.join(self.base_dir, "lib") - self.manifest_dir = os.path.join(self.conf_dir, "manifest") - self.type_base_dir = os.path.join(self.conf_dir, "type") + self.lib_dir = os.path.join(self.base_dir, "lib") + self.manifest_dir = os.path.join(self.conf_dir, "manifest") + self.type_base_dir = os.path.join(self.conf_dir, "type") self.out_dir = os.path.join(self.temp_dir, "out") os.mkdir(self.out_dir) From ea9dc8d60c648448c42f765fcab265c33cd55c0a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 23 Sep 2011 16:43:25 +0200 Subject: [PATCH 0336/4212] handle errors with exceptions instead of function Signed-off-by: Steven Armstrong --- bin/cdist | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/bin/cdist b/bin/cdist index fe3c17fd..e3d63458 100755 --- a/bin/cdist +++ b/bin/cdist @@ -81,9 +81,9 @@ def file_to_list(filename): return lines -def exit_error(*args): - log.error(*args) - sys.exit(1) +class CdistError(Exception): + """Base exception class for this project""" + pass class Cdist: """Cdist main class to hold arbitrary data""" @@ -185,9 +185,9 @@ class Cdist: print(script_fd.read()) script_fd.close() - exit_error("Command failed (shell): " + " ".join(*args)) + raise CdistError("Command failed (shell): " + " ".join(*args)) except OSError as error: - exit_error(" ".join(*args) + ": " + error.args[1]) + raise CdistError(" ".join(*args) + ": " + error.args[1]) def run_or_fail(self, *args, **kargs): if "remote" in kargs: @@ -200,9 +200,9 @@ class Cdist: try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: - exit_error("Command failed: " + " ".join(*args)) + raise CdistError("Command failed: " + " ".join(*args)) except OSError as error: - exit_error(" ".join(*args) + ": " + error.args[1]) + raise CdistError(" ".join(*args) + ": " + error.args[1]) def remove_remote_dir(self, destination): @@ -368,7 +368,7 @@ class Cdist: """Run global explorers""" explorers = self.list_global_explorers() if(len(explorers) == 0): - exit_error("No explorers found in", self.global_explorer_dir) + raise CdistError("No explorers found in", self.global_explorer_dir) self.transfer_global_explorers() for explorer in explorers: @@ -674,7 +674,7 @@ def emulator(): try: os.makedirs(param_out_dir, exist_ok=True) except OSError as error: - exit_error(param_out_dir + ": " + error.args[1]) + raise CdistError(param_out_dir + ": " + error.args[1]) # Record parameter params = vars(args) @@ -790,3 +790,6 @@ if __name__ == "__main__": commandline() except KeyboardInterrupt: sys.exit(0) + except CdistError as e: + log.error(e) + sys.exit(1) From b72fab3c01804b19f00744321f8e8e854e10c290 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 17:00:48 +0200 Subject: [PATCH 0337/4212] begin split into path module Signed-off-by: Nico Schottelius --- module/cdist/__init__.py | 0 module/cdist/path.py | 11 +++++++++++ 2 files changed, 11 insertions(+) create mode 100644 module/cdist/__init__.py create mode 100644 module/cdist/path.py diff --git a/module/cdist/__init__.py b/module/cdist/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/module/cdist/path.py b/module/cdist/path.py new file mode 100644 index 00000000..37d92940 --- /dev/null +++ b/module/cdist/path.py @@ -0,0 +1,11 @@ +class Path: + """Class that handles path related configurations""" + + def __init__(self, home=None): + if home: + self.base_dir = home + else: + self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) + + + print("Base:" + self.base_dir) From 3ace43ff01528717528034bb827ccc03b056b715 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 17:00:59 +0200 Subject: [PATCH 0338/4212] ignore pycache everywhere Signed-off-by: Nico Schottelius --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 259e3be3..bd4ecaaa 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,4 @@ doc/man/man*/docbook-xsl.css cache/ # Python -*/__pycache__/ +**/__pycache__/ From a2f3246758cf954e1eecf682c16992cbf9a6026d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 23 Sep 2011 17:03:00 +0200 Subject: [PATCH 0339/4212] fix typo /nun_or_fail/run_or_fail/ Signed-off-by: Steven Armstrong --- bin/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 0aa661a3..fde7a251 100755 --- a/bin/cdist +++ b/bin/cdist @@ -153,7 +153,7 @@ class Cdist: def remote_mkdir(self, directory): """Create directory on remote side""" - self.nun_or_fail(["mkdir", "-p", directory], remote=True) + self.run_or_fail(["mkdir", "-p", directory], remote=True) def remote_cat(filename): """Use cat on the remote side for output""" From 747517f06782db10da115f3f66f2115cf7e4fa48 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 17:06:42 +0200 Subject: [PATCH 0340/4212] import path information from current cdist Signed-off-by: Nico Schottelius --- module/cdist/path.py | 56 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/module/cdist/path.py b/module/cdist/path.py index 37d92940..ee492cc5 100644 --- a/module/cdist/path.py +++ b/module/cdist/path.py @@ -1,11 +1,59 @@ class Path: """Class that handles path related configurations""" - def __init__(self, home=None): + def __init__(self, target_host, base_dir=None): + # Base and Temp Base if home: - self.base_dir = home + self.base_dir = base_dir else: self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) - - print("Base:" + self.base_dir) + self.temp_dir = tempfile.mkdtemp() + + self.conf_dir = os.path.join(self.base_dir, "conf") + self.cache_base_dir = os.path.join(self.base_dir, "cache") + self.cache_dir = os.path.join(self.cache_base_dir, target_host) + self.global_explorer_dir = os.path.join(self.conf_dir, "explorer") + self.lib_dir = os.path.join(self.base_dir, "lib") + self.manifest_dir = os.path.join(self.conf_dir, "manifest") + self.type_base_dir = os.path.join(self.conf_dir, "type") + + self.out_dir = os.path.join(self.temp_dir, "out") + os.mkdir(self.out_dir) + + self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") + os.mkdir(self.global_explorer_out_dir) + + self.object_base_dir = os.path.join(self.out_dir, "object") + + # Setup binary directory + contents + self.bin_dir = os.path.join(self.out_dir, "bin") + os.mkdir(self.bin_dir) + self.link_type_to_emulator() + + # List of type explorers transferred + self.type_explorers_transferred = {} + + # objects + self.objects_prepared = [] + + self.remote_user = remote_user + + # Mostly static, but can be overwritten on user demand + if initial_manifest: + self.initial_manifest = initial_manifest + else: + self.initial_manifest = os.path.join(self.manifest_dir, "init") + + def cleanup(self): + # Do not use in __del__: + # http://docs.python.org/reference/datamodel.html#customization + # "other globals referenced by the __del__() method may already have been deleted + # or in the process of being torn down (e.g. the import machinery shutting down)" + # + log.debug("Saving" + self.temp_dir + "to " + self.cache_dir) + # Remove previous cache + if os.path.exists(self.cache_dir): + shutil.rmtree(self.cache_dir) + shutil.move(self.temp_dir, self.cache_dir) + From 26772939ca8dce14507358f100cbfd9bdeacdb4d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 17:11:03 +0200 Subject: [PATCH 0341/4212] import whole cdist into path.py and strip down (most stuff is moved here anyway) Signed-off-by: Nico Schottelius --- module/cdist/path.py | 665 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 665 insertions(+) diff --git a/module/cdist/path.py b/module/cdist/path.py index ee492cc5..387481ca 100644 --- a/module/cdist/path.py +++ b/module/cdist/path.py @@ -1,3 +1,28 @@ +# Given paths from installation +REMOTE_BASE_DIR = "/var/lib/cdist" +REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") +REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") +REMOTE_TYPE_DIR = os.path.join(REMOTE_CONF_DIR, "type") +REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") + +CODE_HEADER = "#!/bin/sh -e\n" +DOT_CDIST = ".cdist" +TYPE_PREFIX = "__" + +def file_to_list(filename): + """Return list from \n seperated file""" + if os.path.isfile(filename): + file_fd = open(filename, "r") + lines = file_fd.readlines() + file_fd.close() + + # Remove \n from all lines + lines = map(lambda s: s.strip(), lines) + else: + lines = [] + + return lines + class Path: """Class that handles path related configurations""" @@ -57,3 +82,643 @@ class Path: shutil.rmtree(self.cache_dir) shutil.move(self.temp_dir, self.cache_dir) + + def remote_mkdir(self, directory): + """Create directory on remote side""" + self.run_or_fail(["mkdir", "-p", directory], remote=True) + + def remote_cat(filename): + """Use cat on the remote side for output""" + self.run_or_fail(["cat", filename], remote=True) + + def shell_run_or_debug_fail(self, script, *args, **kargs): + # Manually execute /bin/sh, because sh -e does what we want + # and sh -c -e does not exit if /bin/false called + args[0][:0] = [ "/bin/sh", "-e" ] + + remote = False + if "remote" in kargs: + if kargs["remote"]: + args[0][:0] = self.remote_prefix + remote = true + + del kargs["remote"] + + log.debug("Shell exec cmd: %s", args) + log.debug("Shell exec env: %s", kargs['env']) + try: + subprocess.check_call(*args, **kargs) + except subprocess.CalledProcessError: + log.error("Code that raised the error:\n") + if remote: + remote_cat(script) + else: + script_fd = open(script) + print(script_fd.read()) + script_fd.close() + + exit_error("Command failed (shell): " + " ".join(*args)) + except OSError as error: + exit_error(" ".join(*args) + ": " + error.args[1]) + + def run_or_fail(self, *args, **kargs): + if "remote" in kargs: + if kargs["remote"]: + args[0][:0] = self.remote_prefix + + del kargs["remote"] + + log.debug("Exec: " + " ".join(*args)) + try: + subprocess.check_call(*args, **kargs) + except subprocess.CalledProcessError: + exit_error("Command failed: " + " ".join(*args)) + except OSError as error: + exit_error(" ".join(*args) + ": " + error.args[1]) + + + def remove_remote_dir(self, destination): + self.run_or_fail(["rm", "-rf", destination], remote=True) + + def transfer_dir(self, source, destination): + """Transfer directory and previously delete the remote destination""" + self.remove_remote_dir(destination) + self.run_or_fail(["scp", "-qr", source, + self.remote_user + "@" + + self.target_host + ":" + + destination]) + + def transfer_file(self, source, destination): + """Transfer file""" + self.run_or_fail(["scp", "-q", source, + self.remote_user + "@" + + self.target_host + ":" + + destination]) + + def global_explorer_output_path(self, explorer): + """Returns path of the output for a global explorer""" + return os.path.join(self.global_explorer_out_dir, explorer) + + def type_explorer_output_dir(self, cdist_object): + """Returns and creates dir of the output for a type explorer""" + dir = os.path.join(self.object_dir(cdist_object), "explorer") + if not os.path.isdir(dir): + os.mkdir(dir) + + return dir + + def remote_global_explorer_path(self, explorer): + """Returns path to the remote explorer""" + return os.path.join(REMOTE_GLOBAL_EXPLORER_DIR, explorer) + + def list_global_explorers(self): + """Return list of available explorers""" + return os.listdir(self.global_explorer_dir) + + def list_type_explorers(self, type): + """Return list of available explorers for a specific type""" + dir = self.type_dir(type, "explorer") + if os.path.isdir(dir): + list = os.listdir(dir) + else: + list = [] + + log.debug("Explorers for %s in %s: %s", type, dir, list) + + return list + + def list_types(self): + return os.listdir(self.type_base_dir) + + def list_object_paths(self, starting_point): + """Return list of paths of existing objects""" + object_paths = [] + + for content in os.listdir(starting_point): + full_path = os.path.join(starting_point, content) + if os.path.isdir(full_path): + object_paths.extend(self.list_object_paths(starting_point = full_path)) + + # Directory contains .cdist -> is an object + if content == DOT_CDIST: + object_paths.append(starting_point) + + return object_paths + + def get_type_from_object(self, cdist_object): + """Returns the first part (i.e. type) of an object""" + return cdist_object.split(os.sep)[0] + + def get_object_id_from_object(self, cdist_object): + """Returns everything but the first part (i.e. object_id) of an object""" + return os.sep.join(cdist_object.split(os.sep)[1:]) + + def object_dir(self, cdist_object): + """Returns the full path to the object (including .cdist)""" + return os.path.join(self.object_base_dir, cdist_object, DOT_CDIST) + + def remote_object_dir(self, cdist_object): + """Returns the remote full path to the object (including .cdist)""" + return os.path.join(REMOTE_OBJECT_DIR, cdist_object, DOT_CDIST) + + def object_parameter_dir(self, cdist_object): + """Returns the dir to the object parameter""" + return os.path.join(self.object_dir(cdist_object), "parameter") + + def remote_object_parameter_dir(self, cdist_object): + """Returns the remote dir to the object parameter""" + return os.path.join(self.remote_object_dir(cdist_object), "parameter") + + def object_code_paths(self, cdist_object): + """Return paths to code scripts of object""" + return [os.path.join(self.object_dir(cdist_object), "code-local"), + os.path.join(self.object_dir(cdist_object), "code-remote")] + + def list_objects(self): + """Return list of existing objects""" + + objects = [] + if os.path.isdir(self.object_base_dir): + object_paths = self.list_object_paths(self.object_base_dir) + + for path in object_paths: + objects.append(os.path.relpath(path, self.object_base_dir)) + + return objects + + def type_dir(self, type, *args): + """Return directory the type""" + return os.path.join(self.type_base_dir, type, *args) + + def remote_type_explorer_dir(self, type): + """Return remote directory that holds the explorers of a type""" + return os.path.join(REMOTE_TYPE_DIR, type, "explorer") + + def transfer_object_parameter(self, cdist_object): + """Transfer the object parameter to the remote destination""" + # Create base path before using mkdir -p + self.remote_mkdir(self.remote_object_parameter_dir(cdist_object)) + + # Synchronise parameter dir afterwards + self.transfer_dir(self.object_parameter_dir(cdist_object), + self.remote_object_parameter_dir(cdist_object)) + + def transfer_global_explorers(self): + """Transfer the global explorers""" + self.remote_mkdir(REMOTE_GLOBAL_EXPLORER_DIR) + self.transfer_dir(self.global_explorer_dir, REMOTE_GLOBAL_EXPLORER_DIR) + + def transfer_type_explorers(self, type): + """Transfer explorers of a type, but only once""" + if type in self.type_explorers_transferred: + log.debug("Skipping retransfer for explorers of %s", type) + return + else: + # Do not retransfer + self.type_explorers_transferred[type] = 1 + + src = self.type_dir(type, "explorer") + remote_base = os.path.join(REMOTE_TYPE_DIR, type) + dst = self.remote_type_explorer_dir(type) + + # Only continue, if there is at least the directory + if os.path.isdir(src): + # Ensure that the path exists + self.remote_mkdir(remote_base) + self.transfer_dir(src, dst) + + + def link_type_to_emulator(self): + """Link type names to cdist-type-emulator""" + source = os.path.abspath(sys.argv[0]) + for type in self.list_types(): + destination = os.path.join(self.bin_dir, type) + log.debug("Linking %s to %s", source, destination) + os.symlink(source, destination) + + def run_global_explores(self): + """Run global explorers""" + explorers = self.list_global_explorers() + if(len(explorers) == 0): + exit_error("No explorers found in", self.global_explorer_dir) + + self.transfer_global_explorers() + for explorer in explorers: + output = self.global_explorer_output_path(explorer) + output_fd = open(output, mode='w') + cmd = [] + cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append(self.remote_global_explorer_path(explorer)) + + self.run_or_fail(cmd, stdout=output_fd, remote=True) + output_fd.close() + + def run_type_explorer(self, cdist_object): + """Run type specific explorers for objects""" + # Based on bin/cdist-object-explorer-run + + # Transfering explorers for this type + type = self.get_type_from_object(cdist_object) + self.transfer_type_explorers(type) + + cmd = [] + cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append("__type_explorer=" + self.remote_type_explorer_dir(type)) + cmd.append("__object=" + self.remote_object_dir(cdist_object)) + cmd.append("__object_id=" + self.get_object_id_from_object(cdist_object)) + cmd.append("__object_fq=" + cdist_object) + + # Need to transfer at least the parameters for objects to be useful + self.transfer_object_parameter(cdist_object) + + explorers = self.list_type_explorers(type) + for explorer in explorers: + remote_cmd = cmd + [os.path.join(self.remote_type_explorer_dir(type), explorer)] + output = os.path.join(self.type_explorer_output_dir(cdist_object), explorer) + output_fd = open(output, mode='w') + log.debug("%s exploring %s using %s storing to %s", + cdist_object, explorer, remote_cmd, output) + + self.run_or_fail(remote_cmd, stdout=output_fd, remote=True) + output_fd.close() + + def init_deploy(self): + """Ensure the base directories are cleaned up""" + log.debug("Creating clean directory structure") + + self.remove_remote_dir(REMOTE_BASE_DIR) + self.remote_mkdir(REMOTE_BASE_DIR) + + def run_initial_manifest(self): + """Run the initial manifest""" + env = { "__manifest" : self.manifest_dir } + self.run_manifest(self.initial_manifest, extra_env=env) + + def run_type_manifest(self, cdist_object): + """Run manifest for a specific object""" + type = self.get_type_from_object(cdist_object) + manifest = self.type_dir(type, "manifest") + + log.debug("%s: Running %s", cdist_object, manifest) + if os.path.exists(manifest): + env = { "__object" : self.object_dir(cdist_object), + "__object_id": self.get_object_id_from_object(cdist_object), + "__object_fq": cdist_object, + "__type": self.type_dir(type) + } + self.run_manifest(manifest, extra_env=env) + + def run_manifest(self, manifest, extra_env=None): + """Run a manifest""" + log.debug("Running manifest %s, env=%s", manifest, extra_env) + env = os.environ.copy() + env['PATH'] = self.bin_dir + ":" + env['PATH'] + + # Information required in every manifest + env['__target_host'] = self.target_host + env['__global'] = self.out_dir + + # Legacy stuff to make cdist-type-emulator work + env['__cdist_core_dir'] = os.path.join(self.base_dir, "core") + env['__cdist_local_base_dir'] = self.temp_dir + + # Submit information to new type emulator + env['__cdist_manifest'] = manifest + env['__cdist_type_base_dir'] = self.type_base_dir + + # Other environment stuff + if extra_env: + env.update(extra_env) + + self.shell_run_or_debug_fail(manifest, [manifest], env=env) + + def object_run(self, cdist_object, mode): + """Run gencode or code for an object""" + log.debug("Running %s from %s", mode, cdist_object) + file=os.path.join(self.object_dir(cdist_object), "require") + requirements = file_to_list(file) + type = self.get_type_from_object(cdist_object) + + for requirement in requirements: + log.debug("Object %s requires %s", cdist_object, requirement) + self.object_run(requirement, mode=mode) + + # + # Setup env Variable: + # + env = os.environ.copy() + env['__target_host'] = self.target_host + env['__global'] = self.out_dir + env["__object"] = self.object_dir(cdist_object) + env["__object_id"] = self.get_object_id_from_object(cdist_object) + env["__object_fq"] = cdist_object + env["__type"] = self.type_dir(type) + + if mode == "gencode": + paths = [ + self.type_dir(type, "gencode-local"), + self.type_dir(type, "gencode-remote") + ] + for bin in paths: + if os.path.isfile(bin): + # omit "gen" from gencode and use it for output base + outfile=os.path.join(self.object_dir(cdist_object), + os.path.basename(bin)[3:]) + + outfile_fd = open(outfile, "w") + + # Need to flush to ensure our write is done before stdout write + outfile_fd.write(CODE_HEADER) + outfile_fd.flush() + + self.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) + outfile_fd.close() + + status = os.stat(outfile) + + # Remove output if empty, else make it executable + if status.st_size == len(CODE_HEADER): + os.unlink(outfile) + else: + # Add header and make executable - identically to 0o700 + os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + + # Mark object as changed + open(os.path.join(self.object_dir(cdist_object), "changed"), "w").close() + + + if mode == "code": + local_dir = self.object_dir(cdist_object) + remote_dir = self.remote_object_dir(cdist_object) + + bin = os.path.join(local_dir, "code-local") + if os.path.isfile(bin): + self.run_or_fail([bin], remote=False) + + + local_remote_code = os.path.join(local_dir, "code-remote") + remote_remote_code = os.path.join(remote_dir, "code-remote") + if os.path.isfile(local_remote_code): + self.transfer_file(local_remote_code, remote_remote_code) + self.run_or_fail([remote_remote_code], remote=True) + + def stage_prepare(self): + """Do everything for a deploy, minus the actual code stage""" + self.init_deploy() + self.run_global_explores() + self.run_initial_manifest() + + old_objects = [] + objects = self.list_objects() + + # Continue process until no new objects are created anymore + while old_objects != objects: + log.debug("Prepare stage") + old_objects = list(objects) + for cdist_object in objects: + if cdist_object in self.objects_prepared: + log.debug("Skipping rerun of object %s", cdist_object) + continue + else: + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + self.objects_prepared.append(cdist_object) + + objects = self.list_objects() + + def stage_run(self): + """The final (and real) step of deployment""" + log.debug("Actual run objects") + # Now do the final steps over the existing objects + for cdist_object in self.list_objects(): + log.debug("Run object: %s", cdist_object) + self.object_run(cdist_object, mode="gencode") + self.object_run(cdist_object, mode="code") + + def deploy_to(self): + """Mimic the old deploy to: Deploy to one host""" + log.info("Deploying to " + self.target_host) + time_start = datetime.datetime.now() + + self.stage_prepare() + self.stage_run() + + time_end = datetime.datetime.now() + duration = time_end - time_start + log.info("Finished run of %s in %s seconds", + self.target_host, + duration.total_seconds()) + + def deploy_and_cleanup(self): + """Do what is most often done: deploy & cleanup""" + self.deploy_to() + self.cleanup() + +def banner(args): + """Guess what :-)""" + print(BANNER) + sys.exit(0) + +def config(args): + """Configure remote system""" + process = {} + + time_start = datetime.datetime.now() + + for host in args.host: + c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) + if args.parallel: + log.debug("Creating child process for %s", host) + process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) + process[host].start() + else: + c.deploy_and_cleanup() + + if args.parallel: + for p in process.keys(): + log.debug("Joining %s", p) + process[p].join() + + time_end = datetime.datetime.now() + log.info("Total processing time for %s host(s): %s", len(args.host), + (time_end - time_start).total_seconds()) + +def install(args): + """Install remote system""" + process = {} + +def emulator(): + """Emulate type commands (i.e. __file and co)""" + type = os.path.basename(sys.argv[0]) + type_dir = os.path.join(os.environ['__cdist_type_base_dir'], type) + param_dir = os.path.join(type_dir, "parameter") + global_dir = os.environ['__global'] + object_source = os.environ['__cdist_manifest'] + + parser = argparse.ArgumentParser(add_help=False) + + # Setup optional parameters + for parameter in file_to_list(os.path.join(param_dir, "optional")): + argument = "--" + parameter + parser.add_argument(argument, action='store', required=False) + + # Setup required parameters + for parameter in file_to_list(os.path.join(param_dir, "required")): + argument = "--" + parameter + parser.add_argument(argument, action='store', required=True) + + # Setup positional parameter, if not singleton + + if not os.path.isfile(os.path.join(type_dir, "singleton")): + parser.add_argument("object_id", nargs=1) + + # And finally verify parameter + args = parser.parse_args(sys.argv[1:]) + + # Setup object_id + if os.path.isfile(os.path.join(type_dir, "singleton")): + object_id = "singleton" + else: + object_id = args.object_id[0] + del args.object_id + + # FIXME: / hardcoded - better portable solution available? + if object_id[0] == '/': + object_id = object_id[1:] + + # FIXME: verify object id + log.debug(args) + + object_dir = os.path.join(global_dir, "object", type, + object_id, DOT_CDIST) + param_out_dir = os.path.join(object_dir, "parameter") + + object_source_file = os.path.join(object_dir, "source") + + if os.path.exists(param_out_dir): + object_exists = True + old_object_source_fd = open(object_source_file, "r") + old_object_source = old_object_source_fd.readlines() + old_object_source_fd.close() + + else: + object_exists = False + try: + os.makedirs(param_out_dir, exist_ok=True) + except OSError as error: + exit_error(param_out_dir + ": " + error.args[1]) + + # Record parameter + params = vars(args) + for param in params: + value = getattr(args, param) + if value: + file = os.path.join(param_out_dir, param) + log.debug(file + "<-" + param + " = " + value) + + # Already exists, verify all parameter are the same + if object_exists: + if not os.path.isfile(file): + print("New parameter + " + param + "specified, aborting") + print("Source = " + old_object_source + "new =" + object_source) + sys.exit(1) + else: + param_fd = open(file, "r") + param_old = param_fd.readlines() + param_fd.close() + + if(param_old != param): + print("Parameter " + param + " differs: " + " ".join(param_old) + " vs. " + param) + print("Sources: " + " ".join(old_object_source) + " and " + object_source) + sys.exit(1) + else: + param_fd = open(file, "w") + param_fd.writelines(value) + param_fd.close() + + # Record requirements + if "__require" in os.environ: + requirements = os.environ['__require'] + print(object_id + ":Writing requirements: " + requirements) + require_fd = open(os.path.join(object_dir, "require"), "a") + require_fd.writelines(requirements.split(" ")) + require_fd.close() + + # Record / Append source + source_fd = open(os.path.join(object_dir, "source"), "a") + source_fd.writelines(object_source) + source_fd.close() + + # sys.exit(1) + print("Finished " + type + "/" + object_id + repr(params)) + + +def commandline(): + """Parse command line""" + # Construct parser others can reuse + parser = {} + # Options _all_ parsers have in common + parser['most'] = argparse.ArgumentParser(add_help=False) + parser['most'].add_argument('-d', '--debug', + help='Set log level to debug', action='store_true') + + # Main subcommand parser + parser['main'] = argparse.ArgumentParser(description='cdist ' + VERSION) + parser['main'].add_argument('-V', '--version', + help='Show version', action='version', + version='%(prog)s ' + VERSION) + parser['sub'] = parser['main'].add_subparsers(title="Commands") + + # Banner + parser['banner'] = parser['sub'].add_parser('banner', + add_help=False) + parser['banner'].set_defaults(func=banner) + + # Config and install (common stuff) + parser['configinstall'] = argparse.ArgumentParser(add_help=False) + parser['configinstall'].add_argument('host', nargs='+', + help='one or more hosts to operate on') + parser['configinstall'].add_argument('-c', '--cdist-home', + help='Change cdist home (default: .. from bin directory)', + action='store') + parser['configinstall'].add_argument('-i', '--initial-manifest', + help='Path to a cdist manifest', + dest='manifest', required=False) + parser['configinstall'].add_argument('-p', '--parallel', + help='Operate on multiple hosts in parallel', + action='store_true', dest='parallel') + parser['configinstall'].add_argument('-s', '--sequential', + help='Operate on multiple hosts sequentially (default)', + action='store_false', dest='parallel') + + # Config + parser['config'] = parser['sub'].add_parser('config', + parents=[parser['most'], parser['configinstall']]) + parser['config'].set_defaults(func=config) + + # Install + parser['install'] = parser['sub'].add_parser('install', + parents=[parser['most'], 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/" + + args = parser['main'].parse_args(sys.argv[1:]) + + # Most subcommands have --debug, so handle it here + if 'debug' in args: + if args.debug: + logging.root.setLevel(logging.DEBUG) + log.debug(args) + + args.func(args) + +if __name__ == "__main__": + try: + if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): + emulator() + else: + commandline() + except KeyboardInterrupt: + sys.exit(0) From 02b9b71ffeb38e26af06b7cf06dc8e9e494f08f9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 17:11:39 +0200 Subject: [PATCH 0342/4212] remove exec functions from path Signed-off-by: Nico Schottelius --- module/cdist/path.py | 46 -------------------------------------------- 1 file changed, 46 deletions(-) diff --git a/module/cdist/path.py b/module/cdist/path.py index 387481ca..964e29b8 100644 --- a/module/cdist/path.py +++ b/module/cdist/path.py @@ -91,52 +91,6 @@ class Path: """Use cat on the remote side for output""" self.run_or_fail(["cat", filename], remote=True) - def shell_run_or_debug_fail(self, script, *args, **kargs): - # Manually execute /bin/sh, because sh -e does what we want - # and sh -c -e does not exit if /bin/false called - args[0][:0] = [ "/bin/sh", "-e" ] - - remote = False - if "remote" in kargs: - if kargs["remote"]: - args[0][:0] = self.remote_prefix - remote = true - - del kargs["remote"] - - log.debug("Shell exec cmd: %s", args) - log.debug("Shell exec env: %s", kargs['env']) - try: - subprocess.check_call(*args, **kargs) - except subprocess.CalledProcessError: - log.error("Code that raised the error:\n") - if remote: - remote_cat(script) - else: - script_fd = open(script) - print(script_fd.read()) - script_fd.close() - - exit_error("Command failed (shell): " + " ".join(*args)) - except OSError as error: - exit_error(" ".join(*args) + ": " + error.args[1]) - - def run_or_fail(self, *args, **kargs): - if "remote" in kargs: - if kargs["remote"]: - args[0][:0] = self.remote_prefix - - del kargs["remote"] - - log.debug("Exec: " + " ".join(*args)) - try: - subprocess.check_call(*args, **kargs) - except subprocess.CalledProcessError: - exit_error("Command failed: " + " ".join(*args)) - except OSError as error: - exit_error(" ".join(*args) + ": " + error.args[1]) - - def remove_remote_dir(self, destination): self.run_or_fail(["rm", "-rf", destination], remote=True) From 7bc4f74d50d0ff115e62981d17ed6b732590fa69 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 17:17:59 +0200 Subject: [PATCH 0343/4212] remove non path stuff from path Signed-off-by: Nico Schottelius --- module/cdist/path.py | 431 +------------------------------------------ 1 file changed, 4 insertions(+), 427 deletions(-) diff --git a/module/cdist/path.py b/module/cdist/path.py index 964e29b8..c72d29a8 100644 --- a/module/cdist/path.py +++ b/module/cdist/path.py @@ -23,6 +23,9 @@ def file_to_list(filename): return lines +# FIXME: self.run_or_fail needs to be elsewhere! +# Exec? + class Path: """Class that handles path related configurations""" @@ -159,6 +162,7 @@ class Path: return object_paths + # FIXME def get_type_from_object(self, cdist_object): """Returns the first part (i.e. type) of an object""" return cdist_object.split(os.sep)[0] @@ -249,430 +253,3 @@ class Path: destination = os.path.join(self.bin_dir, type) log.debug("Linking %s to %s", source, destination) os.symlink(source, destination) - - def run_global_explores(self): - """Run global explorers""" - explorers = self.list_global_explorers() - if(len(explorers) == 0): - exit_error("No explorers found in", self.global_explorer_dir) - - self.transfer_global_explorers() - for explorer in explorers: - output = self.global_explorer_output_path(explorer) - output_fd = open(output, mode='w') - cmd = [] - cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append(self.remote_global_explorer_path(explorer)) - - self.run_or_fail(cmd, stdout=output_fd, remote=True) - output_fd.close() - - def run_type_explorer(self, cdist_object): - """Run type specific explorers for objects""" - # Based on bin/cdist-object-explorer-run - - # Transfering explorers for this type - type = self.get_type_from_object(cdist_object) - self.transfer_type_explorers(type) - - cmd = [] - cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append("__type_explorer=" + self.remote_type_explorer_dir(type)) - cmd.append("__object=" + self.remote_object_dir(cdist_object)) - cmd.append("__object_id=" + self.get_object_id_from_object(cdist_object)) - cmd.append("__object_fq=" + cdist_object) - - # Need to transfer at least the parameters for objects to be useful - self.transfer_object_parameter(cdist_object) - - explorers = self.list_type_explorers(type) - for explorer in explorers: - remote_cmd = cmd + [os.path.join(self.remote_type_explorer_dir(type), explorer)] - output = os.path.join(self.type_explorer_output_dir(cdist_object), explorer) - output_fd = open(output, mode='w') - log.debug("%s exploring %s using %s storing to %s", - cdist_object, explorer, remote_cmd, output) - - self.run_or_fail(remote_cmd, stdout=output_fd, remote=True) - output_fd.close() - - def init_deploy(self): - """Ensure the base directories are cleaned up""" - log.debug("Creating clean directory structure") - - self.remove_remote_dir(REMOTE_BASE_DIR) - self.remote_mkdir(REMOTE_BASE_DIR) - - def run_initial_manifest(self): - """Run the initial manifest""" - env = { "__manifest" : self.manifest_dir } - self.run_manifest(self.initial_manifest, extra_env=env) - - def run_type_manifest(self, cdist_object): - """Run manifest for a specific object""" - type = self.get_type_from_object(cdist_object) - manifest = self.type_dir(type, "manifest") - - log.debug("%s: Running %s", cdist_object, manifest) - if os.path.exists(manifest): - env = { "__object" : self.object_dir(cdist_object), - "__object_id": self.get_object_id_from_object(cdist_object), - "__object_fq": cdist_object, - "__type": self.type_dir(type) - } - self.run_manifest(manifest, extra_env=env) - - def run_manifest(self, manifest, extra_env=None): - """Run a manifest""" - log.debug("Running manifest %s, env=%s", manifest, extra_env) - env = os.environ.copy() - env['PATH'] = self.bin_dir + ":" + env['PATH'] - - # Information required in every manifest - env['__target_host'] = self.target_host - env['__global'] = self.out_dir - - # Legacy stuff to make cdist-type-emulator work - env['__cdist_core_dir'] = os.path.join(self.base_dir, "core") - env['__cdist_local_base_dir'] = self.temp_dir - - # Submit information to new type emulator - env['__cdist_manifest'] = manifest - env['__cdist_type_base_dir'] = self.type_base_dir - - # Other environment stuff - if extra_env: - env.update(extra_env) - - self.shell_run_or_debug_fail(manifest, [manifest], env=env) - - def object_run(self, cdist_object, mode): - """Run gencode or code for an object""" - log.debug("Running %s from %s", mode, cdist_object) - file=os.path.join(self.object_dir(cdist_object), "require") - requirements = file_to_list(file) - type = self.get_type_from_object(cdist_object) - - for requirement in requirements: - log.debug("Object %s requires %s", cdist_object, requirement) - self.object_run(requirement, mode=mode) - - # - # Setup env Variable: - # - env = os.environ.copy() - env['__target_host'] = self.target_host - env['__global'] = self.out_dir - env["__object"] = self.object_dir(cdist_object) - env["__object_id"] = self.get_object_id_from_object(cdist_object) - env["__object_fq"] = cdist_object - env["__type"] = self.type_dir(type) - - if mode == "gencode": - paths = [ - self.type_dir(type, "gencode-local"), - self.type_dir(type, "gencode-remote") - ] - for bin in paths: - if os.path.isfile(bin): - # omit "gen" from gencode and use it for output base - outfile=os.path.join(self.object_dir(cdist_object), - os.path.basename(bin)[3:]) - - outfile_fd = open(outfile, "w") - - # Need to flush to ensure our write is done before stdout write - outfile_fd.write(CODE_HEADER) - outfile_fd.flush() - - self.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) - outfile_fd.close() - - status = os.stat(outfile) - - # Remove output if empty, else make it executable - if status.st_size == len(CODE_HEADER): - os.unlink(outfile) - else: - # Add header and make executable - identically to 0o700 - os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) - - # Mark object as changed - open(os.path.join(self.object_dir(cdist_object), "changed"), "w").close() - - - if mode == "code": - local_dir = self.object_dir(cdist_object) - remote_dir = self.remote_object_dir(cdist_object) - - bin = os.path.join(local_dir, "code-local") - if os.path.isfile(bin): - self.run_or_fail([bin], remote=False) - - - local_remote_code = os.path.join(local_dir, "code-remote") - remote_remote_code = os.path.join(remote_dir, "code-remote") - if os.path.isfile(local_remote_code): - self.transfer_file(local_remote_code, remote_remote_code) - self.run_or_fail([remote_remote_code], remote=True) - - def stage_prepare(self): - """Do everything for a deploy, minus the actual code stage""" - self.init_deploy() - self.run_global_explores() - self.run_initial_manifest() - - old_objects = [] - objects = self.list_objects() - - # Continue process until no new objects are created anymore - while old_objects != objects: - log.debug("Prepare stage") - old_objects = list(objects) - for cdist_object in objects: - if cdist_object in self.objects_prepared: - log.debug("Skipping rerun of object %s", cdist_object) - continue - else: - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) - self.objects_prepared.append(cdist_object) - - objects = self.list_objects() - - def stage_run(self): - """The final (and real) step of deployment""" - log.debug("Actual run objects") - # Now do the final steps over the existing objects - for cdist_object in self.list_objects(): - log.debug("Run object: %s", cdist_object) - self.object_run(cdist_object, mode="gencode") - self.object_run(cdist_object, mode="code") - - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to " + self.target_host) - time_start = datetime.datetime.now() - - self.stage_prepare() - self.stage_run() - - time_end = datetime.datetime.now() - duration = time_end - time_start - log.info("Finished run of %s in %s seconds", - self.target_host, - duration.total_seconds()) - - def deploy_and_cleanup(self): - """Do what is most often done: deploy & cleanup""" - self.deploy_to() - self.cleanup() - -def banner(args): - """Guess what :-)""" - print(BANNER) - sys.exit(0) - -def config(args): - """Configure remote system""" - process = {} - - time_start = datetime.datetime.now() - - for host in args.host: - c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) - if args.parallel: - log.debug("Creating child process for %s", host) - process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) - process[host].start() - else: - c.deploy_and_cleanup() - - if args.parallel: - for p in process.keys(): - log.debug("Joining %s", p) - process[p].join() - - time_end = datetime.datetime.now() - log.info("Total processing time for %s host(s): %s", len(args.host), - (time_end - time_start).total_seconds()) - -def install(args): - """Install remote system""" - process = {} - -def emulator(): - """Emulate type commands (i.e. __file and co)""" - type = os.path.basename(sys.argv[0]) - type_dir = os.path.join(os.environ['__cdist_type_base_dir'], type) - param_dir = os.path.join(type_dir, "parameter") - global_dir = os.environ['__global'] - object_source = os.environ['__cdist_manifest'] - - parser = argparse.ArgumentParser(add_help=False) - - # Setup optional parameters - for parameter in file_to_list(os.path.join(param_dir, "optional")): - argument = "--" + parameter - parser.add_argument(argument, action='store', required=False) - - # Setup required parameters - for parameter in file_to_list(os.path.join(param_dir, "required")): - argument = "--" + parameter - parser.add_argument(argument, action='store', required=True) - - # Setup positional parameter, if not singleton - - if not os.path.isfile(os.path.join(type_dir, "singleton")): - parser.add_argument("object_id", nargs=1) - - # And finally verify parameter - args = parser.parse_args(sys.argv[1:]) - - # Setup object_id - if os.path.isfile(os.path.join(type_dir, "singleton")): - object_id = "singleton" - else: - object_id = args.object_id[0] - del args.object_id - - # FIXME: / hardcoded - better portable solution available? - if object_id[0] == '/': - object_id = object_id[1:] - - # FIXME: verify object id - log.debug(args) - - object_dir = os.path.join(global_dir, "object", type, - object_id, DOT_CDIST) - param_out_dir = os.path.join(object_dir, "parameter") - - object_source_file = os.path.join(object_dir, "source") - - if os.path.exists(param_out_dir): - object_exists = True - old_object_source_fd = open(object_source_file, "r") - old_object_source = old_object_source_fd.readlines() - old_object_source_fd.close() - - else: - object_exists = False - try: - os.makedirs(param_out_dir, exist_ok=True) - except OSError as error: - exit_error(param_out_dir + ": " + error.args[1]) - - # Record parameter - params = vars(args) - for param in params: - value = getattr(args, param) - if value: - file = os.path.join(param_out_dir, param) - log.debug(file + "<-" + param + " = " + value) - - # Already exists, verify all parameter are the same - if object_exists: - if not os.path.isfile(file): - print("New parameter + " + param + "specified, aborting") - print("Source = " + old_object_source + "new =" + object_source) - sys.exit(1) - else: - param_fd = open(file, "r") - param_old = param_fd.readlines() - param_fd.close() - - if(param_old != param): - print("Parameter " + param + " differs: " + " ".join(param_old) + " vs. " + param) - print("Sources: " + " ".join(old_object_source) + " and " + object_source) - sys.exit(1) - else: - param_fd = open(file, "w") - param_fd.writelines(value) - param_fd.close() - - # Record requirements - if "__require" in os.environ: - requirements = os.environ['__require'] - print(object_id + ":Writing requirements: " + requirements) - require_fd = open(os.path.join(object_dir, "require"), "a") - require_fd.writelines(requirements.split(" ")) - require_fd.close() - - # Record / Append source - source_fd = open(os.path.join(object_dir, "source"), "a") - source_fd.writelines(object_source) - source_fd.close() - - # sys.exit(1) - print("Finished " + type + "/" + object_id + repr(params)) - - -def commandline(): - """Parse command line""" - # Construct parser others can reuse - parser = {} - # Options _all_ parsers have in common - parser['most'] = argparse.ArgumentParser(add_help=False) - parser['most'].add_argument('-d', '--debug', - help='Set log level to debug', action='store_true') - - # Main subcommand parser - parser['main'] = argparse.ArgumentParser(description='cdist ' + VERSION) - parser['main'].add_argument('-V', '--version', - help='Show version', action='version', - version='%(prog)s ' + VERSION) - parser['sub'] = parser['main'].add_subparsers(title="Commands") - - # Banner - parser['banner'] = parser['sub'].add_parser('banner', - add_help=False) - parser['banner'].set_defaults(func=banner) - - # Config and install (common stuff) - parser['configinstall'] = argparse.ArgumentParser(add_help=False) - parser['configinstall'].add_argument('host', nargs='+', - help='one or more hosts to operate on') - parser['configinstall'].add_argument('-c', '--cdist-home', - help='Change cdist home (default: .. from bin directory)', - action='store') - parser['configinstall'].add_argument('-i', '--initial-manifest', - help='Path to a cdist manifest', - dest='manifest', required=False) - parser['configinstall'].add_argument('-p', '--parallel', - help='Operate on multiple hosts in parallel', - action='store_true', dest='parallel') - parser['configinstall'].add_argument('-s', '--sequential', - help='Operate on multiple hosts sequentially (default)', - action='store_false', dest='parallel') - - # Config - parser['config'] = parser['sub'].add_parser('config', - parents=[parser['most'], parser['configinstall']]) - parser['config'].set_defaults(func=config) - - # Install - parser['install'] = parser['sub'].add_parser('install', - parents=[parser['most'], 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/" - - args = parser['main'].parse_args(sys.argv[1:]) - - # Most subcommands have --debug, so handle it here - if 'debug' in args: - if args.debug: - logging.root.setLevel(logging.DEBUG) - log.debug(args) - - args.func(args) - -if __name__ == "__main__": - try: - if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): - emulator() - else: - commandline() - except KeyboardInterrupt: - sys.exit(0) From ceaf82f6df5494f96d31aab271a690e8bb5e13dc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 17:19:16 +0200 Subject: [PATCH 0344/4212] better comment Signed-off-by: Nico Schottelius --- module/cdist/path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/cdist/path.py b/module/cdist/path.py index c72d29a8..e18f6582 100644 --- a/module/cdist/path.py +++ b/module/cdist/path.py @@ -1,4 +1,4 @@ -# Given paths from installation +# Hardcoded paths usually not changable REMOTE_BASE_DIR = "/var/lib/cdist" REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") From 91022c3f7e7102833a4416cb45ae171f6e8d4b1e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 23 Sep 2011 17:19:45 +0200 Subject: [PATCH 0345/4212] handle ioerror if script does not exist Signed-off-by: Steven Armstrong --- bin/cdist | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index fde7a251..d9f88b48 100755 --- a/bin/cdist +++ b/bin/cdist @@ -181,9 +181,12 @@ class Cdist: if remote: remote_cat(script) else: - script_fd = open(script) - print(script_fd.read()) - script_fd.close() + try: + script_fd = open(script) + print(script_fd.read()) + script_fd.close() + except IOError as error: + raise CdistError(str(error)) raise CdistError("Command failed (shell): " + " ".join(*args)) except OSError as error: From 8e59f97800a0c9fecccbdb9517b1a8a581e5c933 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 18:55:23 +0200 Subject: [PATCH 0346/4212] begin to used cdist.path Signed-off-by: Nico Schottelius --- bin/cdist | 13 ++++++++----- {module => lib}/cdist/__init__.py | 0 {module => lib}/cdist/path.py | 0 3 files changed, 8 insertions(+), 5 deletions(-) rename {module => lib}/cdist/__init__.py (100%) rename {module => lib}/cdist/path.py (100%) diff --git a/bin/cdist b/bin/cdist index d9f88b48..69e0623f 100755 --- a/bin/cdist +++ b/bin/cdist @@ -20,6 +20,10 @@ # # +# Add our own library path +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), + '../lib/python'))) + import argparse import datetime import logging @@ -32,6 +36,8 @@ import stat import sys import tempfile +import cdist.path + BANNER = """ .. . .x+=:. s dF @88> z` ^% :8 @@ -62,11 +68,6 @@ VERSION = "2.0.1" logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') log = logging.getLogger() -# Begin to split into parts -sys.path.insert(0, - os.path.abspath(os.path.join(os.path.dirname(__file__), - '../lib/python'))) - def file_to_list(filename): """Return list from \n seperated file""" if os.path.isfile(filename): @@ -94,6 +95,8 @@ class Cdist: self.target_host = target_host self.remote_prefix = ["ssh", "root@" + self.target_host] + self.path_info = cdist.path.Path(target_host, home) + # Setup directory paths self.temp_dir = tempfile.mkdtemp() diff --git a/module/cdist/__init__.py b/lib/cdist/__init__.py similarity index 100% rename from module/cdist/__init__.py rename to lib/cdist/__init__.py diff --git a/module/cdist/path.py b/lib/cdist/path.py similarity index 100% rename from module/cdist/path.py rename to lib/cdist/path.py From 2aa9f2ab8c8cb4d1349ea6ce98a9e3df8e5b0851 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 18:56:29 +0200 Subject: [PATCH 0347/4212] test: things to do Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 5439a1b9..8be1da54 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -9,6 +9,12 @@ CORE - allow cdist to run without $PATH setup: ./bin/cdist-deploy-to - support non-ssh access? +TESTS +----- +- multiple defines of object: + - fail if different parameters + - succeed if same parameters + USER INTERFACE -------------- - add support $__tmp? From 6139fab354b52ca56e5d4ffaea281d83b020a21e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 19:10:07 +0200 Subject: [PATCH 0348/4212] import cdist.path works Signed-off-by: Nico Schottelius --- bin/cdist | 10 +++++----- lib/cdist/path.py | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index 69e0623f..18e7845b 100755 --- a/bin/cdist +++ b/bin/cdist @@ -20,10 +20,6 @@ # # -# Add our own library path -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), - '../lib/python'))) - import argparse import datetime import logging @@ -36,6 +32,10 @@ import stat import sys import tempfile +# Add our own library path +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), + '../lib'))) + import cdist.path BANNER = """ @@ -95,7 +95,7 @@ class Cdist: self.target_host = target_host self.remote_prefix = ["ssh", "root@" + self.target_host] - self.path_info = cdist.path.Path(target_host, home) + self.path_info = cdist.path.Path(target_host, base_dir=home) # Setup directory paths self.temp_dir = tempfile.mkdtemp() diff --git a/lib/cdist/path.py b/lib/cdist/path.py index e18f6582..5d72a23a 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -1,3 +1,7 @@ +import os +import sys +import tempfile + # Hardcoded paths usually not changable REMOTE_BASE_DIR = "/var/lib/cdist" REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") @@ -31,7 +35,7 @@ class Path: def __init__(self, target_host, base_dir=None): # Base and Temp Base - if home: + if base_dir: self.base_dir = base_dir else: self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) From 26fad6f23ce1b656618eb64e1d367cf5757cf79f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 19:13:36 +0200 Subject: [PATCH 0349/4212] correct base dir, now relative to lib Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 5d72a23a..69bc5496 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -38,7 +38,7 @@ class Path: if base_dir: self.base_dir = base_dir else: - self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) + self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) self.temp_dir = tempfile.mkdtemp() From 79173488ffd697ef89d8a387034eb3447cf3da61 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 20:08:55 +0200 Subject: [PATCH 0350/4212] cdist runs with path module loaded (unusued though) Signed-off-by: Nico Schottelius --- bin/cdist | 13 ++++++++----- lib/cdist/path.py | 31 ++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index 18e7845b..f6156825 100755 --- a/bin/cdist +++ b/bin/cdist @@ -32,11 +32,6 @@ import stat import sys import tempfile -# Add our own library path -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), - '../lib'))) - -import cdist.path BANNER = """ .. . .x+=:. s @@ -788,11 +783,19 @@ def commandline(): args.func(args) + if __name__ == "__main__": try: if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): emulator() else: + # Add our own library path + sys.path.insert(0, + os.path.abspath(os.path.join(os.path.dirname(__file__), + '../lib'))) + + import cdist.path + commandline() except KeyboardInterrupt: sys.exit(0) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 69bc5496..2050a1a3 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -1,3 +1,25 @@ +# -*- 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 logging import os import sys import tempfile @@ -13,6 +35,10 @@ CODE_HEADER = "#!/bin/sh -e\n" DOT_CDIST = ".cdist" TYPE_PREFIX = "__" +logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') +log = logging.getLogger() + + def file_to_list(filename): """Return list from \n seperated file""" if os.path.isfile(filename): @@ -33,7 +59,10 @@ def file_to_list(filename): class Path: """Class that handles path related configurations""" - def __init__(self, target_host, base_dir=None): + def __init__(self, target_host, + initial_manifest=False, remote_user="root", + base_dir=None, debug=False): + # Base and Temp Base if base_dir: self.base_dir = base_dir From d4406cece3dc07e8a1f7a248b32c98c92f2895cb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 20:17:17 +0200 Subject: [PATCH 0351/4212] begin to replace first function with path module Signed-off-by: Nico Schottelius --- bin/cdist | 67 +++++++------------------------------------------------ 1 file changed, 8 insertions(+), 59 deletions(-) diff --git a/bin/cdist b/bin/cdist index f6156825..137f701f 100755 --- a/bin/cdist +++ b/bin/cdist @@ -90,72 +90,21 @@ class Cdist: self.target_host = target_host self.remote_prefix = ["ssh", "root@" + self.target_host] - self.path_info = cdist.path.Path(target_host, base_dir=home) - - # Setup directory paths - self.temp_dir = tempfile.mkdtemp() + self.path = cdist.path.Path(target_host, + initial_manifest=initial_manifest, + remote_user=remote_user, + base_dir=home, + debug=debug) self.debug = debug - if home: - self.base_dir = home - else: - self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) - - self.conf_dir = os.path.join(self.base_dir, "conf") - self.cache_base_dir = os.path.join(self.base_dir, "cache") - self.cache_dir = os.path.join(self.cache_base_dir, self.target_host) - self.global_explorer_dir = os.path.join(self.conf_dir, "explorer") - self.lib_dir = os.path.join(self.base_dir, "lib") - self.manifest_dir = os.path.join(self.conf_dir, "manifest") - self.type_base_dir = os.path.join(self.conf_dir, "type") - - self.out_dir = os.path.join(self.temp_dir, "out") - os.mkdir(self.out_dir) - - self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") - os.mkdir(self.global_explorer_out_dir) - - self.object_base_dir = os.path.join(self.out_dir, "object") - - # Setup binary directory + contents - self.bin_dir = os.path.join(self.out_dir, "bin") - os.mkdir(self.bin_dir) - self.link_type_to_emulator() - - # List of type explorers transferred - self.type_explorers_transferred = {} - # objects self.objects_prepared = [] self.remote_user = remote_user - # Mostly static, but can be overwritten on user demand - if initial_manifest: - self.initial_manifest = initial_manifest - else: - self.initial_manifest = os.path.join(self.manifest_dir, "init") - def cleanup(self): - # Do not use in __del__: - # http://docs.python.org/reference/datamodel.html#customization - # "other globals referenced by the __del__() method may already have been deleted - # or in the process of being torn down (e.g. the import machinery shutting down)" - # - log.debug("Saving" + self.temp_dir + "to " + self.cache_dir) - # Remove previous cache - if os.path.exists(self.cache_dir): - shutil.rmtree(self.cache_dir) - shutil.move(self.temp_dir, self.cache_dir) - - def remote_mkdir(self, directory): - """Create directory on remote side""" - self.run_or_fail(["mkdir", "-p", directory], remote=True) - - def remote_cat(filename): - """Use cat on the remote side for output""" - self.run_or_fail(["cat", filename], remote=True) + self.path.cleanup() def shell_run_or_debug_fail(self, script, *args, **kargs): # Manually execute /bin/sh, because sh -e does what we want @@ -415,8 +364,8 @@ class Cdist: """Ensure the base directories are cleaned up""" log.debug("Creating clean directory structure") - self.remove_remote_dir(REMOTE_BASE_DIR) - self.remote_mkdir(REMOTE_BASE_DIR) + self.path.remove_remote_dir(REMOTE_BASE_DIR) + self.path.remote_mkdir(REMOTE_BASE_DIR) def run_initial_manifest(self): """Run the initial manifest""" From e14848ec1f88e1e79aade52fa4180d4a8d33db9e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 20:21:10 +0200 Subject: [PATCH 0352/4212] remove run* from cdist and put it into lib/exec Signed-off-by: Nico Schottelius --- bin/cdist | 49 --------------------------------- lib/cdist/exec.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 49 deletions(-) create mode 100644 lib/cdist/exec.py diff --git a/bin/cdist b/bin/cdist index 137f701f..30fec278 100755 --- a/bin/cdist +++ b/bin/cdist @@ -106,55 +106,6 @@ class Cdist: def cleanup(self): self.path.cleanup() - def shell_run_or_debug_fail(self, script, *args, **kargs): - # Manually execute /bin/sh, because sh -e does what we want - # and sh -c -e does not exit if /bin/false called - args[0][:0] = [ "/bin/sh", "-e" ] - - remote = False - if "remote" in kargs: - if kargs["remote"]: - args[0][:0] = self.remote_prefix - remote = true - - del kargs["remote"] - - log.debug("Shell exec cmd: %s", args) - log.debug("Shell exec env: %s", kargs['env']) - try: - subprocess.check_call(*args, **kargs) - except subprocess.CalledProcessError: - log.error("Code that raised the error:\n") - if remote: - remote_cat(script) - else: - try: - script_fd = open(script) - print(script_fd.read()) - script_fd.close() - except IOError as error: - raise CdistError(str(error)) - - raise CdistError("Command failed (shell): " + " ".join(*args)) - except OSError as error: - raise CdistError(" ".join(*args) + ": " + error.args[1]) - - def run_or_fail(self, *args, **kargs): - if "remote" in kargs: - if kargs["remote"]: - args[0][:0] = self.remote_prefix - - del kargs["remote"] - - log.debug("Exec: " + " ".join(*args)) - try: - subprocess.check_call(*args, **kargs) - except subprocess.CalledProcessError: - raise CdistError("Command failed: " + " ".join(*args)) - except OSError as error: - raise CdistError(" ".join(*args) + ": " + error.args[1]) - - def remove_remote_dir(self, destination): self.run_or_fail(["rm", "-rf", destination], remote=True) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py new file mode 100644 index 00000000..7a1421e0 --- /dev/null +++ b/lib/cdist/exec.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +# +# 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 . +# +# + +def shell_run_or_debug_fail(self, script, *args, **kargs): + # Manually execute /bin/sh, because sh -e does what we want + # and sh -c -e does not exit if /bin/false called + args[0][:0] = [ "/bin/sh", "-e" ] + + remote = False + if "remote" in kargs: + if kargs["remote"]: + args[0][:0] = self.remote_prefix + remote = true + + del kargs["remote"] + + log.debug("Shell exec cmd: %s", args) + log.debug("Shell exec env: %s", kargs['env']) + try: + subprocess.check_call(*args, **kargs) + except subprocess.CalledProcessError: + log.error("Code that raised the error:\n") + if remote: + remote_cat(script) + else: + try: + script_fd = open(script) + print(script_fd.read()) + script_fd.close() + except IOError as error: + raise CdistError(str(error)) + + raise CdistError("Command failed (shell): " + " ".join(*args)) + except OSError as error: + raise CdistError(" ".join(*args) + ": " + error.args[1]) + + +def run_or_fail(self, *args, **kargs): + if "remote" in kargs: + if kargs["remote"]: + args[0][:0] = self.remote_prefix + + del kargs["remote"] + + log.debug("Exec: " + " ".join(*args)) + try: + subprocess.check_call(*args, **kargs) + except subprocess.CalledProcessError: + raise CdistError("Command failed: " + " ".join(*args)) + except OSError as error: + raise CdistError(" ".join(*args) + ": " + error.args[1]) + From 3925ba1c6e0bb7276a374836ec98f4f9e2c81552 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 20:35:13 +0200 Subject: [PATCH 0353/4212] pass remote_prefix to run_or_fail/shell Signed-off-by: Nico Schottelius --- lib/cdist/exec.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index 7a1421e0..a4cf4592 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -19,7 +19,8 @@ # # -def shell_run_or_debug_fail(self, script, *args, **kargs): + +def shell_run_or_debug_fail(script, *args, **kargs): # Manually execute /bin/sh, because sh -e does what we want # and sh -c -e does not exit if /bin/false called args[0][:0] = [ "/bin/sh", "-e" ] @@ -27,10 +28,11 @@ def shell_run_or_debug_fail(self, script, *args, **kargs): remote = False if "remote" in kargs: if kargs["remote"]: - args[0][:0] = self.remote_prefix + args[0][:0] = kargs["remote_prefix"] remote = true del kargs["remote"] + del kargs["remote_prefix"] log.debug("Shell exec cmd: %s", args) log.debug("Shell exec env: %s", kargs['env']) @@ -56,9 +58,10 @@ def shell_run_or_debug_fail(self, script, *args, **kargs): def run_or_fail(self, *args, **kargs): if "remote" in kargs: if kargs["remote"]: - args[0][:0] = self.remote_prefix + args[0][:0] = kargs["remote_prefix"] del kargs["remote"] + del kargs["remote_prefix"] log.debug("Exec: " + " ".join(*args)) try: @@ -67,4 +70,3 @@ def run_or_fail(self, *args, **kargs): raise CdistError("Command failed: " + " ".join(*args)) except OSError as error: raise CdistError(" ".join(*args) + ": " + error.args[1]) - From 8af45f83b20bd8a0e48f58eb5e7e9105bc76edda Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 23 Sep 2011 20:53:09 +0200 Subject: [PATCH 0354/4212] rearange remote_user Signed-off-by: Nico Schottelius --- bin/cdist | 17 ----------------- lib/cdist/path.py | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/bin/cdist b/bin/cdist index 30fec278..67b96a09 100755 --- a/bin/cdist +++ b/bin/cdist @@ -88,7 +88,6 @@ class Cdist: initial_manifest=False, remote_user="root", home=None, debug=False): self.target_host = target_host - self.remote_prefix = ["ssh", "root@" + self.target_host] self.path = cdist.path.Path(target_host, initial_manifest=initial_manifest, @@ -98,7 +97,6 @@ class Cdist: self.debug = debug - # objects self.objects_prepared = [] self.remote_user = remote_user @@ -109,21 +107,6 @@ class Cdist: def remove_remote_dir(self, destination): self.run_or_fail(["rm", "-rf", destination], remote=True) - def transfer_dir(self, source, destination): - """Transfer directory and previously delete the remote destination""" - self.remove_remote_dir(destination) - self.run_or_fail(["scp", "-qr", source, - self.remote_user + "@" + - self.target_host + ":" + - destination]) - - def transfer_file(self, source, destination): - """Transfer file""" - self.run_or_fail(["scp", "-q", source, - self.remote_user + "@" + - self.target_host + ":" + - destination]) - def global_explorer_output_path(self, explorer): """Returns path of the output for a global explorer""" return os.path.join(self.global_explorer_out_dir, explorer) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 2050a1a3..1e9d7195 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -38,6 +38,7 @@ TYPE_PREFIX = "__" logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') log = logging.getLogger() +import cdist.exec def file_to_list(filename): """Return list from \n seperated file""" @@ -53,9 +54,6 @@ def file_to_list(filename): return lines -# FIXME: self.run_or_fail needs to be elsewhere! -# Exec? - class Path: """Class that handles path related configurations""" @@ -70,6 +68,10 @@ class Path: self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) self.temp_dir = tempfile.mkdtemp() + self.target_host = target_host + + self.remote_user = remote_user + self.remote_prefix = ["ssh", self.remote_user + "@" + self.target_host] self.conf_dir = os.path.join(self.base_dir, "conf") self.cache_base_dir = os.path.join(self.base_dir, "cache") @@ -98,8 +100,6 @@ class Path: # objects self.objects_prepared = [] - self.remote_user = remote_user - # Mostly static, but can be overwritten on user demand if initial_manifest: self.initial_manifest = initial_manifest @@ -121,26 +121,26 @@ class Path: def remote_mkdir(self, directory): """Create directory on remote side""" - self.run_or_fail(["mkdir", "-p", directory], remote=True) + cdist.exec.run_or_fail(["mkdir", "-p", directory], remote=True) def remote_cat(filename): """Use cat on the remote side for output""" - self.run_or_fail(["cat", filename], remote=True) + cdist.exec.run_or_fail(["cat", filename], remote=True) def remove_remote_dir(self, destination): - self.run_or_fail(["rm", "-rf", destination], remote=True) + cdist.exec.run_or_fail(["rm", "-rf", destination], remote=True) def transfer_dir(self, source, destination): """Transfer directory and previously delete the remote destination""" self.remove_remote_dir(destination) - self.run_or_fail(["scp", "-qr", source, + cdist.exec.run_or_fail(["scp", "-qr", source, self.remote_user + "@" + self.target_host + ":" + destination]) def transfer_file(self, source, destination): """Transfer file""" - self.run_or_fail(["scp", "-q", source, + cdist.exec.run_or_fail(["scp", "-q", source, self.remote_user + "@" + self.target_host + ":" + destination]) From 7b39169e3e55231eef729d83eea32be97ff49841 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 25 Sep 2011 15:25:38 +0200 Subject: [PATCH 0355/4212] ignore all python cache dirs Signed-off-by: Nico Schottelius --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index d606aec7..fb9c495c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,5 @@ doc/man/man*/docbook-xsl.css # Ignore cache for version control cache/ -# Python -bin/__pycache__/ +# Python / cache +__pycache__/ From a5bfd4119521b6758b7893945812ae2be2ad70dd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 25 Sep 2011 15:26:54 +0200 Subject: [PATCH 0356/4212] Detect owl Signed-off-by: Nico Schottelius --- conf/explorer/os | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/conf/explorer/os b/conf/explorer/os index e922c067..268dae24 100755 --- a/conf/explorer/os +++ b/conf/explorer/os @@ -65,6 +65,11 @@ if [ -f /etc/SuSE-release ]; then exit 0 fi +if uname -r | grep -s '.owl' >/dev/null 2>&1; then + echo owl + exit 0 +fi + if [ -f /etc/cdist-preos ]; then echo preos exit 0 From c10fedaf8c9f87c36e0a0bb2602de8a6ff46edec Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 25 Sep 2011 21:10:18 +0200 Subject: [PATCH 0357/4212] it's not preos, but cdist-preos Signed-off-by: Nico Schottelius --- conf/explorer/os | 2 +- doc/changelog | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/conf/explorer/os b/conf/explorer/os index 268dae24..3e1582ec 100755 --- a/conf/explorer/os +++ b/conf/explorer/os @@ -71,7 +71,7 @@ if uname -r | grep -s '.owl' >/dev/null 2>&1; then fi if [ -f /etc/cdist-preos ]; then - echo preos + echo cdist-preos exit 0 fi diff --git a/doc/changelog b/doc/changelog index b1149eb1..a08efb34 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,3 +1,6 @@ +2.0.2: + * Add support for detection of OpenWall Linux (Matthias Teege) + 2.0.1: 2011-09-23 * Bugfix core: Always print source of error in case of exec errors * Bugfix core: Various smaller bugs in string concatenation From 98f4ec9f3e6334768e3f7065dfd66ef9e13c772c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 09:24:49 +0200 Subject: [PATCH 0358/4212] document asciidoc requirement Signed-off-by: Nico Schottelius --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index 5e60a093..b8181757 100644 --- a/README +++ b/README @@ -78,6 +78,7 @@ cdist was tested or is know to run on at least * A posix like shell * Python (>= 3.2 required) * SSH-Client + * Asciidoc (for building the manpages) ### Client ("target host") From fd9fb13606aa54687d36f9b70965cb6a9e086829 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 09:26:58 +0200 Subject: [PATCH 0359/4212] and remove asciidoc/gmake dep from the comment Signed-off-by: Nico Schottelius --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index b8181757..daa12f70 100644 --- a/README +++ b/README @@ -99,7 +99,7 @@ To install cdist, execute the following commands: cd cdist export PATH=$PATH:$(pwd -P)/bin - # If you want the manpages (requires gmake and asciidoc to be installed) + # If you want the manpages ./build.sh man export MANPATH=$MANPATH:$(pwd -P)/doc/man From bc9bc37aab80bc85d991621da9addd016ac9d0d4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 10:17:02 +0200 Subject: [PATCH 0360/4212] use remote_prefix internally Signed-off-by: Nico Schottelius --- lib/cdist/exec.py | 26 +++++++++++++------------- lib/cdist/path.py | 6 +++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index a4cf4592..aca1d689 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -19,19 +19,21 @@ # # +import logging +import subprocess + +logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') +log = logging.getLogger() + def shell_run_or_debug_fail(script, *args, **kargs): # Manually execute /bin/sh, because sh -e does what we want # and sh -c -e does not exit if /bin/false called args[0][:0] = [ "/bin/sh", "-e" ] - remote = False - if "remote" in kargs: - if kargs["remote"]: - args[0][:0] = kargs["remote_prefix"] - remote = true - - del kargs["remote"] + if "remote_prefix" in kargs: + remote = True + args[0][:0] = kargs["remote_prefix"] del kargs["remote_prefix"] log.debug("Shell exec cmd: %s", args) @@ -41,6 +43,7 @@ def shell_run_or_debug_fail(script, *args, **kargs): except subprocess.CalledProcessError: log.error("Code that raised the error:\n") if remote: + # FIXME: included in Path! remote_cat(script) else: try: @@ -55,12 +58,9 @@ def shell_run_or_debug_fail(script, *args, **kargs): raise CdistError(" ".join(*args) + ": " + error.args[1]) -def run_or_fail(self, *args, **kargs): - if "remote" in kargs: - if kargs["remote"]: - args[0][:0] = kargs["remote_prefix"] - - del kargs["remote"] +def run_or_fail(*args, **kargs): + if "remote_prefix" in kargs: + args[0][:0] = kargs["remote_prefix"] del kargs["remote_prefix"] log.debug("Exec: " + " ".join(*args)) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 1e9d7195..c2cef1a6 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -121,14 +121,14 @@ class Path: def remote_mkdir(self, directory): """Create directory on remote side""" - cdist.exec.run_or_fail(["mkdir", "-p", directory], remote=True) + cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=self.remote_prefix) def remote_cat(filename): """Use cat on the remote side for output""" - cdist.exec.run_or_fail(["cat", filename], remote=True) + cdist.exec.run_or_fail(["cat", filename], remote_prefix=self.remote_prefix) def remove_remote_dir(self, destination): - cdist.exec.run_or_fail(["rm", "-rf", destination], remote=True) + cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=self.remote_prefix) def transfer_dir(self, source, destination): """Transfer directory and previously delete the remote destination""" From 8f2e5bb8c869bd0cce84ae13ccf84756c70298cb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 10:25:51 +0200 Subject: [PATCH 0361/4212] cleanup and move error class to init Signed-off-by: Nico Schottelius --- bin/cdist | 150 +----------------------------------------- lib/cdist/__init__.py | 24 +++++++ 2 files changed, 25 insertions(+), 149 deletions(-) diff --git a/bin/cdist b/bin/cdist index 67b96a09..369fbd29 100755 --- a/bin/cdist +++ b/bin/cdist @@ -77,10 +77,6 @@ def file_to_list(filename): return lines -class CdistError(Exception): - """Base exception class for this project""" - pass - class Cdist: """Cdist main class to hold arbitrary data""" @@ -104,153 +100,9 @@ class Cdist: def cleanup(self): self.path.cleanup() - def remove_remote_dir(self, destination): - self.run_or_fail(["rm", "-rf", destination], remote=True) - - def global_explorer_output_path(self, explorer): - """Returns path of the output for a global explorer""" - return os.path.join(self.global_explorer_out_dir, explorer) - - def type_explorer_output_dir(self, cdist_object): - """Returns and creates dir of the output for a type explorer""" - dir = os.path.join(self.object_dir(cdist_object), "explorer") - if not os.path.isdir(dir): - os.mkdir(dir) - - return dir - - def remote_global_explorer_path(self, explorer): - """Returns path to the remote explorer""" - return os.path.join(REMOTE_GLOBAL_EXPLORER_DIR, explorer) - - def list_global_explorers(self): - """Return list of available explorers""" - return os.listdir(self.global_explorer_dir) - - def list_type_explorers(self, type): - """Return list of available explorers for a specific type""" - dir = self.type_dir(type, "explorer") - if os.path.isdir(dir): - list = os.listdir(dir) - else: - list = [] - - log.debug("Explorers for %s in %s: %s", type, dir, list) - - return list - - def list_types(self): - return os.listdir(self.type_base_dir) - - def list_object_paths(self, starting_point): - """Return list of paths of existing objects""" - object_paths = [] - - for content in os.listdir(starting_point): - full_path = os.path.join(starting_point, content) - if os.path.isdir(full_path): - object_paths.extend(self.list_object_paths(starting_point = full_path)) - - # Directory contains .cdist -> is an object - if content == DOT_CDIST: - object_paths.append(starting_point) - - return object_paths - - def get_type_from_object(self, cdist_object): - """Returns the first part (i.e. type) of an object""" - return cdist_object.split(os.sep)[0] - - def get_object_id_from_object(self, cdist_object): - """Returns everything but the first part (i.e. object_id) of an object""" - return os.sep.join(cdist_object.split(os.sep)[1:]) - - def object_dir(self, cdist_object): - """Returns the full path to the object (including .cdist)""" - return os.path.join(self.object_base_dir, cdist_object, DOT_CDIST) - - def remote_object_dir(self, cdist_object): - """Returns the remote full path to the object (including .cdist)""" - return os.path.join(REMOTE_OBJECT_DIR, cdist_object, DOT_CDIST) - - def object_parameter_dir(self, cdist_object): - """Returns the dir to the object parameter""" - return os.path.join(self.object_dir(cdist_object), "parameter") - - def remote_object_parameter_dir(self, cdist_object): - """Returns the remote dir to the object parameter""" - return os.path.join(self.remote_object_dir(cdist_object), "parameter") - - def object_code_paths(self, cdist_object): - """Return paths to code scripts of object""" - return [os.path.join(self.object_dir(cdist_object), "code-local"), - os.path.join(self.object_dir(cdist_object), "code-remote")] - - def list_objects(self): - """Return list of existing objects""" - - objects = [] - if os.path.isdir(self.object_base_dir): - object_paths = self.list_object_paths(self.object_base_dir) - - for path in object_paths: - objects.append(os.path.relpath(path, self.object_base_dir)) - - return objects - - def type_dir(self, type, *args): - """Return directory the type""" - return os.path.join(self.type_base_dir, type, *args) - - def remote_type_explorer_dir(self, type): - """Return remote directory that holds the explorers of a type""" - return os.path.join(REMOTE_TYPE_DIR, type, "explorer") - - def transfer_object_parameter(self, cdist_object): - """Transfer the object parameter to the remote destination""" - # Create base path before using mkdir -p - self.remote_mkdir(self.remote_object_parameter_dir(cdist_object)) - - # Synchronise parameter dir afterwards - self.transfer_dir(self.object_parameter_dir(cdist_object), - self.remote_object_parameter_dir(cdist_object)) - - def transfer_global_explorers(self): - """Transfer the global explorers""" - self.remote_mkdir(REMOTE_GLOBAL_EXPLORER_DIR) - self.transfer_dir(self.global_explorer_dir, REMOTE_GLOBAL_EXPLORER_DIR) - - def transfer_type_explorers(self, type): - """Transfer explorers of a type, but only once""" - if type in self.type_explorers_transferred: - log.debug("Skipping retransfer for explorers of %s", type) - return - else: - # Do not retransfer - self.type_explorers_transferred[type] = 1 - - src = self.type_dir(type, "explorer") - remote_base = os.path.join(REMOTE_TYPE_DIR, type) - dst = self.remote_type_explorer_dir(type) - - # Only continue, if there is at least the directory - if os.path.isdir(src): - # Ensure that the path exists - self.remote_mkdir(remote_base) - self.transfer_dir(src, dst) - - - def link_type_to_emulator(self): - """Link type names to cdist-type-emulator""" - source = os.path.abspath(sys.argv[0]) - for type in self.list_types(): - destination = os.path.join(self.bin_dir, type) - log.debug("Linking %s to %s", source, destination) - os.symlink(source, destination) - def run_global_explores(self): """Run global explorers""" - explorers = self.list_global_explorers() + explorers = self.path.list_global_explorers() if(len(explorers) == 0): raise CdistError("No explorers found in", self.global_explorer_dir) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index e69de29b..a1afebbd 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -0,0 +1,24 @@ +# -*- 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 . +# +# + +class Error(Exception): + """Base exception class for this project""" + pass From e6a903fd967be6cde4e7b6585aceaa42954f4049 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 10:28:57 +0200 Subject: [PATCH 0362/4212] cleanup logger stuff, remove more path stuff from cdist bin Signed-off-by: Nico Schottelius --- bin/cdist | 10 ---------- lib/cdist/exec.py | 4 +--- lib/cdist/path.py | 3 +-- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/bin/cdist b/bin/cdist index 369fbd29..ed71249c 100755 --- a/bin/cdist +++ b/bin/cdist @@ -48,16 +48,6 @@ BANNER = """ "P' "" "" """ -# Given paths from installation -REMOTE_BASE_DIR = "/var/lib/cdist" -REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") -REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") -REMOTE_TYPE_DIR = os.path.join(REMOTE_CONF_DIR, "type") -REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") - -CODE_HEADER = "#!/bin/sh -e\n" -DOT_CDIST = ".cdist" -TYPE_PREFIX = "__" VERSION = "2.0.1" logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index aca1d689..4b61a097 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -22,9 +22,7 @@ import logging import subprocess -logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') -log = logging.getLogger() - +log = logging.getLogger(__name__) def shell_run_or_debug_fail(script, *args, **kargs): # Manually execute /bin/sh, because sh -e does what we want diff --git a/lib/cdist/path.py b/lib/cdist/path.py index c2cef1a6..401e3c46 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -35,8 +35,7 @@ CODE_HEADER = "#!/bin/sh -e\n" DOT_CDIST = ".cdist" TYPE_PREFIX = "__" -logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') -log = logging.getLogger() +log = logging.getLogger(__name__) import cdist.exec From cf920ca3e96d302e00b6827968ff1a387c574bed Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 10:53:34 +0200 Subject: [PATCH 0363/4212] prefix issues Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 91dbc72f..4e07dd96 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,16 +1,3 @@ -2.0.1: - -- Rewrite cdist-type-emulator - - Remove legacy code in cdist - - Remove cdist-config - - Remove man1/cdist-type-emulator.text - - Remove the PATH=... part from the README - - - how to access output dir? - - Test: - __cdist_type_base_dir=$(pwd -P)/conf/type __file - - Fix / rewrite cdist-quickstart - write tutorial!!!!!!!!! @@ -49,3 +36,7 @@ http://www.youtube.com/watch?v=PRMjzy48eTI - Setup __debug, if -d is given, so other tools can reuse it + (-> non core feature! + +- remote_prefix: + scp vs. ssh issue From 16d58dcac73f71352d5b77bbf5df2d78988bd68e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 11:05:18 +0200 Subject: [PATCH 0364/4212] move out banner, fail at emulator Signed-off-by: Nico Schottelius --- bin/cdist | 204 ++++++++++++++++++------------------------ bin/cdist.py | 1 - lib/cdist/__init__.py | 3 + lib/cdist/banner.py | 46 ++++++++++ lib/cdist/path.py | 8 +- 5 files changed, 140 insertions(+), 122 deletions(-) delete mode 120000 bin/cdist.py create mode 100644 lib/cdist/banner.py diff --git a/bin/cdist b/bin/cdist index ed71249c..15c3ff62 100755 --- a/bin/cdist +++ b/bin/cdist @@ -32,40 +32,7 @@ import stat import sys import tempfile - -BANNER = """ - .. . .x+=:. s - dF @88> z` ^% :8 - '88bu. %8P . . +# +# + +import logging +import sys + +log = logging.getLogger(__name__) + +BANNER = """ + .. . .x+=:. s + dF @88> z` ^% :8 + '88bu. %8P . Date: Mon, 26 Sep 2011 11:07:45 +0200 Subject: [PATCH 0365/4212] move TYPE_PREFIX back into main, as it's only needed there and should work without module Signed-off-by: Nico Schottelius --- bin/cdist | 4 +++- lib/cdist/__init__.py | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 15c3ff62..f4d67616 100755 --- a/bin/cdist +++ b/bin/cdist @@ -34,6 +34,8 @@ import tempfile log = logging.getLogger(__name__) +TYPE_PREFIX = "__" + class Cdist: """Cdist main class to hold arbitrary data""" @@ -482,7 +484,7 @@ if __name__ == "__main__": '../lib'))) import cdist - if re.match(cdist.TYPE_PREFIX, os.path.basename(sys.argv[0])): + if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): emulator() else: import cdist.banner diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 6bcc93d2..192e5001 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -19,7 +19,6 @@ # # -TYPE_PREFIX = "__" VERSION = "2.0.2" class Error(Exception): From 4eec4d96270464d8b5275a71e9d40e6f44f54bb4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 11:09:58 +0200 Subject: [PATCH 0366/4212] only setup library path in main, not emulator Signed-off-by: Nico Schottelius --- bin/cdist | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index f4d67616..d6a6da3b 100755 --- a/bin/cdist +++ b/bin/cdist @@ -478,15 +478,14 @@ if __name__ == "__main__": try: logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') - # Import generic cdist options - sys.path.insert(0, - os.path.abspath(os.path.join(os.path.dirname(__file__), - '../lib'))) - import cdist - if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): emulator() else: + cdist_lib = os.path.abspath(os.path.join(os.path.dirname(__file__), + '../lib')) + sys.path.insert(0, cdist_lib) + + import cdist import cdist.banner import cdist.exec import cdist.path From 6d75016139cec7d14a9d937eecabd3c32f4bd885 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 11:18:36 +0200 Subject: [PATCH 0367/4212] make type emulator load again Signed-off-by: Nico Schottelius --- bin/cdist | 120 ++++---------------------------------- lib/cdist/emulator.py | 132 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 108 deletions(-) create mode 100755 lib/cdist/emulator.py diff --git a/bin/cdist b/bin/cdist index d6a6da3b..3b19e388 100755 --- a/bin/cdist +++ b/bin/cdist @@ -146,9 +146,16 @@ class Cdist: env['__cdist_local_base_dir'] = self.path.temp_dir # Submit information to new type emulator + + # Required for recording source env['__cdist_manifest'] = manifest + + # Required to find types env['__cdist_type_base_dir'] = self.path.type_base_dir + # Required for loading emulator :-) + env['__cdist_python_lib'] = cdist_lib + # Other environment stuff if extra_env: env.update(extra_env) @@ -306,112 +313,6 @@ def install(args): """Install remote system""" process = {} -def emulator(): - """Emulate type commands (i.e. __file and co)""" - type = os.path.basename(sys.argv[0]) - type_dir = os.path.join(os.environ['__cdist_type_base_dir'], type) - param_dir = os.path.join(type_dir, "parameter") - global_dir = os.environ['__global'] - object_source = os.environ['__cdist_manifest'] - - parser = argparse.ArgumentParser(add_help=False) - - # Setup optional parameters - for parameter in file_to_list(os.path.join(param_dir, "optional")): - argument = "--" + parameter - parser.add_argument(argument, action='store', required=False) - - # Setup required parameters - for parameter in file_to_list(os.path.join(param_dir, "required")): - argument = "--" + parameter - parser.add_argument(argument, action='store', required=True) - - # Setup positional parameter, if not singleton - - if not os.path.isfile(os.path.join(type_dir, "singleton")): - parser.add_argument("object_id", nargs=1) - - # And finally verify parameter - args = parser.parse_args(sys.argv[1:]) - - # Setup object_id - if os.path.isfile(os.path.join(type_dir, "singleton")): - object_id = "singleton" - else: - object_id = args.object_id[0] - del args.object_id - - # FIXME: / hardcoded - better portable solution available? - if object_id[0] == '/': - object_id = object_id[1:] - - # FIXME: verify object id - log.debug(args) - - object_dir = os.path.join(global_dir, "object", type, - object_id, DOT_CDIST) - param_out_dir = os.path.join(object_dir, "parameter") - - object_source_file = os.path.join(object_dir, "source") - - if os.path.exists(param_out_dir): - object_exists = True - old_object_source_fd = open(object_source_file, "r") - old_object_source = old_object_source_fd.readlines() - old_object_source_fd.close() - - else: - object_exists = False - try: - os.makedirs(param_out_dir, exist_ok=True) - except OSError as error: - raise CdistError(param_out_dir + ": " + error.args[1]) - - # Record parameter - params = vars(args) - for param in params: - value = getattr(args, param) - if value: - file = os.path.join(param_out_dir, param) - log.debug(file + "<-" + param + " = " + value) - - # Already exists, verify all parameter are the same - if object_exists: - if not os.path.isfile(file): - print("New parameter + " + param + "specified, aborting") - print("Source = " + old_object_source + "new =" + object_source) - sys.exit(1) - else: - param_fd = open(file, "r") - param_old = param_fd.readlines() - param_fd.close() - - if(param_old != param): - print("Parameter " + param + " differs: " + " ".join(param_old) + " vs. " + param) - print("Sources: " + " ".join(old_object_source) + " and " + object_source) - sys.exit(1) - else: - param_fd = open(file, "w") - param_fd.writelines(value) - param_fd.close() - - # Record requirements - if "__require" in os.environ: - requirements = os.environ['__require'] - print(object_id + ":Writing requirements: " + requirements) - require_fd = open(os.path.join(object_dir, "require"), "a") - require_fd.writelines(requirements.split(" ")) - require_fd.close() - - # Record / Append source - source_fd = open(os.path.join(object_dir, "source"), "a") - source_fd.writelines(object_source) - source_fd.close() - - # sys.exit(1) - print("Finished " + type + "/" + object_id + repr(params)) - - def commandline(): """Parse command line""" # Construct parser others can reuse @@ -477,9 +378,12 @@ def commandline(): if __name__ == "__main__": try: logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') - + if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): - emulator() + cdist_lib = os.environ["__cdist_python_lib"] + sys.path.insert(0, cdist_lib) + import cdist.emulator + cdist.emulator.emulator(sys.argv) else: cdist_lib = os.path.abspath(os.path.join(os.path.dirname(__file__), '../lib')) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py new file mode 100755 index 00000000..0e693dbe --- /dev/null +++ b/lib/cdist/emulator.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- +# +# 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 argparse +import logging +import os +import sys + +log = logging.getLogger(__name__) + +def emulator(argv): + """Emulate type commands (i.e. __file and co)""" + type = os.path.basename(argv[0]) + type_dir = os.path.join(os.environ['__cdist_type_base_dir'], type) + param_dir = os.path.join(type_dir, "parameter") + global_dir = os.environ['__global'] + object_source = os.environ['__cdist_manifest'] + + parser = argparse.ArgumentParser(add_help=False) + + # Setup optional parameters + for parameter in file_to_list(os.path.join(param_dir, "optional")): + argument = "--" + parameter + parser.add_argument(argument, action='store', required=False) + + # Setup required parameters + for parameter in file_to_list(os.path.join(param_dir, "required")): + argument = "--" + parameter + parser.add_argument(argument, action='store', required=True) + + # Setup positional parameter, if not singleton + + if not os.path.isfile(os.path.join(type_dir, "singleton")): + parser.add_argument("object_id", nargs=1) + + # And finally verify parameter + args = parser.parse_args(argv[1:]) + + # Setup object_id + if os.path.isfile(os.path.join(type_dir, "singleton")): + object_id = "singleton" + else: + object_id = args.object_id[0] + del args.object_id + + # FIXME: / hardcoded - better portable solution available? + if object_id[0] == '/': + object_id = object_id[1:] + + # FIXME: verify object id + log.debug(args) + + object_dir = os.path.join(global_dir, "object", type, + object_id, DOT_CDIST) + param_out_dir = os.path.join(object_dir, "parameter") + + object_source_file = os.path.join(object_dir, "source") + + if os.path.exists(param_out_dir): + object_exists = True + old_object_source_fd = open(object_source_file, "r") + old_object_source = old_object_source_fd.readlines() + old_object_source_fd.close() + + else: + object_exists = False + try: + os.makedirs(param_out_dir, exist_ok=True) + except OSError as error: + raise CdistError(param_out_dir + ": " + error.args[1]) + + # Record parameter + params = vars(args) + for param in params: + value = getattr(args, param) + if value: + file = os.path.join(param_out_dir, param) + log.debug(file + "<-" + param + " = " + value) + + # Already exists, verify all parameter are the same + if object_exists: + if not os.path.isfile(file): + print("New parameter + " + param + "specified, aborting") + print("Source = " + old_object_source + "new =" + object_source) + sys.exit(1) + else: + param_fd = open(file, "r") + param_old = param_fd.readlines() + param_fd.close() + + if(param_old != param): + print("Parameter " + param + " differs: " + " ".join(param_old) + " vs. " + param) + print("Sources: " + " ".join(old_object_source) + " and " + object_source) + sys.exit(1) + else: + param_fd = open(file, "w") + param_fd.writelines(value) + param_fd.close() + + # Record requirements + if "__require" in os.environ: + requirements = os.environ['__require'] + print(object_id + ":Writing requirements: " + requirements) + require_fd = open(os.path.join(object_dir, "require"), "a") + require_fd.writelines(requirements.split(" ")) + require_fd.close() + + # Record / Append source + source_fd = open(os.path.join(object_dir, "source"), "a") + source_fd.writelines(object_source) + source_fd.close() + + # sys.exit(1) + print("Finished " + type + "/" + object_id + repr(params)) From 74dc5b96cb3af00f8fb6ac3dd805f69de40d2737 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 11:21:04 +0200 Subject: [PATCH 0368/4212] type emulator begins to run Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 8 +++++--- lib/cdist/exec.py | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 0e693dbe..ecdfff25 100755 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -24,6 +24,8 @@ import logging import os import sys +import cdist.path + log = logging.getLogger(__name__) def emulator(argv): @@ -37,12 +39,12 @@ def emulator(argv): parser = argparse.ArgumentParser(add_help=False) # Setup optional parameters - for parameter in file_to_list(os.path.join(param_dir, "optional")): + for parameter in cdist.path.file_to_list(os.path.join(param_dir, "optional")): argument = "--" + parameter parser.add_argument(argument, action='store', required=False) # Setup required parameters - for parameter in file_to_list(os.path.join(param_dir, "required")): + for parameter in cdist.path.file_to_list(os.path.join(param_dir, "required")): argument = "--" + parameter parser.add_argument(argument, action='store', required=True) @@ -69,7 +71,7 @@ def emulator(argv): log.debug(args) object_dir = os.path.join(global_dir, "object", type, - object_id, DOT_CDIST) + object_id, cdist.path.DOT_CDIST) param_out_dir = os.path.join(object_dir, "parameter") object_source_file = os.path.join(object_dir, "source") diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index 4b61a097..09e4e8a4 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -29,6 +29,7 @@ def shell_run_or_debug_fail(script, *args, **kargs): # and sh -c -e does not exit if /bin/false called args[0][:0] = [ "/bin/sh", "-e" ] + remote = False if "remote_prefix" in kargs: remote = True args[0][:0] = kargs["remote_prefix"] From 0197f8da13ffdff8103a1a35c118f82ffca6968e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 11:25:22 +0200 Subject: [PATCH 0369/4212] more cleanups from refactoring Signed-off-by: Nico Schottelius --- bin/cdist | 5 +++-- lib/cdist/path.py | 17 +++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/bin/cdist b/bin/cdist index 3b19e388..f511d78e 100755 --- a/bin/cdist +++ b/bin/cdist @@ -35,6 +35,7 @@ import tempfile log = logging.getLogger(__name__) TYPE_PREFIX = "__" +CODE_HEADER = "#!/bin/sh -e\n" class Cdist: """Cdist main class to hold arbitrary data""" @@ -102,7 +103,7 @@ class Cdist: log.debug("%s exploring %s using %s storing to %s", cdist_object, explorer, remote_cmd, output) - self.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=self.remote_prefix) + cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=self.remote_prefix) output_fd.close() def init_deploy(self): @@ -240,7 +241,7 @@ class Cdist: self.run_initial_manifest() old_objects = [] - objects = self.list_objects() + objects = self.path.list_objects() # Continue process until no new objects are created anymore while old_objects != objects: diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 16aa51ea..0fa753a8 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -21,6 +21,7 @@ import logging import os +import shutil import sys import tempfile @@ -31,7 +32,6 @@ REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") REMOTE_TYPE_DIR = os.path.join(REMOTE_CONF_DIR, "type") REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") -CODE_HEADER = "#!/bin/sh -e\n" DOT_CDIST = ".cdist" log = logging.getLogger(__name__) @@ -55,9 +55,13 @@ def file_to_list(filename): class Path: """Class that handles path related configurations""" - def __init__(self, target_host, - initial_manifest=False, remote_user="root", - remote_prefix=False, base_dir=None, debug=False): + def __init__(self, + target_host, + remote_user, + remote_prefix, + initial_manifest=False, + base_dir=None, + debug=False): # Base and Temp Base if base_dir: @@ -69,10 +73,7 @@ class Path: self.target_host = target_host self.remote_user = remote_user - if remote_prefix: - self.remote_prefix = remote_prefix - else: - self.remote_prefix = ["ssh", self.remote_user + "@" + self.target_host] + self.remote_prefix = remote_prefix self.conf_dir = os.path.join(self.base_dir, "conf") self.cache_base_dir = os.path.join(self.base_dir, "cache") From 35e33570d18eadd88d929a3b213a504218152a72 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 11:45:19 +0200 Subject: [PATCH 0370/4212] also move out config Signed-off-by: Nico Schottelius --- bin/cdist | 286 +------------------------------- lib/cdist/config.py | 393 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 399 insertions(+), 280 deletions(-) create mode 100755 lib/cdist/config.py diff --git a/bin/cdist b/bin/cdist index f511d78e..4dd4f971 100755 --- a/bin/cdist +++ b/bin/cdist @@ -33,283 +33,14 @@ import sys import tempfile log = logging.getLogger(__name__) +real_me = os.path.dirname(os.path.realpath(__file__)) +cdist_lib = os.path.abspath(os.path.join(real_me, '../lib')) + +sys.path.insert(0, cdist_lib) TYPE_PREFIX = "__" CODE_HEADER = "#!/bin/sh -e\n" -class Cdist: - """Cdist main class to hold arbitrary data""" - - def __init__(self, target_host, - initial_manifest=False, remote_user="root", - home=None, debug=False): - - self.target_host = target_host - self.debug = debug - self.remote_user = remote_user - self.remote_prefix = ["ssh", self.remote_user + "@" + self.target_host] - - self.path = cdist.path.Path(self.target_host, - initial_manifest=initial_manifest, - remote_user=self.remote_user, - remote_prefix=self.remote_prefix, - base_dir=home, - debug=debug) - - - self.objects_prepared = [] - - def cleanup(self): - self.path.cleanup() - - def run_global_explores(self): - """Run global explorers""" - explorers = self.path.list_global_explorers() - if(len(explorers) == 0): - raise CdistError("No explorers found in", self.path.global_explorer_dir) - - self.path.transfer_global_explorers() - for explorer in explorers: - output = self.path.global_explorer_output_path(explorer) - output_fd = open(output, mode='w') - cmd = [] - cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append(self.path.remote_global_explorer_path(explorer)) - - cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=self.remote_prefix) - output_fd.close() - - def run_type_explorer(self, cdist_object): - """Run type specific explorers for objects""" - - type = self.path.get_type_from_object(cdist_object) - self.path.transfer_type_explorers(type) - - cmd = [] - cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append("__type_explorer=" + self.path.remote_type_explorer_dir(type)) - cmd.append("__object=" + self.path.remote_object_dir(cdist_object)) - cmd.append("__object_id=" + self.path.get_object_id_from_object(cdist_object)) - cmd.append("__object_fq=" + cdist_object) - - # Need to transfer at least the parameters for objects to be useful - self.path.transfer_object_parameter(cdist_object) - - explorers = self.path.list_type_explorers(type) - for explorer in explorers: - remote_cmd = cmd + [os.path.join(self.path.remote_type_explorer_dir(type), explorer)] - output = os.path.join(self.path.type_explorer_output_dir(cdist_object), explorer) - output_fd = open(output, mode='w') - log.debug("%s exploring %s using %s storing to %s", - cdist_object, explorer, remote_cmd, output) - - cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=self.remote_prefix) - output_fd.close() - - def init_deploy(self): - """Ensure the base directories are cleaned up""" - log.debug("Creating clean directory structure") - - self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) - self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) - - def run_initial_manifest(self): - """Run the initial manifest""" - env = { "__manifest" : self.path.manifest_dir } - self.run_manifest(self.path.initial_manifest, extra_env=env) - - def run_type_manifest(self, cdist_object): - """Run manifest for a specific object""" - type = self.path.get_type_from_object(cdist_object) - manifest = self.path.type_dir(type, "manifest") - - log.debug("%s: Running %s", cdist_object, manifest) - if os.path.exists(manifest): - env = { "__object" : self.path.object_dir(cdist_object), - "__object_id": self.path.get_object_id_from_object(cdist_object), - "__object_fq": cdist_object, - "__type": self.path.type_dir(type) - } - self.run_manifest(manifest, extra_env=env) - - def run_manifest(self, manifest, extra_env=None): - """Run a manifest""" - log.debug("Running manifest %s, env=%s", manifest, extra_env) - env = os.environ.copy() - env['PATH'] = self.path.bin_dir + ":" + env['PATH'] - - # Information required in every manifest - env['__target_host'] = self.target_host - env['__global'] = self.path.out_dir - - # Legacy stuff to make cdist-type-emulator work - env['__cdist_core_dir'] = os.path.join(self.path.base_dir, "core") - env['__cdist_local_base_dir'] = self.path.temp_dir - - # Submit information to new type emulator - - # Required for recording source - env['__cdist_manifest'] = manifest - - # Required to find types - env['__cdist_type_base_dir'] = self.path.type_base_dir - - # Required for loading emulator :-) - env['__cdist_python_lib'] = cdist_lib - - # Other environment stuff - if extra_env: - env.update(extra_env) - - cdist.exec.shell_run_or_debug_fail(manifest, [manifest], env=env) - - def object_run(self, cdist_object, mode): - """Run gencode or code for an object""" - log.debug("Running %s from %s", mode, cdist_object) - file=os.path.join(self.path.object_dir(cdist_object), "require") - requirements = cdist.path.file_to_list(file) - type = self.path.get_type_from_object(cdist_object) - - for requirement in requirements: - log.debug("Object %s requires %s", cdist_object, requirement) - self.object_run(requirement, mode=mode) - - # - # Setup env Variable: - # - env = os.environ.copy() - env['__target_host'] = self.target_host - env['__global'] = self.path.out_dir - env["__object"] = self.path.object_dir(cdist_object) - env["__object_id"] = self.path.get_object_id_from_object(cdist_object) - env["__object_fq"] = cdist_object - env["__type"] = self.path.type_dir(type) - - if mode == "gencode": - paths = [ - self.path.type_dir(type, "gencode-local"), - self.path.type_dir(type, "gencode-remote") - ] - for bin in paths: - if os.path.isfile(bin): - # omit "gen" from gencode and use it for output base - outfile=os.path.join(self.path.object_dir(cdist_object), - os.path.basename(bin)[3:]) - - outfile_fd = open(outfile, "w") - - # Need to flush to ensure our write is done before stdout write - outfile_fd.write(CODE_HEADER) - outfile_fd.flush() - - cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) - outfile_fd.close() - - status = os.stat(outfile) - - # Remove output if empty, else make it executable - if status.st_size == len(CODE_HEADER): - os.unlink(outfile) - else: - # Add header and make executable - identically to 0o700 - os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) - - # Mark object as changed - open(os.path.join(self.path.object_dir(cdist_object), "changed"), "w").close() - - - if mode == "code": - local_dir = self.path.object_dir(cdist_object) - remote_dir = self.path.remote_object_dir(cdist_object) - - bin = os.path.join(local_dir, "code-local") - if os.path.isfile(bin): - cdist.exec.run_or_fail([bin]) - - - local_remote_code = os.path.join(local_dir, "code-remote") - remote_remote_code = os.path.join(remote_dir, "code-remote") - if os.path.isfile(local_remote_code): - self.path.transfer_file(local_remote_code, remote_remote_code) - # FIXME: remote_prefix - cdist.exec.run_or_fail([remote_remote_code], remote_prefix=self.remote_prefix) - - def stage_prepare(self): - """Do everything for a deploy, minus the actual code stage""" - self.init_deploy() - self.run_global_explores() - self.run_initial_manifest() - - old_objects = [] - objects = self.path.list_objects() - - # Continue process until no new objects are created anymore - while old_objects != objects: - log.debug("Prepare stage") - old_objects = list(objects) - for cdist_object in objects: - if cdist_object in self.objects_prepared: - log.debug("Skipping rerun of object %s", cdist_object) - continue - else: - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) - self.objects_prepared.append(cdist_object) - - objects = self.path.list_objects() - - def stage_run(self): - """The final (and real) step of deployment""" - log.debug("Actual run objects") - # Now do the final steps over the existing objects - for cdist_object in self.path.list_objects(): - log.debug("Run object: %s", cdist_object) - self.object_run(cdist_object, mode="gencode") - self.object_run(cdist_object, mode="code") - - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to " + self.target_host) - time_start = datetime.datetime.now() - - self.stage_prepare() - self.stage_run() - - time_end = datetime.datetime.now() - duration = time_end - time_start - log.info("Finished run of %s in %s seconds", - self.target_host, - duration.total_seconds()) - - def deploy_and_cleanup(self): - """Do what is most often done: deploy & cleanup""" - self.deploy_to() - self.cleanup() - -def config(args): - """Configure remote system""" - process = {} - - time_start = datetime.datetime.now() - - for host in args.host: - c = Cdist(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) - if args.parallel: - log.debug("Creating child process for %s", host) - process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) - process[host].start() - else: - c.deploy_and_cleanup() - - if args.parallel: - for p in process.keys(): - log.debug("Joining %s", p) - process[p].join() - - time_end = datetime.datetime.now() - log.info("Total processing time for %s host(s): %s", len(args.host), - (time_end - time_start).total_seconds()) - def install(args): """Install remote system""" process = {} @@ -355,7 +86,7 @@ def commandline(): # Config parser['config'] = parser['sub'].add_parser('config', parents=[parser['most'], parser['configinstall']]) - parser['config'].set_defaults(func=config) + parser['config'].set_defaults(func=cdist.config.config) # Install parser['install'] = parser['sub'].add_parser('install', @@ -381,17 +112,12 @@ if __name__ == "__main__": logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): - cdist_lib = os.environ["__cdist_python_lib"] - sys.path.insert(0, cdist_lib) import cdist.emulator cdist.emulator.emulator(sys.argv) else: - cdist_lib = os.path.abspath(os.path.join(os.path.dirname(__file__), - '../lib')) - sys.path.insert(0, cdist_lib) - import cdist import cdist.banner + import cdist.config import cdist.exec import cdist.path diff --git a/lib/cdist/config.py b/lib/cdist/config.py new file mode 100755 index 00000000..a5a2252f --- /dev/null +++ b/lib/cdist/config.py @@ -0,0 +1,393 @@ +#!/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 datetime +import logging +import os +import stat + +log = logging.getLogger(__name__) + +import cdist.path + +CODE_HEADER = "#!/bin/sh -e\n" + +class Config: + """Cdist main class to hold arbitrary data""" + + def __init__(self, target_host, + initial_manifest=False, remote_user="root", + home=None, debug=False): + + self.target_host = target_host + self.debug = debug + self.remote_user = remote_user + self.remote_prefix = ["ssh", self.remote_user + "@" + self.target_host] + + self.path = cdist.path.Path(self.target_host, + initial_manifest=initial_manifest, + remote_user=self.remote_user, + remote_prefix=self.remote_prefix, + base_dir=home, + debug=debug) + + self.objects_prepared = [] + + def cleanup(self): + self.path.cleanup() + + def run_global_explores(self): + """Run global explorers""" + explorers = self.path.list_global_explorers() + if(len(explorers) == 0): + raise CdistError("No explorers found in", self.path.global_explorer_dir) + + self.path.transfer_global_explorers() + for explorer in explorers: + output = self.path.global_explorer_output_path(explorer) + output_fd = open(output, mode='w') + cmd = [] + cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append(self.path.remote_global_explorer_path(explorer)) + + cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=self.remote_prefix) + output_fd.close() + + def run_type_explorer(self, cdist_object): + """Run type specific explorers for objects""" + + type = self.path.get_type_from_object(cdist_object) + self.path.transfer_type_explorers(type) + + cmd = [] + cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append("__type_explorer=" + self.path.remote_type_explorer_dir(type)) + cmd.append("__object=" + self.path.remote_object_dir(cdist_object)) + cmd.append("__object_id=" + self.path.get_object_id_from_object(cdist_object)) + cmd.append("__object_fq=" + cdist_object) + + # Need to transfer at least the parameters for objects to be useful + self.path.transfer_object_parameter(cdist_object) + + explorers = self.path.list_type_explorers(type) + for explorer in explorers: + remote_cmd = cmd + [os.path.join(self.path.remote_type_explorer_dir(type), explorer)] + output = os.path.join(self.path.type_explorer_output_dir(cdist_object), explorer) + output_fd = open(output, mode='w') + log.debug("%s exploring %s using %s storing to %s", + cdist_object, explorer, remote_cmd, output) + + cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=self.remote_prefix) + output_fd.close() + + def init_deploy(self): + """Ensure the base directories are cleaned up""" + log.debug("Creating clean directory structure") + + self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) + self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) + + def run_initial_manifest(self): + """Run the initial manifest""" + env = { "__manifest" : self.path.manifest_dir } + self.run_manifest(self.path.initial_manifest, extra_env=env) + + def run_type_manifest(self, cdist_object): + """Run manifest for a specific object""" + type = self.path.get_type_from_object(cdist_object) + manifest = self.path.type_dir(type, "manifest") + + log.debug("%s: Running %s", cdist_object, manifest) + if os.path.exists(manifest): + env = { "__object" : self.path.object_dir(cdist_object), + "__object_id": self.path.get_object_id_from_object(cdist_object), + "__object_fq": cdist_object, + "__type": self.path.type_dir(type) + } + self.run_manifest(manifest, extra_env=env) + + def run_manifest(self, manifest, extra_env=None): + """Run a manifest""" + log.debug("Running manifest %s, env=%s", manifest, extra_env) + env = os.environ.copy() + env['PATH'] = self.path.bin_dir + ":" + env['PATH'] + + # Information required in every manifest + env['__target_host'] = self.target_host + env['__global'] = self.path.out_dir + + # Legacy stuff to make cdist-type-emulator work + env['__cdist_core_dir'] = os.path.join(self.path.base_dir, "core") + env['__cdist_local_base_dir'] = self.path.temp_dir + + # Submit information to new type emulator + + # Required for recording source + env['__cdist_manifest'] = manifest + + # Required to find types + env['__cdist_type_base_dir'] = self.path.type_base_dir + + # Other environment stuff + if extra_env: + env.update(extra_env) + + cdist.exec.shell_run_or_debug_fail(manifest, [manifest], env=env) + + def object_run(self, cdist_object, mode): + """Run gencode or code for an object""" + log.debug("Running %s from %s", mode, cdist_object) + file=os.path.join(self.path.object_dir(cdist_object), "require") + requirements = cdist.path.file_to_list(file) + type = self.path.get_type_from_object(cdist_object) + + for requirement in requirements: + log.debug("Object %s requires %s", cdist_object, requirement) + self.object_run(requirement, mode=mode) + + # + # Setup env Variable: + # + env = os.environ.copy() + env['__target_host'] = self.target_host + env['__global'] = self.path.out_dir + env["__object"] = self.path.object_dir(cdist_object) + env["__object_id"] = self.path.get_object_id_from_object(cdist_object) + env["__object_fq"] = cdist_object + env["__type"] = self.path.type_dir(type) + + if mode == "gencode": + paths = [ + self.path.type_dir(type, "gencode-local"), + self.path.type_dir(type, "gencode-remote") + ] + for bin in paths: + if os.path.isfile(bin): + # omit "gen" from gencode and use it for output base + outfile=os.path.join(self.path.object_dir(cdist_object), + os.path.basename(bin)[3:]) + + outfile_fd = open(outfile, "w") + + # Need to flush to ensure our write is done before stdout write + outfile_fd.write(CODE_HEADER) + outfile_fd.flush() + + cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) + outfile_fd.close() + + status = os.stat(outfile) + + # Remove output if empty, else make it executable + if status.st_size == len(CODE_HEADER): + os.unlink(outfile) + else: + # Add header and make executable - identically to 0o700 + os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + + # Mark object as changed + open(os.path.join(self.path.object_dir(cdist_object), "changed"), "w").close() + + + if mode == "code": + local_dir = self.path.object_dir(cdist_object) + remote_dir = self.path.remote_object_dir(cdist_object) + + bin = os.path.join(local_dir, "code-local") + if os.path.isfile(bin): + cdist.exec.run_or_fail([bin]) + + + local_remote_code = os.path.join(local_dir, "code-remote") + remote_remote_code = os.path.join(remote_dir, "code-remote") + if os.path.isfile(local_remote_code): + self.path.transfer_file(local_remote_code, remote_remote_code) + # FIXME: remote_prefix + cdist.exec.run_or_fail([remote_remote_code], remote_prefix=self.remote_prefix) + + def stage_prepare(self): + """Do everything for a deploy, minus the actual code stage""" + self.init_deploy() + self.run_global_explores() + self.run_initial_manifest() + + old_objects = [] + objects = self.path.list_objects() + + # Continue process until no new objects are created anymore + while old_objects != objects: + log.debug("Prepare stage") + old_objects = list(objects) + for cdist_object in objects: + if cdist_object in self.objects_prepared: + log.debug("Skipping rerun of object %s", cdist_object) + continue + else: + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + self.objects_prepared.append(cdist_object) + + objects = self.path.list_objects() + + def stage_run(self): + """The final (and real) step of deployment""" + log.debug("Actual run objects") + # Now do the final steps over the existing objects + for cdist_object in self.path.list_objects(): + log.debug("Run object: %s", cdist_object) + self.object_run(cdist_object, mode="gencode") + self.object_run(cdist_object, mode="code") + + def deploy_to(self): + """Mimic the old deploy to: Deploy to one host""" + log.info("Deploying to " + self.target_host) + time_start = datetime.datetime.now() + + self.stage_prepare() + self.stage_run() + + time_end = datetime.datetime.now() + duration = time_end - time_start + log.info("Finished run of %s in %s seconds", + self.target_host, + duration.total_seconds()) + + def deploy_and_cleanup(self): + """Do what is most often done: deploy & cleanup""" + self.deploy_to() + self.cleanup() + +def config(args): + """Configure remote system""" + process = {} + + time_start = datetime.datetime.now() + + for host in args.host: + c = Config(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) + if args.parallel: + log.debug("Creating child process for %s", host) + process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) + process[host].start() + else: + c.deploy_and_cleanup() + + if args.parallel: + for p in process.keys(): + log.debug("Joining %s", p) + process[p].join() + + time_end = datetime.datetime.now() + log.info("Total processing time for %s host(s): %s", len(args.host), + (time_end - time_start).total_seconds()) + +def install(args): + """Install remote system""" + process = {} + +def commandline(): + """Parse command line""" + # Construct parser others can reuse + parser = {} + # Options _all_ parsers have in common + parser['most'] = argparse.ArgumentParser(add_help=False) + parser['most'].add_argument('-d', '--debug', + help='Set log level to debug', action='store_true') + + # Main subcommand parser + parser['main'] = argparse.ArgumentParser(description='cdist ' + cdist.VERSION) + parser['main'].add_argument('-V', '--version', + help='Show version', action='version', + version='%(prog)s ' + cdist.VERSION) + parser['sub'] = parser['main'].add_subparsers(title="Commands") + + # Banner + parser['banner'] = parser['sub'].add_parser('banner', + add_help=False) + 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='+', + help='one or more hosts to operate on') + parser['configinstall'].add_argument('-c', '--cdist-home', + help='Change cdist home (default: .. from bin directory)', + action='store') + parser['configinstall'].add_argument('-i', '--initial-manifest', + help='Path to a cdist manifest', + dest='manifest', required=False) + parser['configinstall'].add_argument('-p', '--parallel', + help='Operate on multiple hosts in parallel', + action='store_true', dest='parallel') + parser['configinstall'].add_argument('-s', '--sequential', + help='Operate on multiple hosts sequentially (default)', + action='store_false', dest='parallel') + + # Config + parser['config'] = parser['sub'].add_parser('config', + parents=[parser['most'], parser['configinstall']]) + parser['config'].set_defaults(func=config) + + # Install + parser['install'] = parser['sub'].add_parser('install', + parents=[parser['most'], 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/" + + args = parser['main'].parse_args(sys.argv[1:]) + + # Most subcommands have --debug, so handle it here + if 'debug' in args: + if args.debug: + logging.root.setLevel(logging.DEBUG) + log.debug(args) + + args.func(args) + + +if __name__ == "__main__": + try: + logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') + + if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): + cdist_lib = os.environ["__cdist_python_lib"] + sys.path.insert(0, cdist_lib) + import cdist.emulator + cdist.emulator.emulator(sys.argv) + else: + cdist_lib = os.path.abspath(os.path.join(os.path.dirname(__file__), + '../lib')) + sys.path.insert(0, cdist_lib) + + import cdist + import cdist.banner + import cdist.exec + import cdist.path + + commandline() + except KeyboardInterrupt: + sys.exit(0) + except cdist.Error as e: + log.error(e) + sys.exit(1) From 27b4b9cd039f30ad71f7533da79f195c82c1fbdc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 11:53:09 +0200 Subject: [PATCH 0371/4212] also move out install and cleanup library path code Signed-off-by: Nico Schottelius --- bin/cdist | 16 ++++++---------- lib/cdist/install.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 10 deletions(-) create mode 100755 lib/cdist/install.py diff --git a/bin/cdist b/bin/cdist index 4dd4f971..5e1b96bf 100755 --- a/bin/cdist +++ b/bin/cdist @@ -33,17 +33,13 @@ import sys import tempfile log = logging.getLogger(__name__) -real_me = os.path.dirname(os.path.realpath(__file__)) -cdist_lib = os.path.abspath(os.path.join(real_me, '../lib')) -sys.path.insert(0, cdist_lib) +# Ensure our /lib/ is included into PYTHON_PATH +sys.path.insert(0, os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib')) +) TYPE_PREFIX = "__" -CODE_HEADER = "#!/bin/sh -e\n" - -def install(args): - """Install remote system""" - process = {} def commandline(): """Parse command line""" @@ -91,7 +87,7 @@ def commandline(): # Install parser['install'] = parser['sub'].add_parser('install', parents=[parser['most'], parser['configinstall']]) - parser['install'].set_defaults(func=install) + parser['install'].set_defaults(func=cdist.install.install) for p in parser: parser[p].epilog = "Get cdist at http://www.nico.schottelius.org/software/cdist/" @@ -106,7 +102,6 @@ def commandline(): args.func(args) - if __name__ == "__main__": try: logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') @@ -119,6 +114,7 @@ if __name__ == "__main__": import cdist.banner import cdist.config import cdist.exec + import cdist.install import cdist.path commandline() diff --git a/lib/cdist/install.py b/lib/cdist/install.py new file mode 100755 index 00000000..98b388ec --- /dev/null +++ b/lib/cdist/install.py @@ -0,0 +1,30 @@ +#!/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 logging + +log = logging.getLogger(__name__) + +def install(args): + """Install remote system""" + process = {} + From fc1e0d9f1fbdead1ab0c548ef17ce94f64f53f0c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 11:55:59 +0200 Subject: [PATCH 0372/4212] remove exec bits from copying Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 0 lib/cdist/emulator.py | 0 lib/cdist/install.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 lib/cdist/config.py mode change 100755 => 100644 lib/cdist/emulator.py mode change 100755 => 100644 lib/cdist/install.py diff --git a/lib/cdist/config.py b/lib/cdist/config.py old mode 100755 new mode 100644 diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py old mode 100755 new mode 100644 diff --git a/lib/cdist/install.py b/lib/cdist/install.py old mode 100755 new mode 100644 From 6458499d2bda5eacf2f40da3515dd103cc9031e7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 12:02:24 +0200 Subject: [PATCH 0373/4212] J) Signed-off-by: Nico Schottelius --- bin/cdist | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 5e1b96bf..f8596e67 100755 --- a/bin/cdist +++ b/bin/cdist @@ -36,8 +36,7 @@ log = logging.getLogger(__name__) # Ensure our /lib/ is included into PYTHON_PATH sys.path.insert(0, os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib')) -) + os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) TYPE_PREFIX = "__" From 0cd24f1544f71c63d9e8aaab7b9425b8e53c9772 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 15:08:59 +0200 Subject: [PATCH 0374/4212] rename quickstart to tutorial Signed-off-by: Nico Schottelius --- doc/man/man7/{cdist-quickstart.text => cdist-tutorial.text} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/man/man7/{cdist-quickstart.text => cdist-tutorial.text} (100%) diff --git a/doc/man/man7/cdist-quickstart.text b/doc/man/man7/cdist-tutorial.text similarity index 100% rename from doc/man/man7/cdist-quickstart.text rename to doc/man/man7/cdist-tutorial.text From 597e1e73453318f7886c8eb6c63f0ab8e27bc011 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 15:15:36 +0200 Subject: [PATCH 0375/4212] remove obsolete cdist-deploy-stdin-to Signed-off-by: Nico Schottelius --- bin/cdist-deploy-stdin-to | 36 ------------------------- doc/man/man1/cdist-deploy-stdin-to.text | 30 --------------------- 2 files changed, 66 deletions(-) delete mode 100755 bin/cdist-deploy-stdin-to delete mode 100644 doc/man/man1/cdist-deploy-stdin-to.text diff --git a/bin/cdist-deploy-stdin-to b/bin/cdist-deploy-stdin-to deleted file mode 100755 index 391dd431..00000000 --- a/bin/cdist-deploy-stdin-to +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -# -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Use stdin as the manifest to deploy on the given host. -# - -. cdist-config -[ $# -eq 1 ] || __cdist_usage "" -set -eu - -__cdist_target_host="$1" -shift - -cat >> "$__cdist_tmp_file" - -chmod +x "$__cdist_tmp_file" - -export __cdist_manifest_init="$__cdist_tmp_file" -cdist-deploy-to "$__cdist_target_host" diff --git a/doc/man/man1/cdist-deploy-stdin-to.text b/doc/man/man1/cdist-deploy-stdin-to.text deleted file mode 100644 index 14f19478..00000000 --- a/doc/man/man1/cdist-deploy-stdin-to.text +++ /dev/null @@ -1,30 +0,0 @@ -cdist-deploy-stdin-to(1) -======================== -Steven Armstrong - - -NAME ----- -cdist-deploy-stdin-to - Deploy the configuration given on stdin to host - - -SYNOPSIS --------- -echo "__file /tmp/whatever" | cdist-deploy-stdin-to HOSTNAME - - -DESCRIPTION ------------ -Use stdin as the manifest for cdist-deploy-to. - - -SEE ALSO --------- -- cdist(7) -- cdist-deploy-to(1) - - -COPYING -------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). From 996fa75c2eff3bd0ffe4c6a10b30447a953209b1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 15:18:55 +0200 Subject: [PATCH 0376/4212] cleanup cdist imports Signed-off-by: Nico Schottelius --- bin/cdist | 6 ------ 1 file changed, 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index f8596e67..d21fda40 100755 --- a/bin/cdist +++ b/bin/cdist @@ -21,16 +21,10 @@ # import argparse -import datetime import logging -import multiprocessing import os import re -import subprocess -import shutil -import stat import sys -import tempfile log = logging.getLogger(__name__) From ef197eebe330bcdfb1af07806b288b88c8b6cfd7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 15:42:27 +0200 Subject: [PATCH 0377/4212] move test to top level Signed-off-by: Nico Schottelius --- test.py | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ test/cdist.py | 12 ----------- 2 files changed, 59 insertions(+), 12 deletions(-) create mode 100755 test.py delete mode 100644 test/cdist.py diff --git a/test.py b/test.py new file mode 100755 index 00000000..ad56df11 --- /dev/null +++ b/test.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 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 sys +import unittest + +sys.path.insert(0, os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), 'lib'))) + +import cdist +import cdist.config +import cdist.exec + +class Exec(unittest.TestCase): + def test_local_success(self): + try: + cdist.exec.run_or_fail(["/bin/true"]) + except cdist.Error: + failed = True + else: + failed = False + + self.assertFalse(failed) + + def test_local_fail(self): + try: + cdist.exec.run_or_fail(["/bin/false"]) + except cdist.Error: + failed = True + else: + failed = False + + self.assertTrue(failed) + + + +if __name__ == '__main__': + unittest.main() diff --git a/test/cdist.py b/test/cdist.py deleted file mode 100644 index 3ccc69bc..00000000 --- a/test/cdist.py +++ /dev/null @@ -1,12 +0,0 @@ -import cdist -import unittest - - -class CdistGeneric(unittest.TestCase): - - def test_initial_manifest(self): - self.assertEqual(numeral, result) - - -if __name__ == '__main__': - unittest.main() From 4906f604f0d1da1968c06e5e9e7cd3ca88a4c75d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 15:42:39 +0200 Subject: [PATCH 0378/4212] raise cdist errors Signed-off-by: Nico Schottelius --- lib/cdist/exec.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index 09e4e8a4..f95ba941 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -24,6 +24,8 @@ import subprocess log = logging.getLogger(__name__) +import cdist + def shell_run_or_debug_fail(script, *args, **kargs): # Manually execute /bin/sh, because sh -e does what we want # and sh -c -e does not exit if /bin/false called @@ -50,11 +52,11 @@ def shell_run_or_debug_fail(script, *args, **kargs): print(script_fd.read()) script_fd.close() except IOError as error: - raise CdistError(str(error)) + raise cdist.Error(str(error)) - raise CdistError("Command failed (shell): " + " ".join(*args)) + raise cdist.Error("Command failed (shell): " + " ".join(*args)) except OSError as error: - raise CdistError(" ".join(*args) + ": " + error.args[1]) + raise cdist.Error(" ".join(*args) + ": " + error.args[1]) def run_or_fail(*args, **kargs): @@ -66,6 +68,6 @@ def run_or_fail(*args, **kargs): try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: - raise CdistError("Command failed: " + " ".join(*args)) + raise cdist.Error("Command failed: " + " ".join(*args)) except OSError as error: - raise CdistError(" ".join(*args) + ": " + error.args[1]) + raise cdist.Error(" ".join(*args) + ": " + error.args[1]) From 7882b4a3ac11b0866819f92b50e9231d11166aed Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 16:03:53 +0200 Subject: [PATCH 0379/4212] only print env, if existent Signed-off-by: Nico Schottelius --- lib/cdist/exec.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index f95ba941..b0f98b56 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -38,7 +38,10 @@ def shell_run_or_debug_fail(script, *args, **kargs): del kargs["remote_prefix"] log.debug("Shell exec cmd: %s", args) - log.debug("Shell exec env: %s", kargs['env']) + + if 'env' in kargs: + log.debug("Shell exec env: %s", kargs['env']) + try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: From 24b8a57df51160463c501f92523303dcdf050269 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 16:04:27 +0200 Subject: [PATCH 0380/4212] write first tests for the exec module Signed-off-by: Nico Schottelius --- test.py | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/test.py b/test.py index ad56df11..b5b80dc9 100755 --- a/test.py +++ b/test.py @@ -23,6 +23,8 @@ import os import sys +import shutil +import tempfile import unittest sys.path.insert(0, os.path.abspath( @@ -33,6 +35,38 @@ import cdist.config import cdist.exec class Exec(unittest.TestCase): + def setUp(self): + """Create shell code and co.""" + + self.temp_dir = tempfile.mkdtemp() + self.shell_false = os.path.join(self.temp_dir, "shell_false") + self.shell_true = os.path.join(self.temp_dir, "shell_true") + + true_fd = open(self.shell_false, "w") + true_fd.writelines(["!/bin/sh", "/bin/true"]) + true_fd.close() + + false_fd = open(self.shell_false, "w") + false_fd.writelines(["!/bin/sh", "/bin/false"]) + false_fd.close() + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_local_success_shell(self): + try: + cdist.shell_run_or_debug_fail(self.shell_true, [self.shell_true]) + except cdist.Error: + failed = True + else: + failed = False + + self.assertFalse(failed) + + def test_local_fail_shell(self): + self.assertRaises(cdist.Error, cdist.exec.shell_run_or_debug_fail, + self.shell_false, [self.shell_false]) + def test_local_success(self): try: cdist.exec.run_or_fail(["/bin/true"]) @@ -44,15 +78,7 @@ class Exec(unittest.TestCase): self.assertFalse(failed) def test_local_fail(self): - try: - cdist.exec.run_or_fail(["/bin/false"]) - except cdist.Error: - failed = True - else: - failed = False - - self.assertTrue(failed) - + self.assertRaises(cdist.Error, cdist.exec.run_or_fail, ["/bin/false"]) if __name__ == '__main__': From 6e73572a9514583c32f6643ed4d21d09ab8cde74 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 16:21:56 +0200 Subject: [PATCH 0381/4212] easier check for remote_prefix Signed-off-by: Nico Schottelius --- lib/cdist/exec.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index b0f98b56..7985bdb3 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -26,16 +26,13 @@ log = logging.getLogger(__name__) import cdist -def shell_run_or_debug_fail(script, *args, **kargs): +def shell_run_or_debug_fail(script, *args, remote_prefix=False, **kargs): # Manually execute /bin/sh, because sh -e does what we want # and sh -c -e does not exit if /bin/false called args[0][:0] = [ "/bin/sh", "-e" ] - remote = False - if "remote_prefix" in kargs: - remote = True - args[0][:0] = kargs["remote_prefix"] - del kargs["remote_prefix"] + if remote_prefix: + args[0][:0] = remote_prefix log.debug("Shell exec cmd: %s", args) @@ -46,9 +43,9 @@ def shell_run_or_debug_fail(script, *args, **kargs): subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: log.error("Code that raised the error:\n") - if remote: - # FIXME: included in Path! - remote_cat(script) + if remote_prefix: + run_or_fail(["cat", script], remote_prefix=remote_prefix) + else: try: script_fd = open(script) @@ -62,10 +59,9 @@ def shell_run_or_debug_fail(script, *args, **kargs): raise cdist.Error(" ".join(*args) + ": " + error.args[1]) -def run_or_fail(*args, **kargs): - if "remote_prefix" in kargs: - args[0][:0] = kargs["remote_prefix"] - del kargs["remote_prefix"] +def run_or_fail(*args, remote_prefix=False, **kargs): + if remote_prefix: + args[0][:0] = remote_prefix log.debug("Exec: " + " ".join(*args)) try: From c687dbdc70951e15d0ba8e7adbd486e8c147a493 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 16:22:09 +0200 Subject: [PATCH 0382/4212] remove remote_cat, as it's only used in exec module Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 0fa753a8..277b1401 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -125,10 +125,6 @@ class Path: """Create directory on remote side""" cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=self.remote_prefix) - def remote_cat(filename): - """Use cat on the remote side for output""" - cdist.exec.run_or_fail(["cat", filename], remote_prefix=self.remote_prefix) - def remove_remote_dir(self, destination): cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=self.remote_prefix) From 5e862c9ede969ec026dbf19e2a3ea158182a8ede Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 17:33:26 +0200 Subject: [PATCH 0383/4212] make cdist-tutorial compile Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-tutorial.text | 55 ++++++++++++-------------------- 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index e146f1a8..dfda5325 100755 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -1,40 +1,23 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Give the user an introduction into cdist -# +cdist-tutorial(7) +================= +Nico Schottelius -. cdist-config -set -eu -banner="cdist-quickstart>" -continue="Press enter to continue or ctrl-c to abort." -create_continue="Press enter to create the described files/directories" +NAME +---- +cdist-tutorial - a guided introduction into cdist -__prompt() -{ - echo -n "$banner" "$@" - read answer -} -################################################################################ +INTRODUCTION +------------ +This tutorial is aimed at people learning cdist and shows +typical approaches as well as gives an easy start into +the world of configuration management. + + +NOT MIGRATED +------------ + # Intro of quickstart # cat << eof @@ -305,6 +288,10 @@ That's it, this is the end of the cdist-quickstart. I hope you've got some impression on how cdist works, here are again some pointers on where to continue to read: -cdist(7), cdist-deploy-to(1), cdist-type(7), cdist-stages(7) eof + +SEE ALSO +-------- +cdist(1), cdist-type(7), cdist-stages(7) + From d5df740f17c2207fdf0e92181c2f74b6671fbe1b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Sep 2011 20:14:04 +0200 Subject: [PATCH 0384/4212] always compile documentation with UTF-8 encoding Signed-off-by: Nico Schottelius --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index bef4393b..68abafde 100755 --- a/build.sh +++ b/build.sh @@ -27,7 +27,7 @@ #set -e # Manpage and HTML -A2XM="a2x -f manpage --no-xmllint" +A2XM="a2x -f manpage --no-xmllint -a encoding=UTF-8" A2XH="a2x -f xhtml --no-xmllint" # Developer webbase From df84480fcc5efb0763f34b420b9568396a0e375a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 00:02:04 +0200 Subject: [PATCH 0385/4212] BUGFIX: emulator compared parameter with value Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index ecdfff25..a97959e6 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -105,11 +105,11 @@ def emulator(argv): sys.exit(1) else: param_fd = open(file, "r") - param_old = param_fd.readlines() + value_old = param_fd.readlines() param_fd.close() - if(param_old != param): - print("Parameter " + param + " differs: " + " ".join(param_old) + " vs. " + param) + if(value_old != value): + print("Parameter " + param + " differs: " + " ".join(value_old) + " vs. " + value) print("Sources: " + " ".join(old_object_source) + " and " + object_source) sys.exit(1) else: From 1cfb6bf5a8f6707b30e9239f69d94c06df446290 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 00:11:59 +0200 Subject: [PATCH 0386/4212] make manpage compile for __partition_msdos_apply Signed-off-by: Nico Schottelius --- conf/type/__partition_msdos_apply/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__partition_msdos_apply/man.text b/conf/type/__partition_msdos_apply/man.text index 4d4f127c..6cc53b77 100644 --- a/conf/type/__partition_msdos_apply/man.text +++ b/conf/type/__partition_msdos_apply/man.text @@ -5,7 +5,7 @@ Steven Armstrong NAME ---- -cdist-type__partition_msdos_apply +cdist-type__partition_msdos_apply - Apply dos partition settings DESCRIPTION From 87937ecec92232fc8e4aa402c35b9cd0fb988121 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 00:12:11 +0200 Subject: [PATCH 0387/4212] also always use utf-8 for html Signed-off-by: Nico Schottelius --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 68abafde..d20e0211 100755 --- a/build.sh +++ b/build.sh @@ -28,7 +28,7 @@ # Manpage and HTML A2XM="a2x -f manpage --no-xmllint -a encoding=UTF-8" -A2XH="a2x -f xhtml --no-xmllint" +A2XH="a2x -f xhtml --no-xmllint -a encoding=UTF-8" # Developer webbase WEBDIR=$HOME/niconetz From 877d8fed309fac3df8691f4533f0ee5385b5a406 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 00:34:41 +0200 Subject: [PATCH 0388/4212] verify that corrupted manifests are detected as such Signed-off-by: Nico Schottelius --- test.py | 49 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/test.py b/test.py index b5b80dc9..d1d62d25 100755 --- a/test.py +++ b/test.py @@ -42,12 +42,12 @@ class Exec(unittest.TestCase): self.shell_false = os.path.join(self.temp_dir, "shell_false") self.shell_true = os.path.join(self.temp_dir, "shell_true") - true_fd = open(self.shell_false, "w") - true_fd.writelines(["!/bin/sh", "/bin/true"]) + true_fd = open(self.shell_true, "w") + true_fd.writelines(["#!/bin/sh", "/bin/true"]) true_fd.close() false_fd = open(self.shell_false, "w") - false_fd.writelines(["!/bin/sh", "/bin/false"]) + false_fd.writelines(["#!/bin/sh", "/bin/false"]) false_fd.close() def tearDown(self): @@ -55,7 +55,7 @@ class Exec(unittest.TestCase): def test_local_success_shell(self): try: - cdist.shell_run_or_debug_fail(self.shell_true, [self.shell_true]) + cdist.exec.shell_run_or_debug_fail(self.shell_true, [self.shell_true]) except cdist.Error: failed = True else: @@ -80,6 +80,47 @@ class Exec(unittest.TestCase): def test_local_fail(self): self.assertRaises(cdist.Error, cdist.exec.run_or_fail, ["/bin/false"]) +class Config(unittest.TestCase): + def setUp(self): + self.temp_dir = tempfile.mkdtemp() + self.init_manifest = os.path.join(self.temp_dir, "manifest") + self.config = cdist.config.Config("localhost", + initial_manifest=self.init_manifest) + + def test_initial_manifest_different_parameter(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh", + "__file " + self.temp_dir + "--mode 0700", + "__file " + self.temp_dir + "--mode 0600", + ]) + manifest_fd.close() + + self.assertRaises(cdist.Error, self.config.run_initial_manifest()) + + def test_initial_manifest_parameter_added(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh", + "__file " + self.temp_dir, + "__file " + self.temp_dir + "--mode 0600", + ]) + manifest_fd.close() + + self.assertRaises(cdist.Error, self.config.run_initial_manifest()) + + def test_initial_manifest_parameter_removed(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh", + "__file " + self.temp_dir + "--mode 0600", + "__file " + self.temp_dir, + ]) + manifest_fd.close() + + self.assertRaises(cdist.Error, self.config.run_initial_manifest()) + +# Todo: +# fail if parameter in manifest given are different +# fail if parameter in manifest given are absent once/given once +# succeed if same parameter is specified twice if __name__ == '__main__': unittest.main() From 603f1c3ae075c7d5e47f1bfd472e89cec884cda4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 00:38:08 +0200 Subject: [PATCH 0389/4212] also check that giving a paramter twice works Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-tutorial.text | 65 +++++++++++++++++++++++++++++++- test.py | 20 ++++++++-- 2 files changed, 79 insertions(+), 6 deletions(-) diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index dfda5325..8abcbad4 100755 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -15,8 +15,69 @@ typical approaches as well as gives an easy start into the world of configuration management. -NOT MIGRATED ------------- + +QUICK START +----------- +For those who just want to configure a system with the +cdist configuration management and do not need (or want) +to understand everything. + +Cdist uses **ssh** for communication and transportation +and usually logs into the **target host** as the +**root** user. So you need to configure the **ssh server** +of the target host to allow root logins: Edit +the file **/etc/ssh/sshd_config** and add one of the following +lines: + +-------------------------------------------------------------------------------- +# Allow login only via public key +PermitRootLogin without-password + +# Allow login via password and public key +PermitRootLogin yes +-------------------------------------------------------------------------------- + + +Before you can start using cdist, you need to ensure that +you can login +sshd config! + + + + + +You can copy and paste the following +code into your shell to get started and even configure your system. + +-------------------------------------------------------------------------------- +# Get cdist +git clone git://git.schottelius.org/cdist + +# Create manifest (maps configuration to host(s) +cd cdist +echo '__file /etc/cdist-configured' > conf/manifest/init +chmod 0700 conf/manifest/init + +echo 'Ensure that you can login as root to localhost without password' +echo '(i.e. via public key) and then press return' +read tmp + +# Configure localhost +./bin/cdist config localhost + +# Find out that cdist created /etc/cdist-configured +ls -l /etc/cdist-configured +-------------------------------------------------------------------------------- + +The file 'conf/manifest/init' is usually the entry point for cdist, +to find out what to configure on which host. All manifests are +essentially shell scripts. Every manifest can use the types known to +cdist, which are usually underline prefixed (\_\_). + + + +Everything you specify in manifests + # Intro of quickstart # diff --git a/test.py b/test.py index d1d62d25..2eb0b89f 100755 --- a/test.py +++ b/test.py @@ -117,10 +117,22 @@ class Config(unittest.TestCase): self.assertRaises(cdist.Error, self.config.run_initial_manifest()) -# Todo: -# fail if parameter in manifest given are different -# fail if parameter in manifest given are absent once/given once -# succeed if same parameter is specified twice + def test_initial_manifest_parameter_twice(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh", + "__file " + self.temp_dir + "--mode 0600", + "__file " + self.temp_dir + "--mode 0600", + ]) + manifest_fd.close() + + try: + self.config.run_initial_manifest() + except cdist.Error: + failed = True + else: + failed = False + + self.assertFalse(failed) if __name__ == '__main__': unittest.main() From 326ff6728365cd94b8e29d3dbbb49d0d704ebbe2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 00:48:29 +0200 Subject: [PATCH 0390/4212] break tests by fixing them Signed-off-by: Nico Schottelius --- test.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test.py b/test.py index 2eb0b89f..a3652c41 100755 --- a/test.py +++ b/test.py @@ -89,9 +89,9 @@ class Config(unittest.TestCase): def test_initial_manifest_different_parameter(self): manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh", - "__file " + self.temp_dir + "--mode 0700", - "__file " + self.temp_dir + "--mode 0600", + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + "--mode 0700\n", + "__file " + self.temp_dir + "--mode 0600\n", ]) manifest_fd.close() @@ -99,9 +99,9 @@ class Config(unittest.TestCase): def test_initial_manifest_parameter_added(self): manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh", - "__file " + self.temp_dir, - "__file " + self.temp_dir + "--mode 0600", + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + '\n', + "__file " + self.temp_dir + "--mode 0600\n", ]) manifest_fd.close() @@ -109,9 +109,9 @@ class Config(unittest.TestCase): def test_initial_manifest_parameter_removed(self): manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh", - "__file " + self.temp_dir + "--mode 0600", - "__file " + self.temp_dir, + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + "--mode 0600\n", + "__file " + self.temp_dir + "\n", ]) manifest_fd.close() @@ -119,9 +119,9 @@ class Config(unittest.TestCase): def test_initial_manifest_parameter_twice(self): manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh", - "__file " + self.temp_dir + "--mode 0600", - "__file " + self.temp_dir + "--mode 0600", + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + "--mode 0600\n", + "__file " + self.temp_dir + "--mode 0600\n", ]) manifest_fd.close() From 2c0a7adf74578ce6151468afcf724ddddbcf46fc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 00:49:12 +0200 Subject: [PATCH 0391/4212] replace CdistError with cdist.Error Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 3 ++- lib/cdist/exec.py | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index a97959e6..bd97f69b 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -24,6 +24,7 @@ import logging import os import sys +import cdist import cdist.path log = logging.getLogger(__name__) @@ -87,7 +88,7 @@ def emulator(argv): try: os.makedirs(param_out_dir, exist_ok=True) except OSError as error: - raise CdistError(param_out_dir + ": " + error.args[1]) + raise cdist.Error(param_out_dir + ": " + error.args[1]) # Record parameter params = vars(args) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index 7985bdb3..9cedefcc 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -58,7 +58,6 @@ def shell_run_or_debug_fail(script, *args, remote_prefix=False, **kargs): except OSError as error: raise cdist.Error(" ".join(*args) + ": " + error.args[1]) - def run_or_fail(*args, remote_prefix=False, **kargs): if remote_prefix: args[0][:0] = remote_prefix From 1dcc3b771e42c7593f65890aa41fd723957693a7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 00:58:16 +0200 Subject: [PATCH 0392/4212] +some ssh hints, localhost hint Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-tutorial.text | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 8abcbad4..9b6e7492 100755 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -14,6 +14,10 @@ This tutorial is aimed at people learning cdist and shows typical approaches as well as gives an easy start into the world of configuration management. +This tutorial assumes you are configuring **localhost**, because +it is always available. Just repace **localhost** with your target +host for real life usage. + QUICK START @@ -37,6 +41,19 @@ PermitRootLogin without-password PermitRootLogin yes -------------------------------------------------------------------------------- +As cdist uses ssh intensively, it is recommended to setup authentication +with public keys: + +-------------------------------------------------------------------------------- +# Generate pubkey pair as a normal user +ssh-keygen + +# Copy pubkey over to target host +ssh-copy-id root@target_host +-------------------------------------------------------------------------------- + +As soon as you are able to login to the target host + Before you can start using cdist, you need to ensure that you can login @@ -75,6 +92,9 @@ essentially shell scripts. Every manifest can use the types known to cdist, which are usually underline prefixed (\_\_). +SSH HINTS +--------- +Control master, ssh agent Everything you specify in manifests From d87deba30eccd70ce37b9b4844e2a25e873d9513 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 01:01:12 +0200 Subject: [PATCH 0393/4212] cleanup tutorial, fillup todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 280 ++++++++++++++++++++++++++++ doc/man/man7/cdist-tutorial.text | 301 +------------------------------ 2 files changed, 283 insertions(+), 298 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 4e07dd96..91b418a2 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -8,6 +8,286 @@ - and that ssh will wait for answer of prompt - nasty if used in parallel mode (scroll up!) + +SSH HINTS +--------- +Control master, ssh agent + +Everything you specify in manifests + + +# Intro of quickstart +# +cat << eof +$banner cdist version $__cdist_version + +Welcome to the interactive guide to cdist! +This is the interactive tutorial and beginners help for cdist and here's +our schedule: + + - Stages: How cdist operates + - Explorer: Explore facts of the target host + - Manifest: Map configurations to hosts + - Types: Bundled functionality + - Deploy a configuration to the local host! + +eof +__prompt "$continue" + +################################################################################ +# Stages +# +cat << eof + +To deploy configurations to a host, you call + + cdist-deploy-to + +which makes calls to other scripts, which realise the so called "stages". +Usually you'll not notice this, but in case you want to debug or hack cdist, +you can run each stage on its own. Besides that, you just need to remember +that the command cdist-deploy-to is the main cdist command. + +See also: + + Source of cdist-deploy-to(1), cdist-stages(7) + +eof +__prompt "$continue" + +################################################################################ +# Explorer +# +cat << eof + +The first thing cdist always does is running different explorers on the +target host. The explorers can be found in the directory + + ${__cdist_explorer_dir} + +An explorer is executed on the target host and its output is saved to a file. +You can use these files later to decide what or how to configure the host. + +For a demonstration, we'll call the OS explorer locally now, but remember: +This is only for demonstration, normally it is run on the target host. +The os explorer will which either displays the detected operating system or +nothing if it does not know your OS. + +See also: + + cdist-explorer(7) + +eof +explorer="${__cdist_explorer_dir}/os" + +__prompt "Press enter to execute $explorer" + +set -x +"$explorer" +set +x + +################################################################################ +# Manifest +# +cat << eof + +The initial manifest is the entry point for cdist to find out, what you would +like to have configured. It is located at + + ${__cdist_manifest_init} + +And can be as simple as + +-------------------------------------------------------------------------------- +__file /etc/cdist-configured --type file +-------------------------------------------------------------------------------- + +See also: + + cdist-manifest(7) + +eof +__prompt "$continue" + +cat << eof + +Let's take a deeper look at the initial manifest to understand what it means: + + __file /etc/cdist-configured --type file + | | | \\ + | | The parameter type \\ With the value file + | | + | | + | | This is the object id + | + __file is a so called "type" + + +This essentially looks like a standard command executed in the shell. +eof +__prompt "$continue" + +cat << eof + +And that's exactly true. Manifests are shell snippets that can use +types as commands with arguments. cdist prepends a special path +that contain links to the cdist-type-emulator, to \$PATH, so you +can use your types as a command. + +This is also the reason why types should always be prefixed with +"__", to prevent collisions with existing binaries. + +The object id is unique per type and used to prevent you from creating +the same object twice. + +Parameters are type specific and are always specified as --parameter . + +See also: + + cdist-type-build-emulation(1), cdist-type-emulator(1) + +eof +__prompt "$continue" + +################################################################################ +# Types +# +cat << eof + +Types are bundled functionality and are the main component of cdist. +If you want to have a feature x, you write the type __x. Types are stored in + + ${__cdist_type_dir} + +And cdist ships with some types already! + +See also: + + cdist-type(7) + +eof +__prompt "Press enter to see available types" + +set -x +ls ${__cdist_type_dir} +set +x + +cat << eof + +Types consist of the following parts: + + - ${__cdist_name_parameter} (${__cdist_name_parameter_required}/${__cdist_name_parameter_optional} + - ${__cdist_name_manifest} + - ${__cdist_name_explorer} + - ${__cdist_name_gencode} + +eof +__prompt "$continue" + + +cat << eof + +Every type must have a directory named ${__cdist_name_parameter}, which +contains required or optional parameters (in newline seperated files). + +If an object of a specific type was created in the initial manifest, +the manifest of the type is run and may create other objects. + +A type may have ${__cdist_name_explorer}, which are very similar to the +${__cdist_name_explorer} seen above, but with a different purpose: +They are specific to the type and are not relevant for other types. + +You may use them for instance to find out details on the target host, +so you can decide what to do on the target host eventually. + +After the ${__cdist_name_manifest} and the ${__cdist_name_explorer} of +a type have been run, ${__cdist_name_gencode} is executed, which creates +code to be executed on the target on stdout. + +eof +__prompt "$continue" + +################################################################################ +# Deployment +# + +cat << eof + +Now you've got some basic knowledge about cdist, let's configure your a host! + +Ensure that you have a ssh server running on the host and that you can login as root. + +eof + +__prompt "Enter hostname or press enter for localhost: " + +if [ "$answer" ]; then + host="$answer" +else + host="localhost" +fi + +manifestinit="conf/manifest/init" +cat << eof + +I'll now setup $manifestinit, containing the following code: + +-------------------------------------------------------------------------------- +# Every machine becomes a marker, so sysadmins know that automatic +# configurations are happening +__file /etc/cdist-configured + +case "\$__target_host" in + $host) + __link /tmp/cdist-testfile --source /etc/cdist-configured --type symbolic + __addifnosuchline /tmp/cdist-welcome --line "Welcome to cdist" + ;; +esac +-------------------------------------------------------------------------------- + +WARNING: This will overwrite ${manifestinit}. + +eof + +cat > "$__cdist_abs_mydir/../$manifestinit" << eof + +# Every machine becomes a marker, so sysadmins know that automatic +# configurations are happening +__file /etc/cdist-configured + +case "\$__target_host" in + $host) + __link /tmp/cdist-testfile --source /etc/cdist-configured --type symbolic + __addifnosuchline /tmp/cdist-welcome --line "Welcome to cdist" + ;; +esac + +eof + +chmod u+x "$__cdist_abs_mydir/../$manifestinit" + +cmd="cdist-deploy-to $host" + +__prompt "Press enter to run \"$cmd\"" + +# No quotes, we need field splitting +$cmd + +################################################################################ +# End +# + +cat << eof + + +-------------------------------------------------------------------------------- +That's it, this is the end of the cdist-quickstart. + +I hope you've got some impression on how cdist works, here are again some +pointers on where to continue to read: + + +eof -------------------------------------------------------------------------------- - Initial install support diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 9b6e7492..15f2a81d 100755 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -52,19 +52,9 @@ ssh-keygen ssh-copy-id root@target_host -------------------------------------------------------------------------------- -As soon as you are able to login to the target host - - -Before you can start using cdist, you need to ensure that -you can login -sshd config! - - - - - -You can copy and paste the following -code into your shell to get started and even configure your system. +As soon as you are able to login without passwort to the target host, +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 @@ -75,10 +65,6 @@ cd cdist echo '__file /etc/cdist-configured' > conf/manifest/init chmod 0700 conf/manifest/init -echo 'Ensure that you can login as root to localhost without password' -echo '(i.e. via public key) and then press return' -read tmp - # Configure localhost ./bin/cdist config localhost @@ -92,287 +78,6 @@ essentially shell scripts. Every manifest can use the types known to cdist, which are usually underline prefixed (\_\_). -SSH HINTS ---------- -Control master, ssh agent - -Everything you specify in manifests - - -# Intro of quickstart -# -cat << eof -$banner cdist version $__cdist_version - -Welcome to the interactive guide to cdist! -This is the interactive tutorial and beginners help for cdist and here's -our schedule: - - - Stages: How cdist operates - - Explorer: Explore facts of the target host - - Manifest: Map configurations to hosts - - Types: Bundled functionality - - Deploy a configuration to the local host! - -eof -__prompt "$continue" - -################################################################################ -# Stages -# -cat << eof - -To deploy configurations to a host, you call - - cdist-deploy-to - -which makes calls to other scripts, which realise the so called "stages". -Usually you'll not notice this, but in case you want to debug or hack cdist, -you can run each stage on its own. Besides that, you just need to remember -that the command cdist-deploy-to is the main cdist command. - -See also: - - Source of cdist-deploy-to(1), cdist-stages(7) - -eof -__prompt "$continue" - -################################################################################ -# Explorer -# -cat << eof - -The first thing cdist always does is running different explorers on the -target host. The explorers can be found in the directory - - ${__cdist_explorer_dir} - -An explorer is executed on the target host and its output is saved to a file. -You can use these files later to decide what or how to configure the host. - -For a demonstration, we'll call the OS explorer locally now, but remember: -This is only for demonstration, normally it is run on the target host. -The os explorer will which either displays the detected operating system or -nothing if it does not know your OS. - -See also: - - cdist-explorer(7) - -eof -explorer="${__cdist_explorer_dir}/os" - -__prompt "Press enter to execute $explorer" - -set -x -"$explorer" -set +x - -################################################################################ -# Manifest -# -cat << eof - -The initial manifest is the entry point for cdist to find out, what you would -like to have configured. It is located at - - ${__cdist_manifest_init} - -And can be as simple as - --------------------------------------------------------------------------------- -__file /etc/cdist-configured --type file --------------------------------------------------------------------------------- - -See also: - - cdist-manifest(7) - -eof -__prompt "$continue" - -cat << eof - -Let's take a deeper look at the initial manifest to understand what it means: - - __file /etc/cdist-configured --type file - | | | \\ - | | The parameter type \\ With the value file - | | - | | - | | This is the object id - | - __file is a so called "type" - - -This essentially looks like a standard command executed in the shell. -eof -__prompt "$continue" - -cat << eof - -And that's exactly true. Manifests are shell snippets that can use -types as commands with arguments. cdist prepends a special path -that contain links to the cdist-type-emulator, to \$PATH, so you -can use your types as a command. - -This is also the reason why types should always be prefixed with -"__", to prevent collisions with existing binaries. - -The object id is unique per type and used to prevent you from creating -the same object twice. - -Parameters are type specific and are always specified as --parameter . - -See also: - - cdist-type-build-emulation(1), cdist-type-emulator(1) - -eof -__prompt "$continue" - -################################################################################ -# Types -# -cat << eof - -Types are bundled functionality and are the main component of cdist. -If you want to have a feature x, you write the type __x. Types are stored in - - ${__cdist_type_dir} - -And cdist ships with some types already! - -See also: - - cdist-type(7) - -eof -__prompt "Press enter to see available types" - -set -x -ls ${__cdist_type_dir} -set +x - -cat << eof - -Types consist of the following parts: - - - ${__cdist_name_parameter} (${__cdist_name_parameter_required}/${__cdist_name_parameter_optional} - - ${__cdist_name_manifest} - - ${__cdist_name_explorer} - - ${__cdist_name_gencode} - -eof -__prompt "$continue" - - -cat << eof - -Every type must have a directory named ${__cdist_name_parameter}, which -contains required or optional parameters (in newline seperated files). - -If an object of a specific type was created in the initial manifest, -the manifest of the type is run and may create other objects. - -A type may have ${__cdist_name_explorer}, which are very similar to the -${__cdist_name_explorer} seen above, but with a different purpose: -They are specific to the type and are not relevant for other types. - -You may use them for instance to find out details on the target host, -so you can decide what to do on the target host eventually. - -After the ${__cdist_name_manifest} and the ${__cdist_name_explorer} of -a type have been run, ${__cdist_name_gencode} is executed, which creates -code to be executed on the target on stdout. - -eof -__prompt "$continue" - -################################################################################ -# Deployment -# - -cat << eof - -Now you've got some basic knowledge about cdist, let's configure your a host! - -Ensure that you have a ssh server running on the host and that you can login as root. - -eof - -__prompt "Enter hostname or press enter for localhost: " - -if [ "$answer" ]; then - host="$answer" -else - host="localhost" -fi - -manifestinit="conf/manifest/init" -cat << eof - -I'll now setup $manifestinit, containing the following code: - --------------------------------------------------------------------------------- -# Every machine becomes a marker, so sysadmins know that automatic -# configurations are happening -__file /etc/cdist-configured - -case "\$__target_host" in - $host) - __link /tmp/cdist-testfile --source /etc/cdist-configured --type symbolic - __addifnosuchline /tmp/cdist-welcome --line "Welcome to cdist" - ;; -esac --------------------------------------------------------------------------------- - -WARNING: This will overwrite ${manifestinit}. - -eof - -cat > "$__cdist_abs_mydir/../$manifestinit" << eof - -# Every machine becomes a marker, so sysadmins know that automatic -# configurations are happening -__file /etc/cdist-configured - -case "\$__target_host" in - $host) - __link /tmp/cdist-testfile --source /etc/cdist-configured --type symbolic - __addifnosuchline /tmp/cdist-welcome --line "Welcome to cdist" - ;; -esac - -eof - -chmod u+x "$__cdist_abs_mydir/../$manifestinit" - -cmd="cdist-deploy-to $host" - -__prompt "Press enter to run \"$cmd\"" - -# No quotes, we need field splitting -$cmd - -################################################################################ -# End -# - -cat << eof - - --------------------------------------------------------------------------------- -That's it, this is the end of the cdist-quickstart. - -I hope you've got some impression on how cdist works, here are again some -pointers on where to continue to read: - - -eof - SEE ALSO -------- cdist(1), cdist-type(7), cdist-stages(7) - From cdd4e0968343cc72d79f3228fd7e2f56c611c404 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 01:12:09 +0200 Subject: [PATCH 0394/4212] prefix/localhost in tutorial Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-tutorial.text | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 15f2a81d..80135da9 100755 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -49,7 +49,7 @@ with public keys: ssh-keygen # Copy pubkey over to target host -ssh-copy-id root@target_host +ssh-copy-id root@localhost -------------------------------------------------------------------------------- As soon as you are able to login without passwort to the target host, @@ -75,7 +75,7 @@ ls -l /etc/cdist-configured The file 'conf/manifest/init' is usually the entry point for cdist, to find out what to configure on which host. All manifests are essentially shell scripts. Every manifest can use the types known to -cdist, which are usually underline prefixed (\_\_). +cdist, which are usually underline prefixed (__). SEE ALSO From 3e49b12a6d30dd4621aa5150948c3662cc18aaf0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 01:17:32 +0200 Subject: [PATCH 0395/4212] update cdist-hacker Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-hacker.text | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/doc/man/man7/cdist-hacker.text b/doc/man/man7/cdist-hacker.text index efd6ef7d..b9f79d01 100644 --- a/doc/man/man7/cdist-hacker.text +++ b/doc/man/man7/cdist-hacker.text @@ -26,26 +26,12 @@ in the latest version, drop a mail to the cdist mailing list, subject prefixed with "[BUG] ". -UNDERSTANDING CDIST INTERNALS ------------------------------ -IF you are interested in how cdist internally works, you can open -bin/cdist-config and bin/cdist-deploy-to in your favorite editor and -read the scripts bin/cdist-deploy-to calls. The magnificent HACKERS_README -may be of great help as well. - - CODING CONVENTIONS (EVERYWHERE) ------------------------------- If something should be better done or needs to fixed, add the word FIXME nearby, so grepping for FIXME gives all positions that need to be fixed. -CODING CONVENTIONS (CORE) -------------------------- -- All variables exported by cdist are prefixed with a double underscore (__) -- All cdist-internal variables are prefixed with __cdist_ and are generally not exported. - - HOW TO SUBMIT STUFF FOR INCLUSION INTO UPSTREAM CDIST ----------------------------------------------------- If you did some cool changes to cdist, which you value as a benefit for From ae4d6002f06364a12598d449262c3872746bc7b2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 01:21:16 +0200 Subject: [PATCH 0396/4212] permissions/rephrase Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-explorer.text | 2 +- doc/man/man7/cdist-tutorial.text | 0 2 files changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 doc/man/man7/cdist-tutorial.text diff --git a/doc/man/man7/cdist-explorer.text b/doc/man/man7/cdist-explorer.text index 63c7a5c9..e1909ab5 100644 --- a/doc/man/man7/cdist-explorer.text +++ b/doc/man/man7/cdist-explorer.text @@ -26,7 +26,7 @@ $__explorer/ (general and type explorer) or $__type_explorer/ (type explorer). In case of significant errors, the explorer may exit non-zero and return an -error message on stderr, which will cause the cdist run to abort. +error message on stderr, which will cause cdist to abort. You can also use stderr for debugging purposes while developing a new explorer. diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text old mode 100755 new mode 100644 From 75023a4ac9061f0eca8792622e972d5d4b57e124 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 01:22:45 +0200 Subject: [PATCH 0397/4212] begin to cleanup cdist-stages Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 1 + doc/man/man7/cdist-stages.text | 35 +--------------------------------- 2 files changed, 2 insertions(+), 34 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 91b418a2..14098099 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -8,6 +8,7 @@ - and that ssh will wait for answer of prompt - nasty if used in parallel mode (scroll up!) +- rewrite cdist-stages SSH HINTS --------- diff --git a/doc/man/man7/cdist-stages.text b/doc/man/man7/cdist-stages.text index 294dffc7..8ac30015 100644 --- a/doc/man/man7/cdist-stages.text +++ b/doc/man/man7/cdist-stages.text @@ -32,11 +32,6 @@ explorers. Every existing explorer is run on the target and the output of all explorers are copied back into the local cache. The results can be used by manifests and types. -Related documentation: - - cdist-explorer-run-global(1) - - cdist-remote-explorer-run(1) - - cdist-explorer(7) - STAGE 2: RUN THE INITIAL MANIFEST --------------------------------- @@ -46,11 +41,6 @@ the objects as defined in the manifest for the specific host. In this stage, no conflicts may occur, i.e. no object of the same type with the same id may be created. -Related documentation: - - cdist-manifest-run-init(1) - - cdist-manifest-run(1) - - cdist-manifest(7) - STAGE 3: OBJECT INFORMATION RETRIEVAL ------------------------------------- @@ -59,12 +49,6 @@ transfered to the target host and executed. The results are transfered 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. -Related documentation: - - cdist-object-explorer-run(1) - - cdist-remote-explorer-run(1) - - cdist-type(7) - - cdist-explorer(7) - STAGE 4: RUN THE OBJECT MANIFEST -------------------------------- @@ -79,11 +63,6 @@ The newly created objects are merged back into the existing tree. No conflicts may occur during the merge. A conflict would mean that two different objects try to create the same object, which indicates a broken configuration. -Related documentation: - - cdist-object-manifest-run(1) - - cdist-manifest-run(1) - - cdist-type(7) - STAGE 5: CODE GENERATION ------------------------ @@ -92,29 +71,17 @@ gencode scripts. The gencode scripts generate the code to be executed on the target on stdout. If the gencode executables fail, they must print diagnostic messages on stderr and exit non-zero. -Related documentation: - - cdist-object-gencode-run(1) - - cdist-object-gencode(1) - - cdist-type(7) - STAGE 6: CODE EXECUTION ----------------------- For every object the resulting code from the previous stage is transferred to the target host and executed there to apply the configuration changes. -Related documentation: - - cdist-object-code-run(1) - - cdist-code-run(1) - STAGE 7: CACHE -------------- The cache stores the information from the current run for later use. -Related documentation: - - cdist-cache(1) - SUMMARY ------- @@ -126,8 +93,8 @@ in correct order. SEE ALSO -------- +- cdist(1) - cdist(7) -- cdist-deploy-to(1) - cdist-reference(7) From 4879f744c168b536843764a1e40a99a6821ed279 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 01:25:04 +0200 Subject: [PATCH 0398/4212] manpage cleanups Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 4 +++- doc/man/man7/cdist-type.text | 6 +----- doc/man/man7/cdist.text | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 14098099..b7748949 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -8,7 +8,9 @@ - and that ssh will wait for answer of prompt - nasty if used in parallel mode (scroll up!) -- rewrite cdist-stages +- rewrite cdist-stages, remove +- update man7! +- exec flag is not true for manifest anymore SSH HINTS --------- diff --git a/doc/man/man7/cdist-type.text b/doc/man/man7/cdist-type.text index 1af386fb..2439876c 100644 --- a/doc/man/man7/cdist-type.text +++ b/doc/man/man7/cdist-type.text @@ -35,10 +35,6 @@ __file /etc/cdist-configured --type file __package tree --state installed -------------------------------------------------------------------------------- -Internally cdist-type-emulator(1) will be called from cdist-manifest-run(1) to -save the given parameters into a cconfig database, so they can be accessed by -the manifest and gencode scripts of the type (see below). - A list of supported types can be found in the cdist-reference(7) manpage. SINGLETON TYPES @@ -111,7 +107,7 @@ __package_$type "$@" -------------------------------------------------------------------------------- As you can see, the type can reference different environment variables, -which are documented in cdist-environment-variables(7). +which are documented in cdist-reference(7). Always ensure the manifest is executable, otherwise cdist will not be able to execute it. diff --git a/doc/man/man7/cdist.text b/doc/man/man7/cdist.text index 9f7dbbab..2a5d1fe5 100644 --- a/doc/man/man7/cdist.text +++ b/doc/man/man7/cdist.text @@ -35,12 +35,11 @@ pull mechanism (client requests configuration). SEE ALSO -------- - Website: http://www.nico.schottelius.org/software/cdist/[] -- cdist-best-practise(7) -- cdist-deploy-to(1) - cdist-hacker(7) - cdist-manifest(7) -- cdist-quickstart(1) - cdist-type(7) +- cdist(1) +- cdist(7) COPYING From b9335bb7ce221abf09cc96951edd3ae2587d8ae9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 10:35:25 +0200 Subject: [PATCH 0399/4212] update os/os_version explorer to support owl (openwall linux) Signed-off-by: Nico Schottelius --- conf/explorer/os | 2 +- conf/explorer/os_version | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/conf/explorer/os b/conf/explorer/os index 3e1582ec..e59301e7 100755 --- a/conf/explorer/os +++ b/conf/explorer/os @@ -65,7 +65,7 @@ if [ -f /etc/SuSE-release ]; then exit 0 fi -if uname -r | grep -s '.owl' >/dev/null 2>&1; then +if [ -f /etc/owl-release ]; then echo owl exit 0 fi diff --git a/conf/explorer/os_version b/conf/explorer/os_version index 08fda60b..ef80e8fc 100755 --- a/conf/explorer/os_version +++ b/conf/explorer/os_version @@ -42,6 +42,9 @@ case "$($__explorer/os)" in *bsd|solaris) uname -r ;; + owl) + cat /etc/owl-release + ;; redhat|centos) cat /etc/redhat-release ;; From 6f1a13b531cc0664721b5763f8f2be17e8beb807 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 13:38:25 +0200 Subject: [PATCH 0400/4212] move emulator link to emulator module and make source variable (exec_path) Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 115 +++++++----------------------------------- lib/cdist/emulator.py | 9 ++++ lib/cdist/path.py | 10 ---- 3 files changed, 26 insertions(+), 108 deletions(-) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index a5a2252f..cc0f7817 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -24,9 +24,11 @@ import datetime import logging import os import stat +import sys log = logging.getLogger(__name__) +import cdist.emulator import cdist.path CODE_HEADER = "#!/bin/sh -e\n" @@ -35,12 +37,18 @@ class Config: """Cdist main class to hold arbitrary data""" def __init__(self, target_host, - initial_manifest=False, remote_user="root", - home=None, debug=False): + initial_manifest=False, + remote_user="root", + home=None, + exec_path=sys.argv[0], + debug=False): - self.target_host = target_host - self.debug = debug - self.remote_user = remote_user + self.target_host = target_host + self.debug = debug + self.remote_user = remote_user + self.exec_path = exec_path + + # FIXME: broken - construct elsewhere! self.remote_prefix = ["ssh", self.remote_user + "@" + self.target_host] self.path = cdist.path.Path(self.target_host, @@ -94,7 +102,7 @@ class Config: output = os.path.join(self.path.type_explorer_output_dir(cdist_object), explorer) output_fd = open(output, mode='w') log.debug("%s exploring %s using %s storing to %s", - cdist_object, explorer, remote_cmd, output) + cdist_object, explorer, remote_cmd, output) cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=self.remote_prefix) output_fd.close() @@ -106,6 +114,9 @@ class Config: self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) + cdist.emulator.link(self.exec_path, + self.path.bin_dir, self.path.list_types()) + def run_initial_manifest(self): """Run the initial manifest""" env = { "__manifest" : self.path.manifest_dir } @@ -299,95 +310,3 @@ def config(args): time_end = datetime.datetime.now() log.info("Total processing time for %s host(s): %s", len(args.host), (time_end - time_start).total_seconds()) - -def install(args): - """Install remote system""" - process = {} - -def commandline(): - """Parse command line""" - # Construct parser others can reuse - parser = {} - # Options _all_ parsers have in common - parser['most'] = argparse.ArgumentParser(add_help=False) - parser['most'].add_argument('-d', '--debug', - help='Set log level to debug', action='store_true') - - # Main subcommand parser - parser['main'] = argparse.ArgumentParser(description='cdist ' + cdist.VERSION) - parser['main'].add_argument('-V', '--version', - help='Show version', action='version', - version='%(prog)s ' + cdist.VERSION) - parser['sub'] = parser['main'].add_subparsers(title="Commands") - - # Banner - parser['banner'] = parser['sub'].add_parser('banner', - add_help=False) - 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='+', - help='one or more hosts to operate on') - parser['configinstall'].add_argument('-c', '--cdist-home', - help='Change cdist home (default: .. from bin directory)', - action='store') - parser['configinstall'].add_argument('-i', '--initial-manifest', - help='Path to a cdist manifest', - dest='manifest', required=False) - parser['configinstall'].add_argument('-p', '--parallel', - help='Operate on multiple hosts in parallel', - action='store_true', dest='parallel') - parser['configinstall'].add_argument('-s', '--sequential', - help='Operate on multiple hosts sequentially (default)', - action='store_false', dest='parallel') - - # Config - parser['config'] = parser['sub'].add_parser('config', - parents=[parser['most'], parser['configinstall']]) - parser['config'].set_defaults(func=config) - - # Install - parser['install'] = parser['sub'].add_parser('install', - parents=[parser['most'], 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/" - - args = parser['main'].parse_args(sys.argv[1:]) - - # Most subcommands have --debug, so handle it here - if 'debug' in args: - if args.debug: - logging.root.setLevel(logging.DEBUG) - log.debug(args) - - args.func(args) - - -if __name__ == "__main__": - try: - logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') - - if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): - cdist_lib = os.environ["__cdist_python_lib"] - sys.path.insert(0, cdist_lib) - import cdist.emulator - cdist.emulator.emulator(sys.argv) - else: - cdist_lib = os.path.abspath(os.path.join(os.path.dirname(__file__), - '../lib')) - sys.path.insert(0, cdist_lib) - - import cdist - import cdist.banner - import cdist.exec - import cdist.path - - commandline() - except KeyboardInterrupt: - sys.exit(0) - except cdist.Error as e: - log.error(e) - sys.exit(1) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index bd97f69b..b96b62dd 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -133,3 +133,12 @@ def emulator(argv): # sys.exit(1) print("Finished " + type + "/" + object_id + repr(params)) + + +def link(exec_path, bin_dir, type_list): + """Link type names to cdist-type-emulator""" + source = os.path.abspath(exec_path) + for type in type_list: + destination = os.path.join(bin_dir, type) + log.debug("Linking %s to %s", source, destination) + os.symlink(source, destination) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 277b1401..e416c42d 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -94,7 +94,6 @@ class Path: # Setup binary directory + contents self.bin_dir = os.path.join(self.out_dir, "bin") os.mkdir(self.bin_dir) - self.link_type_to_emulator() # List of type explorers transferred self.type_explorers_transferred = {} @@ -275,12 +274,3 @@ class Path: # Ensure that the path exists self.remote_mkdir(remote_base) self.transfer_dir(src, dst) - - - def link_type_to_emulator(self): - """Link type names to cdist-type-emulator""" - source = os.path.abspath(sys.argv[0]) - for type in self.list_types(): - destination = os.path.join(self.bin_dir, type) - log.debug("Linking %s to %s", source, destination) - os.symlink(source, destination) From 7ec9fbbf128e72b16a588007cd2d11d92198a673 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 14:01:04 +0200 Subject: [PATCH 0401/4212] fix argument passing in tests Signed-off-by: Nico Schottelius --- test.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/test.py b/test.py index a3652c41..908fad5e 100755 --- a/test.py +++ b/test.py @@ -30,6 +30,9 @@ import unittest sys.path.insert(0, os.path.abspath( os.path.join(os.path.dirname(os.path.realpath(__file__)), 'lib'))) +cdist_exec_path = os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), "bin/cdist")) + import cdist import cdist.config import cdist.exec @@ -85,13 +88,14 @@ class Config(unittest.TestCase): self.temp_dir = tempfile.mkdtemp() self.init_manifest = os.path.join(self.temp_dir, "manifest") self.config = cdist.config.Config("localhost", - initial_manifest=self.init_manifest) + initial_manifest=self.init_manifest, + exec_path=cdist_exec_path) def test_initial_manifest_different_parameter(self): manifest_fd = open(self.init_manifest, "w") manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + "--mode 0700\n", - "__file " + self.temp_dir + "--mode 0600\n", + "__file " + self.temp_dir + " --mode 0700\n", + "__file " + self.temp_dir + " --mode 0600\n", ]) manifest_fd.close() @@ -101,7 +105,7 @@ class Config(unittest.TestCase): manifest_fd = open(self.init_manifest, "w") manifest_fd.writelines(["#!/bin/sh\n", "__file " + self.temp_dir + '\n', - "__file " + self.temp_dir + "--mode 0600\n", + "__file " + self.temp_dir + " --mode 0600\n", ]) manifest_fd.close() @@ -110,7 +114,7 @@ class Config(unittest.TestCase): def test_initial_manifest_parameter_removed(self): manifest_fd = open(self.init_manifest, "w") manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + "--mode 0600\n", + "__file " + self.temp_dir + " --mode 0600\n", "__file " + self.temp_dir + "\n", ]) manifest_fd.close() @@ -120,8 +124,8 @@ class Config(unittest.TestCase): def test_initial_manifest_parameter_twice(self): manifest_fd = open(self.init_manifest, "w") manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + "--mode 0600\n", - "__file " + self.temp_dir + "--mode 0600\n", + "__file " + self.temp_dir + " --mode 0600\n", + "__file " + self.temp_dir + " --mode 0600\n", ]) manifest_fd.close() From 9d582ae24f1fa4c3697bb0ddfd83a146fcb75432 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 14:01:09 +0200 Subject: [PATCH 0402/4212] rename emulator to run Signed-off-by: Nico Schottelius --- bin/cdist | 2 +- lib/cdist/emulator.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/cdist b/bin/cdist index d21fda40..245b2fc0 100755 --- a/bin/cdist +++ b/bin/cdist @@ -101,7 +101,7 @@ if __name__ == "__main__": if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): import cdist.emulator - cdist.emulator.emulator(sys.argv) + cdist.emulator.run(sys.argv) else: import cdist import cdist.banner diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index b96b62dd..33594e45 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -29,7 +29,7 @@ import cdist.path log = logging.getLogger(__name__) -def emulator(argv): +def run(argv): """Emulate type commands (i.e. __file and co)""" type = os.path.basename(argv[0]) type_dir = os.path.join(os.environ['__cdist_type_base_dir'], type) @@ -101,8 +101,8 @@ def emulator(argv): # Already exists, verify all parameter are the same if object_exists: if not os.path.isfile(file): - print("New parameter + " + param + "specified, aborting") - print("Source = " + old_object_source + "new =" + object_source) + print("New parameter + \"" + param + "\" specified, aborting") + print("Source = " + " ".join(old_object_source) + " new =" + object_source) sys.exit(1) else: param_fd = open(file, "r") From 0913bb21dd26ec871a683d77a9e623f2be3716f5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 14:08:11 +0200 Subject: [PATCH 0403/4212] use raise instead of sys.exit in emulator Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 33594e45..68a67176 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -22,7 +22,6 @@ import argparse import logging import os -import sys import cdist import cdist.path @@ -101,18 +100,22 @@ def run(argv): # Already exists, verify all parameter are the same if object_exists: if not os.path.isfile(file): - print("New parameter + \"" + param + "\" specified, aborting") - print("Source = " + " ".join(old_object_source) + " new =" + object_source) - sys.exit(1) + raise cdist.Error("New parameter \"" + + param + "\" specified, aborting\n" + + "Source = " + + " ".join(old_object_source) + + " new =" + object_source) else: param_fd = open(file, "r") value_old = param_fd.readlines() param_fd.close() if(value_old != value): - print("Parameter " + param + " differs: " + " ".join(value_old) + " vs. " + value) - print("Sources: " + " ".join(old_object_source) + " and " + object_source) - sys.exit(1) + raise cdist.Error("Parameter + \"" + param + + "\" differs: " + " ".join(value_old) + " vs. " + + value + + "\nSource = " + " ".join(old_object_source) + + " new =" + object_source) else: param_fd = open(file, "w") param_fd.writelines(value) @@ -131,7 +134,6 @@ def run(argv): source_fd.writelines(object_source) source_fd.close() - # sys.exit(1) print("Finished " + type + "/" + object_id + repr(params)) From cc87573d6b877fb7e49db8cea342204bd02efc18 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 15:35:04 +0200 Subject: [PATCH 0404/4212] remove lecagy cdist-type-emulator support Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index cc0f7817..aef0b28a 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -146,12 +146,6 @@ class Config: env['__target_host'] = self.target_host env['__global'] = self.path.out_dir - # Legacy stuff to make cdist-type-emulator work - env['__cdist_core_dir'] = os.path.join(self.path.base_dir, "core") - env['__cdist_local_base_dir'] = self.path.temp_dir - - # Submit information to new type emulator - # Required for recording source env['__cdist_manifest'] = manifest From dc416f5f4910ba9c8d80efdcc68e0717123d906e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 15:43:54 +0200 Subject: [PATCH 0405/4212] pass function, not return :-) Signed-off-by: Nico Schottelius --- test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test.py b/test.py index 908fad5e..44068d52 100755 --- a/test.py +++ b/test.py @@ -99,7 +99,7 @@ class Config(unittest.TestCase): ]) manifest_fd.close() - self.assertRaises(cdist.Error, self.config.run_initial_manifest()) + self.assertRaises(cdist.Error, self.config.run_initial_manifest) def test_initial_manifest_parameter_added(self): manifest_fd = open(self.init_manifest, "w") @@ -109,7 +109,7 @@ class Config(unittest.TestCase): ]) manifest_fd.close() - self.assertRaises(cdist.Error, self.config.run_initial_manifest()) + self.assertRaises(cdist.Error, self.config.run_initial_manifest) def test_initial_manifest_parameter_removed(self): manifest_fd = open(self.init_manifest, "w") @@ -119,7 +119,7 @@ class Config(unittest.TestCase): ]) manifest_fd.close() - self.assertRaises(cdist.Error, self.config.run_initial_manifest()) + self.assertRaises(cdist.Error, self.config.run_initial_manifest) def test_initial_manifest_parameter_twice(self): manifest_fd = open(self.init_manifest, "w") From 3ebece5784bf64f1e961a5d8fdae1a4da8d52507 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 15:47:56 +0200 Subject: [PATCH 0406/4212] +\n in writelines Signed-off-by: Nico Schottelius --- test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index 44068d52..8a797d98 100755 --- a/test.py +++ b/test.py @@ -46,11 +46,11 @@ class Exec(unittest.TestCase): self.shell_true = os.path.join(self.temp_dir, "shell_true") true_fd = open(self.shell_true, "w") - true_fd.writelines(["#!/bin/sh", "/bin/true"]) + true_fd.writelines(["#!/bin/sh\n", "/bin/true"]) true_fd.close() false_fd = open(self.shell_false, "w") - false_fd.writelines(["#!/bin/sh", "/bin/false"]) + false_fd.writelines(["#!/bin/sh\n", "/bin/false"]) false_fd.close() def tearDown(self): From 1d981200c8cfaff9da4a301a261525649bab2da7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 15:56:43 +0200 Subject: [PATCH 0407/4212] test breaking run, if a non existent command is called Signed-off-by: Nico Schottelius --- test.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test.py b/test.py index 8a797d98..1e9aee48 100755 --- a/test.py +++ b/test.py @@ -121,6 +121,14 @@ class Config(unittest.TestCase): self.assertRaises(cdist.Error, self.config.run_initial_manifest) + def test_initial_manifest_non_existent_command(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh\n", + "thereisdefinitelynosuchcommend"]) + manifest_fd.close() + + self.assertRaises(cdist.Error, self.config.run_initial_manifest) + def test_initial_manifest_parameter_twice(self): manifest_fd = open(self.init_manifest, "w") manifest_fd.writelines(["#!/bin/sh\n", From ccbd0f1d8450af180f5883f3b4dad0d429dc35d6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 16:05:26 +0200 Subject: [PATCH 0408/4212] introduce config.link_emulator() to be called from test Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 11 +++++++---- test.py | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index aef0b28a..05bdb2a1 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -107,15 +107,18 @@ class Config: cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=self.remote_prefix) output_fd.close() + def link_emulator(self): + """Link emulator to types""" + cdist.emulator.link(self.exec_path, + self.path.bin_dir, self.path.list_types()) + def init_deploy(self): """Ensure the base directories are cleaned up""" log.debug("Creating clean directory structure") self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) - - cdist.emulator.link(self.exec_path, - self.path.bin_dir, self.path.list_types()) + self.link_emulator() def run_initial_manifest(self): """Run the initial manifest""" @@ -149,7 +152,7 @@ class Config: # Required for recording source env['__cdist_manifest'] = manifest - # Required to find types + # Required to find types env['__cdist_type_base_dir'] = self.path.type_base_dir # Other environment stuff diff --git a/test.py b/test.py index 1e9aee48..ce433152 100755 --- a/test.py +++ b/test.py @@ -90,6 +90,7 @@ class Config(unittest.TestCase): self.config = cdist.config.Config("localhost", initial_manifest=self.init_manifest, exec_path=cdist_exec_path) + self.config.link_emulator() def test_initial_manifest_different_parameter(self): manifest_fd = open(self.init_manifest, "w") From 272b8722c1cdda9fa7f1ef349abe9cdc9366945d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 16:10:53 +0200 Subject: [PATCH 0409/4212] fix output, compare string with string not string with list Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 6 +++--- test.py | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 68a67176..6a99ba79 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -110,12 +110,12 @@ def run(argv): value_old = param_fd.readlines() param_fd.close() - if(value_old != value): - raise cdist.Error("Parameter + \"" + param + + if(value_old[0] != value): + raise cdist.Error("Parameter\"" + param + "\" differs: " + " ".join(value_old) + " vs. " + value + "\nSource = " + " ".join(old_object_source) - + " new =" + object_source) + + " new = " + object_source) else: param_fd = open(file, "w") param_fd.writelines(value) diff --git a/test.py b/test.py index ce433152..b6a575e9 100755 --- a/test.py +++ b/test.py @@ -139,7 +139,9 @@ class Config(unittest.TestCase): manifest_fd.close() try: + print("a") self.config.run_initial_manifest() + print("b") except cdist.Error: failed = True else: From a1655856999a06fae352e61bf54d6b29561d58dd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 16:20:46 +0200 Subject: [PATCH 0410/4212] pass __debug to manifest Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 5 ++++- lib/cdist/emulator.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index 05bdb2a1..6df5d6d8 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -149,10 +149,13 @@ class Config: env['__target_host'] = self.target_host env['__global'] = self.path.out_dir + # Submit debug flag to manifest, can be used by emulator and types + env['__debug'] = "yes" + # Required for recording source env['__cdist_manifest'] = manifest - # Required to find types + # Required to find types env['__cdist_type_base_dir'] = self.path.type_base_dir # Other environment stuff diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 6a99ba79..9fc7c576 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -36,6 +36,9 @@ def run(argv): global_dir = os.environ['__global'] object_source = os.environ['__cdist_manifest'] + if '__debug' in os.environ: + logging.root.setLevel(logging.DEBUG) + parser = argparse.ArgumentParser(add_help=False) # Setup optional parameters @@ -134,7 +137,7 @@ def run(argv): source_fd.writelines(object_source) source_fd.close() - print("Finished " + type + "/" + object_id + repr(params)) + log.debug("Finished " + type + "/" + object_id + repr(params)) def link(exec_path, bin_dir, type_list): From b63fdf16edb71129908fedda0fd82e06d33d7b7a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 16:21:36 +0200 Subject: [PATCH 0411/4212] document __debug in reference Signed-off-by: Nico Schottelius --- doc/man/cdist-reference.text.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index c205bdcc..7196c3b3 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -166,6 +166,11 @@ changed:: ENVIRONMENT VARIABLES --------------------- +__debug:: + If this variable is setup, cdist runs in debug mode. + You can use this information, to only output stuff in debug + mode as well. + Available for: initial manifest, type manifest __explorer:: Directory that contains all global explorers. Available for: explorer From ae7887f775b8db8b1f89f1798de22dc15f9aa98a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 16:25:58 +0200 Subject: [PATCH 0412/4212] ++changes Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ lib/cdist/emulator.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index a08efb34..53ea04a4 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,5 +1,7 @@ 2.0.2: * Add support for detection of OpenWall Linux (Matthias Teege) + * Add support for __debug variable in manifests + * Bugfix core: Various issues with type emulator 2.0.1: 2011-09-23 * Bugfix core: Always print source of error in case of exec errors diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 9fc7c576..d69694df 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -127,7 +127,7 @@ def run(argv): # Record requirements if "__require" in os.environ: requirements = os.environ['__require'] - print(object_id + ":Writing requirements: " + requirements) + log.debug(object_id + ":Writing requirements: " + requirements) require_fd = open(os.path.join(object_dir, "require"), "a") require_fd.writelines(requirements.split(" ")) require_fd.close() From b52939ccfedf2b4e536f103cd883f61b19cf67a9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 16:40:50 +0200 Subject: [PATCH 0413/4212] only debug if __debug is setup Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 3 ++- lib/cdist/emulator.py | 12 +++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index 6df5d6d8..af47d091 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -150,7 +150,8 @@ class Config: env['__global'] = self.path.out_dir # Submit debug flag to manifest, can be used by emulator and types - env['__debug'] = "yes" + if self.debug: + env['__debug'] = "yes" # Required for recording source env['__cdist_manifest'] = manifest diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index d69694df..38a58f8c 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -38,21 +38,19 @@ def run(argv): if '__debug' in os.environ: logging.root.setLevel(logging.DEBUG) + else: + logging.basicConfig(level=logging.INFO) parser = argparse.ArgumentParser(add_help=False) - # Setup optional parameters for parameter in cdist.path.file_to_list(os.path.join(param_dir, "optional")): argument = "--" + parameter parser.add_argument(argument, action='store', required=False) - - # Setup required parameters for parameter in cdist.path.file_to_list(os.path.join(param_dir, "required")): argument = "--" + parameter parser.add_argument(argument, action='store', required=True) - # Setup positional parameter, if not singleton - + # If not singleton support one positional parameter if not os.path.isfile(os.path.join(type_dir, "singleton")): parser.add_argument("object_id", nargs=1) @@ -70,6 +68,10 @@ def run(argv): if object_id[0] == '/': object_id = object_id[1:] + # Prefix output by object_self + logformat = '%(levelname)s: ' + type + '/' + object_id + ': %(message)s' + logging.basicConfig(format=logformat) + # FIXME: verify object id log.debug(args) From 67f45944dd7d99b4a7710f34dc419ce760d65047 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 16:43:53 +0200 Subject: [PATCH 0414/4212] less todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index b7748949..11c734f9 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -311,15 +311,13 @@ eof via __global/ - Support parallel execution - - and maximum number of parallel runs (-p X) - error handling / report failed hosts -- Allow manifest to be read from stdin - Create new video for cdist 2.0.0 http://www.youtube.com/watch?v=PRMjzy48eTI - Setup __debug, if -d is given, so other tools can reuse it - (-> non core feature! + - implement everywhere to external! - remote_prefix: scp vs. ssh issue From 4a0e0ceb8a9ec695ae5e0c7c0760dc5684d82d0f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 16:44:38 +0200 Subject: [PATCH 0415/4212] release 2.0.2 today Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 53ea04a4..39455351 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,4 +1,4 @@ -2.0.2: +2.0.2: 2011-09-27 * Add support for detection of OpenWall Linux (Matthias Teege) * Add support for __debug variable in manifests * Bugfix core: Various issues with type emulator From 6519d7e92c72ff66ee2fcaeeaa62e2fb45424269 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 16:53:02 +0200 Subject: [PATCH 0416/4212] add hint for debian/argparse Signed-off-by: Nico Schottelius --- README | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/README b/README index daa12f70..7c089cf3 100644 --- a/README +++ b/README @@ -86,13 +86,23 @@ cdist was tested or is know to run on at least * SSH-Server -## Getting cdist +## Installation + +### Preperation + +Ensure you have Python 3.x and the **argparse** module installed on +the machine you use to **deploy to the targets**. + +#### Debian + + aptitude install python3 python3-setuptools + easy_install3 argparse + + +### Get cdist You can clone cdist from git, which gives you the advantage of having a version control in place for development of your own stuff as well. - -### Installation - To install cdist, execute the following commands: git clone git://git.schottelius.org/cdist From dfc3d4c7c87bc6ce0e601940a6e4417f037684da Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 16:55:39 +0200 Subject: [PATCH 0417/4212] toc = level 3 (we are getting bigger) Signed-off-by: Nico Schottelius --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 7c089cf3..555d28d6 100644 --- a/README +++ b/README @@ -15,7 +15,7 @@ "P' "" "" -[[!toc levels=2]] +[[!toc levels=3]] ## Introduction From 6c9bf9e5d7d527f4e098272e68e5ad67d6de0322 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 17:12:08 +0200 Subject: [PATCH 0418/4212] use cdist, not __main__ as logger name Signed-off-by: Nico Schottelius --- bin/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 245b2fc0..c79db293 100755 --- a/bin/cdist +++ b/bin/cdist @@ -26,7 +26,7 @@ import os import re import sys -log = logging.getLogger(__name__) +log = logging.getLogger("cdist") # Ensure our /lib/ is included into PYTHON_PATH sys.path.insert(0, os.path.abspath( From d8da7635def25dc9873886681345d67418e80de5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 17:15:54 +0200 Subject: [PATCH 0419/4212] use warning loglevel by default Signed-off-by: Nico Schottelius --- bin/cdist | 2 +- lib/cdist/config.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index c79db293..ea7cf4f9 100755 --- a/bin/cdist +++ b/bin/cdist @@ -97,7 +97,7 @@ def commandline(): if __name__ == "__main__": try: - logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') + logging.basicConfig(format='%(levelname)s: %(message)s') if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): import cdist.emulator diff --git a/lib/cdist/config.py b/lib/cdist/config.py index af47d091..f50195aa 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -65,6 +65,7 @@ class Config: def run_global_explores(self): """Run global explorers""" + log.info("Running global explorers") explorers = self.path.list_global_explorers() if(len(explorers) == 0): raise CdistError("No explorers found in", self.path.global_explorer_dir) From 0e8dcb2f3db257e5e76f89b4b8394e3ceaa09a4b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 17:20:31 +0200 Subject: [PATCH 0420/4212] add verbose support Signed-off-by: Nico Schottelius --- bin/cdist | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index ea7cf4f9..7d78ff51 100755 --- a/bin/cdist +++ b/bin/cdist @@ -41,7 +41,11 @@ def commandline(): # Options _all_ parsers have in common parser['most'] = argparse.ArgumentParser(add_help=False) parser['most'].add_argument('-d', '--debug', - help='Set log level to debug', action='store_true') + help='Set log level to debug', action='store_true', + default=False) + parser['most'].add_argument('-v', '--verbose', + help='Set log level to info, is more verbose', + action='store_true', default=False) # Main subcommand parser parser['main'] = argparse.ArgumentParser(description='cdist ' + cdist.VERSION) @@ -87,12 +91,13 @@ def commandline(): args = parser['main'].parse_args(sys.argv[1:]) - # Most subcommands have --debug, so handle it here - if 'debug' in args: - if args.debug: - logging.root.setLevel(logging.DEBUG) - log.debug(args) + # Loglevels are handled globally in here and debug wins over verbose + if args.verbose: + logging.root.setLevel(logging.INFO) + if args.debug: + logging.root.setLevel(logging.DEBUG) + log.debug(args) args.func(args) if __name__ == "__main__": From d15d65924835d0c0f1c4d559bf44fcc9cdccb21c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 17:20:43 +0200 Subject: [PATCH 0421/4212] increment version for next release Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 192e5001..a0ca2ba2 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -19,7 +19,7 @@ # # -VERSION = "2.0.2" +VERSION = "2.0.3" class Error(Exception): """Base exception class for this project""" From 26c0d5d9aa28b67b1da47e326bdc3facc045d29a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 17:27:28 +0200 Subject: [PATCH 0422/4212] upcoming changes for 2.0.3 Signed-off-by: Nico Schottelius --- doc/changelog | 3 +++ lib/cdist/config.py | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/changelog b/doc/changelog index 39455351..9fb11307 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,3 +1,6 @@ +2.0.3: + * Improved logging, added --verbose, by more quiet by default + 2.0.2: 2011-09-27 * Add support for detection of OpenWall Linux (Matthias Teege) * Add support for __debug variable in manifests diff --git a/lib/cdist/config.py b/lib/cdist/config.py index f50195aa..51615c28 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -123,6 +123,7 @@ class Config: def run_initial_manifest(self): """Run the initial manifest""" + log.info("Running initial manifest %s", self.path.initial_manifest) env = { "__manifest" : self.path.manifest_dir } self.run_manifest(self.path.initial_manifest, extra_env=env) @@ -243,12 +244,13 @@ class Config: self.run_global_explores() self.run_initial_manifest() + log.info("Running object manifests and type explorers") + old_objects = [] objects = self.path.list_objects() # Continue process until no new objects are created anymore while old_objects != objects: - log.debug("Prepare stage") old_objects = list(objects) for cdist_object in objects: if cdist_object in self.objects_prepared: @@ -263,7 +265,7 @@ class Config: def stage_run(self): """The final (and real) step of deployment""" - log.debug("Actual run objects") + log.info("Generating and executing code") # Now do the final steps over the existing objects for cdist_object in self.path.list_objects(): log.debug("Run object: %s", cdist_object) @@ -306,7 +308,7 @@ def config(args): if args.parallel: for p in process.keys(): - log.debug("Joining %s", p) + log.debug("Joining process %s", p) process[p].join() time_end = datetime.datetime.now() From 298688eb35eef7b4faee8f538062145272b7308d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 17:31:39 +0200 Subject: [PATCH 0423/4212] hint for archlinux users Signed-off-by: Nico Schottelius --- README | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README b/README index 555d28d6..28580c38 100644 --- a/README +++ b/README @@ -93,6 +93,12 @@ cdist was tested or is know to run on at least Ensure you have Python 3.x and the **argparse** module installed on the machine you use to **deploy to the targets**. +#### Archlinux + +Archlinux already has python >= 3.2, so you only need to do: + + pacman -S python + #### Debian aptitude install python3 python3-setuptools From fdb694bc42a09f94a71765c85d3fcaba74f2c70e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Sep 2011 17:36:01 +0200 Subject: [PATCH 0424/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 8be1da54..4cdb6fcf 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -34,6 +34,8 @@ USER INTERFACE -> given after manifest run already! - use absent/present for state by default? +- buggy output with packages that don't exist in archlinux and fedora: + python3 vs. python TYPES ------ From e162861b17e3bd4287ddd55e8532bb00c49ffae1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Sep 2011 09:06:20 +0200 Subject: [PATCH 0425/4212] consistently support -h, -v, -d in all commands Signed-off-by: Nico Schottelius --- bin/cdist | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/bin/cdist b/bin/cdist index 7d78ff51..0bf3ed9c 100755 --- a/bin/cdist +++ b/bin/cdist @@ -39,16 +39,17 @@ def commandline(): # Construct parser others can reuse parser = {} # Options _all_ parsers have in common - parser['most'] = argparse.ArgumentParser(add_help=False) - parser['most'].add_argument('-d', '--debug', + parser['loglevel'] = argparse.ArgumentParser(add_help=False) + parser['loglevel'].add_argument('-d', '--debug', help='Set log level to debug', action='store_true', default=False) - parser['most'].add_argument('-v', '--verbose', - help='Set log level to info, is more verbose', + parser['loglevel'].add_argument('-v', '--verbose', + help='Set log level to info, be more verbose', action='store_true', default=False) # Main subcommand parser - parser['main'] = argparse.ArgumentParser(description='cdist ' + cdist.VERSION) + parser['main'] = argparse.ArgumentParser(description='cdist ' + cdist.VERSION, + parents=[parser['loglevel']]) parser['main'].add_argument('-V', '--version', help='Show version', action='version', version='%(prog)s ' + cdist.VERSION) @@ -56,7 +57,7 @@ def commandline(): # Banner parser['banner'] = parser['sub'].add_parser('banner', - add_help=False) + parents=[parser['loglevel']]) parser['banner'].set_defaults(func=cdist.banner.banner) # Config and install (common stuff) @@ -78,12 +79,12 @@ def commandline(): # Config parser['config'] = parser['sub'].add_parser('config', - parents=[parser['most'], parser['configinstall']]) + parents=[parser['loglevel'], parser['configinstall']]) parser['config'].set_defaults(func=cdist.config.config) # Install parser['install'] = parser['sub'].add_parser('install', - parents=[parser['most'], parser['configinstall']]) + parents=[parser['loglevel'], parser['configinstall']]) parser['install'].set_defaults(func=cdist.install.install) for p in parser: From 5d018393a9a25e41121d12c8697a0c7368cd1c2f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Sep 2011 09:13:39 +0200 Subject: [PATCH 0426/4212] test if banner works Signed-off-by: Nico Schottelius --- test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test.py b/test.py index b6a575e9..8fe759a6 100755 --- a/test.py +++ b/test.py @@ -24,6 +24,7 @@ import os import sys import shutil +import subprocess import tempfile import unittest @@ -149,5 +150,11 @@ class Config(unittest.TestCase): self.assertFalse(failed) + +class UI(unittest.TestCase): + def test_banner(self): + self.assertEqual(subprocess.call([cdist_exec_path, "banner"]), 0) + + if __name__ == '__main__': unittest.main() From 3265755bb9197e54e66de791d24b7eff70c980e1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Sep 2011 09:15:04 +0200 Subject: [PATCH 0427/4212] test help function Signed-off-by: Nico Schottelius --- test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test.py b/test.py index 8fe759a6..d03ad0f1 100755 --- a/test.py +++ b/test.py @@ -34,6 +34,8 @@ sys.path.insert(0, os.path.abspath( cdist_exec_path = os.path.abspath( os.path.join(os.path.dirname(os.path.realpath(__file__)), "bin/cdist")) +cdist_commands=["banner", "config", "install"] + import cdist import cdist.config import cdist.exec @@ -155,6 +157,10 @@ class UI(unittest.TestCase): def test_banner(self): self.assertEqual(subprocess.call([cdist_exec_path, "banner"]), 0) + def test_help(self): + for cmd in cdist_commands: + self.assertEqual(subprocess.call([cdist_exec_path, cmd, "-h"]), 0) + if __name__ == '__main__': unittest.main() From f357eb3038c9d5eef63c506384011f1d0a7e0067 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Sep 2011 09:17:27 +0200 Subject: [PATCH 0428/4212] test config of localhost Signed-off-by: Nico Schottelius --- test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test.py b/test.py index d03ad0f1..5d57fae4 100755 --- a/test.py +++ b/test.py @@ -161,6 +161,11 @@ class UI(unittest.TestCase): for cmd in cdist_commands: self.assertEqual(subprocess.call([cdist_exec_path, cmd, "-h"]), 0) + # FIXME: mockup needed + def test_config_localhost(self): + for cmd in cdist_commands: + self.assertEqual(subprocess.call([cdist_exec_path, "config", "localhost"]), 0) + if __name__ == '__main__': unittest.main() From ab061770f4c4fa2b5fdde1fea46a73c156776278 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Sat, 1 Oct 2011 13:08:07 +0200 Subject: [PATCH 0429/4212] Installation with gentoo --- README | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README b/README index 28580c38..aab4c3a5 100644 --- a/README +++ b/README @@ -105,6 +105,16 @@ Archlinux already has python >= 3.2, so you only need to do: easy_install3 argparse +#### Gentoo + +Gentoo only provides python 3.2 in testing packages (http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=3&chap=3). +If you want to ensure nothing breaks you must set back the python version to what was default before. + + emerge -av =python-3.2.2 --autounmask-write + emerge -av =python-3.2.2 + eselect python list + eselect python list set python3.2 + ### Get cdist You can clone cdist from git, which gives you the advantage of having From 7d290a7755532a66618caa94093db1a040d90492 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 1 Oct 2011 16:34:25 +0200 Subject: [PATCH 0430/4212] begin to splitup test cases Signed-off-by: Nico Schottelius --- test.py | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/test.py b/test.py index 5d57fae4..1e0973c5 100755 --- a/test.py +++ b/test.py @@ -142,9 +142,7 @@ class Config(unittest.TestCase): manifest_fd.close() try: - print("a") self.config.run_initial_manifest() - print("b") except cdist.Error: failed = True else: @@ -166,6 +164,30 @@ class UI(unittest.TestCase): for cmd in cdist_commands: self.assertEqual(subprocess.call([cdist_exec_path, "config", "localhost"]), 0) - + +def almost_all_tests(): + suite = unittest.TestSuite([ + unittest.TestLoader().loadTestsFromTestCase(Config), + unittest.TestLoader().loadTestsFromTestCase(Exec)]) + + return suite + +def all_tests(): + suite = unittest.defaultTestLoader + return suite + if __name__ == '__main__': - unittest.main() + result = unittest.TestResult() + # only run some tests, when giving -a -> stuff that usually breaks + if len(sys.argv) >= 2: + if sys.argv[1] == "-a": + suite = all_tests(); + else: + sys.exit(1) + else: + suite = almost_all_tests(); + + # suite.run(result) + # unittest.main() + # unittest.TextTestRunner().run(suite) + From f3bedd8d93b56fc3c2c3aa29b6638ed441f972d9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 1 Oct 2011 17:25:12 +0200 Subject: [PATCH 0431/4212] move tests to test/ again, but seperate them now and add ./build.sh test Signed-off-by: Nico Schottelius --- build.sh | 4 ++ test/test_config.py | 101 ++++++++++++++++++++++++++++++++++++++++++++ test/test_exec.py | 80 +++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 test/test_config.py create mode 100755 test/test_exec.py diff --git a/build.sh b/build.sh index d20e0211..24c907e6 100755 --- a/build.sh +++ b/build.sh @@ -126,6 +126,10 @@ case "$1" in | xargs rm -f ;; + test) + python3 -m unittest discover test 'test_*.py' + ;; + *) echo '' echo 'Welcome to cdist!' diff --git a/test/test_config.py b/test/test_config.py new file mode 100644 index 00000000..0632ebcc --- /dev/null +++ b/test/test_config.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 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 sys +import tempfile +import unittest + +sys.path.insert(0, os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) + +import cdist.config + +cdist_exec_path = os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), "bin/cdist")) + + +class Config(unittest.TestCase): + def setUp(self): + self.temp_dir = tempfile.mkdtemp() + self.init_manifest = os.path.join(self.temp_dir, "manifest") + self.config = cdist.config.Config("localhost", + initial_manifest=self.init_manifest, + exec_path=cdist_exec_path) + self.config.link_emulator() + + def test_initial_manifest_different_parameter(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + " --mode 0700\n", + "__file " + self.temp_dir + " --mode 0600\n", + ]) + manifest_fd.close() + + self.assertRaises(cdist.Error, self.config.run_initial_manifest) + + def test_initial_manifest_parameter_added(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + '\n', + "__file " + self.temp_dir + " --mode 0600\n", + ]) + manifest_fd.close() + + self.assertRaises(cdist.Error, self.config.run_initial_manifest) + + def test_initial_manifest_parameter_removed(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + " --mode 0600\n", + "__file " + self.temp_dir + "\n", + ]) + manifest_fd.close() + + self.assertRaises(cdist.Error, self.config.run_initial_manifest) + + def test_initial_manifest_non_existent_command(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh\n", + "thereisdefinitelynosuchcommend"]) + manifest_fd.close() + + self.assertRaises(cdist.Error, self.config.run_initial_manifest) + + def test_initial_manifest_parameter_twice(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + " --mode 0600\n", + "__file " + self.temp_dir + " --mode 0600\n", + ]) + manifest_fd.close() + + try: + self.config.run_initial_manifest() + except cdist.Error: + failed = True + else: + failed = False + + self.assertFalse(failed) + + diff --git a/test/test_exec.py b/test/test_exec.py new file mode 100755 index 00000000..901b5efd --- /dev/null +++ b/test/test_exec.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 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 sys +import shutil +import subprocess +import tempfile +import unittest + +sys.path.insert(0, os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) + +import cdist.exec + +class Exec(unittest.TestCase): + def setUp(self): + """Create shell code and co.""" + + self.temp_dir = tempfile.mkdtemp() + self.shell_false = os.path.join(self.temp_dir, "shell_false") + self.shell_true = os.path.join(self.temp_dir, "shell_true") + + true_fd = open(self.shell_true, "w") + true_fd.writelines(["#!/bin/sh\n", "/bin/true"]) + true_fd.close() + + false_fd = open(self.shell_false, "w") + false_fd.writelines(["#!/bin/sh\n", "/bin/false"]) + false_fd.close() + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_local_success_shell(self): + try: + cdist.exec.shell_run_or_debug_fail(self.shell_true, [self.shell_true]) + except cdist.Error: + failed = True + else: + failed = False + + self.assertFalse(failed) + + def test_local_fail_shell(self): + self.assertRaises(cdist.Error, cdist.exec.shell_run_or_debug_fail, + self.shell_false, [self.shell_false]) + + def test_local_success(self): + try: + cdist.exec.run_or_fail(["/bin/true"]) + except cdist.Error: + failed = True + else: + failed = False + + self.assertFalse(failed) + + def test_local_fail(self): + self.assertRaises(cdist.Error, cdist.exec.run_or_fail, ["/bin/false"]) From 390342b324c0b7bca68bdcf381c37bac98c5c326 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Sat, 1 Oct 2011 14:02:45 +0200 Subject: [PATCH 0432/4212] Mac OS X Tutorial --- README | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README b/README index aab4c3a5..2c6465f2 100644 --- a/README +++ b/README @@ -115,6 +115,12 @@ If you want to ensure nothing breaks you must set back the python version to wha eselect python list eselect python list set python3.2 +#### Max OS X + +Ensure you have port installed and configured (http://www.macports.org/install.php). + + port install python32 + ### Get cdist You can clone cdist from git, which gives you the advantage of having From 6425f1d55c86d383464d64e177eb2d28ac544f41 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Sat, 1 Oct 2011 14:46:41 +0200 Subject: [PATCH 0433/4212] Finished Mac OS X installation --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index 2c6465f2..3dff690f 100644 --- a/README +++ b/README @@ -120,6 +120,7 @@ If you want to ensure nothing breaks you must set back the python version to wha Ensure you have port installed and configured (http://www.macports.org/install.php). port install python32 + ln -s /opt/local/bin/python3.2 /opt/local/bin/python3 ### Get cdist From df727a6b6bf52bd35c820480640ec651c3ede841 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 2 Oct 2011 15:52:19 +0200 Subject: [PATCH 0434/4212] remove everything but ui from ui test Signed-off-by: Nico Schottelius --- test.py | 193 ------------------------------------------------ test/nico_ui.py | 41 ++++++++++ 2 files changed, 41 insertions(+), 193 deletions(-) delete mode 100755 test.py create mode 100755 test/nico_ui.py diff --git a/test.py b/test.py deleted file mode 100755 index 1e0973c5..00000000 --- a/test.py +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 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 sys -import shutil -import subprocess -import tempfile -import unittest - -sys.path.insert(0, os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), 'lib'))) - -cdist_exec_path = os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "bin/cdist")) - -cdist_commands=["banner", "config", "install"] - -import cdist -import cdist.config -import cdist.exec - -class Exec(unittest.TestCase): - def setUp(self): - """Create shell code and co.""" - - self.temp_dir = tempfile.mkdtemp() - self.shell_false = os.path.join(self.temp_dir, "shell_false") - self.shell_true = os.path.join(self.temp_dir, "shell_true") - - true_fd = open(self.shell_true, "w") - true_fd.writelines(["#!/bin/sh\n", "/bin/true"]) - true_fd.close() - - false_fd = open(self.shell_false, "w") - false_fd.writelines(["#!/bin/sh\n", "/bin/false"]) - false_fd.close() - - def tearDown(self): - shutil.rmtree(self.temp_dir) - - def test_local_success_shell(self): - try: - cdist.exec.shell_run_or_debug_fail(self.shell_true, [self.shell_true]) - except cdist.Error: - failed = True - else: - failed = False - - self.assertFalse(failed) - - def test_local_fail_shell(self): - self.assertRaises(cdist.Error, cdist.exec.shell_run_or_debug_fail, - self.shell_false, [self.shell_false]) - - def test_local_success(self): - try: - cdist.exec.run_or_fail(["/bin/true"]) - except cdist.Error: - failed = True - else: - failed = False - - self.assertFalse(failed) - - def test_local_fail(self): - self.assertRaises(cdist.Error, cdist.exec.run_or_fail, ["/bin/false"]) - -class Config(unittest.TestCase): - def setUp(self): - self.temp_dir = tempfile.mkdtemp() - self.init_manifest = os.path.join(self.temp_dir, "manifest") - self.config = cdist.config.Config("localhost", - initial_manifest=self.init_manifest, - exec_path=cdist_exec_path) - self.config.link_emulator() - - def test_initial_manifest_different_parameter(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + " --mode 0700\n", - "__file " + self.temp_dir + " --mode 0600\n", - ]) - manifest_fd.close() - - self.assertRaises(cdist.Error, self.config.run_initial_manifest) - - def test_initial_manifest_parameter_added(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + '\n', - "__file " + self.temp_dir + " --mode 0600\n", - ]) - manifest_fd.close() - - self.assertRaises(cdist.Error, self.config.run_initial_manifest) - - def test_initial_manifest_parameter_removed(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + " --mode 0600\n", - "__file " + self.temp_dir + "\n", - ]) - manifest_fd.close() - - self.assertRaises(cdist.Error, self.config.run_initial_manifest) - - def test_initial_manifest_non_existent_command(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "thereisdefinitelynosuchcommend"]) - manifest_fd.close() - - self.assertRaises(cdist.Error, self.config.run_initial_manifest) - - def test_initial_manifest_parameter_twice(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + " --mode 0600\n", - "__file " + self.temp_dir + " --mode 0600\n", - ]) - manifest_fd.close() - - try: - self.config.run_initial_manifest() - except cdist.Error: - failed = True - else: - failed = False - - self.assertFalse(failed) - - -class UI(unittest.TestCase): - def test_banner(self): - self.assertEqual(subprocess.call([cdist_exec_path, "banner"]), 0) - - def test_help(self): - for cmd in cdist_commands: - self.assertEqual(subprocess.call([cdist_exec_path, cmd, "-h"]), 0) - - # FIXME: mockup needed - def test_config_localhost(self): - for cmd in cdist_commands: - self.assertEqual(subprocess.call([cdist_exec_path, "config", "localhost"]), 0) - - -def almost_all_tests(): - suite = unittest.TestSuite([ - unittest.TestLoader().loadTestsFromTestCase(Config), - unittest.TestLoader().loadTestsFromTestCase(Exec)]) - - return suite - -def all_tests(): - suite = unittest.defaultTestLoader - return suite - -if __name__ == '__main__': - result = unittest.TestResult() - # only run some tests, when giving -a -> stuff that usually breaks - if len(sys.argv) >= 2: - if sys.argv[1] == "-a": - suite = all_tests(); - else: - sys.exit(1) - else: - suite = almost_all_tests(); - - # suite.run(result) - # unittest.main() - # unittest.TextTestRunner().run(suite) - diff --git a/test/nico_ui.py b/test/nico_ui.py new file mode 100755 index 00000000..4e5b1a17 --- /dev/null +++ b/test/nico_ui.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 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 subprocess + +cdist_exec_path = os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), "bin/cdist")) + +class UI(unittest.TestCase): + def test_banner(self): + self.assertEqual(subprocess.call([cdist_exec_path, "banner"]), 0) + + def test_help(self): + for cmd in cdist_commands: + self.assertEqual(subprocess.call([cdist_exec_path, cmd, "-h"]), 0) + + # FIXME: mockup needed + def test_config_localhost(self): + for cmd in cdist_commands: + self.assertEqual(subprocess.call([cdist_exec_path, "config", "localhost"]), 0) + From cadb4fa852870f872fc65ea7e85680406eff20a5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 2 Oct 2011 15:56:27 +0200 Subject: [PATCH 0435/4212] add test all and make ui tests work again Signed-off-by: Nico Schottelius --- build.sh | 4 ++++ test/nico_ui.py | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 24c907e6..021fb480 100755 --- a/build.sh +++ b/build.sh @@ -130,6 +130,10 @@ case "$1" in python3 -m unittest discover test 'test_*.py' ;; + test-all) + python3 -m unittest discover test '*.py' + ;; + *) echo '' echo 'Welcome to cdist!' diff --git a/test/nico_ui.py b/test/nico_ui.py index 4e5b1a17..8ce98043 100755 --- a/test/nico_ui.py +++ b/test/nico_ui.py @@ -21,10 +21,14 @@ # +import os import subprocess +import unittest + +cdist_commands=["banner", "config", "install"] cdist_exec_path = os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "bin/cdist")) + os.path.join(os.path.dirname(os.path.realpath(__file__)), "../bin/cdist")) class UI(unittest.TestCase): def test_banner(self): From 5d256b21b1e844026426f4ab22207952ecf35b7f Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Sun, 2 Oct 2011 22:33:56 +0200 Subject: [PATCH 0436/4212] Initial init_script type --- conf/type/__init_script/gencode-remote | 30 ++++++++++++++++++++++ conf/type/__init_script/parameter/optional | 1 + conf/type/__init_script/parameter/required | 1 + 3 files changed, 32 insertions(+) create mode 100644 conf/type/__init_script/gencode-remote create mode 100644 conf/type/__init_script/parameter/optional create mode 100644 conf/type/__init_script/parameter/required diff --git a/conf/type/__init_script/gencode-remote b/conf/type/__init_script/gencode-remote new file mode 100644 index 00000000..d9e56970 --- /dev/null +++ b/conf/type/__init_script/gencode-remote @@ -0,0 +1,30 @@ +#!/bin/sh +# +# 2010-2011 Daniel Roth (dani-cdist@d-roth.li) +# +# 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/service" ]; then + service=$(cat "$__object/parameter/service") +else + service="/$__object_id" +fi + +mode=$(cat "$__object/parameter/mode") + +echo "/etc/init.d/${service} ${mode}" diff --git a/conf/type/__init_script/parameter/optional b/conf/type/__init_script/parameter/optional new file mode 100644 index 00000000..24e10984 --- /dev/null +++ b/conf/type/__init_script/parameter/optional @@ -0,0 +1 @@ +service diff --git a/conf/type/__init_script/parameter/required b/conf/type/__init_script/parameter/required new file mode 100644 index 00000000..17ab372f --- /dev/null +++ b/conf/type/__init_script/parameter/required @@ -0,0 +1 @@ +mode From 5f1afb08f6387111a754fef0bbdc1e7abe093257 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Mon, 3 Oct 2011 17:33:19 +0200 Subject: [PATCH 0437/4212] man page --- conf/type/__init_script/man.text | 49 ++++++++++++++++++++++ conf/type/__init_script/parameter/optional | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 conf/type/__init_script/man.text diff --git a/conf/type/__init_script/man.text b/conf/type/__init_script/man.text new file mode 100644 index 00000000..34065260 --- /dev/null +++ b/conf/type/__init_script/man.text @@ -0,0 +1,49 @@ +cdist-type__init_script(7) +============================== +Daniel Roth + + +NAME +---- +cdist-type__init_script - Use the init scripts + + +DESCRIPTION +----------- +This type can be used to control your init scripts. + + +REQUIRED PARAMETERS +------------------- +mode:: + Specifies what shall be done with the init script (usually one of 'start'|'stop'|'restart'|'reload' or 'force-reload') + + +OPTIONAL PARAMETERS +------------------- +script:: + If supplied, use this as the init-script. + Otherwise the object_id is used. The script will be pretended with '/etc/init.d/' + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Reloads the configuration for lighttpd +__init_script lighttpd --mode force-reload + +# Reloads the configuration for lighttpd +__init_script lighty --script lighttpd --mode force-reload +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011 Daniel Roth. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__init_script/parameter/optional b/conf/type/__init_script/parameter/optional index 24e10984..84f7e31d 100644 --- a/conf/type/__init_script/parameter/optional +++ b/conf/type/__init_script/parameter/optional @@ -1 +1 @@ -service +script From 342cbca533a5da451555769d55cd83b7cb0959c1 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Mon, 3 Oct 2011 18:00:07 +0200 Subject: [PATCH 0438/4212] additional parameter base_dir --- conf/type/__init_script/gencode-remote | 16 ++++++++++++---- conf/type/__init_script/man.text | 4 +++- conf/type/__init_script/parameter/optional | 1 + 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/conf/type/__init_script/gencode-remote b/conf/type/__init_script/gencode-remote index d9e56970..9b493cfc 100644 --- a/conf/type/__init_script/gencode-remote +++ b/conf/type/__init_script/gencode-remote @@ -19,12 +19,20 @@ # # -if [ -f "$__object/parameter/service" ]; then - service=$(cat "$__object/parameter/service") +if [ -f "$__object/parameter/script" ]; then + script=$(cat "$__object/parameter/script") else - service="/$__object_id" + script="/$__object_id" fi +if [ -f "$__object/parameter/base_dir" ]; then + base_dir=$(cat "$__object/parameter/base_dir") +else + base_dir="/etc/init.d" +fi + + + mode=$(cat "$__object/parameter/mode") -echo "/etc/init.d/${service} ${mode}" +echo "${base_dir}/${script} ${mode}" diff --git a/conf/type/__init_script/man.text b/conf/type/__init_script/man.text index 34065260..898943a5 100644 --- a/conf/type/__init_script/man.text +++ b/conf/type/__init_script/man.text @@ -23,8 +23,10 @@ OPTIONAL PARAMETERS ------------------- script:: If supplied, use this as the init-script. - Otherwise the object_id is used. The script will be pretended with '/etc/init.d/' + Otherwise the object_id is used. +base_dir:: + If supplied, this type uses this directory instead of '/etc/init.d'. The parameter will not need an ending slash. EXAMPLES -------- diff --git a/conf/type/__init_script/parameter/optional b/conf/type/__init_script/parameter/optional index 84f7e31d..5551a8f2 100644 --- a/conf/type/__init_script/parameter/optional +++ b/conf/type/__init_script/parameter/optional @@ -1 +1,2 @@ script +base_dir From 2147480fcd418c21b3a539e622d9ad46641f6a6f Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Mon, 3 Oct 2011 18:35:45 +0200 Subject: [PATCH 0439/4212] base_dir is /etc/rc.d for archlinux /etc/init.d otherwise --- conf/type/__init_script/gencode-remote | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/conf/type/__init_script/gencode-remote b/conf/type/__init_script/gencode-remote index 9b493cfc..ff823cad 100644 --- a/conf/type/__init_script/gencode-remote +++ b/conf/type/__init_script/gencode-remote @@ -28,11 +28,13 @@ fi if [ -f "$__object/parameter/base_dir" ]; then base_dir=$(cat "$__object/parameter/base_dir") else - base_dir="/etc/init.d" + os="$(cat "$__global/explorer/os")" + case "$os" in + archlinux) base_dir="/etc/rc.d" ;; + *) base_dir="/etc/init.d" + esac fi - - mode=$(cat "$__object/parameter/mode") echo "${base_dir}/${script} ${mode}" From 40d5b9cb05f93a8fc770fd595aadc8d9cd0ce40c Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Mon, 3 Oct 2011 21:39:07 +0200 Subject: [PATCH 0440/4212] bsd init location --- conf/type/__init_script/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__init_script/gencode-remote b/conf/type/__init_script/gencode-remote index ff823cad..d212feb7 100644 --- a/conf/type/__init_script/gencode-remote +++ b/conf/type/__init_script/gencode-remote @@ -30,7 +30,7 @@ if [ -f "$__object/parameter/base_dir" ]; then else os="$(cat "$__global/explorer/os")" case "$os" in - archlinux) base_dir="/etc/rc.d" ;; + archlinux|netbsd|macosx|freebsd|openbsd) base_dir="/etc/rc.d" ;; *) base_dir="/etc/init.d" esac fi From d3923c7b0f06a3cf11b9adb0a1ffc1ffa9a4cdb3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 14:15:30 +0200 Subject: [PATCH 0441/4212] add template for install tests Signed-off-by: Nico Schottelius --- test/test_install.py | 101 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 test/test_install.py diff --git a/test/test_install.py b/test/test_install.py new file mode 100644 index 00000000..21e8ca06 --- /dev/null +++ b/test/test_install.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 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 sys +import tempfile +import unittest + +sys.path.insert(0, os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) + +import cdist.config + +cdist_exec_path = os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), "bin/cdist")) + + +class Install(unittest.TestCase): + def setUp(self): + self.temp_dir = tempfile.mkdtemp() + self.init_manifest = os.path.join(self.temp_dir, "manifest") + self.config = cdist.config.Config("localhost", + initial_manifest=self.init_manifest, + exec_path=cdist_exec_path) + self.config.link_emulator() + + def test_initial_manifest_different_parameter(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + " --mode 0700\n", + "__file " + self.temp_dir + " --mode 0600\n", + ]) + manifest_fd.close() + + self.assertRaises(cdist.Error, self.config.run_initial_manifest) + + def test_initial_manifest_parameter_added(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + '\n', + "__file " + self.temp_dir + " --mode 0600\n", + ]) + manifest_fd.close() + + self.assertRaises(cdist.Error, self.config.run_initial_manifest) + + def test_initial_manifest_parameter_removed(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + " --mode 0600\n", + "__file " + self.temp_dir + "\n", + ]) + manifest_fd.close() + + self.assertRaises(cdist.Error, self.config.run_initial_manifest) + + def test_initial_manifest_non_existent_command(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh\n", + "thereisdefinitelynosuchcommend"]) + manifest_fd.close() + + self.assertRaises(cdist.Error, self.config.run_initial_manifest) + + def test_initial_manifest_parameter_twice(self): + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + " --mode 0600\n", + "__file " + self.temp_dir + " --mode 0600\n", + ]) + manifest_fd.close() + + try: + self.config.run_initial_manifest() + except cdist.Error: + failed = True + else: + failed = False + + self.assertFalse(failed) + + From 2d567c175926fa40b427b3cbb9eaeaa00ff8b9da Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 14:18:39 +0200 Subject: [PATCH 0442/4212] prepare cleanup of tests for later Signed-off-by: Nico Schottelius --- build.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.sh b/build.sh index 021fb480..c6906357 100755 --- a/build.sh +++ b/build.sh @@ -41,6 +41,9 @@ MAN1DSTDIR=${MANDIR}/man1 MAN7DSTDIR=${MANDIR}/man7 SPEECHESDIR=doc/speeches +# FIXME: make lib for tests! +# PYTHONPATH=$PYTHONPATH:$(pwd -P)/test/lib + case "$1" in man) set -e From ffb533eae8b881ac7b67781453d60baaa1916649 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 14:18:43 +0200 Subject: [PATCH 0443/4212] -exec Signed-off-by: Nico Schottelius --- test/nico_ui.py | 0 test/test_exec.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 test/nico_ui.py mode change 100755 => 100644 test/test_exec.py diff --git a/test/nico_ui.py b/test/nico_ui.py old mode 100755 new mode 100644 diff --git a/test/test_exec.py b/test/test_exec.py old mode 100755 new mode 100644 From db322c0b5e52849c99226bec383978f3fbab2a65 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 14:29:33 +0200 Subject: [PATCH 0444/4212] integrate tests into library Signed-off-by: Nico Schottelius --- lib/cdist/test/__init__.py | 0 {test => lib/cdist/test}/nico_ui.py | 0 {test => lib/cdist/test}/test_config.py | 0 {test => lib/cdist/test}/test_exec.py | 0 {test => lib/cdist/test}/test_install.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/cdist/test/__init__.py rename {test => lib/cdist/test}/nico_ui.py (100%) rename {test => lib/cdist/test}/test_config.py (100%) rename {test => lib/cdist/test}/test_exec.py (100%) rename {test => lib/cdist/test}/test_install.py (100%) diff --git a/lib/cdist/test/__init__.py b/lib/cdist/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/nico_ui.py b/lib/cdist/test/nico_ui.py similarity index 100% rename from test/nico_ui.py rename to lib/cdist/test/nico_ui.py diff --git a/test/test_config.py b/lib/cdist/test/test_config.py similarity index 100% rename from test/test_config.py rename to lib/cdist/test/test_config.py diff --git a/test/test_exec.py b/lib/cdist/test/test_exec.py similarity index 100% rename from test/test_exec.py rename to lib/cdist/test/test_exec.py diff --git a/test/test_install.py b/lib/cdist/test/test_install.py similarity index 100% rename from test/test_install.py rename to lib/cdist/test/test_install.py From f5a58f768371be278dd66760c87b43127c5acb6f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 14:30:38 +0200 Subject: [PATCH 0445/4212] adjust auto discovery Signed-off-by: Nico Schottelius --- build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index c6906357..39192c78 100755 --- a/build.sh +++ b/build.sh @@ -130,11 +130,11 @@ case "$1" in ;; test) - python3 -m unittest discover test 'test_*.py' + python3 -m unittest discover lib/cdist/test 'test_*.py' ;; test-all) - python3 -m unittest discover test '*.py' + python3 -m unittest discover lib/cdist/test '*.py' ;; *) From 13ed37a4e954d60e27199bfc981d7b795fb36302 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 14:45:35 +0200 Subject: [PATCH 0446/4212] begin to test explorer success in test_install Signed-off-by: Nico Schottelius --- build.sh | 8 +++++--- lib/cdist/test/test_install.py | 12 ++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/build.sh b/build.sh index 39192c78..01094e12 100755 --- a/build.sh +++ b/build.sh @@ -41,9 +41,6 @@ MAN1DSTDIR=${MANDIR}/man1 MAN7DSTDIR=${MANDIR}/man7 SPEECHESDIR=doc/speeches -# FIXME: make lib for tests! -# PYTHONPATH=$PYTHONPATH:$(pwd -P)/test/lib - case "$1" in man) set -e @@ -133,6 +130,11 @@ case "$1" in python3 -m unittest discover lib/cdist/test 'test_*.py' ;; + test-install) + PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib \ + python3 -m unittest cdist.test.test_install + ;; + test-all) python3 -m unittest discover lib/cdist/test '*.py' ;; diff --git a/lib/cdist/test/test_install.py b/lib/cdist/test/test_install.py index 21e8ca06..f5956585 100644 --- a/lib/cdist/test/test_install.py +++ b/lib/cdist/test/test_install.py @@ -43,6 +43,18 @@ class Install(unittest.TestCase): exec_path=cdist_exec_path) self.config.link_emulator() +### NEW FOR INSTALL ############################################################ + + def test_explorer_ran(self): + """Check that all explorers returned a result""" + self.config.run_global_explores() + explorers = self.config.path.list_global_explorers() + + for explorer in explorers: + output = self.path.global_explorer_output_path(explorer) + self.assertTrue(os.path.isfile(output)) + +### OLD FROM CONFIG ############################################################ def test_initial_manifest_different_parameter(self): manifest_fd = open(self.init_manifest, "w") manifest_fd.writelines(["#!/bin/sh\n", From 5940c21fba007f9f8fad0650d696ed2056a57f8e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Oct 2011 14:56:59 +0200 Subject: [PATCH 0447/4212] get rid of bashism /echo -n/printf/ Signed-off-by: Steven Armstrong --- conf/type/__partition_msdos_apply/files/lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__partition_msdos_apply/files/lib.sh b/conf/type/__partition_msdos_apply/files/lib.sh index e24c1cb7..01a817a8 100644 --- a/conf/type/__partition_msdos_apply/files/lib.sh +++ b/conf/type/__partition_msdos_apply/files/lib.sh @@ -11,7 +11,7 @@ fdisk_command() { local cmd="$2" debug fdisk_command "running fdisk command '${cmd}' on device ${device}" - echo -en "${cmd}\nw\n" | fdisk -c -u "$device" + printf "${cmd}\nw\n" | fdisk -c -u "$device" return $? } From 410a2fe7ff1f56dc54420c921fff6390af357e62 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 15:08:37 +0200 Subject: [PATCH 0448/4212] test_explorer_ran finished Signed-off-by: Nico Schottelius --- lib/cdist/test/test_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/test/test_install.py b/lib/cdist/test/test_install.py index f5956585..3289ea47 100644 --- a/lib/cdist/test/test_install.py +++ b/lib/cdist/test/test_install.py @@ -51,7 +51,7 @@ class Install(unittest.TestCase): explorers = self.config.path.list_global_explorers() for explorer in explorers: - output = self.path.global_explorer_output_path(explorer) + output = self.config.path.global_explorer_output_path(explorer) self.assertTrue(os.path.isfile(output)) ### OLD FROM CONFIG ############################################################ From ec82fa8f972b13cec907d8fff4560ff2fa3201ad Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 15:09:33 +0200 Subject: [PATCH 0449/4212] document tests/single ones Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-04 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 doc/dev/logs/2011-10-04 diff --git a/doc/dev/logs/2011-10-04 b/doc/dev/logs/2011-10-04 new file mode 100644 index 00000000..f3bb852d --- /dev/null +++ b/doc/dev/logs/2011-10-04 @@ -0,0 +1,3 @@ +Testing for single tests: + PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib python3 -m unittest cdist.test.test_install.Install.test_explorer_ran + From 32832777c6778a881b9389e3e3b325c101b4a131 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Oct 2011 15:24:19 +0200 Subject: [PATCH 0450/4212] give disk some time to write parition table Signed-off-by: Steven Armstrong --- conf/type/__partition_msdos_apply/files/lib.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/type/__partition_msdos_apply/files/lib.sh b/conf/type/__partition_msdos_apply/files/lib.sh index 01a817a8..f0859aab 100644 --- a/conf/type/__partition_msdos_apply/files/lib.sh +++ b/conf/type/__partition_msdos_apply/files/lib.sh @@ -12,6 +12,8 @@ fdisk_command() { debug fdisk_command "running fdisk command '${cmd}' on device ${device}" printf "${cmd}\nw\n" | fdisk -c -u "$device" + # give disk some time + sleep 1 return $? } From 3d75ec9bfcde3b3f057d1d7c4061c1e553c3e681 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 15:49:18 +0200 Subject: [PATCH 0451/4212] make test suite usable from command line Signed-off-by: Nico Schottelius --- lib/cdist/test/__main__.py | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 lib/cdist/test/__main__.py diff --git a/lib/cdist/test/__main__.py b/lib/cdist/test/__main__.py new file mode 100644 index 00000000..03bca847 --- /dev/null +++ b/lib/cdist/test/__main__.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 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 sys +import cdist.test + +#class UI(unittest.TestCase): +# def test_banner(self): +# self.assertEqual(subprocess.call([cdist_exec_path, "banner"]), 0) +# +# def test_help(self): +# for cmd in cdist_commands: +# self.assertEqual(subprocess.call([cdist_exec_path, cmd, "-h"]), 0) +# +# # FIXME: mockup needed +# def test_config_localhost(self): +# for cmd in cdist_commands: +# self.assertEqual(subprocess.call([cdist_exec_path, "config", "localhost"]), 0) + +print(cdist.test.cdist_exec_path) +print(sys.argv) From 40a1619c1ad6731666a6c3303e4550958e43ef45 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 16:15:10 +0200 Subject: [PATCH 0452/4212] make build test work (or fail, but work) again Signed-off-by: Nico Schottelius --- build.sh | 6 +++-- lib/cdist/test/__init__.py | 47 ++++++++++++++++++++++++++++++++++++++ lib/cdist/test/__main__.py | 5 ++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index 01094e12..6a91ff3d 100755 --- a/build.sh +++ b/build.sh @@ -127,7 +127,8 @@ case "$1" in ;; test) - python3 -m unittest discover lib/cdist/test 'test_*.py' + PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib \ + python3 -m cdist.test ;; test-install) @@ -136,7 +137,8 @@ case "$1" in ;; test-all) - python3 -m unittest discover lib/cdist/test '*.py' + PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib \ + python3 -m unittest discover lib/cdist/test '*.py' ;; *) diff --git a/lib/cdist/test/__init__.py b/lib/cdist/test/__init__.py index e69de29b..f614fa05 100644 --- a/lib/cdist/test/__init__.py +++ b/lib/cdist/test/__init__.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 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 subprocess +import unittest + +cdist_commands=["banner", "config", "install"] + +cdist_exec_path = os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../bin/cdist")) + +def exec(): + print(cdist_exec_path) + +#class UI(unittest.TestCase): +# def test_banner(self): +# self.assertEqual(subprocess.call([cdist_exec_path, "banner"]), 0) +# +# def test_help(self): +# for cmd in cdist_commands: +# self.assertEqual(subprocess.call([cdist_exec_path, cmd, "-h"]), 0) +# +# # FIXME: mockup needed +# def test_config_localhost(self): +# for cmd in cdist_commands: +# self.assertEqual(subprocess.call([cdist_exec_path, "config", "localhost"]), 0) diff --git a/lib/cdist/test/__main__.py b/lib/cdist/test/__main__.py index 03bca847..3b31a2cd 100644 --- a/lib/cdist/test/__main__.py +++ b/lib/cdist/test/__main__.py @@ -21,8 +21,10 @@ # +import os import sys import cdist.test +import unittest #class UI(unittest.TestCase): # def test_banner(self): @@ -39,3 +41,6 @@ import cdist.test print(cdist.test.cdist_exec_path) print(sys.argv) + +suite = unittest.defaultTestLoader.discover(os.path.dirname(__file__)) +unittest.TextTestRunner(verbosity=1).run(suite) From 6c22867fc253096f8134960fbb0b4c68f05dd44b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 16:32:43 +0200 Subject: [PATCH 0453/4212] begin to test path and add method to check type Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 6 +++ lib/cdist/test/test_install.py | 16 ++++++++ lib/cdist/test/test_path.py | 71 ++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 lib/cdist/test/test_path.py diff --git a/lib/cdist/path.py b/lib/cdist/path.py index e416c42d..2dd9dcf1 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -175,8 +175,14 @@ class Path: return list def list_types(self): + """Retuns list of types""" return os.listdir(self.type_base_dir) + def is_install_type(self, type): + """Check whether a type is used for installation (if not: for configuration)""" + marker = os.path.join(self.type_dir(type), "install") + return os.path.isfile(marker) + def list_object_paths(self, starting_point): """Return list of paths of existing objects""" object_paths = [] diff --git a/lib/cdist/test/test_install.py b/lib/cdist/test/test_install.py index 3289ea47..9cfae066 100644 --- a/lib/cdist/test/test_install.py +++ b/lib/cdist/test/test_install.py @@ -54,6 +54,22 @@ class Install(unittest.TestCase): output = self.config.path.global_explorer_output_path(explorer) self.assertTrue(os.path.isfile(output)) + def test_manifest_uses_install_types_only(self): + """Check that objects created from manifest are only of install type""" + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + " --mode 0700\n", + "__partition_msdos /dev/null --type 82\n", + ]) + manifest_fd.close() + + self.config.run_initial_manifest() + + # FIXME: check that only __partition_msdos objects are created! + + self.assertFalse(failed) + + ### OLD FROM CONFIG ############################################################ def test_initial_manifest_different_parameter(self): manifest_fd = open(self.init_manifest, "w") diff --git a/lib/cdist/test/test_path.py b/lib/cdist/test/test_path.py new file mode 100644 index 00000000..04a107b8 --- /dev/null +++ b/lib/cdist/test/test_path.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 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 sys +import tempfile +import unittest + +import cdist.path +import cdist.test + +class Path(unittest.TestCase): + def setUp(self): + self.temp_dir = tempfile.mkdtemp() + self.init_manifest = os.path.join(self.temp_dir, "manifest") + self.path = cdist.config.Path("localhost", "root", + "ssh root@localhost", + initial_manifest=self.init_manifest, + base_dir=self.temp_dir) + + def tearDown(self): + self.path.cleanup() + + def test_type_detection(self): + """Check that a type is identified as install or configuration correctly""" + + # Create install type + install_type = os.path.join( + os.mkdir( + # Create non-install type + + self.config.run_global_explores() + explorers = self.config.path.list_global_explorers() + + for explorer in explorers: + output = self.config.path.global_explorer_output_path(explorer) + self.assertTrue(os.path.isfile(output)) + + def test_manifest_uses_install_types_only(self): + """Check that objects created from manifest are only of install type""" + manifest_fd = open(self.init_manifest, "w") + manifest_fd.writelines(["#!/bin/sh\n", + "__file " + self.temp_dir + " --mode 0700\n", + "__partition_msdos /dev/null --type 82\n", + ]) + manifest_fd.close() + + self.config.run_initial_manifest() + + # FIXME: check that only __partition_msdos objects are created! + + self.assertFalse(failed) From 919f251759958403e097150e460f31a708d95ee2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Oct 2011 16:33:58 +0200 Subject: [PATCH 0454/4212] ++examples Signed-off-by: Steven Armstrong --- conf/type/__partition_msdos/man.text | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/conf/type/__partition_msdos/man.text b/conf/type/__partition_msdos/man.text index c9ef0cf1..78220ee0 100644 --- a/conf/type/__partition_msdos/man.text +++ b/conf/type/__partition_msdos/man.text @@ -36,20 +36,18 @@ EXAMPLES -------- -------------------------------------------------------------------------------- -# 128MB linux, bootable +# 128MB, linux, bootable __partition_msdos /dev/sda1 --type 83 --size 128M --bootable true -# 512MB swap +# 512MB, swap __partition_msdos /dev/sda2 --type 82 --size 512M -# extended +# 100GB, extended __partition_msdos /dev/sda3 --type extended --size 100G # 10GB, linux __partition_msdos /dev/sda5 --type 83 --size 10G -# 50% of free space, linux +# 50% of the free space of the extended partition, linux __partition_msdos /dev/sda6 --type 83 --size 50% -# rest of disk, linux +# rest of the extended partition, linux __partition_msdos /dev/sda7 --type 83 --size + -# same thing as -__partition_msdos /dev/sda7 --type 83 -------------------------------------------------------------------------------- From 60fab053f2a08d0aeda0a780aecdc22e0fdd5f12 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 16:36:33 +0200 Subject: [PATCH 0455/4212] ++changes for 2.0.3 Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 9fb11307..632ddb45 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,5 +1,6 @@ 2.0.3: * Improved logging, added --verbose, by more quiet by default + * Bugfix __user: Correct quoting (Steven Armstrong) 2.0.2: 2011-09-27 * Add support for detection of OpenWall Linux (Matthias Teege) From 1d2ec72396498731e693f809e08104ca90240ad3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 16:43:13 +0200 Subject: [PATCH 0456/4212] add paragraph to cdist-hacker that states manpages always need to build on merge request Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-hacker.text | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/man/man7/cdist-hacker.text b/doc/man/man7/cdist-hacker.text index b9f79d01..f8e3730e 100644 --- a/doc/man/man7/cdist-hacker.text +++ b/doc/man/man7/cdist-hacker.text @@ -46,9 +46,8 @@ work nor kill the authors brain: private branch! - Code to be included should be branched of the upstream "master" branch - Exception: Bugfixes to a version branch -- Code submissions should be in your master branch - - Other branches are fine as well, but you need to tell me which branch - your work is in! +- On a merge request, always name the branch I should pull from +- Always ensure **all** manpages build: ./build.sh man - If you developed more than **one** feature, consider submitting them in seperate branches. This way one feature can already be included, even if the other needs to be improved. From 8dd248cf7664c2cc428c7639b26b102a20e6cbea Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 17:01:11 +0200 Subject: [PATCH 0457/4212] cleanup on exit and begin to create test types Signed-off-by: Nico Schottelius --- lib/cdist/test/test_path.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/cdist/test/test_path.py b/lib/cdist/test/test_path.py index 04a107b8..1fd955e3 100644 --- a/lib/cdist/test/test_path.py +++ b/lib/cdist/test/test_path.py @@ -21,6 +21,7 @@ # import os +import shutil import sys import tempfile import unittest @@ -32,28 +33,29 @@ class Path(unittest.TestCase): def setUp(self): self.temp_dir = tempfile.mkdtemp() self.init_manifest = os.path.join(self.temp_dir, "manifest") - self.path = cdist.config.Path("localhost", "root", - "ssh root@localhost", + self.path = cdist.path.Path("localhost", "root", "ssh root@localhost", initial_manifest=self.init_manifest, base_dir=self.temp_dir) + os.mkdir(self.path.conf_dir) + os.mkdir(self.path.type_base_dir) + + # Create install type + self.install_type = os.path.join(self.path.type_base_dir, "__install_test") + os.mkdir(self.install_type) + open(os.path.join(self.install_type, "install"), "w").close() + + # Create config type + config_type = os.path.join(self.path.type_base_dir, "__config_test") + os.mkdir(config_type) + def tearDown(self): self.path.cleanup() + shutil.rmtree(self.temp_dir) def test_type_detection(self): """Check that a type is identified as install or configuration correctly""" - # Create install type - install_type = os.path.join( - os.mkdir( - # Create non-install type - - self.config.run_global_explores() - explorers = self.config.path.list_global_explorers() - - for explorer in explorers: - output = self.config.path.global_explorer_output_path(explorer) - self.assertTrue(os.path.isfile(output)) def test_manifest_uses_install_types_only(self): """Check that objects created from manifest are only of install type""" From f88cb78d61bd803b183aab450075e0b1bdee8304 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 18:36:43 +0200 Subject: [PATCH 0458/4212] finish test_path.test_type_detection Signed-off-by: Nico Schottelius --- lib/cdist/test/test_path.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/cdist/test/test_path.py b/lib/cdist/test/test_path.py index 1fd955e3..c8ca95c0 100644 --- a/lib/cdist/test/test_path.py +++ b/lib/cdist/test/test_path.py @@ -40,14 +40,17 @@ class Path(unittest.TestCase): os.mkdir(self.path.conf_dir) os.mkdir(self.path.type_base_dir) + self.install_type_name = "__install_test" + self.config_type_name = "__config_test" + # Create install type - self.install_type = os.path.join(self.path.type_base_dir, "__install_test") + self.install_type = os.path.join(self.path.type_base_dir, self.install_type_name) os.mkdir(self.install_type) open(os.path.join(self.install_type, "install"), "w").close() # Create config type - config_type = os.path.join(self.path.type_base_dir, "__config_test") - os.mkdir(config_type) + self.config_type = os.path.join(self.path.type_base_dir, self.config_type_name) + os.mkdir(self.config_type) def tearDown(self): self.path.cleanup() @@ -55,7 +58,9 @@ class Path(unittest.TestCase): def test_type_detection(self): """Check that a type is identified as install or configuration correctly""" - + + self.assertTrue(self.path.is_install_type(self.install_type)) + self.assertFalse(self.path.is_install_type(self.config_type)) def test_manifest_uses_install_types_only(self): """Check that objects created from manifest are only of install type""" From b3f914f6f6fa2ef0ce390622d5b5cb4438000270 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 4 Oct 2011 18:45:29 +0200 Subject: [PATCH 0459/4212] create base module for install and config Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 268 +-------------------------------- lib/cdist/config_install.py | 292 ++++++++++++++++++++++++++++++++++++ 2 files changed, 295 insertions(+), 265 deletions(-) create mode 100644 lib/cdist/config_install.py diff --git a/lib/cdist/config.py b/lib/cdist/config.py index 51615c28..fcc9ed7e 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -22,274 +22,12 @@ import datetime import logging -import os -import stat -import sys - log = logging.getLogger(__name__) -import cdist.emulator -import cdist.path +import cdist.config_install -CODE_HEADER = "#!/bin/sh -e\n" - -class Config: - """Cdist main class to hold arbitrary data""" - - def __init__(self, target_host, - initial_manifest=False, - remote_user="root", - home=None, - exec_path=sys.argv[0], - debug=False): - - self.target_host = target_host - self.debug = debug - self.remote_user = remote_user - self.exec_path = exec_path - - # FIXME: broken - construct elsewhere! - self.remote_prefix = ["ssh", self.remote_user + "@" + self.target_host] - - self.path = cdist.path.Path(self.target_host, - initial_manifest=initial_manifest, - remote_user=self.remote_user, - remote_prefix=self.remote_prefix, - base_dir=home, - debug=debug) - - self.objects_prepared = [] - - def cleanup(self): - self.path.cleanup() - - def run_global_explores(self): - """Run global explorers""" - log.info("Running global explorers") - explorers = self.path.list_global_explorers() - if(len(explorers) == 0): - raise CdistError("No explorers found in", self.path.global_explorer_dir) - - self.path.transfer_global_explorers() - for explorer in explorers: - output = self.path.global_explorer_output_path(explorer) - output_fd = open(output, mode='w') - cmd = [] - cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append(self.path.remote_global_explorer_path(explorer)) - - cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=self.remote_prefix) - output_fd.close() - - def run_type_explorer(self, cdist_object): - """Run type specific explorers for objects""" - - type = self.path.get_type_from_object(cdist_object) - self.path.transfer_type_explorers(type) - - cmd = [] - cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append("__type_explorer=" + self.path.remote_type_explorer_dir(type)) - cmd.append("__object=" + self.path.remote_object_dir(cdist_object)) - cmd.append("__object_id=" + self.path.get_object_id_from_object(cdist_object)) - cmd.append("__object_fq=" + cdist_object) - - # Need to transfer at least the parameters for objects to be useful - self.path.transfer_object_parameter(cdist_object) - - explorers = self.path.list_type_explorers(type) - for explorer in explorers: - remote_cmd = cmd + [os.path.join(self.path.remote_type_explorer_dir(type), explorer)] - output = os.path.join(self.path.type_explorer_output_dir(cdist_object), explorer) - output_fd = open(output, mode='w') - log.debug("%s exploring %s using %s storing to %s", - cdist_object, explorer, remote_cmd, output) - - cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=self.remote_prefix) - output_fd.close() - - def link_emulator(self): - """Link emulator to types""" - cdist.emulator.link(self.exec_path, - self.path.bin_dir, self.path.list_types()) - - def init_deploy(self): - """Ensure the base directories are cleaned up""" - log.debug("Creating clean directory structure") - - self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) - self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) - self.link_emulator() - - def run_initial_manifest(self): - """Run the initial manifest""" - log.info("Running initial manifest %s", self.path.initial_manifest) - env = { "__manifest" : self.path.manifest_dir } - self.run_manifest(self.path.initial_manifest, extra_env=env) - - def run_type_manifest(self, cdist_object): - """Run manifest for a specific object""" - type = self.path.get_type_from_object(cdist_object) - manifest = self.path.type_dir(type, "manifest") - - log.debug("%s: Running %s", cdist_object, manifest) - if os.path.exists(manifest): - env = { "__object" : self.path.object_dir(cdist_object), - "__object_id": self.path.get_object_id_from_object(cdist_object), - "__object_fq": cdist_object, - "__type": self.path.type_dir(type) - } - self.run_manifest(manifest, extra_env=env) - - def run_manifest(self, manifest, extra_env=None): - """Run a manifest""" - log.debug("Running manifest %s, env=%s", manifest, extra_env) - env = os.environ.copy() - env['PATH'] = self.path.bin_dir + ":" + env['PATH'] - - # Information required in every manifest - env['__target_host'] = self.target_host - env['__global'] = self.path.out_dir - - # Submit debug flag to manifest, can be used by emulator and types - if self.debug: - env['__debug'] = "yes" - - # Required for recording source - env['__cdist_manifest'] = manifest - - # Required to find types - env['__cdist_type_base_dir'] = self.path.type_base_dir - - # Other environment stuff - if extra_env: - env.update(extra_env) - - cdist.exec.shell_run_or_debug_fail(manifest, [manifest], env=env) - - def object_run(self, cdist_object, mode): - """Run gencode or code for an object""" - log.debug("Running %s from %s", mode, cdist_object) - file=os.path.join(self.path.object_dir(cdist_object), "require") - requirements = cdist.path.file_to_list(file) - type = self.path.get_type_from_object(cdist_object) - - for requirement in requirements: - log.debug("Object %s requires %s", cdist_object, requirement) - self.object_run(requirement, mode=mode) - - # - # Setup env Variable: - # - env = os.environ.copy() - env['__target_host'] = self.target_host - env['__global'] = self.path.out_dir - env["__object"] = self.path.object_dir(cdist_object) - env["__object_id"] = self.path.get_object_id_from_object(cdist_object) - env["__object_fq"] = cdist_object - env["__type"] = self.path.type_dir(type) - - if mode == "gencode": - paths = [ - self.path.type_dir(type, "gencode-local"), - self.path.type_dir(type, "gencode-remote") - ] - for bin in paths: - if os.path.isfile(bin): - # omit "gen" from gencode and use it for output base - outfile=os.path.join(self.path.object_dir(cdist_object), - os.path.basename(bin)[3:]) - - outfile_fd = open(outfile, "w") - - # Need to flush to ensure our write is done before stdout write - outfile_fd.write(CODE_HEADER) - outfile_fd.flush() - - cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) - outfile_fd.close() - - status = os.stat(outfile) - - # Remove output if empty, else make it executable - if status.st_size == len(CODE_HEADER): - os.unlink(outfile) - else: - # Add header and make executable - identically to 0o700 - os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) - - # Mark object as changed - open(os.path.join(self.path.object_dir(cdist_object), "changed"), "w").close() - - - if mode == "code": - local_dir = self.path.object_dir(cdist_object) - remote_dir = self.path.remote_object_dir(cdist_object) - - bin = os.path.join(local_dir, "code-local") - if os.path.isfile(bin): - cdist.exec.run_or_fail([bin]) - - - local_remote_code = os.path.join(local_dir, "code-remote") - remote_remote_code = os.path.join(remote_dir, "code-remote") - if os.path.isfile(local_remote_code): - self.path.transfer_file(local_remote_code, remote_remote_code) - # FIXME: remote_prefix - cdist.exec.run_or_fail([remote_remote_code], remote_prefix=self.remote_prefix) - - def stage_prepare(self): - """Do everything for a deploy, minus the actual code stage""" - self.init_deploy() - self.run_global_explores() - self.run_initial_manifest() - - log.info("Running object manifests and type explorers") - - old_objects = [] - objects = self.path.list_objects() - - # Continue process until no new objects are created anymore - while old_objects != objects: - old_objects = list(objects) - for cdist_object in objects: - if cdist_object in self.objects_prepared: - log.debug("Skipping rerun of object %s", cdist_object) - continue - else: - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) - self.objects_prepared.append(cdist_object) - - objects = self.path.list_objects() - - def stage_run(self): - """The final (and real) step of deployment""" - log.info("Generating and executing code") - # Now do the final steps over the existing objects - for cdist_object in self.path.list_objects(): - log.debug("Run object: %s", cdist_object) - self.object_run(cdist_object, mode="gencode") - self.object_run(cdist_object, mode="code") - - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to " + self.target_host) - time_start = datetime.datetime.now() - - self.stage_prepare() - self.stage_run() - - time_end = datetime.datetime.now() - duration = time_end - time_start - log.info("Finished run of %s in %s seconds", - self.target_host, - duration.total_seconds()) - - def deploy_and_cleanup(self): - """Do what is most often done: deploy & cleanup""" - self.deploy_to() - self.cleanup() +class Config(cdist.config_install.ConfigInstall): + pass def config(args): """Configure remote system""" diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py new file mode 100644 index 00000000..f7bd43e8 --- /dev/null +++ b/lib/cdist/config_install.py @@ -0,0 +1,292 @@ +#!/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 datetime +import logging +import os +import stat +import sys + +log = logging.getLogger(__name__) + +import cdist.emulator +import cdist.path + +CODE_HEADER = "#!/bin/sh -e\n" + +class ConfigInstall: + """Class to hold install and config methods""" + + def __init__(self, target_host, + initial_manifest=False, + remote_user="root", + home=None, + exec_path=sys.argv[0], + debug=False): + + self.target_host = target_host + self.debug = debug + self.remote_user = remote_user + self.exec_path = exec_path + + # FIXME: broken - construct elsewhere! + self.remote_prefix = ["ssh", self.remote_user + "@" + self.target_host] + + self.path = cdist.path.Path(self.target_host, + initial_manifest=initial_manifest, + remote_user=self.remote_user, + remote_prefix=self.remote_prefix, + base_dir=home, + debug=debug) + + self.objects_prepared = [] + + def cleanup(self): + self.path.cleanup() + + def run_global_explores(self): + """Run global explorers""" + log.info("Running global explorers") + explorers = self.path.list_global_explorers() + if(len(explorers) == 0): + raise CdistError("No explorers found in", self.path.global_explorer_dir) + + self.path.transfer_global_explorers() + for explorer in explorers: + output = self.path.global_explorer_output_path(explorer) + output_fd = open(output, mode='w') + cmd = [] + cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append(self.path.remote_global_explorer_path(explorer)) + + cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=self.remote_prefix) + output_fd.close() + + def run_type_explorer(self, cdist_object): + """Run type specific explorers for objects""" + + type = self.path.get_type_from_object(cdist_object) + self.path.transfer_type_explorers(type) + + cmd = [] + cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append("__type_explorer=" + self.path.remote_type_explorer_dir(type)) + cmd.append("__object=" + self.path.remote_object_dir(cdist_object)) + cmd.append("__object_id=" + self.path.get_object_id_from_object(cdist_object)) + cmd.append("__object_fq=" + cdist_object) + + # Need to transfer at least the parameters for objects to be useful + self.path.transfer_object_parameter(cdist_object) + + explorers = self.path.list_type_explorers(type) + for explorer in explorers: + remote_cmd = cmd + [os.path.join(self.path.remote_type_explorer_dir(type), explorer)] + output = os.path.join(self.path.type_explorer_output_dir(cdist_object), explorer) + output_fd = open(output, mode='w') + log.debug("%s exploring %s using %s storing to %s", + cdist_object, explorer, remote_cmd, output) + + cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=self.remote_prefix) + output_fd.close() + + def link_emulator(self): + """Link emulator to types""" + cdist.emulator.link(self.exec_path, + self.path.bin_dir, self.path.list_types()) + + def init_deploy(self): + """Ensure the base directories are cleaned up""" + log.debug("Creating clean directory structure") + + self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) + self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) + self.link_emulator() + + def run_initial_manifest(self): + """Run the initial manifest""" + log.info("Running initial manifest %s", self.path.initial_manifest) + env = { "__manifest" : self.path.manifest_dir } + self.run_manifest(self.path.initial_manifest, extra_env=env) + + def run_type_manifest(self, cdist_object): + """Run manifest for a specific object""" + type = self.path.get_type_from_object(cdist_object) + manifest = self.path.type_dir(type, "manifest") + + log.debug("%s: Running %s", cdist_object, manifest) + if os.path.exists(manifest): + env = { "__object" : self.path.object_dir(cdist_object), + "__object_id": self.path.get_object_id_from_object(cdist_object), + "__object_fq": cdist_object, + "__type": self.path.type_dir(type) + } + self.run_manifest(manifest, extra_env=env) + + def run_manifest(self, manifest, extra_env=None): + """Run a manifest""" + log.debug("Running manifest %s, env=%s", manifest, extra_env) + env = os.environ.copy() + env['PATH'] = self.path.bin_dir + ":" + env['PATH'] + + # Information required in every manifest + env['__target_host'] = self.target_host + env['__global'] = self.path.out_dir + + # Submit debug flag to manifest, can be used by emulator and types + if self.debug: + env['__debug'] = "yes" + + # Required for recording source + env['__cdist_manifest'] = manifest + + # Required to find types + env['__cdist_type_base_dir'] = self.path.type_base_dir + + # Other environment stuff + if extra_env: + env.update(extra_env) + + cdist.exec.shell_run_or_debug_fail(manifest, [manifest], env=env) + + def object_run(self, cdist_object, mode): + """Run gencode or code for an object""" + log.debug("Running %s from %s", mode, cdist_object) + file=os.path.join(self.path.object_dir(cdist_object), "require") + requirements = cdist.path.file_to_list(file) + type = self.path.get_type_from_object(cdist_object) + + for requirement in requirements: + log.debug("Object %s requires %s", cdist_object, requirement) + self.object_run(requirement, mode=mode) + + # + # Setup env Variable: + # + env = os.environ.copy() + env['__target_host'] = self.target_host + env['__global'] = self.path.out_dir + env["__object"] = self.path.object_dir(cdist_object) + env["__object_id"] = self.path.get_object_id_from_object(cdist_object) + env["__object_fq"] = cdist_object + env["__type"] = self.path.type_dir(type) + + if mode == "gencode": + paths = [ + self.path.type_dir(type, "gencode-local"), + self.path.type_dir(type, "gencode-remote") + ] + for bin in paths: + if os.path.isfile(bin): + # omit "gen" from gencode and use it for output base + outfile=os.path.join(self.path.object_dir(cdist_object), + os.path.basename(bin)[3:]) + + outfile_fd = open(outfile, "w") + + # Need to flush to ensure our write is done before stdout write + outfile_fd.write(CODE_HEADER) + outfile_fd.flush() + + cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) + outfile_fd.close() + + status = os.stat(outfile) + + # Remove output if empty, else make it executable + if status.st_size == len(CODE_HEADER): + os.unlink(outfile) + else: + # Add header and make executable - identically to 0o700 + os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + + # Mark object as changed + open(os.path.join(self.path.object_dir(cdist_object), "changed"), "w").close() + + + if mode == "code": + local_dir = self.path.object_dir(cdist_object) + remote_dir = self.path.remote_object_dir(cdist_object) + + bin = os.path.join(local_dir, "code-local") + if os.path.isfile(bin): + cdist.exec.run_or_fail([bin]) + + + local_remote_code = os.path.join(local_dir, "code-remote") + remote_remote_code = os.path.join(remote_dir, "code-remote") + if os.path.isfile(local_remote_code): + self.path.transfer_file(local_remote_code, remote_remote_code) + # FIXME: remote_prefix + cdist.exec.run_or_fail([remote_remote_code], remote_prefix=self.remote_prefix) + + def stage_prepare(self): + """Do everything for a deploy, minus the actual code stage""" + self.init_deploy() + self.run_global_explores() + self.run_initial_manifest() + + log.info("Running object manifests and type explorers") + + old_objects = [] + objects = self.path.list_objects() + + # Continue process until no new objects are created anymore + while old_objects != objects: + old_objects = list(objects) + for cdist_object in objects: + if cdist_object in self.objects_prepared: + log.debug("Skipping rerun of object %s", cdist_object) + continue + else: + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + self.objects_prepared.append(cdist_object) + + objects = self.path.list_objects() + + def stage_run(self): + """The final (and real) step of deployment""" + log.info("Generating and executing code") + # Now do the final steps over the existing objects + for cdist_object in self.path.list_objects(): + log.debug("Run object: %s", cdist_object) + self.object_run(cdist_object, mode="gencode") + self.object_run(cdist_object, mode="code") + + def deploy_to(self): + """Mimic the old deploy to: Deploy to one host""" + log.info("Deploying to " + self.target_host) + time_start = datetime.datetime.now() + + self.stage_prepare() + self.stage_run() + + time_end = datetime.datetime.now() + duration = time_end - time_start + log.info("Finished run of %s in %s seconds", + self.target_host, + duration.total_seconds()) + + def deploy_and_cleanup(self): + """Do what is most often done: deploy & cleanup""" + self.deploy_to() + self.cleanup() From acc64caf95524156686f3aabbe7fea1b9c4fab60 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Oct 2011 22:23:26 +0200 Subject: [PATCH 0460/4212] new type: __mkfs Signed-off-by: Steven Armstrong --- conf/type/__mkfs/gencode-remote | 36 ++++++++++++++++++ conf/type/__mkfs/installer | 0 conf/type/__mkfs/man.text | 57 +++++++++++++++++++++++++++++ conf/type/__mkfs/manifest | 31 ++++++++++++++++ conf/type/__mkfs/parameter/optional | 3 ++ conf/type/__mkfs/parameter/required | 1 + 6 files changed, 128 insertions(+) create mode 100755 conf/type/__mkfs/gencode-remote create mode 100644 conf/type/__mkfs/installer create mode 100644 conf/type/__mkfs/man.text create mode 100755 conf/type/__mkfs/manifest create mode 100644 conf/type/__mkfs/parameter/optional create mode 100644 conf/type/__mkfs/parameter/required diff --git a/conf/type/__mkfs/gencode-remote b/conf/type/__mkfs/gencode-remote new file mode 100755 index 00000000..e5061013 --- /dev/null +++ b/conf/type/__mkfs/gencode-remote @@ -0,0 +1,36 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +device="(cat "$__object/parameter/device")" +type="(cat "$__object/parameter/type")" + +command="mkfs -t $type" + +if [ -f "$__object/parameter/options" ]; then + options="(cat "$__object/parameter/options")" + command="$command -o '$options'" +fi +command="$command $device" +if [ -f "$__object/parameter/blocks" ]; then + blocks="(cat "$__object/parameter/blocks")" + command="$command $blocks" +fi + +echo "$command" diff --git a/conf/type/__mkfs/installer b/conf/type/__mkfs/installer new file mode 100644 index 00000000..e69de29b diff --git a/conf/type/__mkfs/man.text b/conf/type/__mkfs/man.text new file mode 100644 index 00000000..4320c639 --- /dev/null +++ b/conf/type/__mkfs/man.text @@ -0,0 +1,57 @@ +cdist-type__mkfs(7) +=================== +Steven Armstrong + + +NAME +---- +cdist-type__mkfs - build a linux file system + + +DESCRIPTION +----------- +This cdist type is a wrapper for the mkfs command. + + +REQUIRED PARAMETERS +------------------- +type:: + The filesystem type to use. Same as mkfs -t. + + +OPTIONAL PARAMETERS +------------------- +device:: + defaults to object_id + +options:: + file system-specific options to be passed to the mkfs command + +blocks:: + the number of blocks to be used for the file system + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# reiserfs /dev/sda5 +__mkfs /dev/sda5 --type reiserfs +# same thing with explicit device +__mkfs whatever --device /dev/sda5 --type reiserfs + +# jfs with journal on /dev/sda2 +__mkfs /dev/sda1 --type jfs --options "-j /dev/sda2" +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- mkfs(8) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__mkfs/manifest b/conf/type/__mkfs/manifest new file mode 100755 index 00000000..e9d275a4 --- /dev/null +++ b/conf/type/__mkfs/manifest @@ -0,0 +1,31 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# set defaults +if [ -f "$__object/parameter/device" ]; then + device="(cat "$__object/parameter/device")" +else + device="/$__object_id" + echo "$device" > "$__object/parameter/device" +fi + +type="(cat "$__object/parameter/type")" + +options="(cat "$__object/parameter/options")" diff --git a/conf/type/__mkfs/parameter/optional b/conf/type/__mkfs/parameter/optional new file mode 100644 index 00000000..86aeae30 --- /dev/null +++ b/conf/type/__mkfs/parameter/optional @@ -0,0 +1,3 @@ +device +options +blocks diff --git a/conf/type/__mkfs/parameter/required b/conf/type/__mkfs/parameter/required new file mode 100644 index 00000000..aa80e646 --- /dev/null +++ b/conf/type/__mkfs/parameter/required @@ -0,0 +1 @@ +type From 27a774432e900896fc2a9a5e73adec794e13c296 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Oct 2011 22:42:19 +0200 Subject: [PATCH 0461/4212] mark __partition_msdos and __partition_msdos_apply as installer types Signed-off-by: Steven Armstrong --- conf/type/__partition_msdos/installer | 0 conf/type/__partition_msdos_apply/installer | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 conf/type/__partition_msdos/installer create mode 100644 conf/type/__partition_msdos_apply/installer diff --git a/conf/type/__partition_msdos/installer b/conf/type/__partition_msdos/installer new file mode 100644 index 00000000..e69de29b diff --git a/conf/type/__partition_msdos_apply/installer b/conf/type/__partition_msdos_apply/installer new file mode 100644 index 00000000..e69de29b From 9fd74acfac2194874224ea046953094cd56dfffa Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Oct 2011 22:50:49 +0200 Subject: [PATCH 0462/4212] add support for swap Signed-off-by: Steven Armstrong --- conf/type/__mkfs/gencode-remote | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/conf/type/__mkfs/gencode-remote b/conf/type/__mkfs/gencode-remote index e5061013..0a220ec9 100755 --- a/conf/type/__mkfs/gencode-remote +++ b/conf/type/__mkfs/gencode-remote @@ -21,16 +21,18 @@ device="(cat "$__object/parameter/device")" type="(cat "$__object/parameter/type")" -command="mkfs -t $type" - -if [ -f "$__object/parameter/options" ]; then - options="(cat "$__object/parameter/options")" - command="$command -o '$options'" +if [ "$type" = "swap" ]; then + echo "mkswap $device" +else + command="mkfs -t $type" + if [ -f "$__object/parameter/options" ]; then + options="(cat "$__object/parameter/options")" + command="$command -o '$options'" + fi + command="$command $device" + if [ -f "$__object/parameter/blocks" ]; then + blocks="(cat "$__object/parameter/blocks")" + command="$command $blocks" + fi + echo "$command" fi -command="$command $device" -if [ -f "$__object/parameter/blocks" ]; then - blocks="(cat "$__object/parameter/blocks")" - command="$command $blocks" -fi - -echo "$command" From 20241a0c5c4d005f66ac2591e8bddcebb9ba8ab6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Oct 2011 22:56:24 +0200 Subject: [PATCH 0463/4212] fix copy/paste error Signed-off-by: Steven Armstrong --- conf/type/__mkfs/gencode-remote | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/conf/type/__mkfs/gencode-remote b/conf/type/__mkfs/gencode-remote index 0a220ec9..67e37cce 100755 --- a/conf/type/__mkfs/gencode-remote +++ b/conf/type/__mkfs/gencode-remote @@ -18,20 +18,20 @@ # along with cdist. If not, see . # -device="(cat "$__object/parameter/device")" -type="(cat "$__object/parameter/type")" +device="$(cat "$__object/parameter/device")" +type="$(cat "$__object/parameter/type")" if [ "$type" = "swap" ]; then echo "mkswap $device" else command="mkfs -t $type" if [ -f "$__object/parameter/options" ]; then - options="(cat "$__object/parameter/options")" + options="$(cat "$__object/parameter/options")" command="$command -o '$options'" fi command="$command $device" if [ -f "$__object/parameter/blocks" ]; then - blocks="(cat "$__object/parameter/blocks")" + blocks="$(cat "$__object/parameter/blocks")" command="$command $blocks" fi echo "$command" From 3d017abd6f207a819b9fc90fc043bbe1be91accc Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Oct 2011 22:56:50 +0200 Subject: [PATCH 0464/4212] pass options to mkfs without -o Signed-off-by: Steven Armstrong --- conf/type/__mkfs/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__mkfs/gencode-remote b/conf/type/__mkfs/gencode-remote index 67e37cce..e774f33d 100755 --- a/conf/type/__mkfs/gencode-remote +++ b/conf/type/__mkfs/gencode-remote @@ -27,7 +27,7 @@ else command="mkfs -t $type" if [ -f "$__object/parameter/options" ]; then options="$(cat "$__object/parameter/options")" - command="$command -o '$options'" + command="$command $options" fi command="$command $device" if [ -f "$__object/parameter/blocks" ]; then From de4ddf9d1e4cdce8376e1bc87381c70de8cf6eba Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Oct 2011 23:03:50 +0200 Subject: [PATCH 0465/4212] mv installer install Signed-off-by: Steven Armstrong --- conf/type/__mkfs/gencode-remote | 2 +- conf/type/__mkfs/{installer => install} | 0 conf/type/__partition_msdos/{installer => install} | 0 conf/type/__partition_msdos_apply/{installer => install} | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename conf/type/__mkfs/{installer => install} (100%) rename conf/type/__partition_msdos/{installer => install} (100%) rename conf/type/__partition_msdos_apply/{installer => install} (100%) diff --git a/conf/type/__mkfs/gencode-remote b/conf/type/__mkfs/gencode-remote index e774f33d..b3561bad 100755 --- a/conf/type/__mkfs/gencode-remote +++ b/conf/type/__mkfs/gencode-remote @@ -24,7 +24,7 @@ type="$(cat "$__object/parameter/type")" if [ "$type" = "swap" ]; then echo "mkswap $device" else - command="mkfs -t $type" + command="mkfs -t $type -q" if [ -f "$__object/parameter/options" ]; then options="$(cat "$__object/parameter/options")" command="$command $options" diff --git a/conf/type/__mkfs/installer b/conf/type/__mkfs/install similarity index 100% rename from conf/type/__mkfs/installer rename to conf/type/__mkfs/install diff --git a/conf/type/__partition_msdos/installer b/conf/type/__partition_msdos/install similarity index 100% rename from conf/type/__partition_msdos/installer rename to conf/type/__partition_msdos/install diff --git a/conf/type/__partition_msdos_apply/installer b/conf/type/__partition_msdos_apply/install similarity index 100% rename from conf/type/__partition_msdos_apply/installer rename to conf/type/__partition_msdos_apply/install From f0223647e34c642aa24abb5b08db0cee4ae05154 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Oct 2011 23:12:49 +0200 Subject: [PATCH 0466/4212] --debug Signed-off-by: Steven Armstrong --- conf/type/__partition_msdos_apply/files/lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__partition_msdos_apply/files/lib.sh b/conf/type/__partition_msdos_apply/files/lib.sh index f0859aab..021c11d4 100644 --- a/conf/type/__partition_msdos_apply/files/lib.sh +++ b/conf/type/__partition_msdos_apply/files/lib.sh @@ -3,7 +3,7 @@ die() { exit 1 } debug() { - echo "[__partition_msdos_apply] $@" >&2 + #echo "[__partition_msdos_apply] $@" >&2 } fdisk_command() { From 9d6a00af3885f8e8f23f450c0b589c2660c1ef12 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Oct 2011 23:13:53 +0200 Subject: [PATCH 0467/4212] --debug without creating syntax errors Signed-off-by: Steven Armstrong --- conf/type/__partition_msdos_apply/files/lib.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/type/__partition_msdos_apply/files/lib.sh b/conf/type/__partition_msdos_apply/files/lib.sh index 021c11d4..d7f07060 100644 --- a/conf/type/__partition_msdos_apply/files/lib.sh +++ b/conf/type/__partition_msdos_apply/files/lib.sh @@ -4,6 +4,7 @@ die() { } debug() { #echo "[__partition_msdos_apply] $@" >&2 + : } fdisk_command() { From 648f57173c7fa1f405e62bd7f441c88f2e83b758 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Oct 2011 23:53:06 +0200 Subject: [PATCH 0468/4212] bugfix: use -gt when comparing int values Signed-off-by: Steven Armstrong --- conf/type/__partition_msdos_apply/files/lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__partition_msdos_apply/files/lib.sh b/conf/type/__partition_msdos_apply/files/lib.sh index d7f07060..5767ea43 100644 --- a/conf/type/__partition_msdos_apply/files/lib.sh +++ b/conf/type/__partition_msdos_apply/files/lib.sh @@ -52,7 +52,7 @@ create_partition() { first_minor="${minor}\n" type_minor="${minor}\n" primary_extended="l\n" - [ "$primary_count" > "3" ] && primary_extended="" + [ "$primary_count" -gt "3" ] && primary_extended="" fi [ -n "${size}" ] && size="+${size}M" fdisk_command ${device} "n\n${primary_extended}${first_minor}\n${size}\nt\n${type_minor}${type}\n" From 9dfd6a27ad2b0e771e03d633a20248b2c7a0e102 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 5 Oct 2011 09:15:20 +0200 Subject: [PATCH 0469/4212] fixed broken man page --- conf/type/__init_script/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__init_script/man.text b/conf/type/__init_script/man.text index 898943a5..c33ff7b7 100644 --- a/conf/type/__init_script/man.text +++ b/conf/type/__init_script/man.text @@ -1,5 +1,5 @@ cdist-type__init_script(7) -============================== +========================== Daniel Roth From 8a044919eb9e74dde6651ccd60ce390004ab8e97 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Oct 2011 13:24:07 +0200 Subject: [PATCH 0470/4212] +discussion about restructering/ "object-orientation" Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-05 | 112 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 doc/dev/logs/2011-10-05 diff --git a/doc/dev/logs/2011-10-05 b/doc/dev/logs/2011-10-05 new file mode 100644 index 00000000..92e8675f --- /dev/null +++ b/doc/dev/logs/2011-10-05 @@ -0,0 +1,112 @@ +Config/Install/Deploy/Run: + target host + remote_cmd_prefix - ssh user@bla sudo foo????? + remote_cp_prefix - cp statt scp oder so + + debug -> env für alles += __debug + + +Storage/Metaobject/Tree? == Path? + base_dir? + nimmt objekte + + Sammelt Objekte + + Ist prepared hier? + +Object + "Infos" / Datenhalde + + Base_Dir-Abhängigkeit? - wo + + out_dir - wo speichern + + nur eigenes verzeichnis interessant? + -> nicht für shell code / aka gencode! + -> __global abhängigkeit + + object.gencode()? + + hast du type-explorer? + ja? + führe JEDEN remote aus + speichere ausgabe in object + nein: + fertig + hast du gencode-{local,remote}? + ja? + führe local oder remote aus + speichere ausgabe in s/^gen// + nein: + fertig + + hast du code-{local,remote}? + ja? + führe local oder remote aus + nein: + fertig + + ich habe ... + object_id + type + type.singleton() == False -> require object_id + parameter gegeben + requirements / order + + type_explorer := methode zum ausführen? + + cdist.object.Object(type, id) + + methoden: + gen_code + code + run_manifest + manifest == ort + +Type + singleton: ja / nein + install: ja / nein + type_explorer := liste + + optional_parameter + required_parameter + + TypeExplorer + verwandt oder == explorer + Verwandschaft klären! + + sehr abhängig von base_dir! + - welche gibt es? + - was für optionen haben sie + + cdist.type.Type("/path/to/type") + Tree/Path vieh, das liste von $_ speichert + Einfach iterieren + + + +Explorer + execute(env) + env == __explorer -> nur im explorer + +z.B. BaseExplorer oder andersherum GlobalExplorer + +Manifest + +Exec + wrapper um auszuführen, + error handling, + output redirection (variable, file, beides, socat :-) + + +-------------------------------------------------------------------------------- + +- base_dir (conf/, type, ...) +- manifest (initiale) + $methode_mit_inhalt_von_manifest? + run_manifest(code) + ob sinnvoll? + geht auch mit stdin oder datei + + stdin -> muss in tmp-datei, für sh -e? +- From f00b8fe56a8cb45116b9595c212c9a54796b2007 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Oct 2011 13:31:57 +0200 Subject: [PATCH 0471/4212] buffering/output idea Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-05 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/dev/logs/2011-10-05 b/doc/dev/logs/2011-10-05 index 92e8675f..39fc48a2 100644 --- a/doc/dev/logs/2011-10-05 +++ b/doc/dev/logs/2011-10-05 @@ -110,3 +110,7 @@ Exec stdin -> muss in tmp-datei, für sh -e? - +-------------------------------------------------------------------------------- + +save output of shell in buffer instead of displaying? + -> freedom to decide whether to display or not! From a875d69d7e9dc6dabdcd33c0ee4d33dd13640376 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Oct 2011 14:15:05 +0200 Subject: [PATCH 0472/4212] continue on test_path testcase Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 5 +++-- lib/cdist/install.py | 6 ++++++ lib/cdist/test/test_path.py | 6 +++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index f7bd43e8..cd8ea720 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -26,11 +26,11 @@ import os import stat import sys -log = logging.getLogger(__name__) - import cdist.emulator import cdist.path +log = logging.getLogger(__name__) + CODE_HEADER = "#!/bin/sh -e\n" class ConfigInstall: @@ -203,6 +203,7 @@ class ConfigInstall: outfile_fd = open(outfile, "w") # Need to flush to ensure our write is done before stdout write + # FIXME: CODE_HEADER needed in our sh -e scenario???? outfile_fd.write(CODE_HEADER) outfile_fd.flush() diff --git a/lib/cdist/install.py b/lib/cdist/install.py index 98b388ec..5a35626d 100644 --- a/lib/cdist/install.py +++ b/lib/cdist/install.py @@ -22,8 +22,14 @@ import logging +import cdist.config_install + log = logging.getLogger(__name__) + +Class Install(cdist.config_install.ConfigInstall): + pass + def install(args): """Install remote system""" process = {} diff --git a/lib/cdist/test/test_path.py b/lib/cdist/test/test_path.py index c8ca95c0..f86c8fad 100644 --- a/lib/cdist/test/test_path.py +++ b/lib/cdist/test/test_path.py @@ -66,12 +66,12 @@ class Path(unittest.TestCase): """Check that objects created from manifest are only of install type""" manifest_fd = open(self.init_manifest, "w") manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + " --mode 0700\n", - "__partition_msdos /dev/null --type 82\n", + self.install_type_name + "testid\n", + self.config_type_name + "testid\n", ]) manifest_fd.close() - self.config.run_initial_manifest() + self.install.run_initial_manifest() # FIXME: check that only __partition_msdos objects are created! From 9128cc28c414e1fa1abe4a482f6777f753123910 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Oct 2011 15:50:17 +0200 Subject: [PATCH 0473/4212] introduce a lot todo in path Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 2dd9dcf1..5cde357b 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -107,6 +107,7 @@ class Path: else: self.initial_manifest = os.path.join(self.manifest_dir, "init") + # FIXME: stays def cleanup(self): # Do not use in __del__: # http://docs.python.org/reference/datamodel.html#customization @@ -120,13 +121,16 @@ class Path: shutil.move(self.temp_dir, self.cache_dir) + # FIXME: belongs to here - clearify remote* def remote_mkdir(self, directory): """Create directory on remote side""" cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=self.remote_prefix) + # FIXME: belongs to here - clearify remote* def remove_remote_dir(self, destination): cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=self.remote_prefix) + # FIXME: belongs to here - clearify remote* def transfer_dir(self, source, destination): """Transfer directory and previously delete the remote destination""" self.remove_remote_dir(destination) @@ -135,6 +139,7 @@ class Path: self.target_host + ":" + destination]) + # FIXME: belongs to here - clearify remote* def transfer_file(self, source, destination): """Transfer file""" cdist.exec.run_or_fail(["scp", "-q", source, @@ -142,10 +147,12 @@ class Path: self.target_host + ":" + destination]) + # FIXME: Explorer or stays def global_explorer_output_path(self, explorer): """Returns path of the output for a global explorer""" return os.path.join(self.global_explorer_out_dir, explorer) + # FIXME: object def type_explorer_output_dir(self, cdist_object): """Returns and creates dir of the output for a type explorer""" dir = os.path.join(self.object_dir(cdist_object), "explorer") @@ -154,14 +161,17 @@ class Path: return dir + # FIXME Stays here / Explorer? def remote_global_explorer_path(self, explorer): """Returns path to the remote explorer""" return os.path.join(REMOTE_GLOBAL_EXPLORER_DIR, explorer) + # FIXME: stays here def list_global_explorers(self): """Return list of available explorers""" return os.listdir(self.global_explorer_dir) + # FIXME: Type - only needs to know its path def list_type_explorers(self, type): """Return list of available explorers for a specific type""" dir = self.type_dir(type, "explorer") @@ -174,15 +184,18 @@ class Path: return list + # Stays here def list_types(self): """Retuns list of types""" return os.listdir(self.type_base_dir) + # FIXME: type def is_install_type(self, type): """Check whether a type is used for installation (if not: for configuration)""" marker = os.path.join(self.type_dir(type), "install") return os.path.isfile(marker) + # Stays here def list_object_paths(self, starting_point): """Return list of paths of existing objects""" object_paths = [] @@ -198,36 +211,43 @@ class Path: return object_paths - # FIXME + # FIXME: Object def get_type_from_object(self, cdist_object): """Returns the first part (i.e. type) of an object""" return cdist_object.split(os.sep)[0] + # FIXME: Object def get_object_id_from_object(self, cdist_object): """Returns everything but the first part (i.e. object_id) of an object""" return os.sep.join(cdist_object.split(os.sep)[1:]) + # FIXME: Object def object_dir(self, cdist_object): """Returns the full path to the object (including .cdist)""" return os.path.join(self.object_base_dir, cdist_object, DOT_CDIST) + # FIXME: Object def remote_object_dir(self, cdist_object): """Returns the remote full path to the object (including .cdist)""" return os.path.join(REMOTE_OBJECT_DIR, cdist_object, DOT_CDIST) + # FIXME: Object def object_parameter_dir(self, cdist_object): """Returns the dir to the object parameter""" return os.path.join(self.object_dir(cdist_object), "parameter") + # FIXME: object def remote_object_parameter_dir(self, cdist_object): """Returns the remote dir to the object parameter""" return os.path.join(self.remote_object_dir(cdist_object), "parameter") + # FIXME: object def object_code_paths(self, cdist_object): """Return paths to code scripts of object""" return [os.path.join(self.object_dir(cdist_object), "code-local"), os.path.join(self.object_dir(cdist_object), "code-remote")] + # Stays here def list_objects(self): """Return list of existing objects""" @@ -240,14 +260,17 @@ class Path: return objects + # FIXME: Type def type_dir(self, type, *args): - """Return directory the type""" + """Return (sub-)directory of a type""" return os.path.join(self.type_base_dir, type, *args) + # FIXME: Type def remote_type_explorer_dir(self, type): """Return remote directory that holds the explorers of a type""" return os.path.join(REMOTE_TYPE_DIR, type, "explorer") + # Stays here def transfer_object_parameter(self, cdist_object): """Transfer the object parameter to the remote destination""" # Create base path before using mkdir -p @@ -257,11 +280,13 @@ class Path: self.transfer_dir(self.object_parameter_dir(cdist_object), self.remote_object_parameter_dir(cdist_object)) + # Stays here def transfer_global_explorers(self): """Transfer the global explorers""" self.remote_mkdir(REMOTE_GLOBAL_EXPLORER_DIR) self.transfer_dir(self.global_explorer_dir, REMOTE_GLOBAL_EXPLORER_DIR) + # Stays here def transfer_type_explorers(self, type): """Transfer explorers of a type, but only once""" if type in self.type_explorers_transferred: From 28428177ae8734c3b4eb84d361f2c6447c58debc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Oct 2011 15:53:34 +0200 Subject: [PATCH 0474/4212] --typo Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 426 ++++++++++++++++++------------------ 1 file changed, 213 insertions(+), 213 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index cd8ea720..a550c45e 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -31,263 +31,263 @@ import cdist.path log = logging.getLogger(__name__) -CODE_HEADER = "#!/bin/sh -e\n" +CODE_HEADER = "#!/bin/sh -e\n" class ConfigInstall: - """Class to hold install and config methods""" + """Class to hold install and config methods""" - def __init__(self, target_host, - initial_manifest=False, - remote_user="root", - home=None, - exec_path=sys.argv[0], - debug=False): + def __init__(self, target_host, + initial_manifest=False, + remote_user="root", + home=None, + exec_path=sys.argv[0], + debug=False): - self.target_host = target_host - self.debug = debug - self.remote_user = remote_user - self.exec_path = exec_path + self.target_host = target_host + self.debug = debug + self.remote_user = remote_user + self.exec_path = exec_path - # FIXME: broken - construct elsewhere! - self.remote_prefix = ["ssh", self.remote_user + "@" + self.target_host] + # FIXME: broken - construct elsewhere! + self.remote_prefix = ["ssh", self.remote_user + "@" + self.target_host] - self.path = cdist.path.Path(self.target_host, - initial_manifest=initial_manifest, - remote_user=self.remote_user, - remote_prefix=self.remote_prefix, - base_dir=home, - debug=debug) - - self.objects_prepared = [] + self.path = cdist.path.Path(self.target_host, + initial_manifest=initial_manifest, + remote_user=self.remote_user, + remote_prefix=self.remote_prefix, + base_dir=home, + debug=debug) + + self.objects_prepared = [] - def cleanup(self): - self.path.cleanup() + def cleanup(self): + self.path.cleanup() - def run_global_explores(self): - """Run global explorers""" - log.info("Running global explorers") - explorers = self.path.list_global_explorers() - if(len(explorers) == 0): - raise CdistError("No explorers found in", self.path.global_explorer_dir) + def run_global_explorers(self): + """Run global explorers""" + log.info("Running global explorers") + explorers = self.path.list_global_explorers() + if(len(explorers) == 0): + raise CdistError("No explorers found in", self.path.global_explorer_dir) - self.path.transfer_global_explorers() - for explorer in explorers: - output = self.path.global_explorer_output_path(explorer) - output_fd = open(output, mode='w') - cmd = [] - cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append(self.path.remote_global_explorer_path(explorer)) + self.path.transfer_global_explorers() + for explorer in explorers: + output = self.path.global_explorer_output_path(explorer) + output_fd = open(output, mode='w') + cmd = [] + cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append(self.path.remote_global_explorer_path(explorer)) - cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=self.remote_prefix) - output_fd.close() + cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=self.remote_prefix) + output_fd.close() - def run_type_explorer(self, cdist_object): - """Run type specific explorers for objects""" + def run_type_explorer(self, cdist_object): + """Run type specific explorers for objects""" - type = self.path.get_type_from_object(cdist_object) - self.path.transfer_type_explorers(type) + type = self.path.get_type_from_object(cdist_object) + self.path.transfer_type_explorers(type) - cmd = [] - cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append("__type_explorer=" + self.path.remote_type_explorer_dir(type)) - cmd.append("__object=" + self.path.remote_object_dir(cdist_object)) - cmd.append("__object_id=" + self.path.get_object_id_from_object(cdist_object)) - cmd.append("__object_fq=" + cdist_object) + cmd = [] + cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append("__type_explorer=" + self.path.remote_type_explorer_dir(type)) + cmd.append("__object=" + self.path.remote_object_dir(cdist_object)) + cmd.append("__object_id=" + self.path.get_object_id_from_object(cdist_object)) + cmd.append("__object_fq=" + cdist_object) - # Need to transfer at least the parameters for objects to be useful - self.path.transfer_object_parameter(cdist_object) + # Need to transfer at least the parameters for objects to be useful + self.path.transfer_object_parameter(cdist_object) - explorers = self.path.list_type_explorers(type) - for explorer in explorers: - remote_cmd = cmd + [os.path.join(self.path.remote_type_explorer_dir(type), explorer)] - output = os.path.join(self.path.type_explorer_output_dir(cdist_object), explorer) - output_fd = open(output, mode='w') - log.debug("%s exploring %s using %s storing to %s", - cdist_object, explorer, remote_cmd, output) - - cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=self.remote_prefix) - output_fd.close() + explorers = self.path.list_type_explorers(type) + for explorer in explorers: + remote_cmd = cmd + [os.path.join(self.path.remote_type_explorer_dir(type), explorer)] + output = os.path.join(self.path.type_explorer_output_dir(cdist_object), explorer) + output_fd = open(output, mode='w') + log.debug("%s exploring %s using %s storing to %s", + cdist_object, explorer, remote_cmd, output) + + cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=self.remote_prefix) + output_fd.close() - def link_emulator(self): - """Link emulator to types""" - cdist.emulator.link(self.exec_path, - self.path.bin_dir, self.path.list_types()) + def link_emulator(self): + """Link emulator to types""" + cdist.emulator.link(self.exec_path, + self.path.bin_dir, self.path.list_types()) - def init_deploy(self): - """Ensure the base directories are cleaned up""" - log.debug("Creating clean directory structure") + def init_deploy(self): + """Ensure the base directories are cleaned up""" + log.debug("Creating clean directory structure") - self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) - self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) - self.link_emulator() + self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) + self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) + self.link_emulator() - def run_initial_manifest(self): - """Run the initial manifest""" - log.info("Running initial manifest %s", self.path.initial_manifest) - env = { "__manifest" : self.path.manifest_dir } - self.run_manifest(self.path.initial_manifest, extra_env=env) + def run_initial_manifest(self): + """Run the initial manifest""" + log.info("Running initial manifest %s", self.path.initial_manifest) + env = { "__manifest" : self.path.manifest_dir } + self.run_manifest(self.path.initial_manifest, extra_env=env) - def run_type_manifest(self, cdist_object): - """Run manifest for a specific object""" - type = self.path.get_type_from_object(cdist_object) - manifest = self.path.type_dir(type, "manifest") - - log.debug("%s: Running %s", cdist_object, manifest) - if os.path.exists(manifest): - env = { "__object" : self.path.object_dir(cdist_object), - "__object_id": self.path.get_object_id_from_object(cdist_object), - "__object_fq": cdist_object, - "__type": self.path.type_dir(type) - } - self.run_manifest(manifest, extra_env=env) + def run_type_manifest(self, cdist_object): + """Run manifest for a specific object""" + type = self.path.get_type_from_object(cdist_object) + manifest = self.path.type_dir(type, "manifest") + + log.debug("%s: Running %s", cdist_object, manifest) + if os.path.exists(manifest): + env = { "__object" : self.path.object_dir(cdist_object), + "__object_id": self.path.get_object_id_from_object(cdist_object), + "__object_fq": cdist_object, + "__type": self.path.type_dir(type) + } + self.run_manifest(manifest, extra_env=env) - def run_manifest(self, manifest, extra_env=None): - """Run a manifest""" - log.debug("Running manifest %s, env=%s", manifest, extra_env) - env = os.environ.copy() - env['PATH'] = self.path.bin_dir + ":" + env['PATH'] + def run_manifest(self, manifest, extra_env=None): + """Run a manifest""" + log.debug("Running manifest %s, env=%s", manifest, extra_env) + env = os.environ.copy() + env['PATH'] = self.path.bin_dir + ":" + env['PATH'] - # Information required in every manifest - env['__target_host'] = self.target_host - env['__global'] = self.path.out_dir - - # Submit debug flag to manifest, can be used by emulator and types - if self.debug: - env['__debug'] = "yes" + # Information required in every manifest + env['__target_host'] = self.target_host + env['__global'] = self.path.out_dir + + # Submit debug flag to manifest, can be used by emulator and types + if self.debug: + env['__debug'] = "yes" - # Required for recording source - env['__cdist_manifest'] = manifest + # Required for recording source + env['__cdist_manifest'] = manifest - # Required to find types - env['__cdist_type_base_dir'] = self.path.type_base_dir + # Required to find types + env['__cdist_type_base_dir'] = self.path.type_base_dir - # Other environment stuff - if extra_env: - env.update(extra_env) + # Other environment stuff + if extra_env: + env.update(extra_env) - cdist.exec.shell_run_or_debug_fail(manifest, [manifest], env=env) + cdist.exec.shell_run_or_debug_fail(manifest, [manifest], env=env) - def object_run(self, cdist_object, mode): - """Run gencode or code for an object""" - log.debug("Running %s from %s", mode, cdist_object) - file=os.path.join(self.path.object_dir(cdist_object), "require") - requirements = cdist.path.file_to_list(file) - type = self.path.get_type_from_object(cdist_object) - - for requirement in requirements: - log.debug("Object %s requires %s", cdist_object, requirement) - self.object_run(requirement, mode=mode) + def object_run(self, cdist_object, mode): + """Run gencode or code for an object""" + log.debug("Running %s from %s", mode, cdist_object) + file=os.path.join(self.path.object_dir(cdist_object), "require") + requirements = cdist.path.file_to_list(file) + type = self.path.get_type_from_object(cdist_object) + + for requirement in requirements: + log.debug("Object %s requires %s", cdist_object, requirement) + self.object_run(requirement, mode=mode) - # - # Setup env Variable: - # - env = os.environ.copy() - env['__target_host'] = self.target_host - env['__global'] = self.path.out_dir - env["__object"] = self.path.object_dir(cdist_object) - env["__object_id"] = self.path.get_object_id_from_object(cdist_object) - env["__object_fq"] = cdist_object - env["__type"] = self.path.type_dir(type) + # + # Setup env Variable: + # + env = os.environ.copy() + env['__target_host'] = self.target_host + env['__global'] = self.path.out_dir + env["__object"] = self.path.object_dir(cdist_object) + env["__object_id"] = self.path.get_object_id_from_object(cdist_object) + env["__object_fq"] = cdist_object + env["__type"] = self.path.type_dir(type) - if mode == "gencode": - paths = [ - self.path.type_dir(type, "gencode-local"), - self.path.type_dir(type, "gencode-remote") - ] - for bin in paths: - if os.path.isfile(bin): - # omit "gen" from gencode and use it for output base - outfile=os.path.join(self.path.object_dir(cdist_object), - os.path.basename(bin)[3:]) + if mode == "gencode": + paths = [ + self.path.type_dir(type, "gencode-local"), + self.path.type_dir(type, "gencode-remote") + ] + for bin in paths: + if os.path.isfile(bin): + # omit "gen" from gencode and use it for output base + outfile=os.path.join(self.path.object_dir(cdist_object), + os.path.basename(bin)[3:]) - outfile_fd = open(outfile, "w") + outfile_fd = open(outfile, "w") - # Need to flush to ensure our write is done before stdout write - # FIXME: CODE_HEADER needed in our sh -e scenario???? - outfile_fd.write(CODE_HEADER) - outfile_fd.flush() + # Need to flush to ensure our write is done before stdout write + # FIXME: CODE_HEADER needed in our sh -e scenario? + outfile_fd.write(CODE_HEADER) + outfile_fd.flush() - cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) - outfile_fd.close() + cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) + outfile_fd.close() - status = os.stat(outfile) + status = os.stat(outfile) - # Remove output if empty, else make it executable - if status.st_size == len(CODE_HEADER): - os.unlink(outfile) - else: - # Add header and make executable - identically to 0o700 - os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + # Remove output if empty, else make it executable + if status.st_size == len(CODE_HEADER): + os.unlink(outfile) + else: + # Add header and make executable - identically to 0o700 + os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) - # Mark object as changed - open(os.path.join(self.path.object_dir(cdist_object), "changed"), "w").close() + # Mark object as changed + open(os.path.join(self.path.object_dir(cdist_object), "changed"), "w").close() - if mode == "code": - local_dir = self.path.object_dir(cdist_object) - remote_dir = self.path.remote_object_dir(cdist_object) + if mode == "code": + local_dir = self.path.object_dir(cdist_object) + remote_dir = self.path.remote_object_dir(cdist_object) - bin = os.path.join(local_dir, "code-local") - if os.path.isfile(bin): - cdist.exec.run_or_fail([bin]) - + bin = os.path.join(local_dir, "code-local") + if os.path.isfile(bin): + cdist.exec.run_or_fail([bin]) + - local_remote_code = os.path.join(local_dir, "code-remote") - remote_remote_code = os.path.join(remote_dir, "code-remote") - if os.path.isfile(local_remote_code): - self.path.transfer_file(local_remote_code, remote_remote_code) - # FIXME: remote_prefix - cdist.exec.run_or_fail([remote_remote_code], remote_prefix=self.remote_prefix) - - def stage_prepare(self): - """Do everything for a deploy, minus the actual code stage""" - self.init_deploy() - self.run_global_explores() - self.run_initial_manifest() - - log.info("Running object manifests and type explorers") + local_remote_code = os.path.join(local_dir, "code-remote") + remote_remote_code = os.path.join(remote_dir, "code-remote") + if os.path.isfile(local_remote_code): + self.path.transfer_file(local_remote_code, remote_remote_code) + # FIXME: remote_prefix + cdist.exec.run_or_fail([remote_remote_code], remote_prefix=self.remote_prefix) + + def stage_prepare(self): + """Do everything for a deploy, minus the actual code stage""" + self.init_deploy() + self.run_global_explorers() + self.run_initial_manifest() + + log.info("Running object manifests and type explorers") - old_objects = [] - objects = self.path.list_objects() + old_objects = [] + objects = self.path.list_objects() - # Continue process until no new objects are created anymore - while old_objects != objects: - old_objects = list(objects) - for cdist_object in objects: - if cdist_object in self.objects_prepared: - log.debug("Skipping rerun of object %s", cdist_object) - continue - else: - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) - self.objects_prepared.append(cdist_object) + # Continue process until no new objects are created anymore + while old_objects != objects: + old_objects = list(objects) + for cdist_object in objects: + if cdist_object in self.objects_prepared: + log.debug("Skipping rerun of object %s", cdist_object) + continue + else: + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + self.objects_prepared.append(cdist_object) - objects = self.path.list_objects() + objects = self.path.list_objects() - def stage_run(self): - """The final (and real) step of deployment""" - log.info("Generating and executing code") - # Now do the final steps over the existing objects - for cdist_object in self.path.list_objects(): - log.debug("Run object: %s", cdist_object) - self.object_run(cdist_object, mode="gencode") - self.object_run(cdist_object, mode="code") + def stage_run(self): + """The final (and real) step of deployment""" + log.info("Generating and executing code") + # Now do the final steps over the existing objects + for cdist_object in self.path.list_objects(): + log.debug("Run object: %s", cdist_object) + self.object_run(cdist_object, mode="gencode") + self.object_run(cdist_object, mode="code") - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to " + self.target_host) - time_start = datetime.datetime.now() + def deploy_to(self): + """Mimic the old deploy to: Deploy to one host""" + log.info("Deploying to " + self.target_host) + time_start = datetime.datetime.now() - self.stage_prepare() - self.stage_run() + self.stage_prepare() + self.stage_run() - time_end = datetime.datetime.now() - duration = time_end - time_start - log.info("Finished run of %s in %s seconds", - self.target_host, - duration.total_seconds()) + time_end = datetime.datetime.now() + duration = time_end - time_start + log.info("Finished run of %s in %s seconds", + self.target_host, + duration.total_seconds()) - def deploy_and_cleanup(self): - """Do what is most often done: deploy & cleanup""" - self.deploy_to() - self.cleanup() + def deploy_and_cleanup(self): + """Do what is most often done: deploy & cleanup""" + self.deploy_to() + self.cleanup() From 2176e4e2d402318713b08a7004317a742effc2b1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Oct 2011 16:05:11 +0200 Subject: [PATCH 0475/4212] begin new type type (no typo) Signed-off-by: Nico Schottelius --- lib/cdist/type.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 lib/cdist/type.py diff --git a/lib/cdist/type.py b/lib/cdist/type.py new file mode 100644 index 00000000..b0280660 --- /dev/null +++ b/lib/cdist/type.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 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 logging +import os +log = logging.getLogger(__name__) + +class Type(object): + + def __init__(self, path, remote_path): + self.path = path + self.remote_path = remote_path + + def list_explorers(self): + """Return list of available explorers""" + dir = os.path.join(self.path, "explorer") + if os.path.isdir(dir): + list = os.listdir(dir) + else: + list = [] + + log.debug("Explorers for %s in %s: %s", type, dir, list) + + return list + + def is_install(self): + """Check whether a type is used for installation (if not: for configuration)""" + return os.path.isfile(os.path.join(self.path, "install")) + + # FIXME: Type + def type_dir(self, type, *args): + """Return (sub-)directory of a type""" + return os.path.join(self.type_base_dir, type, *args) + + # FIXME: Type + def remote_type_explorer_dir(self, type): + """Return remote directory that holds the explorers of a type""" + return os.path.join(REMOTE_TYPE_DIR, type, "explorer") From 099adec61fb22ca2b79005612980035326718ebd Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 5 Oct 2011 16:08:29 +0200 Subject: [PATCH 0476/4212] start working on object class Signed-off-by: Steven Armstrong --- lib/cdist/object.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 lib/cdist/object.py diff --git a/lib/cdist/object.py b/lib/cdist/object.py new file mode 100644 index 00000000..396d8e48 --- /dev/null +++ b/lib/cdist/object.py @@ -0,0 +1,33 @@ +# -*- 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 logging +log = logging.getLogger(__name__) + + + +class Object(object): + def __init__(self, path, remote_path): + self.path = path + self.remote_path = remote_path + + From 68889c4bf7a5281cab51a8be0ba7fa7ca40c4da7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Oct 2011 16:12:25 +0200 Subject: [PATCH 0477/4212] finish type, shrink path Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 31 +------------------------------ lib/cdist/type.py | 10 ++-------- 2 files changed, 3 insertions(+), 38 deletions(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 5cde357b..e709e6fe 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -171,30 +171,11 @@ class Path: """Return list of available explorers""" return os.listdir(self.global_explorer_dir) - # FIXME: Type - only needs to know its path - def list_type_explorers(self, type): - """Return list of available explorers for a specific type""" - dir = self.type_dir(type, "explorer") - if os.path.isdir(dir): - list = os.listdir(dir) - else: - list = [] - - log.debug("Explorers for %s in %s: %s", type, dir, list) - - return list - # Stays here def list_types(self): """Retuns list of types""" return os.listdir(self.type_base_dir) - # FIXME: type - def is_install_type(self, type): - """Check whether a type is used for installation (if not: for configuration)""" - marker = os.path.join(self.type_dir(type), "install") - return os.path.isfile(marker) - # Stays here def list_object_paths(self, starting_point): """Return list of paths of existing objects""" @@ -260,16 +241,6 @@ class Path: return objects - # FIXME: Type - def type_dir(self, type, *args): - """Return (sub-)directory of a type""" - return os.path.join(self.type_base_dir, type, *args) - - # FIXME: Type - def remote_type_explorer_dir(self, type): - """Return remote directory that holds the explorers of a type""" - return os.path.join(REMOTE_TYPE_DIR, type, "explorer") - # Stays here def transfer_object_parameter(self, cdist_object): """Transfer the object parameter to the remote destination""" @@ -286,7 +257,7 @@ class Path: self.remote_mkdir(REMOTE_GLOBAL_EXPLORER_DIR) self.transfer_dir(self.global_explorer_dir, REMOTE_GLOBAL_EXPLORER_DIR) - # Stays here + # Stays here - FIXME: adjust to type code, loop over types! def transfer_type_explorers(self, type): """Transfer explorers of a type, but only once""" if type in self.type_explorers_transferred: diff --git a/lib/cdist/type.py b/lib/cdist/type.py index b0280660..e1c5f589 100644 --- a/lib/cdist/type.py +++ b/lib/cdist/type.py @@ -46,12 +46,6 @@ class Type(object): """Check whether a type is used for installation (if not: for configuration)""" return os.path.isfile(os.path.join(self.path, "install")) - # FIXME: Type - def type_dir(self, type, *args): - """Return (sub-)directory of a type""" - return os.path.join(self.type_base_dir, type, *args) - - # FIXME: Type - def remote_type_explorer_dir(self, type): + def remote_explorer_dir(self): """Return remote directory that holds the explorers of a type""" - return os.path.join(REMOTE_TYPE_DIR, type, "explorer") + return os.path.join(self.remote_path, "explorer") From a0c984acddbe9fc88c588d3b54901a6a40337faa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Oct 2011 16:38:19 +0200 Subject: [PATCH 0478/4212] config+install is broken now due to refactoring Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index a550c45e..8211f374 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -81,6 +81,7 @@ class ConfigInstall: cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=self.remote_prefix) output_fd.close() +# FIXME: where to call this from? def run_type_explorer(self, cdist_object): """Run type specific explorers for objects""" @@ -97,6 +98,7 @@ class ConfigInstall: # Need to transfer at least the parameters for objects to be useful self.path.transfer_object_parameter(cdist_object) + # FIXME: Broken due to refactoring into type.py explorers = self.path.list_type_explorers(type) for explorer in explorers: remote_cmd = cmd + [os.path.join(self.path.remote_type_explorer_dir(type), explorer)] From 2e61e8b202e883a899413bd8c18e9ad04709f031 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 5 Oct 2011 16:44:22 +0200 Subject: [PATCH 0479/4212] finish object class Signed-off-by: Steven Armstrong --- lib/cdist/object.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/cdist/object.py b/lib/cdist/object.py index 396d8e48..0a282dc2 100644 --- a/lib/cdist/object.py +++ b/lib/cdist/object.py @@ -26,8 +26,26 @@ log = logging.getLogger(__name__) class Object(object): - def __init__(self, path, remote_path): + + def __init__(self, path, remote_path, object_fq): self.path = path self.remote_path = remote_path + self.object_fq = object_fq + self.type = self.object_fq.split(os.sep)[0] + self.object_id = self.object_fq.split(os.sep)[1:] + self.parameter_dir = os.path.join(self.path, "parameter") + self.remote_object_parameter_dir = os.path.join(self.remote_path, "parameter") + self.object_code_paths = [ + os.path.join(self.path, "code-local"), + os.path.join(self.path, "code-remote")] + @property + def type_explorer_output_dir(self): + """Returns and creates dir of the output for a type explorer""" + if not self.__type_explorer_output_dir: + dir = os.path.join(self.path, "explorer") + if not os.path.isdir(dir): + os.mkdir(dir) + self.__type_explorer_output_dir = dir + return self.__type_explorer_output_dir From 7f85aab3ef3b63a261be8da5e9edcc1c39765d2c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Oct 2011 16:45:10 +0200 Subject: [PATCH 0480/4212] add some pseudo code to adapt to changes Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 8211f374..9a84c2cf 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -260,6 +260,17 @@ class ConfigInstall: log.debug("Skipping rerun of object %s", cdist_object) continue else: + # FIXME: run_type_explorer: + # object can return type + # type has explorers + # path knows about where to save explorer output + # type = self.path.objects[object].type() + # self.path.types['type'].explorers() + # for explorer in explorers: + # output = cdist.exec.run_debug_or_fail_shell(explorer) + # if output: + # write_output_to(output, os.path.join(self.path.objects[object].explorer_dir(),explorer) ) + # self.run_type_explorer(cdist_object) self.run_type_manifest(cdist_object) self.objects_prepared.append(cdist_object) From f84cabffe35c720614a2d327cc3e3c1d799113b6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Oct 2011 16:49:20 +0200 Subject: [PATCH 0481/4212] cleanup path Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 54 ++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index e709e6fe..5a2b64d2 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -75,6 +75,7 @@ class Path: self.remote_user = remote_user self.remote_prefix = remote_prefix + # Input directories self.conf_dir = os.path.join(self.base_dir, "conf") self.cache_base_dir = os.path.join(self.base_dir, "cache") self.cache_dir = os.path.join(self.cache_base_dir, target_host) @@ -83,31 +84,27 @@ class Path: self.manifest_dir = os.path.join(self.conf_dir, "manifest") self.type_base_dir = os.path.join(self.conf_dir, "type") - self.out_dir = os.path.join(self.temp_dir, "out") - os.mkdir(self.out_dir) - - self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") - os.mkdir(self.global_explorer_out_dir) - - self.object_base_dir = os.path.join(self.out_dir, "object") - - # Setup binary directory + contents - self.bin_dir = os.path.join(self.out_dir, "bin") - os.mkdir(self.bin_dir) - - # List of type explorers transferred - self.type_explorers_transferred = {} - - # objects - self.objects_prepared = [] - # Mostly static, but can be overwritten on user demand if initial_manifest: self.initial_manifest = initial_manifest else: self.initial_manifest = os.path.join(self.manifest_dir, "init") - # FIXME: stays + # Output directories + self.out_dir = os.path.join(self.temp_dir, "out") + self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") + self.object_base_dir = os.path.join(self.out_dir, "object") + self.bin_dir = os.path.join(self.out_dir, "bin") + + # List of type explorers transferred + self.type_explorers_transferred = {} + + # objects prepared + self.objects_prepared = [] + + # Create directories + self.__init_out_dirs() + def cleanup(self): # Do not use in __del__: # http://docs.python.org/reference/datamodel.html#customization @@ -120,6 +117,20 @@ class Path: shutil.rmtree(self.cache_dir) shutil.move(self.temp_dir, self.cache_dir) + + def __init_out_dirs(self): + """Initialise output directory structure""" + os.mkdir(self.out_dir) + os.mkdir(self.global_explorer_out_dir) + os.mkdir(self.bin_dir) + + + # Stays here + def list_types(self): + """Retuns list of types""" + return os.listdir(self.type_base_dir) + + ###################################################################### # FIXME: belongs to here - clearify remote* def remote_mkdir(self, directory): @@ -171,11 +182,6 @@ class Path: """Return list of available explorers""" return os.listdir(self.global_explorer_dir) - # Stays here - def list_types(self): - """Retuns list of types""" - return os.listdir(self.type_base_dir) - # Stays here def list_object_paths(self, starting_point): """Return list of paths of existing objects""" From 50a3ad7993d08a6ac630007b49758337d6963fd3 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 6 Oct 2011 00:58:43 +0200 Subject: [PATCH 0482/4212] proof of concept object oriented aproach Signed-off-by: Steven Armstrong --- oo.py | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 oo.py diff --git a/oo.py b/oo.py new file mode 100644 index 00000000..dd33e0bc --- /dev/null +++ b/oo.py @@ -0,0 +1,242 @@ +import os +import tempfile + +# FIXME: change these to match your environment +os.environ['__cdist_base_dir'] = '/home/sar/vcs/cdist' +# FIXME: testing against the cache, change path +os.environ['__cdist_out_dir'] = '/home/sar/vcs/cdist/cache/sans-asteven-02.ethz.ch/out' + + +''' +cd /path/to/dir/with/this/file +ipython + + +In [1]: import oo + +In [2]: t = oo.Type('__mkfs') + +In [3]: t. +t.base_dir t.is_install t.list_type_names t.name t.path +t.explorers t.is_singleton t.list_types t.optional_parameters t.required_parameters + +In [3]: t.path +Out[3]: '/home/sar/vcs/cdist/conf/type/__mkfs' + +In [4]: t.required_parameters +Out[4]: ['type'] + +In [5]: t.optional_parameters +Out[5]: ['device', 'options', 'blocks'] + +In [6]: t.is +t.is_install t.is_singleton + +In [6]: t.is_singleton +Out[6]: False + +In [7]: o = oo.Object(t, 'dev/sda1') + +In [8]: o. +o.base_dir o.list_object_names o.list_type_names o.parameter o.qualified_name o.type +o.changed o.list_objects o.object_id o.path o.requirements + +In [8]: o.pa +o.parameter o.path + +In [8]: o.path +Out[8]: '/home/sar/vcs/cdist/cache/sans-asteven-02.ethz.ch/out/object/__mkfs/dev/sda1/.cdist' + +In [9]: o.changed +Out[9]: False + +In [10]: o.changed = True + +In [11]: # creates /home/sar/vcs/cdist/cache/sans-asteven-02.ethz.ch/out/object/__mkfs/dev/sda1/.cdist/changed + +In [12]: o.changed +Out[12]: True + +In [13]: o.changed = False + +In [14]: # removes /home/sar/vcs/cdist/cache/sans-asteven-02.ethz.ch/out/object/__mkfs/dev/sda1/.cdist/changed + +In [15]: + +''' + +class Type(object): + + @staticmethod + def base_dir(): + """Return the absolute path to the top level directory where types + are defined. + + Requires the environment variable '__cdist_base_dir' to be set. + + """ + return os.path.join( + os.environ['__cdist_base_dir'], + 'conf', + 'type' + ) + + @classmethod + def list_types(cls): + """Return a list of type instances""" + for type_name in cls.list_type_names(): + yield cls(type_name) + + @classmethod + def list_type_names(cls): + """Return a list of type names""" + return os.listdir(cls.base_dir()) + + + def __init__(self, name): + self.name = name + self.__explorers = None + self.__required_parameters = None + self.__optional_parameters = None + + def __repr__(self): + return '' % self.name + + @property + def path(self): + return os.path.join( + self.base_dir(), + self.name + ) + + @property + def is_singleton(self): + """Check whether a type is a singleton.""" + return os.path.isfile(os.path.join(self.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.path, "install")) + + @property + def explorers(self): + """Return a list of available explorers""" + if not self.__explorers: + try: + self.__explorers = os.listdir(os.path.join(self.path, "explorer")) + except EnvironmentError as e: + # error ignored + self.__explorers = [] + return self.__explorers + + @property + def required_parameters(self): + """Return a list of required parameters""" + if not self.__required_parameters: + parameters = [] + try: + with open(os.path.join(self.path, "parameter", "required")) as fd: + for line in fd: + parameters.append(line.strip()) + except EnvironmentError as e: + # error ignored + pass + finally: + self.__required_parameters = parameters + return self.__required_parameters + + @property + def optional_parameters(self): + """Return a list of optional parameters""" + if not self.__optional_parameters: + parameters = [] + try: + with open(os.path.join(self.path, "parameter", "optional")) as fd: + for line in fd: + parameters.append(line.strip()) + except EnvironmentError as e: + # error ignored + pass + finally: + self.__optional_parameters = parameters + return self.__optional_parameters + + +class Object(object): + + @staticmethod + def base_dir(): + """Return the absolute path to the top level directory where objects + are defined. + + Requires the environment variable '__cdist_out_dir' to be set. + + """ + base_dir = os.path.join( + os.environ['__cdist_out_dir'], + 'object' + ) + # FIXME: should directory be created elsewhere? + if not os.path.isdir(base_dir): + os.mkdir(base_dir) + return base_dir + + @classmethod + def list_objects(cls): + """Return a list of object instances""" + for object_name in cls.list_object_names(): + type_name = object_name.split(os.sep)[0] + object_id = os.sep.join(object_name.split(os.sep)[1:]) + yield cls(Type(type_name), object_id=object_id) + + @classmethod + def list_type_names(cls): + """Return a list of type names""" + return os.listdir(cls.base_dir()) + + @classmethod + def list_object_names(cls): + """Return a list of object names""" + for path, dirs, files in os.walk(cls.base_dir()): + # FIXME: use constant instead of string + if '.cdist' in dirs: + yield os.path.relpath(path, cls.base_dir()) + + def __init__(self, type, object_id=None, parameter=None, requirements=None): + self.type = type # instance of Type + self.object_id = object_id + self.qualified_name = os.path.join(self.type.name, self.object_id) + self.parameter = parameter or {} + self.requirements = requirements or [] + + def __repr__(self): + return '' % self.qualified_name + + @property + def path(self): + return os.path.join( + self.base_dir(), + self.qualified_name, + '.cdist' + ) + + @property + def changed(self): + """Check whether the object has been changed.""" + return os.path.isfile(os.path.join(self.path, "changed")) + + @changed.setter + def changed(self, value): + """Change the objects changed status.""" + path = os.path.join(self.path, "changed") + if value: + open(path, "w").close() + else: + try: + os.remove(path) + except EnvironmentError: + # ignore + pass + + # FIXME: implement other properties/methods From f262cc4ccf1110365f92ce35c1fc83288ebb8f53 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 6 Oct 2011 01:04:09 +0200 Subject: [PATCH 0483/4212] ++example usage Signed-off-by: Steven Armstrong --- oo.py | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/oo.py b/oo.py index dd33e0bc..081b3e56 100644 --- a/oo.py +++ b/oo.py @@ -63,6 +63,129 @@ In [14]: # removes /home/sar/vcs/cdist/cache/sans-asteven-02.ethz.ch/out/object/ In [15]: + +----- + +In [1]: import oo + +In [2]: oo.Type. +oo.Type.base_dir oo.Type.is_install oo.Type.list_type_names oo.Type.mro oo.Type.path +oo.Type.explorers oo.Type.is_singleton oo.Type.list_types oo.Type.optional_parameters oo.Type.required_parameters + +In [2]: oo.Type.list +oo.Type.list_type_names oo.Type.list_types + +In [2]: oo.Type.list_type_names() +Out[2]: +['__addifnosuchline', + '__apt_ppa', + '__apt_update_index', + '__autofs_map', + '__autofs_master', + '__debconf_set_selections', + '__directory', + '__file', + '__group', + '__issue', + '__key_value', + '__link', + '__mkfs', + '__motd', + '__package', + '__package_apt', + '__package_pacman', + '__package_pkg_openbsd', + '__package_rubygem', + '__package_yum', + '__partition_msdos', + '__partition_msdos_apply', + '__postgres_database', + '__postgres_role', + '__process', + '__removeline', + '__ssh_authorized_key', + '__timezone', + '__user'] + +In [3]: list(oo.Type.list_types()) +Out[3]: +[, + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ] + +In [4]: + +In [4]: oo.Object. +oo.Object.base_dir oo.Object.changed oo.Object.list_object_names oo.Object.list_objects oo.Object.list_type_names oo.Object.mro oo.Object.path + +In [4]: oo.Object.list +oo.Object.list_object_names oo.Object.list_objects oo.Object.list_type_names + +In [4]: oo.Object.list_ob +oo.Object.list_object_names oo.Object.list_objects + +In [4]: oo.Object.list_object_names() +Out[4]: + +In [5]: list(oo.Object.list_object_names()) +Out[5]: +['__mkfs/dev/sda1', + '__mkfs/dev/sda2', + '__mkfs/dev/sda5', + '__mkfs/dev/sda6', + '__mkfs/dev/sda7', + '__partition_msdos/dev/sda1', + '__partition_msdos/dev/sda2', + '__partition_msdos/dev/sda3', + '__partition_msdos/dev/sda5', + '__partition_msdos/dev/sda6', + '__partition_msdos/dev/sda7', + '__partition_msdos_apply/singleton'] + +In [6]: list(oo.Object.list_objects()) +Out[6]: +[, + , + , + , + , + , + , + , + , + , + , + ] + +In [7]: + + ''' class Type(object): From 820eea56fb5a2cde0784eadedf6bf5710061a534 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 09:27:16 +0200 Subject: [PATCH 0484/4212] install finish Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 2 +- lib/cdist/type.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 9a84c2cf..39ee79c6 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -68,7 +68,7 @@ class ConfigInstall: log.info("Running global explorers") explorers = self.path.list_global_explorers() if(len(explorers) == 0): - raise CdistError("No explorers found in", self.path.global_explorer_dir) + raise CdistError("No explorers found in ", self.path.global_explorer_dir) self.path.transfer_global_explorers() for explorer in explorers: diff --git a/lib/cdist/type.py b/lib/cdist/type.py index e1c5f589..e6c35ad1 100644 --- a/lib/cdist/type.py +++ b/lib/cdist/type.py @@ -46,6 +46,10 @@ class Type(object): """Check whether a type is used for installation (if not: for configuration)""" return os.path.isfile(os.path.join(self.path, "install")) + def explorer_dir(self): + """Return remote directory that holds the explorers of a type""" + return os.path.join(self.remote_path, "explorer") + def remote_explorer_dir(self): """Return remote directory that holds the explorers of a type""" return os.path.join(self.remote_path, "explorer") From 5b70ff5694bfa18ad745987d9aee7c32a131eeb3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 12:07:50 +0200 Subject: [PATCH 0485/4212] whiteboard to file Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-06 | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 doc/dev/logs/2011-10-06 diff --git a/doc/dev/logs/2011-10-06 b/doc/dev/logs/2011-10-06 new file mode 100644 index 00000000..14edab51 --- /dev/null +++ b/doc/dev/logs/2011-10-06 @@ -0,0 +1,30 @@ +GlobalExplorer + list_explorers() + list_explorers_names() + + base_dir + __init__(name) + out_dir + env + name = id + path + return_code + return_value + +-------------------------------------------------------------------------------- +Exec: + +normal: + +scp /from/where $USER@$HOST:REMOTE_BASE/cdist-internal +ssh $USER@$HOST MY_CMD_THAT_NEEDS_TO_RUN_IN_BIN_SH (including ENV) + +sudo: + +scp $USER@$HOST:REMOTE_BASE/cdist-internal +ssh $USER@$HOST sudo MY_CMD_THAT_NEEDS_TO_RUN_IN_BIN_SH (including ENV) + +chroot: + +[sudo] cp file /chroot/THE_HOST_BASE/REMOTE_BASE/cdist-internal +[sudo] chroot /chroot MY_CMD_THAT_NEEDS_TO_RUN_IN_BIN_SH (including ENV) From 2ec2ab26ce95b967a82577409e42fdf745adba41 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 12:34:34 +0200 Subject: [PATCH 0486/4212] update path with changes from yesterday (system crash) Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 5a2b64d2..2fcf3aea 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -117,7 +117,7 @@ class Path: shutil.rmtree(self.cache_dir) shutil.move(self.temp_dir, self.cache_dir) - + def __init_out_dirs(self): """Initialise output directory structure""" os.mkdir(self.out_dir) From a4abb53ced22a5af16b6f0d68c90146c9e3dd423 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 6 Oct 2011 12:52:13 +0200 Subject: [PATCH 0487/4212] +MissingEnvironmentVariableError Signed-off-by: Steven Armstrong --- lib/cdist/__init__.py | 10 ++++++++++ oo.py => lib/cdist/core/object.py | 0 2 files changed, 10 insertions(+) rename oo.py => lib/cdist/core/object.py (100%) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index a0ca2ba2..864b4f37 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -24,3 +24,13 @@ VERSION = "2.0.3" class Error(Exception): """Base exception class for this project""" pass + + +class MissingEnvironmentVariableError(Error): + """Raised when a required environment variable is not set.""" + + def __init__(self, name) + self.name = name + + def __str__(self): + return 'Missing required environment variable: {0.name}'.format(o) diff --git a/oo.py b/lib/cdist/core/object.py similarity index 100% rename from oo.py rename to lib/cdist/core/object.py From cdba503ff279a67e0f99ff430952a822dd7e2a88 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 6 Oct 2011 12:57:38 +0200 Subject: [PATCH 0488/4212] move Object class into its own file Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 325 +++++---------------------------------- 1 file changed, 37 insertions(+), 288 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 081b3e56..c136390e 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -1,292 +1,37 @@ +# -*- 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 tempfile -# FIXME: change these to match your environment -os.environ['__cdist_base_dir'] = '/home/sar/vcs/cdist' -# FIXME: testing against the cache, change path -os.environ['__cdist_out_dir'] = '/home/sar/vcs/cdist/cache/sans-asteven-02.ethz.ch/out' - - -''' -cd /path/to/dir/with/this/file -ipython - - -In [1]: import oo - -In [2]: t = oo.Type('__mkfs') - -In [3]: t. -t.base_dir t.is_install t.list_type_names t.name t.path -t.explorers t.is_singleton t.list_types t.optional_parameters t.required_parameters - -In [3]: t.path -Out[3]: '/home/sar/vcs/cdist/conf/type/__mkfs' - -In [4]: t.required_parameters -Out[4]: ['type'] - -In [5]: t.optional_parameters -Out[5]: ['device', 'options', 'blocks'] - -In [6]: t.is -t.is_install t.is_singleton - -In [6]: t.is_singleton -Out[6]: False - -In [7]: o = oo.Object(t, 'dev/sda1') - -In [8]: o. -o.base_dir o.list_object_names o.list_type_names o.parameter o.qualified_name o.type -o.changed o.list_objects o.object_id o.path o.requirements - -In [8]: o.pa -o.parameter o.path - -In [8]: o.path -Out[8]: '/home/sar/vcs/cdist/cache/sans-asteven-02.ethz.ch/out/object/__mkfs/dev/sda1/.cdist' - -In [9]: o.changed -Out[9]: False - -In [10]: o.changed = True - -In [11]: # creates /home/sar/vcs/cdist/cache/sans-asteven-02.ethz.ch/out/object/__mkfs/dev/sda1/.cdist/changed - -In [12]: o.changed -Out[12]: True - -In [13]: o.changed = False - -In [14]: # removes /home/sar/vcs/cdist/cache/sans-asteven-02.ethz.ch/out/object/__mkfs/dev/sda1/.cdist/changed - -In [15]: - - ------ - -In [1]: import oo - -In [2]: oo.Type. -oo.Type.base_dir oo.Type.is_install oo.Type.list_type_names oo.Type.mro oo.Type.path -oo.Type.explorers oo.Type.is_singleton oo.Type.list_types oo.Type.optional_parameters oo.Type.required_parameters - -In [2]: oo.Type.list -oo.Type.list_type_names oo.Type.list_types - -In [2]: oo.Type.list_type_names() -Out[2]: -['__addifnosuchline', - '__apt_ppa', - '__apt_update_index', - '__autofs_map', - '__autofs_master', - '__debconf_set_selections', - '__directory', - '__file', - '__group', - '__issue', - '__key_value', - '__link', - '__mkfs', - '__motd', - '__package', - '__package_apt', - '__package_pacman', - '__package_pkg_openbsd', - '__package_rubygem', - '__package_yum', - '__partition_msdos', - '__partition_msdos_apply', - '__postgres_database', - '__postgres_role', - '__process', - '__removeline', - '__ssh_authorized_key', - '__timezone', - '__user'] - -In [3]: list(oo.Type.list_types()) -Out[3]: -[, - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ] - -In [4]: - -In [4]: oo.Object. -oo.Object.base_dir oo.Object.changed oo.Object.list_object_names oo.Object.list_objects oo.Object.list_type_names oo.Object.mro oo.Object.path - -In [4]: oo.Object.list -oo.Object.list_object_names oo.Object.list_objects oo.Object.list_type_names - -In [4]: oo.Object.list_ob -oo.Object.list_object_names oo.Object.list_objects - -In [4]: oo.Object.list_object_names() -Out[4]: - -In [5]: list(oo.Object.list_object_names()) -Out[5]: -['__mkfs/dev/sda1', - '__mkfs/dev/sda2', - '__mkfs/dev/sda5', - '__mkfs/dev/sda6', - '__mkfs/dev/sda7', - '__partition_msdos/dev/sda1', - '__partition_msdos/dev/sda2', - '__partition_msdos/dev/sda3', - '__partition_msdos/dev/sda5', - '__partition_msdos/dev/sda6', - '__partition_msdos/dev/sda7', - '__partition_msdos_apply/singleton'] - -In [6]: list(oo.Object.list_objects()) -Out[6]: -[, - , - , - , - , - , - , - , - , - , - , - ] - -In [7]: - - -''' - -class Type(object): - - @staticmethod - def base_dir(): - """Return the absolute path to the top level directory where types - are defined. - - Requires the environment variable '__cdist_base_dir' to be set. - - """ - return os.path.join( - os.environ['__cdist_base_dir'], - 'conf', - 'type' - ) - - @classmethod - def list_types(cls): - """Return a list of type instances""" - for type_name in cls.list_type_names(): - yield cls(type_name) - - @classmethod - def list_type_names(cls): - """Return a list of type names""" - return os.listdir(cls.base_dir()) - - - def __init__(self, name): - self.name = name - self.__explorers = None - self.__required_parameters = None - self.__optional_parameters = None - - def __repr__(self): - return '' % self.name - - @property - def path(self): - return os.path.join( - self.base_dir(), - self.name - ) - - @property - def is_singleton(self): - """Check whether a type is a singleton.""" - return os.path.isfile(os.path.join(self.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.path, "install")) - - @property - def explorers(self): - """Return a list of available explorers""" - if not self.__explorers: - try: - self.__explorers = os.listdir(os.path.join(self.path, "explorer")) - except EnvironmentError as e: - # error ignored - self.__explorers = [] - return self.__explorers - - @property - def required_parameters(self): - """Return a list of required parameters""" - if not self.__required_parameters: - parameters = [] - try: - with open(os.path.join(self.path, "parameter", "required")) as fd: - for line in fd: - parameters.append(line.strip()) - except EnvironmentError as e: - # error ignored - pass - finally: - self.__required_parameters = parameters - return self.__required_parameters - - @property - def optional_parameters(self): - """Return a list of optional parameters""" - if not self.__optional_parameters: - parameters = [] - try: - with open(os.path.join(self.path, "parameter", "optional")) as fd: - for line in fd: - parameters.append(line.strip()) - except EnvironmentError as e: - # error ignored - pass - finally: - self.__optional_parameters = parameters - return self.__optional_parameters +import cdist class Object(object): + """Represents a cdist object. + + All interaction with objects in cdist should be done through this class. + Directly accessing an object through the file system from python code is + a bug. + + """ @staticmethod def base_dir(): @@ -296,10 +41,14 @@ class Object(object): Requires the environment variable '__cdist_out_dir' to be set. """ - base_dir = os.path.join( - os.environ['__cdist_out_dir'], - 'object' - ) + try: + base_dir = os.path.join( + os.environ['__cdist_out_dir'], + 'object' + ) + except KeyError as e: + raise cdist.MissingEnvironmentVariableError(e.args[0]) + # FIXME: should directory be created elsewhere? if not os.path.isdir(base_dir): os.mkdir(base_dir) From 080ca10e193a1889f82d3be7f4bcffb352e1a1a8 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 6 Oct 2011 12:58:08 +0200 Subject: [PATCH 0489/4212] new package cdist.core Signed-off-by: Steven Armstrong --- lib/cdist/core/__init__.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 lib/cdist/core/__init__.py diff --git a/lib/cdist/core/__init__.py b/lib/cdist/core/__init__.py new file mode 100644 index 00000000..80310ffc --- /dev/null +++ b/lib/cdist/core/__init__.py @@ -0,0 +1,25 @@ +# -*- 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 . +# +# + +__all__ = ['Type', 'Object'] + +from cdist.core.type import Type +from cdist.core.object import Object From aa1c13898aa6b66cb833036af43aef7facb0d363 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 13:00:00 +0200 Subject: [PATCH 0490/4212] add ideas about remote exec/copy Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot | 45 +++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot diff --git a/doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot b/doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot new file mode 100644 index 00000000..1dd9039d --- /dev/null +++ b/doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot @@ -0,0 +1,45 @@ +Commands needed: + conf/cmd/remote_exec + conf/cmd/copy + +If ! conf/cmd/remote_exec: + use builtin +If ! conf/cmd/copy: + use builtin + + -> Depend on session! + +Builtin: + cdist.exec.run_or_fail(["scp", "-qr", source, + self.remote_user + "@" + + self.target_host + ":" + + destination]) + +self.remote_prefix = ["ssh", self.remote_user + "@" + self.target_host] + + self.remote_user = remote_user + self.remote_prefix = remote_prefix + +-------------------------------------------------------------------------------- +What is in a session? + + base_dir + target_host + +-------------------------------------------------------------------------------- +remote_user + pseudo-static, can be hardcoded again +-------------------------------------------------------------------------------- + +Result: + +os.environ['__remote_exec'] = ["ssh", "-l", "root" ] +os.environ['__remote_copy'] = ["scp", "-o" "User=root" ] + +args for __remote_exec + $1 = hostname + $2 - ... = stuff to be executed in /bin/sh on remote side + +args for __remote_copy + $1 = file here + $2 = hostname:destination From 4de5f6f58ecef4068ccdd2e42f00268fe0693a1f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 6 Oct 2011 13:00:17 +0200 Subject: [PATCH 0491/4212] move Type into its own file Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 125 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 lib/cdist/core/type.py diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py new file mode 100644 index 00000000..c35e0ad8 --- /dev/null +++ b/lib/cdist/core/type.py @@ -0,0 +1,125 @@ +# -*- 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 cdist + + +class Type(object): + + @staticmethod + def base_dir(): + """Return the absolute path to the top level directory where types + are defined. + + Requires the environment variable '__cdist_base_dir' to be set. + + """ + try: + return os.path.join( + os.environ['__cdist_base_dir'], + 'conf', + 'type' + ) + except KeyError as e: + raise cdist.MissingEnvironmentVariableError(e.args[0]) + + @classmethod + def list_types(cls): + """Return a list of type instances""" + for type_name in cls.list_type_names(): + yield cls(type_name) + + @classmethod + def list_type_names(cls): + """Return a list of type names""" + return os.listdir(cls.base_dir()) + + + def __init__(self, name): + self.name = name + self.__explorers = None + self.__required_parameters = None + self.__optional_parameters = None + + def __repr__(self): + return '' % self.name + + @property + def path(self): + return os.path.join( + self.base_dir(), + self.name + ) + + @property + def is_singleton(self): + """Check whether a type is a singleton.""" + return os.path.isfile(os.path.join(self.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.path, "install")) + + @property + def explorers(self): + """Return a list of available explorers""" + if not self.__explorers: + try: + self.__explorers = os.listdir(os.path.join(self.path, "explorer")) + except EnvironmentError as e: + # error ignored + self.__explorers = [] + return self.__explorers + + @property + def required_parameters(self): + """Return a list of required parameters""" + if not self.__required_parameters: + parameters = [] + try: + with open(os.path.join(self.path, "parameter", "required")) as fd: + for line in fd: + parameters.append(line.strip()) + except EnvironmentError as e: + # error ignored + pass + finally: + self.__required_parameters = parameters + return self.__required_parameters + + @property + def optional_parameters(self): + """Return a list of optional parameters""" + if not self.__optional_parameters: + parameters = [] + try: + with open(os.path.join(self.path, "parameter", "optional")) as fd: + for line in fd: + parameters.append(line.strip()) + except EnvironmentError as e: + # error ignored + pass + finally: + self.__optional_parameters = parameters + return self.__optional_parameters From 41ab7390dbb223415d15387507a9aaaccb585483 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 6 Oct 2011 13:02:08 +0200 Subject: [PATCH 0492/4212] use constant instead of string for .cdist Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index c136390e..80c2c351 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -22,6 +22,7 @@ import os import cdist +import cdist.path class Object(object): @@ -72,7 +73,7 @@ class Object(object): """Return a list of object names""" for path, dirs, files in os.walk(cls.base_dir()): # FIXME: use constant instead of string - if '.cdist' in dirs: + if cdist.path.DOT_CDIST in dirs: yield os.path.relpath(path, cls.base_dir()) def __init__(self, type, object_id=None, parameter=None, requirements=None): @@ -90,7 +91,7 @@ class Object(object): return os.path.join( self.base_dir(), self.qualified_name, - '.cdist' + cdist.path.DOT_CDIST ) @property From c0f04cab0f5e9ed0d0b70114111f46c6ad64dc90 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 13:20:05 +0200 Subject: [PATCH 0493/4212] more hints on env Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot | 22 ++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot b/doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot index 1dd9039d..91f5d204 100644 --- a/doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot +++ b/doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot @@ -7,6 +7,12 @@ If ! conf/cmd/remote_exec: If ! conf/cmd/copy: use builtin +-------------------------------------------------------------------------------- + +--cmd-dir? +$__cdist_cmd_dir + +-------------------------------------------------------------------------------- -> Depend on session! Builtin: @@ -34,12 +40,26 @@ remote_user Result: os.environ['__remote_exec'] = ["ssh", "-l", "root" ] -os.environ['__remote_copy'] = ["scp", "-o" "User=root" ] + +os.environ['__remote_exec'] = ["ssh", "-o", "User=root" ] +os.environ['__remote_copy'] = ["scp", "-o", "User=root" ] args for __remote_exec $1 = hostname $2 - ... = stuff to be executed in /bin/sh on remote side + $2 - $7 = env + $7 - 12 = cmd + args for __remote_copy $1 = file here $2 = hostname:destination + +-------------------------------------------------------------------------------- +There needs to be an easy way to change those cmds! +-------------------------------------------------------------------------------- +Env-Passing: + _a=b test -> test can access $_a + _a=b test $_a -> $1 = "", because _a is *not* set within the shell + _a=b; test -> can access $_a + _a=b; test $_a -> $1 == "b" From a15972f20da781f61767b060a1243bb2a53ca5ad Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 6 Oct 2011 13:21:48 +0200 Subject: [PATCH 0494/4212] +docstring Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index c35e0ad8..126b4d16 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -25,6 +25,13 @@ import cdist class Type(object): + """Represents a cdist type. + + All interaction with types in cdist should be done through this class. + Directly accessing an type through the file system from python code is + a bug. + + """ @staticmethod def base_dir(): From eaf2b28fd7b9af740b511657ad66d2e3f52fa3cb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 13:34:28 +0200 Subject: [PATCH 0495/4212] more prefix ideas Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot b/doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot index 91f5d204..ec89a999 100644 --- a/doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot +++ b/doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot @@ -44,6 +44,28 @@ os.environ['__remote_exec'] = ["ssh", "-l", "root" ] os.environ['__remote_exec'] = ["ssh", "-o", "User=root" ] os.environ['__remote_copy'] = ["scp", "-o", "User=root" ] + +__remote_exec=~/sudossh __remote_copy=... cdist config localhost + +~/sudossh hostname $@... +~/sudocopy a hostname:b + +~/chrootssh +~/chrootcopy + + + +a) + 3 cmd verzeichnnise: cdist, sudo, chroot + pro aufruf variable ändern + +b) + 1 dir, mit zeug + pro aufruf variablen ändern + + +conf/cmd/remote_exec + args for __remote_exec $1 = hostname $2 - ... = stuff to be executed in /bin/sh on remote side From ecc4fc10d73b8c56d2203e67803b3154a8a066f0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 13:34:45 +0200 Subject: [PATCH 0496/4212] setup __remote_exec and __remote_copy variables Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index 51615c28..43d4bf51 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -297,6 +297,9 @@ def config(args): time_start = datetime.datetime.now() + os.environ['__remote_exec'] = ["ssh", "-o", "User=root" ] + os.environ['__remote_copy'] = ["scp", "-o", "User=root" ] + for host in args.host: c = Config(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) if args.parallel: From 278c379e077b398685db1ebff5d72ddcc4f9b78e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 13:37:12 +0200 Subject: [PATCH 0497/4212] use os.environ['__remote_exec'] in exec* Signed-off-by: Nico Schottelius --- lib/cdist/exec.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index 9cedefcc..aaa2c13f 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -20,6 +20,7 @@ # import logging +import os import subprocess log = logging.getLogger(__name__) @@ -32,7 +33,7 @@ def shell_run_or_debug_fail(script, *args, remote_prefix=False, **kargs): args[0][:0] = [ "/bin/sh", "-e" ] if remote_prefix: - args[0][:0] = remote_prefix + args[0][:0] = os.environ['__remote_exec'] log.debug("Shell exec cmd: %s", args) @@ -43,8 +44,8 @@ def shell_run_or_debug_fail(script, *args, remote_prefix=False, **kargs): subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: log.error("Code that raised the error:\n") - if remote_prefix: - run_or_fail(["cat", script], remote_prefix=remote_prefix) + + run_or_fail(["cat", script], remote_prefix=remote_prefix) else: try: @@ -60,7 +61,7 @@ def shell_run_or_debug_fail(script, *args, remote_prefix=False, **kargs): def run_or_fail(*args, remote_prefix=False, **kargs): if remote_prefix: - args[0][:0] = remote_prefix + args[0][:0] = os.environ['__remote_exec'] log.debug("Exec: " + " ".join(*args)) try: From eea6a38f3342d38973fcc79ebdf4204dc94cc831 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 13:39:08 +0200 Subject: [PATCH 0498/4212] cat only locally :-) Signed-off-by: Nico Schottelius --- lib/cdist/exec.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index aaa2c13f..bb375404 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -45,7 +45,8 @@ def shell_run_or_debug_fail(script, *args, remote_prefix=False, **kargs): except subprocess.CalledProcessError: log.error("Code that raised the error:\n") - run_or_fail(["cat", script], remote_prefix=remote_prefix) + if remote_prefix: + run_or_fail(["cat", script], remote_prefix=remote_prefix) else: try: From df630e1fdf0da5049a802717e039baa75a2f734f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 13:40:46 +0200 Subject: [PATCH 0499/4212] user remote_prefix=True now Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index 43d4bf51..81c5b3fc 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -38,23 +38,16 @@ class Config: def __init__(self, target_host, initial_manifest=False, - remote_user="root", home=None, exec_path=sys.argv[0], debug=False): self.target_host = target_host self.debug = debug - self.remote_user = remote_user self.exec_path = exec_path - # FIXME: broken - construct elsewhere! - self.remote_prefix = ["ssh", self.remote_user + "@" + self.target_host] - self.path = cdist.path.Path(self.target_host, initial_manifest=initial_manifest, - remote_user=self.remote_user, - remote_prefix=self.remote_prefix, base_dir=home, debug=debug) @@ -78,7 +71,7 @@ class Config: cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) cmd.append(self.path.remote_global_explorer_path(explorer)) - cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=self.remote_prefix) + cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=True) output_fd.close() def run_type_explorer(self, cdist_object): @@ -105,7 +98,7 @@ class Config: log.debug("%s exploring %s using %s storing to %s", cdist_object, explorer, remote_cmd, output) - cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=self.remote_prefix) + cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=True) output_fd.close() def link_emulator(self): @@ -235,8 +228,7 @@ class Config: remote_remote_code = os.path.join(remote_dir, "code-remote") if os.path.isfile(local_remote_code): self.path.transfer_file(local_remote_code, remote_remote_code) - # FIXME: remote_prefix - cdist.exec.run_or_fail([remote_remote_code], remote_prefix=self.remote_prefix) + cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" @@ -297,8 +289,8 @@ def config(args): time_start = datetime.datetime.now() - os.environ['__remote_exec'] = ["ssh", "-o", "User=root" ] - os.environ['__remote_copy'] = ["scp", "-o", "User=root" ] + os.environ['__remote_exec'] = "ssh -o User=root" + os.environ['__remote_copy'] = "scp -o User=root" for host in args.host: c = Config(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) From 59bee1410147bfc40eb6387d2363e27921e859a2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 14:02:37 +0200 Subject: [PATCH 0500/4212] begin to eliminate remote_user/prefix from path Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index e416c42d..721764bf 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -57,8 +57,6 @@ class Path: def __init__(self, target_host, - remote_user, - remote_prefix, initial_manifest=False, base_dir=None, debug=False): @@ -72,9 +70,6 @@ class Path: self.temp_dir = tempfile.mkdtemp() self.target_host = target_host - self.remote_user = remote_user - self.remote_prefix = remote_prefix - self.conf_dir = os.path.join(self.base_dir, "conf") self.cache_base_dir = os.path.join(self.base_dir, "cache") self.cache_dir = os.path.join(self.cache_base_dir, target_host) @@ -122,10 +117,10 @@ class Path: def remote_mkdir(self, directory): """Create directory on remote side""" - cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=self.remote_prefix) + cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) def remove_remote_dir(self, destination): - cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=self.remote_prefix) + cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) def transfer_dir(self, source, destination): """Transfer directory and previously delete the remote destination""" From 0d9906b0b8f678a2359bc6728aef81753d0456ef Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 6 Oct 2011 15:18:06 +0200 Subject: [PATCH 0501/4212] --typo, missing colon Signed-off-by: Steven Armstrong --- lib/cdist/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 864b4f37..1f325a8c 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -29,7 +29,7 @@ class Error(Exception): class MissingEnvironmentVariableError(Error): """Raised when a required environment variable is not set.""" - def __init__(self, name) + def __init__(self, name): self.name = name def __str__(self): From 5a7e4b2f322aaf06fcb422b72fabbcda3ae9bbf8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 15:48:44 +0200 Subject: [PATCH 0502/4212] quiet ssh/scp Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index 81c5b3fc..7b59d416 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -289,8 +289,8 @@ def config(args): time_start = datetime.datetime.now() - os.environ['__remote_exec'] = "ssh -o User=root" - os.environ['__remote_copy'] = "scp -o User=root" + os.environ['__remote_exec'] = "ssh -o User=root -q" + os.environ['__remote_copy'] = "scp -o User=root -q" for host in args.host: c = Config(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) From 919f67184a01bde6f45d3e36e1d94ff5a9503cbf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 15:49:08 +0200 Subject: [PATCH 0503/4212] do not reference scp anymore Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 721764bf..a2b47610 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -125,17 +125,13 @@ class Path: def transfer_dir(self, source, destination): """Transfer directory and previously delete the remote destination""" self.remove_remote_dir(destination) - cdist.exec.run_or_fail(["scp", "-qr", source, - self.remote_user + "@" + - self.target_host + ":" + - destination]) + cdist.exec.run_or_fail([os.environ['__remote_copy'], "-r", source, + self.target_host + ":" + destination]) def transfer_file(self, source, destination): """Transfer file""" - cdist.exec.run_or_fail(["scp", "-q", source, - self.remote_user + "@" + - self.target_host + ":" + - destination]) + cdist.exec.run_or_fail([os.environ['__remote_copy'], source, + self.target_host + ":" + destination]) def global_explorer_output_path(self, explorer): """Returns path of the output for a global explorer""" From 26278b1e326a4b8951e6df433b9b352985968f71 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 16:28:21 +0200 Subject: [PATCH 0504/4212] expose target host from config Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index 7b59d416..c027da17 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -43,6 +43,8 @@ class Config: debug=False): self.target_host = target_host + os.environ['target_host'] = target_host + self.debug = debug self.exec_path = exec_path From 8b561fd63ca886d20644d1e8f977258c9074947c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 16:30:06 +0200 Subject: [PATCH 0505/4212] fixup correct split/insert of os.environ() for target_host and args Signed-off-by: Nico Schottelius --- lib/cdist/exec.py | 8 ++++++-- lib/cdist/path.py | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index bb375404..a9b8d147 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -33,7 +33,9 @@ def shell_run_or_debug_fail(script, *args, remote_prefix=False, **kargs): args[0][:0] = [ "/bin/sh", "-e" ] if remote_prefix: - args[0][:0] = os.environ['__remote_exec'] + remote_prefix = os.environ['__remote_exec'].split() + remote_prefix.append(os.environ['target_host']) + args[0][:0] = remote_prefix log.debug("Shell exec cmd: %s", args) @@ -62,7 +64,9 @@ def shell_run_or_debug_fail(script, *args, remote_prefix=False, **kargs): def run_or_fail(*args, remote_prefix=False, **kargs): if remote_prefix: - args[0][:0] = os.environ['__remote_exec'] + remote_prefix = os.environ['__remote_exec'].split() + remote_prefix.append(os.environ['target_host']) + args[0][:0] = remote_prefix log.debug("Exec: " + " ".join(*args)) try: diff --git a/lib/cdist/path.py b/lib/cdist/path.py index a2b47610..85d1a87f 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -125,13 +125,13 @@ class Path: def transfer_dir(self, source, destination): """Transfer directory and previously delete the remote destination""" self.remove_remote_dir(destination) - cdist.exec.run_or_fail([os.environ['__remote_copy'], "-r", source, - self.target_host + ":" + destination]) + cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + + ["-r", source, self.target_host + ":" + destination]) def transfer_file(self, source, destination): """Transfer file""" - cdist.exec.run_or_fail([os.environ['__remote_copy'], source, - self.target_host + ":" + destination]) + cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + + [source, self.target_host + ":" + destination]) def global_explorer_output_path(self, explorer): """Returns path of the output for a global explorer""" From 063fc61291edc18b3c0205526f903dbee47b257c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 16:41:28 +0200 Subject: [PATCH 0506/4212] remove legacy manpage of cdist-type-emulator Signed-off-by: Nico Schottelius --- doc/man/man1/cdist-type-emulator.text | 56 --------------------------- 1 file changed, 56 deletions(-) delete mode 100644 doc/man/man1/cdist-type-emulator.text diff --git a/doc/man/man1/cdist-type-emulator.text b/doc/man/man1/cdist-type-emulator.text deleted file mode 100644 index 507c1054..00000000 --- a/doc/man/man1/cdist-type-emulator.text +++ /dev/null @@ -1,56 +0,0 @@ -cdist-type-emulator(1) -====================== -Nico Schottelius - - -NAME ----- -cdist-type-emulator - Emulate type and record parameters and dependencies - - -SYNOPSIS --------- -cdist-type-emulator [TYPE ARGS] - - -DESCRIPTION ------------ -cdist-type-emulator is normally called through a link to it of the -name of a specifc type. It saves the given parameters into -a parameters directory and the requirements into a require file. - -It checks whether the parameters are valid: - -- are required parameter given? -- are all other required parameters specified as optional? - - -EXAMPLES --------- -Your manifest may contain stuff like this: - - --------------------------------------------------------------------------------- -__addifnosuchline /tmp/linetest --line "test" - -__motd --------------------------------------------------------------------------------- - -In both cases, cdist-type-emulator is called instead of a real type. -In the first case, the object id "/tmp/linetest" is recorded and the -parameter "line" stored with the content "test". - -In the second case, __motd must be decleared as a singleton, as the -object id is missing. - - -SEE ALSO --------- -- cdist(7) -- cdist-type-build-emulation(1) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). From afa3920ca987347c50ffd44f9b4d11a3d28f37d3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 16:42:45 +0200 Subject: [PATCH 0507/4212] remove more obsolete manpages Signed-off-by: Nico Schottelius --- doc/man/man1/cdist-config.text | 48 ----------------------------- doc/man/man1/cdist-env.text | 49 ------------------------------ doc/man/man1/cdist-quickstart.text | 47 ---------------------------- 3 files changed, 144 deletions(-) delete mode 100644 doc/man/man1/cdist-config.text delete mode 100644 doc/man/man1/cdist-env.text delete mode 100644 doc/man/man1/cdist-quickstart.text diff --git a/doc/man/man1/cdist-config.text b/doc/man/man1/cdist-config.text deleted file mode 100644 index 0c8b0735..00000000 --- a/doc/man/man1/cdist-config.text +++ /dev/null @@ -1,48 +0,0 @@ -cdist-config(1) -=============== -Nico Schottelius - - -NAME ----- -cdist-config - Read basic cdist configuration - - -DESCRIPTION ------------ -Cdist-config is sourced by cdist programs and provides hints on where to find -types, manifests, etc. Generally speaking, it's just usable from within the -core and is only of interest for cdist-developers. - - -ENVIRONMENT VARIABLES ---------------------- -The following list contains environment variables that are known -to be changed by users in various situations. To change the variable, -use your current shell and export it, so all cdist-binaries know about it. - -__cdist_tmp_base_dir:: - Normally this points to /tmp. In case /tmp is not suitable for - cdist (i.e. has noexec flag setup) you can change this variable - to point to a better location. - - -EXAMPLES --------- - -If /tmp has the noexec flag, you can use $HOME/.tmp for instance: - --------------------------------------------------------------------------------- -export __cdist_tmp_base_dir=$HOME/.tmp --------------------------------------------------------------------------------- - - -SEE ALSO --------- -cdist(7) - - -COPYING -------- -Copyright \(C) 2010-2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-env.text b/doc/man/man1/cdist-env.text deleted file mode 100644 index 9a736133..00000000 --- a/doc/man/man1/cdist-env.text +++ /dev/null @@ -1,49 +0,0 @@ -cdist-env(1) -============ -Nico Schottelius - - -NAME ----- -cdist-env - Setup environment for using cdist - - -SYNOPSIS --------- -cdist-env - - -DESCRIPTION ------------ -cdist-env outputs two strings suitable for usage in your current shell, -so you can use cdist from the checkout. cdist-env essentially helps you -to easily setup PATH and MANPATH. - -If you've multiple checkouts of cdist and run cdist-env from the various -checkouts, a new run will prepend the last directory, thus ensures you -can run it multiple times and does what one expects. - -EXAMPLES --------- -For use in bourne shell variants (like dash, bash, ksh) as well as -in csh variants (csh, tcsh): - --------------------------------------------------------------------------------- -eval `./bin/cdist-env` --------------------------------------------------------------------------------- - -For bourne shell, there is also a shorter version: --------------------------------------------------------------------------------- -. ./bin/cdist-env --------------------------------------------------------------------------------- - - -SEE ALSO --------- -cdist(7) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man1/cdist-quickstart.text b/doc/man/man1/cdist-quickstart.text deleted file mode 100644 index 087fd2d5..00000000 --- a/doc/man/man1/cdist-quickstart.text +++ /dev/null @@ -1,47 +0,0 @@ -cdist-quickstart(1) -=================== -Nico Schottelius - -NAME ----- -cdist-quickstart - Make use of cinit in 5 minutes - - -SYNOPSIS --------- -cdist-quickstart - - -DESCRIPTION ------------ -cdist-quickstart is an interactive guide to cdist. It should be one -of the first tools you use when you begin with cdist. - - -EXAMPLES --------- -To use cdist-quickstart, add the bin directory to your PATH, execute -cdist-quickstart and enjoy cdist: - --------------------------------------------------------------------------------- -# Bourne shell example -export PATH=$(pwd -P)/bin:$PATH - -# Alternatively, usable for csh and bsh, set's up PATH and MANPATH -eval `./bin/cdist-env` - -# Let's go! -cdist-quickstart --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist(7) -- cdist-env(1) - - -COPYING -------- -Copyright \(C) 2010-2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). From 7c11fa09378e63c49a52114f80f5d9e00919453f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 16:49:27 +0200 Subject: [PATCH 0508/4212] introduce unclear changes (names not yet decided) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 632ddb45..798c90e0 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,6 +1,7 @@ 2.0.3: * Improved logging, added --verbose, by more quiet by default * Bugfix __user: Correct quoting (Steven Armstrong) + * FIXME: Support for __remote_exec and __remote_copy 2.0.2: 2011-09-27 * Add support for detection of OpenWall Linux (Matthias Teege) From 1c8a14339759aece4029e8ca8452b22bca3a9753 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 16:52:56 +0200 Subject: [PATCH 0509/4212] commit previously missed change Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 429 +++++++++++++++++------------------- 1 file changed, 202 insertions(+), 227 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 39ee79c6..4829061b 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -31,276 +31,251 @@ import cdist.path log = logging.getLogger(__name__) -CODE_HEADER = "#!/bin/sh -e\n" +CODE_HEADER = "#!/bin/sh -e\n" class ConfigInstall: - """Class to hold install and config methods""" + """Cdist main class to hold arbitrary data""" - def __init__(self, target_host, - initial_manifest=False, - remote_user="root", - home=None, - exec_path=sys.argv[0], - debug=False): + def __init__(self, target_host, + initial_manifest=False, + home=None, + exec_path=sys.argv[0], + debug=False): - self.target_host = target_host - self.debug = debug - self.remote_user = remote_user - self.exec_path = exec_path + self.target_host = target_host + os.environ['target_host'] = target_host - # FIXME: broken - construct elsewhere! - self.remote_prefix = ["ssh", self.remote_user + "@" + self.target_host] + self.debug = debug + self.exec_path = exec_path - self.path = cdist.path.Path(self.target_host, - initial_manifest=initial_manifest, - remote_user=self.remote_user, - remote_prefix=self.remote_prefix, - base_dir=home, - debug=debug) - - self.objects_prepared = [] + self.path = cdist.path.Path(self.target_host, + initial_manifest=initial_manifest, + base_dir=home, + debug=debug) + + self.objects_prepared = [] - def cleanup(self): - self.path.cleanup() + def cleanup(self): + self.path.cleanup() - def run_global_explorers(self): - """Run global explorers""" - log.info("Running global explorers") - explorers = self.path.list_global_explorers() - if(len(explorers) == 0): - raise CdistError("No explorers found in ", self.path.global_explorer_dir) + def run_global_explores(self): + """Run global explorers""" + log.info("Running global explorers") + explorers = self.path.list_global_explorers() + if(len(explorers) == 0): + raise CdistError("No explorers found in", self.path.global_explorer_dir) - self.path.transfer_global_explorers() - for explorer in explorers: - output = self.path.global_explorer_output_path(explorer) - output_fd = open(output, mode='w') - cmd = [] - cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append(self.path.remote_global_explorer_path(explorer)) + self.path.transfer_global_explorers() + for explorer in explorers: + output = self.path.global_explorer_output_path(explorer) + output_fd = open(output, mode='w') + cmd = [] + cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append(self.path.remote_global_explorer_path(explorer)) - cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=self.remote_prefix) - output_fd.close() + cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=True) + output_fd.close() -# FIXME: where to call this from? - def run_type_explorer(self, cdist_object): - """Run type specific explorers for objects""" + def run_type_explorer(self, cdist_object): + """Run type specific explorers for objects""" - type = self.path.get_type_from_object(cdist_object) - self.path.transfer_type_explorers(type) + type = self.path.get_type_from_object(cdist_object) + self.path.transfer_type_explorers(type) - cmd = [] - cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append("__type_explorer=" + self.path.remote_type_explorer_dir(type)) - cmd.append("__object=" + self.path.remote_object_dir(cdist_object)) - cmd.append("__object_id=" + self.path.get_object_id_from_object(cdist_object)) - cmd.append("__object_fq=" + cdist_object) + cmd = [] + cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) + cmd.append("__type_explorer=" + self.path.remote_type_explorer_dir(type)) + cmd.append("__object=" + self.path.remote_object_dir(cdist_object)) + cmd.append("__object_id=" + self.path.get_object_id_from_object(cdist_object)) + cmd.append("__object_fq=" + cdist_object) - # Need to transfer at least the parameters for objects to be useful - self.path.transfer_object_parameter(cdist_object) + # Need to transfer at least the parameters for objects to be useful + self.path.transfer_object_parameter(cdist_object) - # FIXME: Broken due to refactoring into type.py - explorers = self.path.list_type_explorers(type) - for explorer in explorers: - remote_cmd = cmd + [os.path.join(self.path.remote_type_explorer_dir(type), explorer)] - output = os.path.join(self.path.type_explorer_output_dir(cdist_object), explorer) - output_fd = open(output, mode='w') - log.debug("%s exploring %s using %s storing to %s", - cdist_object, explorer, remote_cmd, output) - - cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=self.remote_prefix) - output_fd.close() + explorers = self.path.list_type_explorers(type) + for explorer in explorers: + remote_cmd = cmd + [os.path.join(self.path.remote_type_explorer_dir(type), explorer)] + output = os.path.join(self.path.type_explorer_output_dir(cdist_object), explorer) + output_fd = open(output, mode='w') + log.debug("%s exploring %s using %s storing to %s", + cdist_object, explorer, remote_cmd, output) + + cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=True) + output_fd.close() - def link_emulator(self): - """Link emulator to types""" - cdist.emulator.link(self.exec_path, - self.path.bin_dir, self.path.list_types()) + def link_emulator(self): + """Link emulator to types""" + cdist.emulator.link(self.exec_path, + self.path.bin_dir, self.path.list_types()) - def init_deploy(self): - """Ensure the base directories are cleaned up""" - log.debug("Creating clean directory structure") + def init_deploy(self): + """Ensure the base directories are cleaned up""" + log.debug("Creating clean directory structure") - self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) - self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) - self.link_emulator() + self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) + self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) + self.link_emulator() - def run_initial_manifest(self): - """Run the initial manifest""" - log.info("Running initial manifest %s", self.path.initial_manifest) - env = { "__manifest" : self.path.manifest_dir } - self.run_manifest(self.path.initial_manifest, extra_env=env) + def run_initial_manifest(self): + """Run the initial manifest""" + log.info("Running initial manifest %s", self.path.initial_manifest) + env = { "__manifest" : self.path.manifest_dir } + self.run_manifest(self.path.initial_manifest, extra_env=env) - def run_type_manifest(self, cdist_object): - """Run manifest for a specific object""" - type = self.path.get_type_from_object(cdist_object) - manifest = self.path.type_dir(type, "manifest") - - log.debug("%s: Running %s", cdist_object, manifest) - if os.path.exists(manifest): - env = { "__object" : self.path.object_dir(cdist_object), - "__object_id": self.path.get_object_id_from_object(cdist_object), - "__object_fq": cdist_object, - "__type": self.path.type_dir(type) - } - self.run_manifest(manifest, extra_env=env) + def run_type_manifest(self, cdist_object): + """Run manifest for a specific object""" + type = self.path.get_type_from_object(cdist_object) + manifest = self.path.type_dir(type, "manifest") + + log.debug("%s: Running %s", cdist_object, manifest) + if os.path.exists(manifest): + env = { "__object" : self.path.object_dir(cdist_object), + "__object_id": self.path.get_object_id_from_object(cdist_object), + "__object_fq": cdist_object, + "__type": self.path.type_dir(type) + } + self.run_manifest(manifest, extra_env=env) - def run_manifest(self, manifest, extra_env=None): - """Run a manifest""" - log.debug("Running manifest %s, env=%s", manifest, extra_env) - env = os.environ.copy() - env['PATH'] = self.path.bin_dir + ":" + env['PATH'] + def run_manifest(self, manifest, extra_env=None): + """Run a manifest""" + log.debug("Running manifest %s, env=%s", manifest, extra_env) + env = os.environ.copy() + env['PATH'] = self.path.bin_dir + ":" + env['PATH'] - # Information required in every manifest - env['__target_host'] = self.target_host - env['__global'] = self.path.out_dir - - # Submit debug flag to manifest, can be used by emulator and types - if self.debug: - env['__debug'] = "yes" + # Information required in every manifest + env['__target_host'] = self.target_host + env['__global'] = self.path.out_dir + + # Submit debug flag to manifest, can be used by emulator and types + if self.debug: + env['__debug'] = "yes" - # Required for recording source - env['__cdist_manifest'] = manifest + # Required for recording source + env['__cdist_manifest'] = manifest - # Required to find types - env['__cdist_type_base_dir'] = self.path.type_base_dir + # Required to find types + env['__cdist_type_base_dir'] = self.path.type_base_dir - # Other environment stuff - if extra_env: - env.update(extra_env) + # Other environment stuff + if extra_env: + env.update(extra_env) - cdist.exec.shell_run_or_debug_fail(manifest, [manifest], env=env) + cdist.exec.shell_run_or_debug_fail(manifest, [manifest], env=env) - def object_run(self, cdist_object, mode): - """Run gencode or code for an object""" - log.debug("Running %s from %s", mode, cdist_object) - file=os.path.join(self.path.object_dir(cdist_object), "require") - requirements = cdist.path.file_to_list(file) - type = self.path.get_type_from_object(cdist_object) - - for requirement in requirements: - log.debug("Object %s requires %s", cdist_object, requirement) - self.object_run(requirement, mode=mode) + def object_run(self, cdist_object, mode): + """Run gencode or code for an object""" + log.debug("Running %s from %s", mode, cdist_object) + file=os.path.join(self.path.object_dir(cdist_object), "require") + requirements = cdist.path.file_to_list(file) + type = self.path.get_type_from_object(cdist_object) + + for requirement in requirements: + log.debug("Object %s requires %s", cdist_object, requirement) + self.object_run(requirement, mode=mode) - # - # Setup env Variable: - # - env = os.environ.copy() - env['__target_host'] = self.target_host - env['__global'] = self.path.out_dir - env["__object"] = self.path.object_dir(cdist_object) - env["__object_id"] = self.path.get_object_id_from_object(cdist_object) - env["__object_fq"] = cdist_object - env["__type"] = self.path.type_dir(type) + # + # Setup env Variable: + # + env = os.environ.copy() + env['__target_host'] = self.target_host + env['__global'] = self.path.out_dir + env["__object"] = self.path.object_dir(cdist_object) + env["__object_id"] = self.path.get_object_id_from_object(cdist_object) + env["__object_fq"] = cdist_object + env["__type"] = self.path.type_dir(type) - if mode == "gencode": - paths = [ - self.path.type_dir(type, "gencode-local"), - self.path.type_dir(type, "gencode-remote") - ] - for bin in paths: - if os.path.isfile(bin): - # omit "gen" from gencode and use it for output base - outfile=os.path.join(self.path.object_dir(cdist_object), - os.path.basename(bin)[3:]) + if mode == "gencode": + paths = [ + self.path.type_dir(type, "gencode-local"), + self.path.type_dir(type, "gencode-remote") + ] + for bin in paths: + if os.path.isfile(bin): + # omit "gen" from gencode and use it for output base + outfile=os.path.join(self.path.object_dir(cdist_object), + os.path.basename(bin)[3:]) - outfile_fd = open(outfile, "w") + outfile_fd = open(outfile, "w") - # Need to flush to ensure our write is done before stdout write - # FIXME: CODE_HEADER needed in our sh -e scenario? - outfile_fd.write(CODE_HEADER) - outfile_fd.flush() + # Need to flush to ensure our write is done before stdout write + outfile_fd.write(CODE_HEADER) + outfile_fd.flush() - cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) - outfile_fd.close() + cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) + outfile_fd.close() - status = os.stat(outfile) + status = os.stat(outfile) - # Remove output if empty, else make it executable - if status.st_size == len(CODE_HEADER): - os.unlink(outfile) - else: - # Add header and make executable - identically to 0o700 - os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + # Remove output if empty, else make it executable + if status.st_size == len(CODE_HEADER): + os.unlink(outfile) + else: + # Add header and make executable - identically to 0o700 + os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) - # Mark object as changed - open(os.path.join(self.path.object_dir(cdist_object), "changed"), "w").close() + # Mark object as changed + open(os.path.join(self.path.object_dir(cdist_object), "changed"), "w").close() - if mode == "code": - local_dir = self.path.object_dir(cdist_object) - remote_dir = self.path.remote_object_dir(cdist_object) + if mode == "code": + local_dir = self.path.object_dir(cdist_object) + remote_dir = self.path.remote_object_dir(cdist_object) - bin = os.path.join(local_dir, "code-local") - if os.path.isfile(bin): - cdist.exec.run_or_fail([bin]) - + bin = os.path.join(local_dir, "code-local") + if os.path.isfile(bin): + cdist.exec.run_or_fail([bin]) + - local_remote_code = os.path.join(local_dir, "code-remote") - remote_remote_code = os.path.join(remote_dir, "code-remote") - if os.path.isfile(local_remote_code): - self.path.transfer_file(local_remote_code, remote_remote_code) - # FIXME: remote_prefix - cdist.exec.run_or_fail([remote_remote_code], remote_prefix=self.remote_prefix) - - def stage_prepare(self): - """Do everything for a deploy, minus the actual code stage""" - self.init_deploy() - self.run_global_explorers() - self.run_initial_manifest() - - log.info("Running object manifests and type explorers") + local_remote_code = os.path.join(local_dir, "code-remote") + remote_remote_code = os.path.join(remote_dir, "code-remote") + if os.path.isfile(local_remote_code): + self.path.transfer_file(local_remote_code, remote_remote_code) + cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) + + def stage_prepare(self): + """Do everything for a deploy, minus the actual code stage""" + self.init_deploy() + self.run_global_explores() + self.run_initial_manifest() + + log.info("Running object manifests and type explorers") - old_objects = [] - objects = self.path.list_objects() + old_objects = [] + objects = self.path.list_objects() - # Continue process until no new objects are created anymore - while old_objects != objects: - old_objects = list(objects) - for cdist_object in objects: - if cdist_object in self.objects_prepared: - log.debug("Skipping rerun of object %s", cdist_object) - continue - else: - # FIXME: run_type_explorer: - # object can return type - # type has explorers - # path knows about where to save explorer output - # type = self.path.objects[object].type() - # self.path.types['type'].explorers() - # for explorer in explorers: - # output = cdist.exec.run_debug_or_fail_shell(explorer) - # if output: - # write_output_to(output, os.path.join(self.path.objects[object].explorer_dir(),explorer) ) - # - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) - self.objects_prepared.append(cdist_object) + # Continue process until no new objects are created anymore + while old_objects != objects: + old_objects = list(objects) + for cdist_object in objects: + if cdist_object in self.objects_prepared: + log.debug("Skipping rerun of object %s", cdist_object) + continue + else: + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + self.objects_prepared.append(cdist_object) - objects = self.path.list_objects() + objects = self.path.list_objects() - def stage_run(self): - """The final (and real) step of deployment""" - log.info("Generating and executing code") - # Now do the final steps over the existing objects - for cdist_object in self.path.list_objects(): - log.debug("Run object: %s", cdist_object) - self.object_run(cdist_object, mode="gencode") - self.object_run(cdist_object, mode="code") + def stage_run(self): + """The final (and real) step of deployment""" + log.info("Generating and executing code") + # Now do the final steps over the existing objects + for cdist_object in self.path.list_objects(): + log.debug("Run object: %s", cdist_object) + self.object_run(cdist_object, mode="gencode") + self.object_run(cdist_object, mode="code") - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to " + self.target_host) - time_start = datetime.datetime.now() + def deploy_to(self): + """Mimic the old deploy to: Deploy to one host""" + log.info("Deploying to " + self.target_host) + time_start = datetime.datetime.now() - self.stage_prepare() - self.stage_run() + self.stage_prepare() + self.stage_run() - time_end = datetime.datetime.now() - duration = time_end - time_start - log.info("Finished run of %s in %s seconds", - self.target_host, - duration.total_seconds()) - - def deploy_and_cleanup(self): - """Do what is most often done: deploy & cleanup""" - self.deploy_to() - self.cleanup() + time_end = datetime.datetime.now() + duration = time_end - time_start + log.info("Finished run of %s in %s seconds", + self.target_host, + duration.total_seconds()) From 8341e0cc0f964ad8e3c9b301e3c548b953fe7d9a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 16:54:47 +0200 Subject: [PATCH 0510/4212] think about the __init_script type (probably raise discussion) Signed-off-by: Nico Schottelius --- other/types_pending_inclusion/__init_script/README | 4 ++++ .../types_pending_inclusion}/__init_script/gencode-remote | 0 .../types_pending_inclusion}/__init_script/man.text | 0 .../types_pending_inclusion}/__init_script/parameter/optional | 0 .../types_pending_inclusion}/__init_script/parameter/required | 0 5 files changed, 4 insertions(+) create mode 100644 other/types_pending_inclusion/__init_script/README rename {conf/type => other/types_pending_inclusion}/__init_script/gencode-remote (100%) rename {conf/type => other/types_pending_inclusion}/__init_script/man.text (100%) rename {conf/type => other/types_pending_inclusion}/__init_script/parameter/optional (100%) rename {conf/type => other/types_pending_inclusion}/__init_script/parameter/required (100%) diff --git a/other/types_pending_inclusion/__init_script/README b/other/types_pending_inclusion/__init_script/README new file mode 100644 index 00000000..f2621f12 --- /dev/null +++ b/other/types_pending_inclusion/__init_script/README @@ -0,0 +1,4 @@ +Moved out of conf/type/ to think about whether this type makes sense or not. + +Cdist describes the state and using an init_script may be useful, but +should only be used conditionally. diff --git a/conf/type/__init_script/gencode-remote b/other/types_pending_inclusion/__init_script/gencode-remote similarity index 100% rename from conf/type/__init_script/gencode-remote rename to other/types_pending_inclusion/__init_script/gencode-remote diff --git a/conf/type/__init_script/man.text b/other/types_pending_inclusion/__init_script/man.text similarity index 100% rename from conf/type/__init_script/man.text rename to other/types_pending_inclusion/__init_script/man.text diff --git a/conf/type/__init_script/parameter/optional b/other/types_pending_inclusion/__init_script/parameter/optional similarity index 100% rename from conf/type/__init_script/parameter/optional rename to other/types_pending_inclusion/__init_script/parameter/optional diff --git a/conf/type/__init_script/parameter/required b/other/types_pending_inclusion/__init_script/parameter/required similarity index 100% rename from conf/type/__init_script/parameter/required rename to other/types_pending_inclusion/__init_script/parameter/required From 220611604b5ecc8c01a2f592c99f1ff793c7b26e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 17:00:09 +0200 Subject: [PATCH 0511/4212] +: Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 864b4f37..1f325a8c 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -29,7 +29,7 @@ class Error(Exception): class MissingEnvironmentVariableError(Error): """Raised when a required environment variable is not set.""" - def __init__(self, name) + def __init__(self, name): self.name = name def __str__(self): From 60b5f8783c56b405c4b13105dbd4bfeeb9671b6e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 17:02:37 +0200 Subject: [PATCH 0512/4212] revert changes from upcoming install branch Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 7 +++---- lib/cdist/install.py | 3 --- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index 657714a4..0ae41174 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -22,13 +22,15 @@ import datetime import logging -log = logging.getLogger(__name__) +import sys import cdist.emulator import cdist.path CODE_HEADER = "#!/bin/sh -e\n" +log = logging.getLogger(__name__) + class Config: """Cdist main class to hold arbitrary data""" @@ -276,9 +278,6 @@ class Config: self.target_host, duration.total_seconds()) -class Config(cdist.config_install.ConfigInstall): - pass - def config(args): """Configure remote system""" process = {} diff --git a/lib/cdist/install.py b/lib/cdist/install.py index 5a35626d..87714fa8 100644 --- a/lib/cdist/install.py +++ b/lib/cdist/install.py @@ -27,9 +27,6 @@ import cdist.config_install log = logging.getLogger(__name__) -Class Install(cdist.config_install.ConfigInstall): - pass - def install(args): """Install remote system""" process = {} From 12dc0d2bddcbb55c98727126f2fd0747edd87060 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 6 Oct 2011 17:15:45 +0200 Subject: [PATCH 0513/4212] cleanup and file system backed properties Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 58 ++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 80c2c351..127bf038 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -20,9 +20,13 @@ # import os +import collections import cdist -import cdist.path +import cdist.core.property + + +DOT_CDIST = '.cdist' class Object(object): @@ -73,27 +77,64 @@ class Object(object): """Return a list of object names""" for path, dirs, files in os.walk(cls.base_dir()): # FIXME: use constant instead of string - if cdist.path.DOT_CDIST in dirs: + if DOT_CDIST in dirs: yield os.path.relpath(path, cls.base_dir()) - def __init__(self, type, object_id=None, parameter=None, requirements=None): + def __init__(self, type, object_id=None, parameters=None, requirements=None): self.type = type # instance of Type self.object_id = object_id - self.qualified_name = os.path.join(self.type.name, self.object_id) - self.parameter = parameter or {} + self.name = os.path.join(self.type.name, self.object_id) + self.parameters = parameters or {} self.requirements = requirements or [] + + self.__parameters = None + self.__requirements = None def __repr__(self): - return '' % self.qualified_name + return '' % self.name @property def path(self): return os.path.join( self.base_dir(), - self.qualified_name, - cdist.path.DOT_CDIST + self.name, + DOT_CDIST ) + + ### requirements + @property + def requirements(self): + if not self.__requirements: + self.__requirements = cdist.core.property.FileList(os.path.join(self.path, "require")) + return self.__requirements + + @requirements.setter + def requirements(self, value): + if isinstance(value, cdist.core.property.FileList): + self.__requirements = value + else: + self.__requirements = cdist.core.property.FileList(os.path.join(self.path, "require"), value) + ### /requirements + + + ### parameters + @property + def parameters(self): + if not self.__parameters: + self.__parameters = cdist.core.property.DirectoryDict(os.path.join(self.path, "parameter")) + return self.__parameters + + @parameters.setter + def parameters(self, value): + if isinstance(value, cdist.core.property.DirectoryDict): + self.__parameters = value + else: + self.__parameters = cdist.core.property.DirectoryDict(os.path.join(self.path, "parameter"), value) + ### /parameters + + + ### changed @property def changed(self): """Check whether the object has been changed.""" @@ -111,5 +152,6 @@ class Object(object): except EnvironmentError: # ignore pass + ### /changed # FIXME: implement other properties/methods From 3a1cea68873f585529dcfab5b0d7dc3a7df58942 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 6 Oct 2011 17:16:12 +0200 Subject: [PATCH 0514/4212] file system backed properties Signed-off-by: Steven Armstrong --- lib/cdist/core/property.py | 119 +++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 lib/cdist/core/property.py diff --git a/lib/cdist/core/property.py b/lib/cdist/core/property.py new file mode 100644 index 00000000..e22e33cd --- /dev/null +++ b/lib/cdist/core/property.py @@ -0,0 +1,119 @@ +# -*- 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 collections + +import cdist + + +DOT_CDIST = '.cdist' + + +class FileList(collections.MutableSequence): + """A list that stores it's state in a file. + + """ + def __init__(self, path, initial=None): + self._path = path + if initial: + for i in initial: + self.append(i) + + def __read(self): + lines = [] + try: + with open(self._path) as fd: + for line in fd: + lines.append(line.strip()) + except EnvironmentError as e: + # error ignored + pass + return lines + + def __write(self, lines): + try: + with open(self._path, 'w') as fd: + for line in lines: + fd.write(line + '\n') + except EnvironmentError as e: + # error ignored + raise + + def __repr__(self): + return repr(list(self)) + + def __getitem__(self, index): + return self.__read()[index] + + def __setitem__(self, index, value): + lines = self.__read() + lines[index] = value + self.__write(lines) + + def __delitem__(self, index): + lines = self.__read() + del lines[index] + self.__write(lines) + + def __len__(self): + lines = self.__read() + return len(lines) + + def insert(self, index, value): + lines = self.__read() + lines.insert(index, value) + self.__write(lines) + + +class DirectoryDict(collections.MutableMapping): + """A dict that stores it's state in a directory. + + """ + def __init__(self, path, dict=None, **kwargs): + self._path = path + if dict is not None: + self.update(dict) + if len(kwargs): + self.update(kwargs) + + def __repr__(self): + return repr(dict(self)) + + def __getitem__(self, key): + try: + with open(os.path.join(self._path, key), "r") as fd: + return fd.read() + except EnvironmentError: + raise KeyError(key) + + def __setitem__(self, key, value): + with open(os.path.join(self._path, key), "w") as fd: + fd.write(value) + + def __delitem__(self, key): + os.remove(os.path.join(self._path, key)) + + def __iter__(self): + return iter(os.listdir(self._path)) + + def __len__(self): + return len(os.listdir(self._path)) From c0854ebb2e00041fd1f3d69dacaff86c52f8962b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 6 Oct 2011 17:47:08 +0200 Subject: [PATCH 0515/4212] remove unused constant Signed-off-by: Steven Armstrong --- lib/cdist/core/property.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/cdist/core/property.py b/lib/cdist/core/property.py index e22e33cd..790ff802 100644 --- a/lib/cdist/core/property.py +++ b/lib/cdist/core/property.py @@ -25,9 +25,6 @@ import collections import cdist -DOT_CDIST = '.cdist' - - class FileList(collections.MutableSequence): """A list that stores it's state in a file. From df5de24b72cf98c6ca091b11fbf827758dd78d1c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 18:26:55 +0200 Subject: [PATCH 0516/4212] begin use of cdist.core.Object.list_objects() Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index c7c592a5..b6d7451b 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -29,6 +29,8 @@ import sys import cdist.emulator import cdist.path +import cdist.core + log = logging.getLogger(__name__) CODE_HEADER = "#!/bin/sh -e\n" @@ -108,14 +110,6 @@ class ConfigInstall: cdist.emulator.link(self.exec_path, self.path.bin_dir, self.path.list_types()) - def init_deploy(self): - """Ensure the base directories are cleaned up""" - log.debug("Creating clean directory structure") - - self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) - self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) - self.link_emulator() - def run_initial_manifest(self): """Run the initial manifest""" log.info("Running initial manifest %s", self.path.initial_manifest) @@ -241,11 +235,11 @@ class ConfigInstall: log.info("Running object manifests and type explorers") old_objects = [] - objects = self.path.list_objects() + objects = cdist.core.Object.list_objects() # Continue process until no new objects are created anymore while old_objects != objects: - old_objects = list(objects) + old_objects = objects for cdist_object in objects: if cdist_object in self.objects_prepared: log.debug("Skipping rerun of object %s", cdist_object) @@ -255,7 +249,7 @@ class ConfigInstall: self.run_type_manifest(cdist_object) self.objects_prepared.append(cdist_object) - objects = self.path.list_objects() + objects = cdist.core.Object.list_objects() def stage_run(self): """The final (and real) step of deployment""" @@ -285,3 +279,11 @@ class ConfigInstall: self.deploy_to() self.cleanup() + ### Cleaned / check functions: Round 1 :-) ################################# + def init_deploy(self): + """Ensure the base directories are cleaned up""" + log.debug("Creating clean directory structure") + + self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) + self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) + self.link_emulator() From 2157cef2a6048a61ef9708269b2dc4a0c1ed38d2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 19:22:08 +0200 Subject: [PATCH 0517/4212] make cdist.MissingEnvironmentVariableError print the key and not fail :-) Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 1f325a8c..fcfa3693 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -33,4 +33,4 @@ class MissingEnvironmentVariableError(Error): self.name = name def __str__(self): - return 'Missing required environment variable: {0.name}'.format(o) + return 'Missing required environment variable: ' + str(self.name) From 5c9694215ca4943c5209062d9394c5ee1194df7e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 19:26:58 +0200 Subject: [PATCH 0518/4212] setup '__cdist_out_dir' in path for use in Object Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index c45ddcd6..73a90302 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -68,6 +68,8 @@ class Path: self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) self.temp_dir = tempfile.mkdtemp() + os.environ['__cdist_out_dir'] = self.temp_dir + self.target_host = target_host # Input directories From 344bfb06030f4ebe4e59efe755d642f52893765a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 19:40:19 +0200 Subject: [PATCH 0519/4212] was the object prepared/ran? Signed-off-by: Nico Schottelius --- lib/cdist/core/object.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 127bf038..544f7565 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -89,6 +89,10 @@ class Object(object): self.__parameters = None self.__requirements = None + + # Whether this object was prepared/ran + self.prepared = False + self.ran = False def __repr__(self): return '' % self.name From 8305f07aab6c7c9b57ce2d69045a4550b3fcfadd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 19:43:07 +0200 Subject: [PATCH 0520/4212] stage prepare uses new object interface Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 48 ++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index b6d7451b..b1db2855 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -226,31 +226,6 @@ class ConfigInstall: self.path.transfer_file(local_remote_code, remote_remote_code) cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) - def stage_prepare(self): - """Do everything for a deploy, minus the actual code stage""" - self.init_deploy() - self.run_global_explores() - self.run_initial_manifest() - - log.info("Running object manifests and type explorers") - - old_objects = [] - objects = cdist.core.Object.list_objects() - - # Continue process until no new objects are created anymore - while old_objects != objects: - old_objects = objects - for cdist_object in objects: - if cdist_object in self.objects_prepared: - log.debug("Skipping rerun of object %s", cdist_object) - continue - else: - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) - self.objects_prepared.append(cdist_object) - - objects = cdist.core.Object.list_objects() - def stage_run(self): """The final (and real) step of deployment""" log.info("Generating and executing code") @@ -287,3 +262,26 @@ class ConfigInstall: self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) self.link_emulator() + + def stage_prepare(self): + """Do everything for a deploy, minus the actual code stage""" + self.init_deploy() + self.run_global_explores() + self.run_initial_manifest() + + 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 cdist.core.Object.list_objects(): + if cdist_object.prepared: + log.debug("Skipping rerun of object %s", cdist_object) + continue + else: + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + self.objects_prepared.append(cdist_object) + cdist_object.prepared = True + new_objects_created = True From ccb2ffcae620d829d090729ff7232f3c35df25f1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 19:47:55 +0200 Subject: [PATCH 0521/4212] remove toplevel object/type Signed-off-by: Nico Schottelius --- lib/cdist/object.py | 51 ----------------------------------------- lib/cdist/type.py | 55 --------------------------------------------- 2 files changed, 106 deletions(-) delete mode 100644 lib/cdist/object.py delete mode 100644 lib/cdist/type.py diff --git a/lib/cdist/object.py b/lib/cdist/object.py deleted file mode 100644 index 0a282dc2..00000000 --- a/lib/cdist/object.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- 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 logging -log = logging.getLogger(__name__) - - - -class Object(object): - - def __init__(self, path, remote_path, object_fq): - self.path = path - self.remote_path = remote_path - self.object_fq = object_fq - self.type = self.object_fq.split(os.sep)[0] - self.object_id = self.object_fq.split(os.sep)[1:] - self.parameter_dir = os.path.join(self.path, "parameter") - self.remote_object_parameter_dir = os.path.join(self.remote_path, "parameter") - self.object_code_paths = [ - os.path.join(self.path, "code-local"), - os.path.join(self.path, "code-remote")] - - @property - def type_explorer_output_dir(self): - """Returns and creates dir of the output for a type explorer""" - if not self.__type_explorer_output_dir: - dir = os.path.join(self.path, "explorer") - if not os.path.isdir(dir): - os.mkdir(dir) - self.__type_explorer_output_dir = dir - return self.__type_explorer_output_dir - diff --git a/lib/cdist/type.py b/lib/cdist/type.py deleted file mode 100644 index e6c35ad1..00000000 --- a/lib/cdist/type.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 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 logging -import os -log = logging.getLogger(__name__) - -class Type(object): - - def __init__(self, path, remote_path): - self.path = path - self.remote_path = remote_path - - def list_explorers(self): - """Return list of available explorers""" - dir = os.path.join(self.path, "explorer") - if os.path.isdir(dir): - list = os.listdir(dir) - else: - list = [] - - log.debug("Explorers for %s in %s: %s", type, dir, list) - - return list - - def is_install(self): - """Check whether a type is used for installation (if not: for configuration)""" - return os.path.isfile(os.path.join(self.path, "install")) - - def explorer_dir(self): - """Return remote directory that holds the explorers of a type""" - return os.path.join(self.remote_path, "explorer") - - def remote_explorer_dir(self): - """Return remote directory that holds the explorers of a type""" - return os.path.join(self.remote_path, "explorer") From ae9eba80a9e369e91d5b9a69c2af0fe88c5769fc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 19:50:45 +0200 Subject: [PATCH 0522/4212] use require, not __require in emulator Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 38a58f8c..519afd24 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -127,7 +127,7 @@ def run(argv): param_fd.close() # Record requirements - if "__require" in os.environ: + if "require" in os.environ: requirements = os.environ['__require'] log.debug(object_id + ":Writing requirements: " + requirements) require_fd = open(os.path.join(object_dir, "require"), "a") From 52268d032a11afe0c6abfc473314be654571be69 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 19:51:42 +0200 Subject: [PATCH 0523/4212] ++todos Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 11c734f9..42dec573 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,3 +1,10 @@ +2.0.3: + +- fix emulator +- introduce tests for $require + +-------------------------------------------------------------------------------- + - Fix / rewrite cdist-quickstart - write tutorial!!!!!!!!! From d07a191867b31efc914248181de207fbaef37fc3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 19:54:41 +0200 Subject: [PATCH 0524/4212] add logger to config Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index 6bf9d782..942d2917 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -27,6 +27,8 @@ import sys import cdist.config_install +log = logging.getLogger(__name__) + class Config(cdist.config_install.ConfigInstall): pass From a87e6f22b5251c364e86d74da535d7aa52b8ce3f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 19:59:07 +0200 Subject: [PATCH 0525/4212] use new cdist.Error exception Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index b1db2855..3b6c79a1 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -65,7 +65,7 @@ class ConfigInstall: log.info("Running global explorers") explorers = self.path.list_global_explorers() if(len(explorers) == 0): - raise CdistError("No explorers found in", self.path.global_explorer_dir) + raise cdist.Error("No explorers found in", self.path.global_explorer_dir) self.path.transfer_global_explorers() for explorer in explorers: @@ -159,6 +159,8 @@ class ConfigInstall: def object_run(self, cdist_object, mode): """Run gencode or code for an object""" log.debug("Running %s from %s", mode, cdist_object) + + # FIXME: replace with new object interface file=os.path.join(self.path.object_dir(cdist_object), "require") requirements = cdist.path.file_to_list(file) type = self.path.get_type_from_object(cdist_object) @@ -169,7 +171,7 @@ class ConfigInstall: # # Setup env Variable: - # + # env = os.environ.copy() env['__target_host'] = self.target_host env['__global'] = self.path.out_dir @@ -230,7 +232,7 @@ class ConfigInstall: """The final (and real) step of deployment""" log.info("Generating and executing code") # Now do the final steps over the existing objects - for cdist_object in self.path.list_objects(): + for cdist_object in cdist.core.Object.list_objects(): log.debug("Run object: %s", cdist_object) self.object_run(cdist_object, mode="gencode") self.object_run(cdist_object, mode="code") From 14126cb4b85a88a1dbd55af19c975243877d19dd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:04:44 +0200 Subject: [PATCH 0526/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 42dec573..966ead7a 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,8 +1,12 @@ 2.0.3: - fix emulator -- introduce tests for $require +- introduce tests: + - does $require work? + - $whatever should fail if there is no global explorer directory +- Create GlobalExplorer + -------------------------------------------------------------------------------- - Fix / rewrite cdist-quickstart From 14082f5c0049e8eba532034bf601dfc500f71392 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:05:24 +0200 Subject: [PATCH 0527/4212] string, not tuple in exception Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 3b6c79a1..f3dac289 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -65,7 +65,7 @@ class ConfigInstall: log.info("Running global explorers") explorers = self.path.list_global_explorers() if(len(explorers) == 0): - raise cdist.Error("No explorers found in", self.path.global_explorer_dir) + raise cdist.Error("No explorers found in " + self.path.global_explorer_dir) self.path.transfer_global_explorers() for explorer in explorers: @@ -251,12 +251,13 @@ class ConfigInstall: self.target_host, duration.total_seconds()) + + ### Cleaned / check functions: Round 1 :-) ################################# def deploy_and_cleanup(self): """Do what is most often done: deploy & cleanup""" self.deploy_to() self.cleanup() - ### Cleaned / check functions: Round 1 :-) ################################# def init_deploy(self): """Ensure the base directories are cleaned up""" log.debug("Creating clean directory structure") From d4bf98cf0c5b9c5026f136b92c973c6a9d5a93c4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:08:46 +0200 Subject: [PATCH 0528/4212] +tests needed Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 966ead7a..85620098 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -4,6 +4,7 @@ - introduce tests: - does $require work? - $whatever should fail if there is no global explorer directory + - emulator may only be called with __ as prefix - fail otherwise! - Create GlobalExplorer From 1db4cd48d24fecd4e92b4a941de3f86ef291c910 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:11:23 +0200 Subject: [PATCH 0529/4212] -typo Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index f3dac289..1f590d07 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -55,12 +55,10 @@ class ConfigInstall: base_dir=home, debug=debug) - self.objects_prepared = [] - def cleanup(self): self.path.cleanup() - def run_global_explores(self): + def run_global_explorers(self): """Run global explorers""" log.info("Running global explorers") explorers = self.path.list_global_explorers() @@ -269,7 +267,7 @@ class ConfigInstall: def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" self.init_deploy() - self.run_global_explores() + self.run_global_explorers() self.run_initial_manifest() log.info("Running object manifests and type explorers") @@ -285,6 +283,5 @@ class ConfigInstall: else: self.run_type_explorer(cdist_object) self.run_type_manifest(cdist_object) - self.objects_prepared.append(cdist_object) cdist_object.prepared = True new_objects_created = True From 609efcbfd1af1b2e679c5a0c708941c3b35caedd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:14:34 +0200 Subject: [PATCH 0530/4212] Remove datetime from config_install, break code and make it more beautiful Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 1f590d07..3be7e0b1 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -20,7 +20,6 @@ # # -import datetime import logging import os import stat From 84867db20a08aa7c742d28e891a1ffea328f90de Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:14:48 +0200 Subject: [PATCH 0531/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 85620098..bfbdd8c3 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -10,6 +10,9 @@ -------------------------------------------------------------------------------- +- insert prefix into logger to distinguish between modules + - in debug/info only? + - Fix / rewrite cdist-quickstart - write tutorial!!!!!!!!! From 13d47f3cf4fd2a083218073e6fc7f79fcc57e3b9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:20:35 +0200 Subject: [PATCH 0532/4212] remove datetime from config to wrong position Signed-off-by: Nico Schottelius --- bin/cdist | 11 +++++++++++ lib/cdist/config_install.py | 11 +---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/bin/cdist b/bin/cdist index 0bf3ed9c..36dc3d5c 100755 --- a/bin/cdist +++ b/bin/cdist @@ -21,6 +21,7 @@ # import argparse +import datetime import logging import os import re @@ -105,6 +106,8 @@ if __name__ == "__main__": try: logging.basicConfig(format='%(levelname)s: %(message)s') + time_start = datetime.datetime.now() + if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): import cdist.emulator cdist.emulator.run(sys.argv) @@ -117,6 +120,14 @@ if __name__ == "__main__": import cdist.path commandline() + + time_end = datetime.datetime.now() + duration = time_end - time_start + # FIXME: move into runner + # log.info("Finished run of %s in %s seconds", self.target_host, + # duration.total_seconds()) + log.info("Finished run in %s seconds", duration.total_seconds()) + except KeyboardInterrupt: sys.exit(0) except cdist.Error as e: diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 3be7e0b1..7d0e2c9a 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -234,22 +234,13 @@ class ConfigInstall: self.object_run(cdist_object, mode="gencode") self.object_run(cdist_object, mode="code") + ### Cleaned / check functions: Round 1 :-) ################################# def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" log.info("Deploying to " + self.target_host) - time_start = datetime.datetime.now() - self.stage_prepare() self.stage_run() - time_end = datetime.datetime.now() - duration = time_end - time_start - log.info("Finished run of %s in %s seconds", - self.target_host, - duration.total_seconds()) - - - ### Cleaned / check functions: Round 1 :-) ################################# def deploy_and_cleanup(self): """Do what is most often done: deploy & cleanup""" self.deploy_to() From 579bd45c8765f44560f2279a063bf97c46dc050f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:24:40 +0200 Subject: [PATCH 0533/4212] cleanup more stuff in config_install Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 7d0e2c9a..ac988425 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -225,6 +225,7 @@ class ConfigInstall: self.path.transfer_file(local_remote_code, remote_remote_code) cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) + ### Cleaned / check functions: Round 1 :-) ################################# def stage_run(self): """The final (and real) step of deployment""" log.info("Generating and executing code") @@ -234,7 +235,6 @@ class ConfigInstall: self.object_run(cdist_object, mode="gencode") self.object_run(cdist_object, mode="code") - ### Cleaned / check functions: Round 1 :-) ################################# def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" log.info("Deploying to " + self.target_host) @@ -271,6 +271,7 @@ class ConfigInstall: log.debug("Skipping rerun of object %s", cdist_object) continue else: + log.debug("Preparing object: " + cdist_object) self.run_type_explorer(cdist_object) self.run_type_manifest(cdist_object) cdist_object.prepared = True From be1d4afd589e3265089d736b9a75e2e191d94776 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:27:07 +0200 Subject: [PATCH 0534/4212] add log to object Signed-off-by: Nico Schottelius --- lib/cdist/core/object.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 544f7565..8ad2a9eb 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -19,12 +19,14 @@ # # +import logging import os import collections import cdist import cdist.core.property +log = logging.getLogger(__name__) DOT_CDIST = '.cdist' From 9b5b94577fd75f6433b045c4dfa18770e80a9dde Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:32:47 +0200 Subject: [PATCH 0535/4212] add debug Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 2 ++ lib/cdist/emulator.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index ac988425..29154f84 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -262,6 +262,8 @@ class ConfigInstall: log.info("Running object manifests and type explorers") + log.debug("Searching for objects in " + cdist.core.Object.base_dir()) + # Continue process until no new objects are created anymore new_objects_created = True while new_objects_created: diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 519afd24..51b2ecc1 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -77,6 +77,8 @@ def run(argv): object_dir = os.path.join(global_dir, "object", type, object_id, cdist.path.DOT_CDIST) + log.debug("Object output dir = " + object_dir) + param_out_dir = os.path.join(object_dir, "parameter") object_source_file = os.path.join(object_dir, "source") From 6bd64437213a177924f699b22d5e5b72ec8653c9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:32:59 +0200 Subject: [PATCH 0536/4212] fix out dir for object Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 73a90302..98572b81 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -68,7 +68,6 @@ class Path: self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) self.temp_dir = tempfile.mkdtemp() - os.environ['__cdist_out_dir'] = self.temp_dir self.target_host = target_host @@ -93,6 +92,8 @@ class Path: self.object_base_dir = os.path.join(self.out_dir, "object") self.bin_dir = os.path.join(self.out_dir, "bin") + os.environ['__cdist_out_dir'] = self.out_dir + # List of type explorers transferred self.type_explorers_transferred = {} From 354e15015a9385a7cae7b4e0a83c3599a69a6a69 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:34:36 +0200 Subject: [PATCH 0537/4212] use full.path.to.cdist.core.Type(), Steven ;-) Signed-off-by: Nico Schottelius --- lib/cdist/core/object.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 8ad2a9eb..dbb6542d 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # -# 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -67,7 +68,7 @@ class Object(object): for object_name in cls.list_object_names(): type_name = object_name.split(os.sep)[0] object_id = os.sep.join(object_name.split(os.sep)[1:]) - yield cls(Type(type_name), object_id=object_id) + yield cls(cdist.core.Type(type_name), object_id=object_id) @classmethod def list_type_names(cls): From c0d6d4d5309d46530090ed0ef9460c86fc7237d1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:37:55 +0200 Subject: [PATCH 0538/4212] use name, not object Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 29154f84..3c11d6bb 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -273,7 +273,7 @@ class ConfigInstall: log.debug("Skipping rerun of object %s", cdist_object) continue else: - log.debug("Preparing object: " + cdist_object) + log.debug("Preparing object: " + cdist_object.name) self.run_type_explorer(cdist_object) self.run_type_manifest(cdist_object) cdist_object.prepared = True From b891818b9cd34ec59878eeb04f1880f4a006a0de Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:42:31 +0200 Subject: [PATCH 0539/4212] remove obsolete get_type_from_object() and use Object.type Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 2 +- lib/cdist/path.py | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 3c11d6bb..2071a0e9 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -78,7 +78,7 @@ class ConfigInstall: def run_type_explorer(self, cdist_object): """Run type specific explorers for objects""" - type = self.path.get_type_from_object(cdist_object) + type = cdist_object.type self.path.transfer_type_explorers(type) cmd = [] diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 98572b81..d82ae974 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -192,11 +192,6 @@ class Path: return object_paths - # FIXME: Object - def get_type_from_object(self, cdist_object): - """Returns the first part (i.e. type) of an object""" - return cdist_object.split(os.sep)[0] - # FIXME: Object def get_object_id_from_object(self, cdist_object): """Returns everything but the first part (i.e. object_id) of an object""" From 35a7757e1aa6f1f7d6722a6bd903ce631aefb24a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:51:31 +0200 Subject: [PATCH 0540/4212] rewrite path to include calls to non-existent methods in type (fix needed, sar :-) Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index d82ae974..deeb6b0d 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -255,19 +255,25 @@ class Path: # Stays here - FIXME: adjust to type code, loop over types! def transfer_type_explorers(self, type): """Transfer explorers of a type, but only once""" - if type in self.type_explorers_transferred: + if type.transferred: log.debug("Skipping retransfer for explorers of %s", type) return else: # Do not retransfer - self.type_explorers_transferred[type] = 1 + type.transferred = True - src = self.type_dir(type, "explorer") - remote_base = os.path.join(REMOTE_TYPE_DIR, type) - dst = self.remote_type_explorer_dir(type) + # FIXME: need to get explorer path from type! + src = type.explorer_path() + dst = type.remote_explorer_path() + # FIXME: where to construct remote path? here? + # remote_base = os.path.join(REMOTE_TYPE_DIR, type.name) + # dst = self.remote_type_explorer_dir(type) # Only continue, if there is at least the directory - if os.path.isdir(src): + #if os.path.isdir(src): + + # Transfer if there is at least one explorer + if len(type.explorers) > 0: # Ensure that the path exists - self.remote_mkdir(remote_base) + self.remote_mkdir(dst) self.transfer_dir(src, dst) From 6f58b18c8cff14d3ce736dc6a605a222ccf0d913 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Oct 2011 20:52:34 +0200 Subject: [PATCH 0541/4212] remove legacy code, fail until type supports us Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index deeb6b0d..f7d2a8ae 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -262,16 +262,10 @@ class Path: # Do not retransfer type.transferred = True - # FIXME: need to get explorer path from type! + # FIXME: Can be explorer_path or explorer_dir, I don't care. src = type.explorer_path() dst = type.remote_explorer_path() - # FIXME: where to construct remote path? here? - # remote_base = os.path.join(REMOTE_TYPE_DIR, type.name) - # dst = self.remote_type_explorer_dir(type) - # Only continue, if there is at least the directory - #if os.path.isdir(src): - # Transfer if there is at least one explorer if len(type.explorers) > 0: # Ensure that the path exists From 3873aefcf55ed2c0953b164e14ef46546bd912b5 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 00:46:59 +0200 Subject: [PATCH 0542/4212] cleanup, add sort method Signed-off-by: Steven Armstrong --- lib/cdist/core/property.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/cdist/core/property.py b/lib/cdist/core/property.py index 790ff802..359cf32c 100644 --- a/lib/cdist/core/property.py +++ b/lib/cdist/core/property.py @@ -32,6 +32,8 @@ class FileList(collections.MutableSequence): def __init__(self, path, initial=None): self._path = path if initial: + # delete existing file + os.unlink(self._path) for i in initial: self.append(i) @@ -40,7 +42,7 @@ class FileList(collections.MutableSequence): try: with open(self._path) as fd: for line in fd: - lines.append(line.strip()) + lines.append(line.rstrip('\n')) except EnvironmentError as e: # error ignored pass @@ -50,7 +52,7 @@ class FileList(collections.MutableSequence): try: with open(self._path, 'w') as fd: for line in lines: - fd.write(line + '\n') + fd.write(str(line) + '\n') except EnvironmentError as e: # error ignored raise @@ -80,6 +82,10 @@ class FileList(collections.MutableSequence): lines.insert(index, value) self.__write(lines) + def sort(self): + lines = sorted(self) + self.__write(lines) + class DirectoryDict(collections.MutableMapping): """A dict that stores it's state in a directory. @@ -98,13 +104,13 @@ class DirectoryDict(collections.MutableMapping): def __getitem__(self, key): try: with open(os.path.join(self._path, key), "r") as fd: - return fd.read() + return fd.read().rstrip('\n') except EnvironmentError: raise KeyError(key) def __setitem__(self, key, value): with open(os.path.join(self._path, key), "w") as fd: - fd.write(value) + fd.write(str(value)) def __delitem__(self, key): os.remove(os.path.join(self._path, key)) From 7bbecb25868a8bc798dfbc7f96c9efa0649a0de6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 00:48:06 +0200 Subject: [PATCH 0543/4212] implement descriptor protocol for FileList and DirectoryDict Signed-off-by: Steven Armstrong --- lib/cdist/core/property.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/cdist/core/property.py b/lib/cdist/core/property.py index 359cf32c..30887547 100644 --- a/lib/cdist/core/property.py +++ b/lib/cdist/core/property.py @@ -87,6 +87,22 @@ class FileList(collections.MutableSequence): self.__write(lines) +class FileListProperty(FileList): + # Descriptor Protocol + def __get__(self, obj, objtype=None): + if obj is None: + return self.__class__ + return self + + def __set__(self, obj, value): + os.unlink(self._path) + for item in value: + self.append(item) + + def __delete__(self, obj): + raise AttributeError("can't delete attribute") + + class DirectoryDict(collections.MutableMapping): """A dict that stores it's state in a directory. @@ -120,3 +136,20 @@ class DirectoryDict(collections.MutableMapping): def __len__(self): return len(os.listdir(self._path)) + + +class DirectoryDictProperty(DirectoryDict): + # Descriptor Protocol + def __get__(self, obj, objtype=None): + if obj is None: + return self.__class__ + return self + + def __set__(self, obj, value): + for name in self.keys(): + del self[name] + if value is not None: + self.update(value) + + def __delete__(self, obj): + raise AttributeError("can't delete attribute") From 2b1c4df8d97686a6c80e1e55c4139b6b2f6bffd6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 09:01:47 +0200 Subject: [PATCH 0544/4212] have explorers been transferred? (type) Signed-off-by: Nico Schottelius --- lib/cdist/core/type.py | 5 ++++- lib/cdist/path.py | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index 126b4d16..7492659e 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # -# 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -68,6 +69,8 @@ class Type(object): self.__required_parameters = None self.__optional_parameters = None + self.transferred_explorers = False + def __repr__(self): return '' % self.name diff --git a/lib/cdist/path.py b/lib/cdist/path.py index f7d2a8ae..e2d319ef 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -255,12 +255,12 @@ class Path: # Stays here - FIXME: adjust to type code, loop over types! def transfer_type_explorers(self, type): """Transfer explorers of a type, but only once""" - if type.transferred: + if type.transferred_explorers: log.debug("Skipping retransfer for explorers of %s", type) return else: # Do not retransfer - type.transferred = True + type.transferred_explorers = True # FIXME: Can be explorer_path or explorer_dir, I don't care. src = type.explorer_path() From 6be542d9bb5ed50aa7a71e2a6d57b4a3eac940f6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 09:05:26 +0200 Subject: [PATCH 0545/4212] missing functionality in oo Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index e69de29b..0ff17f6a 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -0,0 +1,8 @@ +Object: + code_remote + code_local + gencode_local + gencode_remote + +Type: + explorer_path From 1810462989c6ad6e81137ad2168907a14effe364 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 09:05:42 +0200 Subject: [PATCH 0546/4212] move stuff over from path to object to be fixed Signed-off-by: Nico Schottelius --- lib/cdist/core/object.py | 36 +++++++++++++++++++++++++++++++++++- lib/cdist/path.py | 31 ------------------------------- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index dbb6542d..e75c06c8 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -161,4 +161,38 @@ class Object(object): pass ### /changed - # FIXME: implement other properties/methods + # FIXME: implement other properties/methods + + # FIXME: check following methods: implement or revoke / delete + # FIXME: Object + def get_object_id_from_object(self, cdist_object): + """Returns everything but the first part (i.e. object_id) of an object""" + return os.sep.join(cdist_object.split(os.sep)[1:]) + + # FIXME: Object + def object_dir(self, cdist_object): + """Returns the full path to the object (including .cdist)""" + return os.path.join(self.object_base_dir, cdist_object, DOT_CDIST) + + # FIXME: Object + def remote_object_dir(self, cdist_object): + """Returns the remote full path to the object (including .cdist)""" + return os.path.join(REMOTE_OBJECT_DIR, cdist_object, DOT_CDIST) + + # FIXME: Object + def object_parameter_dir(self, cdist_object): + """Returns the dir to the object parameter""" + return os.path.join(self.object_dir(cdist_object), "parameter") + + # FIXME: object + def remote_object_parameter_dir(self, cdist_object): + """Returns the remote dir to the object parameter""" + return os.path.join(self.remote_object_dir(cdist_object), "parameter") + + # FIXME: object + def object_code_paths(self, cdist_object): + """Return paths to code scripts of object""" + return [os.path.join(self.object_dir(cdist_object), "code-local"), + os.path.join(self.object_dir(cdist_object), "code-remote")] + + diff --git a/lib/cdist/path.py b/lib/cdist/path.py index e2d319ef..99adfe99 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -192,37 +192,6 @@ class Path: return object_paths - # FIXME: Object - def get_object_id_from_object(self, cdist_object): - """Returns everything but the first part (i.e. object_id) of an object""" - return os.sep.join(cdist_object.split(os.sep)[1:]) - - # FIXME: Object - def object_dir(self, cdist_object): - """Returns the full path to the object (including .cdist)""" - return os.path.join(self.object_base_dir, cdist_object, DOT_CDIST) - - # FIXME: Object - def remote_object_dir(self, cdist_object): - """Returns the remote full path to the object (including .cdist)""" - return os.path.join(REMOTE_OBJECT_DIR, cdist_object, DOT_CDIST) - - # FIXME: Object - def object_parameter_dir(self, cdist_object): - """Returns the dir to the object parameter""" - return os.path.join(self.object_dir(cdist_object), "parameter") - - # FIXME: object - def remote_object_parameter_dir(self, cdist_object): - """Returns the remote dir to the object parameter""" - return os.path.join(self.remote_object_dir(cdist_object), "parameter") - - # FIXME: object - def object_code_paths(self, cdist_object): - """Return paths to code scripts of object""" - return [os.path.join(self.object_dir(cdist_object), "code-local"), - os.path.join(self.object_dir(cdist_object), "code-remote")] - # Stays here def list_objects(self): """Return list of existing objects""" From cf97fd9837c4253613ba809b9d87763197741d51 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 09:27:46 +0200 Subject: [PATCH 0547/4212] remove type_explorer information from path Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 99adfe99..4c36bfa5 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -92,7 +92,6 @@ class Path: self.object_base_dir = os.path.join(self.out_dir, "object") self.bin_dir = os.path.join(self.out_dir, "bin") - os.environ['__cdist_out_dir'] = self.out_dir # List of type explorers transferred self.type_explorers_transferred = {} @@ -116,6 +115,10 @@ class Path: shutil.move(self.temp_dir, self.cache_dir) + def __init_env(self): + """Setup environment""" + os.environ['__cdist_out_dir'] = self.out_dir + def __init_out_dirs(self): """Initialise output directory structure""" os.mkdir(self.out_dir) From e26f6120123c142fcbb949eaa69c1d20aa089f18 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 09:29:22 +0200 Subject: [PATCH 0548/4212] move file_to_list to cdist Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 14 ++++++++++++++ lib/cdist/emulator.py | 4 ++-- lib/cdist/path.py | 21 --------------------- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index fcfa3693..3a1b94e3 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -34,3 +34,17 @@ class MissingEnvironmentVariableError(Error): def __str__(self): return 'Missing required environment variable: ' + str(self.name) + +def file_to_list(filename): + """Return list from \n seperated file""" + if os.path.isfile(filename): + file_fd = open(filename, "r") + lines = file_fd.readlines() + file_fd.close() + + # Remove \n from all lines + lines = map(lambda s: s.strip(), lines) + else: + lines = [] + + return lines diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 51b2ecc1..f3e9ac30 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -43,10 +43,10 @@ def run(argv): parser = argparse.ArgumentParser(add_help=False) - for parameter in cdist.path.file_to_list(os.path.join(param_dir, "optional")): + for parameter in cdist.file_to_list(os.path.join(param_dir, "optional")): argument = "--" + parameter parser.add_argument(argument, action='store', required=False) - for parameter in cdist.path.file_to_list(os.path.join(param_dir, "required")): + for parameter in cdist.file_to_list(os.path.join(param_dir, "required")): argument = "--" + parameter parser.add_argument(argument, action='store', required=True) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 4c36bfa5..50977afd 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -38,20 +38,6 @@ log = logging.getLogger(__name__) import cdist.exec -def file_to_list(filename): - """Return list from \n seperated file""" - if os.path.isfile(filename): - file_fd = open(filename, "r") - lines = file_fd.readlines() - file_fd.close() - - # Remove \n from all lines - lines = map(lambda s: s.strip(), lines) - else: - lines = [] - - return lines - class Path: """Class that handles path related configurations""" @@ -92,13 +78,6 @@ class Path: self.object_base_dir = os.path.join(self.out_dir, "object") self.bin_dir = os.path.join(self.out_dir, "bin") - - # List of type explorers transferred - self.type_explorers_transferred = {} - - # objects prepared - self.objects_prepared = [] - # Create directories self.__init_out_dirs() From ee69971465a61874e65eebc2665ed23a2d8c9082 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 09:38:52 +0200 Subject: [PATCH 0549/4212] make temp_dir unecessary / only implementation detail Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 50977afd..b9d0b6bf 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -41,22 +41,16 @@ import cdist.exec class Path: """Class that handles path related configurations""" - def __init__(self, - target_host, - initial_manifest=False, - base_dir=None, - debug=False): - - # Base and Temp Base - if base_dir: - self.base_dir = base_dir - else: - self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) - - self.temp_dir = tempfile.mkdtemp() + def __init__(self, target_host, initial_manifest=False, debug=False): self.target_host = target_host + # Base and Temp Base + if "__cdist_base_dir" in os.environ: + self.base_dir = os.environ['__cdist_base_dir'] + else: + self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) + # Input directories self.conf_dir = os.path.join(self.base_dir, "conf") self.cache_base_dir = os.path.join(self.base_dir, "cache") @@ -73,7 +67,11 @@ class Path: self.initial_manifest = os.path.join(self.manifest_dir, "init") # Output directories - self.out_dir = os.path.join(self.temp_dir, "out") + if "__cdist_out_dir" in os.environ: + self.out_dir = os.environ['__cdist_out_dir'] + else: + self.out_dir = os.path.join(tempfile.mkdtemp(), "out") + self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") self.object_base_dir = os.path.join(self.out_dir, "object") self.bin_dir = os.path.join(self.out_dir, "bin") @@ -87,12 +85,11 @@ class Path: # "other globals referenced by the __del__() method may already have been deleted # or in the process of being torn down (e.g. the import machinery shutting down)" # - log.debug("Saving" + self.temp_dir + "to " + self.cache_dir) + log.debug("Saving" + self.base_dir + "to " + self.cache_dir) # Remove previous cache if os.path.exists(self.cache_dir): shutil.rmtree(self.cache_dir) - shutil.move(self.temp_dir, self.cache_dir) - + shutil.move(self.base_dir, self.cache_dir) def __init_env(self): """Setup environment""" @@ -100,6 +97,11 @@ class Path: def __init_out_dirs(self): """Initialise output directory structure""" + + # Create base dir, if user supplied and not existing + if not os.isdir(self.base_dir): + os.mkdir(self.base_dir) + os.mkdir(self.out_dir) os.mkdir(self.global_explorer_out_dir) os.mkdir(self.bin_dir) From 06f438f824afc0ae5d9a28b78f65ee090e5d0174 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 09:46:06 +0200 Subject: [PATCH 0550/4212] move stuff from path to object, remove if already existent Signed-off-by: Nico Schottelius --- lib/cdist/core/object.py | 37 ++++++++++++++++++++ lib/cdist/path.py | 73 +++------------------------------------- 2 files changed, 42 insertions(+), 68 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index e75c06c8..85822a24 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -195,4 +195,41 @@ class Object(object): return [os.path.join(self.object_dir(cdist_object), "code-local"), os.path.join(self.object_dir(cdist_object), "code-remote")] + # Stays here + def list_object_paths(self, starting_point): + """Return list of paths of existing objects""" + object_paths = [] + + for content in os.listdir(starting_point): + full_path = os.path.join(starting_point, content) + if os.path.isdir(full_path): + object_paths.extend(self.list_object_paths(starting_point = full_path)) + + # Directory contains .cdist -> is an object + if content == DOT_CDIST: + object_paths.append(starting_point) + + return object_paths + + # Stays here + def list_objects(self): + """Return list of existing objects""" + + objects = [] + if os.path.isdir(self.object_base_dir): + object_paths = self.list_object_paths(self.object_base_dir) + + for path in object_paths: + objects.append(os.path.relpath(path, self.object_base_dir)) + + return objects + + # FIXME: object + def type_explorer_output_dir(self, cdist_object): + """Returns and creates dir of the output for a type explorer""" + dir = os.path.join(self.object_dir(cdist_object), "explorer") + if not os.path.isdir(dir): + os.mkdir(dir) + + return dir diff --git a/lib/cdist/path.py b/lib/cdist/path.py index b9d0b6bf..448fc918 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -106,90 +106,27 @@ class Path: os.mkdir(self.global_explorer_out_dir) os.mkdir(self.bin_dir) - - # Stays here - def list_types(self): - """Retuns list of types""" - return os.listdir(self.type_base_dir) - - ###################################################################### - - # FIXME: belongs to here - clearify remote* def remote_mkdir(self, directory): """Create directory on remote side""" cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) - # FIXME: belongs to here - clearify remote* def remove_remote_dir(self, destination): cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) - # FIXME: belongs to here - clearify remote* + # FIXME: To Copy def transfer_dir(self, source, destination): """Transfer directory and previously delete the remote destination""" self.remove_remote_dir(destination) cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + ["-r", source, self.target_host + ":" + destination]) - # FIXME: belongs to here - clearify remote* + # FIXME: To Copy def transfer_file(self, source, destination): """Transfer file""" cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + [source, self.target_host + ":" + destination]) - # FIXME: Explorer or stays - def global_explorer_output_path(self, explorer): - """Returns path of the output for a global explorer""" - return os.path.join(self.global_explorer_out_dir, explorer) - - # FIXME: object - def type_explorer_output_dir(self, cdist_object): - """Returns and creates dir of the output for a type explorer""" - dir = os.path.join(self.object_dir(cdist_object), "explorer") - if not os.path.isdir(dir): - os.mkdir(dir) - - return dir - - # FIXME Stays here / Explorer? - def remote_global_explorer_path(self, explorer): - """Returns path to the remote explorer""" - return os.path.join(REMOTE_GLOBAL_EXPLORER_DIR, explorer) - - # FIXME: stays here - def list_global_explorers(self): - """Return list of available explorers""" - return os.listdir(self.global_explorer_dir) - - # Stays here - def list_object_paths(self, starting_point): - """Return list of paths of existing objects""" - object_paths = [] - - for content in os.listdir(starting_point): - full_path = os.path.join(starting_point, content) - if os.path.isdir(full_path): - object_paths.extend(self.list_object_paths(starting_point = full_path)) - - # Directory contains .cdist -> is an object - if content == DOT_CDIST: - object_paths.append(starting_point) - - return object_paths - - # Stays here - def list_objects(self): - """Return list of existing objects""" - - objects = [] - if os.path.isdir(self.object_base_dir): - object_paths = self.list_object_paths(self.object_base_dir) - - for path in object_paths: - objects.append(os.path.relpath(path, self.object_base_dir)) - - return objects - - # Stays here + # FIXME Move into configinstall def transfer_object_parameter(self, cdist_object): """Transfer the object parameter to the remote destination""" # Create base path before using mkdir -p @@ -199,13 +136,13 @@ class Path: self.transfer_dir(self.object_parameter_dir(cdist_object), self.remote_object_parameter_dir(cdist_object)) - # Stays here + # FIXME Move into configinstall def transfer_global_explorers(self): """Transfer the global explorers""" self.remote_mkdir(REMOTE_GLOBAL_EXPLORER_DIR) self.transfer_dir(self.global_explorer_dir, REMOTE_GLOBAL_EXPLORER_DIR) - # Stays here - FIXME: adjust to type code, loop over types! + # FIXME Move into configinstall def transfer_type_explorers(self, type): """Transfer explorers of a type, but only once""" if type.transferred_explorers: From 0b63919cdd3b8f74b11a66016098e2d213de908c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 09:46:48 +0200 Subject: [PATCH 0551/4212] path -> copy Signed-off-by: Nico Schottelius --- lib/cdist/copy.py | 13 +++++++++++++ lib/cdist/path.py | 13 ------------- 2 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 lib/cdist/copy.py diff --git a/lib/cdist/copy.py b/lib/cdist/copy.py new file mode 100644 index 00000000..b0eae54e --- /dev/null +++ b/lib/cdist/copy.py @@ -0,0 +1,13 @@ + # FIXME: To Copy + def transfer_dir(self, source, destination): + """Transfer directory and previously delete the remote destination""" + self.remove_remote_dir(destination) + cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + + ["-r", source, self.target_host + ":" + destination]) + + # FIXME: To Copy + def transfer_file(self, source, destination): + """Transfer file""" + cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + + [source, self.target_host + ":" + destination]) + diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 448fc918..2f6670e8 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -113,19 +113,6 @@ class Path: def remove_remote_dir(self, destination): cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) - # FIXME: To Copy - def transfer_dir(self, source, destination): - """Transfer directory and previously delete the remote destination""" - self.remove_remote_dir(destination) - cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + - ["-r", source, self.target_host + ":" + destination]) - - # FIXME: To Copy - def transfer_file(self, source, destination): - """Transfer file""" - cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + - [source, self.target_host + ":" + destination]) - # FIXME Move into configinstall def transfer_object_parameter(self, cdist_object): """Transfer the object parameter to the remote destination""" From 08975c4d2f2f78fa13fc0ed1fa07c96d557670da Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 09:47:29 +0200 Subject: [PATCH 0552/4212] path -> config_install Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 36 ++++++++++++++++++++++++++++++++++++ lib/cdist/path.py | 35 ----------------------------------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 2071a0e9..9e2b5edc 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -278,3 +278,39 @@ class ConfigInstall: self.run_type_manifest(cdist_object) cdist_object.prepared = True new_objects_created = True + + # FIXME Move into configinstall + def transfer_object_parameter(self, cdist_object): + """Transfer the object parameter to the remote destination""" + # Create base path before using mkdir -p + self.remote_mkdir(self.remote_object_parameter_dir(cdist_object)) + + # Synchronise parameter dir afterwards + self.transfer_dir(self.object_parameter_dir(cdist_object), + self.remote_object_parameter_dir(cdist_object)) + + # FIXME Move into configinstall + def transfer_global_explorers(self): + """Transfer the global explorers""" + self.remote_mkdir(REMOTE_GLOBAL_EXPLORER_DIR) + self.transfer_dir(self.global_explorer_dir, REMOTE_GLOBAL_EXPLORER_DIR) + + # FIXME Move into configinstall + def transfer_type_explorers(self, type): + """Transfer explorers of a type, but only once""" + if type.transferred_explorers: + log.debug("Skipping retransfer for explorers of %s", type) + return + else: + # Do not retransfer + type.transferred_explorers = True + + # FIXME: Can be explorer_path or explorer_dir, I don't care. + src = type.explorer_path() + dst = type.remote_explorer_path() + + # Transfer if there is at least one explorer + if len(type.explorers) > 0: + # Ensure that the path exists + self.remote_mkdir(dst) + self.transfer_dir(src, dst) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 2f6670e8..2dc06ceb 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -113,38 +113,3 @@ class Path: def remove_remote_dir(self, destination): cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) - # FIXME Move into configinstall - def transfer_object_parameter(self, cdist_object): - """Transfer the object parameter to the remote destination""" - # Create base path before using mkdir -p - self.remote_mkdir(self.remote_object_parameter_dir(cdist_object)) - - # Synchronise parameter dir afterwards - self.transfer_dir(self.object_parameter_dir(cdist_object), - self.remote_object_parameter_dir(cdist_object)) - - # FIXME Move into configinstall - def transfer_global_explorers(self): - """Transfer the global explorers""" - self.remote_mkdir(REMOTE_GLOBAL_EXPLORER_DIR) - self.transfer_dir(self.global_explorer_dir, REMOTE_GLOBAL_EXPLORER_DIR) - - # FIXME Move into configinstall - def transfer_type_explorers(self, type): - """Transfer explorers of a type, but only once""" - if type.transferred_explorers: - log.debug("Skipping retransfer for explorers of %s", type) - return - else: - # Do not retransfer - type.transferred_explorers = True - - # FIXME: Can be explorer_path or explorer_dir, I don't care. - src = type.explorer_path() - dst = type.remote_explorer_path() - - # Transfer if there is at least one explorer - if len(type.explorers) > 0: - # Ensure that the path exists - self.remote_mkdir(dst) - self.transfer_dir(src, dst) From 886c1d32acfa31ec156eccdb3e3169af1053437a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 09:48:43 +0200 Subject: [PATCH 0553/4212] DOT_CDIST -> cdist Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 1 + lib/cdist/path.py | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 3a1b94e3..6ce0c788 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -20,6 +20,7 @@ # VERSION = "2.0.3" +DOT_CDIST = ".cdist" class Error(Exception): """Base exception class for this project""" diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 2dc06ceb..9921dd0f 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -32,8 +32,6 @@ REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") REMOTE_TYPE_DIR = os.path.join(REMOTE_CONF_DIR, "type") REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") -DOT_CDIST = ".cdist" - log = logging.getLogger(__name__) import cdist.exec From 359e5156e27c7f1b397062b07bbe3dbc438c8e43 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 09:52:37 +0200 Subject: [PATCH 0554/4212] +globalexplorer start Signed-off-by: Nico Schottelius --- lib/cdist/core/globalexplorer.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 lib/cdist/core/globalexplorer.py diff --git a/lib/cdist/core/globalexplorer.py b/lib/cdist/core/globalexplorer.py new file mode 100644 index 00000000..1af466e0 --- /dev/null +++ b/lib/cdist/core/globalexplorer.py @@ -0,0 +1,15 @@ + # FIXME: Explorer or stays + def global_explorer_output_path(self, explorer): + """Returns path of the output for a global explorer""" + return os.path.join(self.global_explorer_out_dir, explorer) + + # FIXME Stays here / Explorer? + def remote_global_explorer_path(self, explorer): + """Returns path to the remote explorer""" + return os.path.join(REMOTE_GLOBAL_EXPLORER_DIR, explorer) + + # FIXME: stays here + def list_global_explorers(self): + """Return list of available explorers""" + return os.listdir(self.global_explorer_dir) + From 4b306e45f946ad3f01118ef59fdf512b4563fbe7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 09:53:09 +0200 Subject: [PATCH 0555/4212] more ideas for globalexplorer Signed-off-by: Nico Schottelius --- lib/cdist/core/globalexplorer.py | 51 ++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/lib/cdist/core/globalexplorer.py b/lib/cdist/core/globalexplorer.py index 1af466e0..49052d53 100644 --- a/lib/cdist/core/globalexplorer.py +++ b/lib/cdist/core/globalexplorer.py @@ -13,3 +13,54 @@ """Return list of available explorers""" return os.listdir(self.global_explorer_dir) +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 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 logging +import os +log = logging.getLogger(__name__) + +class Explorer(object): + + def __init__(self, src_dir, dst_dir): + self.src_dir = src_dir + self.dst_dir = dst_dir + + def list_explorers(self): + """Return list of available explorers""" + dir = os.path.join(self.path, "explorer") + if os.path.isdir(dir): + list = os.listdir(dir) + else: + list = [] + + log.debug("Explorers for %s in %s: %s", type, dir, list) + + return list + + def is_install(self): + """Check whether a type is used for installation (if not: for configuration)""" + return os.path.isfile(os.path.join(self.path, "install")) + + def remote_explorer_dir(self): + """Return remote directory that holds the explorers of a type""" + return os.path.join(self.remote_path, "explorer") From 9540d529d687699fc2da7b03626fd6318965aa9a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 09:53:24 +0200 Subject: [PATCH 0556/4212] also allow to overwrite remote_base_dir Signed-off-by: Nico Schottelius --- lib/cdist/path.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/cdist/path.py b/lib/cdist/path.py index 9921dd0f..44b121df 100644 --- a/lib/cdist/path.py +++ b/lib/cdist/path.py @@ -25,12 +25,6 @@ import shutil import sys import tempfile -# Hardcoded paths usually not changable -REMOTE_BASE_DIR = "/var/lib/cdist" -REMOTE_CONF_DIR = os.path.join(REMOTE_BASE_DIR, "conf") -REMOTE_OBJECT_DIR = os.path.join(REMOTE_BASE_DIR, "object") -REMOTE_TYPE_DIR = os.path.join(REMOTE_CONF_DIR, "type") -REMOTE_GLOBAL_EXPLORER_DIR = os.path.join(REMOTE_CONF_DIR, "explorer") log = logging.getLogger(__name__) @@ -74,6 +68,17 @@ class Path: self.object_base_dir = os.path.join(self.out_dir, "object") self.bin_dir = os.path.join(self.out_dir, "bin") + # Remote directories + if "__cdist_remote_base_dir" in os.environ: + self.remote_base_dir = os.environ['__cdist_remote_base_dir'] + else: + self.remote_base_dir = "/var/lib/cdist" + + self.remote_conf_dir = os.path.join(self.remote_base_dir, "conf") + self.remote_object_dir = os.path.join(self.remote_base_dir, "object") + self.remote_type_dir = os.path.join(self.remote_conf_dir, "type") + self.remote_global_explorer_dir = os.path.join(self.remote_conf_dir, "explorer") + # Create directories self.__init_out_dirs() From 73fa0e1ab7ac34b1f621060332e7c72e69a6d0a2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 11:51:21 +0200 Subject: [PATCH 0557/4212] path becomes context (+1 happy developer) Signed-off-by: Nico Schottelius --- lib/cdist/{path.py => context.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/cdist/{path.py => context.py} (100%) diff --git a/lib/cdist/path.py b/lib/cdist/context.py similarity index 100% rename from lib/cdist/path.py rename to lib/cdist/context.py From b568a5886c24554d7b5f13ffd032b04c45b78422 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 11:56:16 +0200 Subject: [PATCH 0558/4212] retrieve explorers from explorer class and allow zero explorers Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 9e2b5edc..d0c27e54 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -60,9 +60,8 @@ class ConfigInstall: def run_global_explorers(self): """Run global explorers""" log.info("Running global explorers") - explorers = self.path.list_global_explorers() - if(len(explorers) == 0): - raise cdist.Error("No explorers found in " + self.path.global_explorer_dir) + + explorers = cdist.core.GlobalExplorer.list_explorers() self.path.transfer_global_explorers() for explorer in explorers: From f99df72931c8374a8f821310ed1f4af9b810806a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 12:04:12 +0200 Subject: [PATCH 0559/4212] ++todo for steven Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 0ff17f6a..0383c23e 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -6,3 +6,14 @@ Object: Type: explorer_path + +GlobalExplorer: + out_path: local path into which the output is written + + cdist.core.GlobalExplorer.base_dir - local directory containing explorers + cdist.core.GlobalExplorer.remote_base_dir - remote directory containing explorers + + path: local path to explorer + remote_path: remote path to explorer + + See config_install: run_global_explorers() From 8a4b8e9b66fa271f1e4b85aa185f110cfeb58d0e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 12:04:38 +0200 Subject: [PATCH 0560/4212] cleanup run_global_explorers() Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index d0c27e54..c2c4a804 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -57,23 +57,6 @@ class ConfigInstall: def cleanup(self): self.path.cleanup() - def run_global_explorers(self): - """Run global explorers""" - log.info("Running global explorers") - - explorers = cdist.core.GlobalExplorer.list_explorers() - - self.path.transfer_global_explorers() - for explorer in explorers: - output = self.path.global_explorer_output_path(explorer) - output_fd = open(output, mode='w') - cmd = [] - cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append(self.path.remote_global_explorer_path(explorer)) - - cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=True) - output_fd.close() - def run_type_explorer(self, cdist_object): """Run type specific explorers for objects""" @@ -225,6 +208,25 @@ class ConfigInstall: cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) ### Cleaned / check functions: Round 1 :-) ################################# + def run_global_explorers(self): + """Run global explorers""" + log.info("Running global explorers") + + src = cdist.core.GlobalExplorer.base_dir + dst = cdist.core.GlobalExplorer.remote_base_dir + + self.context.transfer_dir(src, dst) + + for explorer in cdist.core.GlobalExplorer.list_explorers(): + output_fd = open(explorer.out_path, mode='w') + cmd = [] + cmd.append("__explorer=" + cdist.core.GlobalExplorer.remote_base_dir) + cmd.append(explorer.remote_path) + + cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=True) + output_fd.close() + + def stage_run(self): """The final (and real) step of deployment""" log.info("Generating and executing code") From b936fea3e53729f6f74dc9aa2b36772da7f67d75 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 12:10:57 +0200 Subject: [PATCH 0561/4212] link to emulator in config_install and remove it from emulator Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 19 +++++++++++-------- lib/cdist/emulator.py | 9 --------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index c2c4a804..e3e15548 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -37,9 +37,7 @@ CODE_HEADER = "#!/bin/sh -e\n" class ConfigInstall: """Cdist main class to hold arbitrary data""" - def __init__(self, target_host, - initial_manifest=False, - home=None, + def __init__(self, target_host, initial_manifest=False, exec_path=sys.argv[0], debug=False): @@ -51,7 +49,6 @@ class ConfigInstall: self.path = cdist.path.Path(self.target_host, initial_manifest=initial_manifest, - base_dir=home, debug=debug) def cleanup(self): @@ -84,10 +81,7 @@ class ConfigInstall: cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=True) output_fd.close() - def link_emulator(self): - """Link emulator to types""" - cdist.emulator.link(self.exec_path, - self.path.bin_dir, self.path.list_types()) + def run_initial_manifest(self): """Run the initial manifest""" @@ -208,6 +202,15 @@ class ConfigInstall: cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) ### Cleaned / check functions: Round 1 :-) ################################# + def link_emulator(self): + """Link emulator to types""" + src = os.path.abspath(self.exec_path) + for type in cdist.core.Type.list_types(): + log.debug("Linking emulator: %s to %s", source, destination) + dst = os.path.join(self.context.bin_dir, type.name) + # FIXME: handle exception / make it more beautiful + os.symlink(src, dst) + def run_global_explorers(self): """Run global explorers""" log.info("Running global explorers") diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index f3e9ac30..77f26e7f 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -142,12 +142,3 @@ def run(argv): source_fd.close() log.debug("Finished " + type + "/" + object_id + repr(params)) - - -def link(exec_path, bin_dir, type_list): - """Link type names to cdist-type-emulator""" - source = os.path.abspath(exec_path) - for type in type_list: - destination = os.path.join(bin_dir, type) - log.debug("Linking %s to %s", source, destination) - os.symlink(source, destination) From 240383e4b625afd1ae222e83233efcb7292e24e4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 12:15:23 +0200 Subject: [PATCH 0562/4212] update todo steven Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 0383c23e..09c87851 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -5,7 +5,8 @@ Object: gencode_remote Type: - explorer_path + explorer_dir + remote_explorer_dir GlobalExplorer: out_path: local path into which the output is written From fecd5c99b649b6592b81ea888a7fade843786e65 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 12:18:04 +0200 Subject: [PATCH 0563/4212] ++todo steven Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 09c87851..77b74451 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,9 +1,11 @@ Object: code_remote - code_local + code gencode_local gencode_remote + path_remote + Type: explorer_dir remote_explorer_dir From 79dd98739df2ef323b685185b57c55a77c9a11bd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 12:29:49 +0200 Subject: [PATCH 0564/4212] ++todo steven Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 77b74451..41306a66 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -10,6 +10,9 @@ Type: explorer_dir remote_explorer_dir + explorer_remote_dir + + GlobalExplorer: out_path: local path into which the output is written From e301b74610827ccb2119d386e9393db6fb243856 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 12:42:11 +0200 Subject: [PATCH 0565/4212] ++steven Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 41306a66..cb452450 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,11 +1,13 @@ Object: code_remote code - gencode_local + gencode gencode_remote path_remote + explorer_out_dir + Type: explorer_dir remote_explorer_dir From 480c1bbb357d5bd8215401c5d0b0c3792ae9bc7b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 12:43:17 +0200 Subject: [PATCH 0566/4212] cleanup run_type_explorer() Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 56 +++++++++++++++++++------------------ lib/cdist/context.py | 17 +++++------ 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index e3e15548..b9442f68 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -54,33 +54,6 @@ class ConfigInstall: def cleanup(self): self.path.cleanup() - def run_type_explorer(self, cdist_object): - """Run type specific explorers for objects""" - - type = cdist_object.type - self.path.transfer_type_explorers(type) - - cmd = [] - cmd.append("__explorer=" + cdist.path.REMOTE_GLOBAL_EXPLORER_DIR) - cmd.append("__type_explorer=" + self.path.remote_type_explorer_dir(type)) - cmd.append("__object=" + self.path.remote_object_dir(cdist_object)) - cmd.append("__object_id=" + self.path.get_object_id_from_object(cdist_object)) - cmd.append("__object_fq=" + cdist_object) - - # Need to transfer at least the parameters for objects to be useful - self.path.transfer_object_parameter(cdist_object) - - explorers = self.path.list_type_explorers(type) - for explorer in explorers: - remote_cmd = cmd + [os.path.join(self.path.remote_type_explorer_dir(type), explorer)] - output = os.path.join(self.path.type_explorer_output_dir(cdist_object), explorer) - output_fd = open(output, mode='w') - log.debug("%s exploring %s using %s storing to %s", - cdist_object, explorer, remote_cmd, output) - - cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=True) - output_fd.close() - def run_initial_manifest(self): @@ -202,6 +175,35 @@ class ConfigInstall: cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) ### Cleaned / check functions: Round 1 :-) ################################# + def run_type_explorer(self, cdist_object): + """Run type specific explorers for objects""" + + type = cdist_object.type + # FIXME + self.path.transfer_type_explorers(type) + + cmd = [] + cmd.append("__explorer=" + self.context.remote_global_explorer_dir) + cmd.append("__type_explorer=" + type.explorer_remote_dir) + cmd.append("__object=" + object.path_remote) + cmd.append("__object_id=" + object.object_id) + cmd.append("__object_fq=" + cdist_object) + + # Need to transfer at least the parameters for objects to be useful + self.path.transfer_object_parameter(cdist_object) + + explorers = self.path.list_type_explorers(type) + for explorer in explorers: + remote_cmd = cmd + [os.path.join(type.explorer_remote_dir, explorer)] + output = os.path.join(cdist_object.explorer_output_dir(), explorer) + output_fd = open(output, mode='w') + log.debug("%s exploring %s using %s storing to %s", + cdist_object, explorer, remote_cmd, output) + + cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=True) + output_fd.close() + + def link_emulator(self): """Link emulator to types""" src = os.path.abspath(self.exec_path) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index 44b121df..44f432a8 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -30,8 +30,8 @@ log = logging.getLogger(__name__) import cdist.exec -class Path: - """Class that handles path related configurations""" +class Context: + """Storing context dependent information""" def __init__(self, target_host, initial_manifest=False, debug=False): @@ -44,13 +44,14 @@ class Path: self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) # Input directories - self.conf_dir = os.path.join(self.base_dir, "conf") - self.cache_base_dir = os.path.join(self.base_dir, "cache") - self.cache_dir = os.path.join(self.cache_base_dir, target_host) - self.global_explorer_dir = os.path.join(self.conf_dir, "explorer") - self.lib_dir = os.path.join(self.base_dir, "lib") + self.cache_dir = os.path.join(self.base_dir, "cache", target_host) self.manifest_dir = os.path.join(self.conf_dir, "manifest") - self.type_base_dir = os.path.join(self.conf_dir, "type") + + # Probably unused paths + # self.conf_dir = os.path.join(self.base_dir, "conf") + # self.global_explorer_dir = os.path.join(self.conf_dir, "explorer") + # self.lib_dir = os.path.join(self.base_dir, "lib") + # self.type_base_dir = os.path.join(self.conf_dir, "type") # Mostly static, but can be overwritten on user demand if initial_manifest: From 860473fcda835e8e9d94171a4e4229a907ba9192 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 12:46:03 +0200 Subject: [PATCH 0567/4212] +info required Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index cb452450..a4f2dd40 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -14,6 +14,8 @@ Type: explorer_remote_dir + type.manifest_path + GlobalExplorer: out_path: local path into which the output is written From 9473a3a19e24a9bde1bc6de9ec8875af3930c7f1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 12:49:30 +0200 Subject: [PATCH 0568/4212] Type: implement explorer_dir, remote_explorer_dir Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index 7492659e..7856c92f 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -25,6 +25,8 @@ import os import cdist +# FIXME: i should not have to care about prefix directory, local, remote and such. +# I know what my internals look like, the outside is none of my business. class Type(object): """Represents a cdist type. @@ -51,6 +53,28 @@ class Type(object): except KeyError as e: raise cdist.MissingEnvironmentVariableError(e.args[0]) + @staticmethod + def remote_base_dir(): + """Return the absolute path to the top level directory where types + are kept on the remote/target host. + + Requires the environment variable '__cdist_remote_base_dir' to be set. + + """ + try: + return os.path.join( + os.environ['__cdist_remote_base_dir'], + 'conf', + 'type' + ) + except KeyError as e: + raise cdist.MissingEnvironmentVariableError(e.args[0]) + + # FIXME: probably wrong place for this + @property + def remote_explorer_dir(self): + return os.path.join(self.remote_path, "explorer") + @classmethod def list_types(cls): """Return a list of type instances""" @@ -80,6 +104,13 @@ class Type(object): self.base_dir(), self.name ) + # FIXME: prefix directory should not leak into me + @property + def remote_path(self): + return os.path.join( + self.remote_base_dir(), + self.name + ) @property def is_singleton(self): From 9a8e1681687b7eca7f9c04dc595fb593697195ce Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 12:50:00 +0200 Subject: [PATCH 0569/4212] --todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 7 ------- 1 file changed, 7 deletions(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 41306a66..37945166 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -6,13 +6,6 @@ Object: path_remote -Type: - explorer_dir - remote_explorer_dir - - explorer_remote_dir - - GlobalExplorer: out_path: local path into which the output is written From 4a98b9af55931dccd565ee243abaccc02ff748f0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 12:56:36 +0200 Subject: [PATCH 0570/4212] finish run_type_manifest Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index b9442f68..96f9224e 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -47,15 +47,13 @@ class ConfigInstall: self.debug = debug self.exec_path = exec_path - self.path = cdist.path.Path(self.target_host, - initial_manifest=initial_manifest, - debug=debug) + self.context = cdist.context.Context(self.target_host, + initial_manifest=initial_manifest, + debug=debug) def cleanup(self): self.path.cleanup() - - def run_initial_manifest(self): """Run the initial manifest""" log.info("Running initial manifest %s", self.path.initial_manifest) @@ -64,15 +62,15 @@ class ConfigInstall: def run_type_manifest(self, cdist_object): """Run manifest for a specific object""" - type = self.path.get_type_from_object(cdist_object) - manifest = self.path.type_dir(type, "manifest") + type = cdist_object.type + manifest = type.manifest_path - log.debug("%s: Running %s", cdist_object, manifest) + log.debug("%s: Running %s", cdist_object.name, manifest) if os.path.exists(manifest): - env = { "__object" : self.path.object_dir(cdist_object), - "__object_id": self.path.get_object_id_from_object(cdist_object), - "__object_fq": cdist_object, - "__type": self.path.type_dir(type) + env = { "__object" : cdist_object.path, + "__object_id": cdist_object.object_id, + "__object_fq": cdist_object.name, + "__type": type.path, } self.run_manifest(manifest, extra_env=env) @@ -80,11 +78,14 @@ class ConfigInstall: """Run a manifest""" log.debug("Running manifest %s, env=%s", manifest, extra_env) env = os.environ.copy() - env['PATH'] = self.path.bin_dir + ":" + env['PATH'] + env['PATH'] = self.context.bin_dir + ":" + env['PATH'] # Information required in every manifest env['__target_host'] = self.target_host - env['__global'] = self.path.out_dir + + # FIXME: __global == __cdist_out_dir + # FIXME: __global? shouldn't this be $global? + env['__global'] = self.context.out_dir # Submit debug flag to manifest, can be used by emulator and types if self.debug: @@ -102,6 +103,7 @@ class ConfigInstall: cdist.exec.shell_run_or_debug_fail(manifest, [manifest], env=env) +################################################################################ def object_run(self, cdist_object, mode): """Run gencode or code for an object""" log.debug("Running %s from %s", mode, cdist_object) From 00550edfcbed8f767994ac602846cb7ff634de42 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 12:58:35 +0200 Subject: [PATCH 0571/4212] finish run_manifest() Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 96f9224e..548d3808 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -83,8 +83,7 @@ class ConfigInstall: # Information required in every manifest env['__target_host'] = self.target_host - # FIXME: __global == __cdist_out_dir - # FIXME: __global? shouldn't this be $global? + # FIXME: __global == __cdist_out_dir - duplication env['__global'] = self.context.out_dir # Submit debug flag to manifest, can be used by emulator and types @@ -95,7 +94,7 @@ class ConfigInstall: env['__cdist_manifest'] = manifest # Required to find types - env['__cdist_type_base_dir'] = self.path.type_base_dir + env['__cdist_type_base_dir'] = type.path # Other environment stuff if extra_env: @@ -104,6 +103,7 @@ class ConfigInstall: cdist.exec.shell_run_or_debug_fail(manifest, [manifest], env=env) ################################################################################ + def object_run(self, cdist_object, mode): """Run gencode or code for an object""" log.debug("Running %s from %s", mode, cdist_object) From 34f2999e146aa10ca72dc72a9c4d8c3621c756e9 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 12:59:29 +0200 Subject: [PATCH 0572/4212] Type: implement manifest_path Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index 7856c92f..36f6c276 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -70,11 +70,6 @@ class Type(object): except KeyError as e: raise cdist.MissingEnvironmentVariableError(e.args[0]) - # FIXME: probably wrong place for this - @property - def remote_explorer_dir(self): - return os.path.join(self.remote_path, "explorer") - @classmethod def list_types(cls): """Return a list of type instances""" @@ -112,6 +107,15 @@ class Type(object): self.name ) + # FIXME: probably wrong place for this + @property + def remote_explorer_dir(self): + return os.path.join(self.remote_path, "explorer") + + @property + def manifest_path(self): + return os.path.join(self.path, "manifest") + @property def is_singleton(self): """Check whether a type is a singleton.""" From d3ae8b7c9017d49ff81ae9d3d969f3753809f34b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 12:59:53 +0200 Subject: [PATCH 0573/4212] --todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index a2a4740e..d35565eb 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -10,7 +10,6 @@ Object: Type: - type.manifest_path GlobalExplorer: From 4f33e5222dda3bb2477281b613277ac3214172d0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 13:04:00 +0200 Subject: [PATCH 0574/4212] Type: implement gencode, gencode_remote Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index 36f6c276..f679bb04 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -116,6 +116,14 @@ class Type(object): def manifest_path(self): return os.path.join(self.path, "manifest") + @property + def gencode(self): + return os.path.join(self.path, "gencode-local") + + @property + def gencode_remote(self): + return os.path.join(self.path, "gencode-remote") + @property def is_singleton(self): """Check whether a type is a singleton.""" From 9482f9ef439aabffe2640a1a5eaec37ab1d0aea7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 13:05:06 +0200 Subject: [PATCH 0575/4212] --todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index d35565eb..0bf8aed1 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,10 +1,6 @@ Object: code_remote code - gencode - gencode_remote - - path_remote explorer_out_dir From 3ef97980987bd113ad618bc31dcd14212bfa74a9 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 13:06:56 +0200 Subject: [PATCH 0576/4212] implement code, code_remote Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 85822a24..65abc012 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -108,6 +108,13 @@ class Object(object): DOT_CDIST ) + @property + def code(self): + return os.path.join(self.path, "code-local") + + @property + def code_remote(self): + return os.path.join(self.path, "code-remote") ### requirements @property From 36803d16dbaccc689bdb2d16adc1cedcdb3e619e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 13:07:13 +0200 Subject: [PATCH 0577/4212] --todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 0bf8aed1..144c4150 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,6 +1,4 @@ Object: - code_remote - code explorer_out_dir From af5a99dc9fd7ca6ef10589eee7bcc73c88ed8a17 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 13:14:47 +0200 Subject: [PATCH 0578/4212] update object_run() for new interface Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 548d3808..64ad33d0 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -108,11 +108,11 @@ class ConfigInstall: """Run gencode or code for an object""" log.debug("Running %s from %s", mode, cdist_object) - # FIXME: replace with new object interface - file=os.path.join(self.path.object_dir(cdist_object), "require") - requirements = cdist.path.file_to_list(file) - type = self.path.get_type_from_object(cdist_object) + requirements = cdist_object.requirements + type = cdist_object.type + # FIXME: ensure objects are not run multiple times! + # FIXME: probably mark objects! for requirement in requirements: log.debug("Object %s requires %s", cdist_object, requirement) self.object_run(requirement, mode=mode) @@ -122,22 +122,23 @@ class ConfigInstall: # env = os.environ.copy() env['__target_host'] = self.target_host - env['__global'] = self.path.out_dir - env["__object"] = self.path.object_dir(cdist_object) - env["__object_id"] = self.path.get_object_id_from_object(cdist_object) - env["__object_fq"] = cdist_object - env["__type"] = self.path.type_dir(type) + env['__global'] = self.context.out_dir + env["__object"] = cdist_object.path + env["__object_id"] = cdist_object.object_id + env["__object_fq"] = cdist_object.name + env["__type"] = type.name if mode == "gencode": paths = [ - self.path.type_dir(type, "gencode-local"), - self.path.type_dir(type, "gencode-remote") + type.gencode + type.gencode_remote ] - for bin in paths: + + for cmd in ["local", "remote"]: + bin = getattr(type, "gencode_" + cmd) + if os.path.isfile(bin): - # omit "gen" from gencode and use it for output base - outfile=os.path.join(self.path.object_dir(cdist_object), - os.path.basename(bin)[3:]) + outfile = getattr(cdist_object, "code_" + cmd) outfile_fd = open(outfile, "w") @@ -157,6 +158,7 @@ class ConfigInstall: # Add header and make executable - identically to 0o700 os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + # FIXME: use new interface # Mark object as changed open(os.path.join(self.path.object_dir(cdist_object), "changed"), "w").close() From 6e011dc289c4545c4d078f3dec86b3f038a45295 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 13:15:11 +0200 Subject: [PATCH 0579/4212] implement explorer_out_dir Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 65abc012..e224a18f 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -116,6 +116,13 @@ class Object(object): def code_remote(self): return os.path.join(self.path, "code-remote") + @property + def explorer_out_dir(self): + path = os.path.join(self.path, "explorer") + if not os.path.isdir(path): + os.mkdir(path) + return path + ### requirements @property def requirements(self): From d36ab75b1a38066b7195b47685997827e76a874b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 13:15:23 +0200 Subject: [PATCH 0580/4212] --todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 144c4150..262255d7 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,7 +1,5 @@ Object: - explorer_out_dir - Type: From d9f86e26d96afd6adcc6115bd01e3be13a8a6795 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 13:15:52 +0200 Subject: [PATCH 0581/4212] consistent naming Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index e224a18f..c47fc905 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -109,7 +109,7 @@ class Object(object): ) @property - def code(self): + def code_local(self): return os.path.join(self.path, "code-local") @property From 4db02516e7952d6ab3219d1beb84b4db7f7a6c3d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 13:16:14 +0200 Subject: [PATCH 0582/4212] consistent naming Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index f679bb04..8439464e 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -117,7 +117,7 @@ class Type(object): return os.path.join(self.path, "manifest") @property - def gencode(self): + def gencode_local(self): return os.path.join(self.path, "gencode-local") @property From f121934769959386d3e95e77d37663323bb083e3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 13:34:22 +0200 Subject: [PATCH 0583/4212] cleanup object_run() finally Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 99 +++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 55 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 64ad33d0..d77f6d7b 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -104,16 +104,17 @@ class ConfigInstall: ################################################################################ - def object_run(self, cdist_object, mode): + def object_run(self, cdist_object): """Run gencode or code for an object""" log.debug("Running %s from %s", mode, cdist_object) - requirements = cdist_object.requirements + # Catch requirements, which re-call us + if cdist_object.ran: + return + type = cdist_object.type - # FIXME: ensure objects are not run multiple times! - # FIXME: probably mark objects! - for requirement in requirements: + for requirement in cdist_object.requirements: log.debug("Object %s requires %s", cdist_object, requirement) self.object_run(requirement, mode=mode) @@ -128,56 +129,46 @@ class ConfigInstall: env["__object_fq"] = cdist_object.name env["__type"] = type.name - if mode == "gencode": - paths = [ - type.gencode - type.gencode_remote - ] + # gencode + for cmd in ["local", "remote"]: + bin = getattr(type, "gencode_" + cmd) - for cmd in ["local", "remote"]: - bin = getattr(type, "gencode_" + cmd) - - if os.path.isfile(bin): - outfile = getattr(cdist_object, "code_" + cmd) - - outfile_fd = open(outfile, "w") - - # Need to flush to ensure our write is done before stdout write - outfile_fd.write(CODE_HEADER) - outfile_fd.flush() - - cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) - outfile_fd.close() - - status = os.stat(outfile) - - # Remove output if empty, else make it executable - if status.st_size == len(CODE_HEADER): - os.unlink(outfile) - else: - # Add header and make executable - identically to 0o700 - os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) - - # FIXME: use new interface - # Mark object as changed - open(os.path.join(self.path.object_dir(cdist_object), "changed"), "w").close() - - - if mode == "code": - local_dir = self.path.object_dir(cdist_object) - remote_dir = self.path.remote_object_dir(cdist_object) - - bin = os.path.join(local_dir, "code-local") if os.path.isfile(bin): - cdist.exec.run_or_fail([bin]) - + outfile = getattr(cdist_object, "code_" + cmd) + + outfile_fd = open(outfile, "w") + + # Need to flush to ensure our write is done before stdout write + outfile_fd.write(CODE_HEADER) + outfile_fd.flush() + + cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) + outfile_fd.close() + + status = os.stat(outfile) + + # Remove output if empty, else make it executable + if status.st_size == len(CODE_HEADER): + os.unlink(outfile) + else: + # Add header and make executable - identically to 0o700 + os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + cdist_object.changed=True + + # code local + code_local = cdist_object.code_local + if os.path.isfile(code_local): + cdist.exec.run_or_fail([code_local]) + + # code remote + local_remote_code = cdist_object.code_remote + remote_remote_code = cdist_object.code_remote_remote + if os.path.isfile(local_remote_code): + self.context.transfer_file(local_remote_code, remote_remote_code) + cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) + + cdist_object.ran = True - local_remote_code = os.path.join(local_dir, "code-remote") - remote_remote_code = os.path.join(remote_dir, "code-remote") - if os.path.isfile(local_remote_code): - self.path.transfer_file(local_remote_code, remote_remote_code) - cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) - ### Cleaned / check functions: Round 1 :-) ################################# def run_type_explorer(self, cdist_object): """Run type specific explorers for objects""" @@ -239,11 +230,9 @@ class ConfigInstall: def stage_run(self): """The final (and real) step of deployment""" log.info("Generating and executing code") - # Now do the final steps over the existing objects for cdist_object in cdist.core.Object.list_objects(): log.debug("Run object: %s", cdist_object) - self.object_run(cdist_object, mode="gencode") - self.object_run(cdist_object, mode="code") + self.object_run(cdist_object) def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" From ca5361afc1df1cdb585f581281e9cc5bccf16868 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 13:36:51 +0200 Subject: [PATCH 0584/4212] remote cdist.path, use base_dir Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 2 +- lib/cdist/config_install.py | 5 ++--- lib/cdist/emulator.py | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index 942d2917..c5f4b4ef 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -42,7 +42,7 @@ def config(args): os.environ['__remote_copy'] = "scp -o User=root -q" for host in args.host: - c = Config(host, initial_manifest=args.manifest, home=args.cdist_home, debug=args.debug) + c = Config(host, initial_manifest=args.manifest, base_dir=args.cdist_home, debug=args.debug) if args.parallel: log.debug("Creating child process for %s", host) process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index d77f6d7b..a8ea9043 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -25,10 +25,9 @@ import os import stat import sys -import cdist.emulator -import cdist.path - +import cdist.context import cdist.core +import cdist.emulator log = logging.getLogger(__name__) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 77f26e7f..aa22e1fa 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -24,7 +24,6 @@ import logging import os import cdist -import cdist.path log = logging.getLogger(__name__) From 386e2ca34c2c400a6d848dd0f8bc24d50c4f72ce Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 13:37:56 +0200 Subject: [PATCH 0585/4212] make cli work again Signed-off-by: Nico Schottelius --- bin/cdist | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 36dc3d5c..bd6825eb 100755 --- a/bin/cdist +++ b/bin/cdist @@ -115,9 +115,7 @@ if __name__ == "__main__": import cdist import cdist.banner import cdist.config - import cdist.exec import cdist.install - import cdist.path commandline() From 1138d8b439acb2f343a4d4f046882ec10b9dff84 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 13:44:07 +0200 Subject: [PATCH 0586/4212] remote_remote_code_remote_remote Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index a8ea9043..e8d179e8 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -101,8 +101,6 @@ class ConfigInstall: cdist.exec.shell_run_or_debug_fail(manifest, [manifest], env=env) -################################################################################ - def object_run(self, cdist_object): """Run gencode or code for an object""" log.debug("Running %s from %s", mode, cdist_object) @@ -161,7 +159,7 @@ class ConfigInstall: # code remote local_remote_code = cdist_object.code_remote - remote_remote_code = cdist_object.code_remote_remote + remote_remote_code = cdist_object.remote_code_remote if os.path.isfile(local_remote_code): self.context.transfer_file(local_remote_code, remote_remote_code) cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) From 2b0a337584b929546e1515824c3b8ccc991ab7ec Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 13:45:19 +0200 Subject: [PATCH 0587/4212] fix base_dir passing Signed-off-by: Nico Schottelius --- bin/cdist | 1 - lib/cdist/config_install.py | 7 ++++--- lib/cdist/context.py | 7 +++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/bin/cdist b/bin/cdist index bd6825eb..7d2c035b 100755 --- a/bin/cdist +++ b/bin/cdist @@ -112,7 +112,6 @@ if __name__ == "__main__": import cdist.emulator cdist.emulator.run(sys.argv) else: - import cdist import cdist.banner import cdist.config import cdist.install diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index e8d179e8..407cdcd7 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -37,8 +37,9 @@ class ConfigInstall: """Cdist main class to hold arbitrary data""" def __init__(self, target_host, initial_manifest=False, - exec_path=sys.argv[0], - debug=False): + base_dir=False, + exec_path=sys.argv[0], + debug=False): self.target_host = target_host os.environ['target_host'] = target_host @@ -47,7 +48,7 @@ class ConfigInstall: self.exec_path = exec_path self.context = cdist.context.Context(self.target_host, - initial_manifest=initial_manifest, + initial_manifest=initial_manifest, base_dir=base_dir, debug=debug) def cleanup(self): diff --git a/lib/cdist/context.py b/lib/cdist/context.py index 44f432a8..1615d196 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -33,12 +33,15 @@ import cdist.exec class Context: """Storing context dependent information""" - def __init__(self, target_host, initial_manifest=False, debug=False): + def __init__(self, target_host, initial_manifest=False, base_dir=False, + debug=False): self.target_host = target_host # Base and Temp Base - if "__cdist_base_dir" in os.environ: + if base_dir: + self.base_dir = base_dir + elif "__cdist_base_dir" in os.environ: self.base_dir = os.environ['__cdist_base_dir'] else: self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) From fc7ae28b02f10109ccde685ccfd04021b7131558 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 13:45:45 +0200 Subject: [PATCH 0588/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index bfbdd8c3..b8fcc5b0 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -8,6 +8,8 @@ - Create GlobalExplorer +- base_dir passing in config/config_install superseeded by __cdist_base_dir? + -------------------------------------------------------------------------------- - insert prefix into logger to distinguish between modules From e03ebcd5c163ca583279ae937c4f837a98ea3f4a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 13:46:30 +0200 Subject: [PATCH 0589/4212] require conf_dir to find manifest_dir to find manifest Signed-off-by: Nico Schottelius --- lib/cdist/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index 1615d196..673309af 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -48,10 +48,10 @@ class Context: # Input directories self.cache_dir = os.path.join(self.base_dir, "cache", target_host) + self.conf_dir = os.path.join(self.base_dir, "conf") self.manifest_dir = os.path.join(self.conf_dir, "manifest") # Probably unused paths - # self.conf_dir = os.path.join(self.base_dir, "conf") # self.global_explorer_dir = os.path.join(self.conf_dir, "explorer") # self.lib_dir = os.path.join(self.base_dir, "lib") # self.type_base_dir = os.path.join(self.conf_dir, "type") From fc6ae548893fd9bc1a447e79aec70ba417145057 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 13:48:10 +0200 Subject: [PATCH 0590/4212] os.path not os Signed-off-by: Nico Schottelius --- lib/cdist/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index 673309af..3ecd84e0 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -106,7 +106,7 @@ class Context: """Initialise output directory structure""" # Create base dir, if user supplied and not existing - if not os.isdir(self.base_dir): + if not os.path.isdir(self.base_dir): os.mkdir(self.base_dir) os.mkdir(self.out_dir) From ed347ffb8a547ca3df02a98b2241c29bc3a20faf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 13:49:14 +0200 Subject: [PATCH 0591/4212] fix init_deploy() Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 407cdcd7..8d926447 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -247,8 +247,8 @@ class ConfigInstall: """Ensure the base directories are cleaned up""" log.debug("Creating clean directory structure") - self.path.remove_remote_dir(cdist.path.REMOTE_BASE_DIR) - self.path.remote_mkdir(cdist.path.REMOTE_BASE_DIR) + self.context.remove_remote_dir(self.context.remote_base_dir) + self.context.remote_mkdir(self.context.remote_base_dir) self.link_emulator() def stage_prepare(self): From f39418a7b5f9d71c7ec49b1ffa1f5bbd1126ade0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 13:50:17 +0200 Subject: [PATCH 0592/4212] implement remote_code_remote :-( Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 42 ++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index c47fc905..b4469e61 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -31,7 +31,8 @@ log = logging.getLogger(__name__) DOT_CDIST = '.cdist' - +# FIXME: i should not have to care about prefix directory, local, remote and such. +# I know what my internals look like, the outside is none of my business. class Object(object): """Represents a cdist object. @@ -63,6 +64,21 @@ class Object(object): return base_dir @classmethod + def remote_base_dir(): + """Return the absolute path to the top level directory where objects + are kept on the remote/target host. + + Requires the environment variable '__cdist_remote_out_dir' to be set. + + """ + try: + return os.path.join( + os.environ['__cdist_remote_out_dir'], + 'object', + ) + except KeyError as e: + raise cdist.MissingEnvironmentVariableError(e.args[0]) + def list_objects(cls): """Return a list of object instances""" for object_name in cls.list_object_names(): @@ -123,6 +139,19 @@ class Object(object): os.mkdir(path) return path + # FIXME: prefix directory should not leak into me + @property + def remote_path(self): + return os.path.join( + self.remote_base_dir(), + self.name, + DOT_CDIST + ) + @property + def remote_code_remote(self): + return os.path.join(self.remote_path, "code-remote") + + ### requirements @property def requirements(self): @@ -175,18 +204,7 @@ class Object(object): pass ### /changed - # FIXME: implement other properties/methods - # FIXME: check following methods: implement or revoke / delete - # FIXME: Object - def get_object_id_from_object(self, cdist_object): - """Returns everything but the first part (i.e. object_id) of an object""" - return os.sep.join(cdist_object.split(os.sep)[1:]) - - # FIXME: Object - def object_dir(self, cdist_object): - """Returns the full path to the object (including .cdist)""" - return os.path.join(self.object_base_dir, cdist_object, DOT_CDIST) # FIXME: Object def remote_object_dir(self, cdist_object): From 1b484e2d87111d0c44bdeb8e985d6f45937618bd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 13:50:37 +0200 Subject: [PATCH 0593/4212] setup __cdist_base_dir Signed-off-by: Nico Schottelius --- lib/cdist/context.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index 3ecd84e0..a503372f 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -45,6 +45,7 @@ class Context: self.base_dir = os.environ['__cdist_base_dir'] else: self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) + # Input directories self.cache_dir = os.path.join(self.base_dir, "cache", target_host) @@ -86,6 +87,8 @@ class Context: # Create directories self.__init_out_dirs() + self.__init_env() + def cleanup(self): # Do not use in __del__: # http://docs.python.org/reference/datamodel.html#customization @@ -100,7 +103,8 @@ class Context: def __init_env(self): """Setup environment""" - os.environ['__cdist_out_dir'] = self.out_dir + os.environ['__cdist_out_dir'] = self.out_dir + os.environ['__cdist_base_dir'] = self.base_dir def __init_out_dirs(self): """Initialise output directory structure""" From fa1a4263e062507003bc569e15086d4b184c0232 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 13:51:00 +0200 Subject: [PATCH 0594/4212] setup __cdist_base_dir Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 8d926447..71d352da 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -201,8 +201,9 @@ class ConfigInstall: """Link emulator to types""" src = os.path.abspath(self.exec_path) for type in cdist.core.Type.list_types(): - log.debug("Linking emulator: %s to %s", source, destination) dst = os.path.join(self.context.bin_dir, type.name) + log.debug("Linking emulator: %s to %s", src, dst) + # FIXME: handle exception / make it more beautiful os.symlink(src, dst) From 1992c9a1751b0bc5c3143224ed8c46693fc87e46 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 13:52:55 +0200 Subject: [PATCH 0595/4212] --legacy code Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 44 ---------------------------------------- 1 file changed, 44 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index b4469e61..b922701d 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -95,7 +95,6 @@ class Object(object): def list_object_names(cls): """Return a list of object names""" for path, dirs, files in os.walk(cls.base_dir()): - # FIXME: use constant instead of string if DOT_CDIST in dirs: yield os.path.relpath(path, cls.base_dir()) @@ -206,11 +205,6 @@ class Object(object): - # FIXME: Object - def remote_object_dir(self, cdist_object): - """Returns the remote full path to the object (including .cdist)""" - return os.path.join(REMOTE_OBJECT_DIR, cdist_object, DOT_CDIST) - # FIXME: Object def object_parameter_dir(self, cdist_object): """Returns the dir to the object parameter""" @@ -227,41 +221,3 @@ class Object(object): return [os.path.join(self.object_dir(cdist_object), "code-local"), os.path.join(self.object_dir(cdist_object), "code-remote")] - # Stays here - def list_object_paths(self, starting_point): - """Return list of paths of existing objects""" - object_paths = [] - - for content in os.listdir(starting_point): - full_path = os.path.join(starting_point, content) - if os.path.isdir(full_path): - object_paths.extend(self.list_object_paths(starting_point = full_path)) - - # Directory contains .cdist -> is an object - if content == DOT_CDIST: - object_paths.append(starting_point) - - return object_paths - - # Stays here - def list_objects(self): - """Return list of existing objects""" - - objects = [] - if os.path.isdir(self.object_base_dir): - object_paths = self.list_object_paths(self.object_base_dir) - - for path in object_paths: - objects.append(os.path.relpath(path, self.object_base_dir)) - - return objects - - # FIXME: object - def type_explorer_output_dir(self, cdist_object): - """Returns and creates dir of the output for a type explorer""" - dir = os.path.join(self.object_dir(cdist_object), "explorer") - if not os.path.isdir(dir): - os.mkdir(dir) - - return dir - From 13ec2a82b6689b075f6c65ea8dc1fb51105cd037 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 14:25:39 +0200 Subject: [PATCH 0596/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 262255d7..0760f368 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -14,3 +14,7 @@ GlobalExplorer: remote_path: remote path to explorer See config_install: run_global_explorers() + +Object/Type: + - rutern relative only + - Have accept absulet path on listing From e1f0d60e8bf3aff20d028ea7920105fa274e0aec Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:03:26 +0200 Subject: [PATCH 0597/4212] restructure to _path and do not make context dependent on env Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 9 +++-- lib/cdist/context.py | 75 ++++++++++++++++++++----------------- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 71d352da..d122348d 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -54,11 +54,14 @@ class ConfigInstall: def cleanup(self): self.path.cleanup() + def __init_env(self): + """Setup environment""" + def run_initial_manifest(self): """Run the initial manifest""" - log.info("Running initial manifest %s", self.path.initial_manifest) - env = { "__manifest" : self.path.manifest_dir } - self.run_manifest(self.path.initial_manifest, extra_env=env) + log.info("Running initial manifest %s", self.context.initial_manifest) + env = { "__manifest" : self.context.manifest_dir } + self.run_manifest(self.context.initial_manifest, extra_env=env) def run_type_manifest(self, cdist_object): """Run manifest for a specific object""" diff --git a/lib/cdist/context.py b/lib/cdist/context.py index a503372f..edc29d60 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -31,58 +31,63 @@ log = logging.getLogger(__name__) import cdist.exec class Context: - """Storing context dependent information""" + """Storing context information""" - def __init__(self, target_host, initial_manifest=False, base_dir=False, + def __init__(self, + target_host, + initial_manifest=False, + base_path=False, + out_path=False, debug=False): self.target_host = target_host # Base and Temp Base - if base_dir: - self.base_dir = base_dir - elif "__cdist_base_dir" in os.environ: - self.base_dir = os.environ['__cdist_base_dir'] + if base_path: + self.base_path = base_path else: - self.base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) + self.base_path = + os.path.abspath( + os.path.join(os.path.dirname(__file__), + os.pardir, + os.pardir)) # Input directories - self.cache_dir = os.path.join(self.base_dir, "cache", target_host) - self.conf_dir = os.path.join(self.base_dir, "conf") - self.manifest_dir = os.path.join(self.conf_dir, "manifest") + self.cache_path = os.path.join(self.base_path, "cache", target_host) + self.conf_path = os.path.join(self.base_path, "conf") - # Probably unused paths - # self.global_explorer_dir = os.path.join(self.conf_dir, "explorer") - # self.lib_dir = os.path.join(self.base_dir, "lib") - # self.type_base_dir = os.path.join(self.conf_dir, "type") + self.global_explorer_path = os.path.join(self.conf_path, "explorer") + self.manifest_path = os.path.join(self.conf_path, "manifest") + self.type_base_path = os.path.join(self.conf_path, "type") + self.lib_path = os.path.join(self.base_path, "lib") # Mostly static, but can be overwritten on user demand if initial_manifest: self.initial_manifest = initial_manifest else: - self.initial_manifest = os.path.join(self.manifest_dir, "init") + self.initial_manifest = os.path.join(self.manifest_path, "init") # Output directories - if "__cdist_out_dir" in os.environ: - self.out_dir = os.environ['__cdist_out_dir'] + if out_path: + self.out_path = out_path: else: - self.out_dir = os.path.join(tempfile.mkdtemp(), "out") + self.out_path = os.path.join(tempfile.mkdtemp(), "out") - self.global_explorer_out_dir = os.path.join(self.out_dir, "explorer") - self.object_base_dir = os.path.join(self.out_dir, "object") - self.bin_dir = os.path.join(self.out_dir, "bin") + self.global_explorer_out_path = os.path.join(self.out_path, "explorer") + self.object_base_path = os.path.join(self.out_path, "object") + self.bin_path = os.path.join(self.out_path, "bin") # Remote directories - if "__cdist_remote_base_dir" in os.environ: - self.remote_base_dir = os.environ['__cdist_remote_base_dir'] + if "__cdist_remote_base_path" in os.environ: + self.remote_base_path = os.environ['__cdist_remote_base_path'] else: - self.remote_base_dir = "/var/lib/cdist" + self.remote_base_path = "/var/lib/cdist" - self.remote_conf_dir = os.path.join(self.remote_base_dir, "conf") - self.remote_object_dir = os.path.join(self.remote_base_dir, "object") - self.remote_type_dir = os.path.join(self.remote_conf_dir, "type") - self.remote_global_explorer_dir = os.path.join(self.remote_conf_dir, "explorer") + self.remote_conf_path = os.path.join(self.remote_base_path, "conf") + self.remote_object_dir = os.path.join(self.remote_base_path, "object") + self.remote_type_dir = os.path.join(self.remote_conf_path, "type") + self.remote_global_explorer_dir = os.path.join(self.remote_conf_path, "explorer") # Create directories self.__init_out_dirs() @@ -95,23 +100,23 @@ class Context: # "other globals referenced by the __del__() method may already have been deleted # or in the process of being torn down (e.g. the import machinery shutting down)" # - log.debug("Saving" + self.base_dir + "to " + self.cache_dir) + log.debug("Saving" + self.base_path + "to " + self.cache_path) # Remove previous cache - if os.path.exists(self.cache_dir): - shutil.rmtree(self.cache_dir) - shutil.move(self.base_dir, self.cache_dir) + if os.path.exists(self.cache_path): + shutil.rmtree(self.cache_path) + shutil.move(self.base_path, self.cache_path) def __init_env(self): """Setup environment""" os.environ['__cdist_out_dir'] = self.out_dir - os.environ['__cdist_base_dir'] = self.base_dir + os.environ['__cdist_base_path'] = self.base_path def __init_out_dirs(self): """Initialise output directory structure""" # Create base dir, if user supplied and not existing - if not os.path.isdir(self.base_dir): - os.mkdir(self.base_dir) + if not os.path.isdir(self.base_path): + os.mkdir(self.base_path) os.mkdir(self.out_dir) os.mkdir(self.global_explorer_out_dir) From 7169d6ac42385093f721a534504b96389a18227d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:05:52 +0200 Subject: [PATCH 0598/4212] more s/_dir/_path/g Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 57 +++++++++++++++++++------------------ lib/cdist/context.py | 34 +++++++++++----------- 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index d122348d..e8d8b0c9 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -37,7 +37,7 @@ class ConfigInstall: """Cdist main class to hold arbitrary data""" def __init__(self, target_host, initial_manifest=False, - base_dir=False, + base_path=False, exec_path=sys.argv[0], debug=False): @@ -48,7 +48,7 @@ class ConfigInstall: self.exec_path = exec_path self.context = cdist.context.Context(self.target_host, - initial_manifest=initial_manifest, base_dir=base_dir, + initial_manifest=initial_manifest, base_path=base_path, debug=debug) def cleanup(self): @@ -60,17 +60,18 @@ class ConfigInstall: def run_initial_manifest(self): """Run the initial manifest""" log.info("Running initial manifest %s", self.context.initial_manifest) - env = { "__manifest" : self.context.manifest_dir } + env = { "__manifest" : self.context.manifest_path } self.run_manifest(self.context.initial_manifest, extra_env=env) def run_type_manifest(self, cdist_object): """Run manifest for a specific object""" type = cdist_object.type - manifest = type.manifest_path + manifest_path = os.path.join(self.context.type_base_path, + type.manifest_path) log.debug("%s: Running %s", cdist_object.name, manifest) if os.path.exists(manifest): - env = { "__object" : cdist_object.path, + env = { "__object" : os.path.join(self.context.cdist_object.path, "__object_id": cdist_object.object_id, "__object_fq": cdist_object.name, "__type": type.path, @@ -81,13 +82,13 @@ class ConfigInstall: """Run a manifest""" log.debug("Running manifest %s, env=%s", manifest, extra_env) env = os.environ.copy() - env['PATH'] = self.context.bin_dir + ":" + env['PATH'] + env['PATH'] = self.context.bin_path + ":" + env['PATH'] # Information required in every manifest env['__target_host'] = self.target_host - # FIXME: __global == __cdist_out_dir - duplication - env['__global'] = self.context.out_dir + # FIXME: __global == __cdist_out_path - duplication + env['__global'] = self.context.out_path # Submit debug flag to manifest, can be used by emulator and types if self.debug: @@ -97,7 +98,7 @@ class ConfigInstall: env['__cdist_manifest'] = manifest # Required to find types - env['__cdist_type_base_dir'] = type.path + env['__cdist_type_base_path'] = type.path # Other environment stuff if extra_env: @@ -124,7 +125,7 @@ class ConfigInstall: # env = os.environ.copy() env['__target_host'] = self.target_host - env['__global'] = self.context.out_dir + env['__global'] = self.context.out_path env["__object"] = cdist_object.path env["__object_id"] = cdist_object.object_id env["__object_fq"] = cdist_object.name @@ -179,8 +180,8 @@ class ConfigInstall: self.path.transfer_type_explorers(type) cmd = [] - cmd.append("__explorer=" + self.context.remote_global_explorer_dir) - cmd.append("__type_explorer=" + type.explorer_remote_dir) + cmd.append("__explorer=" + self.context.remote_global_explorer_path) + cmd.append("__type_explorer=" + type.explorer_remote_path) cmd.append("__object=" + object.path_remote) cmd.append("__object_id=" + object.object_id) cmd.append("__object_fq=" + cdist_object) @@ -190,8 +191,8 @@ class ConfigInstall: explorers = self.path.list_type_explorers(type) for explorer in explorers: - remote_cmd = cmd + [os.path.join(type.explorer_remote_dir, explorer)] - output = os.path.join(cdist_object.explorer_output_dir(), explorer) + remote_cmd = cmd + [os.path.join(type.explorer_remote_path, explorer)] + output = os.path.join(cdist_object.explorer_output_path(), explorer) output_fd = open(output, mode='w') log.debug("%s exploring %s using %s storing to %s", cdist_object, explorer, remote_cmd, output) @@ -204,7 +205,7 @@ class ConfigInstall: """Link emulator to types""" src = os.path.abspath(self.exec_path) for type in cdist.core.Type.list_types(): - dst = os.path.join(self.context.bin_dir, type.name) + dst = os.path.join(self.context.bin_path, type.name) log.debug("Linking emulator: %s to %s", src, dst) # FIXME: handle exception / make it more beautiful @@ -214,15 +215,15 @@ class ConfigInstall: """Run global explorers""" log.info("Running global explorers") - src = cdist.core.GlobalExplorer.base_dir - dst = cdist.core.GlobalExplorer.remote_base_dir + src = cdist.core.GlobalExplorer.base_path + dst = cdist.core.GlobalExplorer.remote_base_path - self.context.transfer_dir(src, dst) + self.context.transfer_path(src, dst) for explorer in cdist.core.GlobalExplorer.list_explorers(): output_fd = open(explorer.out_path, mode='w') cmd = [] - cmd.append("__explorer=" + cdist.core.GlobalExplorer.remote_base_dir) + cmd.append("__explorer=" + cdist.core.GlobalExplorer.remote_base_path) cmd.append(explorer.remote_path) cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=True) @@ -251,8 +252,8 @@ class ConfigInstall: """Ensure the base directories are cleaned up""" log.debug("Creating clean directory structure") - self.context.remove_remote_dir(self.context.remote_base_dir) - self.context.remote_mkdir(self.context.remote_base_dir) + self.context.remove_remote_path(self.context.remote_base_path) + self.context.remote_mkdir(self.context.remote_base_path) self.link_emulator() def stage_prepare(self): @@ -263,7 +264,7 @@ class ConfigInstall: log.info("Running object manifests and type explorers") - log.debug("Searching for objects in " + cdist.core.Object.base_dir()) + log.debug("Searching for objects in " + cdist.core.Object.base_path()) # Continue process until no new objects are created anymore new_objects_created = True @@ -284,17 +285,17 @@ class ConfigInstall: def transfer_object_parameter(self, cdist_object): """Transfer the object parameter to the remote destination""" # Create base path before using mkdir -p - self.remote_mkdir(self.remote_object_parameter_dir(cdist_object)) + self.remote_mkdir(self.remote_object_parameter_path(cdist_object)) # Synchronise parameter dir afterwards - self.transfer_dir(self.object_parameter_dir(cdist_object), - self.remote_object_parameter_dir(cdist_object)) + self.transfer_path(self.object_parameter_path(cdist_object), + self.remote_object_parameter_path(cdist_object)) # FIXME Move into configinstall def transfer_global_explorers(self): """Transfer the global explorers""" self.remote_mkdir(REMOTE_GLOBAL_EXPLORER_DIR) - self.transfer_dir(self.global_explorer_dir, REMOTE_GLOBAL_EXPLORER_DIR) + self.transfer_path(self.global_explorer_path, REMOTE_GLOBAL_EXPLORER_DIR) # FIXME Move into configinstall def transfer_type_explorers(self, type): @@ -306,7 +307,7 @@ class ConfigInstall: # Do not retransfer type.transferred_explorers = True - # FIXME: Can be explorer_path or explorer_dir, I don't care. + # FIXME: Can be explorer_path or explorer_path, I don't care. src = type.explorer_path() dst = type.remote_explorer_path() @@ -314,4 +315,4 @@ class ConfigInstall: if len(type.explorers) > 0: # Ensure that the path exists self.remote_mkdir(dst) - self.transfer_dir(src, dst) + self.transfer_path(src, dst) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index edc29d60..1de57f94 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -38,6 +38,7 @@ class Context: initial_manifest=False, base_path=False, out_path=False, + remote_base_path=False, debug=False): self.target_host = target_host @@ -53,7 +54,7 @@ class Context: os.pardir)) - # Input directories + # Local input directories self.cache_path = os.path.join(self.base_path, "cache", target_host) self.conf_path = os.path.join(self.base_path, "conf") @@ -62,35 +63,34 @@ class Context: self.type_base_path = os.path.join(self.conf_path, "type") self.lib_path = os.path.join(self.base_path, "lib") - # Mostly static, but can be overwritten on user demand if initial_manifest: self.initial_manifest = initial_manifest else: self.initial_manifest = os.path.join(self.manifest_path, "init") - # Output directories + # Local output directories if out_path: self.out_path = out_path: else: self.out_path = os.path.join(tempfile.mkdtemp(), "out") + self.bin_path = os.path.join(self.out_path, "bin") self.global_explorer_out_path = os.path.join(self.out_path, "explorer") - self.object_base_path = os.path.join(self.out_path, "object") - self.bin_path = os.path.join(self.out_path, "bin") + self.object_base_path = os.path.join(self.out_path, "object") # Remote directories - if "__cdist_remote_base_path" in os.environ: - self.remote_base_path = os.environ['__cdist_remote_base_path'] + if remote_base_path: + self.remote_base_path = remote_base_path else: self.remote_base_path = "/var/lib/cdist" self.remote_conf_path = os.path.join(self.remote_base_path, "conf") - self.remote_object_dir = os.path.join(self.remote_base_path, "object") - self.remote_type_dir = os.path.join(self.remote_conf_path, "type") - self.remote_global_explorer_dir = os.path.join(self.remote_conf_path, "explorer") + self.remote_object_path = os.path.join(self.remote_base_path, "object") + self.remote_type_path = os.path.join(self.remote_conf_path, "type") + self.remote_global_explorer_path = os.path.join(self.remote_conf_path, "explorer") # Create directories - self.__init_out_dirs() + self.__init_out_paths() self.__init_env() @@ -108,24 +108,24 @@ class Context: def __init_env(self): """Setup environment""" - os.environ['__cdist_out_dir'] = self.out_dir + os.environ['__cdist_out_path'] = self.out_path os.environ['__cdist_base_path'] = self.base_path - def __init_out_dirs(self): + def __init_out_paths(self): """Initialise output directory structure""" # Create base dir, if user supplied and not existing if not os.path.isdir(self.base_path): os.mkdir(self.base_path) - os.mkdir(self.out_dir) - os.mkdir(self.global_explorer_out_dir) - os.mkdir(self.bin_dir) + os.mkdir(self.out_path) + os.mkdir(self.global_explorer_out_path) + os.mkdir(self.bin_path) def remote_mkdir(self, directory): """Create directory on remote side""" cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) - def remove_remote_dir(self, destination): + def remove_remote_path(self, destination): cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) From 8aa91726870955967f9686d01db786e450818062 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:07:38 +0200 Subject: [PATCH 0599/4212] ++tests Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 0760f368..a66255a9 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -18,3 +18,8 @@ GlobalExplorer: Object/Type: - rutern relative only - Have accept absulet path on listing + +Tests needed: + + - Fail if cache_dir from previous run cannot be deleted + - Fail if cache_dir cannot be created from current out_dir From c56d17d674cbaac17cf175713465cee95f6847c5 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 15:07:57 +0200 Subject: [PATCH 0600/4212] relative paths Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 98 +++++++++--------------------------------- 1 file changed, 20 insertions(+), 78 deletions(-) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index 8439464e..4493be18 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -25,8 +25,6 @@ import os import cdist -# FIXME: i should not have to care about prefix directory, local, remote and such. -# I know what my internals look like, the outside is none of my business. class Type(object): """Represents a cdist type. @@ -36,93 +34,37 @@ class Type(object): """ - @staticmethod - def base_dir(): - """Return the absolute path to the top level directory where types - are defined. - - Requires the environment variable '__cdist_base_dir' to be set. - - """ - try: - return os.path.join( - os.environ['__cdist_base_dir'], - 'conf', - 'type' - ) - except KeyError as e: - raise cdist.MissingEnvironmentVariableError(e.args[0]) - - @staticmethod - def remote_base_dir(): - """Return the absolute path to the top level directory where types - are kept on the remote/target host. - - Requires the environment variable '__cdist_remote_base_dir' to be set. - - """ - try: - return os.path.join( - os.environ['__cdist_remote_base_dir'], - 'conf', - 'type' - ) - except KeyError as e: - raise cdist.MissingEnvironmentVariableError(e.args[0]) - @classmethod - def list_types(cls): + def list_types(cls, base_path): """Return a list of type instances""" - for type_name in cls.list_type_names(): - yield cls(type_name) + for name in cls.list_type_names(base_path): + yield cls(base_path, name) @classmethod - def list_type_names(cls): + def list_type_names(cls, base_path): """Return a list of type names""" - return os.listdir(cls.base_dir()) + return os.listdir(base_path) - def __init__(self, name): + def __init__(self, base_path, name): + self._base_path = base_path self.name = name + self.manifest_path = os.path.join(self.name, "manifest") + self.explorer_path = os.path.join(self.name, "explorer") + self.manifest_path = os.path.join(self.name, "manifest") + self.gencode_local_path = os.path.join(self.name, "gencode-local") + self.gencode_remote_path = os.path.join(self.name, "gencode-remote") + self.manifest_path = os.path.join(self.name, "manifest") + + self.transferred_explorers = False + self.__explorers = None self.__required_parameters = None self.__optional_parameters = None - self.transferred_explorers = False def __repr__(self): - return '' % self.name - - @property - def path(self): - return os.path.join( - self.base_dir(), - self.name - ) - # FIXME: prefix directory should not leak into me - @property - def remote_path(self): - return os.path.join( - self.remote_base_dir(), - self.name - ) - - # FIXME: probably wrong place for this - @property - def remote_explorer_dir(self): - return os.path.join(self.remote_path, "explorer") - - @property - def manifest_path(self): - return os.path.join(self.path, "manifest") - - @property - def gencode_local(self): - return os.path.join(self.path, "gencode-local") - - @property - def gencode_remote(self): - return os.path.join(self.path, "gencode-remote") + return '' % self.name @property def is_singleton(self): @@ -140,7 +82,7 @@ class Type(object): if not self.__explorers: try: self.__explorers = os.listdir(os.path.join(self.path, "explorer")) - except EnvironmentError as e: + except EnvironmentError: # error ignored self.__explorers = [] return self.__explorers @@ -154,7 +96,7 @@ class Type(object): with open(os.path.join(self.path, "parameter", "required")) as fd: for line in fd: parameters.append(line.strip()) - except EnvironmentError as e: + except EnvironmentError: # error ignored pass finally: @@ -170,7 +112,7 @@ class Type(object): with open(os.path.join(self.path, "parameter", "optional")) as fd: for line in fd: parameters.append(line.strip()) - except EnvironmentError as e: + except EnvironmentError: # error ignored pass finally: From ffb33189c76e3d53a67e1e3ae28e909aeefa4faa Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 15:18:25 +0200 Subject: [PATCH 0601/4212] fix path/absolute_path handling Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index 4493be18..c701bf48 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -49,6 +49,8 @@ class Type(object): def __init__(self, base_path, name): self._base_path = base_path self.name = name + self.path = self.name + self.absolute_path = os.path.join(self._base_path, self.path) self.manifest_path = os.path.join(self.name, "manifest") self.explorer_path = os.path.join(self.name, "explorer") self.manifest_path = os.path.join(self.name, "manifest") @@ -66,22 +68,24 @@ class Type(object): def __repr__(self): return '' % self.name + def + @property def is_singleton(self): """Check whether a type is a singleton.""" - return os.path.isfile(os.path.join(self.path, "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.path, "install")) + return os.path.isfile(os.path.join(self.absolute_path, "install")) @property def explorers(self): """Return a list of available explorers""" if not self.__explorers: try: - self.__explorers = os.listdir(os.path.join(self.path, "explorer")) + self.__explorers = os.listdir(os.path.join(self.absolute_path, "explorer")) except EnvironmentError: # error ignored self.__explorers = [] @@ -93,7 +97,7 @@ class Type(object): if not self.__required_parameters: parameters = [] try: - with open(os.path.join(self.path, "parameter", "required")) as fd: + with open(os.path.join(self.absolute_path, "parameter", "required")) as fd: for line in fd: parameters.append(line.strip()) except EnvironmentError: @@ -109,7 +113,7 @@ class Type(object): if not self.__optional_parameters: parameters = [] try: - with open(os.path.join(self.path, "parameter", "optional")) as fd: + with open(os.path.join(self.absolute_path, "parameter", "optional")) as fd: for line in fd: parameters.append(line.strip()) except EnvironmentError: From 8af7c075ec584981e9eb8654ab35823d3f97e53b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:19:01 +0200 Subject: [PATCH 0602/4212] ++todo(steven) Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index a66255a9..2a953e0d 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,4 +1,7 @@ Object: + cdist_object.code_local_path + cdist_object.code_remote_path + cdist_object.remote_code_remote_path Type: From dd29e86b8163b3a09f42525b2ceed1f63156d0a9 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 15:19:03 +0200 Subject: [PATCH 0603/4212] -syntax error Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index c701bf48..309528ef 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -68,8 +68,6 @@ class Type(object): def __repr__(self): return '' % self.name - def - @property def is_singleton(self): """Check whether a type is a singleton.""" From 4f76cfc84e8ea7d0c3dfaa428d77d68a22dff1dd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:20:38 +0200 Subject: [PATCH 0604/4212] changes for relative Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 43 +++++++++++++++++++------------------ lib/cdist/context.py | 8 +++---- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index e8d8b0c9..c630487f 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -70,45 +70,45 @@ class ConfigInstall: type.manifest_path) log.debug("%s: Running %s", cdist_object.name, manifest) - if os.path.exists(manifest): - env = { "__object" : os.path.join(self.context.cdist_object.path, + if os.path.exists(manifest_path): + env = { "__object" : os.path.join(self.context.object_base_path, + cdist_object.path) "__object_id": cdist_object.object_id, "__object_fq": cdist_object.name, - "__type": type.path, + "__type": os.path.join(self.context.type_base_path, + type.path) } - self.run_manifest(manifest, extra_env=env) + self.run_manifest(manifest_path, extra_env=env) - def run_manifest(self, manifest, extra_env=None): + def run_manifest(self, manifest_path, extra_env=None): """Run a manifest""" - log.debug("Running manifest %s, env=%s", manifest, extra_env) + log.debug("Running manifest %s, env=%s", manifest_path, extra_env) env = os.environ.copy() env['PATH'] = self.context.bin_path + ":" + env['PATH'] # Information required in every manifest env['__target_host'] = self.target_host - - # FIXME: __global == __cdist_out_path - duplication env['__global'] = self.context.out_path # Submit debug flag to manifest, can be used by emulator and types if self.debug: env['__debug'] = "yes" - # Required for recording source - env['__cdist_manifest'] = manifest + # Required for recording source in emulator + env['__cdist_manifest'] = manifest_path - # Required to find types + # Required to find types in emulator env['__cdist_type_base_path'] = type.path # Other environment stuff if extra_env: env.update(extra_env) - cdist.exec.shell_run_or_debug_fail(manifest, [manifest], env=env) + cdist.exec.shell_run_or_debug_fail(manifest_path, [manifest_path], env=env) def object_run(self, cdist_object): """Run gencode or code for an object""" - log.debug("Running %s from %s", mode, cdist_object) + log.debug("Running object %s", cdist_object) # Catch requirements, which re-call us if cdist_object.ran: @@ -118,7 +118,7 @@ class ConfigInstall: for requirement in cdist_object.requirements: log.debug("Object %s requires %s", cdist_object, requirement) - self.object_run(requirement, mode=mode) + self.object_run(requirement) # # Setup env Variable: @@ -126,17 +126,19 @@ class ConfigInstall: env = os.environ.copy() env['__target_host'] = self.target_host env['__global'] = self.context.out_path - env["__object"] = cdist_object.path + env["__object"] = os.path.join(self.context.object_base_path, cdist_object.path) env["__object_id"] = cdist_object.object_id env["__object_fq"] = cdist_object.name env["__type"] = type.name # gencode for cmd in ["local", "remote"]: - bin = getattr(type, "gencode_" + cmd) + bin = os.path.join(self.context.type_base_path, + getattr(type, "gencode_" + cmd)) if os.path.isfile(bin): - outfile = getattr(cdist_object, "code_" + cmd) + outfile = os.path.join(self.context.object_base_path, + getattr(cdist_object, "code_" + cmd)) outfile_fd = open(outfile, "w") @@ -158,20 +160,19 @@ class ConfigInstall: cdist_object.changed=True # code local - code_local = cdist_object.code_local + code_local = cdist_object.code_local_path if os.path.isfile(code_local): cdist.exec.run_or_fail([code_local]) # code remote - local_remote_code = cdist_object.code_remote - remote_remote_code = cdist_object.remote_code_remote + local_remote_code = cdist_object.code_remote_path + remote_remote_code = cdist_object.remote_code_remote_path if os.path.isfile(local_remote_code): self.context.transfer_file(local_remote_code, remote_remote_code) cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) cdist_object.ran = True - ### Cleaned / check functions: Round 1 :-) ################################# def run_type_explorer(self, cdist_object): """Run type specific explorers for objects""" diff --git a/lib/cdist/context.py b/lib/cdist/context.py index 1de57f94..af37199e 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -106,10 +106,10 @@ class Context: shutil.rmtree(self.cache_path) shutil.move(self.base_path, self.cache_path) - def __init_env(self): - """Setup environment""" - os.environ['__cdist_out_path'] = self.out_path - os.environ['__cdist_base_path'] = self.base_path + #def __init_env(self): + # """Setup environment""" + # os.environ['__cdist_out_path'] = self.out_path + # os.environ['__cdist_base_path'] = self.base_path def __init_out_paths(self): """Initialise output directory structure""" From e6e1c07531258ca225bac975db3d9dcfed9871c8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:22:01 +0200 Subject: [PATCH 0605/4212] ++todo(steven) Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 2a953e0d..b79b719b 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -5,6 +5,7 @@ Object: Type: + type.transferred_explorers GlobalExplorer: From c1db2bd51ae60e7f65347fca17998ed361b17b0e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:23:48 +0200 Subject: [PATCH 0606/4212] ++todo(steven) Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index b79b719b..35648910 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -7,6 +7,8 @@ Object: Type: type.transferred_explorers + type.type_explorer_paths() -> relative list of paths of explorer + GlobalExplorer: out_path: local path into which the output is written From 73ba8e2366d25333314d4bf960ce558ce31d596e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:26:38 +0200 Subject: [PATCH 0607/4212] --todo(steven) Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 35648910..b79b719b 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -7,8 +7,6 @@ Object: Type: type.transferred_explorers - type.type_explorer_paths() -> relative list of paths of explorer - GlobalExplorer: out_path: local path into which the output is written From 187510bbd34ccdd3a7d74d49847bfb274a254ce5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:33:27 +0200 Subject: [PATCH 0608/4212] ++todo(steven) Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index b79b719b..dc9f965b 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -27,3 +27,5 @@ Tests needed: - Fail if cache_dir from previous run cannot be deleted - Fail if cache_dir cannot be created from current out_dir + - transfer_type_explorers: Explorers are not transferred twice + - transfer_type_explorers: No transfer tried if there are no type_explorers From 183bbf61d4e1b96125c5e1421ef73f4a45bfde2a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:34:47 +0200 Subject: [PATCH 0609/4212] fix imports from path in config_install Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index c630487f..0b05f8a9 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -177,8 +177,7 @@ class ConfigInstall: """Run type specific explorers for objects""" type = cdist_object.type - # FIXME - self.path.transfer_type_explorers(type) + self.transfer_type_explorers(type) cmd = [] cmd.append("__explorer=" + self.context.remote_global_explorer_path) @@ -292,13 +291,15 @@ class ConfigInstall: self.transfer_path(self.object_parameter_path(cdist_object), self.remote_object_parameter_path(cdist_object)) - # FIXME Move into configinstall + +####FIXED ###################################################################### + def transfer_global_explorers(self): """Transfer the global explorers""" - self.remote_mkdir(REMOTE_GLOBAL_EXPLORER_DIR) - self.transfer_path(self.global_explorer_path, REMOTE_GLOBAL_EXPLORER_DIR) + self.remote_mkdir(self.context.remote_global_explorer_path) + self.transfer_path(self.context.global_explorer_path, + self.remote_global_explorer_path) - # FIXME Move into configinstall def transfer_type_explorers(self, type): """Transfer explorers of a type, but only once""" if type.transferred_explorers: @@ -308,12 +309,13 @@ class ConfigInstall: # Do not retransfer type.transferred_explorers = True - # FIXME: Can be explorer_path or explorer_path, I don't care. - src = type.explorer_path() - dst = type.remote_explorer_path() + explorers = type.explorers() + + if len(explorers) > 0: + rel_path = os.path.join(type.explorer_path(), explorer) + src = os.path.join(self.context.type_base_path, rel_path) + dst = os.path.join(self.context.remote_type_path, rel_path) - # Transfer if there is at least one explorer - if len(type.explorers) > 0: # Ensure that the path exists self.remote_mkdir(dst) self.transfer_path(src, dst) From c268e5f7c25778b2cf0fbdf58818546b08d56942 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:36:59 +0200 Subject: [PATCH 0610/4212] ++todo(steven) Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index dc9f965b..54b43210 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -3,6 +3,10 @@ Object: cdist_object.code_remote_path cdist_object.remote_code_remote_path + cdist_object.parameter_path + + + Type: type.transferred_explorers From 79234148aa7eaf249ad6b24eb06f255acb8f3bfa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:39:29 +0200 Subject: [PATCH 0611/4212] transfer_object_parameter: new src/dst Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 0b05f8a9..9c1f3b9d 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -284,12 +284,19 @@ class ConfigInstall: # FIXME Move into configinstall def transfer_object_parameter(self, cdist_object): """Transfer the object parameter to the remote destination""" + local_path = + os.path.join(self.context.object_base_path, + cdist_object.parameter_path) + remote_path = + os.path.join(self.context.remote_object_path, + cdist_object.parameter_path) + # Create base path before using mkdir -p - self.remote_mkdir(self.remote_object_parameter_path(cdist_object)) + # FIXME: needed? + self.remote_mkdir(remote_path) # Synchronise parameter dir afterwards - self.transfer_path(self.object_parameter_path(cdist_object), - self.remote_object_parameter_path(cdist_object)) + self.transfer_path(local_path, remote_path) ####FIXED ###################################################################### From f8853467f3aae87bd6c1b670aeac75c0dd206bd8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:39:51 +0200 Subject: [PATCH 0612/4212] do not create base directory in transfer_object_parameter, somebody else should have done this Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 9c1f3b9d..734f7280 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -291,10 +291,6 @@ class ConfigInstall: os.path.join(self.context.remote_object_path, cdist_object.parameter_path) - # Create base path before using mkdir -p - # FIXME: needed? - self.remote_mkdir(remote_path) - # Synchronise parameter dir afterwards self.transfer_path(local_path, remote_path) From be8428e592da733a81de35c74697e8f2bd859883 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 15:42:04 +0200 Subject: [PATCH 0613/4212] relative paths Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 152 +++++++++++++++------------------------ 1 file changed, 57 insertions(+), 95 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index b922701d..8a214a58 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -42,113 +42,52 @@ class Object(object): """ - @staticmethod - def base_dir(): - """Return the absolute path to the top level directory where objects - are defined. - - Requires the environment variable '__cdist_out_dir' to be set. - - """ - try: - base_dir = os.path.join( - os.environ['__cdist_out_dir'], - 'object' - ) - except KeyError as e: - raise cdist.MissingEnvironmentVariableError(e.args[0]) - - # FIXME: should directory be created elsewhere? - if not os.path.isdir(base_dir): - os.mkdir(base_dir) - return base_dir - @classmethod - def remote_base_dir(): - """Return the absolute path to the top level directory where objects - are kept on the remote/target host. - - Requires the environment variable '__cdist_remote_out_dir' to be set. - - """ - try: - return os.path.join( - os.environ['__cdist_remote_out_dir'], - 'object', - ) - except KeyError as e: - raise cdist.MissingEnvironmentVariableError(e.args[0]) - - def list_objects(cls): + def list_objects(cls, object_base_path, type_base_path): """Return a list of object instances""" - for object_name in cls.list_object_names(): + for object_name in cls.list_object_names(object_base_path): 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:]) - yield cls(cdist.core.Type(type_name), object_id=object_id) + yield cls(cdist.core.Type(type_base_path, type_name), object_base_path, object_id=object_id) @classmethod - def list_type_names(cls): + def list_type_names(cls, object_base_path): """Return a list of type names""" - return os.listdir(cls.base_dir()) + return os.listdir(object_base_path) @classmethod - def list_object_names(cls): + def list_object_names(cls, object_base_path): """Return a list of object names""" - for path, dirs, files in os.walk(cls.base_dir()): + for path, dirs, files in os.walk(object_base_path): if DOT_CDIST in dirs: - yield os.path.relpath(path, cls.base_dir()) + yield os.path.relpath(path, object_base_path) - def __init__(self, type, object_id=None, parameters=None, requirements=None): + def __init__(self, type, base_path, object_id=None) self.type = type # instance of Type + self.base_path = base_path self.object_id = object_id self.name = os.path.join(self.type.name, self.object_id) - self.parameters = parameters or {} - self.requirements = requirements or [] + self.path = os.path.join(self.type.path, self.object_id) + self.absolute_path = os.path.join(self.base_path, self.path) + self.code_local_path = os.path.join(self.path, "code-local") + self.code_remote_path = os.path.join(self.path, "code-remote") + self.parameter_path = os.path.join(self.path, "parameter") self.__parameters = None self.__requirements = None - # Whether this object was prepared/ran - self.prepared = False - self.ran = False - def __repr__(self): return '' % self.name @property - def path(self): - return os.path.join( - self.base_dir(), - self.name, - DOT_CDIST - ) - - @property - def code_local(self): - return os.path.join(self.path, "code-local") - - @property - def code_remote(self): - return os.path.join(self.path, "code-remote") - - @property - def explorer_out_dir(self): - path = os.path.join(self.path, "explorer") + def explorer_path(self): + # create absolute path + path = os.path.join(self.absolute_path, "explorer") if not os.path.isdir(path): os.mkdir(path) - return path - - # FIXME: prefix directory should not leak into me - @property - def remote_path(self): - return os.path.join( - self.remote_base_dir(), - self.name, - DOT_CDIST - ) - @property - def remote_code_remote(self): - return os.path.join(self.remote_path, "code-remote") + # return relative path + return os.path.join(self.path, "explorer") ### requirements @@ -204,20 +143,43 @@ class Object(object): ### /changed + ### prepared + @property + def prepared(self): + """Check whether the object has been prepared.""" + return os.path.isfile(os.path.join(self.path, "prepared")) - # FIXME: Object - def object_parameter_dir(self, cdist_object): - """Returns the dir to the object parameter""" - return os.path.join(self.object_dir(cdist_object), "parameter") + @prepared.setter + def prepared(self, value): + """Change the objects prepared status.""" + path = os.path.join(self.path, "prepared") + if value: + open(path, "w").close() + else: + try: + os.remove(path) + except EnvironmentError: + # ignore + pass + ### /prepared - # FIXME: object - def remote_object_parameter_dir(self, cdist_object): - """Returns the remote dir to the object parameter""" - return os.path.join(self.remote_object_dir(cdist_object), "parameter") - # FIXME: object - def object_code_paths(self, cdist_object): - """Return paths to code scripts of object""" - return [os.path.join(self.object_dir(cdist_object), "code-local"), - os.path.join(self.object_dir(cdist_object), "code-remote")] + ### ran + @property + def ran(self): + """Check whether the object has been ran.""" + return os.path.isfile(os.path.join(self.path, "ran")) + @ran.setter + def ran(self, value): + """Change the objects ran status.""" + path = os.path.join(self.path, "ran") + if value: + open(path, "w").close() + else: + try: + os.remove(path) + except EnvironmentError: + # ignore + pass + ### /ran From c1e773199251f79db92f5083ef736b3835056ab7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 15:49:25 +0200 Subject: [PATCH 0614/4212] cleanups/fixes Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 33 +++++++++------------------------ lib/cdist/context.py | 8 +++++++- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 734f7280..3f1c467e 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -48,15 +48,13 @@ class ConfigInstall: self.exec_path = exec_path self.context = cdist.context.Context(self.target_host, - initial_manifest=initial_manifest, base_path=base_path, + initial_manifest=initial_manifest, + base_path=base_path, debug=debug) - + def cleanup(self): self.path.cleanup() - def __init_env(self): - """Setup environment""" - def run_initial_manifest(self): """Run the initial manifest""" log.info("Running initial manifest %s", self.context.initial_manifest) @@ -248,22 +246,15 @@ class ConfigInstall: self.deploy_to() self.cleanup() - def init_deploy(self): - """Ensure the base directories are cleaned up""" - log.debug("Creating clean directory structure") +####FIXED ###################################################################### - self.context.remove_remote_path(self.context.remote_base_path) - self.context.remote_mkdir(self.context.remote_base_path) - self.link_emulator() - def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" - self.init_deploy() + self.link_emulator() self.run_global_explorers() self.run_initial_manifest() log.info("Running object manifests and type explorers") - log.debug("Searching for objects in " + cdist.core.Object.base_path()) # Continue process until no new objects are created anymore @@ -281,22 +272,16 @@ class ConfigInstall: cdist_object.prepared = True new_objects_created = True - # FIXME Move into configinstall def transfer_object_parameter(self, cdist_object): """Transfer the object parameter to the remote destination""" - local_path = - os.path.join(self.context.object_base_path, - cdist_object.parameter_path) - remote_path = - os.path.join(self.context.remote_object_path, - cdist_object.parameter_path) + src = os.path.join(self.context.object_base_path, + cdist_object.parameter_path) + dst = os.path.join(self.context.remote_object_path, + cdist_object.parameter_path) # Synchronise parameter dir afterwards self.transfer_path(local_path, remote_path) - -####FIXED ###################################################################### - def transfer_global_explorers(self): """Transfer the global explorers""" self.remote_mkdir(self.context.remote_global_explorer_path) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index af37199e..4cfc6c59 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -91,7 +91,7 @@ class Context: # Create directories self.__init_out_paths() - + self.__init_remote_paths() self.__init_env() def cleanup(self): @@ -122,6 +122,12 @@ class Context: os.mkdir(self.global_explorer_out_path) os.mkdir(self.bin_path) + def __init_remote_paths(self): + """Initialise remote directory structure""" + + self.remove_remote_path(self.remote_base_path) + self.remote_mkdir(self.remote_base_path) + def remote_mkdir(self, directory): """Create directory on remote side""" cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) From e5e2fb866c301474f8e25bd738318cfe1c7882a0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:00:32 +0200 Subject: [PATCH 0615/4212] ++fixes Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 2 +- lib/cdist/config_install.py | 17 +++++++++-------- lib/cdist/context.py | 17 +++++------------ 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index c5f4b4ef..71ce14ed 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -42,7 +42,7 @@ def config(args): os.environ['__remote_copy'] = "scp -o User=root -q" for host in args.host: - c = Config(host, initial_manifest=args.manifest, base_dir=args.cdist_home, debug=args.debug) + c = Config(host, initial_manifest=args.manifest, base_path=args.cdist_home, debug=args.debug) if args.parallel: log.debug("Creating child process for %s", host) process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 3f1c467e..c1cdf328 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -70,7 +70,7 @@ class ConfigInstall: log.debug("%s: Running %s", cdist_object.name, manifest) if os.path.exists(manifest_path): env = { "__object" : os.path.join(self.context.object_base_path, - cdist_object.path) + cdist_object.path), "__object_id": cdist_object.object_id, "__object_fq": cdist_object.name, "__type": os.path.join(self.context.type_base_path, @@ -213,16 +213,17 @@ class ConfigInstall: """Run global explorers""" log.info("Running global explorers") - src = cdist.core.GlobalExplorer.base_path - dst = cdist.core.GlobalExplorer.remote_base_path + src_path = cdist.context.global_explorer_path + dst_path = cdist.context.global_explorer_out_path + remote_dst_path = cdist.context.remote_global_explorer_path - self.context.transfer_path(src, dst) + self.context.transfer_path(src_path, remote_dst_path) - for explorer in cdist.core.GlobalExplorer.list_explorers(): - output_fd = open(explorer.out_path, mode='w') + for explorer in os.listdir(src_path): + output_fd = open(os.path.join(dst_path, explorer), mode='w') cmd = [] - cmd.append("__explorer=" + cdist.core.GlobalExplorer.remote_base_path) - cmd.append(explorer.remote_path) + cmd.append("__explorer=" + remote_dst_path) + cmd.append(os.path.join(src_path, explorer)) cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=True) output_fd.close() diff --git a/lib/cdist/context.py b/lib/cdist/context.py index 4cfc6c59..f1f031a8 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -47,11 +47,10 @@ class Context: if base_path: self.base_path = base_path else: - self.base_path = - os.path.abspath( - os.path.join(os.path.dirname(__file__), - os.pardir, - os.pardir)) + self.base_path = os.path.abspath( + os.path.join(os.path.dirname(__file__), + os.pardir, + os.pardir)) # Local input directories @@ -70,7 +69,7 @@ class Context: # Local output directories if out_path: - self.out_path = out_path: + self.out_path = out_path else: self.out_path = os.path.join(tempfile.mkdtemp(), "out") @@ -92,7 +91,6 @@ class Context: # Create directories self.__init_out_paths() self.__init_remote_paths() - self.__init_env() def cleanup(self): # Do not use in __del__: @@ -106,11 +104,6 @@ class Context: shutil.rmtree(self.cache_path) shutil.move(self.base_path, self.cache_path) - #def __init_env(self): - # """Setup environment""" - # os.environ['__cdist_out_path'] = self.out_path - # os.environ['__cdist_base_path'] = self.base_path - def __init_out_paths(self): """Initialise output directory structure""" From a7a086e29bfc2fe02ee575630dc1459005cc3700 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 16:01:02 +0200 Subject: [PATCH 0616/4212] only one instance of each named type Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index 309528ef..42a74398 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -46,6 +46,16 @@ class Type(object): return os.listdir(base_path) + _instances = {} + def __new__(cls, *args, **kwargs): + """only one instance of each named type may exist""" + # name is second argument + name = args[1] + if not name in cls._instances: + instance = super(Type, cls).__new__(cls, *args, **kwargs) + cls._instances[name] = instance + return cls._instances[name] + def __init__(self, base_path, name): self._base_path = base_path self.name = name @@ -64,7 +74,6 @@ class Type(object): self.__required_parameters = None self.__optional_parameters = None - def __repr__(self): return '' % self.name From 600e7fb5b5d427d6de6810fed08a1ec5227fe8e7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 16:03:37 +0200 Subject: [PATCH 0617/4212] --typo Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 8a214a58..76f37487 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -63,7 +63,7 @@ class Object(object): if DOT_CDIST in dirs: yield os.path.relpath(path, object_base_path) - def __init__(self, type, base_path, object_id=None) + def __init__(self, type, base_path, object_id=None): self.type = type # instance of Type self.base_path = base_path self.object_id = object_id From 3fcbabc5e8db1f41baf6b706baf1826edd9180a8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:04:37 +0200 Subject: [PATCH 0618/4212] ++fixes Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 8 ++++---- lib/cdist/context.py | 5 +++++ lib/cdist/copy.py | 13 ------------- 3 files changed, 9 insertions(+), 17 deletions(-) delete mode 100644 lib/cdist/copy.py diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index c1cdf328..78630f25 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -202,7 +202,7 @@ class ConfigInstall: def link_emulator(self): """Link emulator to types""" src = os.path.abspath(self.exec_path) - for type in cdist.core.Type.list_types(): + for type in cdist.core.Type.list_types(self.context.type_base_path): dst = os.path.join(self.context.bin_path, type.name) log.debug("Linking emulator: %s to %s", src, dst) @@ -213,9 +213,9 @@ class ConfigInstall: """Run global explorers""" log.info("Running global explorers") - src_path = cdist.context.global_explorer_path - dst_path = cdist.context.global_explorer_out_path - remote_dst_path = cdist.context.remote_global_explorer_path + src_path = self.context.global_explorer_path + dst_path = self.context.global_explorer_out_path + remote_dst_path = self.context.remote_global_explorer_path self.context.transfer_path(src_path, remote_dst_path) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index f1f031a8..b39e603e 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -128,3 +128,8 @@ class Context: def remove_remote_path(self, destination): cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) + def transfer_path(self, source, destination): + """Transfer directory and previously delete the remote destination""" + self.remove_remote_path(destination) + cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + + ["-r", source, self.target_host + ":" + destination]) diff --git a/lib/cdist/copy.py b/lib/cdist/copy.py deleted file mode 100644 index b0eae54e..00000000 --- a/lib/cdist/copy.py +++ /dev/null @@ -1,13 +0,0 @@ - # FIXME: To Copy - def transfer_dir(self, source, destination): - """Transfer directory and previously delete the remote destination""" - self.remove_remote_dir(destination) - cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + - ["-r", source, self.target_host + ":" + destination]) - - # FIXME: To Copy - def transfer_file(self, source, destination): - """Transfer file""" - cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + - [source, self.target_host + ":" + destination]) - From 9045b30136794c5003c17c0d3307a75601321cb0 Mon Sep 17 00:00:00 2001 From: Thomas Reifenberger Date: Fri, 7 Oct 2011 16:07:02 +0200 Subject: [PATCH 0619/4212] fix multiple requirements Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index aa22e1fa..8b531e22 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -132,7 +132,7 @@ def run(argv): requirements = os.environ['__require'] log.debug(object_id + ":Writing requirements: " + requirements) require_fd = open(os.path.join(object_dir, "require"), "a") - require_fd.writelines(requirements.split(" ")) + require_fd.write(requirements.replace(" ","\n")) require_fd.close() # Record / Append source From c93e0f90c9062cf6976add1b563828bb770fc29c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:09:10 +0200 Subject: [PATCH 0620/4212] create remote conf path on new context Signed-off-by: Nico Schottelius --- lib/cdist/context.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index b39e603e..fb00b423 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -85,6 +85,7 @@ class Context: self.remote_conf_path = os.path.join(self.remote_base_path, "conf") self.remote_object_path = os.path.join(self.remote_base_path, "object") + self.remote_type_path = os.path.join(self.remote_conf_path, "type") self.remote_global_explorer_path = os.path.join(self.remote_conf_path, "explorer") @@ -120,6 +121,7 @@ class Context: self.remove_remote_path(self.remote_base_path) self.remote_mkdir(self.remote_base_path) + self.remote_mkdir(self.remote_conf_path) def remote_mkdir(self, directory): """Create directory on remote side""" From 79d0a18bb24aea5a19d9c034b74db1e9441a8a0e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 16:12:01 +0200 Subject: [PATCH 0621/4212] use absolute path for accessing file system Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 76f37487..f5179606 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -126,12 +126,12 @@ class Object(object): @property def changed(self): """Check whether the object has been changed.""" - return os.path.isfile(os.path.join(self.path, "changed")) + return os.path.isfile(os.path.join(self.absolute_path, "changed")) @changed.setter def changed(self, value): """Change the objects changed status.""" - path = os.path.join(self.path, "changed") + path = os.path.join(self.absolute_path, "changed") if value: open(path, "w").close() else: @@ -147,12 +147,12 @@ class Object(object): @property def prepared(self): """Check whether the object has been prepared.""" - return os.path.isfile(os.path.join(self.path, "prepared")) + return os.path.isfile(os.path.join(self.absolute_path, "prepared")) @prepared.setter def prepared(self, value): """Change the objects prepared status.""" - path = os.path.join(self.path, "prepared") + path = os.path.join(self.absolute_path, "prepared") if value: open(path, "w").close() else: @@ -168,12 +168,12 @@ class Object(object): @property def ran(self): """Check whether the object has been ran.""" - return os.path.isfile(os.path.join(self.path, "ran")) + return os.path.isfile(os.path.join(self.absolute_path, "ran")) @ran.setter def ran(self, value): """Change the objects ran status.""" - path = os.path.join(self.path, "ran") + path = os.path.join(self.absolute_path, "ran") if value: open(path, "w").close() else: From 14c9317f66384e50888a3fd1baa4f7ee6881658a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:12:15 +0200 Subject: [PATCH 0622/4212] remove old type.path Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 78630f25..3822b688 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -96,7 +96,7 @@ class ConfigInstall: env['__cdist_manifest'] = manifest_path # Required to find types in emulator - env['__cdist_type_base_path'] = type.path + env['__cdist_type_base_path'] = self.context.type_base_path # Other environment stuff if extra_env: From 2aa0a316e6fad4bebb5c1b819dde1d6722e46614 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:13:00 +0200 Subject: [PATCH 0623/4212] use _path not _dir in emulator Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 8b531e22..9672d24a 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -30,7 +30,7 @@ log = logging.getLogger(__name__) def run(argv): """Emulate type commands (i.e. __file and co)""" type = os.path.basename(argv[0]) - type_dir = os.path.join(os.environ['__cdist_type_base_dir'], type) + type_dir = os.path.join(os.environ['__cdist_type_base_path'], type) param_dir = os.path.join(type_dir, "parameter") global_dir = os.environ['__global'] object_source = os.environ['__cdist_manifest'] From 149a605b16befdd8c4339af2295e1a4c27639725 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:14:29 +0200 Subject: [PATCH 0624/4212] use more path, move type -> cdist_type Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 9672d24a..815df948 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -29,9 +29,9 @@ log = logging.getLogger(__name__) def run(argv): """Emulate type commands (i.e. __file and co)""" - type = os.path.basename(argv[0]) - type_dir = os.path.join(os.environ['__cdist_type_base_path'], type) - param_dir = os.path.join(type_dir, "parameter") + cdist_type = os.path.basename(argv[0]) + type_path = os.path.join(os.environ['__cdist_type_base_path'], cdist_type) + param_dir = os.path.join(type_path, "parameter") global_dir = os.environ['__global'] object_source = os.environ['__cdist_manifest'] @@ -50,14 +50,14 @@ def run(argv): parser.add_argument(argument, action='store', required=True) # If not singleton support one positional parameter - if not os.path.isfile(os.path.join(type_dir, "singleton")): + if not os.path.isfile(os.path.join(type_path, "singleton")): parser.add_argument("object_id", nargs=1) # And finally verify parameter args = parser.parse_args(argv[1:]) # Setup object_id - if os.path.isfile(os.path.join(type_dir, "singleton")): + if os.path.isfile(os.path.join(type_path, "singleton")): object_id = "singleton" else: object_id = args.object_id[0] @@ -68,13 +68,13 @@ def run(argv): object_id = object_id[1:] # Prefix output by object_self - logformat = '%(levelname)s: ' + type + '/' + object_id + ': %(message)s' + logformat = '%(levelname)s: ' + cdist_type + '/' + object_id + ': %(message)s' logging.basicConfig(format=logformat) # FIXME: verify object id log.debug(args) - object_dir = os.path.join(global_dir, "object", type, + object_dir = os.path.join(global_dir, "object", cdist_type, object_id, cdist.path.DOT_CDIST) log.debug("Object output dir = " + object_dir) @@ -140,4 +140,4 @@ def run(argv): source_fd.writelines(object_source) source_fd.close() - log.debug("Finished " + type + "/" + object_id + repr(params)) + log.debug("Finished " + cdist_type + "/" + object_id + repr(params)) From 03f5e1b456a1e6bf951965510f7236866ee9f904 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:15:48 +0200 Subject: [PATCH 0625/4212] fix emulator and cdist module Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 2 ++ lib/cdist/emulator.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 6ce0c788..7aca5ac7 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -22,6 +22,8 @@ VERSION = "2.0.3" DOT_CDIST = ".cdist" +import os + class Error(Exception): """Base exception class for this project""" pass diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 815df948..2df95597 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -75,7 +75,7 @@ def run(argv): log.debug(args) object_dir = os.path.join(global_dir, "object", cdist_type, - object_id, cdist.path.DOT_CDIST) + object_id, cdist.DOT_CDIST) log.debug("Object output dir = " + object_dir) param_out_dir = os.path.join(object_dir, "parameter") From a25ef7f0e885cb3ca9bf6d62a14863d7ca30a335 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:16:45 +0200 Subject: [PATCH 0626/4212] fix emulator and cdist module Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 3822b688..a553f6d8 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -256,7 +256,6 @@ class ConfigInstall: self.run_initial_manifest() log.info("Running object manifests and type explorers") - log.debug("Searching for objects in " + cdist.core.Object.base_path()) # Continue process until no new objects are created anymore new_objects_created = True From ea402fc0c546a79cb73818ea520f6164e1a254ce Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:18:38 +0200 Subject: [PATCH 0627/4212] use new call to object lists in absolute path Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index a553f6d8..2905df67 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -232,7 +232,7 @@ class ConfigInstall: def stage_run(self): """The final (and real) step of deployment""" log.info("Generating and executing code") - for cdist_object in cdist.core.Object.list_objects(): + for cdist_object in cdist.core.Object.list_objects(self.context.object_base_path): log.debug("Run object: %s", cdist_object) self.object_run(cdist_object) @@ -247,8 +247,6 @@ class ConfigInstall: self.deploy_to() self.cleanup() -####FIXED ###################################################################### - def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" self.link_emulator() @@ -261,7 +259,7 @@ class ConfigInstall: new_objects_created = True while new_objects_created: new_objects_created = False - for cdist_object in cdist.core.Object.list_objects(): + for cdist_object in cdist.core.Object.list_objects(self.context.object_base_path): if cdist_object.prepared: log.debug("Skipping rerun of object %s", cdist_object) continue From 2c9beb95064c7105bacdbbbf2870f27646a3558d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:23:33 +0200 Subject: [PATCH 0628/4212] use list not method Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 2905df67..ad8a13b9 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -232,7 +232,8 @@ class ConfigInstall: def stage_run(self): """The final (and real) step of deployment""" log.info("Generating and executing code") - for cdist_object in cdist.core.Object.list_objects(self.context.object_base_path): + for cdist_object in cdist.core.Object.list_objects(self.context.object_base_path, + self.context.type_base_path): log.debug("Run object: %s", cdist_object) self.object_run(cdist_object) @@ -259,7 +260,8 @@ class ConfigInstall: new_objects_created = True while new_objects_created: new_objects_created = False - for cdist_object in cdist.core.Object.list_objects(self.context.object_base_path): + for cdist_object in cdist.core.Object.list_objects(self.context.object_base_path, + self.context.type_base_path): if cdist_object.prepared: log.debug("Skipping rerun of object %s", cdist_object) continue @@ -286,16 +288,16 @@ class ConfigInstall: self.transfer_path(self.context.global_explorer_path, self.remote_global_explorer_path) - def transfer_type_explorers(self, type): + def transfer_type_explorers(self, cdist_type): """Transfer explorers of a type, but only once""" - if type.transferred_explorers: + if cdist_type.transferred_explorers: log.debug("Skipping retransfer for explorers of %s", type) return else: # Do not retransfer - type.transferred_explorers = True + cdist_type.transferred_explorers = True - explorers = type.explorers() + explorers = cdist_type.explorers if len(explorers) > 0: rel_path = os.path.join(type.explorer_path(), explorer) From fd2fa235647bbd86e86ad0cd59b741fb44647a43 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:27:15 +0200 Subject: [PATCH 0629/4212] fix typeexplorer transfer Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index ad8a13b9..eeb9e4c0 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -291,7 +291,7 @@ class ConfigInstall: def transfer_type_explorers(self, cdist_type): """Transfer explorers of a type, but only once""" if cdist_type.transferred_explorers: - log.debug("Skipping retransfer for explorers of %s", type) + log.debug("Skipping retransfer for explorers of %s", cdist_type) return else: # Do not retransfer @@ -300,10 +300,8 @@ class ConfigInstall: explorers = cdist_type.explorers if len(explorers) > 0: - rel_path = os.path.join(type.explorer_path(), explorer) + rel_path = cdist_type.explorer_path src = os.path.join(self.context.type_base_path, rel_path) dst = os.path.join(self.context.remote_type_path, rel_path) + self.context.transfer_path(src, dst) - # Ensure that the path exists - self.remote_mkdir(dst) - self.transfer_path(src, dst) From dd8617141e41599182a56cd3a8110d733d772f05 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:27:50 +0200 Subject: [PATCH 0630/4212] todo shift Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 8 -------- doc/dev/todo/steven | 4 ++++ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index b8fcc5b0..f96da0de 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,14 +1,6 @@ 2.0.3: - fix emulator -- introduce tests: - - does $require work? - - $whatever should fail if there is no global explorer directory - - emulator may only be called with __ as prefix - fail otherwise! - -- Create GlobalExplorer - -- base_dir passing in config/config_install superseeded by __cdist_base_dir? -------------------------------------------------------------------------------- diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 54b43210..4b374a92 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -33,3 +33,7 @@ Tests needed: - Fail if cache_dir cannot be created from current out_dir - transfer_type_explorers: Explorers are not transferred twice - transfer_type_explorers: No transfer tried if there are no type_explorers + + - does $require work? + - $whatever should fail if there is no global explorer directory + - emulator may only be called with __ as prefix - fail otherwise! From 03226dc5aa5c379c153153e079d696eb5277ab3a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:36:05 +0200 Subject: [PATCH 0631/4212] more fixes for relative path address Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index eeb9e4c0..2f4aa261 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -174,18 +174,22 @@ class ConfigInstall: def run_type_explorer(self, cdist_object): """Run type specific explorers for objects""" - type = cdist_object.type - self.transfer_type_explorers(type) + cdist_type = cdist_object.type + self.transfer_type_explorers(cdist_type) cmd = [] cmd.append("__explorer=" + self.context.remote_global_explorer_path) - cmd.append("__type_explorer=" + type.explorer_remote_path) - cmd.append("__object=" + object.path_remote) - cmd.append("__object_id=" + object.object_id) - cmd.append("__object_fq=" + cdist_object) + cmd.append("__type_explorer=" + os.path.join( + self.context.remote_type_path, + cdist_type.explorer_path)) + cmd.append("__object=" + os.path.join( + self.context.remote_object_path, + cdist_object.path)) + cmd.append("__object_id=" + cdist_object.object_id) + cmd.append("__object_fq=" + cdist_object.name) # Need to transfer at least the parameters for objects to be useful - self.path.transfer_object_parameter(cdist_object) + self.transfer_object_parameter(cdist_object) explorers = self.path.list_type_explorers(type) for explorer in explorers: @@ -280,7 +284,7 @@ class ConfigInstall: cdist_object.parameter_path) # Synchronise parameter dir afterwards - self.transfer_path(local_path, remote_path) + self.context.transfer_path(src, dst) def transfer_global_explorers(self): """Transfer the global explorers""" @@ -303,5 +307,11 @@ class ConfigInstall: rel_path = cdist_type.explorer_path src = os.path.join(self.context.type_base_path, rel_path) dst = os.path.join(self.context.remote_type_path, rel_path) + + # Ensure full path until type exists: + # /var/lib/cdist/conf/type/__directory/explorer + # /var/lib/cdist/conf/type/__directory may not exist, + # but remote_mkdir uses -p to fix this + self.context.remote_mkdir(dst) self.context.transfer_path(src, dst) From 22784f447d1f60edb11c588be5dc79cd291df5e3 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 16:43:05 +0200 Subject: [PATCH 0632/4212] --todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 7 ------- 1 file changed, 7 deletions(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 54b43210..47e0f6e7 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,11 +1,4 @@ Object: - cdist_object.code_local_path - cdist_object.code_remote_path - cdist_object.remote_code_remote_path - - cdist_object.parameter_path - - Type: From e8c9b1022748ed24514d82fe124f1f116dc8de2e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:44:53 +0200 Subject: [PATCH 0633/4212] also use path in emulator Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 2df95597..298161d9 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -30,9 +30,9 @@ log = logging.getLogger(__name__) def run(argv): """Emulate type commands (i.e. __file and co)""" cdist_type = os.path.basename(argv[0]) - type_path = os.path.join(os.environ['__cdist_type_base_path'], cdist_type) - param_dir = os.path.join(type_path, "parameter") - global_dir = os.environ['__global'] + type_path = os.path.join(os.environ['__cdist_type_base_path'], cdist_type) + param_path = os.path.join(type_path, "parameter") + global_path = os.environ['__global'] object_source = os.environ['__cdist_manifest'] if '__debug' in os.environ: @@ -42,10 +42,10 @@ def run(argv): parser = argparse.ArgumentParser(add_help=False) - for parameter in cdist.file_to_list(os.path.join(param_dir, "optional")): + for parameter in cdist.file_to_list(os.path.join(param_path, "optional")): argument = "--" + parameter parser.add_argument(argument, action='store', required=False) - for parameter in cdist.file_to_list(os.path.join(param_dir, "required")): + for parameter in cdist.file_to_list(os.path.join(param_path, "required")): argument = "--" + parameter parser.add_argument(argument, action='store', required=True) @@ -74,15 +74,15 @@ def run(argv): # FIXME: verify object id log.debug(args) - object_dir = os.path.join(global_dir, "object", cdist_type, + object_path = os.path.join(global_path, "object", cdist_type, object_id, cdist.DOT_CDIST) - log.debug("Object output dir = " + object_dir) + log.debug("Object output dir = " + object_path) - param_out_dir = os.path.join(object_dir, "parameter") + param_out_dir = os.path.join(object_path, "parameter") - object_source_file = os.path.join(object_dir, "source") + object_source_file = os.path.join(object_path, "source") - if os.path.exists(param_out_dir): + if os.path.exists(object_path): object_exists = True old_object_source_fd = open(object_source_file, "r") old_object_source = old_object_source_fd.readlines() @@ -91,7 +91,9 @@ def run(argv): else: object_exists = False try: - os.makedirs(param_out_dir, exist_ok=True) + os.makedirs(object_path, exist_ok=False) + log.debug("Object param dir = " + param_out_dir) + os.makedirs(param_out_dir, exist_ok=False) except OSError as error: raise cdist.Error(param_out_dir + ": " + error.args[1]) @@ -131,12 +133,12 @@ def run(argv): if "require" in os.environ: requirements = os.environ['__require'] log.debug(object_id + ":Writing requirements: " + requirements) - require_fd = open(os.path.join(object_dir, "require"), "a") + require_fd = open(os.path.join(object_path, "require"), "a") require_fd.write(requirements.replace(" ","\n")) require_fd.close() # Record / Append source - source_fd = open(os.path.join(object_dir, "source"), "a") + source_fd = open(os.path.join(object_path, "source"), "a") source_fd.writelines(object_source) source_fd.close() From 3115ee46ab08e9b16a0d05865caba45be90ad2c3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:46:52 +0200 Subject: [PATCH 0634/4212] ++todo(steven) Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 41941739..2c2f523c 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -30,3 +30,5 @@ Tests needed: - does $require work? - $whatever should fail if there is no global explorer directory - emulator may only be called with __ as prefix - fail otherwise! + + - ensure paths returned by object include dot-cdist From 53737aad3a0e83a74ea7150f1210844ca0850bda Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 16:46:55 +0200 Subject: [PATCH 0635/4212] append .cdist to absolute paths Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index f5179606..2f1d93c4 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -69,7 +69,7 @@ class Object(object): self.object_id = object_id self.name = os.path.join(self.type.name, self.object_id) self.path = os.path.join(self.type.path, self.object_id) - self.absolute_path = os.path.join(self.base_path, self.path) + self.absolute_path = os.path.join(self.base_path, self.path, DOT_CDIST) self.code_local_path = os.path.join(self.path, "code-local") self.code_remote_path = os.path.join(self.path, "code-remote") self.parameter_path = os.path.join(self.path, "parameter") From 5f4a85f6ad88f8411965060fc568ed65e4bbbce3 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 16:49:18 +0200 Subject: [PATCH 0636/4212] also need .cdist in relative paths Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 2f1d93c4..4cbcd550 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -68,7 +68,7 @@ class Object(object): self.base_path = base_path self.object_id = object_id self.name = os.path.join(self.type.name, self.object_id) - self.path = os.path.join(self.type.path, self.object_id) + self.path = os.path.join(self.type.path, self.object_id, DOT_CDIST) self.absolute_path = os.path.join(self.base_path, self.path, DOT_CDIST) self.code_local_path = os.path.join(self.path, "code-local") self.code_remote_path = os.path.join(self.path, "code-remote") From d9bb8e31071253f9854b75865ac40addf123d5c4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:55:19 +0200 Subject: [PATCH 0637/4212] use cdist_type Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 2f4aa261..afc32d63 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -63,9 +63,9 @@ class ConfigInstall: def run_type_manifest(self, cdist_object): """Run manifest for a specific object""" - type = cdist_object.type + cdist_type = cdist_object.type manifest_path = os.path.join(self.context.type_base_path, - type.manifest_path) + cdist_type.manifest_path) log.debug("%s: Running %s", cdist_object.name, manifest) if os.path.exists(manifest_path): @@ -74,7 +74,7 @@ class ConfigInstall: "__object_id": cdist_object.object_id, "__object_fq": cdist_object.name, "__type": os.path.join(self.context.type_base_path, - type.path) + cdist_type.path) } self.run_manifest(manifest_path, extra_env=env) @@ -112,7 +112,7 @@ class ConfigInstall: if cdist_object.ran: return - type = cdist_object.type + cdist_type = cdist_object.type for requirement in cdist_object.requirements: log.debug("Object %s requires %s", cdist_object, requirement) @@ -127,12 +127,12 @@ class ConfigInstall: env["__object"] = os.path.join(self.context.object_base_path, cdist_object.path) env["__object_id"] = cdist_object.object_id env["__object_fq"] = cdist_object.name - env["__type"] = type.name + env["__type"] = cdist_type.name # gencode for cmd in ["local", "remote"]: bin = os.path.join(self.context.type_base_path, - getattr(type, "gencode_" + cmd)) + getattr(cdist_type, "gencode_" + cmd)) if os.path.isfile(bin): outfile = os.path.join(self.context.object_base_path, @@ -191,10 +191,9 @@ class ConfigInstall: # Need to transfer at least the parameters for objects to be useful self.transfer_object_parameter(cdist_object) - explorers = self.path.list_type_explorers(type) - for explorer in explorers: - remote_cmd = cmd + [os.path.join(type.explorer_remote_path, explorer)] - output = os.path.join(cdist_object.explorer_output_path(), explorer) + for explorer in cdist_type.explorers: + remote_cmd = cmd + [os.path.join(cdist_type.explorer_path, explorer)] + output = os.path.join(cdist_object.explorer_output_path, explorer) output_fd = open(output, mode='w') log.debug("%s exploring %s using %s storing to %s", cdist_object, explorer, remote_cmd, output) @@ -206,8 +205,8 @@ class ConfigInstall: def link_emulator(self): """Link emulator to types""" src = os.path.abspath(self.exec_path) - for type in cdist.core.Type.list_types(self.context.type_base_path): - dst = os.path.join(self.context.bin_path, type.name) + for cdist_type in cdist.core.Type.list_types(self.context.type_base_path): + dst = os.path.join(self.context.bin_path, cdist_type.name) log.debug("Linking emulator: %s to %s", src, dst) # FIXME: handle exception / make it more beautiful @@ -284,6 +283,7 @@ class ConfigInstall: cdist_object.parameter_path) # Synchronise parameter dir afterwards + self.context.remote_mkdir(dst) self.context.transfer_path(src, dst) def transfer_global_explorers(self): From df2b4fbfd7111c0d8e7fd37e52ddb73d15f469db Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 16:57:24 +0200 Subject: [PATCH 0638/4212] ++todo(steven) Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 2c2f523c..722b6b6b 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -32,3 +32,4 @@ Tests needed: - emulator may only be called with __ as prefix - fail otherwise! - ensure paths returned by object include dot-cdist + - ensure path of explorer of object returns correct path From b778c9ff15f9ab61875257ca1a905d86dca636c0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 16:59:52 +0200 Subject: [PATCH 0639/4212] absolute path is based on relative path -> does not need another .cdist Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 4cbcd550..12d16838 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -69,7 +69,7 @@ class Object(object): self.object_id = object_id self.name = os.path.join(self.type.name, self.object_id) self.path = os.path.join(self.type.path, self.object_id, DOT_CDIST) - self.absolute_path = os.path.join(self.base_path, self.path, DOT_CDIST) + self.absolute_path = os.path.join(self.base_path, self.path) self.code_local_path = os.path.join(self.path, "code-local") self.code_remote_path = os.path.join(self.path, "code-remote") self.parameter_path = os.path.join(self.path, "parameter") From 35900ae66cfda15945a185b1045620210bd54ef2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:01:59 +0200 Subject: [PATCH 0640/4212] make type explorer work Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index afc32d63..d55429ed 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -192,8 +192,10 @@ class ConfigInstall: self.transfer_object_parameter(cdist_object) for explorer in cdist_type.explorers: - remote_cmd = cmd + [os.path.join(cdist_type.explorer_path, explorer)] - output = os.path.join(cdist_object.explorer_output_path, explorer) + remote_cmd = cmd + [os.path.join(self.context.type_base_path, + cdist_type.explorer_path, explorer)] + output = os.path.join(self.context.object_base_path, + cdist_object.explorer_path, explorer) output_fd = open(output, mode='w') log.debug("%s exploring %s using %s storing to %s", cdist_object, explorer, remote_cmd, output) From 4a1cf3dbf3ca40c823ea916d1ee2c87892eb9316 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:02:24 +0200 Subject: [PATCH 0641/4212] -typo Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index d55429ed..db0c8caf 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -67,7 +67,7 @@ class ConfigInstall: manifest_path = os.path.join(self.context.type_base_path, cdist_type.manifest_path) - log.debug("%s: Running %s", cdist_object.name, manifest) + log.debug("%s: Running %s", cdist_object.name, manifest_path) if os.path.exists(manifest_path): env = { "__object" : os.path.join(self.context.object_base_path, cdist_object.path), From c6e8f163f58cf9d3359e8531d6624d7c80e3a666 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:03:38 +0200 Subject: [PATCH 0642/4212] use variable require, not __require for defining Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 298161d9..27a3abb1 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -131,7 +131,7 @@ def run(argv): # Record requirements if "require" in os.environ: - requirements = os.environ['__require'] + requirements = os.environ['require'] log.debug(object_id + ":Writing requirements: " + requirements) require_fd = open(os.path.join(object_path, "require"), "a") require_fd.write(requirements.replace(" ","\n")) From b5c01f7354e92981ae7ed6c6e0beaadb9d700f3c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:04:52 +0200 Subject: [PATCH 0643/4212] update code to use new _path from object and type Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index db0c8caf..c4c1af10 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -132,11 +132,11 @@ class ConfigInstall: # gencode for cmd in ["local", "remote"]: bin = os.path.join(self.context.type_base_path, - getattr(cdist_type, "gencode_" + cmd)) + getattr(cdist_type, "gencode_" + cmd + "_path")) if os.path.isfile(bin): outfile = os.path.join(self.context.object_base_path, - getattr(cdist_object, "code_" + cmd)) + getattr(cdist_object, "code_" + cmd + "_path")) outfile_fd = open(outfile, "w") From 073717e07e68769a5878dd20cbe81eedbcd3e8b9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:07:10 +0200 Subject: [PATCH 0644/4212] some more relative to absolute path changes Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index c4c1af10..e6172a8c 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -163,10 +163,12 @@ class ConfigInstall: cdist.exec.run_or_fail([code_local]) # code remote - local_remote_code = cdist_object.code_remote_path - remote_remote_code = cdist_object.remote_code_remote_path + local_remote_code = os.path.join(self.context.object_base_path, + cdist_object.code_remote_path) + remote_remote_code = os.path.join(self.context.remote_object_path, + cdist_object.code_remote_path) if os.path.isfile(local_remote_code): - self.context.transfer_file(local_remote_code, remote_remote_code) + self.context.transfer_path(local_remote_code, remote_remote_code) cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) cdist_object.ran = True From d32aa37fba9713b80fa71de9f94a30d1fae94076 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:07:31 +0200 Subject: [PATCH 0645/4212] cleanup context Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index e6172a8c..fcbc79fc 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -53,7 +53,7 @@ class ConfigInstall: debug=debug) def cleanup(self): - self.path.cleanup() + self.context.cleanup() def run_initial_manifest(self): """Run the initial manifest""" From c0561958d0efca781a2c27fd1f73e58d7af236f2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:10:10 +0200 Subject: [PATCH 0646/4212] todo(steven) == changed Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 722b6b6b..2e38d817 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,25 +1,3 @@ -Object: - - -Type: - type.transferred_explorers - - -GlobalExplorer: - out_path: local path into which the output is written - - cdist.core.GlobalExplorer.base_dir - local directory containing explorers - cdist.core.GlobalExplorer.remote_base_dir - remote directory containing explorers - - path: local path to explorer - remote_path: remote path to explorer - - See config_install: run_global_explorers() - -Object/Type: - - rutern relative only - - Have accept absulet path on listing - Tests needed: - Fail if cache_dir from previous run cannot be deleted @@ -33,3 +11,7 @@ Tests needed: - ensure paths returned by object include dot-cdist - ensure path of explorer of object returns correct path + +Code fixes needed: + + - shutil, os.mkdir, etc. everywhere: catch/reraise exceptions correctly From 63c9a91bcad5eac759240f00c8ddc0cdcf0d9ff4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:12:06 +0200 Subject: [PATCH 0647/4212] +whitespace save out only Signed-off-by: Nico Schottelius --- lib/cdist/context.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index fb00b423..a4fdbca5 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -99,11 +99,11 @@ class Context: # "other globals referenced by the __del__() method may already have been deleted # or in the process of being torn down (e.g. the import machinery shutting down)" # - log.debug("Saving" + self.base_path + "to " + self.cache_path) + log.debug("Saving " + self.out_path + " to " + self.cache_path) # Remove previous cache if os.path.exists(self.cache_path): shutil.rmtree(self.cache_path) - shutil.move(self.base_path, self.cache_path) + shutil.move(self.out_path, self.cache_path) def __init_out_paths(self): """Initialise output directory structure""" From 9b0c0be5568b503bd5435bc4448d758529097cb0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:13:01 +0200 Subject: [PATCH 0648/4212] ++todo(nico) Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index f96da0de..005f1bb0 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,6 +1,7 @@ 2.0.3: -- fix emulator +- fix emulator / require +- sanity checks -------------------------------------------------------------------------------- From be78955cc6fe28aef9dc0dd0de3fe3c11ba7890b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:18:39 +0200 Subject: [PATCH 0649/4212] move banner into cdist module Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 17 ++++++++++++++++- lib/cdist/banner.py | 19 +++---------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 7aca5ac7..a3dc01cc 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -19,8 +19,23 @@ # # -VERSION = "2.0.3" +BANNER = """ + .. . .x+=:. s + dF @88> z` ^% :8 + '88bu. %8P . z` ^% :8 - '88bu. %8P . Date: Fri, 7 Oct 2011 17:38:10 +0200 Subject: [PATCH 0650/4212] 100% test coverage for the banner (feels good, doesn't it?) Signed-off-by: Nico Schottelius --- lib/cdist/test/test_banner.py | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 lib/cdist/test/test_banner.py diff --git a/lib/cdist/test/test_banner.py b/lib/cdist/test/test_banner.py new file mode 100644 index 00000000..4b0ab6ac --- /dev/null +++ b/lib/cdist/test/test_banner.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 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 io +import sys +import unittest + +import cdist +import cdist.banner + +class Banner(unittest.TestCase): + def setUp(self): + self.banner = cdist.BANNER + "\n" + + def test_banner_output(self): + """Check that printed banner equals saved banner""" + output = io.StringIO() + + sys.stdout = output + + cdist.banner.banner(None) + + self.assertEqual(output.getvalue(), self.banner) From e985c0d69713d7f32be71b387088d5a36792bd83 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:38:50 +0200 Subject: [PATCH 0651/4212] remove sys.exit from banner Signed-off-by: Nico Schottelius --- lib/cdist/banner.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cdist/banner.py b/lib/cdist/banner.py index d7ee1b00..4148fa72 100644 --- a/lib/cdist/banner.py +++ b/lib/cdist/banner.py @@ -30,4 +30,3 @@ log = logging.getLogger(__name__) def banner(args): """Guess what :-)""" print(cdist.BANNER) - sys.exit(0) From d3f0965ace998fe95cc8151b1d0de6b11f6b34f1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:39:04 +0200 Subject: [PATCH 0652/4212] make t less verbose Signed-off-by: Nico Schottelius --- build.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build.sh b/build.sh index 6a91ff3d..63c380cf 100755 --- a/build.sh +++ b/build.sh @@ -126,6 +126,12 @@ case "$1" in | xargs rm -f ;; + t) + shift # skip t + PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib \ + python3 -m unittest "$@" + ;; + test) PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib \ python3 -m cdist.test From f2869161ed6c366e3f88d08b07ca977b8f4ffdec Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:45:39 +0200 Subject: [PATCH 0653/4212] ++todo(steven) Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 2e38d817..8d403245 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -12,6 +12,15 @@ Tests needed: - ensure paths returned by object include dot-cdist - ensure path of explorer of object returns correct path + config_install: + run_type_manifest() - same tests as for test_initial_manifest_*? + run_manifest() - raise exception if manifest is not existent + object_run(): ensure no object is run twice + object_run(): ensure requirements are taken into account + object_run(): check (from extern?) that all needed variables are setup + object_run(): ensure no code-{local, remote} is created, if gencode is not producing code + object_run(): ensure no code-{local, remote} contains what gencode created + Code fixes needed: - shutil, os.mkdir, etc. everywhere: catch/reraise exceptions correctly From 71af3b60c08850853954b71c2b506ef74f29cdc2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 17:48:36 +0200 Subject: [PATCH 0654/4212] move test todos to own file Signed-off-by: Nico Schottelius --- doc/dev/todo/steven | 23 ----------------------- doc/dev/todo/tests | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 23 deletions(-) create mode 100644 doc/dev/todo/tests diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 8d403245..f0c867e1 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,26 +1,3 @@ -Tests needed: - - - Fail if cache_dir from previous run cannot be deleted - - Fail if cache_dir cannot be created from current out_dir - - transfer_type_explorers: Explorers are not transferred twice - - transfer_type_explorers: No transfer tried if there are no type_explorers - - - does $require work? - - $whatever should fail if there is no global explorer directory - - emulator may only be called with __ as prefix - fail otherwise! - - - ensure paths returned by object include dot-cdist - - ensure path of explorer of object returns correct path - - config_install: - run_type_manifest() - same tests as for test_initial_manifest_*? - run_manifest() - raise exception if manifest is not existent - object_run(): ensure no object is run twice - object_run(): ensure requirements are taken into account - object_run(): check (from extern?) that all needed variables are setup - object_run(): ensure no code-{local, remote} is created, if gencode is not producing code - object_run(): ensure no code-{local, remote} contains what gencode created - Code fixes needed: - shutil, os.mkdir, etc. everywhere: catch/reraise exceptions correctly diff --git a/doc/dev/todo/tests b/doc/dev/todo/tests new file mode 100644 index 00000000..8f019fed --- /dev/null +++ b/doc/dev/todo/tests @@ -0,0 +1,28 @@ +Tests needed: + + - Fail if cache_dir from previous run cannot be deleted + - Fail if cache_dir cannot be created from current out_dir + - transfer_type_explorers: Explorers are not transferred twice + - transfer_type_explorers: No transfer tried if there are no type_explorers + + - does $require work? + - $whatever should fail if there is no global explorer directory + - emulator may only be called with __ as prefix - fail otherwise! + + - ensure paths returned by object include dot-cdist + - ensure path of explorer of object returns correct path + + config_install: + run_type_manifest() - same tests as for test_initial_manifest_*? + run_manifest() - raise exception if manifest is not existent + object_run(): ensure no object is run twice + object_run(): ensure requirements are taken into account + object_run(): check (from extern?) that all needed variables are setup + object_run(): ensure no code-{local, remote} is created, if gencode is not producing code + object_run(): ensure no code-{local, remote} contains what gencode created + + run_type_explorer(): ensure output is saved to correct path + run_type_explorer(): ensure a type with no explorers works + run_type_explorer(): ensure environment is setup correctly + + From ae15779c8137420f9cd66b471e883badc56c6349 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 17:50:53 +0200 Subject: [PATCH 0655/4212] -- DeprecationWarning: object.__new__() takes no parameters Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index 42a74398..a9a34946 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -52,7 +52,7 @@ class Type(object): # name is second argument name = args[1] if not name in cls._instances: - instance = super(Type, cls).__new__(cls, *args, **kwargs) + instance = super(Type, cls).__new__(cls) cls._instances[name] = instance return cls._instances[name] From f515e20572c314fa99012e675b05338e8d3283ab Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 17:52:38 +0200 Subject: [PATCH 0656/4212] start unittests for Type Signed-off-by: Steven Armstrong --- lib/cdist/test/type/__init__.py | 0 .../test/type/fixtures/__not_singleton/.keep | 0 .../test/type/fixtures/__singleton/singleton | 0 lib/cdist/test/type/test_type.py | 61 +++++++++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 lib/cdist/test/type/__init__.py create mode 100644 lib/cdist/test/type/fixtures/__not_singleton/.keep create mode 100644 lib/cdist/test/type/fixtures/__singleton/singleton create mode 100644 lib/cdist/test/type/test_type.py diff --git a/lib/cdist/test/type/__init__.py b/lib/cdist/test/type/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/type/fixtures/__not_singleton/.keep b/lib/cdist/test/type/fixtures/__not_singleton/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/type/fixtures/__singleton/singleton b/lib/cdist/test/type/fixtures/__singleton/singleton new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/type/test_type.py b/lib/cdist/test/type/test_type.py new file mode 100644 index 00000000..de202b8b --- /dev/null +++ b/lib/cdist/test/type/test_type.py @@ -0,0 +1,61 @@ +# -*- 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 tempfile +import unittest +import shutil + +import cdist.core + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') + + +class TypeTestCase(unittest.TestCase): + def setUp(self): + # FIXME: use defined set of types for testing? + # FIXME: generate object tree or use predefined? + self.temp_dir = tempfile.mkdtemp() + self.object_base_path = op.join(self.temp_dir, '') + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_singleton_is_singleton(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__singleton') + self.assertTrue(cdist_type.is_singleton) + + def test_not_singleton_is_singleton(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__not_singleton') + self.assertFalse(cdist_type.is_singleton) + + +''' +suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) + +def suite(): + tests = [] + return unittest.TestSuite(map(ObjectTestCase, tests)) +''' From d21126189cc92957087da37b3f4c5d0b4b0ab367 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 18:04:13 +0200 Subject: [PATCH 0657/4212] indent/cleanup Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index fcbc79fc..766cffa2 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -90,13 +90,13 @@ class ConfigInstall: # Submit debug flag to manifest, can be used by emulator and types if self.debug: - env['__debug'] = "yes" + env['__debug'] = "yes" # Required for recording source in emulator env['__cdist_manifest'] = manifest_path # Required to find types in emulator - env['__cdist_type_base_path'] = self.context.type_base_path + env['__cdist_type_base_path'] = self.context.type_base_path # Other environment stuff if extra_env: From 11a8379c75265e721452ab039b7adefb37939579 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 18:13:58 +0200 Subject: [PATCH 0658/4212] +comment Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 766cffa2..3e67f7c1 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -105,7 +105,7 @@ class ConfigInstall: cdist.exec.shell_run_or_debug_fail(manifest_path, [manifest_path], env=env) def object_run(self, cdist_object): - """Run gencode or code for an object""" + """Run gencode and code for an object""" log.debug("Running object %s", cdist_object) # Catch requirements, which re-call us From 71ed728b4adf68ab3460e309d012554af46216d5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Oct 2011 18:14:17 +0200 Subject: [PATCH 0659/4212] move parallel code to main binary, allow branching out on install and config Signed-off-by: Nico Schottelius --- bin/cdist | 40 ++++++++++++++++++++++++++++++++++++++-- lib/cdist/config.py | 27 --------------------------- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/bin/cdist b/bin/cdist index 7d2c035b..1b8b4346 100755 --- a/bin/cdist +++ b/bin/cdist @@ -81,12 +81,12 @@ def commandline(): # Config parser['config'] = parser['sub'].add_parser('config', parents=[parser['loglevel'], parser['configinstall']]) - parser['config'].set_defaults(func=cdist.config.config) + parser['config'].set_defaults(func=config) # Install parser['install'] = parser['sub'].add_parser('install', parents=[parser['loglevel'], parser['configinstall']]) - parser['install'].set_defaults(func=cdist.install.install) + parser['install'].set_defaults(func=install) for p in parser: parser[p].epilog = "Get cdist at http://www.nico.schottelius.org/software/cdist/" @@ -102,6 +102,42 @@ def commandline(): log.debug(args) args.func(args) +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""" + process = {} + + time_start = datetime.datetime.now() + + os.environ['__remote_exec'] = "ssh -o User=root -q" + os.environ['__remote_copy'] = "scp -o User=root -q" + + for host in args.host: + c = mode(host, initial_manifest=args.manifest, base_path=args.cdist_home, debug=args.debug) + if args.parallel: + log.debug("Creating child process for %s", host) + process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) + process[host].start() + else: + c.deploy_and_cleanup() + + if args.parallel: + for p in process.keys(): + log.debug("Joining process %s", p) + process[p].join() + + # FIXME: error handling for parallel mode! + + time_end = datetime.datetime.now() + log.info("Total processing time for %s host(s): %s", len(args.host), + (time_end - time_start).total_seconds()) + + if __name__ == "__main__": try: logging.basicConfig(format='%(levelname)s: %(message)s') diff --git a/lib/cdist/config.py b/lib/cdist/config.py index 71ce14ed..782c88a1 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -31,30 +31,3 @@ log = logging.getLogger(__name__) class Config(cdist.config_install.ConfigInstall): pass - -def config(args): - """Configure remote system""" - process = {} - - time_start = datetime.datetime.now() - - os.environ['__remote_exec'] = "ssh -o User=root -q" - os.environ['__remote_copy'] = "scp -o User=root -q" - - for host in args.host: - c = Config(host, initial_manifest=args.manifest, base_path=args.cdist_home, debug=args.debug) - if args.parallel: - log.debug("Creating child process for %s", host) - process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) - process[host].start() - else: - c.deploy_and_cleanup() - - if args.parallel: - for p in process.keys(): - log.debug("Joining process %s", p) - process[p].join() - - time_end = datetime.datetime.now() - log.info("Total processing time for %s host(s): %s", len(args.host), - (time_end - time_start).total_seconds()) From 52f9388f07ae4842e28e3935c45ea69c2feac543 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 18:22:38 +0200 Subject: [PATCH 0660/4212] tests and fixtures for Type.is_install Signed-off-by: Steven Armstrong --- lib/cdist/test/type/fixtures/__install/install | 0 lib/cdist/test/type/fixtures/__not_install/.keep | 0 lib/cdist/test/type/test_type.py | 8 ++++++++ 3 files changed, 8 insertions(+) create mode 100644 lib/cdist/test/type/fixtures/__install/install create mode 100644 lib/cdist/test/type/fixtures/__not_install/.keep diff --git a/lib/cdist/test/type/fixtures/__install/install b/lib/cdist/test/type/fixtures/__install/install new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/type/fixtures/__not_install/.keep b/lib/cdist/test/type/fixtures/__not_install/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/type/test_type.py b/lib/cdist/test/type/test_type.py index de202b8b..ca62002a 100644 --- a/lib/cdist/test/type/test_type.py +++ b/lib/cdist/test/type/test_type.py @@ -51,7 +51,15 @@ class TypeTestCase(unittest.TestCase): cdist_type = cdist.core.Type(base_path, '__not_singleton') self.assertFalse(cdist_type.is_singleton) + def test_install_is_install(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__install') + self.assertTrue(cdist_type.is_install) + def test_not_install_is_install(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__not_install') + self.assertFalse(cdist_type.is_install) ''' suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) From 8e0501aaa906677c47f418735d491429670d4bdb Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 18:28:22 +0200 Subject: [PATCH 0661/4212] tests and fixtures for Type.explorers Signed-off-by: Steven Armstrong --- lib/cdist/test/test_object.py | 46 +++++++++++++++++++ .../__with_explorers/explorer/whatever | 2 + .../type/fixtures/__without_explorers/.keep | 0 lib/cdist/test/type/test_type.py | 12 +++++ 4 files changed, 60 insertions(+) create mode 100644 lib/cdist/test/test_object.py create mode 100755 lib/cdist/test/type/fixtures/__with_explorers/explorer/whatever create mode 100644 lib/cdist/test/type/fixtures/__without_explorers/.keep diff --git a/lib/cdist/test/test_object.py b/lib/cdist/test/test_object.py new file mode 100644 index 00000000..ae584840 --- /dev/null +++ b/lib/cdist/test/test_object.py @@ -0,0 +1,46 @@ +# -*- 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 tempfile +import unittest +import shutil + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +base_path = op.join(my_dir, 'fixtures') + +class ObjectTestCase(unittest.TestCase): + def setUp(self): + # FIXME: use defined set of types for testing? + # FIXME: generate object tree or use predefined? + self.object_base_dir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.temp_dir) + +''' +suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) + +def suite(): + tests = [] + return unittest.TestSuite(map(ObjectTestCase, tests)) +''' diff --git a/lib/cdist/test/type/fixtures/__with_explorers/explorer/whatever b/lib/cdist/test/type/fixtures/__with_explorers/explorer/whatever new file mode 100755 index 00000000..01b7b61c --- /dev/null +++ b/lib/cdist/test/type/fixtures/__with_explorers/explorer/whatever @@ -0,0 +1,2 @@ +#!/bin/sh +echo whatever diff --git a/lib/cdist/test/type/fixtures/__without_explorers/.keep b/lib/cdist/test/type/fixtures/__without_explorers/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/type/test_type.py b/lib/cdist/test/type/test_type.py index ca62002a..15a596ca 100644 --- a/lib/cdist/test/type/test_type.py +++ b/lib/cdist/test/type/test_type.py @@ -60,6 +60,18 @@ class TypeTestCase(unittest.TestCase): base_path = fixtures cdist_type = cdist.core.Type(base_path, '__not_install') self.assertFalse(cdist_type.is_install) + + def test_with_explorers(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__with_explorers') + self.assertEqual(cdist_type.explorers, ['whatever']) + + def test_without_explorers(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__without_explorers') + self.assertEqual(cdist_type.explorers, []) + + ''' suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) From b7c88b03d30a189bd55cf7b0f9ce65f7cd14a842 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 18:29:24 +0200 Subject: [PATCH 0662/4212] removed unused code/imports Signed-off-by: Steven Armstrong --- lib/cdist/test/type/test_type.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/cdist/test/type/test_type.py b/lib/cdist/test/type/test_type.py index 15a596ca..49cc3a34 100644 --- a/lib/cdist/test/type/test_type.py +++ b/lib/cdist/test/type/test_type.py @@ -20,9 +20,7 @@ # import os -import tempfile import unittest -import shutil import cdist.core @@ -32,14 +30,6 @@ fixtures = op.join(my_dir, 'fixtures') class TypeTestCase(unittest.TestCase): - def setUp(self): - # FIXME: use defined set of types for testing? - # FIXME: generate object tree or use predefined? - self.temp_dir = tempfile.mkdtemp() - self.object_base_path = op.join(self.temp_dir, '') - - def tearDown(self): - shutil.rmtree(self.temp_dir) def test_singleton_is_singleton(self): base_path = fixtures From 8d3cad1815671d3b74b23ef46ff8a89a92e34d67 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 22:32:55 +0200 Subject: [PATCH 0663/4212] test and fixtures for Type.{required,optional}_parameters Signed-off-by: Steven Armstrong --- .../parameter/optional | 2 ++ .../parameter/required | 2 ++ .../__without_optional_parameters/.keep | 0 .../__without_required_parameters/.keep | 0 lib/cdist/test/type/test_type.py | 19 +++++++++++++++++++ 5 files changed, 23 insertions(+) create mode 100644 lib/cdist/test/type/fixtures/__with_optional_parameters/parameter/optional create mode 100644 lib/cdist/test/type/fixtures/__with_required_parameters/parameter/required create mode 100644 lib/cdist/test/type/fixtures/__without_optional_parameters/.keep create mode 100644 lib/cdist/test/type/fixtures/__without_required_parameters/.keep diff --git a/lib/cdist/test/type/fixtures/__with_optional_parameters/parameter/optional b/lib/cdist/test/type/fixtures/__with_optional_parameters/parameter/optional new file mode 100644 index 00000000..8174d2a9 --- /dev/null +++ b/lib/cdist/test/type/fixtures/__with_optional_parameters/parameter/optional @@ -0,0 +1,2 @@ +optional1 +optional2 diff --git a/lib/cdist/test/type/fixtures/__with_required_parameters/parameter/required b/lib/cdist/test/type/fixtures/__with_required_parameters/parameter/required new file mode 100644 index 00000000..e0fba2c9 --- /dev/null +++ b/lib/cdist/test/type/fixtures/__with_required_parameters/parameter/required @@ -0,0 +1,2 @@ +required1 +required2 diff --git a/lib/cdist/test/type/fixtures/__without_optional_parameters/.keep b/lib/cdist/test/type/fixtures/__without_optional_parameters/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/type/fixtures/__without_required_parameters/.keep b/lib/cdist/test/type/fixtures/__without_required_parameters/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/type/test_type.py b/lib/cdist/test/type/test_type.py index 49cc3a34..99ef3820 100644 --- a/lib/cdist/test/type/test_type.py +++ b/lib/cdist/test/type/test_type.py @@ -61,6 +61,25 @@ class TypeTestCase(unittest.TestCase): cdist_type = cdist.core.Type(base_path, '__without_explorers') self.assertEqual(cdist_type.explorers, []) + def test_with_required_parameters(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__with_required_parameters') + self.assertEqual(cdist_type.required_parameters, ['required1', 'required2']) + + def test_without_required_parameters(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__without_required_parameters') + self.assertEqual(cdist_type.required_parameters, []) + + def test_with_optional_parameters(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__with_optional_parameters') + self.assertEqual(cdist_type.optional_parameters, ['optional1', 'optional2']) + + def test_without_optional_parameters(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__without_optional_parameters') + self.assertEqual(cdist_type.optional_parameters, []) ''' suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) From d3e12769658b21f96d676140952d171f634d47fe Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 22:39:45 +0200 Subject: [PATCH 0664/4212] remove duplicate code Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index a9a34946..58a147b7 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -63,7 +63,6 @@ class Type(object): self.absolute_path = os.path.join(self._base_path, self.path) self.manifest_path = os.path.join(self.name, "manifest") self.explorer_path = os.path.join(self.name, "explorer") - self.manifest_path = os.path.join(self.name, "manifest") self.gencode_local_path = os.path.join(self.name, "gencode-local") self.gencode_remote_path = os.path.join(self.name, "gencode-remote") self.manifest_path = os.path.join(self.name, "manifest") From 73bdb7f11f345aaa6ed7a360d8ae92ebd8bb047f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 22:49:09 +0200 Subject: [PATCH 0665/4212] test and fixtures for Type members (name, path, ...) Signed-off-by: Steven Armstrong --- .../test/type/fixtures/__name_path/.keep | 0 lib/cdist/test/type/test_type.py | 36 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 lib/cdist/test/type/fixtures/__name_path/.keep diff --git a/lib/cdist/test/type/fixtures/__name_path/.keep b/lib/cdist/test/type/fixtures/__name_path/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/type/test_type.py b/lib/cdist/test/type/test_type.py index 99ef3820..140e5349 100644 --- a/lib/cdist/test/type/test_type.py +++ b/lib/cdist/test/type/test_type.py @@ -31,6 +31,42 @@ fixtures = op.join(my_dir, 'fixtures') class TypeTestCase(unittest.TestCase): + + def test_name(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.name, '__name_path') + + def test_path(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.path, '__name_path') + + def test_absolute_path(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.absolute_path, os.path.join(base_path, '__name_path')) + + def test_manifest_path(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.manifest_path, os.path.join('__name_path', 'manifest')) + + def test_explorer_path(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.explorer_path, os.path.join('__name_path', 'explorer')) + + def test_gencode_local_path(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.gencode_local_path, os.path.join('__name_path', 'gencode-local')) + + def test_gencode_remote_path(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.gencode_remote_path, os.path.join('__name_path', 'gencode-remote')) + def test_singleton_is_singleton(self): base_path = fixtures cdist_type = cdist.core.Type(base_path, '__singleton') From 5d59102018419e4a78774d3c7e0c9e26ba1eb83d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 22:50:11 +0200 Subject: [PATCH 0666/4212] test only one instance of same type Signed-off-by: Steven Armstrong --- lib/cdist/test/type/test_type.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/cdist/test/type/test_type.py b/lib/cdist/test/type/test_type.py index 140e5349..1c8d10aa 100644 --- a/lib/cdist/test/type/test_type.py +++ b/lib/cdist/test/type/test_type.py @@ -32,6 +32,12 @@ fixtures = op.join(my_dir, 'fixtures') class TypeTestCase(unittest.TestCase): + def test_only_one_instance(self): + base_path = fixtures + cdist_type1 = cdist.core.Type(base_path, '__name_path') + cdist_type2 = cdist.core.Type(base_path, '__name_path') + self.assertEqual(id(cdist_type1), id(cdist_type2)) + def test_name(self): base_path = fixtures cdist_type = cdist.core.Type(base_path, '__name_path') From f46344effe9794481b4f2fddd3e967683e6e8d87 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Oct 2011 22:51:06 +0200 Subject: [PATCH 0667/4212] test and fixtures for Type.list_* Signed-off-by: Steven Armstrong --- .../test/type/fixtures/list_types/__first/.keep | 0 .../test/type/fixtures/list_types/__second/.keep | 0 .../test/type/fixtures/list_types/__third/.keep | 0 lib/cdist/test/type/test_type.py | 14 ++++++++++++++ 4 files changed, 14 insertions(+) create mode 100644 lib/cdist/test/type/fixtures/list_types/__first/.keep create mode 100644 lib/cdist/test/type/fixtures/list_types/__second/.keep create mode 100644 lib/cdist/test/type/fixtures/list_types/__third/.keep diff --git a/lib/cdist/test/type/fixtures/list_types/__first/.keep b/lib/cdist/test/type/fixtures/list_types/__first/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/type/fixtures/list_types/__second/.keep b/lib/cdist/test/type/fixtures/list_types/__second/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/type/fixtures/list_types/__third/.keep b/lib/cdist/test/type/fixtures/list_types/__third/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/type/test_type.py b/lib/cdist/test/type/test_type.py index 1c8d10aa..5ba1f4b9 100644 --- a/lib/cdist/test/type/test_type.py +++ b/lib/cdist/test/type/test_type.py @@ -31,6 +31,20 @@ fixtures = op.join(my_dir, 'fixtures') class TypeTestCase(unittest.TestCase): + def test_list_type_names(self): + base_path = op.join(fixtures, 'list_types') + type_names = cdist.core.Type.list_type_names(base_path) + self.assertEqual(type_names, ['__first', '__second', '__third']) + + def test_list_types(self): + base_path = op.join(fixtures, 'list_types') + types = list(cdist.core.Type.list_types(base_path)) + types_expected = [ + cdist.core.Type(base_path, '__first'), + cdist.core.Type(base_path, '__second'), + cdist.core.Type(base_path, '__third'), + ] + self.assertEqual(types, types_expected) def test_only_one_instance(self): base_path = fixtures From d190b192deef9366262ff8fa9607206e8b1dd4ec Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Oct 2011 03:22:19 +0200 Subject: [PATCH 0668/4212] update timing method Signed-off-by: Nico Schottelius --- bin/cdist | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/bin/cdist b/bin/cdist index 1b8b4346..c42e540c 100755 --- a/bin/cdist +++ b/bin/cdist @@ -21,11 +21,11 @@ # import argparse -import datetime import logging import os import re import sys +import time log = logging.getLogger("cdist") @@ -112,7 +112,7 @@ def configinstall(args, mode): """Configure or install remote system""" process = {} - time_start = datetime.datetime.now() + time_start = time.time() os.environ['__remote_exec'] = "ssh -o User=root -q" os.environ['__remote_copy'] = "scp -o User=root -q" @@ -133,17 +133,15 @@ def configinstall(args, mode): # FIXME: error handling for parallel mode! - time_end = datetime.datetime.now() + time_end = time.time() log.info("Total processing time for %s host(s): %s", len(args.host), - (time_end - time_start).total_seconds()) + (time_end - time_start)) if __name__ == "__main__": try: logging.basicConfig(format='%(levelname)s: %(message)s') - time_start = datetime.datetime.now() - if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): import cdist.emulator cdist.emulator.run(sys.argv) @@ -154,13 +152,6 @@ if __name__ == "__main__": commandline() - time_end = datetime.datetime.now() - duration = time_end - time_start - # FIXME: move into runner - # log.info("Finished run of %s in %s seconds", self.target_host, - # duration.total_seconds()) - log.info("Finished run in %s seconds", duration.total_seconds()) - except KeyboardInterrupt: sys.exit(0) except cdist.Error as e: From e10ebeadf89f31bb1b6a85c45e7eb65b1c6aba0a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Oct 2011 03:24:05 +0200 Subject: [PATCH 0669/4212] BUGFIX: export global explorer with path from remote Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 3e67f7c1..3544a901 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -24,6 +24,7 @@ import logging import os import stat import sys +import time import cdist.context import cdist.core @@ -230,7 +231,7 @@ class ConfigInstall: output_fd = open(os.path.join(dst_path, explorer), mode='w') cmd = [] cmd.append("__explorer=" + remote_dst_path) - cmd.append(os.path.join(src_path, explorer)) + cmd.append(os.path.join(remote_dst_path, explorer)) cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=True) output_fd.close() @@ -252,8 +253,11 @@ class ConfigInstall: def deploy_and_cleanup(self): """Do what is most often done: deploy & cleanup""" + start_time = time.time() self.deploy_to() self.cleanup() + log.info("Finished run of %s in %s seconds", + self.target_host, time.time() - start_time) def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" From ea146c88e7a0cf6f46cb4c6e35f0f3e643d85c17 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Oct 2011 11:59:26 +0200 Subject: [PATCH 0670/4212] cleanup config Signed-off-by: Nico Schottelius --- lib/cdist/config.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/cdist/config.py b/lib/cdist/config.py index 782c88a1..9af25b75 100644 --- a/lib/cdist/config.py +++ b/lib/cdist/config.py @@ -20,14 +20,7 @@ # # -import datetime -import logging -import os -import sys - import cdist.config_install -log = logging.getLogger(__name__) - class Config(cdist.config_install.ConfigInstall): pass From 56e1fc9eb8f47be7139aea1eb1f3e1af3a2be8d5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Oct 2011 12:01:53 +0200 Subject: [PATCH 0671/4212] type explorer should run with remote base as well :-) Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 3544a901..e4b51ad4 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -195,7 +195,7 @@ class ConfigInstall: self.transfer_object_parameter(cdist_object) for explorer in cdist_type.explorers: - remote_cmd = cmd + [os.path.join(self.context.type_base_path, + remote_cmd = cmd + [os.path.join(self.context.remote_base_path, cdist_type.explorer_path, explorer)] output = os.path.join(self.context.object_base_path, cdist_object.explorer_path, explorer) From 93a312702c207e003032f32e9c6f43db4201567b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Oct 2011 12:06:45 +0200 Subject: [PATCH 0672/4212] ++todo(nico) Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 005f1bb0..9710f4ea 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -331,3 +331,4 @@ eof - remote_prefix: scp vs. ssh issue +locale_type From c9159b15f17be4d4f7262d1670e88398571a5b02 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sun, 9 Oct 2011 07:41:53 +0200 Subject: [PATCH 0673/4212] use package, no need for another file Signed-off-by: Steven Armstrong --- lib/cdist/test/type/__init__.py | 146 +++++++++++++++++++++++++++++++ lib/cdist/test/type/test_type.py | 146 ------------------------------- 2 files changed, 146 insertions(+), 146 deletions(-) delete mode 100644 lib/cdist/test/type/test_type.py diff --git a/lib/cdist/test/type/__init__.py b/lib/cdist/test/type/__init__.py index e69de29b..5ba1f4b9 100644 --- a/lib/cdist/test/type/__init__.py +++ b/lib/cdist/test/type/__init__.py @@ -0,0 +1,146 @@ +# -*- 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 unittest + +import cdist.core + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') + + +class TypeTestCase(unittest.TestCase): + + def test_list_type_names(self): + base_path = op.join(fixtures, 'list_types') + type_names = cdist.core.Type.list_type_names(base_path) + self.assertEqual(type_names, ['__first', '__second', '__third']) + + def test_list_types(self): + base_path = op.join(fixtures, 'list_types') + types = list(cdist.core.Type.list_types(base_path)) + types_expected = [ + cdist.core.Type(base_path, '__first'), + cdist.core.Type(base_path, '__second'), + cdist.core.Type(base_path, '__third'), + ] + self.assertEqual(types, types_expected) + + def test_only_one_instance(self): + base_path = fixtures + cdist_type1 = cdist.core.Type(base_path, '__name_path') + cdist_type2 = cdist.core.Type(base_path, '__name_path') + self.assertEqual(id(cdist_type1), id(cdist_type2)) + + def test_name(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.name, '__name_path') + + def test_path(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.path, '__name_path') + + def test_absolute_path(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.absolute_path, os.path.join(base_path, '__name_path')) + + def test_manifest_path(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.manifest_path, os.path.join('__name_path', 'manifest')) + + def test_explorer_path(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.explorer_path, os.path.join('__name_path', 'explorer')) + + def test_gencode_local_path(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.gencode_local_path, os.path.join('__name_path', 'gencode-local')) + + def test_gencode_remote_path(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.gencode_remote_path, os.path.join('__name_path', 'gencode-remote')) + + def test_singleton_is_singleton(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__singleton') + self.assertTrue(cdist_type.is_singleton) + + def test_not_singleton_is_singleton(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__not_singleton') + self.assertFalse(cdist_type.is_singleton) + + def test_install_is_install(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__install') + self.assertTrue(cdist_type.is_install) + + def test_not_install_is_install(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__not_install') + self.assertFalse(cdist_type.is_install) + + def test_with_explorers(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__with_explorers') + self.assertEqual(cdist_type.explorers, ['whatever']) + + def test_without_explorers(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__without_explorers') + self.assertEqual(cdist_type.explorers, []) + + def test_with_required_parameters(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__with_required_parameters') + self.assertEqual(cdist_type.required_parameters, ['required1', 'required2']) + + def test_without_required_parameters(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__without_required_parameters') + self.assertEqual(cdist_type.required_parameters, []) + + def test_with_optional_parameters(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__with_optional_parameters') + self.assertEqual(cdist_type.optional_parameters, ['optional1', 'optional2']) + + def test_without_optional_parameters(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__without_optional_parameters') + self.assertEqual(cdist_type.optional_parameters, []) + +''' +suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) + +def suite(): + tests = [] + return unittest.TestSuite(map(ObjectTestCase, tests)) +''' diff --git a/lib/cdist/test/type/test_type.py b/lib/cdist/test/type/test_type.py deleted file mode 100644 index 5ba1f4b9..00000000 --- a/lib/cdist/test/type/test_type.py +++ /dev/null @@ -1,146 +0,0 @@ -# -*- 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 unittest - -import cdist.core - -import os.path as op -my_dir = op.abspath(op.dirname(__file__)) -fixtures = op.join(my_dir, 'fixtures') - - -class TypeTestCase(unittest.TestCase): - - def test_list_type_names(self): - base_path = op.join(fixtures, 'list_types') - type_names = cdist.core.Type.list_type_names(base_path) - self.assertEqual(type_names, ['__first', '__second', '__third']) - - def test_list_types(self): - base_path = op.join(fixtures, 'list_types') - types = list(cdist.core.Type.list_types(base_path)) - types_expected = [ - cdist.core.Type(base_path, '__first'), - cdist.core.Type(base_path, '__second'), - cdist.core.Type(base_path, '__third'), - ] - self.assertEqual(types, types_expected) - - def test_only_one_instance(self): - base_path = fixtures - cdist_type1 = cdist.core.Type(base_path, '__name_path') - cdist_type2 = cdist.core.Type(base_path, '__name_path') - self.assertEqual(id(cdist_type1), id(cdist_type2)) - - def test_name(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') - self.assertEqual(cdist_type.name, '__name_path') - - def test_path(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') - self.assertEqual(cdist_type.path, '__name_path') - - def test_absolute_path(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') - self.assertEqual(cdist_type.absolute_path, os.path.join(base_path, '__name_path')) - - def test_manifest_path(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') - self.assertEqual(cdist_type.manifest_path, os.path.join('__name_path', 'manifest')) - - def test_explorer_path(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') - self.assertEqual(cdist_type.explorer_path, os.path.join('__name_path', 'explorer')) - - def test_gencode_local_path(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') - self.assertEqual(cdist_type.gencode_local_path, os.path.join('__name_path', 'gencode-local')) - - def test_gencode_remote_path(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') - self.assertEqual(cdist_type.gencode_remote_path, os.path.join('__name_path', 'gencode-remote')) - - def test_singleton_is_singleton(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__singleton') - self.assertTrue(cdist_type.is_singleton) - - def test_not_singleton_is_singleton(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__not_singleton') - self.assertFalse(cdist_type.is_singleton) - - def test_install_is_install(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__install') - self.assertTrue(cdist_type.is_install) - - def test_not_install_is_install(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__not_install') - self.assertFalse(cdist_type.is_install) - - def test_with_explorers(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__with_explorers') - self.assertEqual(cdist_type.explorers, ['whatever']) - - def test_without_explorers(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__without_explorers') - self.assertEqual(cdist_type.explorers, []) - - def test_with_required_parameters(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__with_required_parameters') - self.assertEqual(cdist_type.required_parameters, ['required1', 'required2']) - - def test_without_required_parameters(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__without_required_parameters') - self.assertEqual(cdist_type.required_parameters, []) - - def test_with_optional_parameters(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__with_optional_parameters') - self.assertEqual(cdist_type.optional_parameters, ['optional1', 'optional2']) - - def test_without_optional_parameters(self): - base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__without_optional_parameters') - self.assertEqual(cdist_type.optional_parameters, []) - -''' -suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) - -def suite(): - tests = [] - return unittest.TestSuite(map(ObjectTestCase, tests)) -''' From 790deb464502d97c5e84fe37410cd081d22d4977 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 9 Oct 2011 12:49:57 +0200 Subject: [PATCH 0674/4212] in theory finish the install command Signed-off-by: Nico Schottelius --- lib/cdist/install.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/cdist/install.py b/lib/cdist/install.py index 87714fa8..0f06f5e7 100644 --- a/lib/cdist/install.py +++ b/lib/cdist/install.py @@ -20,14 +20,14 @@ # # -import logging - +import os import cdist.config_install -log = logging.getLogger(__name__) +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" -def install(args): - """Install remote system""" - process = {} - + super().__init__(*args, **kargs) From 48a9309522d4223c0ae8f91d6cfb08ac591e8086 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 9 Oct 2011 12:50:47 +0200 Subject: [PATCH 0675/4212] indent/+FIXME Signed-off-by: Nico Schottelius --- bin/cdist | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index c42e540c..61dad1db 100755 --- a/bin/cdist +++ b/bin/cdist @@ -114,11 +114,16 @@ def configinstall(args, mode): time_start = time.time() + # FIXME: do not overwrite, if set! os.environ['__remote_exec'] = "ssh -o User=root -q" os.environ['__remote_copy'] = "scp -o User=root -q" for host in args.host: - c = mode(host, initial_manifest=args.manifest, base_path=args.cdist_home, debug=args.debug) + c = mode(host, + initial_manifest=args.manifest, + base_path=args.cdist_home, + debug=args.debug, + parallel=True) if args.parallel: log.debug("Creating child process for %s", host) process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) From e27cd9e809d8d7c711662c6f9020f3e6c6ea9a15 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 09:23:27 +0200 Subject: [PATCH 0676/4212] when comparing objects, define equality as 'attributes are the same' Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 12d16838..b6bdeee3 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -80,6 +80,10 @@ class Object(object): def __repr__(self): return '' % self.name + def __eq__(self, other): + """define equality as 'attributes are the same'""" + return self.__dict__ == other.__dict__ + @property def explorer_path(self): # create absolute path From 7c12027311c4483de05bc0c583890382f7517536 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 09:30:28 +0200 Subject: [PATCH 0677/4212] test and fixtures for Object class/static methods Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 61 +++++++++++++++++++ .../test/object/fixtures/object/__first/.keep | 0 .../fixtures/object/__first/man/.cdist/.keep | 0 .../object/fixtures/object/__second/.keep | 0 .../object/__second/on-the/.cdist/.keep | 0 .../test/object/fixtures/object/__third/.keep | 0 .../fixtures/object/__third/moon/.cdist/.keep | 0 .../test/object/fixtures/type/__first/.keep | 0 .../test/object/fixtures/type/__second/.keep | 0 .../test/object/fixtures/type/__third/.keep | 0 lib/cdist/test/test_object.py | 46 -------------- 11 files changed, 61 insertions(+), 46 deletions(-) create mode 100644 lib/cdist/test/object/__init__.py create mode 100644 lib/cdist/test/object/fixtures/object/__first/.keep create mode 100644 lib/cdist/test/object/fixtures/object/__first/man/.cdist/.keep create mode 100644 lib/cdist/test/object/fixtures/object/__second/.keep create mode 100644 lib/cdist/test/object/fixtures/object/__second/on-the/.cdist/.keep create mode 100644 lib/cdist/test/object/fixtures/object/__third/.keep create mode 100644 lib/cdist/test/object/fixtures/object/__third/moon/.cdist/.keep create mode 100644 lib/cdist/test/object/fixtures/type/__first/.keep create mode 100644 lib/cdist/test/object/fixtures/type/__second/.keep create mode 100644 lib/cdist/test/object/fixtures/type/__third/.keep delete mode 100644 lib/cdist/test/test_object.py diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py new file mode 100644 index 00000000..3d04a7a3 --- /dev/null +++ b/lib/cdist/test/object/__init__.py @@ -0,0 +1,61 @@ +# -*- 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 tempfile +import unittest +import shutil + +import cdist.core + +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 ObjectClassTestCase(unittest.TestCase): + + def test_list_object_names(self): + object_names = list(cdist.core.Object.list_object_names(object_base_path)) + self.assertEqual(object_names, ['__first/man', '__second/on-the', '__third/moon']) + + def test_list_type_names(self): + type_names = list(cdist.core.Object.list_type_names(object_base_path)) + self.assertEqual(type_names, ['__first', '__second', '__third']) + + def test_list_objects(self): + objects = list(cdist.core.Object.list_objects(object_base_path, type_base_path)) + objects_expected = [ + cdist.core.Object(cdist.core.Type(type_base_path, '__first'), object_base_path, 'man'), + cdist.core.Object(cdist.core.Type(type_base_path, '__second'), object_base_path, 'on-the'), + cdist.core.Object(cdist.core.Type(type_base_path, '__third'), object_base_path, 'moon'), + ] + self.assertEqual(objects, objects_expected) + + +''' +suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) + +def suite(): + tests = [] + return unittest.TestSuite(map(ObjectTestCase, tests)) +''' diff --git a/lib/cdist/test/object/fixtures/object/__first/.keep b/lib/cdist/test/object/fixtures/object/__first/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/object/fixtures/object/__first/man/.cdist/.keep b/lib/cdist/test/object/fixtures/object/__first/man/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/object/fixtures/object/__second/.keep b/lib/cdist/test/object/fixtures/object/__second/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/object/fixtures/object/__second/on-the/.cdist/.keep b/lib/cdist/test/object/fixtures/object/__second/on-the/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/object/fixtures/object/__third/.keep b/lib/cdist/test/object/fixtures/object/__third/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/.keep b/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/object/fixtures/type/__first/.keep b/lib/cdist/test/object/fixtures/type/__first/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/object/fixtures/type/__second/.keep b/lib/cdist/test/object/fixtures/type/__second/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/object/fixtures/type/__third/.keep b/lib/cdist/test/object/fixtures/type/__third/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/test_object.py b/lib/cdist/test/test_object.py deleted file mode 100644 index ae584840..00000000 --- a/lib/cdist/test/test_object.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- 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 tempfile -import unittest -import shutil - -import os.path as op -my_dir = op.abspath(op.dirname(__file__)) -base_path = op.join(my_dir, 'fixtures') - -class ObjectTestCase(unittest.TestCase): - def setUp(self): - # FIXME: use defined set of types for testing? - # FIXME: generate object tree or use predefined? - self.object_base_dir = tempfile.mkdtemp() - - def tearDown(self): - shutil.rmtree(self.temp_dir) - -''' -suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) - -def suite(): - tests = [] - return unittest.TestSuite(map(ObjectTestCase, tests)) -''' From f3b942e591423c09e71e92af32887d6782f3d5ee Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 09:34:16 +0200 Subject: [PATCH 0678/4212] test for Object paths Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 3d04a7a3..c1685c58 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -52,10 +52,28 @@ class ObjectClassTestCase(unittest.TestCase): self.assertEqual(objects, objects_expected) -''' -suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) +class ObjectTestCase(unittest.TestCase): -def suite(): - tests = [] - return unittest.TestSuite(map(ObjectTestCase, tests)) -''' + def setUp(self): + self.cdist_type = cdist.core.Type(type_base_path, '__third') + self.cdist_object = cdist.core.Object(self.cdist_type, object_base_path, 'moon') + + def test_name(self): + self.assertEqual(self.cdist_object.name, '__third/moon') + + def test_path(self): + self.assertEqual(self.cdist_object.path, '__third/moon/.cdist') + + def test_absolute_path(self): + self.assertEqual(self.cdist_object.absolute_path, os.path.join(object_base_path, '__third/moon/.cdist')) + + def test_code_local_path(self): + self.assertEqual(self.cdist_object.code_local_path, '__third/moon/.cdist/code-local') + + def test_code_remote_path(self): + self.assertEqual(self.cdist_object.code_remote_path, '__third/moon/.cdist/code-remote') + + def test_parameter_path(self): + self.assertEqual(self.cdist_object.parameter_path, '__third/moon/.cdist/parameter') + +#suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) From 8384176080156f3fb6b3087eb5e26b177827c963 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 09:36:48 +0200 Subject: [PATCH 0679/4212] test Object explorer_path Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 3 +++ .../object/fixtures/object/__third/moon/.cdist/explorer/.keep | 0 2 files changed, 3 insertions(+) create mode 100644 lib/cdist/test/object/fixtures/object/__third/moon/.cdist/explorer/.keep diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index c1685c58..55af5bf9 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -76,4 +76,7 @@ class ObjectTestCase(unittest.TestCase): def test_parameter_path(self): self.assertEqual(self.cdist_object.parameter_path, '__third/moon/.cdist/parameter') + def test_explorer_path(self): + self.assertEqual(self.cdist_object.explorer_path, '__third/moon/.cdist/explorer') + #suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) diff --git a/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/explorer/.keep b/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/explorer/.keep new file mode 100644 index 00000000..e69de29b From 88a1e34f3004defd6020f753c9ecec9669302d96 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 09:44:29 +0200 Subject: [PATCH 0680/4212] test for Object object_id Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 55af5bf9..cd6e7f04 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -61,6 +61,9 @@ class ObjectTestCase(unittest.TestCase): def test_name(self): self.assertEqual(self.cdist_object.name, '__third/moon') + def test_object_id(self): + self.assertEqual(self.cdist_object.object_id, 'moon') + def test_path(self): self.assertEqual(self.cdist_object.path, '__third/moon/.cdist') From abf318ae90b827b2fc99555b386c8321a38e0cc0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 09:47:06 +0200 Subject: [PATCH 0681/4212] test and fixtures for Object parameters Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 4 ++++ .../object/fixtures/object/__third/moon/.cdist/parameter/name | 1 + .../fixtures/object/__third/moon/.cdist/parameter/planet | 1 + 3 files changed, 6 insertions(+) create mode 100644 lib/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name create mode 100644 lib/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index cd6e7f04..a9edfdd0 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -82,4 +82,8 @@ class ObjectTestCase(unittest.TestCase): def test_explorer_path(self): self.assertEqual(self.cdist_object.explorer_path, '__third/moon/.cdist/explorer') + def test_parameters(self): + expected_parameters = {'planet': 'Saturn', 'name': 'Prometheus'} + self.assertEqual(self.cdist_object.parameters, expected_parameters) + #suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) diff --git a/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name b/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name new file mode 100644 index 00000000..4129a761 --- /dev/null +++ b/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name @@ -0,0 +1 @@ +Prometheus diff --git a/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet b/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet new file mode 100644 index 00000000..8e6ee422 --- /dev/null +++ b/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet @@ -0,0 +1 @@ +Saturn From 96ca5b6988f249b8320c977d3242846b2e1f0519 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 09:48:19 +0200 Subject: [PATCH 0682/4212] bugfix: use absolute path to when accessing file sytem (unittest discoverd :-) Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index b6bdeee3..96c6076a 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -114,7 +114,7 @@ class Object(object): @property def parameters(self): if not self.__parameters: - self.__parameters = cdist.core.property.DirectoryDict(os.path.join(self.path, "parameter")) + self.__parameters = cdist.core.property.DirectoryDict(os.path.join(self.absolute_path, "parameter")) return self.__parameters @parameters.setter @@ -122,7 +122,7 @@ class Object(object): if isinstance(value, cdist.core.property.DirectoryDict): self.__parameters = value else: - self.__parameters = cdist.core.property.DirectoryDict(os.path.join(self.path, "parameter"), value) + self.__parameters = cdist.core.property.DirectoryDict(os.path.join(self.absolute_path, "parameter"), value) ### /parameters From 0ba6d551919090d079ef6667e1f228be0b79c358 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 09:57:56 +0200 Subject: [PATCH 0683/4212] raise exception when given a relative path Signed-off-by: Steven Armstrong --- lib/cdist/core/property.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/cdist/core/property.py b/lib/cdist/core/property.py index 30887547..e63cadcf 100644 --- a/lib/cdist/core/property.py +++ b/lib/cdist/core/property.py @@ -25,11 +25,21 @@ import collections import cdist +class AbsolutePathRequiredError(cdist.Error): + def __init__(self, path): + self.path = path + + def __str__(self): + return 'Absolute path required, got: %s' % self.path + + class FileList(collections.MutableSequence): """A list that stores it's state in a file. """ def __init__(self, path, initial=None): + if not os.path.isabs(path): + raise AbsolutePathRequiredError(path) self._path = path if initial: # delete existing file @@ -108,6 +118,8 @@ class DirectoryDict(collections.MutableMapping): """ def __init__(self, path, dict=None, **kwargs): + if not os.path.isabs(path): + raise AbsolutePathRequiredError(path) self._path = path if dict is not None: self.update(dict) From b1efc27b39b02ae43cd43156ad82e8a61022023c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 10:00:42 +0200 Subject: [PATCH 0684/4212] test for Object requirements Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index a9edfdd0..910a75e1 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -86,4 +86,8 @@ class ObjectTestCase(unittest.TestCase): expected_parameters = {'planet': 'Saturn', 'name': 'Prometheus'} self.assertEqual(self.cdist_object.parameters, expected_parameters) + def test_requirements(self): + expected = [] + self.assertEqual(list(self.cdist_object.requirements), expected) + #suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) From 86f976976ec5743fa1dfee2dcc5b67f11a3b1066 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 10:01:28 +0200 Subject: [PATCH 0685/4212] bugfix: use absolute path when accessing file system Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 96c6076a..76e8faa1 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -98,7 +98,7 @@ class Object(object): @property def requirements(self): if not self.__requirements: - self.__requirements = cdist.core.property.FileList(os.path.join(self.path, "require")) + self.__requirements = cdist.core.property.FileList(os.path.join(self.absolute_path, "require")) return self.__requirements @requirements.setter @@ -106,7 +106,7 @@ class Object(object): if isinstance(value, cdist.core.property.FileList): self.__requirements = value else: - self.__requirements = cdist.core.property.FileList(os.path.join(self.path, "require"), value) + self.__requirements = cdist.core.property.FileList(os.path.join(self.absolute_path, "require"), value) ### /requirements From f2701cb5124d513b9c80fb45ef3ab527ade4a9e5 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 10:04:36 +0200 Subject: [PATCH 0686/4212] test for Object changed Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 910a75e1..a85e8df9 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -58,6 +58,9 @@ class ObjectTestCase(unittest.TestCase): self.cdist_type = cdist.core.Type(type_base_path, '__third') self.cdist_object = cdist.core.Object(self.cdist_type, object_base_path, 'moon') + def tearDown(self): + self.cdist_object.changed = False + def test_name(self): self.assertEqual(self.cdist_object.name, '__third/moon') @@ -90,4 +93,11 @@ class ObjectTestCase(unittest.TestCase): 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) + #suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) From 7855a485b627100886275e9446e2257b4c12f054 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 10:05:46 +0200 Subject: [PATCH 0687/4212] test for Object prepared Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index a85e8df9..c490bdc3 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -60,6 +60,7 @@ class ObjectTestCase(unittest.TestCase): def tearDown(self): self.cdist_object.changed = False + self.cdist_object.prepared = False def test_name(self): self.assertEqual(self.cdist_object.name, '__third/moon') @@ -100,4 +101,10 @@ class ObjectTestCase(unittest.TestCase): self.cdist_object.changed = True self.assertTrue(self.cdist_object.changed) + def test_prepared(self): + self.assertFalse(self.cdist_object.prepared) + + def test_prepared_after_changing(self): + self.cdist_object.prepared = True + self.assertTrue(self.cdist_object.prepared) #suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) From 6de7bd3377d060d108df07fcabe1506d66666232 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 10:06:41 +0200 Subject: [PATCH 0688/4212] test for Object ran Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index c490bdc3..75322654 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -61,6 +61,7 @@ class ObjectTestCase(unittest.TestCase): def tearDown(self): self.cdist_object.changed = False self.cdist_object.prepared = False + self.cdist_object.ran = False def test_name(self): self.assertEqual(self.cdist_object.name, '__third/moon') @@ -107,4 +108,10 @@ class ObjectTestCase(unittest.TestCase): def test_prepared_after_changing(self): self.cdist_object.prepared = True self.assertTrue(self.cdist_object.prepared) -#suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) + + def test_ran(self): + self.assertFalse(self.cdist_object.ran) + + def test_ran_after_changing(self): + self.cdist_object.ran = True + self.assertTrue(self.cdist_object.ran) From 7823d0c9977aaabf695e38687106d515819fb988 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 10 Oct 2011 11:31:37 +0200 Subject: [PATCH 0689/4212] merge context back into config (it is in fact the same idea) Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 192 ++++++++++++++++++++++++++---------- lib/cdist/context.py | 137 ------------------------- 2 files changed, 139 insertions(+), 190 deletions(-) delete mode 100644 lib/cdist/context.py diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index e4b51ad4..0da820b2 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -24,10 +24,11 @@ import logging import os import stat import sys +import tempfile import time -import cdist.context import cdist.core +import cdist.exec import cdist.emulator log = logging.getLogger(__name__) @@ -37,44 +38,115 @@ CODE_HEADER = "#!/bin/sh -e\n" class ConfigInstall: """Cdist main class to hold arbitrary data""" - def __init__(self, target_host, initial_manifest=False, - base_path=False, - exec_path=sys.argv[0], - debug=False): + def __init__(self, target_host, + initial_manifest=False, base_path=False, debug=False): self.target_host = target_host - os.environ['target_host'] = target_host self.debug = debug - self.exec_path = exec_path + self.exec_path = sys.argv[0] - self.context = cdist.context.Context(self.target_host, - initial_manifest=initial_manifest, - base_path=base_path, - debug=debug) + # Base and Temp Base + if base_path: + self.base_path = base_path + else: + self.base_path = os.path.abspath( + os.path.join(os.path.dirname(__file__), + os.pardir, + os.pardir)) + + + # Local input + self.cache_path = os.path.join(self.base_path, "cache", + self.target_host) + self.conf_path = os.path.join(self.base_path, "conf") + + self.global_explorer_path = os.path.join(self.conf_path, "explorer") + self.manifest_path = os.path.join(self.conf_path, "manifest") + self.type_base_path = os.path.join(self.conf_path, "type") + self.lib_path = os.path.join(self.base_path, "lib") + + if initial_manifest: + self.initial_manifest = initial_manifest + else: + self.initial_manifest = os.path.join(self.manifest_path, "init") + + # Local output + if '__cdist_out_dir' in os.environ: + self.out_path = os.environ['__cdist_out_dir'] + else: + self.out_path = os.path.join(tempfile.mkdtemp(), "out") + self.bin_path = os.path.join(self.out_path, "bin") + self.global_explorer_out_path = os.path.join(self.out_path, "explorer") + self.object_base_path = os.path.join(self.out_path, "object") + + # Remote directory base + if '__cdist_remote_out_dir' in os.environ: + self.remote_base_path = os.environ['__cdist_remote_out_dir'] + else: + self.remote_base_path = "/var/lib/cdist" + self.remote_conf_path = os.path.join(self.remote_base_path, "conf") + self.remote_object_path = os.path.join(self.remote_base_path, "object") + + self.remote_type_path = os.path.join(self.remote_conf_path, "type") + self.remote_global_explorer_path = os.path.join(self.remote_conf_path, "explorer") + + # Create directories + self.__init_local_paths() + self.__init_remote_paths() + + + def __init_remote_paths(self): + """Initialise remote directory structure""" + self.remove_remote_path(self.remote_base_path) + self.remote_mkdir(self.remote_base_path) + self.remote_mkdir(self.remote_conf_path) + + def __init_local_paths(self): + """Initialise local directory structure""" + + # Create base dir, if user supplied and not existing + if not os.path.isdir(self.base_path): + os.mkdir(self.base_path) + + os.mkdir(self.out_path) + os.mkdir(self.global_explorer_out_path) + os.mkdir(self.bin_path) def cleanup(self): - self.context.cleanup() + # Do not use in __del__: + # http://docs.python.org/reference/datamodel.html#customization + # "other globals referenced by the __del__() method may already have been deleted + # or in the process of being torn down (e.g. the import machinery shutting down)" + # + log.debug("Saving " + self.out_path + " to " + self.cache_path) + # Remove previous cache + if os.path.exists(self.cache_path): + shutil.rmtree(self.cache_path) + shutil.move(self.out_path, self.cache_path) + + def logfilter(self): + """Add hostname to logs""" def run_initial_manifest(self): """Run the initial manifest""" - log.info("Running initial manifest %s", self.context.initial_manifest) - env = { "__manifest" : self.context.manifest_path } - self.run_manifest(self.context.initial_manifest, extra_env=env) + log.info("Running initial manifest %s", self.initial_manifest) + env = { "__manifest" : self.manifest_path } + self.run_manifest(self.initial_manifest, extra_env=env) def run_type_manifest(self, cdist_object): """Run manifest for a specific object""" cdist_type = cdist_object.type - manifest_path = os.path.join(self.context.type_base_path, + manifest_path = os.path.join(self.type_base_path, cdist_type.manifest_path) log.debug("%s: Running %s", cdist_object.name, manifest_path) if os.path.exists(manifest_path): - env = { "__object" : os.path.join(self.context.object_base_path, + env = { "__object" : os.path.join(self.object_base_path, cdist_object.path), "__object_id": cdist_object.object_id, "__object_fq": cdist_object.name, - "__type": os.path.join(self.context.type_base_path, + "__type": os.path.join(self.type_base_path, cdist_type.path) } self.run_manifest(manifest_path, extra_env=env) @@ -83,11 +155,11 @@ class ConfigInstall: """Run a manifest""" log.debug("Running manifest %s, env=%s", manifest_path, extra_env) env = os.environ.copy() - env['PATH'] = self.context.bin_path + ":" + env['PATH'] + env['PATH'] = self.bin_path + ":" + env['PATH'] # Information required in every manifest env['__target_host'] = self.target_host - env['__global'] = self.context.out_path + env['__global'] = self.out_path # Submit debug flag to manifest, can be used by emulator and types if self.debug: @@ -97,7 +169,7 @@ class ConfigInstall: env['__cdist_manifest'] = manifest_path # Required to find types in emulator - env['__cdist_type_base_path'] = self.context.type_base_path + env['__cdist_type_base_path'] = self.type_base_path # Other environment stuff if extra_env: @@ -124,19 +196,19 @@ class ConfigInstall: # env = os.environ.copy() env['__target_host'] = self.target_host - env['__global'] = self.context.out_path - env["__object"] = os.path.join(self.context.object_base_path, cdist_object.path) + env['__global'] = self.out_path + env["__object"] = os.path.join(self.object_base_path, cdist_object.path) env["__object_id"] = cdist_object.object_id env["__object_fq"] = cdist_object.name env["__type"] = cdist_type.name # gencode for cmd in ["local", "remote"]: - bin = os.path.join(self.context.type_base_path, + bin = os.path.join(self.type_base_path, getattr(cdist_type, "gencode_" + cmd + "_path")) if os.path.isfile(bin): - outfile = os.path.join(self.context.object_base_path, + outfile = os.path.join(self.object_base_path, getattr(cdist_object, "code_" + cmd + "_path")) outfile_fd = open(outfile, "w") @@ -164,12 +236,12 @@ class ConfigInstall: cdist.exec.run_or_fail([code_local]) # code remote - local_remote_code = os.path.join(self.context.object_base_path, + local_remote_code = os.path.join(self.object_base_path, cdist_object.code_remote_path) - remote_remote_code = os.path.join(self.context.remote_object_path, + remote_remote_code = os.path.join(self.remote_object_path, cdist_object.code_remote_path) if os.path.isfile(local_remote_code): - self.context.transfer_path(local_remote_code, remote_remote_code) + self.transfer_path(local_remote_code, remote_remote_code) cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) cdist_object.ran = True @@ -181,12 +253,12 @@ class ConfigInstall: self.transfer_type_explorers(cdist_type) cmd = [] - cmd.append("__explorer=" + self.context.remote_global_explorer_path) + cmd.append("__explorer=" + self.remote_global_explorer_path) cmd.append("__type_explorer=" + os.path.join( - self.context.remote_type_path, + self.remote_type_path, cdist_type.explorer_path)) cmd.append("__object=" + os.path.join( - self.context.remote_object_path, + self.remote_object_path, cdist_object.path)) cmd.append("__object_id=" + cdist_object.object_id) cmd.append("__object_fq=" + cdist_object.name) @@ -195,9 +267,9 @@ class ConfigInstall: self.transfer_object_parameter(cdist_object) for explorer in cdist_type.explorers: - remote_cmd = cmd + [os.path.join(self.context.remote_base_path, + remote_cmd = cmd + [os.path.join(self.remote_base_path, cdist_type.explorer_path, explorer)] - output = os.path.join(self.context.object_base_path, + output = os.path.join(self.object_base_path, cdist_object.explorer_path, explorer) output_fd = open(output, mode='w') log.debug("%s exploring %s using %s storing to %s", @@ -210,8 +282,8 @@ class ConfigInstall: def link_emulator(self): """Link emulator to types""" src = os.path.abspath(self.exec_path) - for cdist_type in cdist.core.Type.list_types(self.context.type_base_path): - dst = os.path.join(self.context.bin_path, cdist_type.name) + for cdist_type in cdist.core.Type.list_types(self.type_base_path): + dst = os.path.join(self.bin_path, cdist_type.name) log.debug("Linking emulator: %s to %s", src, dst) # FIXME: handle exception / make it more beautiful @@ -221,11 +293,11 @@ class ConfigInstall: """Run global explorers""" log.info("Running global explorers") - src_path = self.context.global_explorer_path - dst_path = self.context.global_explorer_out_path - remote_dst_path = self.context.remote_global_explorer_path + src_path = self.global_explorer_path + dst_path = self.global_explorer_out_path + remote_dst_path = self.remote_global_explorer_path - self.context.transfer_path(src_path, remote_dst_path) + self.transfer_path(src_path, remote_dst_path) for explorer in os.listdir(src_path): output_fd = open(os.path.join(dst_path, explorer), mode='w') @@ -240,8 +312,8 @@ class ConfigInstall: def stage_run(self): """The final (and real) step of deployment""" log.info("Generating and executing code") - for cdist_object in cdist.core.Object.list_objects(self.context.object_base_path, - self.context.type_base_path): + for cdist_object in cdist.core.Object.list_objects(self.object_base_path, + self.type_base_path): log.debug("Run object: %s", cdist_object) self.object_run(cdist_object) @@ -271,8 +343,8 @@ class ConfigInstall: new_objects_created = True while new_objects_created: new_objects_created = False - for cdist_object in cdist.core.Object.list_objects(self.context.object_base_path, - self.context.type_base_path): + for cdist_object in cdist.core.Object.list_objects(self.object_base_path, + self.type_base_path): if cdist_object.prepared: log.debug("Skipping rerun of object %s", cdist_object) continue @@ -285,19 +357,19 @@ class ConfigInstall: def transfer_object_parameter(self, cdist_object): """Transfer the object parameter to the remote destination""" - src = os.path.join(self.context.object_base_path, + src = os.path.join(self.object_base_path, cdist_object.parameter_path) - dst = os.path.join(self.context.remote_object_path, + dst = os.path.join(self.remote_object_path, cdist_object.parameter_path) # Synchronise parameter dir afterwards - self.context.remote_mkdir(dst) - self.context.transfer_path(src, dst) + self.remote_mkdir(dst) + self.transfer_path(src, dst) def transfer_global_explorers(self): """Transfer the global explorers""" - self.remote_mkdir(self.context.remote_global_explorer_path) - self.transfer_path(self.context.global_explorer_path, + self.remote_mkdir(self.remote_global_explorer_path) + self.transfer_path(self.global_explorer_path, self.remote_global_explorer_path) def transfer_type_explorers(self, cdist_type): @@ -313,13 +385,27 @@ class ConfigInstall: if len(explorers) > 0: rel_path = cdist_type.explorer_path - src = os.path.join(self.context.type_base_path, rel_path) - dst = os.path.join(self.context.remote_type_path, rel_path) + src = os.path.join(self.type_base_path, rel_path) + dst = os.path.join(self.remote_type_path, rel_path) # Ensure full path until type exists: # /var/lib/cdist/conf/type/__directory/explorer # /var/lib/cdist/conf/type/__directory may not exist, # but remote_mkdir uses -p to fix this - self.context.remote_mkdir(dst) - self.context.transfer_path(src, dst) + self.remote_mkdir(dst) + self.transfer_path(src, dst) + + def remote_mkdir(self, directory): + """Create directory on remote side""" + cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) + + def remove_remote_path(self, destination): + """Ensure path on remote side vanished""" + cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) + + def transfer_path(self, source, destination): + """Transfer directory and previously delete the remote destination""" + self.remove_remote_path(destination) + cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + + ["-r", source, self.target_host + ":" + destination]) diff --git a/lib/cdist/context.py b/lib/cdist/context.py deleted file mode 100644 index a4fdbca5..00000000 --- a/lib/cdist/context.py +++ /dev/null @@ -1,137 +0,0 @@ -# -*- 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 logging -import os -import shutil -import sys -import tempfile - - -log = logging.getLogger(__name__) - -import cdist.exec - -class Context: - """Storing context information""" - - def __init__(self, - target_host, - initial_manifest=False, - base_path=False, - out_path=False, - remote_base_path=False, - debug=False): - - self.target_host = target_host - - # Base and Temp Base - if base_path: - self.base_path = base_path - else: - self.base_path = os.path.abspath( - os.path.join(os.path.dirname(__file__), - os.pardir, - os.pardir)) - - - # Local input directories - self.cache_path = os.path.join(self.base_path, "cache", target_host) - self.conf_path = os.path.join(self.base_path, "conf") - - self.global_explorer_path = os.path.join(self.conf_path, "explorer") - self.manifest_path = os.path.join(self.conf_path, "manifest") - self.type_base_path = os.path.join(self.conf_path, "type") - self.lib_path = os.path.join(self.base_path, "lib") - - if initial_manifest: - self.initial_manifest = initial_manifest - else: - self.initial_manifest = os.path.join(self.manifest_path, "init") - - # Local output directories - if out_path: - self.out_path = out_path - else: - self.out_path = os.path.join(tempfile.mkdtemp(), "out") - - self.bin_path = os.path.join(self.out_path, "bin") - self.global_explorer_out_path = os.path.join(self.out_path, "explorer") - self.object_base_path = os.path.join(self.out_path, "object") - - # Remote directories - if remote_base_path: - self.remote_base_path = remote_base_path - else: - self.remote_base_path = "/var/lib/cdist" - - self.remote_conf_path = os.path.join(self.remote_base_path, "conf") - self.remote_object_path = os.path.join(self.remote_base_path, "object") - - self.remote_type_path = os.path.join(self.remote_conf_path, "type") - self.remote_global_explorer_path = os.path.join(self.remote_conf_path, "explorer") - - # Create directories - self.__init_out_paths() - self.__init_remote_paths() - - def cleanup(self): - # Do not use in __del__: - # http://docs.python.org/reference/datamodel.html#customization - # "other globals referenced by the __del__() method may already have been deleted - # or in the process of being torn down (e.g. the import machinery shutting down)" - # - log.debug("Saving " + self.out_path + " to " + self.cache_path) - # Remove previous cache - if os.path.exists(self.cache_path): - shutil.rmtree(self.cache_path) - shutil.move(self.out_path, self.cache_path) - - def __init_out_paths(self): - """Initialise output directory structure""" - - # Create base dir, if user supplied and not existing - if not os.path.isdir(self.base_path): - os.mkdir(self.base_path) - - os.mkdir(self.out_path) - os.mkdir(self.global_explorer_out_path) - os.mkdir(self.bin_path) - - def __init_remote_paths(self): - """Initialise remote directory structure""" - - self.remove_remote_path(self.remote_base_path) - self.remote_mkdir(self.remote_base_path) - self.remote_mkdir(self.remote_conf_path) - - def remote_mkdir(self, directory): - """Create directory on remote side""" - cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) - - def remove_remote_path(self, destination): - cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) - - def transfer_path(self, source, destination): - """Transfer directory and previously delete the remote destination""" - self.remove_remote_path(destination) - cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + - ["-r", source, self.target_host + ":" + destination]) From 44a722042a4e321c38ac50b0b796a4fa494f09e4 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 14:37:33 +0200 Subject: [PATCH 0690/4212] new class for using filesystem as backend for boolean properties Signed-off-by: Steven Armstrong --- lib/cdist/core/property.py | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/lib/cdist/core/property.py b/lib/cdist/core/property.py index e63cadcf..11dddcf3 100644 --- a/lib/cdist/core/property.py +++ b/lib/cdist/core/property.py @@ -165,3 +165,50 @@ class DirectoryDictProperty(DirectoryDict): def __delete__(self, obj): raise AttributeError("can't delete attribute") + + +class FileBooleanProperty(object): + def __init__(self, path): + """ + :param path: string or callable + + Usage: + + class Foo(object): + changed = FileBoolean(lambda obj: os.path.join(obj.absolute_path, 'changed')) + other_boolean = FileBoolean('/tmp/other_boolean') + + def __init__(self): + self.absolute_path = '/tmp/foo_boolean' + + """ + self._path = path + + def _get_path(self, *args, **kwargs): + path = self._path + if callable(path): + return path(*args, **kwargs) + if not os.path.isabs(path): + raise AbsolutePathRequiredError(path) + return path + + # Descriptor Protocol + def __get__(self, obj, objtype=None): + if obj is None: + return self.__class__ + path = self._get_path(obj) + return os.path.isfile(path) + + def __set__(self, obj, value): + path = self._get_path(obj) + if value: + open(path, "w").close() + else: + try: + os.remove(path) + except EnvironmentError: + # ignore + pass + + def __delete__(self, obj): + raise AttributeError("can't delete attribute") From f3932bb662bb73c970ba59b74aaba9bde182237d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 14:54:26 +0200 Subject: [PATCH 0691/4212] move file based properties out of core Signed-off-by: Steven Armstrong --- lib/cdist/util/property.py | 214 +++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 lib/cdist/util/property.py diff --git a/lib/cdist/util/property.py b/lib/cdist/util/property.py new file mode 100644 index 00000000..11dddcf3 --- /dev/null +++ b/lib/cdist/util/property.py @@ -0,0 +1,214 @@ +# -*- 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 collections + +import cdist + + +class AbsolutePathRequiredError(cdist.Error): + def __init__(self, path): + self.path = path + + def __str__(self): + return 'Absolute path required, got: %s' % self.path + + +class FileList(collections.MutableSequence): + """A list that stores it's state in a file. + + """ + def __init__(self, path, initial=None): + if not os.path.isabs(path): + raise AbsolutePathRequiredError(path) + self._path = path + if initial: + # delete existing file + os.unlink(self._path) + for i in initial: + self.append(i) + + def __read(self): + lines = [] + try: + with open(self._path) as fd: + for line in fd: + lines.append(line.rstrip('\n')) + except EnvironmentError as e: + # error ignored + pass + return lines + + def __write(self, lines): + try: + with open(self._path, 'w') as fd: + for line in lines: + fd.write(str(line) + '\n') + except EnvironmentError as e: + # error ignored + raise + + def __repr__(self): + return repr(list(self)) + + def __getitem__(self, index): + return self.__read()[index] + + def __setitem__(self, index, value): + lines = self.__read() + lines[index] = value + self.__write(lines) + + def __delitem__(self, index): + lines = self.__read() + del lines[index] + self.__write(lines) + + def __len__(self): + lines = self.__read() + return len(lines) + + def insert(self, index, value): + lines = self.__read() + lines.insert(index, value) + self.__write(lines) + + def sort(self): + lines = sorted(self) + self.__write(lines) + + +class FileListProperty(FileList): + # Descriptor Protocol + def __get__(self, obj, objtype=None): + if obj is None: + return self.__class__ + return self + + def __set__(self, obj, value): + os.unlink(self._path) + for item in value: + self.append(item) + + def __delete__(self, obj): + raise AttributeError("can't delete attribute") + + +class DirectoryDict(collections.MutableMapping): + """A dict that stores it's state in a directory. + + """ + def __init__(self, path, dict=None, **kwargs): + if not os.path.isabs(path): + raise AbsolutePathRequiredError(path) + self._path = path + if dict is not None: + self.update(dict) + if len(kwargs): + self.update(kwargs) + + def __repr__(self): + return repr(dict(self)) + + def __getitem__(self, key): + try: + with open(os.path.join(self._path, key), "r") as fd: + return fd.read().rstrip('\n') + except EnvironmentError: + raise KeyError(key) + + def __setitem__(self, key, value): + with open(os.path.join(self._path, key), "w") as fd: + fd.write(str(value)) + + def __delitem__(self, key): + os.remove(os.path.join(self._path, key)) + + def __iter__(self): + return iter(os.listdir(self._path)) + + def __len__(self): + return len(os.listdir(self._path)) + + +class DirectoryDictProperty(DirectoryDict): + # Descriptor Protocol + def __get__(self, obj, objtype=None): + if obj is None: + return self.__class__ + return self + + def __set__(self, obj, value): + for name in self.keys(): + del self[name] + if value is not None: + self.update(value) + + def __delete__(self, obj): + raise AttributeError("can't delete attribute") + + +class FileBooleanProperty(object): + def __init__(self, path): + """ + :param path: string or callable + + Usage: + + class Foo(object): + changed = FileBoolean(lambda obj: os.path.join(obj.absolute_path, 'changed')) + other_boolean = FileBoolean('/tmp/other_boolean') + + def __init__(self): + self.absolute_path = '/tmp/foo_boolean' + + """ + self._path = path + + def _get_path(self, *args, **kwargs): + path = self._path + if callable(path): + return path(*args, **kwargs) + if not os.path.isabs(path): + raise AbsolutePathRequiredError(path) + return path + + # Descriptor Protocol + def __get__(self, obj, objtype=None): + if obj is None: + return self.__class__ + path = self._get_path(obj) + return os.path.isfile(path) + + def __set__(self, obj, value): + path = self._get_path(obj) + if value: + open(path, "w").close() + else: + try: + os.remove(path) + except EnvironmentError: + # ignore + pass + + def __delete__(self, obj): + raise AttributeError("can't delete attribute") From 4a3bc7284664c82b03f433ce100f02a1a932833d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 14:54:35 +0200 Subject: [PATCH 0692/4212] move file based properties out of core Signed-off-by: Steven Armstrong --- lib/cdist/core/property.py | 214 ------------------------------------- 1 file changed, 214 deletions(-) delete mode 100644 lib/cdist/core/property.py diff --git a/lib/cdist/core/property.py b/lib/cdist/core/property.py deleted file mode 100644 index 11dddcf3..00000000 --- a/lib/cdist/core/property.py +++ /dev/null @@ -1,214 +0,0 @@ -# -*- 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 collections - -import cdist - - -class AbsolutePathRequiredError(cdist.Error): - def __init__(self, path): - self.path = path - - def __str__(self): - return 'Absolute path required, got: %s' % self.path - - -class FileList(collections.MutableSequence): - """A list that stores it's state in a file. - - """ - def __init__(self, path, initial=None): - if not os.path.isabs(path): - raise AbsolutePathRequiredError(path) - self._path = path - if initial: - # delete existing file - os.unlink(self._path) - for i in initial: - self.append(i) - - def __read(self): - lines = [] - try: - with open(self._path) as fd: - for line in fd: - lines.append(line.rstrip('\n')) - except EnvironmentError as e: - # error ignored - pass - return lines - - def __write(self, lines): - try: - with open(self._path, 'w') as fd: - for line in lines: - fd.write(str(line) + '\n') - except EnvironmentError as e: - # error ignored - raise - - def __repr__(self): - return repr(list(self)) - - def __getitem__(self, index): - return self.__read()[index] - - def __setitem__(self, index, value): - lines = self.__read() - lines[index] = value - self.__write(lines) - - def __delitem__(self, index): - lines = self.__read() - del lines[index] - self.__write(lines) - - def __len__(self): - lines = self.__read() - return len(lines) - - def insert(self, index, value): - lines = self.__read() - lines.insert(index, value) - self.__write(lines) - - def sort(self): - lines = sorted(self) - self.__write(lines) - - -class FileListProperty(FileList): - # Descriptor Protocol - def __get__(self, obj, objtype=None): - if obj is None: - return self.__class__ - return self - - def __set__(self, obj, value): - os.unlink(self._path) - for item in value: - self.append(item) - - def __delete__(self, obj): - raise AttributeError("can't delete attribute") - - -class DirectoryDict(collections.MutableMapping): - """A dict that stores it's state in a directory. - - """ - def __init__(self, path, dict=None, **kwargs): - if not os.path.isabs(path): - raise AbsolutePathRequiredError(path) - self._path = path - if dict is not None: - self.update(dict) - if len(kwargs): - self.update(kwargs) - - def __repr__(self): - return repr(dict(self)) - - def __getitem__(self, key): - try: - with open(os.path.join(self._path, key), "r") as fd: - return fd.read().rstrip('\n') - except EnvironmentError: - raise KeyError(key) - - def __setitem__(self, key, value): - with open(os.path.join(self._path, key), "w") as fd: - fd.write(str(value)) - - def __delitem__(self, key): - os.remove(os.path.join(self._path, key)) - - def __iter__(self): - return iter(os.listdir(self._path)) - - def __len__(self): - return len(os.listdir(self._path)) - - -class DirectoryDictProperty(DirectoryDict): - # Descriptor Protocol - def __get__(self, obj, objtype=None): - if obj is None: - return self.__class__ - return self - - def __set__(self, obj, value): - for name in self.keys(): - del self[name] - if value is not None: - self.update(value) - - def __delete__(self, obj): - raise AttributeError("can't delete attribute") - - -class FileBooleanProperty(object): - def __init__(self, path): - """ - :param path: string or callable - - Usage: - - class Foo(object): - changed = FileBoolean(lambda obj: os.path.join(obj.absolute_path, 'changed')) - other_boolean = FileBoolean('/tmp/other_boolean') - - def __init__(self): - self.absolute_path = '/tmp/foo_boolean' - - """ - self._path = path - - def _get_path(self, *args, **kwargs): - path = self._path - if callable(path): - return path(*args, **kwargs) - if not os.path.isabs(path): - raise AbsolutePathRequiredError(path) - return path - - # Descriptor Protocol - def __get__(self, obj, objtype=None): - if obj is None: - return self.__class__ - path = self._get_path(obj) - return os.path.isfile(path) - - def __set__(self, obj, value): - path = self._get_path(obj) - if value: - open(path, "w").close() - else: - try: - os.remove(path) - except EnvironmentError: - # ignore - pass - - def __delete__(self, obj): - raise AttributeError("can't delete attribute") From 09632373216f1f29a11e4743954044c90e82df4b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 14:54:50 +0200 Subject: [PATCH 0693/4212] new package cdist.util Signed-off-by: Steven Armstrong --- lib/cdist/util/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/cdist/util/__init__.py diff --git a/lib/cdist/util/__init__.py b/lib/cdist/util/__init__.py new file mode 100644 index 00000000..e69de29b From d2b042ab7fbaf15790533d0e74b58676961bd052 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 10 Oct 2011 15:14:48 +0200 Subject: [PATCH 0694/4212] remove parallel arg, always change logoutput Signed-off-by: Nico Schottelius --- bin/cdist | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 61dad1db..50e66697 100755 --- a/bin/cdist +++ b/bin/cdist @@ -122,8 +122,7 @@ def configinstall(args, mode): c = mode(host, initial_manifest=args.manifest, base_path=args.cdist_home, - debug=args.debug, - parallel=True) + debug=args.debug) if args.parallel: log.debug("Creating child process for %s", host) process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) From 9ce31fa84a9995641958b4b6570635289d5ae5f4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 10 Oct 2011 15:37:39 +0200 Subject: [PATCH 0695/4212] simplify test Signed-off-by: Nico Schottelius --- build.sh | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/build.sh b/build.sh index 63c380cf..0464defc 100755 --- a/build.sh +++ b/build.sh @@ -126,25 +126,15 @@ case "$1" in | xargs rm -f ;; - t) + test) shift # skip t + set -x + if [ $# -lt 1 ]; then + set -- cdist.test + fi PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib \ python3 -m unittest "$@" - ;; - - test) - PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib \ - python3 -m cdist.test - ;; - - test-install) - PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib \ - python3 -m unittest cdist.test.test_install - ;; - - test-all) - PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib \ - python3 -m unittest discover lib/cdist/test '*.py' + ;; *) From c81a2925b87d2654d4db7447900959cd8c31c609 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 10 Oct 2011 15:38:38 +0200 Subject: [PATCH 0696/4212] accept exec_path, setup__target_host Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 15 +++++++++++---- lib/cdist/exec.py | 4 ++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 0da820b2..6191b118 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -38,13 +38,21 @@ CODE_HEADER = "#!/bin/sh -e\n" class ConfigInstall: """Cdist main class to hold arbitrary data""" - def __init__(self, target_host, - initial_manifest=False, base_path=False, debug=False): + def __init__(self, + target_host, + initial_manifest=False, + base_path=False, + exec_path=sys.argv[0], + debug=False): self.target_host = target_host + # FIXME: should this be setup here? + os.environ['__target_host'] = self.target_host self.debug = debug - self.exec_path = sys.argv[0] + + # Required for testing + self.exec_path = exec_path # Base and Temp Base if base_path: @@ -55,7 +63,6 @@ class ConfigInstall: os.pardir, os.pardir)) - # Local input self.cache_path = os.path.join(self.base_path, "cache", self.target_host) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index a9b8d147..63a3dfa3 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -34,7 +34,7 @@ def shell_run_or_debug_fail(script, *args, remote_prefix=False, **kargs): if remote_prefix: remote_prefix = os.environ['__remote_exec'].split() - remote_prefix.append(os.environ['target_host']) + remote_prefix.append(os.environ['__target_host']) args[0][:0] = remote_prefix log.debug("Shell exec cmd: %s", args) @@ -65,7 +65,7 @@ def shell_run_or_debug_fail(script, *args, remote_prefix=False, **kargs): def run_or_fail(*args, remote_prefix=False, **kargs): if remote_prefix: remote_prefix = os.environ['__remote_exec'].split() - remote_prefix.append(os.environ['target_host']) + remote_prefix.append(os.environ['__target_host']) args[0][:0] = remote_prefix log.debug("Exec: " + " ".join(*args)) From a8fc8678340c8235953d55710c8f21c5803e0a57 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 10 Oct 2011 15:43:36 +0200 Subject: [PATCH 0697/4212] ++test integration Signed-off-by: Nico Schottelius --- lib/cdist/test/__init__.py | 3 --- lib/cdist/test/test_install.py | 12 +++++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/cdist/test/__init__.py b/lib/cdist/test/__init__.py index f614fa05..09429470 100644 --- a/lib/cdist/test/__init__.py +++ b/lib/cdist/test/__init__.py @@ -30,9 +30,6 @@ cdist_commands=["banner", "config", "install"] cdist_exec_path = os.path.abspath( os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../bin/cdist")) -def exec(): - print(cdist_exec_path) - #class UI(unittest.TestCase): # def test_banner(self): # self.assertEqual(subprocess.call([cdist_exec_path, "banner"]), 0) diff --git a/lib/cdist/test/test_install.py b/lib/cdist/test/test_install.py index 9cfae066..d6502b46 100644 --- a/lib/cdist/test/test_install.py +++ b/lib/cdist/test/test_install.py @@ -29,20 +29,22 @@ sys.path.insert(0, os.path.abspath( os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) import cdist.config - -cdist_exec_path = os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "bin/cdist")) - +import cdist.test class Install(unittest.TestCase): def setUp(self): self.temp_dir = tempfile.mkdtemp() self.init_manifest = os.path.join(self.temp_dir, "manifest") + + os.environ['__remote_exec'] = "ssh -o User=root -q" + os.environ['__remote_copy'] = "scp -o User=root -q" + self.config = cdist.config.Config("localhost", initial_manifest=self.init_manifest, - exec_path=cdist_exec_path) + exec_path=cdist.test.cdist_exec_path) self.config.link_emulator() + ### NEW FOR INSTALL ############################################################ def test_explorer_ran(self): From 915ec6d9adee3fd10eaa035075298d4dda1662e5 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 16:37:56 +0200 Subject: [PATCH 0698/4212] rename property module to fsproperty Signed-off-by: Steven Armstrong --- lib/cdist/util/{property.py => fsproperty.py} | 92 +++++++++++++++---- 1 file changed, 75 insertions(+), 17 deletions(-) rename lib/cdist/util/{property.py => fsproperty.py} (69%) diff --git a/lib/cdist/util/property.py b/lib/cdist/util/fsproperty.py similarity index 69% rename from lib/cdist/util/property.py rename to lib/cdist/util/fsproperty.py index 11dddcf3..1af2f0f5 100644 --- a/lib/cdist/util/property.py +++ b/lib/cdist/util/fsproperty.py @@ -40,17 +40,17 @@ class FileList(collections.MutableSequence): def __init__(self, path, initial=None): if not os.path.isabs(path): raise AbsolutePathRequiredError(path) - self._path = path + self.path = path if initial: # delete existing file - os.unlink(self._path) + os.unlink(self.path) for i in initial: self.append(i) def __read(self): lines = [] try: - with open(self._path) as fd: + with open(self.path) as fd: for line in fd: lines.append(line.rstrip('\n')) except EnvironmentError as e: @@ -60,7 +60,7 @@ class FileList(collections.MutableSequence): def __write(self, lines): try: - with open(self._path, 'w') as fd: + with open(self.path, 'w') as fd: for line in lines: fd.write(str(line) + '\n') except EnvironmentError as e: @@ -98,14 +98,43 @@ class FileList(collections.MutableSequence): class FileListProperty(FileList): + + def __init__(self, path): + """ + :param path: string or callable + + Usage: + + class Foo(object): + parameters = DirectoryDictProperty(lambda obj: os.path.join(obj.absolute_path, 'parameter')) + other_dict = DirectoryDictProperty('/tmp/folder') + + def __init__(self): + self.absolute_path = '/tmp/foo' + + """ + self.path = None + self.__path = path + + def _set_path(self, *args, **kwargs): + if self.path is None: + path = self.__path + if callable(path): + path = path(*args, **kwargs) + if not os.path.isabs(path): + raise AbsolutePathRequiredError(path) + self.path = path + # Descriptor Protocol def __get__(self, obj, objtype=None): if obj is None: return self.__class__ + self._set_path(obj) return self def __set__(self, obj, value): - os.unlink(self._path) + self._set_path(obj) + os.unlink(self.path) for item in value: self.append(item) @@ -117,13 +146,13 @@ class DirectoryDict(collections.MutableMapping): """A dict that stores it's state in a directory. """ - def __init__(self, path, dict=None, **kwargs): + def __init__(self, path, initial=None, **kwargs): if not os.path.isabs(path): raise AbsolutePathRequiredError(path) - self._path = path - if dict is not None: - self.update(dict) - if len(kwargs): + self.path = path + if initial is not None: + self.update(initial) + if kwargs: self.update(kwargs) def __repr__(self): @@ -131,36 +160,65 @@ class DirectoryDict(collections.MutableMapping): def __getitem__(self, key): try: - with open(os.path.join(self._path, key), "r") as fd: + with open(os.path.join(self.path, key), "r") as fd: return fd.read().rstrip('\n') except EnvironmentError: raise KeyError(key) def __setitem__(self, key, value): - with open(os.path.join(self._path, key), "w") as fd: + with open(os.path.join(self.path, key), "w") as fd: fd.write(str(value)) def __delitem__(self, key): - os.remove(os.path.join(self._path, key)) + os.remove(os.path.join(self.path, key)) def __iter__(self): - return iter(os.listdir(self._path)) + return iter(os.listdir(self.path)) def __len__(self): - return len(os.listdir(self._path)) + return len(os.listdir(self.path)) class DirectoryDictProperty(DirectoryDict): + + def __init__(self, path): + """ + :param path: string or callable + + Usage: + + class Foo(object): + parameters = DirectoryDictProperty(lambda obj: os.path.join(obj.absolute_path, 'parameter')) + other_dict = DirectoryDictProperty('/tmp/folder') + + def __init__(self): + self.absolute_path = '/tmp/foo' + + """ + self.path = None + self.__path = path + + def _set_path(self, *args, **kwargs): + if self.path is None: + path = self.__path + if callable(path): + path = path(*args, **kwargs) + if not os.path.isabs(path): + raise AbsolutePathRequiredError(path) + self.path = path + # Descriptor Protocol def __get__(self, obj, objtype=None): if obj is None: return self.__class__ + self._set_path(obj) return self def __set__(self, obj, value): - for name in self.keys(): - del self[name] + self._set_path(obj) if value is not None: + for name in self.keys(): + del self[name] self.update(value) def __delete__(self, obj): From bbcecc03ef035f6b0c18ca59720c0a9b423dc258 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 16:39:48 +0200 Subject: [PATCH 0699/4212] remove redundant code, use new fsproperty module instead Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 105 +++------------------------------------ 1 file changed, 8 insertions(+), 97 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 76e8faa1..2ae5f81b 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -25,14 +25,14 @@ import os import collections import cdist -import cdist.core.property +import cdist.core +from cdist.util import fsproperty log = logging.getLogger(__name__) DOT_CDIST = '.cdist' -# FIXME: i should not have to care about prefix directory, local, remote and such. -# I know what my internals look like, the outside is none of my business. + class Object(object): """Represents a cdist object. @@ -93,97 +93,8 @@ class Object(object): # return relative path return os.path.join(self.path, "explorer") - - ### requirements - @property - def requirements(self): - if not self.__requirements: - self.__requirements = cdist.core.property.FileList(os.path.join(self.absolute_path, "require")) - return self.__requirements - - @requirements.setter - def requirements(self, value): - if isinstance(value, cdist.core.property.FileList): - self.__requirements = value - else: - self.__requirements = cdist.core.property.FileList(os.path.join(self.absolute_path, "require"), value) - ### /requirements - - - ### parameters - @property - def parameters(self): - if not self.__parameters: - self.__parameters = cdist.core.property.DirectoryDict(os.path.join(self.absolute_path, "parameter")) - return self.__parameters - - @parameters.setter - def parameters(self, value): - if isinstance(value, cdist.core.property.DirectoryDict): - self.__parameters = value - else: - self.__parameters = cdist.core.property.DirectoryDict(os.path.join(self.absolute_path, "parameter"), value) - ### /parameters - - - ### changed - @property - def changed(self): - """Check whether the object has been changed.""" - return os.path.isfile(os.path.join(self.absolute_path, "changed")) - - @changed.setter - def changed(self, value): - """Change the objects changed status.""" - path = os.path.join(self.absolute_path, "changed") - if value: - open(path, "w").close() - else: - try: - os.remove(path) - except EnvironmentError: - # ignore - pass - ### /changed - - - ### prepared - @property - def prepared(self): - """Check whether the object has been prepared.""" - return os.path.isfile(os.path.join(self.absolute_path, "prepared")) - - @prepared.setter - def prepared(self, value): - """Change the objects prepared status.""" - path = os.path.join(self.absolute_path, "prepared") - if value: - open(path, "w").close() - else: - try: - os.remove(path) - except EnvironmentError: - # ignore - pass - ### /prepared - - - ### ran - @property - def ran(self): - """Check whether the object has been ran.""" - return os.path.isfile(os.path.join(self.absolute_path, "ran")) - - @ran.setter - def ran(self, value): - """Change the objects ran status.""" - path = os.path.join(self.absolute_path, "ran") - if value: - open(path, "w").close() - else: - try: - os.remove(path) - except EnvironmentError: - # ignore - pass - ### /ran + requirements = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'require')) + parameters = fsproperty.DirectoryDictProperty(lambda obj: os.path.join(obj.absolute_path, 'parameter')) + changed = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "changed")) + prepared = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "prepared")) + ran = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "ran")) From af8f006fc682d120924e44ef024a7eee09304f74 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 16:50:56 +0200 Subject: [PATCH 0700/4212] /type/cdist_type/ Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 2ae5f81b..a3baa941 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -63,8 +63,8 @@ class Object(object): if DOT_CDIST in dirs: yield os.path.relpath(path, object_base_path) - def __init__(self, type, base_path, object_id=None): - self.type = type # instance of Type + def __init__(self, cdist_type, base_path, object_id=None): + self.type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id self.name = os.path.join(self.type.name, self.object_id) From 67543146f0fa15b9ad3149b42e0999b02fef132e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 10 Oct 2011 17:46:25 +0200 Subject: [PATCH 0701/4212] add source property Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index a3baa941..83446ad7 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -98,3 +98,4 @@ class Object(object): changed = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "changed")) prepared = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "prepared")) ran = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "ran")) + source = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.absolute_path, "source")) From 1015810391298387b54efc4b58b44347db45673e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 10 Oct 2011 18:31:56 +0200 Subject: [PATCH 0702/4212] ++testtodo Signed-off-by: Nico Schottelius --- doc/dev/todo/tests | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/dev/todo/tests b/doc/dev/todo/tests index 8f019fed..6fcd1a04 100644 --- a/doc/dev/todo/tests +++ b/doc/dev/todo/tests @@ -26,3 +26,4 @@ Tests needed: run_type_explorer(): ensure environment is setup correctly + all: check that messages of all functions contain target_host in string From 35bfa2fcdc5d7cf53dbfac796913aa01f6415c44 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 10 Oct 2011 18:50:06 +0200 Subject: [PATCH 0703/4212] finish merge of context and config_install Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 6191b118..f5b33e3f 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -23,6 +23,7 @@ import logging import os import stat +import shutil import sys import tempfile import time @@ -46,8 +47,6 @@ class ConfigInstall: debug=False): self.target_host = target_host - # FIXME: should this be setup here? - os.environ['__target_host'] = self.target_host self.debug = debug @@ -92,12 +91,16 @@ class ConfigInstall: self.remote_base_path = os.environ['__cdist_remote_out_dir'] else: self.remote_base_path = "/var/lib/cdist" + self.remote_conf_path = os.path.join(self.remote_base_path, "conf") self.remote_object_path = os.path.join(self.remote_base_path, "object") self.remote_type_path = os.path.join(self.remote_conf_path, "type") self.remote_global_explorer_path = os.path.join(self.remote_conf_path, "explorer") + # Setup env to be used by others + self.__init_env() + # Create directories self.__init_local_paths() self.__init_remote_paths() @@ -120,6 +123,10 @@ class ConfigInstall: os.mkdir(self.global_explorer_out_path) os.mkdir(self.bin_path) + def __init_env(self): + """Environment usable for other stuff""" + os.environ['__target_host'] = self.target_host + def cleanup(self): # Do not use in __del__: # http://docs.python.org/reference/datamodel.html#customization @@ -274,7 +281,7 @@ class ConfigInstall: self.transfer_object_parameter(cdist_object) for explorer in cdist_type.explorers: - remote_cmd = cmd + [os.path.join(self.remote_base_path, + remote_cmd = cmd + [os.path.join(self.remote_type_path, cdist_type.explorer_path, explorer)] output = os.path.join(self.object_base_path, cdist_object.explorer_path, explorer) @@ -385,6 +392,7 @@ class ConfigInstall: log.debug("Skipping retransfer for explorers of %s", cdist_type) return else: + log.debug("Ensure no retransfer for %s", cdist_type) # Do not retransfer cdist_type.transferred_explorers = True @@ -402,7 +410,6 @@ class ConfigInstall: self.remote_mkdir(dst) self.transfer_path(src, dst) - def remote_mkdir(self, directory): """Create directory on remote side""" cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) From 92d3925b1cb33cc5d4a5cfbb27eac7ee024e94c8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 00:18:32 +0200 Subject: [PATCH 0704/4212] add filter to prepend hostname in config_install Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index f5b33e3f..0835f972 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -53,6 +53,9 @@ class ConfigInstall: # Required for testing self.exec_path = exec_path + # Configure logging + log.addFilter(self) + # Base and Temp Base if base_path: self.base_path = base_path @@ -106,6 +109,7 @@ class ConfigInstall: self.__init_remote_paths() + def __init_remote_paths(self): """Initialise remote directory structure""" self.remove_remote_path(self.remote_base_path) @@ -139,8 +143,13 @@ class ConfigInstall: shutil.rmtree(self.cache_path) shutil.move(self.out_path, self.cache_path) - def logfilter(self): - """Add hostname to logs""" + def filter(self, record): + """Add hostname to logs via logging Filter""" + + record.msg = self.target_host + ": " + record.msg + + return True + def run_initial_manifest(self): """Run the initial manifest""" From 94cca2e5372336c90246669c54bd0d89b822ea81 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 00:28:53 +0200 Subject: [PATCH 0705/4212] prepend hostname in emulator as well Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 1 - lib/cdist/emulator.py | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 0835f972..7c66d449 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -150,7 +150,6 @@ class ConfigInstall: return True - def run_initial_manifest(self): """Run the initial manifest""" log.info("Running initial manifest %s", self.initial_manifest) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 27a3abb1..b037d63d 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -34,6 +34,7 @@ def run(argv): param_path = os.path.join(type_path, "parameter") global_path = os.environ['__global'] object_source = os.environ['__cdist_manifest'] + target_host = os.environ['__target_host'] if '__debug' in os.environ: logging.root.setLevel(logging.DEBUG) @@ -68,7 +69,7 @@ def run(argv): object_id = object_id[1:] # Prefix output by object_self - logformat = '%(levelname)s: ' + cdist_type + '/' + object_id + ': %(message)s' + logformat = '%(levelname)s: ' + target_host + ": " + cdist_type + '/' + object_id + ': %(message)s' logging.basicConfig(format=logformat) # FIXME: verify object id @@ -103,7 +104,7 @@ def run(argv): value = getattr(args, param) if value: file = os.path.join(param_out_dir, param) - log.debug(file + "<-" + param + " = " + value) + log.debug(file + " = " + value) # Already exists, verify all parameter are the same if object_exists: From 72a2543470a98563077afb69587ff1db04680d94 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 00:42:03 +0200 Subject: [PATCH 0706/4212] introduce install support in emulator Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index b037d63d..7141f16d 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -36,10 +36,28 @@ def run(argv): object_source = os.environ['__cdist_manifest'] target_host = os.environ['__target_host'] + # Logsetup - FIXME: add object_fq as soon as setup! + #id = target_host + ": " + cdist_type + '/' + object_id + id = target_host + ": " + # logformat = '%(levelname)s: ' + target_host + ": " + cdist_type + '/' + object_id + ': %(message)s' + logformat = '%(levelname)s: ' + id + ': %(message)s' + logging.basicConfig(format=logformat) + if '__debug' in os.environ: logging.root.setLevel(logging.DEBUG) else: - logging.basicConfig(level=logging.INFO) + logging.root.setLevel(logging.INFO) + + + if '__install' in os.environ: + install = True + else: + install = False + + if install: + if not os.path.isfile(os.path.join(type_path, "install")): + log.debug("Running in install mode, ignoring non install type") + return True parser = argparse.ArgumentParser(add_help=False) @@ -68,9 +86,6 @@ def run(argv): if object_id[0] == '/': object_id = object_id[1:] - # Prefix output by object_self - logformat = '%(levelname)s: ' + target_host + ": " + cdist_type + '/' + object_id + ': %(message)s' - logging.basicConfig(format=logformat) # FIXME: verify object id log.debug(args) @@ -134,11 +149,13 @@ def run(argv): if "require" in os.environ: requirements = os.environ['require'] log.debug(object_id + ":Writing requirements: " + requirements) + # FIXME: handle exception require_fd = open(os.path.join(object_path, "require"), "a") require_fd.write(requirements.replace(" ","\n")) require_fd.close() # Record / Append source + # FIXME: handle exception source_fd = open(os.path.join(object_path, "source"), "a") source_fd.writelines(object_source) source_fd.close() From 425d973dc28c0e3eb8a75f7815feae8399a8977a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 00:46:01 +0200 Subject: [PATCH 0707/4212] ++changes for 2.0.3 Signed-off-by: Nico Schottelius --- doc/changelog | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 798c90e0..3540498e 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,7 +1,10 @@ 2.0.3: * Improved logging, added --verbose, by more quiet by default * Bugfix __user: Correct quoting (Steven Armstrong) - * FIXME: Support for __remote_exec and __remote_copy + * Bugfix requirements: Restore original require="" behaviour + * Feature: Initial undocumented support for replacing + the remote exec and remote copy commands + * Feature: Initial undocumented support for installations in core 2.0.2: 2011-09-27 * Add support for detection of OpenWall Linux (Matthias Teege) From a1e1c8d66572e2ee289c3c156cea5688a7779b58 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 09:02:01 +0200 Subject: [PATCH 0708/4212] +docstring Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 51 +++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index 1af2f0f5..b855daa4 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -143,7 +143,7 @@ class FileListProperty(FileList): class DirectoryDict(collections.MutableMapping): - """A dict that stores it's state in a directory. + """A dict that stores it's items as files in a directory. """ def __init__(self, path, initial=None, **kwargs): @@ -270,3 +270,52 @@ class FileBooleanProperty(object): def __delete__(self, obj): raise AttributeError("can't delete attribute") + +# FIXME: should have same anchestor as FileList +class FileStringProperty(object): + """A string property which stores its state in a file. + """ + def __init__(self, path): + """ + :param path: string or callable + + Usage: + + class Foo(object): + source = FileStringProperty(lambda obj: os.path.join(obj.absolute_path, 'source')) + other = FileStringProperty('/tmp/other') + + def __init__(self): + self.absolute_path = '/tmp/foo_boolean' + + """ + self._path = path + + def _get_path(self, *args, **kwargs): + path = self._path + if callable(path): + return path(*args, **kwargs) + if not os.path.isabs(path): + raise AbsolutePathRequiredError(path) + return path + + # Descriptor Protocol + def __get__(self, obj, objtype=None): + if obj is None: + return self.__class__ + path = self._get_path(obj) + value = "" + try: + with open(path, "r") as fd: + value = fd.read().rstrip('\n') + except EnvironmentError: + pass + return value + + def __set__(self, obj, value): + path = self._get_path(obj) + with open(path, "w") as fd: + fd.write(str(value)) + + def __delete__(self, obj): + raise AttributeError("can't delete attribute") From 005009ab5da44539e496ba92bf737c790d909221 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 09:38:03 +0200 Subject: [PATCH 0709/4212] finish FileStringProperty Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index b855daa4..c18a1553 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -271,9 +271,9 @@ class FileBooleanProperty(object): def __delete__(self, obj): raise AttributeError("can't delete attribute") -# FIXME: should have same anchestor as FileList + class FileStringProperty(object): - """A string property which stores its state in a file. + """A string property which stores its value in a file. """ def __init__(self, path): """ @@ -307,15 +307,21 @@ class FileStringProperty(object): value = "" try: with open(path, "r") as fd: - value = fd.read().rstrip('\n') + value = fd.read() except EnvironmentError: pass return value def __set__(self, obj, value): path = self._get_path(obj) - with open(path, "w") as fd: - fd.write(str(value)) + if value: + with open(path, "w") as fd: + fd.write(str(value)) + else: + try: + os.unlink(path) + except EnvironmentError: + pass def __delete__(self, obj): - raise AttributeError("can't delete attribute") + raise AttributeError("Can't delete attribute. Set it's value to an empty string to remove the underlying file.") From af83c7af8e936eb32f934b4f6d40a6d228f876fa Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 09:38:31 +0200 Subject: [PATCH 0710/4212] tests for Object source Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 75322654..eee1563c 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -62,6 +62,7 @@ class ObjectTestCase(unittest.TestCase): self.cdist_object.changed = False self.cdist_object.prepared = False self.cdist_object.ran = False + self.cdist_object.source = "" def test_name(self): self.assertEqual(self.cdist_object.name, '__third/moon') @@ -115,3 +116,10 @@ class ObjectTestCase(unittest.TestCase): def test_ran_after_changing(self): self.cdist_object.ran = True self.assertTrue(self.cdist_object.ran) + + def test_source(self): + self.assertEqual(self.cdist_object.source, '') + + def test_source_after_changing(self): + self.cdist_object.source = '/path/to/manifest' + self.assertEqual(self.cdist_object.source, '/path/to/manifest') From 96c059983a93aa50e97a603c238a3866102ab4d7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 10:28:10 +0200 Subject: [PATCH 0711/4212] - legacy code, + docstrings Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 83446ad7..eda7eb40 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -74,9 +74,6 @@ class Object(object): self.code_remote_path = os.path.join(self.path, "code-remote") self.parameter_path = os.path.join(self.path, "parameter") - self.__parameters = None - self.__requirements = None - def __repr__(self): return '' % self.name @@ -86,6 +83,7 @@ class Object(object): @property def explorer_path(self): + """Create and return the relative path to this objects explorers""" # create absolute path path = os.path.join(self.absolute_path, "explorer") if not os.path.isdir(path): From 5a082058e50de2f21776f3a07f15d79c211c10a6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 10:28:41 +0200 Subject: [PATCH 0712/4212] new method which checks if object exists on the file system Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index eda7eb40..f3099e1d 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -97,3 +97,8 @@ class Object(object): prepared = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "prepared")) ran = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "ran")) source = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.absolute_path, "source")) + + @property + def exists(self): + """Checks wether this cdist object exists on the file systems.""" + return os.path.exists(self.absolute_path) From 904396f6a5031c06790190a2d46df0ffe1b5af64 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 10:29:06 +0200 Subject: [PATCH 0713/4212] new method to create object on the file system Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index f3099e1d..acef8079 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -102,3 +102,13 @@ class Object(object): def exists(self): """Checks wether this cdist object exists on the file systems.""" return os.path.exists(self.absolute_path) + + def create(self): + """Create this cdist object on the filesystem. + """ + try: + os.makedirs(self.absolute_path, exist_ok=False) + absolute_parameter_path = os.path.join(self.base_path, self.parameter_path) + os.makedirs(absolute_parameter_path, exist_ok=False) + except EnvironmentError as error: + raise cdist.Error('Error creating directories for cdist object: %s: %s' % (self, error)) From 753936b7c3154546ce8b1c9a2374982cf30e6a17 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 10:30:30 +0200 Subject: [PATCH 0714/4212] make object.source a list Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index acef8079..76634a65 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -96,7 +96,7 @@ class Object(object): changed = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "changed")) prepared = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "prepared")) ran = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "ran")) - source = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.absolute_path, "source")) + source = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, "source")) @property def exists(self): From 6199a255a49b2bdcb89a31d17583a9d88235d8f9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 11:06:10 +0200 Subject: [PATCH 0715/4212] add emulator output Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-11.emulator-output | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 doc/dev/logs/2011-10-11.emulator-output diff --git a/doc/dev/logs/2011-10-11.emulator-output b/doc/dev/logs/2011-10-11.emulator-output new file mode 100644 index 00000000..d1f066c5 --- /dev/null +++ b/doc/dev/logs/2011-10-11.emulator-output @@ -0,0 +1,8 @@ +Debug: +DEBUG: Namespace(name=None, state='installed') +DEBUG: Object output dir = /home/users/nico/.tmp/tmpsdaonx/out/object/__package_pacman/zsh/.cdist +DEBUG: Object param dir = /home/users/nico/.tmp/tmpsdaonx/out/object/__package_pacman/zsh/.cdist/parameter +DEBUG: /home/users/nico/.tmp/tmpsdaonx/out/object/__package_pacman/zsh/.cdist/parameter/state<-state = installed +DEBUG: zsh:Writing requirements: +DEBUG: Finished __package_pacman/zsh{'state': 'installed', 'name': None} + From e72ad1f7cb26fb2970117e31154a27560647ecf9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 12:19:13 +0200 Subject: [PATCH 0716/4212] emulator not needed in config_install anymore Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 7c66d449..2f1adecd 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -30,7 +30,6 @@ import time import cdist.core import cdist.exec -import cdist.emulator log = logging.getLogger(__name__) From bcde8683af9087b589b84d97151f63d7b6a04c91 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 12:27:08 +0200 Subject: [PATCH 0717/4212] rewrite emulator to use Type and Object classes Signed-off-by: Steven Armstrong --- lib/cdist/emulator.py | 108 +++++++++++++----------------------------- 1 file changed, 33 insertions(+), 75 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 27a3abb1..0a6d57d6 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -24,122 +24,80 @@ import logging import os import cdist +from cdist import core log = logging.getLogger(__name__) def run(argv): """Emulate type commands (i.e. __file and co)""" - cdist_type = os.path.basename(argv[0]) - type_path = os.path.join(os.environ['__cdist_type_base_path'], cdist_type) - param_path = os.path.join(type_path, "parameter") - global_path = os.environ['__global'] - object_source = os.environ['__cdist_manifest'] - if '__debug' in os.environ: logging.root.setLevel(logging.DEBUG) else: logging.basicConfig(level=logging.INFO) + global_path = os.environ['__global'] + object_source = os.environ['__cdist_manifest'] + type_name = os.path.basename(argv[0]) + + object_base_path = os.path.join(global_path, "object") + type_base_path = os.environ['__cdist_type_base_path'] + cdist_type = core.Type(type_base_path, type_name) + parser = argparse.ArgumentParser(add_help=False) - for parameter in cdist.file_to_list(os.path.join(param_path, "optional")): + for parameter in cdist_type.optional_parameters: argument = "--" + parameter parser.add_argument(argument, action='store', required=False) - for parameter in cdist.file_to_list(os.path.join(param_path, "required")): + for parameter in cdist_type.required_parameters: argument = "--" + parameter parser.add_argument(argument, action='store', required=True) # If not singleton support one positional parameter - if not os.path.isfile(os.path.join(type_path, "singleton")): + if not cdist_type.is_singleton: parser.add_argument("object_id", nargs=1) # And finally verify parameter args = parser.parse_args(argv[1:]) # Setup object_id - if os.path.isfile(os.path.join(type_path, "singleton")): + if cdist_type.is_singleton: object_id = "singleton" else: object_id = args.object_id[0] del args.object_id - # FIXME: / hardcoded - better portable solution available? - if object_id[0] == '/': - object_id = object_id[1:] + # strip leading slash from object_id + object_id = object_id.lstrip('/') + + # Instantiate the cdist object whe are defining + cdist_object = core.Object(cdist_type, object_base_path, object_id) # Prefix output by object_self - logformat = '%(levelname)s: ' + cdist_type + '/' + object_id + ': %(message)s' + logformat = '%%(levelname)s: %s: %%(message)s' % cdist_object.path logging.basicConfig(format=logformat) # FIXME: verify object id log.debug(args) - object_path = os.path.join(global_path, "object", cdist_type, - object_id, cdist.DOT_CDIST) - log.debug("Object output dir = " + object_path) - - param_out_dir = os.path.join(object_path, "parameter") - - object_source_file = os.path.join(object_path, "source") - - if os.path.exists(object_path): - object_exists = True - old_object_source_fd = open(object_source_file, "r") - old_object_source = old_object_source_fd.readlines() - old_object_source_fd.close() - + # Create object with given parameters + parameters = vars(args) + if cdist_object.exists: + if cdist_object.parameters != parameters: + raise cdist.Error("Object %s already exists with conflicting parameters:\n%s: %s\n%s: %s" + % (cdist_object, " ".join(cdist_object.source), cdist_object.parameters, object_source, parameters) + ) else: - object_exists = False - try: - os.makedirs(object_path, exist_ok=False) - log.debug("Object param dir = " + param_out_dir) - os.makedirs(param_out_dir, exist_ok=False) - except OSError as error: - raise cdist.Error(param_out_dir + ": " + error.args[1]) - - # Record parameter - params = vars(args) - for param in params: - value = getattr(args, param) - if value: - file = os.path.join(param_out_dir, param) - log.debug(file + "<-" + param + " = " + value) - - # Already exists, verify all parameter are the same - if object_exists: - if not os.path.isfile(file): - raise cdist.Error("New parameter \"" + - param + "\" specified, aborting\n" + - "Source = " + - " ".join(old_object_source) - + " new =" + object_source) - else: - param_fd = open(file, "r") - value_old = param_fd.readlines() - param_fd.close() - - if(value_old[0] != value): - raise cdist.Error("Parameter\"" + param + - "\" differs: " + " ".join(value_old) + " vs. " + - value + - "\nSource = " + " ".join(old_object_source) - + " new = " + object_source) - else: - param_fd = open(file, "w") - param_fd.writelines(value) - param_fd.close() + cdist_object.create() + cdist_object.parameters = parameters # Record requirements if "require" in os.environ: requirements = os.environ['require'] - log.debug(object_id + ":Writing requirements: " + requirements) - require_fd = open(os.path.join(object_path, "require"), "a") - require_fd.write(requirements.replace(" ","\n")) - require_fd.close() + log.debug("%s:Writing requirements: %s" % (cdist_object.path, requirements)) + cdist_object.requirements.extend(requirements.split(" ")) # Record / Append source - source_fd = open(os.path.join(object_path, "source"), "a") - source_fd.writelines(object_source) - source_fd.close() + # FIXME: source should be list + cdist_object.source.append(object_source) - log.debug("Finished " + cdist_type + "/" + object_id + repr(params)) + log.debug("Finished %s %s" % (cdist_object.path, parameters)) From 5443db97c4d7199c04dfac5d15d37345d6caa7f1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 12:54:55 +0200 Subject: [PATCH 0718/4212] always setup __debug if debug is set Signed-off-by: Nico Schottelius --- doc/dev/todo/tests | 44 ++++++++++++++++++++++++++++++++----- lib/cdist/config_install.py | 28 ++++++++++------------- 2 files changed, 49 insertions(+), 23 deletions(-) diff --git a/doc/dev/todo/tests b/doc/dev/todo/tests index 6fcd1a04..27bca3b6 100644 --- a/doc/dev/todo/tests +++ b/doc/dev/todo/tests @@ -1,11 +1,43 @@ -Tests needed: +Tests needed for config_install: - - Fail if cache_dir from previous run cannot be deleted - - Fail if cache_dir cannot be created from current out_dir - - transfer_type_explorers: Explorers are not transferred twice - - transfer_type_explorers: No transfer tried if there are no type_explorers + __init__(): + - sets up env: __target_host + + cleanup() + - Fail if cache_dir from previous run cannot be deleted + - Fail if cache_dir cannot be created from current out_dir + + filter() + - ensure logformat is changed: target host is prefixed: + LOGLEVEL: target_host: MESSAGE + + run_initial_manifest(): + - parameter is actually used (from __init__) + - ensure changing the manifest actually runs a different manifest + -> give ConfigInstall Constructor different manifest + -> different manifest is executed. + - test all submitted (from core to type manifest) variables: + - ENVIRONMENT + - they are set + - they contain the correct values + + run_type_manifest(): + - test all submitted (from core to type manifest) variables: + - ENVIRONMENT + - they are set + - they contain the correct values + run_manifest(): + - test all submitted variables: + - ENVIRONMENT + - including __debug, if debug + - they are set + - they contain the correct values + - does $require work? + + transfer_type_explorers(): + - Explorers are not transferred twice + - No transfer tried if there are no type_explorers - - does $require work? - $whatever should fail if there is no global explorer directory - emulator may only be called with __ as prefix - fail otherwise! diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 2f1adecd..a286472b 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -49,20 +49,16 @@ class ConfigInstall: self.debug = debug - # Required for testing + # Only required for testing self.exec_path = exec_path # Configure logging log.addFilter(self) # Base and Temp Base - if base_path: - self.base_path = base_path - else: - self.base_path = os.path.abspath( - os.path.join(os.path.dirname(__file__), - os.pardir, - os.pardir)) + self.base_path = (base_path or + self.base_path = os.path.abspath(os.path.join( + os.path.dirname(__file__), os.pardir, os.pardir)) # Local input self.cache_path = os.path.join(self.base_path, "cache", @@ -74,10 +70,8 @@ class ConfigInstall: self.type_base_path = os.path.join(self.conf_path, "type") self.lib_path = os.path.join(self.base_path, "lib") - if initial_manifest: - self.initial_manifest = initial_manifest - else: - self.initial_manifest = os.path.join(self.manifest_path, "init") + self.initial_manifest = (initial_manifest or + os.path.join(self.manifest_path, "init")) # Local output if '__cdist_out_dir' in os.environ: @@ -108,7 +102,6 @@ class ConfigInstall: self.__init_remote_paths() - def __init_remote_paths(self): """Initialise remote directory structure""" self.remove_remote_path(self.remote_base_path) @@ -122,6 +115,7 @@ class ConfigInstall: if not os.path.isdir(self.base_path): os.mkdir(self.base_path) + # FIXME: raise more beautiful exception / Steven: handle exception os.mkdir(self.out_path) os.mkdir(self.global_explorer_out_path) os.mkdir(self.bin_path) @@ -129,6 +123,9 @@ class ConfigInstall: def __init_env(self): """Environment usable for other stuff""" os.environ['__target_host'] = self.target_host + if self.debug: + os.environ['__debug'] = "yes" + def cleanup(self): # Do not use in __del__: @@ -137,6 +134,7 @@ class ConfigInstall: # or in the process of being torn down (e.g. the import machinery shutting down)" # log.debug("Saving " + self.out_path + " to " + self.cache_path) + # FIXME: raise more beautiful exception / Steven: handle exception # Remove previous cache if os.path.exists(self.cache_path): shutil.rmtree(self.cache_path) @@ -182,10 +180,6 @@ class ConfigInstall: env['__target_host'] = self.target_host env['__global'] = self.out_path - # Submit debug flag to manifest, can be used by emulator and types - if self.debug: - env['__debug'] = "yes" - # Required for recording source in emulator env['__cdist_manifest'] = manifest_path From cfd04dc20449445ff16e7c3315a091dcebc00d44 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 13:04:01 +0200 Subject: [PATCH 0719/4212] ++tests needed Signed-off-by: Nico Schottelius --- doc/dev/todo/tests | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/doc/dev/todo/tests b/doc/dev/todo/tests index 27bca3b6..3d17ba34 100644 --- a/doc/dev/todo/tests +++ b/doc/dev/todo/tests @@ -38,20 +38,21 @@ Tests needed for config_install: - Explorers are not transferred twice - No transfer tried if there are no type_explorers - - $whatever should fail if there is no global explorer directory - - emulator may only be called with __ as prefix - fail otherwise! + emulator() + may only be called with __ as prefix - fail otherwise! - - ensure paths returned by object include dot-cdist - - ensure path of explorer of object returns correct path - - config_install: - run_type_manifest() - same tests as for test_initial_manifest_*? - run_manifest() - raise exception if manifest is not existent - object_run(): ensure no object is run twice - object_run(): ensure requirements are taken into account - object_run(): check (from extern?) that all needed variables are setup - object_run(): ensure no code-{local, remote} is created, if gencode is not producing code - object_run(): ensure no code-{local, remote} contains what gencode created + object_run(): + - ensure no object is run twice + - ensure requirements are taken into account? + - and order of run is adjusted + - check (from extern?) that all needed variables are setup + - ensure no code-{local, remote} is created, + if gencode is not producing code + - ensure THAT code-{local, remote} contains what gencode created + - abort if gencode-* fails + - abort if code-* fails + - abort == raise(FooException) + - gencode-*: ensure ENVIRONMENT is setup correctly run_type_explorer(): ensure output is saved to correct path run_type_explorer(): ensure a type with no explorers works @@ -59,3 +60,7 @@ Tests needed for config_install: all: check that messages of all functions contain target_host in string + + config_install: + run_type_manifest() - same tests as for test_initial_manifest_*? + run_manifest() - raise exception if manifest is not existent From 2c5b064b0034a9a4b8aa3be2448adad23f069f78 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 13:06:29 +0200 Subject: [PATCH 0720/4212] ++todo = remove CODE_HEADER in generated code Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index a286472b..fb27b17d 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -229,6 +229,7 @@ class ConfigInstall: outfile_fd = open(outfile, "w") # Need to flush to ensure our write is done before stdout write + # FIXME: code header still needed? outfile_fd.write(CODE_HEADER) outfile_fd.flush() From 9d7468edf6f7e4408fe04a6d33cdd49018c66efb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 13:09:56 +0200 Subject: [PATCH 0721/4212] add old log of trigger work Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-06-25.trigger-graphic | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 doc/dev/logs/2011-06-25.trigger-graphic diff --git a/doc/dev/logs/2011-06-25.trigger-graphic b/doc/dev/logs/2011-06-25.trigger-graphic new file mode 100644 index 00000000..f17220e1 --- /dev/null +++ b/doc/dev/logs/2011-06-25.trigger-graphic @@ -0,0 +1,15 @@ + + + + + + +client -------------------> trigger via ssh ----------> server + ~/.ssh/authorized_keys + -> cdist-deploy-to + +ssh -R + +server -> via cdist-deploy-to -> client + +cdist-mass-deploy -p From cfb74897c44d8f3fc05797f0bdb4d83a237c8015 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 13:47:41 +0200 Subject: [PATCH 0722/4212] write down (almost?) all tests for config_install Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index fb27b17d..418f9fd9 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -192,6 +192,13 @@ class ConfigInstall: cdist.exec.shell_run_or_debug_fail(manifest_path, [manifest_path], env=env) + def object_prepare(self, cdist_object): + """Prepare object: Run type explorer + manifest""" + log.debug("Preparing object: " + cdist_object.name) + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + cdist_object.prepared = True + def object_run(self, cdist_object): """Run gencode and code for an object""" log.debug("Running object %s", cdist_object) @@ -294,7 +301,6 @@ class ConfigInstall: cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=True) output_fd.close() - def link_emulator(self): """Link emulator to types""" src = os.path.abspath(self.exec_path) @@ -302,7 +308,7 @@ class ConfigInstall: dst = os.path.join(self.bin_path, cdist_type.name) log.debug("Linking emulator: %s to %s", src, dst) - # FIXME: handle exception / make it more beautiful + # FIXME: handle exception / make it more beautiful / Steven: raise except :-) os.symlink(src, dst) def run_global_explorers(self): @@ -324,15 +330,6 @@ class ConfigInstall: cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=True) output_fd.close() - - def stage_run(self): - """The final (and real) step of deployment""" - log.info("Generating and executing code") - for cdist_object in cdist.core.Object.list_objects(self.object_base_path, - self.type_base_path): - log.debug("Run object: %s", cdist_object) - self.object_run(cdist_object) - def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" log.info("Deploying to " + self.target_host) @@ -365,12 +362,17 @@ class ConfigInstall: log.debug("Skipping rerun of object %s", cdist_object) continue else: - log.debug("Preparing object: " + cdist_object.name) - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) - cdist_object.prepared = True + self.object_prepare(cdist_object) new_objects_created = True + def stage_run(self): + """The final (and real) step of deployment""" + log.info("Generating and executing code") + for cdist_object in cdist.core.Object.list_objects(self.object_base_path, + self.type_base_path): + log.debug("Run object: %s", cdist_object) + self.object_run(cdist_object) + def transfer_object_parameter(self, cdist_object): """Transfer the object parameter to the remote destination""" src = os.path.join(self.object_base_path, From 2c02b174526089260aa84a93ff99fbacb495e1fe Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 13:47:53 +0200 Subject: [PATCH 0723/4212] write down (almost?) all tests for config_install (really) Signed-off-by: Nico Schottelius --- doc/dev/todo/tests | 101 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 14 deletions(-) diff --git a/doc/dev/todo/tests b/doc/dev/todo/tests index 3d17ba34..78a63d08 100644 --- a/doc/dev/todo/tests +++ b/doc/dev/todo/tests @@ -26,6 +26,8 @@ Tests needed for config_install: - ENVIRONMENT - they are set - they contain the correct values + - same tests as for test_initial_manifest_*? + run_manifest(): - test all submitted variables: - ENVIRONMENT @@ -33,13 +35,7 @@ Tests needed for config_install: - they are set - they contain the correct values - does $require work? - - transfer_type_explorers(): - - Explorers are not transferred twice - - No transfer tried if there are no type_explorers - - emulator() - may only be called with __ as prefix - fail otherwise! + - check that exception raised, if manifest is not existent object_run(): - ensure no object is run twice @@ -54,13 +50,90 @@ Tests needed for config_install: - abort == raise(FooException) - gencode-*: ensure ENVIRONMENT is setup correctly - run_type_explorer(): ensure output is saved to correct path - run_type_explorer(): ensure a type with no explorers works - run_type_explorer(): ensure environment is setup correctly + run_type_explorer() + - ensure ALL type explores have been run + - ensure output is saved to correct path + - ensure a type with {0,1,2} explorers works ? + - none, one, multiple + - ensure ENVIRONMENT is setup correctly + - fails if ANY of the given explorer fails + + run_global_explorers(): + - ensure ALL type explores have been run + - ensure output is saved to correct path + - ensure a type with {0,1,2} explorers works ? + - none, one, multiple + - ensure ENVIRONMENT is setup correctly + - fails if ANY of the given explorer fails + + link_emulator(): + - ensure that links to ALL types are created + - ensure that links points to correct executable + - i.e. readlink() works + - AND target of readlink is the correct executable + + stage_run() + - ensure that for every object in + cdist.core.Object.list_objects() is passed into + self.object_run() + - instantiate + overwrite + test + + object_prepare(): + - calls (in this order): + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + cdist_object.prepared = True + - object is prepared after function call - all: check that messages of all functions contain target_host in string + stage_prepare(): + - calls (in this order): + self.link_emulator() + self.run_global_explorers() + self.run_initial_manifest() + + - ensure that all objects are created :-) + - as defined in inital manifest + type manifests + + deploy_to() + - ensure self.stage_prepare() and self.stage_run() are + run. [ORDER] + - instantiate + overwrite + test + + deploy_and_cleanup() + - ensure self.deploy_to() + self.cleanup() are are run + run. [ORDER] + - instantiate + overwrite + test + + transfer_object_parameter() + - check that object parameters are transferred + - paths are setup correctly + - test via mock of remote_mkdir and transfer_path + - ensure self.remote_mkdir, self.transfer_path are run. [ORDER] + - instantiate + overwrite + test + + transfer_global_explorers() + - paths are setup correctly + - test via mock of self.remote_mkdir() and self.transfer_path() + - ensure self.remote_mkdir, self.transfer_path are run. [ORDER] + - instantiate + overwrite + test + + transfer_type_explorers(): + - Explorers are not transferred twice + - paths are setup correctly + - test via mock of self.remote_mkdir() and self.transfer_path() + - Explorers are transferred + - test via mock of self.remote_mkdir() and self.transfer_path() + + remote_mkdir() + - is directory created + + remove_remote_path + - is path removed + + transfer_path + - is src to dst transferred? + +emulator: + may only be called with __ as prefix - fail otherwise! - config_install: - run_type_manifest() - same tests as for test_initial_manifest_*? - run_manifest() - raise exception if manifest is not existent From 442ffb75fa6017d16e07068dda74b286fca49962 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 14:09:47 +0200 Subject: [PATCH 0724/4212] nuke legacy files Signed-off-by: Steven Armstrong --- lib/cdist/core/globalexplorer.py | 66 -------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 lib/cdist/core/globalexplorer.py diff --git a/lib/cdist/core/globalexplorer.py b/lib/cdist/core/globalexplorer.py deleted file mode 100644 index 49052d53..00000000 --- a/lib/cdist/core/globalexplorer.py +++ /dev/null @@ -1,66 +0,0 @@ - # FIXME: Explorer or stays - def global_explorer_output_path(self, explorer): - """Returns path of the output for a global explorer""" - return os.path.join(self.global_explorer_out_dir, explorer) - - # FIXME Stays here / Explorer? - def remote_global_explorer_path(self, explorer): - """Returns path to the remote explorer""" - return os.path.join(REMOTE_GLOBAL_EXPLORER_DIR, explorer) - - # FIXME: stays here - def list_global_explorers(self): - """Return list of available explorers""" - return os.listdir(self.global_explorer_dir) - -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 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 logging -import os -log = logging.getLogger(__name__) - -class Explorer(object): - - def __init__(self, src_dir, dst_dir): - self.src_dir = src_dir - self.dst_dir = dst_dir - - def list_explorers(self): - """Return list of available explorers""" - dir = os.path.join(self.path, "explorer") - if os.path.isdir(dir): - list = os.listdir(dir) - else: - list = [] - - log.debug("Explorers for %s in %s: %s", type, dir, list) - - return list - - def is_install(self): - """Check whether a type is used for installation (if not: for configuration)""" - return os.path.isfile(os.path.join(self.path, "install")) - - def remote_explorer_dir(self): - """Return remote directory that holds the explorers of a type""" - return os.path.join(self.remote_path, "explorer") From c674d4a94cdb520c81163d9ac072f8e631f0a087 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 14:14:12 +0200 Subject: [PATCH 0725/4212] distribute tests Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 56 ++++++++++++++++++++- doc/dev/todo/steven | 60 ++++++++++++++++++++++ doc/dev/todo/tests | 112 ------------------------------------------ 3 files changed, 115 insertions(+), 113 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 9710f4ea..520128cc 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,7 +1,61 @@ 2.0.3: - fix emulator / require -- sanity checks +- sanity checks: implement tests + + stage_run() + - ensure that for every object in + cdist.core.Object.list_objects() is passed into + self.object_run() + - instantiate + overwrite + test + + object_prepare(): + - calls (in this order): + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + cdist_object.prepared = True + - object is prepared after function call + + + stage_prepare(): + - calls (in this order): + self.link_emulator() + self.run_global_explorers() + self.run_initial_manifest() + + - ensure that all objects are created :-) + - as defined in inital manifest + type manifests + + deploy_to() + - ensure self.stage_prepare() and self.stage_run() are + run. [ORDER] + - instantiate + overwrite + test + + deploy_and_cleanup() + - ensure self.deploy_to() + self.cleanup() are are run + run. [ORDER] + - instantiate + overwrite + test + + transfer_object_parameter() + - check that object parameters are transferred + - paths are setup correctly + - test via mock of remote_mkdir and transfer_path + - ensure self.remote_mkdir, self.transfer_path are run. [ORDER] + - instantiate + overwrite + test + + transfer_global_explorers() + - paths are setup correctly + - test via mock of self.remote_mkdir() and self.transfer_path() + - ensure self.remote_mkdir, self.transfer_path are run. [ORDER] + - instantiate + overwrite + test + + transfer_type_explorers(): + - Explorers are not transferred twice + - paths are setup correctly + - test via mock of self.remote_mkdir() and self.transfer_path() + - Explorers are transferred + - test via mock of self.remote_mkdir() and self.transfer_path() + -------------------------------------------------------------------------------- diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index f0c867e1..93c6cab3 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,3 +1,63 @@ +tests: + + __init__(): + - sets up env: __target_host + + run_initial_manifest(): + - parameter is actually used (from __init__) + - ensure changing the manifest actually runs a different manifest + -> give ConfigInstall Constructor different manifest + -> different manifest is executed. + - test all submitted (from core to type manifest) variables: + - ENVIRONMENT + - they are set + - they contain the correct values + + run_type_manifest(): + - test all submitted (from core to type manifest) variables: + - ENVIRONMENT + - they are set + - they contain the correct values + - same tests as for test_initial_manifest_*? + + run_manifest(): + - test all submitted variables: + - ENVIRONMENT + - including __debug, if debug + - they are set + - they contain the correct values + - does $require work? + - check that exception raised, if manifest is not existent + + object_run(): + - ensure no object is run twice + - ensure requirements are taken into account? + - and order of run is adjusted + - check (from extern?) that all needed variables are setup + - ensure no code-{local, remote} is created, + if gencode is not producing code + - ensure THAT code-{local, remote} contains what gencode created + - abort if gencode-* fails + - abort if code-* fails + - abort == raise(FooException) + - gencode-*: ensure ENVIRONMENT is setup correctly + + run_type_explorer() + - ensure ALL type explores have been run + - ensure output is saved to correct path + - ensure a type with {0,1,2} explorers works ? + - none, one, multiple + - ensure ENVIRONMENT is setup correctly + - fails if ANY of the given explorer fails + + run_global_explorers(): + - ensure ALL type explores have been run + - ensure output is saved to correct path + - ensure a type with {0,1,2} explorers works ? + - none, one, multiple + - ensure ENVIRONMENT is setup correctly + - fails if ANY of the given explorer fails + Code fixes needed: - shutil, os.mkdir, etc. everywhere: catch/reraise exceptions correctly diff --git a/doc/dev/todo/tests b/doc/dev/todo/tests index 78a63d08..d2101980 100644 --- a/doc/dev/todo/tests +++ b/doc/dev/todo/tests @@ -1,8 +1,5 @@ Tests needed for config_install: - __init__(): - - sets up env: __target_host - cleanup() - Fail if cache_dir from previous run cannot be deleted - Fail if cache_dir cannot be created from current out_dir @@ -11,120 +8,12 @@ Tests needed for config_install: - ensure logformat is changed: target host is prefixed: LOGLEVEL: target_host: MESSAGE - run_initial_manifest(): - - parameter is actually used (from __init__) - - ensure changing the manifest actually runs a different manifest - -> give ConfigInstall Constructor different manifest - -> different manifest is executed. - - test all submitted (from core to type manifest) variables: - - ENVIRONMENT - - they are set - - they contain the correct values - - run_type_manifest(): - - test all submitted (from core to type manifest) variables: - - ENVIRONMENT - - they are set - - they contain the correct values - - same tests as for test_initial_manifest_*? - - run_manifest(): - - test all submitted variables: - - ENVIRONMENT - - including __debug, if debug - - they are set - - they contain the correct values - - does $require work? - - check that exception raised, if manifest is not existent - - object_run(): - - ensure no object is run twice - - ensure requirements are taken into account? - - and order of run is adjusted - - check (from extern?) that all needed variables are setup - - ensure no code-{local, remote} is created, - if gencode is not producing code - - ensure THAT code-{local, remote} contains what gencode created - - abort if gencode-* fails - - abort if code-* fails - - abort == raise(FooException) - - gencode-*: ensure ENVIRONMENT is setup correctly - - run_type_explorer() - - ensure ALL type explores have been run - - ensure output is saved to correct path - - ensure a type with {0,1,2} explorers works ? - - none, one, multiple - - ensure ENVIRONMENT is setup correctly - - fails if ANY of the given explorer fails - - run_global_explorers(): - - ensure ALL type explores have been run - - ensure output is saved to correct path - - ensure a type with {0,1,2} explorers works ? - - none, one, multiple - - ensure ENVIRONMENT is setup correctly - - fails if ANY of the given explorer fails - link_emulator(): - ensure that links to ALL types are created - ensure that links points to correct executable - i.e. readlink() works - AND target of readlink is the correct executable - stage_run() - - ensure that for every object in - cdist.core.Object.list_objects() is passed into - self.object_run() - - instantiate + overwrite + test - - object_prepare(): - - calls (in this order): - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) - cdist_object.prepared = True - - object is prepared after function call - - - stage_prepare(): - - calls (in this order): - self.link_emulator() - self.run_global_explorers() - self.run_initial_manifest() - - - ensure that all objects are created :-) - - as defined in inital manifest + type manifests - - deploy_to() - - ensure self.stage_prepare() and self.stage_run() are - run. [ORDER] - - instantiate + overwrite + test - - deploy_and_cleanup() - - ensure self.deploy_to() + self.cleanup() are are run - run. [ORDER] - - instantiate + overwrite + test - - transfer_object_parameter() - - check that object parameters are transferred - - paths are setup correctly - - test via mock of remote_mkdir and transfer_path - - ensure self.remote_mkdir, self.transfer_path are run. [ORDER] - - instantiate + overwrite + test - - transfer_global_explorers() - - paths are setup correctly - - test via mock of self.remote_mkdir() and self.transfer_path() - - ensure self.remote_mkdir, self.transfer_path are run. [ORDER] - - instantiate + overwrite + test - - transfer_type_explorers(): - - Explorers are not transferred twice - - paths are setup correctly - - test via mock of self.remote_mkdir() and self.transfer_path() - - Explorers are transferred - - test via mock of self.remote_mkdir() and self.transfer_path() - remote_mkdir() - is directory created @@ -136,4 +25,3 @@ Tests needed for config_install: emulator: may only be called with __ as prefix - fail otherwise! - From d7adff4e21b2d5655925603b8123b274dc1ec123 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 14:21:47 +0200 Subject: [PATCH 0726/4212] silently ignore error when deleting nonexistent file Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index c18a1553..68d5edaa 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -134,7 +134,11 @@ class FileListProperty(FileList): def __set__(self, obj, value): self._set_path(obj) - os.unlink(self.path) + try: + os.unlink(self.path) + except EnvironmentError: + # ignored + pass for item in value: self.append(item) From 45ff8f727ffd07418f5cfc646ab177bb8c95cbe8 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 14:22:29 +0200 Subject: [PATCH 0727/4212] tests for Object source as list Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index eee1563c..decf67bf 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -62,7 +62,7 @@ class ObjectTestCase(unittest.TestCase): self.cdist_object.changed = False self.cdist_object.prepared = False self.cdist_object.ran = False - self.cdist_object.source = "" + self.cdist_object.source = [] def test_name(self): self.assertEqual(self.cdist_object.name, '__third/moon') @@ -118,8 +118,8 @@ class ObjectTestCase(unittest.TestCase): self.assertTrue(self.cdist_object.ran) def test_source(self): - self.assertEqual(self.cdist_object.source, '') + self.assertEqual(list(self.cdist_object.source), []) def test_source_after_changing(self): - self.cdist_object.source = '/path/to/manifest' - self.assertEqual(self.cdist_object.source, '/path/to/manifest') + self.cdist_object.source = ['/path/to/manifest'] + self.assertEqual(list(self.cdist_object.source), ['/path/to/manifest']) From 539347184118f357b801272a657e08d0791271ef Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 15:25:29 +0200 Subject: [PATCH 0728/4212] add template for new explorer type Signed-off-by: Nico Schottelius --- lib/cdist/explorer.py | 460 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 460 insertions(+) create mode 100644 lib/cdist/explorer.py diff --git a/lib/cdist/explorer.py b/lib/cdist/explorer.py new file mode 100644 index 00000000..3cd1b949 --- /dev/null +++ b/lib/cdist/explorer.py @@ -0,0 +1,460 @@ +#!/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 logging +import os +import stat +import shutil +import sys +import tempfile +import time + +import cdist.core +import cdist.exec + +log = logging.getLogger(__name__) + +CODE_HEADER = "#!/bin/sh -e\n" + +class ConfigInstall: + """Cdist main class to hold arbitrary data""" + + def __init__(self, + target_host, + initial_manifest=False, + base_path=False, + exec_path=sys.argv[0], + debug=False): + + self.target_host = target_host + + self.debug = debug + + # Only required for testing + self.exec_path = exec_path + + # Configure logging + log.addFilter(self) + + # Base and Temp Base + self.base_path = (base_path or + self.base_path = os.path.abspath(os.path.join( + os.path.dirname(__file__), os.pardir, os.pardir)) + + # Local input + self.cache_path = os.path.join(self.base_path, "cache", + self.target_host) + self.conf_path = os.path.join(self.base_path, "conf") + + self.global_explorer_path = os.path.join(self.conf_path, "explorer") + self.manifest_path = os.path.join(self.conf_path, "manifest") + self.type_base_path = os.path.join(self.conf_path, "type") + self.lib_path = os.path.join(self.base_path, "lib") + + self.initial_manifest = (initial_manifest or + os.path.join(self.manifest_path, "init")) + + # Local output + if '__cdist_out_dir' in os.environ: + self.out_path = os.environ['__cdist_out_dir'] + else: + self.out_path = os.path.join(tempfile.mkdtemp(), "out") + self.bin_path = os.path.join(self.out_path, "bin") + self.global_explorer_out_path = os.path.join(self.out_path, "explorer") + self.object_base_path = os.path.join(self.out_path, "object") + + # Remote directory base + if '__cdist_remote_out_dir' in os.environ: + self.remote_base_path = os.environ['__cdist_remote_out_dir'] + else: + self.remote_base_path = "/var/lib/cdist" + + self.remote_conf_path = os.path.join(self.remote_base_path, "conf") + self.remote_object_path = os.path.join(self.remote_base_path, "object") + + self.remote_type_path = os.path.join(self.remote_conf_path, "type") + self.remote_global_explorer_path = os.path.join(self.remote_conf_path, "explorer") + + # Setup env to be used by others + self.__init_env() + + # Create directories + self.__init_local_paths() + self.__init_remote_paths() + + + def __init_remote_paths(self): + """Initialise remote directory structure""" + self.remove_remote_path(self.remote_base_path) + self.remote_mkdir(self.remote_base_path) + self.remote_mkdir(self.remote_conf_path) + + def __init_local_paths(self): + """Initialise local directory structure""" + + # Create base dir, if user supplied and not existing + if not os.path.isdir(self.base_path): + os.mkdir(self.base_path) + + # FIXME: raise more beautiful exception / Steven: handle exception + os.mkdir(self.out_path) + os.mkdir(self.global_explorer_out_path) + os.mkdir(self.bin_path) + + def __init_env(self): + """Environment usable for other stuff""" + os.environ['__target_host'] = self.target_host + if self.debug: + os.environ['__debug'] = "yes" + + + def cleanup(self): + # Do not use in __del__: + # http://docs.python.org/reference/datamodel.html#customization + # "other globals referenced by the __del__() method may already have been deleted + # or in the process of being torn down (e.g. the import machinery shutting down)" + # + log.debug("Saving " + self.out_path + " to " + self.cache_path) + # FIXME: raise more beautiful exception / Steven: handle exception + # Remove previous cache + if os.path.exists(self.cache_path): + shutil.rmtree(self.cache_path) + shutil.move(self.out_path, self.cache_path) + + def filter(self, record): + """Add hostname to logs via logging Filter""" + + record.msg = self.target_host + ": " + record.msg + + return True + + def run_initial_manifest(self): + """Run the initial manifest""" + log.info("Running initial manifest %s", self.initial_manifest) + env = { "__manifest" : self.manifest_path } + self.run_manifest(self.initial_manifest, extra_env=env) + + def run_type_manifest(self, cdist_object): + """Run manifest for a specific object""" + cdist_type = cdist_object.type + manifest_path = os.path.join(self.type_base_path, + cdist_type.manifest_path) + + log.debug("%s: Running %s", cdist_object.name, manifest_path) + if os.path.exists(manifest_path): + env = { "__object" : os.path.join(self.object_base_path, + cdist_object.path), + "__object_id": cdist_object.object_id, + "__object_fq": cdist_object.name, + "__type": os.path.join(self.type_base_path, + cdist_type.path) + } + self.run_manifest(manifest_path, extra_env=env) + + def run_manifest(self, manifest_path, extra_env=None): + """Run a manifest""" + log.debug("Running manifest %s, env=%s", manifest_path, extra_env) + env = os.environ.copy() + env['PATH'] = self.bin_path + ":" + env['PATH'] + + # Information required in every manifest + env['__target_host'] = self.target_host + env['__global'] = self.out_path + + # Required for recording source in emulator + env['__cdist_manifest'] = manifest_path + + # Required to find types in emulator + env['__cdist_type_base_path'] = self.type_base_path + + # Other environment stuff + if extra_env: + env.update(extra_env) + + cdist.exec.shell_run_or_debug_fail(manifest_path, [manifest_path], env=env) + + def object_prepare(self, cdist_object): + """Prepare object: Run type explorer + manifest""" + log.debug("Preparing object: " + cdist_object.name) + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + cdist_object.prepared = True + + def object_run(self, cdist_object): + """Run gencode and code for an object""" + log.debug("Running object %s", cdist_object) + + # Catch requirements, which re-call us + if cdist_object.ran: + return + + cdist_type = cdist_object.type + + for requirement in cdist_object.requirements: + log.debug("Object %s requires %s", cdist_object, requirement) + self.object_run(requirement) + + # + # Setup env Variable: + # + env = os.environ.copy() + env['__target_host'] = self.target_host + env['__global'] = self.out_path + env["__object"] = os.path.join(self.object_base_path, cdist_object.path) + env["__object_id"] = cdist_object.object_id + env["__object_fq"] = cdist_object.name + env["__type"] = cdist_type.name + + # gencode + for cmd in ["local", "remote"]: + bin = os.path.join(self.type_base_path, + getattr(cdist_type, "gencode_" + cmd + "_path")) + + if os.path.isfile(bin): + outfile = os.path.join(self.object_base_path, + getattr(cdist_object, "code_" + cmd + "_path")) + + outfile_fd = open(outfile, "w") + + # Need to flush to ensure our write is done before stdout write + # FIXME: code header still needed? + outfile_fd.write(CODE_HEADER) + outfile_fd.flush() + + cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) + outfile_fd.close() + + status = os.stat(outfile) + + # Remove output if empty, else make it executable + if status.st_size == len(CODE_HEADER): + os.unlink(outfile) + else: + # Add header and make executable - identically to 0o700 + os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + cdist_object.changed=True + + # code local + code_local = cdist_object.code_local_path + if os.path.isfile(code_local): + cdist.exec.run_or_fail([code_local]) + + # code remote + local_remote_code = os.path.join(self.object_base_path, + cdist_object.code_remote_path) + remote_remote_code = os.path.join(self.remote_object_path, + cdist_object.code_remote_path) + if os.path.isfile(local_remote_code): + self.transfer_path(local_remote_code, remote_remote_code) + cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) + + cdist_object.ran = True + + def run_type_explorer(self, cdist_object): + + def run_type_explorer(self, cdist_object, remote_global_explorer_path, remote_type_path, remote_object_path, scp-hints, ssh-hints, object_base_path): + + def __init__(self, remote_global_explorer_path, remote_type_path, remote_object_path, exec-hint, object_base_path, global_explorer_out_path): + + def __init__(self, remote_global_explorer_path, remote_type_path, remote_object_path, exec-hint): + + def run_type_explorer(self, cdist_object) + + self.value = .,.. + return value + + def run_global_explorer(self) + + def __init__(self, remote_global_explorer_path, remote_type_path, remote_object_path, exec-hint): + == 1x + + + + + run_type_explorer() + self.instance.value[obej + + c = ConfigInstall("foo") + c.remote_global_explorer_path = "moo" + + def run_type_explorer(self, cdist_object) + """Run type specific explorers for objects""" + + cdist_type = cdist_object.type + self.transfer_type_explorers(cdist_type) + + cmd = [] + cmd.append("__explorer=" + self.remote_global_explorer_path) + cmd.append("__type_explorer=" + os.path.join( + self.remote_type_path, + cdist_type.explorer_path)) + cmd.append("__object=" + os.path.join( + self.remote_object_path, + cdist_object.path)) + cmd.append("__object_id=" + cdist_object.object_id) + cmd.append("__object_fq=" + cdist_object.name) + + # Need to transfer at least the parameters for objects to be useful + self.transfer_object_parameter(cdist_object) + + for explorer in cdist_type.explorers: + remote_cmd = cmd + [os.path.join(self.remote_type_path, + cdist_type.explorer_path, explorer)] + output = os.path.join(self.object_base_path, + cdist_object.explorer_path, explorer) + output_fd = open(output, mode='w') + log.debug("%s exploring %s using %s storing to %s", + cdist_object, explorer, remote_cmd, output) + + cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=True) + output_fd.close() + + return outputs + + def link_emulator(self): + """Link emulator to types""" + src = os.path.abspath(self.exec_path) + for cdist_type in cdist.core.Type.list_types(self.type_base_path): + dst = os.path.join(self.bin_path, cdist_type.name) + log.debug("Linking emulator: %s to %s", src, dst) + + # FIXME: handle exception / make it more beautiful / Steven: raise except :-) + os.symlink(src, dst) + + def run_global_explorers(src_path, dst_path, remote_dst_path): + + def run_global_explorers(self): + """Run global explorers""" + log.info("Running global explorers") + + src_path = self.global_explorer_path + dst_path = self.global_explorer_out_path + remote_dst_path = self.remote_global_explorer_path + + self.transfer_path(src_path, remote_dst_path) + + for explorer in os.listdir(src_path): + output_fd = open(os.path.join(dst_path, explorer), mode='w') + cmd = [] + cmd.append("__explorer=" + remote_dst_path) + cmd.append(os.path.join(remote_dst_path, explorer)) + + cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=True) + output_fd.close() + + def deploy_to(self): + """Mimic the old deploy to: Deploy to one host""" + log.info("Deploying to " + self.target_host) + self.stage_prepare() + self.stage_run() + + def deploy_and_cleanup(self): + """Do what is most often done: deploy & cleanup""" + start_time = time.time() + self.deploy_to() + self.cleanup() + log.info("Finished run of %s in %s seconds", + self.target_host, time.time() - start_time) + + def stage_prepare(self): + """Do everything for a deploy, minus the actual code stage""" + self.link_emulator() + self.run_global_explorers() + self.run_initial_manifest() + + 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 cdist.core.Object.list_objects(self.object_base_path, + self.type_base_path): + if cdist_object.prepared: + log.debug("Skipping rerun of object %s", cdist_object) + continue + else: + self.object_prepare(cdist_object) + new_objects_created = True + + def stage_run(self): + """The final (and real) step of deployment""" + log.info("Generating and executing code") + for cdist_object in cdist.core.Object.list_objects(self.object_base_path, + self.type_base_path): + log.debug("Run object: %s", cdist_object) + self.object_run(cdist_object) + + def transfer_object_parameter(self, cdist_object): + """Transfer the object parameter to the remote destination""" + src = os.path.join(self.object_base_path, + cdist_object.parameter_path) + dst = os.path.join(self.remote_object_path, + cdist_object.parameter_path) + + # Synchronise parameter dir afterwards + self.remote_mkdir(dst) + self.transfer_path(src, dst) + + def transfer_global_explorers(self): + """Transfer the global explorers""" + self.remote_mkdir(self.remote_global_explorer_path) + self.transfer_path(self.global_explorer_path, + self.remote_global_explorer_path) + + def transfer_type_explorers(self, cdist_type): + """Transfer explorers of a type, but only once""" + if cdist_type.transferred_explorers: + log.debug("Skipping retransfer for explorers of %s", cdist_type) + return + else: + log.debug("Ensure no retransfer for %s", cdist_type) + # Do not retransfer + cdist_type.transferred_explorers = True + + explorers = cdist_type.explorers + + if len(explorers) > 0: + rel_path = cdist_type.explorer_path + src = os.path.join(self.type_base_path, rel_path) + dst = os.path.join(self.remote_type_path, rel_path) + + # Ensure full path until type exists: + # /var/lib/cdist/conf/type/__directory/explorer + # /var/lib/cdist/conf/type/__directory may not exist, + # but remote_mkdir uses -p to fix this + self.remote_mkdir(dst) + self.transfer_path(src, dst) + + def remote_mkdir(self, directory): + """Create directory on remote side""" + cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) + + def remove_remote_path(self, destination): + """Ensure path on remote side vanished""" + cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) + + def transfer_path(self, source, destination): + """Transfer directory and previously delete the remote destination""" + self.remove_remote_path(destination) + cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + + ["-r", source, self.target_host + ":" + destination]) From 2c6c9bcab5d9f80be60ffd43357a86e79385d9e3 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 15:44:31 +0200 Subject: [PATCH 0729/4212] Object handles its explorers itself Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 76634a65..b7890eeb 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -81,6 +81,7 @@ class Object(object): """define equality as 'attributes are the same'""" return self.__dict__ == other.__dict__ + # FIXME: still needed? @property def explorer_path(self): """Create and return the relative path to this objects explorers""" @@ -93,6 +94,7 @@ class Object(object): requirements = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'require')) parameters = fsproperty.DirectoryDictProperty(lambda obj: os.path.join(obj.absolute_path, 'parameter')) + 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")) prepared = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "prepared")) ran = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "ran")) From d03f23129b0970719c91cb0366e64a9056b054c7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 15:45:10 +0200 Subject: [PATCH 0730/4212] test and fixtures for Object explorers Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 13 +++++++++++++ .../object/__third/moon/.cdist/explorer/.keep | 0 2 files changed, 13 insertions(+) delete mode 100644 lib/cdist/test/object/fixtures/object/__third/moon/.cdist/explorer/.keep diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index decf67bf..6f26fd19 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -92,6 +92,19 @@ class ObjectTestCase(unittest.TestCase): expected_parameters = {'planet': 'Saturn', 'name': 'Prometheus'} self.assertEqual(self.cdist_object.parameters, expected_parameters) + def test_explorers(self): + self.assertEqual(self.cdist_object.explorers, {}) + + def test_explorers_after_changing(self): + expected = {'first': 'foo', 'second': 'bar'} + # when set, written to file + self.cdist_object.explorers = expected + # when accessed, read from file + self.assertEqual(self.cdist_object.explorers, expected) + # remove dynamically created folder + self.cdist_object.explorers = {} + os.rmdir(os.path.join(self.cdist_object.base_path, self.cdist_object.explorer_path)) + def test_requirements(self): expected = [] self.assertEqual(list(self.cdist_object.requirements), expected) diff --git a/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/explorer/.keep b/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/explorer/.keep deleted file mode 100644 index e69de29b..00000000 From d9d9e6bff6660602b034ea1eba230056ef90c60b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 15:47:32 +0200 Subject: [PATCH 0731/4212] move back transfer stuff to exec Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 45 +++++++++++++++++++++++++------------ lib/cdist/exec.py | 20 +++++++++++++++++ 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 418f9fd9..7214cdba 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -270,6 +270,33 @@ class ConfigInstall: cdist_object.ran = True def run_type_explorer(self, cdist_object): + + def run_type_explorer(self, cdist_object, remote_global_explorer_path, remote_type_path, remote_object_path, scp-hints, ssh-hints, object_base_path): + + def __init__(self, remote_global_explorer_path, remote_type_path, remote_object_path, exec-hint, object_base_path, global_explorer_out_path): + + def __init__(self, remote_global_explorer_path, remote_type_path, remote_object_path, exec-hint): + + def run_type_explorer(self, cdist_object) + + self.value = .,.. + return value + + def run_global_explorer(self) + + def __init__(self, remote_global_explorer_path, remote_type_path, remote_object_path, exec-hint): + == 1x + + + + + run_type_explorer() + self.instance.value[obej + + c = ConfigInstall("foo") + c.remote_global_explorer_path = "moo" + + def run_type_explorer(self, cdist_object) """Run type specific explorers for objects""" cdist_type = cdist_object.type @@ -301,6 +328,8 @@ class ConfigInstall: cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=True) output_fd.close() + return outputs + def link_emulator(self): """Link emulator to types""" src = os.path.abspath(self.exec_path) @@ -311,6 +340,8 @@ class ConfigInstall: # FIXME: handle exception / make it more beautiful / Steven: raise except :-) os.symlink(src, dst) + def run_global_explorers(src_path, dst_path, remote_dst_path): + def run_global_explorers(self): """Run global explorers""" log.info("Running global explorers") @@ -413,17 +444,3 @@ class ConfigInstall: # but remote_mkdir uses -p to fix this self.remote_mkdir(dst) self.transfer_path(src, dst) - - def remote_mkdir(self, directory): - """Create directory on remote side""" - cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) - - def remove_remote_path(self, destination): - """Ensure path on remote side vanished""" - cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) - - def transfer_path(self, source, destination): - """Transfer directory and previously delete the remote destination""" - self.remove_remote_path(destination) - cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + - ["-r", source, self.target_host + ":" + destination]) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index 63a3dfa3..7ec9bc0a 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -27,6 +27,10 @@ log = logging.getLogger(__name__) import cdist +class ExecWrapper(object): + def __init__(self, remote_exec, remote_copy, target_host): + self.remote_exec = remote_exec + def shell_run_or_debug_fail(script, *args, remote_prefix=False, **kargs): # Manually execute /bin/sh, because sh -e does what we want # and sh -c -e does not exit if /bin/false called @@ -75,3 +79,19 @@ def run_or_fail(*args, remote_prefix=False, **kargs): raise cdist.Error("Command failed: " + " ".join(*args)) except OSError as error: raise cdist.Error(" ".join(*args) + ": " + error.args[1]) + + + + def remote_mkdir(self, directory): + """Create directory on remote side""" + cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) + + def remove_remote_path(self, destination): + """Ensure path on remote side vanished""" + cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) + + def transfer_path(self, source, destination): + """Transfer directory and previously delete the remote destination""" + self.remove_remote_path(destination) + cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + + ["-r", source, self.target_host + ":" + destination]) From 8a327b6bc73fcdb303f6f40a1afc1a9d1888fa4a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 15:50:50 +0200 Subject: [PATCH 0732/4212] cleanup explorer Signed-off-by: Nico Schottelius --- lib/cdist/explorer.py | 368 ++++-------------------------------------- 1 file changed, 32 insertions(+), 336 deletions(-) diff --git a/lib/cdist/explorer.py b/lib/cdist/explorer.py index 3cd1b949..e2c41f8a 100644 --- a/lib/cdist/explorer.py +++ b/lib/cdist/explorer.py @@ -20,281 +20,36 @@ # # +import io import logging -import os -import stat -import shutil -import sys -import tempfile -import time - -import cdist.core -import cdist.exec +#import os +#import stat +#import shutil +#import sys +#import tempfile +#import time +# +#import cdist.core +#import cdist.exec log = logging.getLogger(__name__) -CODE_HEADER = "#!/bin/sh -e\n" +class Explorer: + """Execute explorers""" -class ConfigInstall: - """Cdist main class to hold arbitrary data""" + def __init__(self, + object_base_path, + remote_global_explorer_path, + remote_type_path, + remote_object_path, + type_path, + exec_hint): - def __init__(self, - target_host, - initial_manifest=False, - base_path=False, - exec_path=sys.argv[0], - debug=False): - - self.target_host = target_host - - self.debug = debug - - # Only required for testing - self.exec_path = exec_path - - # Configure logging - log.addFilter(self) - - # Base and Temp Base - self.base_path = (base_path or - self.base_path = os.path.abspath(os.path.join( - os.path.dirname(__file__), os.pardir, os.pardir)) - - # Local input - self.cache_path = os.path.join(self.base_path, "cache", - self.target_host) - self.conf_path = os.path.join(self.base_path, "conf") - - self.global_explorer_path = os.path.join(self.conf_path, "explorer") - self.manifest_path = os.path.join(self.conf_path, "manifest") - self.type_base_path = os.path.join(self.conf_path, "type") - self.lib_path = os.path.join(self.base_path, "lib") - - self.initial_manifest = (initial_manifest or - os.path.join(self.manifest_path, "init")) - - # Local output - if '__cdist_out_dir' in os.environ: - self.out_path = os.environ['__cdist_out_dir'] - else: - self.out_path = os.path.join(tempfile.mkdtemp(), "out") - self.bin_path = os.path.join(self.out_path, "bin") - self.global_explorer_out_path = os.path.join(self.out_path, "explorer") - self.object_base_path = os.path.join(self.out_path, "object") - - # Remote directory base - if '__cdist_remote_out_dir' in os.environ: - self.remote_base_path = os.environ['__cdist_remote_out_dir'] - else: - self.remote_base_path = "/var/lib/cdist" - - self.remote_conf_path = os.path.join(self.remote_base_path, "conf") - self.remote_object_path = os.path.join(self.remote_base_path, "object") - - self.remote_type_path = os.path.join(self.remote_conf_path, "type") - self.remote_global_explorer_path = os.path.join(self.remote_conf_path, "explorer") - - # Setup env to be used by others - self.__init_env() - - # Create directories - self.__init_local_paths() - self.__init_remote_paths() - - - def __init_remote_paths(self): - """Initialise remote directory structure""" - self.remove_remote_path(self.remote_base_path) - self.remote_mkdir(self.remote_base_path) - self.remote_mkdir(self.remote_conf_path) - - def __init_local_paths(self): - """Initialise local directory structure""" - - # Create base dir, if user supplied and not existing - if not os.path.isdir(self.base_path): - os.mkdir(self.base_path) - - # FIXME: raise more beautiful exception / Steven: handle exception - os.mkdir(self.out_path) - os.mkdir(self.global_explorer_out_path) - os.mkdir(self.bin_path) - - def __init_env(self): - """Environment usable for other stuff""" - os.environ['__target_host'] = self.target_host - if self.debug: - os.environ['__debug'] = "yes" - - - def cleanup(self): - # Do not use in __del__: - # http://docs.python.org/reference/datamodel.html#customization - # "other globals referenced by the __del__() method may already have been deleted - # or in the process of being torn down (e.g. the import machinery shutting down)" - # - log.debug("Saving " + self.out_path + " to " + self.cache_path) - # FIXME: raise more beautiful exception / Steven: handle exception - # Remove previous cache - if os.path.exists(self.cache_path): - shutil.rmtree(self.cache_path) - shutil.move(self.out_path, self.cache_path) - - def filter(self, record): - """Add hostname to logs via logging Filter""" - - record.msg = self.target_host + ": " + record.msg - - return True - - def run_initial_manifest(self): - """Run the initial manifest""" - log.info("Running initial manifest %s", self.initial_manifest) - env = { "__manifest" : self.manifest_path } - self.run_manifest(self.initial_manifest, extra_env=env) - - def run_type_manifest(self, cdist_object): - """Run manifest for a specific object""" - cdist_type = cdist_object.type - manifest_path = os.path.join(self.type_base_path, - cdist_type.manifest_path) - - log.debug("%s: Running %s", cdist_object.name, manifest_path) - if os.path.exists(manifest_path): - env = { "__object" : os.path.join(self.object_base_path, - cdist_object.path), - "__object_id": cdist_object.object_id, - "__object_fq": cdist_object.name, - "__type": os.path.join(self.type_base_path, - cdist_type.path) - } - self.run_manifest(manifest_path, extra_env=env) - - def run_manifest(self, manifest_path, extra_env=None): - """Run a manifest""" - log.debug("Running manifest %s, env=%s", manifest_path, extra_env) - env = os.environ.copy() - env['PATH'] = self.bin_path + ":" + env['PATH'] - - # Information required in every manifest - env['__target_host'] = self.target_host - env['__global'] = self.out_path - - # Required for recording source in emulator - env['__cdist_manifest'] = manifest_path - - # Required to find types in emulator - env['__cdist_type_base_path'] = self.type_base_path - - # Other environment stuff - if extra_env: - env.update(extra_env) - - cdist.exec.shell_run_or_debug_fail(manifest_path, [manifest_path], env=env) - - def object_prepare(self, cdist_object): - """Prepare object: Run type explorer + manifest""" - log.debug("Preparing object: " + cdist_object.name) - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) - cdist_object.prepared = True - - def object_run(self, cdist_object): - """Run gencode and code for an object""" - log.debug("Running object %s", cdist_object) - - # Catch requirements, which re-call us - if cdist_object.ran: - return - - cdist_type = cdist_object.type - - for requirement in cdist_object.requirements: - log.debug("Object %s requires %s", cdist_object, requirement) - self.object_run(requirement) - - # - # Setup env Variable: - # - env = os.environ.copy() - env['__target_host'] = self.target_host - env['__global'] = self.out_path - env["__object"] = os.path.join(self.object_base_path, cdist_object.path) - env["__object_id"] = cdist_object.object_id - env["__object_fq"] = cdist_object.name - env["__type"] = cdist_type.name - - # gencode - for cmd in ["local", "remote"]: - bin = os.path.join(self.type_base_path, - getattr(cdist_type, "gencode_" + cmd + "_path")) - - if os.path.isfile(bin): - outfile = os.path.join(self.object_base_path, - getattr(cdist_object, "code_" + cmd + "_path")) - - outfile_fd = open(outfile, "w") - - # Need to flush to ensure our write is done before stdout write - # FIXME: code header still needed? - outfile_fd.write(CODE_HEADER) - outfile_fd.flush() - - cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) - outfile_fd.close() - - status = os.stat(outfile) - - # Remove output if empty, else make it executable - if status.st_size == len(CODE_HEADER): - os.unlink(outfile) - else: - # Add header and make executable - identically to 0o700 - os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) - cdist_object.changed=True - - # code local - code_local = cdist_object.code_local_path - if os.path.isfile(code_local): - cdist.exec.run_or_fail([code_local]) - - # code remote - local_remote_code = os.path.join(self.object_base_path, - cdist_object.code_remote_path) - remote_remote_code = os.path.join(self.remote_object_path, - cdist_object.code_remote_path) - if os.path.isfile(local_remote_code): - self.transfer_path(local_remote_code, remote_remote_code) - cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) - - cdist_object.ran = True - - def run_type_explorer(self, cdist_object): - - def run_type_explorer(self, cdist_object, remote_global_explorer_path, remote_type_path, remote_object_path, scp-hints, ssh-hints, object_base_path): - - def __init__(self, remote_global_explorer_path, remote_type_path, remote_object_path, exec-hint, object_base_path, global_explorer_out_path): - - def __init__(self, remote_global_explorer_path, remote_type_path, remote_object_path, exec-hint): - - def run_type_explorer(self, cdist_object) - - self.value = .,.. - return value - - def run_global_explorer(self) - - def __init__(self, remote_global_explorer_path, remote_type_path, remote_object_path, exec-hint): - == 1x - - - - - run_type_explorer() - self.instance.value[obej - - c = ConfigInstall("foo") - c.remote_global_explorer_path = "moo" + self.object_base_path = object_base_path + self.remote_global_explorer_path = remote_global_explorer_path + self.remote_type_path = remote_type_path + self.remote_object_path = remote_object_path + self.exec_hint = exec_hint def run_type_explorer(self, cdist_object) """Run type specific explorers for objects""" @@ -316,93 +71,34 @@ class ConfigInstall: # Need to transfer at least the parameters for objects to be useful self.transfer_object_parameter(cdist_object) + outputs = {} for explorer in cdist_type.explorers: remote_cmd = cmd + [os.path.join(self.remote_type_path, cdist_type.explorer_path, explorer)] - output = os.path.join(self.object_base_path, - cdist_object.explorer_path, explorer) - output_fd = open(output, mode='w') + outputs[explorer] = io.StringIO() log.debug("%s exploring %s using %s storing to %s", cdist_object, explorer, remote_cmd, output) - cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=True) - output_fd.close() + cdist.exec.run_or_fail(remote_cmd, stdout=outputs[explorer], remote_prefix=True) return outputs - def link_emulator(self): - """Link emulator to types""" - src = os.path.abspath(self.exec_path) - for cdist_type in cdist.core.Type.list_types(self.type_base_path): - dst = os.path.join(self.bin_path, cdist_type.name) - log.debug("Linking emulator: %s to %s", src, dst) - - # FIXME: handle exception / make it more beautiful / Steven: raise except :-) - os.symlink(src, dst) - - def run_global_explorers(src_path, dst_path, remote_dst_path): - def run_global_explorers(self): """Run global explorers""" log.info("Running global explorers") src_path = self.global_explorer_path - dst_path = self.global_explorer_out_path - remote_dst_path = self.remote_global_explorer_path + dst_path = self.remote_global_explorer_path - self.transfer_path(src_path, remote_dst_path) + self.transfer_path(src_path, dst_path) + outputs = {} for explorer in os.listdir(src_path): - output_fd = open(os.path.join(dst_path, explorer), mode='w') + outputs[explorer] = io.StringIO() cmd = [] cmd.append("__explorer=" + remote_dst_path) cmd.append(os.path.join(remote_dst_path, explorer)) - - cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=True) - output_fd.close() - - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to " + self.target_host) - self.stage_prepare() - self.stage_run() - - def deploy_and_cleanup(self): - """Do what is most often done: deploy & cleanup""" - start_time = time.time() - self.deploy_to() - self.cleanup() - log.info("Finished run of %s in %s seconds", - self.target_host, time.time() - start_time) - - def stage_prepare(self): - """Do everything for a deploy, minus the actual code stage""" - self.link_emulator() - self.run_global_explorers() - self.run_initial_manifest() - - 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 cdist.core.Object.list_objects(self.object_base_path, - self.type_base_path): - if cdist_object.prepared: - log.debug("Skipping rerun of object %s", cdist_object) - continue - else: - self.object_prepare(cdist_object) - new_objects_created = True - - def stage_run(self): - """The final (and real) step of deployment""" - log.info("Generating and executing code") - for cdist_object in cdist.core.Object.list_objects(self.object_base_path, - self.type_base_path): - log.debug("Run object: %s", cdist_object) - self.object_run(cdist_object) + cdist.exec.run_or_fail(cmd, stdout=outputs[explorer], remote_prefix=True) def transfer_object_parameter(self, cdist_object): """Transfer the object parameter to the remote destination""" From 5bd23d06058ce9c6c93612d7ed18e5ebe8ae3351 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 15:59:26 +0200 Subject: [PATCH 0733/4212] template for context (REDO) Signed-off-by: Nico Schottelius --- lib/cdist/context.py | 328 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 lib/cdist/context.py diff --git a/lib/cdist/context.py b/lib/cdist/context.py new file mode 100644 index 00000000..523adda0 --- /dev/null +++ b/lib/cdist/context.py @@ -0,0 +1,328 @@ +#!/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 logging +import os +import stat +import shutil +import sys +import tempfile +import time + +import cdist.core +import cdist.exec + +log = logging.getLogger(__name__) + +CODE_HEADER = "#!/bin/sh -e\n" + +class ConfigInstall: + """Cdist main class to hold arbitrary data""" + + def __init__(self, + target_host, + initial_manifest=False, + base_path=False, + exec_path=sys.argv[0], + debug=False): + + self.target_host = target_host + + self.debug = debug + + # Only required for testing + self.exec_path = exec_path + + self.exec_wrapper = cdist.exec.Wrapper( + targe_host = self.target_host, + remote_exec=os.environ['__remote_exec'].split(), + remote_copy=os.environ['__remote_copy'].split() + ) + + # Configure logging - FIXME: make available for others + log.addFilter(self) + + # Base and Temp Base + self.base_path = (base_path or + self.base_path = os.path.abspath(os.path.join( + os.path.dirname(__file__), os.pardir, os.pardir)) + + # Local input + self.cache_path = os.path.join(self.base_path, "cache", + self.target_host) + self.conf_path = os.path.join(self.base_path, "conf") + + self.global_explorer_path = os.path.join(self.conf_path, "explorer") + self.manifest_path = os.path.join(self.conf_path, "manifest") + self.type_base_path = os.path.join(self.conf_path, "type") + self.lib_path = os.path.join(self.base_path, "lib") + + self.initial_manifest = (initial_manifest or + os.path.join(self.manifest_path, "init")) + + # Local output + if '__cdist_out_dir' in os.environ: + self.out_path = os.environ['__cdist_out_dir'] + else: + self.out_path = os.path.join(tempfile.mkdtemp(), "out") + self.bin_path = os.path.join(self.out_path, "bin") + self.global_explorer_out_path = os.path.join(self.out_path, "explorer") + self.object_base_path = os.path.join(self.out_path, "object") + + # Remote directory base + if '__cdist_remote_out_dir' in os.environ: + self.remote_base_path = os.environ['__cdist_remote_out_dir'] + else: + self.remote_base_path = "/var/lib/cdist" + + self.remote_conf_path = os.path.join(self.remote_base_path, "conf") + self.remote_object_path = os.path.join(self.remote_base_path, "object") + + self.remote_type_path = os.path.join(self.remote_conf_path, "type") + self.remote_global_explorer_path = os.path.join(self.remote_conf_path, "explorer") + + # Setup env to be used by others + self.__init_env() + + # Create directories + self.__init_local_paths() + self.__init_remote_paths() + + + def __init_remote_paths(self): + """Initialise remote directory structure""" + self.remove_remote_path(self.remote_base_path) + self.remote_mkdir(self.remote_base_path) + self.remote_mkdir(self.remote_conf_path) + + def __init_local_paths(self): + """Initialise local directory structure""" + + # Create base dir, if user supplied and not existing + if not os.path.isdir(self.base_path): + os.mkdir(self.base_path) + + # FIXME: raise more beautiful exception / Steven: handle exception + os.mkdir(self.out_path) + os.mkdir(self.global_explorer_out_path) + os.mkdir(self.bin_path) + + def __init_env(self): + """Environment usable for other stuff""" + os.environ['__target_host'] = self.target_host + if self.debug: + os.environ['__debug'] = "yes" + + def cleanup(self): + # Do not use in __del__: + # http://docs.python.org/reference/datamodel.html#customization + # "other globals referenced by the __del__() method may already have been deleted + # or in the process of being torn down (e.g. the import machinery shutting down)" + # + log.debug("Saving " + self.out_path + " to " + self.cache_path) + # FIXME: raise more beautiful exception / Steven: handle exception + # Remove previous cache + if os.path.exists(self.cache_path): + shutil.rmtree(self.cache_path) + shutil.move(self.out_path, self.cache_path) + + def filter(self, record): + """Add hostname to logs via logging Filter""" + + record.msg = self.target_host + ": " + record.msg + + return True + + def run_initial_manifest(self): + """Run the initial manifest""" + log.info("Running initial manifest %s", self.initial_manifest) + env = { "__manifest" : self.manifest_path } + self.run_manifest(self.initial_manifest, extra_env=env) + + def run_type_manifest(self, cdist_object): + """Run manifest for a specific object""" + cdist_type = cdist_object.type + manifest_path = os.path.join(self.type_base_path, + cdist_type.manifest_path) + + log.debug("%s: Running %s", cdist_object.name, manifest_path) + if os.path.exists(manifest_path): + env = { "__object" : os.path.join(self.object_base_path, + cdist_object.path), + "__object_id": cdist_object.object_id, + "__object_fq": cdist_object.name, + "__type": os.path.join(self.type_base_path, + cdist_type.path) + } + self.run_manifest(manifest_path, extra_env=env) + + def run_manifest(self, manifest_path, extra_env=None): + """Run a manifest""" + log.debug("Running manifest %s, env=%s", manifest_path, extra_env) + env = os.environ.copy() + env['PATH'] = self.bin_path + ":" + env['PATH'] + + # Information required in every manifest + env['__target_host'] = self.target_host + env['__global'] = self.out_path + + # Required for recording source in emulator + env['__cdist_manifest'] = manifest_path + + # Required to find types in emulator + env['__cdist_type_base_path'] = self.type_base_path + + # Other environment stuff + if extra_env: + env.update(extra_env) + + cdist.exec.shell_run_or_debug_fail(manifest_path, [manifest_path], env=env) + + def object_prepare(self, cdist_object): + """Prepare object: Run type explorer + manifest""" + log.debug("Preparing object: " + cdist_object.name) + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + cdist_object.prepared = True + + def object_run(self, cdist_object): + """Run gencode and code for an object""" + log.debug("Running object %s", cdist_object) + + # Catch requirements, which re-call us + if cdist_object.ran: + return + + cdist_type = cdist_object.type + + for requirement in cdist_object.requirements: + log.debug("Object %s requires %s", cdist_object, requirement) + self.object_run(requirement) + + # + # Setup env Variable: + # + env = os.environ.copy() + env['__target_host'] = self.target_host + env['__global'] = self.out_path + env["__object"] = os.path.join(self.object_base_path, cdist_object.path) + env["__object_id"] = cdist_object.object_id + env["__object_fq"] = cdist_object.name + env["__type"] = cdist_type.name + + # gencode + for cmd in ["local", "remote"]: + bin = os.path.join(self.type_base_path, + getattr(cdist_type, "gencode_" + cmd + "_path")) + + if os.path.isfile(bin): + outfile = os.path.join(self.object_base_path, + getattr(cdist_object, "code_" + cmd + "_path")) + + outfile_fd = open(outfile, "w") + + # Need to flush to ensure our write is done before stdout write + # FIXME: code header still needed? + outfile_fd.write(CODE_HEADER) + outfile_fd.flush() + + cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) + outfile_fd.close() + + status = os.stat(outfile) + + # Remove output if empty, else make it executable + if status.st_size == len(CODE_HEADER): + os.unlink(outfile) + else: + # Add header and make executable - identically to 0o700 + os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + cdist_object.changed=True + + # code local + code_local = cdist_object.code_local_path + if os.path.isfile(code_local): + cdist.exec.run_or_fail([code_local]) + + # code remote + local_remote_code = os.path.join(self.object_base_path, + cdist_object.code_remote_path) + remote_remote_code = os.path.join(self.remote_object_path, + cdist_object.code_remote_path) + if os.path.isfile(local_remote_code): + self.transfer_path(local_remote_code, remote_remote_code) + cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) + + cdist_object.ran = True + + def link_emulator(self): + """Link emulator to types""" + src = os.path.abspath(self.exec_path) + for cdist_type in cdist.core.Type.list_types(self.type_base_path): + dst = os.path.join(self.bin_path, cdist_type.name) + log.debug("Linking emulator: %s to %s", src, dst) + + # FIXME: handle exception / make it more beautiful / Steven: raise except :-) + os.symlink(src, dst) + + def deploy_to(self): + """Mimic the old deploy to: Deploy to one host""" + log.info("Deploying to " + self.target_host) + self.stage_prepare() + self.stage_run() + + def deploy_and_cleanup(self): + """Do what is most often done: deploy & cleanup""" + start_time = time.time() + self.deploy_to() + self.cleanup() + log.info("Finished run of %s in %s seconds", + self.target_host, time.time() - start_time) + + def stage_prepare(self): + """Do everything for a deploy, minus the actual code stage""" + self.link_emulator() + self.run_global_explorers() + self.run_initial_manifest() + + 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 cdist.core.Object.list_objects(self.object_base_path, + self.type_base_path): + if cdist_object.prepared: + log.debug("Skipping rerun of object %s", cdist_object) + continue + else: + self.object_prepare(cdist_object) + new_objects_created = True + + def stage_run(self): + """The final (and real) step of deployment""" + log.info("Generating and executing code") + for cdist_object in cdist.core.Object.list_objects(self.object_base_path, + self.type_base_path): + log.debug("Run object: %s", cdist_object) + self.object_run(cdist_object) From 0397e77a3ec79900675ed61c45581e70c64cca38 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:04:09 +0200 Subject: [PATCH 0734/4212] cleanup context Signed-off-by: Nico Schottelius --- lib/cdist/context.py | 233 ++----------------------------------------- 1 file changed, 11 insertions(+), 222 deletions(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index 523adda0..240593db 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -22,43 +22,31 @@ import logging import os -import stat -import shutil -import sys -import tempfile -import time - -import cdist.core -import cdist.exec +#import stat +#import shutil +#import sys +#import tempfile +#import time +# +#import cdist.core +#import cdist.exec log = logging.getLogger(__name__) -CODE_HEADER = "#!/bin/sh -e\n" - -class ConfigInstall: - """Cdist main class to hold arbitrary data""" +class Context: + """Hold information about current context""" def __init__(self, target_host, initial_manifest=False, base_path=False, - exec_path=sys.argv[0], - debug=False): + exec_path=sys.argv[0]): self.target_host = target_host - self.debug = debug - # Only required for testing self.exec_path = exec_path - self.exec_wrapper = cdist.exec.Wrapper( - targe_host = self.target_host, - remote_exec=os.environ['__remote_exec'].split(), - remote_copy=os.environ['__remote_copy'].split() - ) - - # Configure logging - FIXME: make available for others log.addFilter(self) # Base and Temp Base @@ -108,30 +96,6 @@ class ConfigInstall: self.__init_remote_paths() - def __init_remote_paths(self): - """Initialise remote directory structure""" - self.remove_remote_path(self.remote_base_path) - self.remote_mkdir(self.remote_base_path) - self.remote_mkdir(self.remote_conf_path) - - def __init_local_paths(self): - """Initialise local directory structure""" - - # Create base dir, if user supplied and not existing - if not os.path.isdir(self.base_path): - os.mkdir(self.base_path) - - # FIXME: raise more beautiful exception / Steven: handle exception - os.mkdir(self.out_path) - os.mkdir(self.global_explorer_out_path) - os.mkdir(self.bin_path) - - def __init_env(self): - """Environment usable for other stuff""" - os.environ['__target_host'] = self.target_host - if self.debug: - os.environ['__debug'] = "yes" - def cleanup(self): # Do not use in __del__: # http://docs.python.org/reference/datamodel.html#customization @@ -151,178 +115,3 @@ class ConfigInstall: record.msg = self.target_host + ": " + record.msg return True - - def run_initial_manifest(self): - """Run the initial manifest""" - log.info("Running initial manifest %s", self.initial_manifest) - env = { "__manifest" : self.manifest_path } - self.run_manifest(self.initial_manifest, extra_env=env) - - def run_type_manifest(self, cdist_object): - """Run manifest for a specific object""" - cdist_type = cdist_object.type - manifest_path = os.path.join(self.type_base_path, - cdist_type.manifest_path) - - log.debug("%s: Running %s", cdist_object.name, manifest_path) - if os.path.exists(manifest_path): - env = { "__object" : os.path.join(self.object_base_path, - cdist_object.path), - "__object_id": cdist_object.object_id, - "__object_fq": cdist_object.name, - "__type": os.path.join(self.type_base_path, - cdist_type.path) - } - self.run_manifest(manifest_path, extra_env=env) - - def run_manifest(self, manifest_path, extra_env=None): - """Run a manifest""" - log.debug("Running manifest %s, env=%s", manifest_path, extra_env) - env = os.environ.copy() - env['PATH'] = self.bin_path + ":" + env['PATH'] - - # Information required in every manifest - env['__target_host'] = self.target_host - env['__global'] = self.out_path - - # Required for recording source in emulator - env['__cdist_manifest'] = manifest_path - - # Required to find types in emulator - env['__cdist_type_base_path'] = self.type_base_path - - # Other environment stuff - if extra_env: - env.update(extra_env) - - cdist.exec.shell_run_or_debug_fail(manifest_path, [manifest_path], env=env) - - def object_prepare(self, cdist_object): - """Prepare object: Run type explorer + manifest""" - log.debug("Preparing object: " + cdist_object.name) - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) - cdist_object.prepared = True - - def object_run(self, cdist_object): - """Run gencode and code for an object""" - log.debug("Running object %s", cdist_object) - - # Catch requirements, which re-call us - if cdist_object.ran: - return - - cdist_type = cdist_object.type - - for requirement in cdist_object.requirements: - log.debug("Object %s requires %s", cdist_object, requirement) - self.object_run(requirement) - - # - # Setup env Variable: - # - env = os.environ.copy() - env['__target_host'] = self.target_host - env['__global'] = self.out_path - env["__object"] = os.path.join(self.object_base_path, cdist_object.path) - env["__object_id"] = cdist_object.object_id - env["__object_fq"] = cdist_object.name - env["__type"] = cdist_type.name - - # gencode - for cmd in ["local", "remote"]: - bin = os.path.join(self.type_base_path, - getattr(cdist_type, "gencode_" + cmd + "_path")) - - if os.path.isfile(bin): - outfile = os.path.join(self.object_base_path, - getattr(cdist_object, "code_" + cmd + "_path")) - - outfile_fd = open(outfile, "w") - - # Need to flush to ensure our write is done before stdout write - # FIXME: code header still needed? - outfile_fd.write(CODE_HEADER) - outfile_fd.flush() - - cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) - outfile_fd.close() - - status = os.stat(outfile) - - # Remove output if empty, else make it executable - if status.st_size == len(CODE_HEADER): - os.unlink(outfile) - else: - # Add header and make executable - identically to 0o700 - os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) - cdist_object.changed=True - - # code local - code_local = cdist_object.code_local_path - if os.path.isfile(code_local): - cdist.exec.run_or_fail([code_local]) - - # code remote - local_remote_code = os.path.join(self.object_base_path, - cdist_object.code_remote_path) - remote_remote_code = os.path.join(self.remote_object_path, - cdist_object.code_remote_path) - if os.path.isfile(local_remote_code): - self.transfer_path(local_remote_code, remote_remote_code) - cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) - - cdist_object.ran = True - - def link_emulator(self): - """Link emulator to types""" - src = os.path.abspath(self.exec_path) - for cdist_type in cdist.core.Type.list_types(self.type_base_path): - dst = os.path.join(self.bin_path, cdist_type.name) - log.debug("Linking emulator: %s to %s", src, dst) - - # FIXME: handle exception / make it more beautiful / Steven: raise except :-) - os.symlink(src, dst) - - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to " + self.target_host) - self.stage_prepare() - self.stage_run() - - def deploy_and_cleanup(self): - """Do what is most often done: deploy & cleanup""" - start_time = time.time() - self.deploy_to() - self.cleanup() - log.info("Finished run of %s in %s seconds", - self.target_host, time.time() - start_time) - - def stage_prepare(self): - """Do everything for a deploy, minus the actual code stage""" - self.link_emulator() - self.run_global_explorers() - self.run_initial_manifest() - - 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 cdist.core.Object.list_objects(self.object_base_path, - self.type_base_path): - if cdist_object.prepared: - log.debug("Skipping rerun of object %s", cdist_object) - continue - else: - self.object_prepare(cdist_object) - new_objects_created = True - - def stage_run(self): - """The final (and real) step of deployment""" - log.info("Generating and executing code") - for cdist_object in cdist.core.Object.list_objects(self.object_base_path, - self.type_base_path): - log.debug("Run object: %s", cdist_object) - self.object_run(cdist_object) From d4f6328eefe1fcf8e210583907b0c82623c1dd71 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:05:32 +0200 Subject: [PATCH 0735/4212] finish context Signed-off-by: Nico Schottelius --- lib/cdist/context.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index 240593db..d8d4e5ea 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -31,8 +31,6 @@ import os #import cdist.core #import cdist.exec -log = logging.getLogger(__name__) - class Context: """Hold information about current context""" @@ -47,7 +45,9 @@ class Context: # Only required for testing self.exec_path = exec_path - log.addFilter(self) + # Context logging + self.log = logging.getLogger(__name__) + self.log.addFilter(self) # Base and Temp Base self.base_path = (base_path or @@ -88,14 +88,6 @@ class Context: self.remote_type_path = os.path.join(self.remote_conf_path, "type") self.remote_global_explorer_path = os.path.join(self.remote_conf_path, "explorer") - # Setup env to be used by others - self.__init_env() - - # Create directories - self.__init_local_paths() - self.__init_remote_paths() - - def cleanup(self): # Do not use in __del__: # http://docs.python.org/reference/datamodel.html#customization From e437cd90d66870e299d807442e5da66c962b2b46 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 16:06:21 +0200 Subject: [PATCH 0736/4212] rewrite exec Signed-off-by: Steven Armstrong --- lib/cdist/exec.py | 120 ++++++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 58 deletions(-) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index 7ec9bc0a..b3b86a52 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -23,75 +23,79 @@ import logging import os import subprocess -log = logging.getLogger(__name__) - import cdist -class ExecWrapper(object): - def __init__(self, remote_exec, remote_copy, target_host): +log = logging.getLogger(__name__) + + +class Wrapper(object): + def __init__(self, target_host, remote_exec, remote_copy): + self.target_host = target_host self.remote_exec = remote_exec - -def shell_run_or_debug_fail(script, *args, remote_prefix=False, **kargs): - # Manually execute /bin/sh, because sh -e does what we want - # and sh -c -e does not exit if /bin/false called - args[0][:0] = [ "/bin/sh", "-e" ] - - if remote_prefix: - remote_prefix = os.environ['__remote_exec'].split() - remote_prefix.append(os.environ['__target_host']) - args[0][:0] = remote_prefix - - log.debug("Shell exec cmd: %s", args) - - if 'env' in kargs: - log.debug("Shell exec env: %s", kargs['env']) - - try: - subprocess.check_call(*args, **kargs) - except subprocess.CalledProcessError: - log.error("Code that raised the error:\n") - - if remote_prefix: - run_or_fail(["cat", script], remote_prefix=remote_prefix) - - else: - try: - script_fd = open(script) - print(script_fd.read()) - script_fd.close() - except IOError as error: - raise cdist.Error(str(error)) - - raise cdist.Error("Command failed (shell): " + " ".join(*args)) - except OSError as error: - raise cdist.Error(" ".join(*args) + ": " + error.args[1]) - -def run_or_fail(*args, remote_prefix=False, **kargs): - if remote_prefix: - remote_prefix = os.environ['__remote_exec'].split() - remote_prefix.append(os.environ['__target_host']) - args[0][:0] = remote_prefix - - log.debug("Exec: " + " ".join(*args)) - try: - subprocess.check_call(*args, **kargs) - except subprocess.CalledProcessError: - raise cdist.Error("Command failed: " + " ".join(*args)) - except OSError as error: - raise cdist.Error(" ".join(*args) + ": " + error.args[1]) - - + self.remote_copy = remote_copy def remote_mkdir(self, directory): """Create directory on remote side""" - cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) + self.run_or_fail(["mkdir", "-p", directory], remote=True) def remove_remote_path(self, destination): """Ensure path on remote side vanished""" - cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) + self.run_or_fail(["rm", "-rf", destination], remote=True) def transfer_path(self, source, destination): """Transfer directory and previously delete the remote destination""" self.remove_remote_path(destination) - cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + + self.run_or_fail(os.environ['__remote_copy'].split() + ["-r", source, self.target_host + ":" + destination]) + + def shell_run_or_debug_fail(self, script, *args, remote=False, **kargs): + # Manually execute /bin/sh, because sh -e does what we want + # and sh -c -e does not exit if /bin/false called + args[0][:0] = [ "/bin/sh", "-e" ] + + if remote: + remote_prefix = self.remote_exec.split() + remote_prefix.append(self.target_host) + args[0][:0] = remote_prefix + + log.debug("Shell exec cmd: %s", args) + + if 'env' in kargs: + log.debug("Shell exec env: %s", kargs['env']) + + try: + subprocess.check_call(*args, **kargs) + except subprocess.CalledProcessError: + log.error("Code that raised the error:\n") + + if remote: + self.run_or_fail(["cat", script], remote=remote) + + else: + try: + script_fd = open(script) + print(script_fd.read()) + script_fd.close() + except IOError as error: + raise cdist.Error(str(error)) + + raise cdist.Error("Command failed (shell): " + " ".join(*args)) + except OSError as error: + raise cdist.Error(" ".join(*args) + ": " + error.args[1]) + + def run_or_fail(self, *args, remote=False, **kargs): + if remote: + remote_prefix = self.remote_exec.split() + remote_prefix.append(self.target_host) + args[0][:0] = remote_prefix + + log.debug("Exec: " + " ".join(*args)) + try: + subprocess.check_call(*args, **kargs) + except subprocess.CalledProcessError: + raise cdist.Error("Command failed: " + " ".join(*args)) + except OSError as error: + raise cdist.Error(" ".join(*args) + ": " + error.args[1]) + + + From 4c29d9839b64f3a4ff7ec3e800b578bfa3ee3111 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:19:27 +0200 Subject: [PATCH 0737/4212] configure logger based on hostname Signed-off-by: Nico Schottelius --- bin/cdist | 4 ---- lib/cdist/context.py | 13 ++++++++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/bin/cdist b/bin/cdist index 50e66697..ac863e9e 100755 --- a/bin/cdist +++ b/bin/cdist @@ -114,10 +114,6 @@ def configinstall(args, mode): time_start = time.time() - # FIXME: do not overwrite, if set! - os.environ['__remote_exec'] = "ssh -o User=root -q" - os.environ['__remote_copy'] = "scp -o User=root -q" - for host in args.host: c = mode(host, initial_manifest=args.manifest, diff --git a/lib/cdist/context.py b/lib/cdist/context.py index d8d4e5ea..f1cd4c14 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -38,7 +38,8 @@ class Context: target_host, initial_manifest=False, base_path=False, - exec_path=sys.argv[0]): + exec_path=sys.argv[0], + debug): self.target_host = target_host @@ -88,6 +89,16 @@ class Context: self.remote_type_path = os.path.join(self.remote_conf_path, "type") self.remote_global_explorer_path = os.path.join(self.remote_conf_path, "explorer") + if '__remote_exec' in os.environ: + self.remote_exec = os.environ['__remote_exec'] + else: + self.remote_exec = "ssh -o User=root -q" + + if '__remote_copy' in os.environ: + self.remote_copy = os.environ['__remote_copy'] + else: + self.remote_copy = "scp -o User=root -q" + def cleanup(self): # Do not use in __del__: # http://docs.python.org/reference/datamodel.html#customization From c28fd5bbfdef3e0fc264e43249a02bea560e332b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:22:44 +0200 Subject: [PATCH 0738/4212] add template for manifest for sar / steven to have fun Signed-off-by: Nico Schottelius --- lib/cdist/manifest.py | 272 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 lib/cdist/manifest.py diff --git a/lib/cdist/manifest.py b/lib/cdist/manifest.py new file mode 100644 index 00000000..ab5f7284 --- /dev/null +++ b/lib/cdist/manifest.py @@ -0,0 +1,272 @@ +#!/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 logging +import os +import stat +import shutil +import sys +import tempfile +import time + +import cdist.core +import cdist.exec + +CODE_HEADER = "#!/bin/sh -e\n" + +class ConfigInstall: + """Cdist main class to hold arbitrary data""" + + def __init__(self, + target_host, + initial_manifest=False, + base_path=False, + exec_path=sys.argv[0], + debug=False): + + self.context = cdist.context.Context( + target_host=target_host, + initial_manifest=initial_manifest, + base_path=base_path, + exec_path=sys.argv[0], + debug=debug) + + + + self.exec_wrapper = cdist.exec.Wrapper( + targe_host = self.target_host, + remote_exec=os.environ['__remote_exec'].split(), + remote_copy=os.environ['__remote_copy'].split() + ) + + self.log = logging.getLogger(self.context.target_host) + + # Setup env to be used by others - FIXME + self.__init_env() + + # Create directories + self.__init_local_paths() + self.__init_remote_paths() + + def __init_remote_paths(self): + """Initialise remote directory structure""" + self.remove_remote_path(self.context.remote_base_path) + self.remote_mkdir(self.context.remote_base_path) + self.remote_mkdir(self.context.remote_conf_path) + + def __init_local_paths(self): + """Initialise local directory structure""" + + # Create base dir, if user supplied and not existing + if not os.path.isdir(self.context.base_path): + os.mkdir(self.context.base_path) + + # FIXME: raise more beautiful exception / Steven: handle exception + os.mkdir(self.out_path) + os.mkdir(self.global_explorer_out_path) + os.mkdir(self.bin_path) + + # FIXME: remove this function, only expose ENV + # explicitly! + def __init_env(self): + """Environment usable for other stuff""" + os.environ['__target_host'] = self.target_host + if self.debug: + os.environ['__debug'] = "yes" + + def cleanup(self): + self.context.cleanup() + + def run_initial_manifest(self): + """Run the initial manifest""" + log.info("Running initial manifest %s", self.initial_manifest) + env = { "__manifest" : self.manifest_path } + self.run_manifest(self.initial_manifest, extra_env=env) + + def run_type_manifest(self, cdist_object): + """Run manifest for a specific object""" + cdist_type = cdist_object.type + manifest_path = os.path.join(self.type_base_path, + cdist_type.manifest_path) + + log.debug("%s: Running %s", cdist_object.name, manifest_path) + if os.path.exists(manifest_path): + env = { "__object" : os.path.join(self.object_base_path, + cdist_object.path), + "__object_id": cdist_object.object_id, + "__object_fq": cdist_object.name, + "__type": os.path.join(self.type_base_path, + cdist_type.path) + } + self.run_manifest(manifest_path, extra_env=env) + + def run_manifest(self, manifest_path, extra_env=None): + """Run a manifest""" + log.debug("Running manifest %s, env=%s", manifest_path, extra_env) + env = os.environ.copy() + env['PATH'] = self.bin_path + ":" + env['PATH'] + + # Information required in every manifest + env['__target_host'] = self.target_host + env['__global'] = self.out_path + + # Required for recording source in emulator + env['__cdist_manifest'] = manifest_path + + # Required to find types in emulator + env['__cdist_type_base_path'] = self.type_base_path + + # Other environment stuff + if extra_env: + env.update(extra_env) + + cdist.exec.shell_run_or_debug_fail(manifest_path, [manifest_path], env=env) + + def object_prepare(self, cdist_object): + """Prepare object: Run type explorer + manifest""" + log.debug("Preparing object: " + cdist_object.name) + self.run_type_explorer(cdist_object) + self.run_type_manifest(cdist_object) + cdist_object.prepared = True + + def object_run(self, cdist_object): + """Run gencode and code for an object""" + log.debug("Running object %s", cdist_object) + + # Catch requirements, which re-call us + if cdist_object.ran: + return + + cdist_type = cdist_object.type + + for requirement in cdist_object.requirements: + log.debug("Object %s requires %s", cdist_object, requirement) + self.object_run(requirement) + + # + # Setup env Variable: + # + env = os.environ.copy() + env['__target_host'] = self.target_host + env['__global'] = self.out_path + env["__object"] = os.path.join(self.object_base_path, cdist_object.path) + env["__object_id"] = cdist_object.object_id + env["__object_fq"] = cdist_object.name + env["__type"] = cdist_type.name + + # gencode + for cmd in ["local", "remote"]: + bin = os.path.join(self.type_base_path, + getattr(cdist_type, "gencode_" + cmd + "_path")) + + if os.path.isfile(bin): + outfile = os.path.join(self.object_base_path, + getattr(cdist_object, "code_" + cmd + "_path")) + + outfile_fd = open(outfile, "w") + + # Need to flush to ensure our write is done before stdout write + # FIXME: code header still needed? + outfile_fd.write(CODE_HEADER) + outfile_fd.flush() + + cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) + outfile_fd.close() + + status = os.stat(outfile) + + # Remove output if empty, else make it executable + if status.st_size == len(CODE_HEADER): + os.unlink(outfile) + else: + # Add header and make executable - identically to 0o700 + os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) + cdist_object.changed=True + + # code local + code_local = cdist_object.code_local_path + if os.path.isfile(code_local): + cdist.exec.run_or_fail([code_local]) + + # code remote + local_remote_code = os.path.join(self.object_base_path, + cdist_object.code_remote_path) + remote_remote_code = os.path.join(self.remote_object_path, + cdist_object.code_remote_path) + if os.path.isfile(local_remote_code): + self.transfer_path(local_remote_code, remote_remote_code) + cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) + + cdist_object.ran = True + + def link_emulator(self): + """Link emulator to types""" + src = os.path.abspath(self.exec_path) + for cdist_type in cdist.core.Type.list_types(self.type_base_path): + dst = os.path.join(self.bin_path, cdist_type.name) + log.debug("Linking emulator: %s to %s", src, dst) + + # FIXME: handle exception / make it more beautiful / Steven: raise except :-) + os.symlink(src, dst) + + def deploy_to(self): + """Mimic the old deploy to: Deploy to one host""" + log.info("Deploying to " + self.target_host) + self.stage_prepare() + self.stage_run() + + def deploy_and_cleanup(self): + """Do what is most often done: deploy & cleanup""" + start_time = time.time() + self.deploy_to() + self.cleanup() + log.info("Finished run of %s in %s seconds", + self.target_host, time.time() - start_time) + + def stage_prepare(self): + """Do everything for a deploy, minus the actual code stage""" + self.link_emulator() + self.run_global_explorers() + self.run_initial_manifest() + + 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 cdist.core.Object.list_objects(self.object_base_path, + self.type_base_path): + if cdist_object.prepared: + log.debug("Skipping rerun of object %s", cdist_object) + continue + else: + self.object_prepare(cdist_object) + new_objects_created = True + + def stage_run(self): + """The final (and real) step of deployment""" + log.info("Generating and executing code") + for cdist_object in cdist.core.Object.list_objects(self.object_base_path, + self.type_base_path): + log.debug("Run object: %s", cdist_object) + self.object_run(cdist_object) From b8a3cf2f4996c11c57adef113389644596051dfb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:25:48 +0200 Subject: [PATCH 0739/4212] remove manifest code from config_install Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 264 ++++-------------------------------- 1 file changed, 23 insertions(+), 241 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 7214cdba..ef37eb86 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -31,8 +31,6 @@ import time import cdist.core import cdist.exec -log = logging.getLogger(__name__) - CODE_HEADER = "#!/bin/sh -e\n" class ConfigInstall: @@ -45,152 +43,59 @@ class ConfigInstall: exec_path=sys.argv[0], debug=False): - self.target_host = target_host + self.context = cdist.context.Context( + target_host=target_host, + initial_manifest=initial_manifest, + base_path=base_path, + exec_path=sys.argv[0], + debug=debug) - self.debug = debug + self.exec_wrapper = cdist.exec.Wrapper( + targe_host = self.target_host, + remote_exec=os.environ['__remote_exec'].split(), + remote_copy=os.environ['__remote_copy'].split() + ) - # Only required for testing - self.exec_path = exec_path + self.explorer = cdist.explorer.Explorer() + self.manifest = cdist.manifest.Mamifest() - # Configure logging - log.addFilter(self) + self.log = logging.getLogger(self.context.target_host) - # Base and Temp Base - self.base_path = (base_path or - self.base_path = os.path.abspath(os.path.join( - os.path.dirname(__file__), os.pardir, os.pardir)) - - # Local input - self.cache_path = os.path.join(self.base_path, "cache", - self.target_host) - self.conf_path = os.path.join(self.base_path, "conf") - - self.global_explorer_path = os.path.join(self.conf_path, "explorer") - self.manifest_path = os.path.join(self.conf_path, "manifest") - self.type_base_path = os.path.join(self.conf_path, "type") - self.lib_path = os.path.join(self.base_path, "lib") - - self.initial_manifest = (initial_manifest or - os.path.join(self.manifest_path, "init")) - - # Local output - if '__cdist_out_dir' in os.environ: - self.out_path = os.environ['__cdist_out_dir'] - else: - self.out_path = os.path.join(tempfile.mkdtemp(), "out") - self.bin_path = os.path.join(self.out_path, "bin") - self.global_explorer_out_path = os.path.join(self.out_path, "explorer") - self.object_base_path = os.path.join(self.out_path, "object") - - # Remote directory base - if '__cdist_remote_out_dir' in os.environ: - self.remote_base_path = os.environ['__cdist_remote_out_dir'] - else: - self.remote_base_path = "/var/lib/cdist" - - self.remote_conf_path = os.path.join(self.remote_base_path, "conf") - self.remote_object_path = os.path.join(self.remote_base_path, "object") - - self.remote_type_path = os.path.join(self.remote_conf_path, "type") - self.remote_global_explorer_path = os.path.join(self.remote_conf_path, "explorer") - - # Setup env to be used by others + # Setup env to be used by others - FIXME self.__init_env() # Create directories self.__init_local_paths() self.__init_remote_paths() - def __init_remote_paths(self): """Initialise remote directory structure""" - self.remove_remote_path(self.remote_base_path) - self.remote_mkdir(self.remote_base_path) - self.remote_mkdir(self.remote_conf_path) + self.remove_remote_path(self.context.remote_base_path) + self.remote_mkdir(self.context.remote_base_path) + self.remote_mkdir(self.context.remote_conf_path) def __init_local_paths(self): """Initialise local directory structure""" # Create base dir, if user supplied and not existing - if not os.path.isdir(self.base_path): - os.mkdir(self.base_path) + if not os.path.isdir(self.context.base_path): + os.mkdir(self.context.base_path) # FIXME: raise more beautiful exception / Steven: handle exception os.mkdir(self.out_path) os.mkdir(self.global_explorer_out_path) os.mkdir(self.bin_path) + # FIXME: remove this function, only expose ENV + # explicitly! def __init_env(self): """Environment usable for other stuff""" os.environ['__target_host'] = self.target_host if self.debug: os.environ['__debug'] = "yes" - def cleanup(self): - # Do not use in __del__: - # http://docs.python.org/reference/datamodel.html#customization - # "other globals referenced by the __del__() method may already have been deleted - # or in the process of being torn down (e.g. the import machinery shutting down)" - # - log.debug("Saving " + self.out_path + " to " + self.cache_path) - # FIXME: raise more beautiful exception / Steven: handle exception - # Remove previous cache - if os.path.exists(self.cache_path): - shutil.rmtree(self.cache_path) - shutil.move(self.out_path, self.cache_path) - - def filter(self, record): - """Add hostname to logs via logging Filter""" - - record.msg = self.target_host + ": " + record.msg - - return True - - def run_initial_manifest(self): - """Run the initial manifest""" - log.info("Running initial manifest %s", self.initial_manifest) - env = { "__manifest" : self.manifest_path } - self.run_manifest(self.initial_manifest, extra_env=env) - - def run_type_manifest(self, cdist_object): - """Run manifest for a specific object""" - cdist_type = cdist_object.type - manifest_path = os.path.join(self.type_base_path, - cdist_type.manifest_path) - - log.debug("%s: Running %s", cdist_object.name, manifest_path) - if os.path.exists(manifest_path): - env = { "__object" : os.path.join(self.object_base_path, - cdist_object.path), - "__object_id": cdist_object.object_id, - "__object_fq": cdist_object.name, - "__type": os.path.join(self.type_base_path, - cdist_type.path) - } - self.run_manifest(manifest_path, extra_env=env) - - def run_manifest(self, manifest_path, extra_env=None): - """Run a manifest""" - log.debug("Running manifest %s, env=%s", manifest_path, extra_env) - env = os.environ.copy() - env['PATH'] = self.bin_path + ":" + env['PATH'] - - # Information required in every manifest - env['__target_host'] = self.target_host - env['__global'] = self.out_path - - # Required for recording source in emulator - env['__cdist_manifest'] = manifest_path - - # Required to find types in emulator - env['__cdist_type_base_path'] = self.type_base_path - - # Other environment stuff - if extra_env: - env.update(extra_env) - - cdist.exec.shell_run_or_debug_fail(manifest_path, [manifest_path], env=env) + self.context.cleanup() def object_prepare(self, cdist_object): """Prepare object: Run type explorer + manifest""" @@ -269,67 +174,6 @@ class ConfigInstall: cdist_object.ran = True - def run_type_explorer(self, cdist_object): - - def run_type_explorer(self, cdist_object, remote_global_explorer_path, remote_type_path, remote_object_path, scp-hints, ssh-hints, object_base_path): - - def __init__(self, remote_global_explorer_path, remote_type_path, remote_object_path, exec-hint, object_base_path, global_explorer_out_path): - - def __init__(self, remote_global_explorer_path, remote_type_path, remote_object_path, exec-hint): - - def run_type_explorer(self, cdist_object) - - self.value = .,.. - return value - - def run_global_explorer(self) - - def __init__(self, remote_global_explorer_path, remote_type_path, remote_object_path, exec-hint): - == 1x - - - - - run_type_explorer() - self.instance.value[obej - - c = ConfigInstall("foo") - c.remote_global_explorer_path = "moo" - - def run_type_explorer(self, cdist_object) - """Run type specific explorers for objects""" - - cdist_type = cdist_object.type - self.transfer_type_explorers(cdist_type) - - cmd = [] - cmd.append("__explorer=" + self.remote_global_explorer_path) - cmd.append("__type_explorer=" + os.path.join( - self.remote_type_path, - cdist_type.explorer_path)) - cmd.append("__object=" + os.path.join( - self.remote_object_path, - cdist_object.path)) - cmd.append("__object_id=" + cdist_object.object_id) - cmd.append("__object_fq=" + cdist_object.name) - - # Need to transfer at least the parameters for objects to be useful - self.transfer_object_parameter(cdist_object) - - for explorer in cdist_type.explorers: - remote_cmd = cmd + [os.path.join(self.remote_type_path, - cdist_type.explorer_path, explorer)] - output = os.path.join(self.object_base_path, - cdist_object.explorer_path, explorer) - output_fd = open(output, mode='w') - log.debug("%s exploring %s using %s storing to %s", - cdist_object, explorer, remote_cmd, output) - - cdist.exec.run_or_fail(remote_cmd, stdout=output_fd, remote_prefix=True) - output_fd.close() - - return outputs - def link_emulator(self): """Link emulator to types""" src = os.path.abspath(self.exec_path) @@ -340,27 +184,6 @@ class ConfigInstall: # FIXME: handle exception / make it more beautiful / Steven: raise except :-) os.symlink(src, dst) - def run_global_explorers(src_path, dst_path, remote_dst_path): - - def run_global_explorers(self): - """Run global explorers""" - log.info("Running global explorers") - - src_path = self.global_explorer_path - dst_path = self.global_explorer_out_path - remote_dst_path = self.remote_global_explorer_path - - self.transfer_path(src_path, remote_dst_path) - - for explorer in os.listdir(src_path): - output_fd = open(os.path.join(dst_path, explorer), mode='w') - cmd = [] - cmd.append("__explorer=" + remote_dst_path) - cmd.append(os.path.join(remote_dst_path, explorer)) - - cdist.exec.run_or_fail(cmd, stdout=output_fd, remote_prefix=True) - output_fd.close() - def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" log.info("Deploying to " + self.target_host) @@ -403,44 +226,3 @@ class ConfigInstall: self.type_base_path): log.debug("Run object: %s", cdist_object) self.object_run(cdist_object) - - def transfer_object_parameter(self, cdist_object): - """Transfer the object parameter to the remote destination""" - src = os.path.join(self.object_base_path, - cdist_object.parameter_path) - dst = os.path.join(self.remote_object_path, - cdist_object.parameter_path) - - # Synchronise parameter dir afterwards - self.remote_mkdir(dst) - self.transfer_path(src, dst) - - def transfer_global_explorers(self): - """Transfer the global explorers""" - self.remote_mkdir(self.remote_global_explorer_path) - self.transfer_path(self.global_explorer_path, - self.remote_global_explorer_path) - - def transfer_type_explorers(self, cdist_type): - """Transfer explorers of a type, but only once""" - if cdist_type.transferred_explorers: - log.debug("Skipping retransfer for explorers of %s", cdist_type) - return - else: - log.debug("Ensure no retransfer for %s", cdist_type) - # Do not retransfer - cdist_type.transferred_explorers = True - - explorers = cdist_type.explorers - - if len(explorers) > 0: - rel_path = cdist_type.explorer_path - src = os.path.join(self.type_base_path, rel_path) - dst = os.path.join(self.remote_type_path, rel_path) - - # Ensure full path until type exists: - # /var/lib/cdist/conf/type/__directory/explorer - # /var/lib/cdist/conf/type/__directory may not exist, - # but remote_mkdir uses -p to fix this - self.remote_mkdir(dst) - self.transfer_path(src, dst) From dc21405583d2da14b7822df2b57d10ecfe127f91 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:26:01 +0200 Subject: [PATCH 0740/4212] use target host as key for logger Signed-off-by: Nico Schottelius --- lib/cdist/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index f1cd4c14..9550b96e 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -47,7 +47,7 @@ class Context: self.exec_path = exec_path # Context logging - self.log = logging.getLogger(__name__) + self.log = logging.getLogger(self.target_host) self.log.addFilter(self) # Base and Temp Base From d690fb30cbdcf81830d6db895547a34072c1baa4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:26:33 +0200 Subject: [PATCH 0741/4212] add base path and exec path to test main Signed-off-by: Nico Schottelius --- lib/cdist/test/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/cdist/test/__init__.py b/lib/cdist/test/__init__.py index 09429470..06c87917 100644 --- a/lib/cdist/test/__init__.py +++ b/lib/cdist/test/__init__.py @@ -27,8 +27,10 @@ import unittest cdist_commands=["banner", "config", "install"] -cdist_exec_path = os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../bin/cdist")) +cdist_base_path = os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../")) + +cdist_exec_path = os.path.join(cdist_base_path, "bin/cdist") #class UI(unittest.TestCase): # def test_banner(self): From a692e551c0080b8dfe71859486b37496f564c5bc Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 16:31:05 +0200 Subject: [PATCH 0742/4212] use new logger Signed-off-by: Steven Armstrong --- lib/cdist/exec.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index b3b86a52..13cec499 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -25,14 +25,13 @@ import subprocess import cdist -log = logging.getLogger(__name__) - class Wrapper(object): def __init__(self, target_host, remote_exec, remote_copy): self.target_host = target_host self.remote_exec = remote_exec self.remote_copy = remote_copy + self.log = logging.getLogger(self.target_host) def remote_mkdir(self, directory): """Create directory on remote side""" @@ -58,15 +57,15 @@ class Wrapper(object): remote_prefix.append(self.target_host) args[0][:0] = remote_prefix - log.debug("Shell exec cmd: %s", args) + self.log.debug("Shell exec cmd: %s", args) if 'env' in kargs: - log.debug("Shell exec env: %s", kargs['env']) + self.log.debug("Shell exec env: %s", kargs['env']) try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: - log.error("Code that raised the error:\n") + self.log.error("Code that raised the error:\n") if remote: self.run_or_fail(["cat", script], remote=remote) @@ -89,13 +88,10 @@ class Wrapper(object): remote_prefix.append(self.target_host) args[0][:0] = remote_prefix - log.debug("Exec: " + " ".join(*args)) + self.log.debug("Exec: " + " ".join(*args)) try: subprocess.check_call(*args, **kargs) except subprocess.CalledProcessError: raise cdist.Error("Command failed: " + " ".join(*args)) except OSError as error: raise cdist.Error(" ".join(*args) + ": " + error.args[1]) - - - From 8ef0c18da0630212a50d92afcfcbcfe006b5da95 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 16:31:43 +0200 Subject: [PATCH 0743/4212] update test suite to match new code Signed-off-by: Steven Armstrong --- lib/cdist/test/test_exec.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/cdist/test/test_exec.py b/lib/cdist/test/test_exec.py index 901b5efd..68f388e9 100644 --- a/lib/cdist/test/test_exec.py +++ b/lib/cdist/test/test_exec.py @@ -49,32 +49,35 @@ class Exec(unittest.TestCase): false_fd.writelines(["#!/bin/sh\n", "/bin/false"]) false_fd.close() + target_host = "does.not.exist" + remote_exec = "ssh -o User=root -q" + remote_copy = "scp -o User=root -q" + self.wrapper = cdist.exec.Wrapper(target_host, remote_exec, remote_copy) + def tearDown(self): shutil.rmtree(self.temp_dir) def test_local_success_shell(self): try: - cdist.exec.shell_run_or_debug_fail(self.shell_true, [self.shell_true]) + self.wrapper.shell_run_or_debug_fail(self.shell_true, [self.shell_true]) except cdist.Error: failed = True else: failed = False - self.assertFalse(failed) def test_local_fail_shell(self): - self.assertRaises(cdist.Error, cdist.exec.shell_run_or_debug_fail, + self.assertRaises(cdist.Error, self.wrapper.shell_run_or_debug_fail, self.shell_false, [self.shell_false]) def test_local_success(self): try: - cdist.exec.run_or_fail(["/bin/true"]) + self.wrapper.run_or_fail(["/bin/true"]) except cdist.Error: failed = True else: failed = False - self.assertFalse(failed) def test_local_fail(self): - self.assertRaises(cdist.Error, cdist.exec.run_or_fail, ["/bin/false"]) + self.assertRaises(cdist.Error, self.wrapper.run_or_fail, ["/bin/false"]) From 29bb5f383cc8a6bbbc5f0184ea40deb84f683e63 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:39:18 +0200 Subject: [PATCH 0744/4212] use context in cdist/bin Signed-off-by: Nico Schottelius --- bin/cdist | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bin/cdist b/bin/cdist index ac863e9e..aee96e6e 100755 --- a/bin/cdist +++ b/bin/cdist @@ -115,10 +115,14 @@ def configinstall(args, mode): time_start = time.time() for host in args.host: - c = mode(host, - initial_manifest=args.manifest, - base_path=args.cdist_home, - debug=args.debug) + context = cdist.context.Context( + target_host=host, + initial_manifest=args.manifest, + base_path=args.cdist_home, + exec_path=sys.argv[0], + debug=args.debug) + + c = mode(context) if args.parallel: log.debug("Creating child process for %s", host) process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) From 1c73fb1288eabb1006e67626065252e6ca0bf594 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 16:41:01 +0200 Subject: [PATCH 0745/4212] -- unused imports Signed-off-by: Steven Armstrong --- lib/cdist/test/test_exec.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/cdist/test/test_exec.py b/lib/cdist/test/test_exec.py index 68f388e9..deb62d11 100644 --- a/lib/cdist/test/test_exec.py +++ b/lib/cdist/test/test_exec.py @@ -22,17 +22,13 @@ import os -import sys import shutil -import subprocess import tempfile import unittest -sys.path.insert(0, os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) - import cdist.exec + class Exec(unittest.TestCase): def setUp(self): """Create shell code and co.""" From 8543f3ed58fe6577b6dcc02868a607ec2bcdb833 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 16:41:44 +0200 Subject: [PATCH 0746/4212] rename to match others Signed-off-by: Steven Armstrong --- lib/cdist/test/test_exec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/test/test_exec.py b/lib/cdist/test/test_exec.py index deb62d11..c2bb52f6 100644 --- a/lib/cdist/test/test_exec.py +++ b/lib/cdist/test/test_exec.py @@ -29,7 +29,7 @@ import unittest import cdist.exec -class Exec(unittest.TestCase): +class ExecTestCase(unittest.TestCase): def setUp(self): """Create shell code and co.""" From 2ec3753d945c45829659fd4f3fb5f5c287f6c2be Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:45:18 +0200 Subject: [PATCH 0747/4212] cleanup context in main Signed-off-by: Nico Schottelius --- bin/cdist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/cdist b/bin/cdist index aee96e6e..fae83ff1 100755 --- a/bin/cdist +++ b/bin/cdist @@ -130,6 +130,8 @@ def configinstall(args, mode): else: c.deploy_and_cleanup() + context.cleanup() + if args.parallel: for p in process.keys(): log.debug("Joining process %s", p) From dbd31252a868c35435ce27180a42a99907e12ebb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:45:36 +0200 Subject: [PATCH 0748/4212] remove CODE_HEADER Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index ef37eb86..cb903a93 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -29,26 +29,15 @@ import tempfile import time import cdist.core +import cdist.context import cdist.exec -CODE_HEADER = "#!/bin/sh -e\n" - -class ConfigInstall: +class ConfigInstall(object): """Cdist main class to hold arbitrary data""" - def __init__(self, - target_host, - initial_manifest=False, - base_path=False, - exec_path=sys.argv[0], - debug=False): + def __init__(self, context): - self.context = cdist.context.Context( - target_host=target_host, - initial_manifest=initial_manifest, - base_path=base_path, - exec_path=sys.argv[0], - debug=debug) + self.context = context self.exec_wrapper = cdist.exec.Wrapper( targe_host = self.target_host, @@ -70,9 +59,9 @@ class ConfigInstall: def __init_remote_paths(self): """Initialise remote directory structure""" - self.remove_remote_path(self.context.remote_base_path) - self.remote_mkdir(self.context.remote_base_path) - self.remote_mkdir(self.context.remote_conf_path) + self.exec_wrapper.remove_remote_path(self.context.remote_base_path) + self.exec_wrapper.remote_mkdir(self.context.remote_base_path) + self.exec_wrapper.remote_mkdir(self.context.remote_conf_path) def __init_local_paths(self): """Initialise local directory structure""" @@ -95,7 +84,10 @@ class ConfigInstall: os.environ['__debug'] = "yes" def cleanup(self): - self.context.cleanup() + log.debug("Saving " + self.out_path + " to " + self.cache_path) + if os.path.exists(self.context.cache_path): + shutil.rmtree(self.context.cache_path) + shutil.move(self.context.out_path, self.context.cache_path) def object_prepare(self, cdist_object): """Prepare object: Run type explorer + manifest""" From 73f1190d55c1cbd0732167b4153c3eed5c21ccfd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:45:45 +0200 Subject: [PATCH 0749/4212] cleanup context internally Signed-off-by: Nico Schottelius --- lib/cdist/context.py | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index 9550b96e..7bb700e8 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -22,24 +22,24 @@ import logging import os +import sys +import tempfile #import stat #import shutil -#import sys -#import tempfile #import time # #import cdist.core #import cdist.exec -class Context: +class Context(object): """Hold information about current context""" - def __init__(self, + def __init__(self, target_host, initial_manifest=False, base_path=False, exec_path=sys.argv[0], - debug): + debug=False): self.target_host = target_host @@ -52,8 +52,8 @@ class Context: # Base and Temp Base self.base_path = (base_path or - self.base_path = os.path.abspath(os.path.join( - os.path.dirname(__file__), os.pardir, os.pardir)) + os.path.abspath(os.path.join(os.path.dirname(__file__), + os.pardir, os.pardir))) # Local input self.cache_path = os.path.join(self.base_path, "cache", @@ -71,8 +71,11 @@ class Context: # Local output if '__cdist_out_dir' in os.environ: self.out_path = os.environ['__cdist_out_dir'] + self.temp_dir = None else: - self.out_path = os.path.join(tempfile.mkdtemp(), "out") + self.temp_dir = tempfile.mkdtemp() + self.out_path = os.path.join(self.temp_dir, "out") + self.bin_path = os.path.join(self.out_path, "bin") self.global_explorer_out_path = os.path.join(self.out_path, "explorer") self.object_base_path = os.path.join(self.out_path, "object") @@ -100,17 +103,9 @@ class Context: self.remote_copy = "scp -o User=root -q" def cleanup(self): - # Do not use in __del__: - # http://docs.python.org/reference/datamodel.html#customization - # "other globals referenced by the __del__() method may already have been deleted - # or in the process of being torn down (e.g. the import machinery shutting down)" - # - log.debug("Saving " + self.out_path + " to " + self.cache_path) - # FIXME: raise more beautiful exception / Steven: handle exception - # Remove previous cache - if os.path.exists(self.cache_path): - shutil.rmtree(self.cache_path) - shutil.move(self.out_path, self.cache_path) + """Remove temp stuff""" + if self.temp_dir: + shutil.rmtree(self.temp_dir) def filter(self, record): """Add hostname to logs via logging Filter""" From 588731661e8a2f13effe29daaa65382de2d3edd4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:49:50 +0200 Subject: [PATCH 0750/4212] use context in explorer Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 19 ++++++++++--------- lib/cdist/explorer.py | 17 +++-------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index cb903a93..2a1c828d 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -31,6 +31,8 @@ import time import cdist.core import cdist.context import cdist.exec +import cdist.explorer +#import cdist.manifest class ConfigInstall(object): """Cdist main class to hold arbitrary data""" @@ -40,12 +42,11 @@ class ConfigInstall(object): self.context = context self.exec_wrapper = cdist.exec.Wrapper( - targe_host = self.target_host, - remote_exec=os.environ['__remote_exec'].split(), - remote_copy=os.environ['__remote_copy'].split() - ) + target_host = self.context.target_host, + remote_exec=self.context.remote_exec, + remote_copy=self.context.remote_copy) - self.explorer = cdist.explorer.Explorer() + self.explorer = cdist.explorer.Explorer(self.context) self.manifest = cdist.manifest.Mamifest() self.log = logging.getLogger(self.context.target_host) @@ -79,7 +80,7 @@ class ConfigInstall(object): # explicitly! def __init_env(self): """Environment usable for other stuff""" - os.environ['__target_host'] = self.target_host + os.environ['__target_host'] = self.context.target_host if self.debug: os.environ['__debug'] = "yes" @@ -114,7 +115,7 @@ class ConfigInstall(object): # Setup env Variable: # env = os.environ.copy() - env['__target_host'] = self.target_host + env['__target_host'] = self.context.target_host env['__global'] = self.out_path env["__object"] = os.path.join(self.object_base_path, cdist_object.path) env["__object_id"] = cdist_object.object_id @@ -178,7 +179,7 @@ class ConfigInstall(object): def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to " + self.target_host) + log.info("Deploying to " + self.context.target_host) self.stage_prepare() self.stage_run() @@ -188,7 +189,7 @@ class ConfigInstall(object): self.deploy_to() self.cleanup() log.info("Finished run of %s in %s seconds", - self.target_host, time.time() - start_time) + self.context.target_host, time.time() - start_time) def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" diff --git a/lib/cdist/explorer.py b/lib/cdist/explorer.py index e2c41f8a..b0db60bc 100644 --- a/lib/cdist/explorer.py +++ b/lib/cdist/explorer.py @@ -37,21 +37,10 @@ log = logging.getLogger(__name__) class Explorer: """Execute explorers""" - def __init__(self, - object_base_path, - remote_global_explorer_path, - remote_type_path, - remote_object_path, - type_path, - exec_hint): + def __init__(self, context): + self.context = context - self.object_base_path = object_base_path - self.remote_global_explorer_path = remote_global_explorer_path - self.remote_type_path = remote_type_path - self.remote_object_path = remote_object_path - self.exec_hint = exec_hint - - def run_type_explorer(self, cdist_object) + def run_type_explorer(self, cdist_object): """Run type specific explorers for objects""" cdist_type = cdist_object.type From 794a11d86648524c6a16131035b09e1db9a17473 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:56:05 +0200 Subject: [PATCH 0751/4212] %s/\(self.\)\([a-z]*_path\)/\1context.\2/g Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 2a1c828d..7864489d 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -47,7 +47,7 @@ class ConfigInstall(object): remote_copy=self.context.remote_copy) self.explorer = cdist.explorer.Explorer(self.context) - self.manifest = cdist.manifest.Mamifest() + #self.manifest = cdist.manifest.Mamifest() self.log = logging.getLogger(self.context.target_host) @@ -72,20 +72,20 @@ class ConfigInstall(object): os.mkdir(self.context.base_path) # FIXME: raise more beautiful exception / Steven: handle exception - os.mkdir(self.out_path) + os.mkdir(self.context.out_path) os.mkdir(self.global_explorer_out_path) - os.mkdir(self.bin_path) + os.mkdir(self.context.bin_path) # FIXME: remove this function, only expose ENV # explicitly! def __init_env(self): """Environment usable for other stuff""" os.environ['__target_host'] = self.context.target_host - if self.debug: + if self.context.debug: os.environ['__debug'] = "yes" def cleanup(self): - log.debug("Saving " + self.out_path + " to " + self.cache_path) + log.debug("Saving " + self.context.out_path + " to " + self.context.cache_path) if os.path.exists(self.context.cache_path): shutil.rmtree(self.context.cache_path) shutil.move(self.context.out_path, self.context.cache_path) @@ -116,7 +116,7 @@ class ConfigInstall(object): # env = os.environ.copy() env['__target_host'] = self.context.target_host - env['__global'] = self.out_path + env['__global'] = self.context.out_path env["__object"] = os.path.join(self.object_base_path, cdist_object.path) env["__object_id"] = cdist_object.object_id env["__object_fq"] = cdist_object.name @@ -162,16 +162,16 @@ class ConfigInstall(object): remote_remote_code = os.path.join(self.remote_object_path, cdist_object.code_remote_path) if os.path.isfile(local_remote_code): - self.transfer_path(local_remote_code, remote_remote_code) + self.context.transfer_path(local_remote_code, remote_remote_code) cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) cdist_object.ran = True def link_emulator(self): """Link emulator to types""" - src = os.path.abspath(self.exec_path) + src = os.path.abspath(self.context.exec_path) for cdist_type in cdist.core.Type.list_types(self.type_base_path): - dst = os.path.join(self.bin_path, cdist_type.name) + dst = os.path.join(self.context.bin_path, cdist_type.name) log.debug("Linking emulator: %s to %s", src, dst) # FIXME: handle exception / make it more beautiful / Steven: raise except :-) From dc9092dbef79ef1b4afbd5989e61ccb912d6f6be Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Oct 2011 16:56:59 +0200 Subject: [PATCH 0752/4212] --os.environ Signed-off-by: Steven Armstrong --- lib/cdist/exec.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py index 13cec499..a2282347 100644 --- a/lib/cdist/exec.py +++ b/lib/cdist/exec.py @@ -20,7 +20,6 @@ # import logging -import os import subprocess import cdist @@ -44,7 +43,7 @@ class Wrapper(object): def transfer_path(self, source, destination): """Transfer directory and previously delete the remote destination""" self.remove_remote_path(destination) - self.run_or_fail(os.environ['__remote_copy'].split() + + self.run_or_fail(self.remote_copy.split() + ["-r", source, self.target_host + ":" + destination]) def shell_run_or_debug_fail(self, script, *args, remote=False, **kargs): From f0852209f01642bea546aeacb9c816890597a195 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:59:22 +0200 Subject: [PATCH 0753/4212] save debug in context Signed-off-by: Nico Schottelius --- lib/cdist/context.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index 7bb700e8..f70e9752 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -41,6 +41,8 @@ class Context(object): exec_path=sys.argv[0], debug=False): + self.debug = debug + self.target_host = target_host # Only required for testing From d95d195b4063b4d7b6806c66c3df5ac34db6dda1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 16:59:43 +0200 Subject: [PATCH 0754/4212] have object seave its explorer outputs Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 7864489d..f9aeaf19 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -93,8 +93,9 @@ class ConfigInstall(object): def object_prepare(self, cdist_object): """Prepare object: Run type explorer + manifest""" log.debug("Preparing object: " + cdist_object.name) - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) + cdist_object.explorers = + self.explorer.run_type_explorer(cdist_object) + self.manifest.run_type_manifest(cdist_object) cdist_object.prepared = True def object_run(self, cdist_object): From b7824c3ead3dfcab89ab6105aaa35b85f94c358c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 17:05:35 +0200 Subject: [PATCH 0755/4212] move explorer out dir creation into Explorer class Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 4 +--- lib/cdist/explorer.py | 9 +++++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index f9aeaf19..3c809331 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -73,7 +73,6 @@ class ConfigInstall(object): # FIXME: raise more beautiful exception / Steven: handle exception os.mkdir(self.context.out_path) - os.mkdir(self.global_explorer_out_path) os.mkdir(self.context.bin_path) # FIXME: remove this function, only expose ENV @@ -93,8 +92,7 @@ class ConfigInstall(object): def object_prepare(self, cdist_object): """Prepare object: Run type explorer + manifest""" log.debug("Preparing object: " + cdist_object.name) - cdist_object.explorers = - self.explorer.run_type_explorer(cdist_object) + cdist_object.explorers = self.explorer.run_type_explorer(cdist_object) self.manifest.run_type_manifest(cdist_object) cdist_object.prepared = True diff --git a/lib/cdist/explorer.py b/lib/cdist/explorer.py index b0db60bc..9030e506 100644 --- a/lib/cdist/explorer.py +++ b/lib/cdist/explorer.py @@ -22,16 +22,17 @@ import io import logging -#import os +import os #import stat #import shutil #import sys #import tempfile #import time # -#import cdist.core #import cdist.exec +import cdist + log = logging.getLogger(__name__) class Explorer: @@ -39,6 +40,10 @@ class Explorer: def __init__(self, context): self.context = context + try: + os.mkdir(self.context.global_explorer_out_path) + except OSError as e: + raise cdist.Error("Failed to create explorer out path: %s" % e) def run_type_explorer(self, cdist_object): """Run type specific explorers for objects""" From 9f49f99294bb6f2579b4f3d4e0c6d68c6ce4358d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Oct 2011 17:09:47 +0200 Subject: [PATCH 0756/4212] use self.log for correct logger Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 41 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 3c809331..152d6c4a 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -40,12 +40,16 @@ class ConfigInstall(object): def __init__(self, context): self.context = context - + self.log = logging.getLogger(self.context.target_host) self.exec_wrapper = cdist.exec.Wrapper( target_host = self.context.target_host, remote_exec=self.context.remote_exec, remote_copy=self.context.remote_copy) + # Create directories other may depend on + self.__init_local_paths() + self.__init_remote_paths() + self.explorer = cdist.explorer.Explorer(self.context) #self.manifest = cdist.manifest.Mamifest() @@ -54,9 +58,6 @@ class ConfigInstall(object): # Setup env to be used by others - FIXME self.__init_env() - # Create directories - self.__init_local_paths() - self.__init_remote_paths() def __init_remote_paths(self): """Initialise remote directory structure""" @@ -84,21 +85,21 @@ class ConfigInstall(object): os.environ['__debug'] = "yes" def cleanup(self): - log.debug("Saving " + self.context.out_path + " to " + self.context.cache_path) + self.log.debug("Saving " + self.context.out_path + " to " + self.context.cache_path) if os.path.exists(self.context.cache_path): shutil.rmtree(self.context.cache_path) shutil.move(self.context.out_path, self.context.cache_path) def object_prepare(self, cdist_object): """Prepare object: Run type explorer + manifest""" - log.debug("Preparing object: " + cdist_object.name) + self.log.debug("Preparing object: " + cdist_object.name) cdist_object.explorers = self.explorer.run_type_explorer(cdist_object) self.manifest.run_type_manifest(cdist_object) cdist_object.prepared = True def object_run(self, cdist_object): """Run gencode and code for an object""" - log.debug("Running object %s", cdist_object) + self.log.debug("Running object %s", cdist_object) # Catch requirements, which re-call us if cdist_object.ran: @@ -107,7 +108,7 @@ class ConfigInstall(object): cdist_type = cdist_object.type for requirement in cdist_object.requirements: - log.debug("Object %s requires %s", cdist_object, requirement) + self.log.debug("Object %s requires %s", cdist_object, requirement) self.object_run(requirement) # @@ -123,7 +124,7 @@ class ConfigInstall(object): # gencode for cmd in ["local", "remote"]: - bin = os.path.join(self.type_base_path, + bin = os.path.join(self.context.type_base_path, getattr(cdist_type, "gencode_" + cmd + "_path")) if os.path.isfile(bin): @@ -169,16 +170,16 @@ class ConfigInstall(object): def link_emulator(self): """Link emulator to types""" src = os.path.abspath(self.context.exec_path) - for cdist_type in cdist.core.Type.list_types(self.type_base_path): + for cdist_type in cdist.core.Type.list_types(self.context.type_base_path): dst = os.path.join(self.context.bin_path, cdist_type.name) - log.debug("Linking emulator: %s to %s", src, dst) + self.log.debug("Linking emulator: %s to %s", src, dst) # FIXME: handle exception / make it more beautiful / Steven: raise except :-) os.symlink(src, dst) def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to " + self.context.target_host) + self.log.info("Deploying to " + self.context.target_host) self.stage_prepare() self.stage_run() @@ -187,25 +188,25 @@ class ConfigInstall(object): start_time = time.time() self.deploy_to() self.cleanup() - log.info("Finished run of %s in %s seconds", + self.log.info("Finished run of %s in %s seconds", self.context.target_host, time.time() - start_time) def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" self.link_emulator() - self.run_global_explorers() + self.explorer.run_global_explorers() self.run_initial_manifest() - log.info("Running object manifests and type explorers") + 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 cdist.core.Object.list_objects(self.object_base_path, - self.type_base_path): + self.context.type_base_path): if cdist_object.prepared: - log.debug("Skipping rerun of object %s", cdist_object) + self.log.debug("Skipping rerun of object %s", cdist_object) continue else: self.object_prepare(cdist_object) @@ -213,8 +214,8 @@ class ConfigInstall(object): def stage_run(self): """The final (and real) step of deployment""" - log.info("Generating and executing code") + self.log.info("Generating and executing code") for cdist_object in cdist.core.Object.list_objects(self.object_base_path, - self.type_base_path): - log.debug("Run object: %s", cdist_object) + self.context.type_base_path): + self.log.debug("Run object: %s", cdist_object) self.object_run(cdist_object) From c8522af0d0ce7bdbe90131bc929ff8d3916f5c8f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 12:29:20 +0200 Subject: [PATCH 0757/4212] ++todo today Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-12 | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 doc/dev/logs/2011-10-12 diff --git a/doc/dev/logs/2011-10-12 b/doc/dev/logs/2011-10-12 new file mode 100644 index 00000000..22caf05e --- /dev/null +++ b/doc/dev/logs/2011-10-12 @@ -0,0 +1,8 @@ +Todo today + tests: + +- explorer (nico) + - create env here +- exec -> local+remote (steven) +- make configinstall work again (nico) +- make manifest work (steven) + - create env here From 7da3a3c30552db6359abc5771a3260bceecdcb1a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 14:30:10 +0200 Subject: [PATCH 0758/4212] remote code execution and tests Signed-off-by: Steven Armstrong --- lib/cdist/exec/__init__.py | 0 lib/cdist/exec/remote.py | 132 +++++++++++++++++++++++++++++ lib/cdist/test/exec/__init__.py | 0 lib/cdist/test/exec/test_remote.py | 111 ++++++++++++++++++++++++ 4 files changed, 243 insertions(+) create mode 100644 lib/cdist/exec/__init__.py create mode 100644 lib/cdist/exec/remote.py create mode 100644 lib/cdist/test/exec/__init__.py create mode 100644 lib/cdist/test/exec/test_remote.py diff --git a/lib/cdist/exec/__init__.py b/lib/cdist/exec/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py new file mode 100644 index 00000000..a5ad0845 --- /dev/null +++ b/lib/cdist/exec/remote.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 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 io +import os +import sys +import subprocess +import logging + +import cdist + + +class RemoteScriptError(cdist.Error): + def __init__(self, script, command, script_content): + self.script = script + self.command = command + self.script_content = script_content + + def __str__(self): + return "Remote script execution failed: %s %s" % (self.script, self.command) + + +class Remote(object): + """Execute commands remotely. + + All interaction with the remote side should be done through this class. + Directly accessing the remote side from python code is a bug. + + """ + def __init__(self, target_host, remote_base_path, remote_exec, remote_copy): + self.target_host = target_host + self.base_path = remote_base_path + self._exec = remote_exec + self._copy = remote_copy + + self.conf_path = os.path.join(self.base_path, "conf") + self.object_path = os.path.join(self.base_path, "object") + + self.type_path = os.path.join(self.conf_path, "type") + self.global_explorer_path = os.path.join(self.conf_path, "explorer") + + self.log = logging.getLogger(self.target_host) + + def create_directories(self): + self.rmdir(self.base_path) + self.mkdir(self.base_path) + self.mkdir(self.conf_path) + + def rmdir(self, path): + """Remove directory on the remote side.""" + self.log.debug("Remote rmdir: %s", path) + self.run(["rm", "-rf", path]) + + def mkdir(self, path): + """Create directory on the remote side.""" + self.log.debug("Remote mkdir: %s", path) + self.run(["mkdir", "-p", path]) + + def transfer(self, source, destination): + """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) + + def run(self, command, env=None): + """Run the given command with the given environment on the remote side. + Return the output as a string. + + """ + # prefix given command with remote_exec + cmd = self._exec.split() + cmd.append(self.target_host) + cmd.extend(command) + return self.run_command(cmd, env=None) + + def run_command(self, command, env=None): + """Run the given command with the given environment. + Return the output as a string. + + """ + assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %s" % command + self.log.debug("Remote run: %s", command) + try: + return subprocess.check_output(command, env=env) + except subprocess.CalledProcessError: + raise cdist.Error("Command failed: " + " ".join(command)) + except OSError as error: + raise cdist.Error(" ".join(*args) + ": " + error.args[1]) + + def run_script(self, script, env=None): + """Run the given script with the given environment on the remote side. + Return the output as a string. + + """ + command = self._exec.split() + command.append(self.target_host) + command.extend(["/bin/sh", "-e"]) + command.append(script) + + self.log.debug("Remote run script: %s", command) + if env: + self.log.debug("Remote run script env: %s", env) + + try: + return subprocess.check_output(command, env=env) + except subprocess.CalledProcessError as error: + script_content = self.run(["cat", script]) + self.log.error("Code that raised the error:\n%s", script_content) + raise RemoteScriptError(script, command, script_content) + except EnvironmentError as error: + raise cdist.Error(" ".join(command) + ": " + error.args[1]) diff --git a/lib/cdist/test/exec/__init__.py b/lib/cdist/test/exec/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/exec/test_remote.py b/lib/cdist/test/exec/test_remote.py new file mode 100644 index 00000000..ae5e7aed --- /dev/null +++ b/lib/cdist/test/exec/test_remote.py @@ -0,0 +1,111 @@ +# -*- 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 unittest +import os +import tempfile +import getpass +import shutil +import string +import random + +import cdist +from cdist.exec import remote + + +class RemoteTestCase(unittest.TestCase): + + def mkdtemp(self, **kwargs): + return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) + + def mkstemp(self, **kwargs): + return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) + + def setUp(self): + self.temp_dir = self.mkdtemp() + target_host = 'localhost' + remote_base_path = self.temp_dir + user = getpass.getuser() + remote_exec = "ssh -o User=%s -q" % user + remote_copy = "scp -o User=%s -q" % user + self.remote = remote.Remote(target_host, remote_base_path, remote_exec, remote_copy) + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_run_success(self): + self.remote.run(['/bin/true']) + + def test_run_fail(self): + self.assertRaises(cdist.Error, self.remote.run, ['/bin/false']) + + def test_run_script_success(self): + handle, script = self.mkstemp(dir=self.temp_dir) + fd = open(script, "w") + fd.writelines(["#!/bin/sh\n", "/bin/true"]) + fd.close() + self.remote.run_script(script) + + def test_run_script_fail(self): + handle, script = self.mkstemp(dir=self.temp_dir) + fd = open(script, "w") + fd.writelines(["#!/bin/sh\n", "/bin/false"]) + fd.close() + self.assertRaises(remote.RemoteScriptError, self.remote.run_script, script) + + def test_run_script_get_output(self): + handle, script = self.mkstemp(dir=self.temp_dir) + fd = open(script, "w") + fd.writelines(["#!/bin/sh\n", "echo foobar"]) + fd.close() + self.assertEqual(self.remote.run_script(script), b"foobar\n") + + def test_mkdir(self): + temp_dir = self.mkdtemp(dir=self.temp_dir) + os.rmdir(temp_dir) + self.remote.mkdir(temp_dir) + self.assertTrue(os.path.isdir(temp_dir)) + + def test_rmdir(self): + temp_dir = self.mkdtemp(dir=self.temp_dir) + self.remote.rmdir(temp_dir) + self.assertFalse(os.path.isdir(temp_dir)) + + def test_transfer_file(self): + handle, source = self.mkstemp(dir=self.temp_dir) + target = self.mkdtemp(dir=self.temp_dir) + self.remote.transfer(source, target) + self.assertTrue(os.path.isfile(target)) + + def test_transfer_dir(self): + source = self.mkdtemp(dir=self.temp_dir) + # put a file in the directory as payload + handle, source_file = self.mkstemp(dir=source) + source_file_name = os.path.split(source_file)[-1] + target = self.mkdtemp(dir=self.temp_dir) + self.remote.transfer(source, target) + # test if the payload file is in the target directory + self.assertTrue(os.path.isfile(os.path.join(target, source_file_name))) + + def test_create_directories(self): + self.remote.create_directories() + self.assertTrue(os.path.isdir(self.remote.base_path)) + self.assertTrue(os.path.isdir(self.remote.conf_path)) From 84e044407e036aa7747a82a0af5f4556f5d69163 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 15:16:33 +0200 Subject: [PATCH 0759/4212] +FIXME Signed-off-by: Steven Armstrong --- lib/cdist/exec/remote.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index a5ad0845..6ec9c46f 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -20,6 +20,8 @@ # # +# FIXME: common base class with Local? + import io import os import sys From 985ed2669a7aae0acd6e6bd6f7b136251a96d328 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 15:17:06 +0200 Subject: [PATCH 0760/4212] local code execution and tests Signed-off-by: Steven Armstrong --- lib/cdist/exec/local.py | 118 ++++++++++++++++++++++++++++++ lib/cdist/test/exec/test_local.py | 102 ++++++++++++++++++++++++++ 2 files changed, 220 insertions(+) create mode 100644 lib/cdist/exec/local.py create mode 100644 lib/cdist/test/exec/test_local.py diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py new file mode 100644 index 00000000..b9c511f4 --- /dev/null +++ b/lib/cdist/exec/local.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 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 io +import os +import sys +import subprocess +import shutil +import logging + +import cdist + + +class LocalScriptError(cdist.Error): + def __init__(self, script, command, script_content): + self.script = script + self.command = command + self.script_content = script_content + + def __str__(self): + return "Remote script execution failed: %s %s" % (self.script, self.command) + + +class Local(object): + """Execute commands locally. + + All interaction with the local side should be done through this class. + Directly accessing the local side from python code is a bug. + + """ + def __init__(self, target_host, local_base_path, out_path): + self.target_host = target_host + self.base_path = local_base_path + + # Local input + self.cache_path = os.path.join(self.base_path, "cache") + self.conf_path = os.path.join(self.base_path, "conf") + self.global_explorer_path = os.path.join(self.conf_path, "explorer") + self.manifest_path = os.path.join(self.conf_path, "manifest") + self.type_base_path = os.path.join(self.conf_path, "type") + # FIXME: should not be needed anywhere + self.lib_path = os.path.join(self.base_path, "lib") + + # Local output + self.out_path = out_path + self.bin_path = os.path.join(self.out_path, "bin") + self.global_explorer_out_path = os.path.join(self.out_path, "explorer") + self.object_base_path = os.path.join(self.out_path, "object") + + self.log = logging.getLogger(self.target_host) + + def create_directories(self): + self.mkdir(self.out_path) + self.mkdir(self.bin_path) + + def rmdir(self, path): + """Remove directory on the local side.""" + self.log.debug("Local rmdir: %s", path) + shutil.rmtree(path) + + def mkdir(self, path): + """Create directory on the local side.""" + self.log.debug("Local mkdir: %s", path) + os.makedirs(path, mode=0o700, exist_ok=True) + + def run(self, command, env=None): + """Run the given command with the given environment. + 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) + try: + return subprocess.check_output(command, env=env) + except subprocess.CalledProcessError: + raise cdist.Error("Command failed: " + " ".join(command)) + except OSError as error: + raise cdist.Error(" ".join(*args) + ": " + error.args[1]) + + def run_script(self, script, env=None): + """Run the given script with the given environment. + Return the output as a string. + + """ + command = ["/bin/sh", "-e"] + command.append(script) + + self.log.debug("Local run script: %s", command) + if env: + self.log.debug("Local run script env: %s", env) + + try: + return subprocess.check_output(command, env=env) + except subprocess.CalledProcessError as error: + script_content = self.run(["cat", script]) + self.log.error("Code that raised the error:\n%s", script_content) + raise LocalScriptError(script, command, script_content) + except EnvironmentError as error: + raise cdist.Error(" ".join(command) + ": " + error.args[1]) diff --git a/lib/cdist/test/exec/test_local.py b/lib/cdist/test/exec/test_local.py new file mode 100644 index 00000000..2c021404 --- /dev/null +++ b/lib/cdist/test/exec/test_local.py @@ -0,0 +1,102 @@ +# -*- 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 unittest +import os +import tempfile +import getpass +import shutil +import string +import random + +#import logging +#logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s') + +import cdist +from cdist.exec import local + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') +local_base_path = fixtures + + +class LocalTestCase(unittest.TestCase): + + def mkdtemp(self, **kwargs): + return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) + + def mkstemp(self, **kwargs): + return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) + + def setUp(self): + self.temp_dir = self.mkdtemp() + target_host = 'localhost' + out_path = self.temp_dir + self.local = local.Local(target_host, local_base_path, out_path) + + def tearDown(self): + #shutil.rmtree(self.temp_dir) + pass + + def test_run_success(self): + self.local.run(['/bin/true']) + + def test_run_fail(self): + self.assertRaises(cdist.Error, self.local.run, ['/bin/false']) + + def test_run_script_success(self): + handle, script = self.mkstemp(dir=self.temp_dir) + fd = open(script, "w") + fd.writelines(["#!/bin/sh\n", "/bin/true"]) + fd.close() + self.local.run_script(script) + + def test_run_script_fail(self): + handle, script = self.mkstemp(dir=self.temp_dir) + fd = open(script, "w") + fd.writelines(["#!/bin/sh\n", "/bin/false"]) + fd.close() + self.assertRaises(local.LocalScriptError, self.local.run_script, script) + + def test_run_script_get_output(self): + handle, script = self.mkstemp(dir=self.temp_dir) + fd = open(script, "w") + fd.writelines(["#!/bin/sh\n", "echo foobar"]) + fd.close() + self.assertEqual(self.local.run_script(script), b"foobar\n") + + def test_mkdir(self): + temp_dir = self.mkdtemp(dir=self.temp_dir) + os.rmdir(temp_dir) + self.local.mkdir(temp_dir) + self.assertTrue(os.path.isdir(temp_dir)) + + def test_rmdir(self): + temp_dir = self.mkdtemp(dir=self.temp_dir) + self.local.rmdir(temp_dir) + self.assertFalse(os.path.isdir(temp_dir)) + + def test_create_directories(self): + self.local.create_directories() + print('self.local.bin_path: %s' % self.local.bin_path) + self.assertTrue(os.path.isdir(self.local.out_path)) + self.assertTrue(os.path.isdir(self.local.bin_path)) From 424c06093415d06a20a5a3c2b47fb09d5a0fef6e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 15:21:25 +0200 Subject: [PATCH 0761/4212] +FIXME Signed-off-by: Steven Armstrong --- lib/cdist/exec/local.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index b9c511f4..18454b8f 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -20,6 +20,8 @@ # # +# FIXME: common base class with Remote? + import io import os import sys From 117ccf94d311d618b08932c2c485af41151a889a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 16:13:22 +0200 Subject: [PATCH 0762/4212] --debug Signed-off-by: Steven Armstrong --- lib/cdist/test/exec/test_local.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/cdist/test/exec/test_local.py b/lib/cdist/test/exec/test_local.py index 2c021404..40611a0b 100644 --- a/lib/cdist/test/exec/test_local.py +++ b/lib/cdist/test/exec/test_local.py @@ -54,8 +54,7 @@ class LocalTestCase(unittest.TestCase): self.local = local.Local(target_host, local_base_path, out_path) def tearDown(self): - #shutil.rmtree(self.temp_dir) - pass + shutil.rmtree(self.temp_dir) def test_run_success(self): self.local.run(['/bin/true']) From 5f358a5ef124bacbed18ab046b8ea4c3ee22d274 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 16:46:54 +0200 Subject: [PATCH 0763/4212] move link_emulator to local Signed-off-by: Steven Armstrong --- lib/cdist/exec/local.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index 18454b8f..aec65e68 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -30,6 +30,7 @@ import shutil import logging import cdist +from cdist import core class LocalScriptError(cdist.Error): @@ -118,3 +119,13 @@ class Local(object): raise LocalScriptError(script, command, script_content) except EnvironmentError as error: raise cdist.Error(" ".join(command) + ": " + error.args[1]) + + def link_emulator(self, exec_path): + """Link emulator to types""" + src = os.path.abspath(exec_path) + for cdist_type in core.Type.list_types(self.type_base_path): + dst = os.path.join(self.bin_path, cdist_type.name) + self.log.debug("Linking emulator: %s to %s", src, dst) + + # FIXME: handle exceptions + os.symlink(src, dst) From d2878e931ed572820da507b17761a03ad82a97ed Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 16:50:21 +0200 Subject: [PATCH 0764/4212] /Remote/Local/ Signed-off-by: Steven Armstrong --- lib/cdist/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index aec65e68..b346bf7d 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -40,7 +40,7 @@ class LocalScriptError(cdist.Error): self.script_content = script_content def __str__(self): - return "Remote script execution failed: %s %s" % (self.script, self.command) + return "Local script execution failed: %s %s" % (self.script, self.command) class Local(object): From 78fd611bb02faa5d552bf4efbf94f7ed6f0e67bb Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 16:56:16 +0200 Subject: [PATCH 0765/4212] fix cdist_base_path Signed-off-by: Steven Armstrong --- lib/cdist/test/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/test/__init__.py b/lib/cdist/test/__init__.py index 06c87917..2f88bf7e 100644 --- a/lib/cdist/test/__init__.py +++ b/lib/cdist/test/__init__.py @@ -28,7 +28,7 @@ import unittest cdist_commands=["banner", "config", "install"] cdist_base_path = os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../")) + os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../")) cdist_exec_path = os.path.join(cdist_base_path, "bin/cdist") From e8f7fe3faae1551b37baebc343fc6e862538e7fe Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 16:59:02 +0200 Subject: [PATCH 0766/4212] intermediate commit for cdist state Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 3 +++ lib/cdist/explorer.py | 47 ++++++++++++++++++++----------------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 152d6c4a..ad748f0b 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -53,6 +53,9 @@ class ConfigInstall(object): self.explorer = cdist.explorer.Explorer(self.context) #self.manifest = cdist.manifest.Mamifest() + self.manifest.initial_manifest() + self.manifest.type_manifest(cdist_object) + self.log = logging.getLogger(self.context.target_host) # Setup env to be used by others - FIXME diff --git a/lib/cdist/explorer.py b/lib/cdist/explorer.py index 9030e506..46139ece 100644 --- a/lib/cdist/explorer.py +++ b/lib/cdist/explorer.py @@ -40,11 +40,33 @@ class Explorer: def __init__(self, context): self.context = context + + self.global_explorer_path = os.path.join(self.context.conf_path, "explorer") + + self. + try: os.mkdir(self.context.global_explorer_out_path) except OSError as e: raise cdist.Error("Failed to create explorer out path: %s" % e) + def run_global_explorers(self): + """Run global explorers""" + log.info("Running global explorers") + + src_path = self.context.global_explorer_path + dst_path = self.context.remote_global_explorer_path + + self.exec_wrapper.transfer_path(src_path, dst_path) + + outputs = {} + for explorer in os.listdir(src_path): + outputs[explorer] = io.StringIO() + cmd = [] + cmd.append("__explorer=" + remote_dst_path) + cmd.append(os.path.join(remote_dst_path, explorer)) + cdist.exec.run_or_fail(cmd, stdout=outputs[explorer], remote_prefix=True) + def run_type_explorer(self, cdist_object): """Run type specific explorers for objects""" @@ -52,12 +74,12 @@ class Explorer: self.transfer_type_explorers(cdist_type) cmd = [] - cmd.append("__explorer=" + self.remote_global_explorer_path) + cmd.append("__explorer=" + self.context.remote_global_explorer_path) cmd.append("__type_explorer=" + os.path.join( - self.remote_type_path, + self.context.remote_type_path, cdist_type.explorer_path)) cmd.append("__object=" + os.path.join( - self.remote_object_path, + self.context.remote_object_path, cdist_object.path)) cmd.append("__object_id=" + cdist_object.object_id) cmd.append("__object_fq=" + cdist_object.name) @@ -67,7 +89,7 @@ class Explorer: outputs = {} for explorer in cdist_type.explorers: - remote_cmd = cmd + [os.path.join(self.remote_type_path, + remote_cmd = cmd + [os.path.join(self.context.remote_type_path, cdist_type.explorer_path, explorer)] outputs[explorer] = io.StringIO() log.debug("%s exploring %s using %s storing to %s", @@ -77,23 +99,6 @@ class Explorer: return outputs - def run_global_explorers(self): - """Run global explorers""" - log.info("Running global explorers") - - src_path = self.global_explorer_path - dst_path = self.remote_global_explorer_path - - self.transfer_path(src_path, dst_path) - - outputs = {} - for explorer in os.listdir(src_path): - outputs[explorer] = io.StringIO() - cmd = [] - cmd.append("__explorer=" + remote_dst_path) - cmd.append(os.path.join(remote_dst_path, explorer)) - cdist.exec.run_or_fail(cmd, stdout=outputs[explorer], remote_prefix=True) - def transfer_object_parameter(self, cdist_object): """Transfer the object parameter to the remote destination""" src = os.path.join(self.object_base_path, From b8cbf22086e35da72dd5ecf575c4c407d2bfba5f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 17:00:00 +0200 Subject: [PATCH 0767/4212] add global and type explorer Signed-off-by: Nico Schottelius --- lib/cdist/{explorer.py => global_explorer.py} | 0 lib/cdist/type_explorer.py | 155 ++++++++++++++++++ 2 files changed, 155 insertions(+) rename lib/cdist/{explorer.py => global_explorer.py} (100%) create mode 100644 lib/cdist/type_explorer.py diff --git a/lib/cdist/explorer.py b/lib/cdist/global_explorer.py similarity index 100% rename from lib/cdist/explorer.py rename to lib/cdist/global_explorer.py diff --git a/lib/cdist/type_explorer.py b/lib/cdist/type_explorer.py new file mode 100644 index 00000000..46139ece --- /dev/null +++ b/lib/cdist/type_explorer.py @@ -0,0 +1,155 @@ +#!/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 io +import logging +import os +#import stat +#import shutil +#import sys +#import tempfile +#import time +# +#import cdist.exec + +import cdist + +log = logging.getLogger(__name__) + +class Explorer: + """Execute explorers""" + + def __init__(self, context): + self.context = context + + self.global_explorer_path = os.path.join(self.context.conf_path, "explorer") + + self. + + try: + os.mkdir(self.context.global_explorer_out_path) + except OSError as e: + raise cdist.Error("Failed to create explorer out path: %s" % e) + + def run_global_explorers(self): + """Run global explorers""" + log.info("Running global explorers") + + src_path = self.context.global_explorer_path + dst_path = self.context.remote_global_explorer_path + + self.exec_wrapper.transfer_path(src_path, dst_path) + + outputs = {} + for explorer in os.listdir(src_path): + outputs[explorer] = io.StringIO() + cmd = [] + cmd.append("__explorer=" + remote_dst_path) + cmd.append(os.path.join(remote_dst_path, explorer)) + cdist.exec.run_or_fail(cmd, stdout=outputs[explorer], remote_prefix=True) + + def run_type_explorer(self, cdist_object): + """Run type specific explorers for objects""" + + cdist_type = cdist_object.type + self.transfer_type_explorers(cdist_type) + + cmd = [] + cmd.append("__explorer=" + self.context.remote_global_explorer_path) + cmd.append("__type_explorer=" + os.path.join( + self.context.remote_type_path, + cdist_type.explorer_path)) + cmd.append("__object=" + os.path.join( + self.context.remote_object_path, + cdist_object.path)) + cmd.append("__object_id=" + cdist_object.object_id) + cmd.append("__object_fq=" + cdist_object.name) + + # Need to transfer at least the parameters for objects to be useful + self.transfer_object_parameter(cdist_object) + + outputs = {} + for explorer in cdist_type.explorers: + remote_cmd = cmd + [os.path.join(self.context.remote_type_path, + cdist_type.explorer_path, explorer)] + outputs[explorer] = io.StringIO() + log.debug("%s exploring %s using %s storing to %s", + cdist_object, explorer, remote_cmd, output) + + cdist.exec.run_or_fail(remote_cmd, stdout=outputs[explorer], remote_prefix=True) + + return outputs + + def transfer_object_parameter(self, cdist_object): + """Transfer the object parameter to the remote destination""" + src = os.path.join(self.object_base_path, + cdist_object.parameter_path) + dst = os.path.join(self.remote_object_path, + cdist_object.parameter_path) + + # Synchronise parameter dir afterwards + self.remote_mkdir(dst) + self.transfer_path(src, dst) + + def transfer_global_explorers(self): + """Transfer the global explorers""" + self.remote_mkdir(self.remote_global_explorer_path) + self.transfer_path(self.global_explorer_path, + self.remote_global_explorer_path) + + def transfer_type_explorers(self, cdist_type): + """Transfer explorers of a type, but only once""" + if cdist_type.transferred_explorers: + log.debug("Skipping retransfer for explorers of %s", cdist_type) + return + else: + log.debug("Ensure no retransfer for %s", cdist_type) + # Do not retransfer + cdist_type.transferred_explorers = True + + explorers = cdist_type.explorers + + if len(explorers) > 0: + rel_path = cdist_type.explorer_path + src = os.path.join(self.type_base_path, rel_path) + dst = os.path.join(self.remote_type_path, rel_path) + + # Ensure full path until type exists: + # /var/lib/cdist/conf/type/__directory/explorer + # /var/lib/cdist/conf/type/__directory may not exist, + # but remote_mkdir uses -p to fix this + self.remote_mkdir(dst) + self.transfer_path(src, dst) + + def remote_mkdir(self, directory): + """Create directory on remote side""" + cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) + + def remove_remote_path(self, destination): + """Ensure path on remote side vanished""" + cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) + + def transfer_path(self, source, destination): + """Transfer directory and previously delete the remote destination""" + self.remove_remote_path(destination) + cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + + ["-r", source, self.target_host + ":" + destination]) From a254e1f31e5f34cc4944de922131688a692c0fd5 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 17:12:22 +0200 Subject: [PATCH 0768/4212] return output of command execution as string instead of bytestring Signed-off-by: Steven Armstrong --- lib/cdist/exec/local.py | 4 ++-- lib/cdist/exec/remote.py | 4 ++-- lib/cdist/test/exec/test_local.py | 2 +- lib/cdist/test/exec/test_remote.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index b346bf7d..521d56c3 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -93,7 +93,7 @@ class Local(object): assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %s" % command self.log.debug("Local run: %s", command) try: - return subprocess.check_output(command, env=env) + return subprocess.check_output(command, env=env).decode() except subprocess.CalledProcessError: raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: @@ -112,7 +112,7 @@ class Local(object): self.log.debug("Local run script env: %s", env) try: - return subprocess.check_output(command, env=env) + return subprocess.check_output(command, env=env).decode() except subprocess.CalledProcessError as error: script_content = self.run(["cat", script]) self.log.error("Code that raised the error:\n%s", script_content) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 6ec9c46f..7821e993 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -104,7 +104,7 @@ class Remote(object): assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %s" % command self.log.debug("Remote run: %s", command) try: - return subprocess.check_output(command, env=env) + return subprocess.check_output(command, env=env).decode() except subprocess.CalledProcessError: raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: @@ -125,7 +125,7 @@ class Remote(object): self.log.debug("Remote run script env: %s", env) try: - return subprocess.check_output(command, env=env) + return subprocess.check_output(command, env=env).decode() except subprocess.CalledProcessError as error: script_content = self.run(["cat", script]) self.log.error("Code that raised the error:\n%s", script_content) diff --git a/lib/cdist/test/exec/test_local.py b/lib/cdist/test/exec/test_local.py index 40611a0b..b74f412e 100644 --- a/lib/cdist/test/exec/test_local.py +++ b/lib/cdist/test/exec/test_local.py @@ -81,7 +81,7 @@ class LocalTestCase(unittest.TestCase): fd = open(script, "w") fd.writelines(["#!/bin/sh\n", "echo foobar"]) fd.close() - self.assertEqual(self.local.run_script(script), b"foobar\n") + self.assertEqual(self.local.run_script(script), "foobar\n") def test_mkdir(self): temp_dir = self.mkdtemp(dir=self.temp_dir) diff --git a/lib/cdist/test/exec/test_remote.py b/lib/cdist/test/exec/test_remote.py index ae5e7aed..1fdb5833 100644 --- a/lib/cdist/test/exec/test_remote.py +++ b/lib/cdist/test/exec/test_remote.py @@ -76,7 +76,7 @@ class RemoteTestCase(unittest.TestCase): fd = open(script, "w") fd.writelines(["#!/bin/sh\n", "echo foobar"]) fd.close() - self.assertEqual(self.remote.run_script(script), b"foobar\n") + self.assertEqual(self.remote.run_script(script), "foobar\n") def test_mkdir(self): temp_dir = self.mkdtemp(dir=self.temp_dir) From 5df8479c5a6e69a85c59a923a435003c060cba4b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 17:20:47 +0200 Subject: [PATCH 0769/4212] implement Manifest and tests Signed-off-by: Steven Armstrong --- lib/cdist/core/manifest.py | 94 +++++++++++++++++++ lib/cdist/test/manifest/__init__.py | 87 +++++++++++++++++ .../fixtures/conf/manifest/dump_environment | 7 ++ .../test/manifest/fixtures/conf/manifest/init | 4 + .../manifest/fixtures/conf/type/__moon/.keep | 0 .../fixtures/conf/type/__moon/manifest | 8 ++ .../conf/type/__moon/parameter/optional | 1 + .../conf/type/__moon/parameter/required | 1 + .../fixtures/conf/type/__planet/.keep | 0 .../fixtures/conf/type/__planet/manifest | 8 ++ .../conf/type/__planet/parameter/optional | 1 + 11 files changed, 211 insertions(+) create mode 100644 lib/cdist/core/manifest.py create mode 100644 lib/cdist/test/manifest/__init__.py create mode 100755 lib/cdist/test/manifest/fixtures/conf/manifest/dump_environment create mode 100755 lib/cdist/test/manifest/fixtures/conf/manifest/init create mode 100644 lib/cdist/test/manifest/fixtures/conf/type/__moon/.keep create mode 100755 lib/cdist/test/manifest/fixtures/conf/type/__moon/manifest create mode 100644 lib/cdist/test/manifest/fixtures/conf/type/__moon/parameter/optional create mode 100644 lib/cdist/test/manifest/fixtures/conf/type/__moon/parameter/required create mode 100644 lib/cdist/test/manifest/fixtures/conf/type/__planet/.keep create mode 100755 lib/cdist/test/manifest/fixtures/conf/type/__planet/manifest create mode 100644 lib/cdist/test/manifest/fixtures/conf/type/__planet/parameter/optional diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py new file mode 100644 index 00000000..8f9fc7ae --- /dev/null +++ b/lib/cdist/core/manifest.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 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 logging +import os + +import cdist + +log = logging.getLogger(__name__) + + +''' +common: + runs only locally, does not need remote + + env: + PATH: prepend directory with type emulator symlinks == local.bin_path + __target_host: the target host we are working on + __global: full qualified path to the global output dir == local.out_path + __cdist_manifest: full qualified path of the manifest == script + __cdist_type_base_path: full qualified path to the directory where types are defined for use in type emulator + == local.type_base_path + +initial manifest is: + script: full qualified path to the initial manifest + + env: + __manifest: path to .../conf/manifest/ == local.manifest_path + + creates: new objects through type emulator + +type manifeste is: + script: full qualified path to the type manifest + + env: + __object: full qualified path to the object's dir + __object_id: the objects id + __object_fq: full qualified object id, iow: $type.name + / + object_id + __type: full qualified path to the type's dir + + creates: new objects through type emulator +''' + + +class Manifest(object): + """Represents a cdist manifest. + + """ + def __init__(self, target_host, local): + self.target_host = target_host + self.local = local + self.env = { + 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), + '__target_host': self.target_host, + '__global': self.local.out_path, + '__cdist_type_base_path': self.local.type_base_path, # for use in type emulator + } + + def run_initial_manifest(self, script): + env = os.environ.copy() + env.update(self.env) + env['__manifest'] = self.local.manifest_path + return self.local.run_script(script, env=env) + + def run_type_manifest(self, cdist_object): + env = os.environ.copy() + env.update(self.env) + env.update({ + '__object': cdist_object.absolute_path, + '__object_id': cdist_object.object_id, + '__object_fq': cdist_object.path, + '__type': cdist_object.type.absolute_path, + }) + script = os.path.join(self.local.type_base_path, cdist_object.type.manifest_path) + return self.local.run_script(script, env=env) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py new file mode 100644 index 00000000..8fcb5d79 --- /dev/null +++ b/lib/cdist/test/manifest/__init__.py @@ -0,0 +1,87 @@ +# -*- 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 unittest +import os +import tempfile +import getpass +import shutil +import string +import random + +#import logging +#logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s') + +import cdist +from cdist.exec import local +from cdist import core +from cdist.core import manifest + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') +local_base_path = fixtures + + +class ManifestTestCase(unittest.TestCase): + + def mkdtemp(self, **kwargs): + return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) + + def mkstemp(self, **kwargs): + return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) + + def setUp(self): + self.temp_dir = self.mkdtemp() + target_host = 'localhost' + out_path = self.temp_dir + self.local = local.Local(target_host, local_base_path, out_path) + self.local.create_directories() + self.local.link_emulator(cdist.test.cdist_exec_path) + self.manifest = manifest.Manifest(target_host, self.local) + + def tearDown(self): + #shutil.rmtree(self.temp_dir) + pass + + def test_initial_manifest_environment(self): + #initial_manifest = os.path.join(self.local.manifest_path, "init") + initial_manifest = os.path.join(self.local.manifest_path, "dump_environment") + output_string = self.manifest.run_initial_manifest(initial_manifest) + output_dict = {} + for line in output_string.split('\n'): + if line: + key,value = line.split(': ') + output_dict[key] = value + self.assertTrue(output_dict['PATH'].startswith(self.local.bin_path)) + self.assertEqual(output_dict['__target_host'], self.local.target_host) + self.assertEqual(output_dict['__global'], self.local.out_path) + self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_base_path) + self.assertEqual(output_dict['__manifest'], self.local.manifest_path) + + +# for line in output.split('\n'): +# print(line) + +# def test_type_manifest(self): +# cdist_type = core.Type(self.local.type_base_path, '__moon') +# cdist_object = core.Object(cdist_type, self.local.object_base_path, 'Saturn') +# self.manifest.run_type_manifest(cdist_object) diff --git a/lib/cdist/test/manifest/fixtures/conf/manifest/dump_environment b/lib/cdist/test/manifest/fixtures/conf/manifest/dump_environment new file mode 100755 index 00000000..1abe7755 --- /dev/null +++ b/lib/cdist/test/manifest/fixtures/conf/manifest/dump_environment @@ -0,0 +1,7 @@ +#!/bin/sh + +echo "PATH: $PATH" +echo "__target_host: $__target_host" +echo "__global: $__global" +echo "__cdist_type_base_path: $__cdist_type_base_path" +echo "__manifest: $__manifest" diff --git a/lib/cdist/test/manifest/fixtures/conf/manifest/init b/lib/cdist/test/manifest/fixtures/conf/manifest/init new file mode 100755 index 00000000..0bdb391a --- /dev/null +++ b/lib/cdist/test/manifest/fixtures/conf/manifest/init @@ -0,0 +1,4 @@ +#!/bin/sh + +__planet Saturn +__moon Prometheus --planet Saturn diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__moon/.keep b/lib/cdist/test/manifest/fixtures/conf/type/__moon/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__moon/manifest b/lib/cdist/test/manifest/fixtures/conf/type/__moon/manifest new file mode 100755 index 00000000..362be5a1 --- /dev/null +++ b/lib/cdist/test/manifest/fixtures/conf/type/__moon/manifest @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ -f "$__object/parameter/name" ]; then + name="(cat "$__object/parameter/name")" +else + name="$__object_id" + echo "$name" > "$__object/parameter/name" +fi diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__moon/parameter/optional b/lib/cdist/test/manifest/fixtures/conf/type/__moon/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/lib/cdist/test/manifest/fixtures/conf/type/__moon/parameter/optional @@ -0,0 +1 @@ +name diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__moon/parameter/required b/lib/cdist/test/manifest/fixtures/conf/type/__moon/parameter/required new file mode 100644 index 00000000..729a5167 --- /dev/null +++ b/lib/cdist/test/manifest/fixtures/conf/type/__moon/parameter/required @@ -0,0 +1 @@ +planet diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__planet/.keep b/lib/cdist/test/manifest/fixtures/conf/type/__planet/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__planet/manifest b/lib/cdist/test/manifest/fixtures/conf/type/__planet/manifest new file mode 100755 index 00000000..362be5a1 --- /dev/null +++ b/lib/cdist/test/manifest/fixtures/conf/type/__planet/manifest @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ -f "$__object/parameter/name" ]; then + name="(cat "$__object/parameter/name")" +else + name="$__object_id" + echo "$name" > "$__object/parameter/name" +fi diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__planet/parameter/optional b/lib/cdist/test/manifest/fixtures/conf/type/__planet/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/lib/cdist/test/manifest/fixtures/conf/type/__planet/parameter/optional @@ -0,0 +1 @@ +name From d93d132c05a89e36afc5dde8bea2d122f0a7d6bf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 17:27:21 +0200 Subject: [PATCH 0770/4212] finish global_explorer (in theory) Signed-off-by: Nico Schottelius --- lib/cdist/global_explorer.py | 104 ++--------------------------------- 1 file changed, 6 insertions(+), 98 deletions(-) diff --git a/lib/cdist/global_explorer.py b/lib/cdist/global_explorer.py index 46139ece..9929cfd6 100644 --- a/lib/cdist/global_explorer.py +++ b/lib/cdist/global_explorer.py @@ -35,30 +35,19 @@ import cdist log = logging.getLogger(__name__) -class Explorer: +class GlobalExplorer: """Execute explorers""" - def __init__(self, context): + def __init__(self, local_path, remote_path): self.context = context - self.global_explorer_path = os.path.join(self.context.conf_path, "explorer") + self.local_path = local_path + self.remote_path = remote_path - self. - - try: - os.mkdir(self.context.global_explorer_out_path) - except OSError as e: - raise cdist.Error("Failed to create explorer out path: %s" % e) - - def run_global_explorers(self): + def run(self): """Run global explorers""" log.info("Running global explorers") - src_path = self.context.global_explorer_path - dst_path = self.context.remote_global_explorer_path - - self.exec_wrapper.transfer_path(src_path, dst_path) - outputs = {} for explorer in os.listdir(src_path): outputs[explorer] = io.StringIO() @@ -67,89 +56,8 @@ class Explorer: cmd.append(os.path.join(remote_dst_path, explorer)) cdist.exec.run_or_fail(cmd, stdout=outputs[explorer], remote_prefix=True) - def run_type_explorer(self, cdist_object): - """Run type specific explorers for objects""" - - cdist_type = cdist_object.type - self.transfer_type_explorers(cdist_type) - - cmd = [] - cmd.append("__explorer=" + self.context.remote_global_explorer_path) - cmd.append("__type_explorer=" + os.path.join( - self.context.remote_type_path, - cdist_type.explorer_path)) - cmd.append("__object=" + os.path.join( - self.context.remote_object_path, - cdist_object.path)) - cmd.append("__object_id=" + cdist_object.object_id) - cmd.append("__object_fq=" + cdist_object.name) - - # Need to transfer at least the parameters for objects to be useful - self.transfer_object_parameter(cdist_object) - - outputs = {} - for explorer in cdist_type.explorers: - remote_cmd = cmd + [os.path.join(self.context.remote_type_path, - cdist_type.explorer_path, explorer)] - outputs[explorer] = io.StringIO() - log.debug("%s exploring %s using %s storing to %s", - cdist_object, explorer, remote_cmd, output) - - cdist.exec.run_or_fail(remote_cmd, stdout=outputs[explorer], remote_prefix=True) - - return outputs - - def transfer_object_parameter(self, cdist_object): - """Transfer the object parameter to the remote destination""" - src = os.path.join(self.object_base_path, - cdist_object.parameter_path) - dst = os.path.join(self.remote_object_path, - cdist_object.parameter_path) - - # Synchronise parameter dir afterwards - self.remote_mkdir(dst) - self.transfer_path(src, dst) - - def transfer_global_explorers(self): + def transfer(self): """Transfer the global explorers""" self.remote_mkdir(self.remote_global_explorer_path) self.transfer_path(self.global_explorer_path, self.remote_global_explorer_path) - - def transfer_type_explorers(self, cdist_type): - """Transfer explorers of a type, but only once""" - if cdist_type.transferred_explorers: - log.debug("Skipping retransfer for explorers of %s", cdist_type) - return - else: - log.debug("Ensure no retransfer for %s", cdist_type) - # Do not retransfer - cdist_type.transferred_explorers = True - - explorers = cdist_type.explorers - - if len(explorers) > 0: - rel_path = cdist_type.explorer_path - src = os.path.join(self.type_base_path, rel_path) - dst = os.path.join(self.remote_type_path, rel_path) - - # Ensure full path until type exists: - # /var/lib/cdist/conf/type/__directory/explorer - # /var/lib/cdist/conf/type/__directory may not exist, - # but remote_mkdir uses -p to fix this - self.remote_mkdir(dst) - self.transfer_path(src, dst) - - def remote_mkdir(self, directory): - """Create directory on remote side""" - cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) - - def remove_remote_path(self, destination): - """Ensure path on remote side vanished""" - cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) - - def transfer_path(self, source, destination): - """Transfer directory and previously delete the remote destination""" - self.remove_remote_path(destination) - cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + - ["-r", source, self.target_host + ":" + destination]) From 1aa2c48baf94b17c148d1671be4e86f384b0ffcb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 17:36:00 +0200 Subject: [PATCH 0771/4212] new style classes Signed-off-by: Nico Schottelius --- lib/cdist/global_explorer.py | 4 +--- lib/cdist/type_explorer.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/cdist/global_explorer.py b/lib/cdist/global_explorer.py index 9929cfd6..8a9b8c73 100644 --- a/lib/cdist/global_explorer.py +++ b/lib/cdist/global_explorer.py @@ -35,12 +35,10 @@ import cdist log = logging.getLogger(__name__) -class GlobalExplorer: +class GlobalExplorer(object): """Execute explorers""" def __init__(self, local_path, remote_path): - self.context = context - self.local_path = local_path self.remote_path = remote_path diff --git a/lib/cdist/type_explorer.py b/lib/cdist/type_explorer.py index 46139ece..7d8df3b2 100644 --- a/lib/cdist/type_explorer.py +++ b/lib/cdist/type_explorer.py @@ -35,7 +35,7 @@ import cdist log = logging.getLogger(__name__) -class Explorer: +class TypeExplorer(object): """Execute explorers""" def __init__(self, context): From 9a33bd3b909a73736abef11c3f3846f390319c9c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 17:56:45 +0200 Subject: [PATCH 0772/4212] test type manifest environment Signed-off-by: Steven Armstrong --- lib/cdist/test/manifest/__init__.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index 8fcb5d79..01d3696a 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -81,7 +81,21 @@ class ManifestTestCase(unittest.TestCase): # for line in output.split('\n'): # print(line) -# def test_type_manifest(self): -# cdist_type = core.Type(self.local.type_base_path, '__moon') -# cdist_object = core.Object(cdist_type, self.local.object_base_path, 'Saturn') -# self.manifest.run_type_manifest(cdist_object) + def test_type_manifest_environment(self): + cdist_type = core.Type(self.local.type_base_path, '__dump_environment') + cdist_object = core.Object(cdist_type, self.local.object_base_path, 'whatever') + + output_string = self.manifest.run_type_manifest(cdist_object) + output_dict = {} + for line in output_string.split('\n'): + if line: + key,value = line.split(': ') + output_dict[key] = value + self.assertTrue(output_dict['PATH'].startswith(self.local.bin_path)) + self.assertEqual(output_dict['__target_host'], self.local.target_host) + self.assertEqual(output_dict['__global'], self.local.out_path) + self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_base_path) + self.assertEqual(output_dict['__type'], cdist_type.absolute_path) + self.assertEqual(output_dict['__object'], cdist_object.absolute_path) + self.assertEqual(output_dict['__object_id'], cdist_object.object_id) + self.assertEqual(output_dict['__object_fq'], cdist_object.path) From 1c38fb492e0989ba307b583fe5a5f35b3e6d5f8a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 17:57:06 +0200 Subject: [PATCH 0773/4212] fixtures for type manifest environment test Signed-off-by: Steven Armstrong --- .../fixtures/conf/type/__dump_environment/manifest | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest b/lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest new file mode 100755 index 00000000..92f533a8 --- /dev/null +++ b/lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest @@ -0,0 +1,10 @@ +#!/bin/sh + +echo "PATH: $PATH" +echo "__target_host: $__target_host" +echo "__global: $__global" +echo "__cdist_type_base_path: $__cdist_type_base_path" +echo "__type: $__type" +echo "__object: $__object" +echo "__object_id: $__object_id" +echo "__object_fq: $__object_fq" From fb80a9555565360e107ddb58e04f6274cd38a2cb Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 17:58:09 +0200 Subject: [PATCH 0774/4212] --debug Signed-off-by: Steven Armstrong --- lib/cdist/test/manifest/__init__.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index 01d3696a..ffbbff29 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -59,11 +59,9 @@ class ManifestTestCase(unittest.TestCase): self.manifest = manifest.Manifest(target_host, self.local) def tearDown(self): - #shutil.rmtree(self.temp_dir) - pass + shutil.rmtree(self.temp_dir) def test_initial_manifest_environment(self): - #initial_manifest = os.path.join(self.local.manifest_path, "init") initial_manifest = os.path.join(self.local.manifest_path, "dump_environment") output_string = self.manifest.run_initial_manifest(initial_manifest) output_dict = {} @@ -76,10 +74,6 @@ class ManifestTestCase(unittest.TestCase): self.assertEqual(output_dict['__global'], self.local.out_path) self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_base_path) self.assertEqual(output_dict['__manifest'], self.local.manifest_path) - - -# for line in output.split('\n'): -# print(line) def test_type_manifest_environment(self): cdist_type = core.Type(self.local.type_base_path, '__dump_environment') From 09209e47d683c800527cc9f24ba5927e93503b97 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 20:29:53 +0200 Subject: [PATCH 0775/4212] ideas for explorer run Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index ad748f0b..9cb4a0df 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -50,11 +50,17 @@ class ConfigInstall(object): self.__init_local_paths() self.__init_remote_paths() + self.global_explorer = cdist.explorer.GlobalExplorer(self.context.global_in, out) + self.type_explorer = cdist.explorer.GlobalExplorer(self.context.global_in, out) + self.explorer = cdist.explorer.Explorer(self.context) #self.manifest = cdist.manifest.Mamifest() self.manifest.initial_manifest() self.manifest.type_manifest(cdist_object) + self.global_explorer.run()? + + self.type_explorer.run(cdist_object)? self.log = logging.getLogger(self.context.target_host) From 478ee1a09627dd6d7e9e9440252b250176189e01 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 20:30:08 +0200 Subject: [PATCH 0776/4212] -senseless comments Signed-off-by: Nico Schottelius --- lib/cdist/global_explorer.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/cdist/global_explorer.py b/lib/cdist/global_explorer.py index 8a9b8c73..fe0ea018 100644 --- a/lib/cdist/global_explorer.py +++ b/lib/cdist/global_explorer.py @@ -36,8 +36,6 @@ import cdist log = logging.getLogger(__name__) class GlobalExplorer(object): - """Execute explorers""" - def __init__(self, local_path, remote_path): self.local_path = local_path self.remote_path = remote_path From d5e24492bef01b625aff44ab36bab1a2bb211b14 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 20:30:38 +0200 Subject: [PATCH 0777/4212] begin to prepare TypeExplorer Signed-off-by: Nico Schottelius --- lib/cdist/type_explorer.py | 77 ++++++++++---------------------------- 1 file changed, 19 insertions(+), 58 deletions(-) diff --git a/lib/cdist/type_explorer.py b/lib/cdist/type_explorer.py index 7d8df3b2..90c726c3 100644 --- a/lib/cdist/type_explorer.py +++ b/lib/cdist/type_explorer.py @@ -36,65 +36,45 @@ import cdist log = logging.getLogger(__name__) class TypeExplorer(object): - """Execute explorers""" + def __init__(self, + remote_global_explorer_path, + object_base_path, + type_base_path, + remote_object_base_path, + remote_type_base_path + ): - def __init__(self, context): - self.context = context + self.object_base_path = object_base_path + self.global_explorer_path = global_explorer_path + self.type_base_path = type_base_path + self.remote_type_base_path = remote_type_base_path + self.remote_object_path = remote_object_path - self.global_explorer_path = os.path.join(self.context.conf_path, "explorer") - - self. - - try: - os.mkdir(self.context.global_explorer_out_path) - except OSError as e: - raise cdist.Error("Failed to create explorer out path: %s" % e) - - def run_global_explorers(self): - """Run global explorers""" - log.info("Running global explorers") - - src_path = self.context.global_explorer_path - dst_path = self.context.remote_global_explorer_path - - self.exec_wrapper.transfer_path(src_path, dst_path) - - outputs = {} - for explorer in os.listdir(src_path): - outputs[explorer] = io.StringIO() - cmd = [] - cmd.append("__explorer=" + remote_dst_path) - cmd.append(os.path.join(remote_dst_path, explorer)) - cdist.exec.run_or_fail(cmd, stdout=outputs[explorer], remote_prefix=True) - - def run_type_explorer(self, cdist_object): + def run(self, cdist_object): """Run type specific explorers for objects""" cdist_type = cdist_object.type - self.transfer_type_explorers(cdist_type) cmd = [] cmd.append("__explorer=" + self.context.remote_global_explorer_path) cmd.append("__type_explorer=" + os.path.join( - self.context.remote_type_path, + self.remote_type_path, cdist_type.explorer_path)) cmd.append("__object=" + os.path.join( - self.context.remote_object_path, + self.remote_object_base_path, cdist_object.path)) cmd.append("__object_id=" + cdist_object.object_id) cmd.append("__object_fq=" + cdist_object.name) - # Need to transfer at least the parameters for objects to be useful - self.transfer_object_parameter(cdist_object) - outputs = {} for explorer in cdist_type.explorers: - remote_cmd = cmd + [os.path.join(self.context.remote_type_path, + remote_cmd = cmd + [os.path.join(self.remote_type_path, cdist_type.explorer_path, explorer)] outputs[explorer] = io.StringIO() log.debug("%s exploring %s using %s storing to %s", cdist_object, explorer, remote_cmd, output) + # FIXME: change to new style cdist.exec.run_or_fail(remote_cmd, stdout=outputs[explorer], remote_prefix=True) return outputs @@ -103,19 +83,14 @@ class TypeExplorer(object): """Transfer the object parameter to the remote destination""" src = os.path.join(self.object_base_path, cdist_object.parameter_path) - dst = os.path.join(self.remote_object_path, + dst = os.path.join(self.remote_object_base_path, cdist_object.parameter_path) + # FIXME: new style # Synchronise parameter dir afterwards self.remote_mkdir(dst) self.transfer_path(src, dst) - def transfer_global_explorers(self): - """Transfer the global explorers""" - self.remote_mkdir(self.remote_global_explorer_path) - self.transfer_path(self.global_explorer_path, - self.remote_global_explorer_path) - def transfer_type_explorers(self, cdist_type): """Transfer explorers of a type, but only once""" if cdist_type.transferred_explorers: @@ -139,17 +114,3 @@ class TypeExplorer(object): # but remote_mkdir uses -p to fix this self.remote_mkdir(dst) self.transfer_path(src, dst) - - def remote_mkdir(self, directory): - """Create directory on remote side""" - cdist.exec.run_or_fail(["mkdir", "-p", directory], remote_prefix=True) - - def remove_remote_path(self, destination): - """Ensure path on remote side vanished""" - cdist.exec.run_or_fail(["rm", "-rf", destination], remote_prefix=True) - - def transfer_path(self, source, destination): - """Transfer directory and previously delete the remote destination""" - self.remove_remote_path(destination) - cdist.exec.run_or_fail(os.environ['__remote_copy'].split() + - ["-r", source, self.target_host + ":" + destination]) From 0a1418f4d311db9847f0697a5270347b14a78050 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 23:01:41 +0200 Subject: [PATCH 0778/4212] forward env Signed-off-by: Steven Armstrong --- lib/cdist/exec/remote.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 7821e993..63551e7a 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -94,7 +94,7 @@ class Remote(object): cmd = self._exec.split() cmd.append(self.target_host) cmd.extend(command) - return self.run_command(cmd, env=None) + return self.run_command(cmd, env=env) def run_command(self, command, env=None): """Run the given command with the given environment. From 4ad2e4f7422974d03c15cb2f5fa53cb4a2a64d49 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 23:10:05 +0200 Subject: [PATCH 0779/4212] ++more to fix Signed-off-by: Nico Schottelius --- lib/cdist/type_explorer.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/cdist/type_explorer.py b/lib/cdist/type_explorer.py index 90c726c3..9e3c99bf 100644 --- a/lib/cdist/type_explorer.py +++ b/lib/cdist/type_explorer.py @@ -33,6 +33,7 @@ import os import cdist +# FIXME: Logging with hostname log = logging.getLogger(__name__) class TypeExplorer(object): @@ -56,7 +57,7 @@ class TypeExplorer(object): cdist_type = cdist_object.type cmd = [] - cmd.append("__explorer=" + self.context.remote_global_explorer_path) + cmd.append("__explorer=" + self.remote_global_explorer_path) cmd.append("__type_explorer=" + os.path.join( self.remote_type_path, cdist_type.explorer_path)) @@ -75,7 +76,8 @@ class TypeExplorer(object): cdist_object, explorer, remote_cmd, output) # FIXME: change to new style - cdist.exec.run_or_fail(remote_cmd, stdout=outputs[explorer], remote_prefix=True) + cdist.exec.run_or_fail(remote_cmd, stdout=outputs[explorer], + remote_prefix=True) return outputs From f2278c42abf22778408a3ae6048ce2912e77a3bb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 23:10:18 +0200 Subject: [PATCH 0780/4212] init tests for type_explorer Signed-off-by: Nico Schottelius --- lib/cdist/test/type_explorer/__init__.py | 38 ++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 lib/cdist/test/type_explorer/__init__.py diff --git a/lib/cdist/test/type_explorer/__init__.py b/lib/cdist/test/type_explorer/__init__.py new file mode 100644 index 00000000..5e7c82aa --- /dev/null +++ b/lib/cdist/test/type_explorer/__init__.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# +# 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 unittest + +import cdist.core + +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 TypeExplorer(unittest.TestCase): + + def setUp(self): + + def test_explorer_output(self): + From d9af865523b04b2370c8318c1cc13a239ce06ffe Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 23:12:56 +0200 Subject: [PATCH 0781/4212] fixture type with one explorer Signed-off-by: Nico Schottelius --- .../test/type_explorer/fixtures/type/__test_type/explorer/world | 2 ++ 1 file changed, 2 insertions(+) create mode 100755 lib/cdist/test/type_explorer/fixtures/type/__test_type/explorer/world diff --git a/lib/cdist/test/type_explorer/fixtures/type/__test_type/explorer/world b/lib/cdist/test/type_explorer/fixtures/type/__test_type/explorer/world new file mode 100755 index 00000000..21ba6825 --- /dev/null +++ b/lib/cdist/test/type_explorer/fixtures/type/__test_type/explorer/world @@ -0,0 +1,2 @@ +#!/bin/sh +echo hello From 8d591b45e22fe4f5b12e3a4f7f55ab45bd8e2cd3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 23:49:17 +0200 Subject: [PATCH 0782/4212] add type to test whether object parameter can be read Signed-off-by: Nico Schottelius --- .../type/__test_type_object_parameter/explorer/test_parameter | 3 +++ 1 file changed, 3 insertions(+) create mode 100755 lib/cdist/test/type_explorer/fixtures/type/__test_type_object_parameter/explorer/test_parameter diff --git a/lib/cdist/test/type_explorer/fixtures/type/__test_type_object_parameter/explorer/test_parameter b/lib/cdist/test/type_explorer/fixtures/type/__test_type_object_parameter/explorer/test_parameter new file mode 100755 index 00000000..0778907c --- /dev/null +++ b/lib/cdist/test/type_explorer/fixtures/type/__test_type_object_parameter/explorer/test_parameter @@ -0,0 +1,3 @@ +#!/bin/sh + +cat "$__object/parameter/test" From d47039e91e3a76233233029745b4911279bc945d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 12 Oct 2011 23:49:42 +0200 Subject: [PATCH 0783/4212] prepend variables to remote commands Signed-off-by: Steven Armstrong --- lib/cdist/exec/remote.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 63551e7a..2ffc73fd 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -102,9 +102,18 @@ class Remote(object): """ assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %s" % command + + # can't pass environment to remote side, so prepend command with + # variable declarations + if env: + cmd = ["%s=%s" % item for item in env.items()] + cmd.extend(command) + else: + cmd = command + self.log.debug("Remote run: %s", command) try: - return subprocess.check_output(command, env=env).decode() + return subprocess.check_output(cmd).decode() except subprocess.CalledProcessError: raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: @@ -117,6 +126,12 @@ class Remote(object): """ command = self._exec.split() command.append(self.target_host) + + # can't pass environment to remote side, so prepend command with + # variable declarations + if env: + command.extend(["%s=%s" % item for item in env.items()]) + command.extend(["/bin/sh", "-e"]) command.append(script) @@ -125,7 +140,7 @@ class Remote(object): self.log.debug("Remote run script env: %s", env) try: - return subprocess.check_output(command, env=env).decode() + return subprocess.check_output(command).decode() except subprocess.CalledProcessError as error: script_content = self.run(["cat", script]) self.log.error("Code that raised the error:\n%s", script_content) From 50a07da96764445e48a8711497e3c9708ac6df2e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 23:55:02 +0200 Subject: [PATCH 0784/4212] global explorer belongs to core Signed-off-by: Nico Schottelius --- lib/cdist/{ => core}/global_explorer.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/cdist/{ => core}/global_explorer.py (100%) diff --git a/lib/cdist/global_explorer.py b/lib/cdist/core/global_explorer.py similarity index 100% rename from lib/cdist/global_explorer.py rename to lib/cdist/core/global_explorer.py From 6d87f4b917d3e8b96983fd865ec6bc500ac03d5d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Oct 2011 23:59:20 +0200 Subject: [PATCH 0785/4212] integrate global explorer into core Signed-off-by: Nico Schottelius --- lib/cdist/core/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/core/__init__.py b/lib/cdist/core/__init__.py index 80310ffc..d6377b12 100644 --- a/lib/cdist/core/__init__.py +++ b/lib/cdist/core/__init__.py @@ -23,3 +23,4 @@ __all__ = ['Type', 'Object'] from cdist.core.type import Type from cdist.core.object import Object +from cdist.core.global_explorer import GlobalExplorer From 1d85d10f4f9806385f39411bc51c3734ff38e43b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 00:16:02 +0200 Subject: [PATCH 0786/4212] consistent naming: /type_base_path/type_path/ Signed-off-by: Steven Armstrong --- lib/cdist/exec/local.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index 521d56c3..8192bf0c 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -59,7 +59,7 @@ class Local(object): self.conf_path = os.path.join(self.base_path, "conf") self.global_explorer_path = os.path.join(self.conf_path, "explorer") self.manifest_path = os.path.join(self.conf_path, "manifest") - self.type_base_path = os.path.join(self.conf_path, "type") + self.type_path = os.path.join(self.conf_path, "type") # FIXME: should not be needed anywhere self.lib_path = os.path.join(self.base_path, "lib") @@ -123,7 +123,7 @@ class Local(object): def link_emulator(self, exec_path): """Link emulator to types""" src = os.path.abspath(exec_path) - for cdist_type in core.Type.list_types(self.type_base_path): + for cdist_type in core.Type.list_types(self.type_path): dst = os.path.join(self.bin_path, cdist_type.name) self.log.debug("Linking emulator: %s to %s", src, dst) From 8545221787266302ddbe71eef58c147f2c6b7e4e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 00:16:30 +0200 Subject: [PATCH 0787/4212] consistent naming: /object_base_path/object_path/ Signed-off-by: Steven Armstrong --- lib/cdist/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index 8192bf0c..1f253f09 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -67,7 +67,7 @@ class Local(object): self.out_path = out_path self.bin_path = os.path.join(self.out_path, "bin") self.global_explorer_out_path = os.path.join(self.out_path, "explorer") - self.object_base_path = os.path.join(self.out_path, "object") + self.object_path = os.path.join(self.out_path, "object") self.log = logging.getLogger(self.target_host) From 67de9d8c7379c3074b8fce2aeac7bb2e57c8c8a2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 00:20:55 +0200 Subject: [PATCH 0788/4212] tests for Local paths Signed-off-by: Steven Armstrong --- lib/cdist/test/exec/test_local.py | 38 ++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/lib/cdist/test/exec/test_local.py b/lib/cdist/test/exec/test_local.py index b74f412e..8585f87a 100644 --- a/lib/cdist/test/exec/test_local.py +++ b/lib/cdist/test/exec/test_local.py @@ -50,12 +50,45 @@ class LocalTestCase(unittest.TestCase): def setUp(self): self.temp_dir = self.mkdtemp() target_host = 'localhost' - out_path = self.temp_dir - self.local = local.Local(target_host, local_base_path, out_path) + self.out_path = self.temp_dir + self.base_path = local_base_path + self.local = local.Local(target_host, self.base_path, self.out_path) def tearDown(self): shutil.rmtree(self.temp_dir) + ### test api + + def test_cache_path(self): + self.assertEqual(self.local.cache_path, os.path.join(self.base_path, "cache")) + + def test_conf_path(self): + self.assertEqual(self.local.conf_path, os.path.join(self.base_path, "conf")) + + def test_global_explorer_path(self): + self.assertEqual(self.local.global_explorer_path, os.path.join(self.base_path, "conf", "explorer")) + + def test_manifest_path(self): + self.assertEqual(self.local.manifest_path, os.path.join(self.base_path, "conf", "manifest")) + + def test_type_path(self): + self.assertEqual(self.local.type_path, os.path.join(self.base_path, "conf", "type")) + + def test_out_path(self): + self.assertEqual(self.local.out_path, self.out_path) + + def test_bin_path(self): + self.assertEqual(self.local.bin_path, os.path.join(self.out_path, "bin")) + + def test_global_explorer_out_path(self): + self.assertEqual(self.local.global_explorer_out_path, os.path.join(self.out_path, "explorer")) + + def test_object_path(self): + self.assertEqual(self.local.object_path, os.path.join(self.out_path, "object")) + + ### /test api + + def test_run_success(self): self.local.run(['/bin/true']) @@ -96,6 +129,5 @@ class LocalTestCase(unittest.TestCase): def test_create_directories(self): self.local.create_directories() - print('self.local.bin_path: %s' % self.local.bin_path) self.assertTrue(os.path.isdir(self.local.out_path)) self.assertTrue(os.path.isdir(self.local.bin_path)) From 5d2827f66ec9152e4e7928e9d4dd47f803f3d7ff Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 00:24:52 +0200 Subject: [PATCH 0789/4212] tests for Remote paths Signed-off-by: Steven Armstrong --- lib/cdist/test/exec/test_remote.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/cdist/test/exec/test_remote.py b/lib/cdist/test/exec/test_remote.py index 1fdb5833..ea9a17aa 100644 --- a/lib/cdist/test/exec/test_remote.py +++ b/lib/cdist/test/exec/test_remote.py @@ -42,15 +42,31 @@ class RemoteTestCase(unittest.TestCase): def setUp(self): self.temp_dir = self.mkdtemp() target_host = 'localhost' - remote_base_path = self.temp_dir + self.base_path = self.temp_dir user = getpass.getuser() remote_exec = "ssh -o User=%s -q" % user remote_copy = "scp -o User=%s -q" % user - self.remote = remote.Remote(target_host, remote_base_path, remote_exec, remote_copy) + self.remote = remote.Remote(target_host, self.base_path, remote_exec, remote_copy) def tearDown(self): shutil.rmtree(self.temp_dir) + ### test api + + def test_conf_path(self): + self.assertEqual(self.remote.conf_path, os.path.join(self.base_path, "conf")) + + def test_object_path(self): + self.assertEqual(self.remote.object_path, os.path.join(self.base_path, "object")) + + def test_type_path(self): + self.assertEqual(self.remote.type_path, os.path.join(self.base_path, "conf", "type")) + + def test_global_explorer_path(self): + self.assertEqual(self.remote.global_explorer_path, os.path.join(self.base_path, "conf", "explorer")) + + ### /test api + def test_run_success(self): self.remote.run(['/bin/true']) From 48eb996a2e5e150c49705bb3531503a9b9e2f828 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 00:26:11 +0200 Subject: [PATCH 0790/4212] remove useless filename prefix Signed-off-by: Steven Armstrong --- lib/cdist/test/exec/{test_local.py => local.py} | 0 lib/cdist/test/exec/{test_remote.py => remote.py} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename lib/cdist/test/exec/{test_local.py => local.py} (100%) rename lib/cdist/test/exec/{test_remote.py => remote.py} (100%) diff --git a/lib/cdist/test/exec/test_local.py b/lib/cdist/test/exec/local.py similarity index 100% rename from lib/cdist/test/exec/test_local.py rename to lib/cdist/test/exec/local.py diff --git a/lib/cdist/test/exec/test_remote.py b/lib/cdist/test/exec/remote.py similarity index 100% rename from lib/cdist/test/exec/test_remote.py rename to lib/cdist/test/exec/remote.py From a8ec91c80484cf248b49559408cf010db99095a2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 00:35:14 +0200 Subject: [PATCH 0791/4212] -e /type_base_path/type_path/ -e /object_base_path/object_path/ Signed-off-by: Steven Armstrong --- lib/cdist/core/manifest.py | 6 +++--- lib/cdist/test/manifest/__init__.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index 8f9fc7ae..e97ba095 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -38,7 +38,7 @@ common: __global: full qualified path to the global output dir == local.out_path __cdist_manifest: full qualified path of the manifest == script __cdist_type_base_path: full qualified path to the directory where types are defined for use in type emulator - == local.type_base_path + == local.type_path initial manifest is: script: full qualified path to the initial manifest @@ -72,7 +72,7 @@ class Manifest(object): 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), '__target_host': self.target_host, '__global': self.local.out_path, - '__cdist_type_base_path': self.local.type_base_path, # for use in type emulator + '__cdist_type_base_path': self.local.type_path, # for use in type emulator } def run_initial_manifest(self, script): @@ -90,5 +90,5 @@ class Manifest(object): '__object_fq': cdist_object.path, '__type': cdist_object.type.absolute_path, }) - script = os.path.join(self.local.type_base_path, cdist_object.type.manifest_path) + script = os.path.join(self.local.type_path, cdist_object.type.manifest_path) return self.local.run_script(script, env=env) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index ffbbff29..341f4893 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -72,12 +72,12 @@ class ManifestTestCase(unittest.TestCase): 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['__cdist_type_base_path'], self.local.type_base_path) + self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) self.assertEqual(output_dict['__manifest'], self.local.manifest_path) def test_type_manifest_environment(self): - cdist_type = core.Type(self.local.type_base_path, '__dump_environment') - cdist_object = core.Object(cdist_type, self.local.object_base_path, 'whatever') + cdist_type = core.Type(self.local.type_path, '__dump_environment') + cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') output_string = self.manifest.run_type_manifest(cdist_object) output_dict = {} @@ -88,7 +88,7 @@ class ManifestTestCase(unittest.TestCase): 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['__cdist_type_base_path'], self.local.type_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) self.assertEqual(output_dict['__object_id'], cdist_object.object_id) From 62383eed8d8a6a28d7ce44faacaa67bc75c4546f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 13 Oct 2011 03:00:57 +0200 Subject: [PATCH 0792/4212] ++stuff Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 4 ++-- lib/cdist/test/type_explorer/__init__.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 9cb4a0df..a319b88c 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -31,7 +31,7 @@ import time import cdist.core import cdist.context import cdist.exec -import cdist.explorer +#import cdist.explorer #import cdist.manifest class ConfigInstall(object): @@ -53,7 +53,7 @@ class ConfigInstall(object): self.global_explorer = cdist.explorer.GlobalExplorer(self.context.global_in, out) self.type_explorer = cdist.explorer.GlobalExplorer(self.context.global_in, out) - self.explorer = cdist.explorer.Explorer(self.context) + self.global_explorer = cdist.core.GlobalExplorer #self.manifest = cdist.manifest.Mamifest() self.manifest.initial_manifest() diff --git a/lib/cdist/test/type_explorer/__init__.py b/lib/cdist/test/type_explorer/__init__.py index 5e7c82aa..19d59342 100644 --- a/lib/cdist/test/type_explorer/__init__.py +++ b/lib/cdist/test/type_explorer/__init__.py @@ -35,4 +35,5 @@ class TypeExplorer(unittest.TestCase): def setUp(self): def test_explorer_output(self): + """Check for output of type explorer""" From 63eee391e0b49f240ec385ab3936ed321c0a088b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 01:25:31 +0200 Subject: [PATCH 0793/4212] implement Explorer analog to Manifest + tests Signed-off-by: Steven Armstrong --- lib/cdist/core/explorer.py | 109 ++++++++++++++++++ lib/cdist/test/explorer/__init__.py | 87 ++++++++++++++ .../explorer/fixtures/conf/explorer/global | 2 + .../conf/type/__test_type/explorer/world | 2 + .../explorer/test_parameter | 3 + 5 files changed, 203 insertions(+) create mode 100644 lib/cdist/core/explorer.py create mode 100644 lib/cdist/test/explorer/__init__.py create mode 100755 lib/cdist/test/explorer/fixtures/conf/explorer/global create mode 100755 lib/cdist/test/explorer/fixtures/conf/type/__test_type/explorer/world create mode 100755 lib/cdist/test/explorer/fixtures/conf/type/__test_type_object_parameter/explorer/test_parameter diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py new file mode 100644 index 00000000..7e1d48de --- /dev/null +++ b/lib/cdist/core/explorer.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 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 logging +import os + +import cdist + +log = logging.getLogger(__name__) + + +''' +common: + runs only remotely, needs local and remote + + env: + __explorer: full qualified path to other global explorers on remote side == remote.global_explorer_path + +global explorer is: + folder full of scripts which have to be: + (- copied to remote) + - executed one by one on remote + - output saved to local files + + env: + + creates: local files with explorer output + +type explorer is: + folder full of scripts which have to be: + (- copied to remote) + - executed one by one on remote for each object instance + - output saved into object instance + + env: + __object: full qualified path to the object's remote dir + __object_id: the objects id + __object_fq: full qualified object id, iow: $type.name + / + object_id + __type_explorer: full qualified path to the other type explorers on remote side + + creates: nothing, all output is handled by the object instances +''' + + +class Explorer(object): + """Executes cdist explorers. + + """ + def __init__(self, target_host, local, remote): + self.target_host = target_host + self.local = local + self.remote = remote + self.env = { + '__target_host': self.target_host, + '__explorer': self.remote.global_explorer_path, + } + + def transfer_global_explorers(self): + """Transfer the global explorers to the remote side.""" + self.remote.mkdir(self.remote.global_explorer_path) + self.remote.transfer(self.local.global_explorer_path, self.remote.global_explorer_path) + + def run_global_explorer(self, explorer): + """Run the given global explorer and return it's output.""" + script = os.path.join(self.remote.global_explorer_path, explorer) + return self.remote.run_script(script, env=self.env) + + def transfer_type_explorers(self, cdist_type): + """Transfer the type explorers for the given type to the remote side.""" + source = os.path.join(self.local.type_path, cdist_type.explorer_path) + destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) + self.remote.mkdir(destination) + self.remote.transfer(source, destination) + + # FIXME: should i do this? probably not + def transfer_object_parameters(self, cdist_object): + pass + + def run_type_explorer(self, explorer, cdist_object): + """Run the given type explorer for the given object and return it's output.""" + cdist_type = cdist_object.type + env = self.env.copy() + env.update({ + '__object': cdist_object.absolute_path, + '__object_id': cdist_object.object_id, + '__object_fq': cdist_object.path, + '__type_explorer': os.path.join(self.remote.type_path, cdist_type.explorer_path) + }) + script = os.path.join(self.remote.type_path, cdist_type.explorer_path, explorer) + return self.remote.run_script(script, env=env) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py new file mode 100644 index 00000000..6fad157b --- /dev/null +++ b/lib/cdist/test/explorer/__init__.py @@ -0,0 +1,87 @@ +# -*- 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 tempfile +import unittest +import shutil +import getpass + +import cdist +from cdist import core +from cdist import test +from cdist.exec import local +from cdist.exec import remote +from cdist.core import explorer + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') +local_base_path = fixtures + +class ExplorerClassTestCase(unittest.TestCase): + + def mkdtemp(self, **kwargs): + return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) + + def mkstemp(self, **kwargs): + return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) + + def setUp(self): + target_host = 'localhost' + + self.local_base_path = local_base_path + self.out_path = self.mkdtemp() + self.local = local.Local(target_host, self.local_base_path, self.out_path) + self.local.create_directories() + + self.remote_base_path = self.mkdtemp() + self.user = getpass.getuser() + remote_exec = "ssh -o User=%s -q" % self.user + remote_copy = "scp -o User=%s -q" % self.user + self.remote = remote.Remote(target_host, self.remote_base_path, remote_exec, remote_copy) + + self.explorer = explorer.Explorer(target_host, self.local, self.remote) + + def tearDown(self): + shutil.rmtree(self.out_path) + shutil.rmtree(self.remote_base_path) + + def test_transfer_global_explorers(self): + # FIXME: test result + self.explorer.transfer_global_explorers() + + def test_run_global_explorer(self): + # FIXME: test result + self.explorer.transfer_global_explorers() + self.explorer.run_global_explorer('global') + + def test_transfer_type_explorers(self): + # FIXME: test result + cdist_type = core.Type(self.local.type_path, '__test_type') + self.explorer.transfer_type_explorers(cdist_type) + + def test_run_type_explorer(self): + cdist_type = core.Type(self.local.type_path, '__test_type') + cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') + self.explorer.transfer_type_explorers(cdist_type) + self.assertEqual(self.explorer.run_type_explorer('world', cdist_object), 'hello\n') + diff --git a/lib/cdist/test/explorer/fixtures/conf/explorer/global b/lib/cdist/test/explorer/fixtures/conf/explorer/global new file mode 100755 index 00000000..39c16ea8 --- /dev/null +++ b/lib/cdist/test/explorer/fixtures/conf/explorer/global @@ -0,0 +1,2 @@ +#!/bin/sh +echo global diff --git a/lib/cdist/test/explorer/fixtures/conf/type/__test_type/explorer/world b/lib/cdist/test/explorer/fixtures/conf/type/__test_type/explorer/world new file mode 100755 index 00000000..21ba6825 --- /dev/null +++ b/lib/cdist/test/explorer/fixtures/conf/type/__test_type/explorer/world @@ -0,0 +1,2 @@ +#!/bin/sh +echo hello diff --git a/lib/cdist/test/explorer/fixtures/conf/type/__test_type_object_parameter/explorer/test_parameter b/lib/cdist/test/explorer/fixtures/conf/type/__test_type_object_parameter/explorer/test_parameter new file mode 100755 index 00000000..0778907c --- /dev/null +++ b/lib/cdist/test/explorer/fixtures/conf/type/__test_type_object_parameter/explorer/test_parameter @@ -0,0 +1,3 @@ +#!/bin/sh + +cat "$__object/parameter/test" From c15673aef79b0805597d326667a9bb99db6b4e9a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 11:05:39 +0200 Subject: [PATCH 0794/4212] +docstring Signed-off-by: Steven Armstrong --- lib/cdist/core/manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index e97ba095..fc82b1cc 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -62,7 +62,7 @@ type manifeste is: class Manifest(object): - """Represents a cdist manifest. + """Executes cdist manifests. """ def __init__(self, target_host, local): From 841b54c6d039e0f1b68b9e3ea22d481d1414b4ef Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 11:06:03 +0200 Subject: [PATCH 0795/4212] +devnotes, +FIXME Signed-off-by: Steven Armstrong --- lib/cdist/core/explorer.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 7e1d48de..c79124b3 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -30,26 +30,25 @@ log = logging.getLogger(__name__) ''' common: - runs only remotely, needs local and remote + runs only remotely, needs local and remote to construct paths env: - __explorer: full qualified path to other global explorers on remote side == remote.global_explorer_path + __explorer: full qualified path to other global explorers on remote side + -> remote.global_explorer_path -global explorer is: - folder full of scripts which have to be: - (- copied to remote) - - executed one by one on remote - - output saved to local files +a global explorer is: + - a script + - executed on the remote side + - returns its output as a string env: - creates: local files with explorer output + creates: nothing, returns output type explorer is: - folder full of scripts which have to be: - (- copied to remote) - - executed one by one on remote for each object instance - - output saved into object instance + - a script + - executed on the remote side for each object instance + - returns its output as a string env: __object: full qualified path to the object's remote dir @@ -57,7 +56,8 @@ type explorer is: __object_fq: full qualified object id, iow: $type.name + / + object_id __type_explorer: full qualified path to the other type explorers on remote side - creates: nothing, all output is handled by the object instances + creates: nothing, returns output + ''' @@ -74,6 +74,7 @@ class Explorer(object): '__explorer': self.remote.global_explorer_path, } + # FIXME: should i do this? def transfer_global_explorers(self): """Transfer the global explorers to the remote side.""" self.remote.mkdir(self.remote.global_explorer_path) @@ -84,6 +85,7 @@ class Explorer(object): script = os.path.join(self.remote.global_explorer_path, explorer) return self.remote.run_script(script, env=self.env) + # FIXME: should i do this? def transfer_type_explorers(self, cdist_type): """Transfer the type explorers for the given type to the remote side.""" source = os.path.join(self.local.type_path, cdist_type.explorer_path) From c305735ed5334ce37742daae650bd6e107c5b524 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 13 Oct 2011 11:08:23 +0200 Subject: [PATCH 0796/4212] begin cleanup/reordering in config_install Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 82 +++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index a319b88c..6ab2c162 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -99,6 +99,53 @@ class ConfigInstall(object): shutil.rmtree(self.context.cache_path) shutil.move(self.context.out_path, self.context.cache_path) + def deploy_to(self): + """Mimic the old deploy to: Deploy to one host""" + self.log.info("Deploying to " + self.context.target_host) + self.stage_prepare() + self.stage_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 run of %s in %s seconds", + self.context.target_host, time.time() - start_time) + + def stage_prepare(self): + """Do everything for a deploy, minus the actual code stage""" + self.link_emulator() + self.global_explorer_run() + self.run_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 cdist.core.Object.list_objects(self.object_base_path, + self.context.type_base_path): + if cdist_object.prepared: + self.log.debug("Skipping rerun of object %s", cdist_object) + continue + else: + self.object_prepare(cdist_object) + new_objects_created = True + + + def self.global_explorer_run() + """Run global explorers and save output""" + + output = self.global_explorer.run() + + for explorer in output: + outfile = os.path.join(self.context.global_explorer_out_path, + explorer) + outfile_fd = open(outfile, "w") + outfile_fd.write() + def object_prepare(self, cdist_object): """Prepare object: Run type explorer + manifest""" self.log.debug("Preparing object: " + cdist_object.name) @@ -186,41 +233,6 @@ class ConfigInstall(object): # FIXME: handle exception / make it more beautiful / Steven: raise except :-) os.symlink(src, dst) - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" - self.log.info("Deploying to " + self.context.target_host) - self.stage_prepare() - self.stage_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 run of %s in %s seconds", - self.context.target_host, time.time() - start_time) - - def stage_prepare(self): - """Do everything for a deploy, minus the actual code stage""" - self.link_emulator() - self.explorer.run_global_explorers() - self.run_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 cdist.core.Object.list_objects(self.object_base_path, - self.context.type_base_path): - if cdist_object.prepared: - self.log.debug("Skipping rerun of object %s", cdist_object) - continue - else: - self.object_prepare(cdist_object) - new_objects_created = True - def stage_run(self): """The final (and real) step of deployment""" self.log.info("Generating and executing code") From 143939a6f71745876859a53e6b426e3768762744 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 13 Oct 2011 11:09:57 +0200 Subject: [PATCH 0797/4212] do not change current env Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 6ab2c162..4c4fd245 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -85,13 +85,9 @@ class ConfigInstall(object): os.mkdir(self.context.out_path) os.mkdir(self.context.bin_path) - # FIXME: remove this function, only expose ENV - # explicitly! - def __init_env(self): - """Environment usable for other stuff""" - os.environ['__target_host'] = self.context.target_host - if self.context.debug: - os.environ['__debug'] = "yes" +# os.environ['__target_host'] = self.context.target_host +# if self.context.debug: +# os.environ['__debug'] = "yes" def cleanup(self): self.log.debug("Saving " + self.context.out_path + " to " + self.context.cache_path) From 94a5558f3fc40ade0c98c2cb51546cd6e16e15a6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 13 Oct 2011 12:20:51 +0200 Subject: [PATCH 0798/4212] ++todo in bin/cdist Signed-off-by: Nico Schottelius --- bin/cdist | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/cdist b/bin/cdist index fae83ff1..37461aab 100755 --- a/bin/cdist +++ b/bin/cdist @@ -115,6 +115,7 @@ def configinstall(args, mode): time_start = time.time() for host in args.host: + # Setup Local/Remote context = cdist.context.Context( target_host=host, initial_manifest=args.manifest, From 79ad04ebe58d7bfc37af2151e1ea4fc38623b297 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 13 Oct 2011 12:21:24 +0200 Subject: [PATCH 0799/4212] -ws Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 4c4fd245..c49d32fc 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -67,7 +67,6 @@ class ConfigInstall(object): # Setup env to be used by others - FIXME self.__init_env() - def __init_remote_paths(self): """Initialise remote directory structure""" self.exec_wrapper.remove_remote_path(self.context.remote_base_path) From 48ae37e832d921ecd0fd32bb250723b1d56429db Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:04:23 +0200 Subject: [PATCH 0800/4212] implement transfer_object_parameters Signed-off-by: Steven Armstrong --- lib/cdist/core/explorer.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index c79124b3..ad19db20 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -74,7 +74,8 @@ class Explorer(object): '__explorer': self.remote.global_explorer_path, } - # FIXME: should i do this? + ### global + def transfer_global_explorers(self): """Transfer the global explorers to the remote side.""" self.remote.mkdir(self.remote.global_explorer_path) @@ -85,7 +86,8 @@ class Explorer(object): script = os.path.join(self.remote.global_explorer_path, explorer) return self.remote.run_script(script, env=self.env) - # FIXME: should i do this? + ### type + def transfer_type_explorers(self, cdist_type): """Transfer the type explorers for the given type to the remote side.""" source = os.path.join(self.local.type_path, cdist_type.explorer_path) @@ -93,9 +95,12 @@ class Explorer(object): self.remote.mkdir(destination) self.remote.transfer(source, destination) - # FIXME: should i do this? probably not def transfer_object_parameters(self, cdist_object): - pass + """Transfer the parameters for the given object to the remote side.""" + source = os.path.join(self.local.object_path, cdist_object.parameter_path) + destination = os.path.join(self.remotei.object_path, cdist_object.parameter_path) + self.remote.mkdir(destination) + self.remote.transfer(source, destination) def run_type_explorer(self, explorer, cdist_object): """Run the given type explorer for the given object and return it's output.""" From d136a6dee340b76ca883826301f03e266f75b887 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:14:01 +0200 Subject: [PATCH 0801/4212] DirectoryDictProperty: create directory before writing Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index 68d5edaa..50b95ea2 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -221,6 +221,8 @@ class DirectoryDictProperty(DirectoryDict): def __set__(self, obj, value): self._set_path(obj) if value is not None: + # create directory if it doesn't exist + os.makedirs(self.path, exist_ok=True) for name in self.keys(): del self[name] self.update(value) From dc6218c3e1fb182f899c7dff0de9e52726d06803 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:14:46 +0200 Subject: [PATCH 0802/4212] initial test for test_transfer_object_parameters Signed-off-by: Steven Armstrong --- lib/cdist/test/explorer/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index 6fad157b..8139431b 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -79,6 +79,13 @@ class ExplorerClassTestCase(unittest.TestCase): cdist_type = core.Type(self.local.type_path, '__test_type') self.explorer.transfer_type_explorers(cdist_type) + def test_transfer_object_parameters(self): + # FIXME: test result + cdist_type = core.Type(self.local.type_path, '__test_type') + cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') + cdist_object.parameters = {'first': 'first value', 'second': 'second value'} + self.explorer.transfer_object_parameters(cdist_object) + def test_run_type_explorer(self): cdist_type = core.Type(self.local.type_path, '__test_type') cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') From 20fae8b52b2751b891cd041df98c88b73f07e0b1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:14:56 +0200 Subject: [PATCH 0803/4212] fix typo Signed-off-by: Steven Armstrong --- lib/cdist/core/explorer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index ad19db20..b86054c7 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -98,7 +98,7 @@ class Explorer(object): def transfer_object_parameters(self, cdist_object): """Transfer the parameters for the given object to the remote side.""" source = os.path.join(self.local.object_path, cdist_object.parameter_path) - destination = os.path.join(self.remotei.object_path, cdist_object.parameter_path) + destination = os.path.join(self.remote.object_path, cdist_object.parameter_path) self.remote.mkdir(destination) self.remote.transfer(source, destination) From 910de0579cc62fb0ba9bf34c4b76b4d6a70fcabb Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:17:22 +0200 Subject: [PATCH 0804/4212] add assertion for test_transfer_object_parameters Signed-off-by: Steven Armstrong --- lib/cdist/test/explorer/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index 8139431b..eb45778b 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -80,11 +80,13 @@ class ExplorerClassTestCase(unittest.TestCase): self.explorer.transfer_type_explorers(cdist_type) def test_transfer_object_parameters(self): - # FIXME: test result cdist_type = core.Type(self.local.type_path, '__test_type') cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') cdist_object.parameters = {'first': 'first value', 'second': 'second value'} self.explorer.transfer_object_parameters(cdist_object) + source = os.path.join(self.local.object_path, cdist_object.parameter_path) + destination = os.path.join(self.remote.object_path, cdist_object.parameter_path) + self.assertEqual(os.listdir(source), os.listdir(destination)) def test_run_type_explorer(self): cdist_type = core.Type(self.local.type_path, '__test_type') From 2eb37367a18ba6168d06f61f0c98a21597df5b60 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:18:34 +0200 Subject: [PATCH 0805/4212] add assertion for test_transfer_type_explorers Signed-off-by: Steven Armstrong --- lib/cdist/test/explorer/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index eb45778b..e6b36f1b 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -75,9 +75,11 @@ class ExplorerClassTestCase(unittest.TestCase): self.explorer.run_global_explorer('global') def test_transfer_type_explorers(self): - # FIXME: test result cdist_type = core.Type(self.local.type_path, '__test_type') self.explorer.transfer_type_explorers(cdist_type) + source = os.path.join(self.local.type_path, cdist_type.explorer_path) + destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) + self.assertEqual(os.listdir(source), os.listdir(destination)) def test_transfer_object_parameters(self): cdist_type = core.Type(self.local.type_path, '__test_type') From f846fdd961501d4133042d49123e4ca8b57d10b3 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:20:07 +0200 Subject: [PATCH 0806/4212] add assertion for test_transfer_global_explorers Signed-off-by: Steven Armstrong --- lib/cdist/test/explorer/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index e6b36f1b..bc1ef820 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -66,8 +66,10 @@ class ExplorerClassTestCase(unittest.TestCase): shutil.rmtree(self.remote_base_path) def test_transfer_global_explorers(self): - # FIXME: test result self.explorer.transfer_global_explorers() + source = self.local.global_explorer_path + destination = self.remote.global_explorer_path + self.assertEqual(os.listdir(source), os.listdir(destination)) def test_run_global_explorer(self): # FIXME: test result From f1fdf0f13c4c92564acb55b232137f6953e90378 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:21:15 +0200 Subject: [PATCH 0807/4212] add assertion for test_run_global_explorer Signed-off-by: Steven Armstrong --- lib/cdist/test/explorer/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index bc1ef820..5974b43a 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -72,9 +72,9 @@ class ExplorerClassTestCase(unittest.TestCase): self.assertEqual(os.listdir(source), os.listdir(destination)) def test_run_global_explorer(self): - # FIXME: test result self.explorer.transfer_global_explorers() - self.explorer.run_global_explorer('global') + output = self.explorer.run_global_explorer('global') + self.assertEqual(output, 'global\n') def test_transfer_type_explorers(self): cdist_type = core.Type(self.local.type_path, '__test_type') From ac79ec101fd678fdb706ed919fa98f0b0110fa23 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:22:52 +0200 Subject: [PATCH 0808/4212] +consistency Signed-off-by: Steven Armstrong --- lib/cdist/test/explorer/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index 5974b43a..a4ad4f7f 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -96,5 +96,6 @@ class ExplorerClassTestCase(unittest.TestCase): cdist_type = core.Type(self.local.type_path, '__test_type') cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') self.explorer.transfer_type_explorers(cdist_type) - self.assertEqual(self.explorer.run_type_explorer('world', cdist_object), 'hello\n') + output = self.explorer.run_type_explorer('world', cdist_object) + self.assertEqual(output, 'hello\n') From f02bdf3e6196285d23a7fd3ff26577ce5840f421 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:30:41 +0200 Subject: [PATCH 0809/4212] test for test_list_global_explorer_names Signed-off-by: Steven Armstrong --- lib/cdist/test/explorer/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index a4ad4f7f..67c05913 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -65,6 +65,10 @@ class ExplorerClassTestCase(unittest.TestCase): shutil.rmtree(self.out_path) shutil.rmtree(self.remote_base_path) + def test_list_global_explorer_names(self): + expected = ['global'] + self.assertEqual(self.explorer.list_global_explorer_names(), expected) + def test_transfer_global_explorers(self): self.explorer.transfer_global_explorers() source = self.local.global_explorer_path From 86fcce928c562dd7f14ccf4d6833db8736120dba Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:31:42 +0200 Subject: [PATCH 0810/4212] implement list_global_explorer_names Signed-off-by: Steven Armstrong --- lib/cdist/core/explorer.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index b86054c7..562683f4 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -76,6 +76,10 @@ class Explorer(object): ### global + def list_global_explorer_names(self): + """Return a list of global explorer names.""" + return os.listdir(self.local.global_explorer_path) + def transfer_global_explorers(self): """Transfer the global explorers to the remote side.""" self.remote.mkdir(self.remote.global_explorer_path) From fb4d20e7e853f8f15cbd4f5b6aae238741478531 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:33:24 +0200 Subject: [PATCH 0811/4212] test for test_list_type_explorer_names Signed-off-by: Steven Armstrong --- lib/cdist/test/explorer/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index 67c05913..96206ae0 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -80,6 +80,11 @@ class ExplorerClassTestCase(unittest.TestCase): output = self.explorer.run_global_explorer('global') self.assertEqual(output, 'global\n') + def test_list_type_explorer_names(self): + cdist_type = core.Type(self.local.type_path, '__test_type') + expected = cdist_type.explorers + self.assertEqual(self.explorer.list_type_explorer_names(cdist_type), expected) + def test_transfer_type_explorers(self): cdist_type = core.Type(self.local.type_path, '__test_type') self.explorer.transfer_type_explorers(cdist_type) From 8fb51a396a640066c99083df69521bd8b1a9148a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:34:06 +0200 Subject: [PATCH 0812/4212] implement list_type_explorer_names Signed-off-by: Steven Armstrong --- lib/cdist/core/explorer.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 562683f4..7e61639e 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -92,6 +92,11 @@ class Explorer(object): ### type + def list_type_explorer_names(self, cdist_type): + """Return a list of explorer names for the given type.""" + source = os.path.join(self.local.type_path, cdist_type.explorer_path) + return os.listdir(source) + def transfer_type_explorers(self, cdist_type): """Transfer the type explorers for the given type to the remote side.""" source = os.path.join(self.local.type_path, cdist_type.explorer_path) From 8e55e74bc274914b3e2e6c09405f5114a52bfcfd Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:40:20 +0200 Subject: [PATCH 0813/4212] test for code_local Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 6f26fd19..8cffe053 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -136,3 +136,10 @@ class ObjectTestCase(unittest.TestCase): def test_source_after_changing(self): self.cdist_object.source = ['/path/to/manifest'] self.assertEqual(list(self.cdist_object.source), ['/path/to/manifest']) + + def test_code_local(self): + self.assertEqual(self.cdist_object.code_local, '') + + def test_code_local_after_changing(self): + self.cdist_object.code_local = 'Hello World' + self.assertEqual(self.cdist_object.code_local, 'Hello World') From 93ede2a3bedbc6d4e86bb470e4eb690cfae0054a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:40:50 +0200 Subject: [PATCH 0814/4212] implement code_local Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index b7890eeb..8cea077c 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -99,6 +99,7 @@ class Object(object): prepared = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "prepared")) ran = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "ran")) source = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, "source")) + code_local = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.absolute_path, "code-local")) @property def exists(self): From 6f7528c4114bc09c067c1a9b689cd82ba35c354e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:42:45 +0200 Subject: [PATCH 0815/4212] test for code_remote Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 8cffe053..0953027b 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -63,6 +63,8 @@ class ObjectTestCase(unittest.TestCase): self.cdist_object.prepared = False self.cdist_object.ran = False self.cdist_object.source = [] + self.cdist_object.code_local = '' + self.cdist_object.code_remote = '' def test_name(self): self.assertEqual(self.cdist_object.name, '__third/moon') @@ -143,3 +145,10 @@ class ObjectTestCase(unittest.TestCase): def test_code_local_after_changing(self): self.cdist_object.code_local = 'Hello World' self.assertEqual(self.cdist_object.code_local, 'Hello World') + + def test_code_remote(self): + self.assertEqual(self.cdist_object.code_remote, '') + + def test_code_remote_after_changing(self): + self.cdist_object.code_remote = 'Hello World' + self.assertEqual(self.cdist_object.code_remote, 'Hello World') From 939962b583f741f5f24ce57ab2534389bbffa9f9 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 13:42:58 +0200 Subject: [PATCH 0816/4212] implement code_remote Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 8cea077c..242b094a 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -100,6 +100,7 @@ class Object(object): ran = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "ran")) source = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, "source")) code_local = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.absolute_path, "code-local")) + code_remote = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.absolute_path, "code-remote")) @property def exists(self): From df57b5188b3604a06bd5564d261110636505c84c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 14:26:36 +0200 Subject: [PATCH 0817/4212] tests for code Signed-off-by: Steven Armstrong --- lib/cdist/test/code/__init__.py | 132 ++++++++++++++++++ .../type/__dump_environment/gencode-local | 8 ++ .../type/__dump_environment/gencode-remote | 1 + 3 files changed, 141 insertions(+) create mode 100644 lib/cdist/test/code/__init__.py create mode 100755 lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local create mode 120000 lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-remote diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py new file mode 100644 index 00000000..397922e8 --- /dev/null +++ b/lib/cdist/test/code/__init__.py @@ -0,0 +1,132 @@ +# -*- 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 os +import tempfile +import unittest +import shutil +import getpass + +import cdist +from cdist import core +from cdist import test +from cdist.exec import local +from cdist.exec import remote +from cdist.core import code + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') +local_base_path = fixtures + +class ExplorerClassTestCase(unittest.TestCase): + + def mkdtemp(self, **kwargs): + return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) + + def mkstemp(self, **kwargs): + return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) + + def setUp(self): + target_host = 'localhost' + + self.local_base_path = local_base_path + self.out_path = self.mkdtemp() + self.local = local.Local(target_host, self.local_base_path, self.out_path) + self.local.create_directories() + + self.remote_base_path = self.mkdtemp() + self.user = getpass.getuser() + remote_exec = "ssh -o User=%s -q" % self.user + remote_copy = "scp -o User=%s -q" % self.user + self.remote = remote.Remote(target_host, self.remote_base_path, remote_exec, remote_copy) + + self.code = code.Code(target_host, self.local, self.remote) + + def tearDown(self): + shutil.rmtree(self.out_path) + shutil.rmtree(self.remote_base_path) + + def test_run_gencode_local_environment(self): + cdist_type = core.Type(self.local.type_path, '__dump_environment') + cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') + output_string = self.code.run_gencode_local(cdist_object) + output_dict = {} + for line in output_string.split('\n'): + if line: + junk,value = line.split(': ') + key = junk.split(' ')[1] + output_dict[key] = value + self.assertEqual(output_dict['__target_host'], self.local.target_host) + self.assertEqual(output_dict['__global'], self.local.out_path) + self.assertEqual(output_dict['__type'], cdist_type.absolute_path) + self.assertEqual(output_dict['__object'], cdist_object.absolute_path) + self.assertEqual(output_dict['__object_id'], cdist_object.object_id) + self.assertEqual(output_dict['__object_fq'], cdist_object.path) + + def test_run_gencode_remote_environment(self): + cdist_type = core.Type(self.local.type_path, '__dump_environment') + cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') + output_string = self.code.run_gencode_remote(cdist_object) + output_dict = {} + for line in output_string.split('\n'): + if line: + junk,value = line.split(': ') + key = junk.split(' ')[1] + output_dict[key] = value + self.assertEqual(output_dict['__target_host'], self.local.target_host) + self.assertEqual(output_dict['__global'], self.local.out_path) + self.assertEqual(output_dict['__type'], cdist_type.absolute_path) + self.assertEqual(output_dict['__object'], cdist_object.absolute_path) + self.assertEqual(output_dict['__object_id'], cdist_object.object_id) + self.assertEqual(output_dict['__object_fq'], cdist_object.path) + + + +''' + def test_list_type_explorer_names(self): + cdist_type = core.Type(self.local.type_path, '__test_type') + expected = cdist_type.explorers + self.assertEqual(self.explorer.list_type_explorer_names(cdist_type), expected) + + def test_transfer_type_explorers(self): + cdist_type = core.Type(self.local.type_path, '__test_type') + self.explorer.transfer_type_explorers(cdist_type) + source = os.path.join(self.local.type_path, cdist_type.explorer_path) + destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) + self.assertEqual(os.listdir(source), os.listdir(destination)) + + def test_transfer_object_parameters(self): + cdist_type = core.Type(self.local.type_path, '__test_type') + cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') + cdist_object.parameters = {'first': 'first value', 'second': 'second value'} + self.explorer.transfer_object_parameters(cdist_object) + source = os.path.join(self.local.object_path, cdist_object.parameter_path) + destination = os.path.join(self.remote.object_path, cdist_object.parameter_path) + self.assertEqual(os.listdir(source), os.listdir(destination)) + + def test_run_type_explorer(self): + cdist_type = core.Type(self.local.type_path, '__test_type') + cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') + self.explorer.transfer_type_explorers(cdist_type) + output = self.explorer.run_type_explorer('world', cdist_object) + self.assertEqual(output, 'hello\n') +''' diff --git a/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local b/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local new file mode 100755 index 00000000..ac292546 --- /dev/null +++ b/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local @@ -0,0 +1,8 @@ +#!/bin/sh + +echo "echo __target_host: $__target_host" +echo "echo __global: $__global" +echo "echo __type: $__type" +echo "echo __object: $__object" +echo "echo __object_id: $__object_id" +echo "echo __object_fq: $__object_fq" diff --git a/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-remote b/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-remote new file mode 120000 index 00000000..7b427cac --- /dev/null +++ b/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-remote @@ -0,0 +1 @@ +gencode-local \ No newline at end of file From 6d438d4ec5cbb738283fa37c1f96e61834287412 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 14:29:20 +0200 Subject: [PATCH 0818/4212] implement run_gencode_local Signed-off-by: Steven Armstrong --- lib/cdist/core/code.py | 110 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 lib/cdist/core/code.py diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py new file mode 100644 index 00000000..de735cb4 --- /dev/null +++ b/lib/cdist/core/code.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 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 logging +import os + +import cdist + +log = logging.getLogger(__name__) + + +''' +common: + runs only locally, does not need remote + + env: + PATH: prepend directory with type emulator symlinks == local.bin_path + __target_host: the target host we are working on + __cdist_manifest: full qualified path of the manifest == script + __cdist_type_base_path: full qualified path to the directory where types are defined for use in type emulator + == local.type_path + +gencode-local + script: full qualified path to a types gencode-local + + env: + __target_host: the target host we are working on + __global: full qualified path to the global output dir == local.out_path + __object: full qualified path to the object's dir + __object_id: the objects id + __object_fq: full qualified object id, iow: $type.name + / + object_id + __type: full qualified path to the type's dir + + returns: string containing the generated code or None + +gencode-remote + script: full qualified path to a types gencode-remote + + env: + __target_host: the target host we are working on + __global: full qualified path to the global output dir == local.out_path + __object: full qualified path to the object's dir + __object_id: the objects id + __object_fq: full qualified object id, iow: $type.name + / + object_id + __type: full qualified path to the type's dir + + returns: string containing the generated code or None + + +code-local + script: full qualified path to object's code-local + - run script localy + returns: string containing the output + +code-remote + script: full qualified path to object's code-remote + - copy script to remote + - run script remotely + returns: string containing the output +''' + + +class Code(object): + """Generates and executes cdist code scripts. + + """ + def __init__(self, target_host, local, remote): + self.target_host = target_host + self.local = local + self.remote = remote + self.env = { + '__target_host': self.target_host, + '__global': self.local.out_path, + } + + def _get_env_for_object(self, cdist_object): + return { + '__type': cdist_object.type.absolute_path, + '__object': cdist_object.absolute_path, + '__object_id': cdist_object.object_id, + '__object_fq': cdist_object.path, + } + + def run_gencode_local(self, cdist_object): + cdist_type = cdist_object.type + script = os.path.join(self.local.type_path, cdist_type.gencode_local_path) + env = os.environ.copy() + env.update(self.env) + env.update(self._get_env_for_object(cdist_object)) + return self.local.run_script(script, env=env) + From 1665b4b5e651b392b91c1a946180117a9cd61eca Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 14:32:52 +0200 Subject: [PATCH 0819/4212] implement run_gencode_remote Signed-off-by: Steven Armstrong --- lib/cdist/core/code.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index de735cb4..a6804c0b 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -100,11 +100,18 @@ class Code(object): '__object_fq': cdist_object.path, } - def run_gencode_local(self, cdist_object): + def _run_gencode(self, cdist_object, which): cdist_type = cdist_object.type - script = os.path.join(self.local.type_path, cdist_type.gencode_local_path) + script = os.path.join(self.local.type_path, getattr(cdist_type, 'gencode_%s_path' % which)) env = os.environ.copy() env.update(self.env) env.update(self._get_env_for_object(cdist_object)) return self.local.run_script(script, env=env) + def run_gencode_local(self, cdist_object): + """Run the gencode-local script for the given cdist object.""" + return self._run_gencode(cdist_object, 'local') + + def run_gencode_remote(self, cdist_object): + """Run the gencode-remote script for the given cdist object.""" + return self._run_gencode(cdist_object, 'remote') From 5edcc0537b4671d5888a43a8b2113ff8fa7aabeb Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 14:37:50 +0200 Subject: [PATCH 0820/4212] use api internally instead of constructing the same paths again Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 242b094a..a170dd30 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -93,14 +93,14 @@ class Object(object): return os.path.join(self.path, "explorer") requirements = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'require')) - parameters = fsproperty.DirectoryDictProperty(lambda obj: os.path.join(obj.absolute_path, 'parameter')) + 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")) prepared = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "prepared")) ran = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "ran")) source = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, "source")) - code_local = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.absolute_path, "code-local")) - code_remote = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.absolute_path, "code-remote")) + code_local = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.base_path, obj.code_local_path)) + code_remote = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.base_path, obj.code_remote_path)) @property def exists(self): From 01ab81a4469d58f2fb421ea3141c6cae228954df Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 14:50:50 +0200 Subject: [PATCH 0821/4212] -- duplicate code Signed-off-by: Steven Armstrong --- lib/cdist/test/code/__init__.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index 397922e8..0c35e09a 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -61,14 +61,15 @@ class ExplorerClassTestCase(unittest.TestCase): self.code = code.Code(target_host, self.local, self.remote) + self.cdist_type = core.Type(self.local.type_path, '__dump_environment') + self.cdist_object = core.Object(self.cdist_type, self.local.object_path, 'whatever') + def tearDown(self): shutil.rmtree(self.out_path) shutil.rmtree(self.remote_base_path) def test_run_gencode_local_environment(self): - cdist_type = core.Type(self.local.type_path, '__dump_environment') - cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') - output_string = self.code.run_gencode_local(cdist_object) + output_string = self.code.run_gencode_local(self.cdist_object) output_dict = {} for line in output_string.split('\n'): if line: @@ -77,15 +78,13 @@ class ExplorerClassTestCase(unittest.TestCase): 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['__type'], cdist_type.absolute_path) - self.assertEqual(output_dict['__object'], cdist_object.absolute_path) - self.assertEqual(output_dict['__object_id'], cdist_object.object_id) - self.assertEqual(output_dict['__object_fq'], cdist_object.path) + self.assertEqual(output_dict['__type'], self.cdist_type.absolute_path) + self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) + self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) + self.assertEqual(output_dict['__object_fq'], self.cdist_object.path) def test_run_gencode_remote_environment(self): - cdist_type = core.Type(self.local.type_path, '__dump_environment') - cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') - output_string = self.code.run_gencode_remote(cdist_object) + output_string = self.code.run_gencode_remote(self.cdist_object) output_dict = {} for line in output_string.split('\n'): if line: @@ -94,12 +93,12 @@ class ExplorerClassTestCase(unittest.TestCase): 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['__type'], cdist_type.absolute_path) - self.assertEqual(output_dict['__object'], cdist_object.absolute_path) - self.assertEqual(output_dict['__object_id'], cdist_object.object_id) - self.assertEqual(output_dict['__object_fq'], cdist_object.path) - + self.assertEqual(output_dict['__type'], self.cdist_type.absolute_path) + self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) + self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) + self.assertEqual(output_dict['__object_fq'], self.cdist_object.path) + ''' def test_list_type_explorer_names(self): From 5055afe0c08f67cf1bf484016b2c4a415a6b87bb Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 14:57:09 +0200 Subject: [PATCH 0822/4212] test for test_transfer_code_remote Signed-off-by: Steven Armstrong --- lib/cdist/test/code/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index 0c35e09a..be4530d8 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -63,6 +63,7 @@ class ExplorerClassTestCase(unittest.TestCase): self.cdist_type = core.Type(self.local.type_path, '__dump_environment') self.cdist_object = core.Object(self.cdist_type, self.local.object_path, 'whatever') + self.cdist_object.create() def tearDown(self): shutil.rmtree(self.out_path) @@ -98,6 +99,12 @@ class ExplorerClassTestCase(unittest.TestCase): self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) self.assertEqual(output_dict['__object_fq'], self.cdist_object.path) + def test_transfer_code_remote(self): + self.cdist_object.code_remote = self.code.run_gencode_remote(self.cdist_object) + self.code.transfer_code_remote(self.cdist_object) + destination = os.path.join(self.remote.object_path, self.cdist_object.code_remote_path) + self.assertTrue(os.path.isfile(destination)) + ''' From 31ce938593ca53c32a7c7756eadd8a373676f42e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 14:57:49 +0200 Subject: [PATCH 0823/4212] implement transfer_code_remote Signed-off-by: Steven Armstrong --- lib/cdist/core/code.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index a6804c0b..c42c360b 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -115,3 +115,10 @@ class Code(object): def run_gencode_remote(self, cdist_object): """Run the gencode-remote script for the given cdist object.""" return self._run_gencode(cdist_object, 'remote') + + def transfer_code_remote(self, cdist_object): + """Transfer the code_remote script for the given object to the remote side.""" + source = os.path.join(self.local.object_path, cdist_object.code_remote_path) + destination = os.path.join(self.remote.object_path, cdist_object.code_remote_path) + self.remote.mkdir(destination) + self.remote.transfer(source, destination) From 12e5b3e8dc2c480c3359499a9bef8c49222c93b7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 15:00:07 +0200 Subject: [PATCH 0824/4212] test for run_code_local Signed-off-by: Steven Armstrong --- lib/cdist/test/code/__init__.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index be4530d8..a6e12e06 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -105,6 +105,20 @@ class ExplorerClassTestCase(unittest.TestCase): destination = os.path.join(self.remote.object_path, self.cdist_object.code_remote_path) self.assertTrue(os.path.isfile(destination)) + def test_run_code_local_environment(self): + self.cdist_object.code_local = self.code.run_gencode_local(self.cdist_object) + output_string = self.code.run_code_local(self.cdist_object) + output_dict = {} + for line in output_string.split('\n'): + if line: + key,value = line.split(': ') + 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['__type'], self.cdist_type.absolute_path) + self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) + self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) + self.assertEqual(output_dict['__object_fq'], self.cdist_object.path) ''' From e60510228132f426019389659947cfeef020844c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 15:02:10 +0200 Subject: [PATCH 0825/4212] implement run_code_local Signed-off-by: Steven Armstrong --- lib/cdist/core/code.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index c42c360b..22a8ad34 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -116,6 +116,10 @@ class Code(object): """Run the gencode-remote script for the given cdist object.""" return self._run_gencode(cdist_object, 'remote') + def run_code_local(self, cdist_object): + script = os.path.join(self.local.object_path, cdist_object.code_local_path) + return self.local.run_script(script) + def transfer_code_remote(self, cdist_object): """Transfer the code_remote script for the given object to the remote side.""" source = os.path.join(self.local.object_path, cdist_object.code_remote_path) From 7bc68476a1d879747ae39c96fda20e05ef024172 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 15:09:05 +0200 Subject: [PATCH 0826/4212] test for run_code_remote Signed-off-by: Steven Armstrong --- lib/cdist/test/code/__init__.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index a6e12e06..970d7692 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -120,6 +120,20 @@ class ExplorerClassTestCase(unittest.TestCase): self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) self.assertEqual(output_dict['__object_fq'], self.cdist_object.path) + def test_run_code_remote_environment(self): + self.cdist_object.code_remote = self.code.run_gencode_remote(self.cdist_object) + output_string = self.code.run_code_remote(self.cdist_object) + output_dict = {} + for line in output_string.split('\n'): + if line: + key,value = line.split(': ') + 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['__type'], self.cdist_type.absolute_path) + self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) + self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) + self.assertEqual(output_dict['__object_fq'], self.cdist_object.path) ''' def test_list_type_explorer_names(self): From 1c3902f3db6dc05240c7ef1c84d825e9e7a3822c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 15:09:47 +0200 Subject: [PATCH 0827/4212] implement run_code_remote Signed-off-by: Steven Armstrong --- lib/cdist/core/code.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index 22a8ad34..b2cc033c 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -116,13 +116,22 @@ class Code(object): """Run the gencode-remote script for the given cdist object.""" return self._run_gencode(cdist_object, 'remote') - def run_code_local(self, cdist_object): - script = os.path.join(self.local.object_path, cdist_object.code_local_path) - return self.local.run_script(script) - def transfer_code_remote(self, cdist_object): """Transfer the code_remote script for the given object to the remote side.""" source = os.path.join(self.local.object_path, cdist_object.code_remote_path) destination = os.path.join(self.remote.object_path, cdist_object.code_remote_path) self.remote.mkdir(destination) self.remote.transfer(source, destination) + + def _run_code(self, cdist_object, which): + which_exec = getattr(self, which) + script = os.path.join(self.local.object_path, getattr(cdist_object, 'code_%s_path' % which)) + return which_exec.run_script(script) + + def run_code_local(self, cdist_object): + """Run the code-local script for the given cdist object.""" + return self._run_code(cdist_object, 'local') + + def run_code_remote(self, cdist_object): + """Run the code-remote script for the given cdist object on the remote side.""" + return self._run_code(cdist_object, 'remote') From 6c7e280eac188051fb0a6bca0fb33a6d91f492b6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 15:11:50 +0200 Subject: [PATCH 0828/4212] remove obsolete method, merge code Signed-off-by: Steven Armstrong --- lib/cdist/core/code.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index b2cc033c..6dfa2da4 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -92,20 +92,17 @@ class Code(object): '__global': self.local.out_path, } - def _get_env_for_object(self, cdist_object): - return { - '__type': cdist_object.type.absolute_path, - '__object': cdist_object.absolute_path, - '__object_id': cdist_object.object_id, - '__object_fq': cdist_object.path, - } - def _run_gencode(self, cdist_object, which): cdist_type = cdist_object.type script = os.path.join(self.local.type_path, getattr(cdist_type, 'gencode_%s_path' % which)) env = os.environ.copy() env.update(self.env) - env.update(self._get_env_for_object(cdist_object)) + env.update({ + '__type': cdist_object.type.absolute_path, + '__object': cdist_object.absolute_path, + '__object_id': cdist_object.object_id, + '__object_fq': cdist_object.path, + }) return self.local.run_script(script, env=env) def run_gencode_local(self, cdist_object): From fec3cca3b01dabbe7133c4be8b53655f7785d630 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 16:25:44 +0200 Subject: [PATCH 0829/4212] delegate path handling to local and remote Signed-off-by: Steven Armstrong --- lib/cdist/context.py | 50 +++++++++++--------------------------------- 1 file changed, 12 insertions(+), 38 deletions(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index f70e9752..3a6ed8a2 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -52,25 +52,13 @@ class Context(object): self.log = logging.getLogger(self.target_host) self.log.addFilter(self) - # Base and Temp Base + # Local base directory self.base_path = (base_path or os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))) - # Local input - self.cache_path = os.path.join(self.base_path, "cache", - self.target_host) - self.conf_path = os.path.join(self.base_path, "conf") - - self.global_explorer_path = os.path.join(self.conf_path, "explorer") - self.manifest_path = os.path.join(self.conf_path, "manifest") - self.type_base_path = os.path.join(self.conf_path, "type") - self.lib_path = os.path.join(self.base_path, "lib") - - self.initial_manifest = (initial_manifest or - os.path.join(self.manifest_path, "init")) - - # Local output + # 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 @@ -78,31 +66,17 @@ class Context(object): self.temp_dir = tempfile.mkdtemp() self.out_path = os.path.join(self.temp_dir, "out") - self.bin_path = os.path.join(self.out_path, "bin") - self.global_explorer_out_path = os.path.join(self.out_path, "explorer") - self.object_base_path = os.path.join(self.out_path, "object") + self.local = local.Local(self.target_host, self.base_path, self.out_path) - # Remote directory base - if '__cdist_remote_out_dir' in os.environ: - self.remote_base_path = os.environ['__cdist_remote_out_dir'] - else: - self.remote_base_path = "/var/lib/cdist" + self.initial_manifest = (initial_manifest or + os.path.join(self.local.manifest_path, "init")) - self.remote_conf_path = os.path.join(self.remote_base_path, "conf") - self.remote_object_path = os.path.join(self.remote_base_path, "object") - - self.remote_type_path = os.path.join(self.remote_conf_path, "type") - self.remote_global_explorer_path = os.path.join(self.remote_conf_path, "explorer") - - if '__remote_exec' in os.environ: - self.remote_exec = os.environ['__remote_exec'] - else: - self.remote_exec = "ssh -o User=root -q" - - if '__remote_copy' in os.environ: - self.remote_copy = os.environ['__remote_copy'] - else: - self.remote_copy = "scp -o User=root -q" + # Remote + self.remote_base_path = os.environ.get('__cdist_remote_out_dir', "/var/lib/cdist") + self.remote_exec = os.environ.get('__remote_exec', "ssh -o User=root -q") + self.remote_copy = os.environ.get('__remote_copy', "scp -o User=root -q") + self.remote = remote.Remote(self.target_host, self.remote_base_path, + self.remote_exec, self.remote_copy) def cleanup(self): """Remove temp stuff""" From 12784c8bd806ebef0f84099a055b234bfc614c98 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 16:26:07 +0200 Subject: [PATCH 0830/4212] +FIXME Signed-off-by: Steven Armstrong --- lib/cdist/exec/local.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index 1f253f09..fd9f8229 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -83,6 +83,7 @@ class Local(object): def mkdir(self, path): """Create directory on the local side.""" self.log.debug("Local mkdir: %s", path) + # FIXME: dont set mode here, fix unittest mkdtemp instead os.makedirs(path, mode=0o700, exist_ok=True) def run(self, command, env=None): From 4f7d75e6047efd9dd102df23c95d86eb3e141f6e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 16:27:07 +0200 Subject: [PATCH 0831/4212] remove/fix copy paste stuff Signed-off-by: Steven Armstrong --- lib/cdist/test/code/__init__.py | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index 970d7692..2b4b1c87 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -37,7 +37,7 @@ my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') local_base_path = fixtures -class ExplorerClassTestCase(unittest.TestCase): +class CodeTestCase(unittest.TestCase): def mkdtemp(self, **kwargs): return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) @@ -134,33 +134,3 @@ class ExplorerClassTestCase(unittest.TestCase): self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) self.assertEqual(output_dict['__object_fq'], self.cdist_object.path) - -''' - def test_list_type_explorer_names(self): - cdist_type = core.Type(self.local.type_path, '__test_type') - expected = cdist_type.explorers - self.assertEqual(self.explorer.list_type_explorer_names(cdist_type), expected) - - def test_transfer_type_explorers(self): - cdist_type = core.Type(self.local.type_path, '__test_type') - self.explorer.transfer_type_explorers(cdist_type) - source = os.path.join(self.local.type_path, cdist_type.explorer_path) - destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) - self.assertEqual(os.listdir(source), os.listdir(destination)) - - def test_transfer_object_parameters(self): - cdist_type = core.Type(self.local.type_path, '__test_type') - cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') - cdist_object.parameters = {'first': 'first value', 'second': 'second value'} - self.explorer.transfer_object_parameters(cdist_object) - source = os.path.join(self.local.object_path, cdist_object.parameter_path) - destination = os.path.join(self.remote.object_path, cdist_object.parameter_path) - self.assertEqual(os.listdir(source), os.listdir(destination)) - - def test_run_type_explorer(self): - cdist_type = core.Type(self.local.type_path, '__test_type') - cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') - self.explorer.transfer_type_explorers(cdist_type) - output = self.explorer.run_type_explorer('world', cdist_object) - self.assertEqual(output, 'hello\n') -''' From fced07634a526f3fb58a08fa3b47a0651d9d786e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 16:27:41 +0200 Subject: [PATCH 0832/4212] initial rewrite of config_install Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 174 +++++++++--------------------------- 1 file changed, 44 insertions(+), 130 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index c49d32fc..dc847a8b 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -28,11 +28,8 @@ import sys import tempfile import time -import cdist.core -import cdist.context -import cdist.exec -#import cdist.explorer -#import cdist.manifest +from cdist import core + class ConfigInstall(object): """Cdist main class to hold arbitrary data""" @@ -41,58 +38,29 @@ class ConfigInstall(object): self.context = context self.log = logging.getLogger(self.context.target_host) - self.exec_wrapper = cdist.exec.Wrapper( - target_host = self.context.target_host, - remote_exec=self.context.remote_exec, - remote_copy=self.context.remote_copy) - # Create directories other may depend on - self.__init_local_paths() - self.__init_remote_paths() + # For easy access + self.local = context.local + self.remote = context.remote - self.global_explorer = cdist.explorer.GlobalExplorer(self.context.global_in, out) - self.type_explorer = cdist.explorer.GlobalExplorer(self.context.global_in, out) + # Initialise local directory structure + self.local.create_directories() + # Initialise remote directory structure + self.remote.create_directories() - self.global_explorer = cdist.core.GlobalExplorer - #self.manifest = cdist.manifest.Mamifest() - - self.manifest.initial_manifest() - self.manifest.type_manifest(cdist_object) - self.global_explorer.run()? - - self.type_explorer.run(cdist_object)? - - self.log = logging.getLogger(self.context.target_host) + self.explorer = core.Explorer(self.context.target_host, self.local, self.remote) + self.manifest = core.Manifest(self.context.target_host, self.local) + self.code = core.Code(self.context.target_host, self.local, self.remote) # Setup env to be used by others - FIXME self.__init_env() - def __init_remote_paths(self): - """Initialise remote directory structure""" - self.exec_wrapper.remove_remote_path(self.context.remote_base_path) - self.exec_wrapper.remote_mkdir(self.context.remote_base_path) - self.exec_wrapper.remote_mkdir(self.context.remote_conf_path) - - def __init_local_paths(self): - """Initialise local directory structure""" - - # Create base dir, if user supplied and not existing - if not os.path.isdir(self.context.base_path): - os.mkdir(self.context.base_path) - - # FIXME: raise more beautiful exception / Steven: handle exception - os.mkdir(self.context.out_path) - os.mkdir(self.context.bin_path) - -# os.environ['__target_host'] = self.context.target_host -# if self.context.debug: -# os.environ['__debug'] = "yes" - def cleanup(self): - self.log.debug("Saving " + self.context.out_path + " to " + self.context.cache_path) - if os.path.exists(self.context.cache_path): - shutil.rmtree(self.context.cache_path) - shutil.move(self.context.out_path, self.context.cache_path) + # FIXME: move to local? + self.log.debug("Saving " + self.local.out_path + " to " + self.local.cache_path) + if os.path.exists(self.local.cache_path): + shutil.rmtree(self.local.cache_path) + shutil.move(self.local.out_path, self.local.cache_path) def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" @@ -110,9 +78,9 @@ class ConfigInstall(object): def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" - self.link_emulator() - self.global_explorer_run() - self.run_initial_manifest() + self.local.link_emulator() + self.run_global_explorers() + self.manifest.run_initial_manifest(self.context.initial_manifest) self.log.info("Running object manifests and type explorers") @@ -120,8 +88,8 @@ class ConfigInstall(object): new_objects_created = True while new_objects_created: new_objects_created = False - for cdist_object in cdist.core.Object.list_objects(self.object_base_path, - self.context.type_base_path): + for cdist_object in core.Object.list_objects(self.local.object_path, + self.local.type_path): if cdist_object.prepared: self.log.debug("Skipping rerun of object %s", cdist_object) continue @@ -129,17 +97,15 @@ class ConfigInstall(object): self.object_prepare(cdist_object) new_objects_created = True - - def self.global_explorer_run() + def run_global_explorers(self): """Run global explorers and save output""" - - output = self.global_explorer.run() - - for explorer in output: - outfile = os.path.join(self.context.global_explorer_out_path, - explorer) - outfile_fd = open(outfile, "w") - outfile_fd.write() + # FIXME: move to explorer, pass global_explorer_out_path as argument + self.explorer.transfer_global_explorers() + for explorer in self.explorer.list_global_explorer_names(): + output = self.explorer.run_global_explorer(explorer) + path = os.path.join(self.local.global_explorer_out_path, explorer) + with open(path, 'w') as fd: + fd.write(output) def object_prepare(self, cdist_object): """Prepare object: Run type explorer + manifest""" @@ -160,78 +126,26 @@ class ConfigInstall(object): for requirement in cdist_object.requirements: self.log.debug("Object %s requires %s", cdist_object, requirement) + # FIXME: requirement is a string, need to create object here self.object_run(requirement) - # - # Setup env Variable: - # - env = os.environ.copy() - env['__target_host'] = self.context.target_host - env['__global'] = self.context.out_path - env["__object"] = os.path.join(self.object_base_path, cdist_object.path) - env["__object_id"] = cdist_object.object_id - env["__object_fq"] = cdist_object.name - env["__type"] = cdist_type.name + # Generate + 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 - # gencode - for cmd in ["local", "remote"]: - bin = os.path.join(self.context.type_base_path, - getattr(cdist_type, "gencode_" + cmd + "_path")) - - if os.path.isfile(bin): - outfile = os.path.join(self.object_base_path, - getattr(cdist_object, "code_" + cmd + "_path")) - - outfile_fd = open(outfile, "w") - - # Need to flush to ensure our write is done before stdout write - # FIXME: code header still needed? - outfile_fd.write(CODE_HEADER) - outfile_fd.flush() - - cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) - outfile_fd.close() - - status = os.stat(outfile) - - # Remove output if empty, else make it executable - if status.st_size == len(CODE_HEADER): - os.unlink(outfile) - else: - # Add header and make executable - identically to 0o700 - os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) - cdist_object.changed=True - - # code local - code_local = cdist_object.code_local_path - if os.path.isfile(code_local): - cdist.exec.run_or_fail([code_local]) - - # code remote - local_remote_code = os.path.join(self.object_base_path, - cdist_object.code_remote_path) - remote_remote_code = os.path.join(self.remote_object_path, - cdist_object.code_remote_path) - if os.path.isfile(local_remote_code): - self.context.transfer_path(local_remote_code, remote_remote_code) - cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) - - cdist_object.ran = True - - def link_emulator(self): - """Link emulator to types""" - src = os.path.abspath(self.context.exec_path) - for cdist_type in cdist.core.Type.list_types(self.context.type_base_path): - dst = os.path.join(self.context.bin_path, cdist_type.name) - self.log.debug("Linking emulator: %s to %s", src, dst) - - # FIXME: handle exception / make it more beautiful / Steven: raise except :-) - os.symlink(src, dst) + # Execute + 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) def stage_run(self): """The final (and real) step of deployment""" self.log.info("Generating and executing code") - for cdist_object in cdist.core.Object.list_objects(self.object_base_path, - self.context.type_base_path): + for cdist_object in cdist.core.Object.list_objects(self.local.object_path, + self.local.type_path): self.log.debug("Run object: %s", cdist_object) self.object_run(cdist_object) From f1ff8d2f61e0416830949135129fe3a8fdc28f79 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 16:28:36 +0200 Subject: [PATCH 0833/4212] -todo Signed-off-by: Steven Armstrong --- bin/cdist | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 37461aab..fae83ff1 100755 --- a/bin/cdist +++ b/bin/cdist @@ -115,7 +115,6 @@ def configinstall(args, mode): time_start = time.time() for host in args.host: - # Setup Local/Remote context = cdist.context.Context( target_host=host, initial_manifest=args.manifest, From 08ffaf61f5ed93868749d6d64f6ff675ebda2222 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 16:36:00 +0200 Subject: [PATCH 0834/4212] -legacy code Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index dc847a8b..ff6d3921 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -52,9 +52,6 @@ class ConfigInstall(object): self.manifest = core.Manifest(self.context.target_host, self.local) self.code = core.Code(self.context.target_host, self.local, self.remote) - # Setup env to be used by others - FIXME - self.__init_env() - def cleanup(self): # FIXME: move to local? self.log.debug("Saving " + self.local.out_path + " to " + self.local.cache_path) From be21cdce178ed0083ace63c11ff717a2a79c8178 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 16:41:54 +0200 Subject: [PATCH 0835/4212] set __cdist_manifest for use in type emulator Signed-off-by: Steven Armstrong --- lib/cdist/core/manifest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index fc82b1cc..8d7f6e36 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -79,6 +79,7 @@ class Manifest(object): env = os.environ.copy() env.update(self.env) env['__manifest'] = self.local.manifest_path + env['__cdist_manifest'] = script return self.local.run_script(script, env=env) def run_type_manifest(self, cdist_object): From 74300ab38ec83be2366a4962e19460f013dddd1c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 16:52:06 +0200 Subject: [PATCH 0836/4212] set __cdist_manifest for use in type emulator Signed-off-by: Steven Armstrong --- lib/cdist/core/manifest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index 8d7f6e36..c1d6b7f0 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -83,6 +83,7 @@ class Manifest(object): return self.local.run_script(script, env=env) def run_type_manifest(self, cdist_object): + script = os.path.join(self.local.type_path, cdist_object.type.manifest_path) env = os.environ.copy() env.update(self.env) env.update({ @@ -90,6 +91,6 @@ class Manifest(object): '__object_id': cdist_object.object_id, '__object_fq': cdist_object.path, '__type': cdist_object.type.absolute_path, + '__cdist_manifest': script, }) - script = os.path.join(self.local.type_path, cdist_object.type.manifest_path) return self.local.run_script(script, env=env) From 6dada17509e7dd37543d654a3f5f92402d091283 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 16:53:07 +0200 Subject: [PATCH 0837/4212] only run type manifest if it exists Signed-off-by: Steven Armstrong --- lib/cdist/core/manifest.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index c1d6b7f0..93eb6f2d 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -84,13 +84,14 @@ class Manifest(object): def run_type_manifest(self, cdist_object): script = os.path.join(self.local.type_path, cdist_object.type.manifest_path) - env = os.environ.copy() - env.update(self.env) - env.update({ - '__object': cdist_object.absolute_path, - '__object_id': cdist_object.object_id, - '__object_fq': cdist_object.path, - '__type': cdist_object.type.absolute_path, - '__cdist_manifest': script, - }) - return self.local.run_script(script, env=env) + if os.path.isfile(script): + env = os.environ.copy() + env.update(self.env) + env.update({ + '__object': cdist_object.absolute_path, + '__object_id': cdist_object.object_id, + '__object_fq': cdist_object.path, + '__type': cdist_object.type.absolute_path, + '__cdist_manifest': script, + }) + return self.local.run_script(script, env=env) From d37ca88752690d6d4f00c204b57fabd6e8d36f9b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 16:53:48 +0200 Subject: [PATCH 0838/4212] +run_type_explorers, minor fixes Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index ff6d3921..d20fb92d 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -75,7 +75,7 @@ class ConfigInstall(object): def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" - self.local.link_emulator() + self.local.link_emulator(self.context.exec_path) self.run_global_explorers() self.manifest.run_initial_manifest(self.context.initial_manifest) @@ -104,10 +104,17 @@ class ConfigInstall(object): with open(path, 'w') as fd: fd.write(output) + def run_type_explorers(self, cdist_object): + """Run type explorers and save output in object.""" + self.explorer.transfer_type_explorers(cdist_object.type) + for explorer in self.explorer.list_type_explorer_names(cdist_object.type): + output = self.explorer.run_type_explorer(explorer, cdist_object) + cdist_object.explorers[explorer] = output + def object_prepare(self, cdist_object): """Prepare object: Run type explorer + manifest""" self.log.debug("Preparing object: " + cdist_object.name) - cdist_object.explorers = self.explorer.run_type_explorer(cdist_object) + self.run_type_explorers(cdist_object) self.manifest.run_type_manifest(cdist_object) cdist_object.prepared = True @@ -142,7 +149,7 @@ class ConfigInstall(object): def stage_run(self): """The final (and real) step of deployment""" self.log.info("Generating and executing code") - for cdist_object in cdist.core.Object.list_objects(self.local.object_path, + for cdist_object in core.Object.list_objects(self.local.object_path, self.local.type_path): self.log.debug("Run object: %s", cdist_object) self.object_run(cdist_object) From 773d325afa67380340d0d6fc12229ccb1eef4d17 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 16:56:03 +0200 Subject: [PATCH 0839/4212] only run gencode scripts if they exist Signed-off-by: Steven Armstrong --- lib/cdist/core/code.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index 6dfa2da4..2345acc8 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -95,15 +95,16 @@ class Code(object): def _run_gencode(self, cdist_object, which): cdist_type = cdist_object.type script = os.path.join(self.local.type_path, getattr(cdist_type, 'gencode_%s_path' % which)) - env = os.environ.copy() - env.update(self.env) - env.update({ - '__type': cdist_object.type.absolute_path, - '__object': cdist_object.absolute_path, - '__object_id': cdist_object.object_id, - '__object_fq': cdist_object.path, - }) - return self.local.run_script(script, env=env) + if os.path.isfile(script): + env = os.environ.copy() + env.update(self.env) + env.update({ + '__type': cdist_object.type.absolute_path, + '__object': cdist_object.absolute_path, + '__object_id': cdist_object.object_id, + '__object_fq': cdist_object.path, + }) + return self.local.run_script(script, env=env) def run_gencode_local(self, cdist_object): """Run the gencode-local script for the given cdist object.""" From 1f44617133b5af4e3d1c1d49793ad67aa9aefe8c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 17:03:05 +0200 Subject: [PATCH 0840/4212] use remote paths when executing on remote side Signed-off-by: Steven Armstrong --- lib/cdist/core/code.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index 2345acc8..af756263 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -123,7 +123,7 @@ class Code(object): def _run_code(self, cdist_object, which): which_exec = getattr(self, which) - script = os.path.join(self.local.object_path, getattr(cdist_object, 'code_%s_path' % which)) + script = os.path.join(which_exec.object_path, getattr(cdist_object, 'code_%s_path' % which)) return which_exec.run_script(script) def run_code_local(self, cdist_object): From d2bbd1d14c929f7d534737de26d301555255a762 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 17:04:07 +0200 Subject: [PATCH 0841/4212] fix imports Signed-off-by: Steven Armstrong --- lib/cdist/context.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index 3a6ed8a2..cf314409 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -24,12 +24,11 @@ import logging import os import sys import tempfile -#import stat -#import shutil -#import time -# -#import cdist.core -#import cdist.exec +import shutil + +from cdist.exec import local +from cdist.exec import remote + class Context(object): """Hold information about current context""" From 99ffda3cdf2dc202bd9852f4b124e6e9557659b8 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 17:04:33 +0200 Subject: [PATCH 0842/4212] always create global_explorer_out_path Signed-off-by: Steven Armstrong --- lib/cdist/exec/local.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index fd9f8229..bef44e21 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -73,6 +73,7 @@ class Local(object): def create_directories(self): self.mkdir(self.out_path) + self.mkdir(self.global_explorer_out_path) self.mkdir(self.bin_path) def rmdir(self, path): From d02b8d9d308fcc40b5e00d9d3ad0fde82600f575 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 17:04:54 +0200 Subject: [PATCH 0843/4212] fix imports Signed-off-by: Steven Armstrong --- lib/cdist/core/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/cdist/core/__init__.py b/lib/cdist/core/__init__.py index d6377b12..1dec9e8f 100644 --- a/lib/cdist/core/__init__.py +++ b/lib/cdist/core/__init__.py @@ -19,8 +19,8 @@ # # -__all__ = ['Type', 'Object'] - from cdist.core.type import Type from cdist.core.object import Object -from cdist.core.global_explorer import GlobalExplorer +from cdist.core.explorer import Explorer +from cdist.core.manifest import Manifest +from cdist.core.code import Code From 08d98ac3890a6535571540727bd0c9ecdf0d34a7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 17:05:34 +0200 Subject: [PATCH 0844/4212] only list type explorers if there are any; only transfer type explorers if there are ant Signed-off-by: Steven Armstrong --- lib/cdist/core/explorer.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 7e61639e..ee1008fe 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -95,14 +95,18 @@ class Explorer(object): def list_type_explorer_names(self, cdist_type): """Return a list of explorer names for the given type.""" source = os.path.join(self.local.type_path, cdist_type.explorer_path) - return os.listdir(source) + try: + return os.listdir(source) + except EnvironmentError: + return [] def transfer_type_explorers(self, cdist_type): """Transfer the type explorers for the given type to the remote side.""" - source = os.path.join(self.local.type_path, cdist_type.explorer_path) - destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) - self.remote.mkdir(destination) - self.remote.transfer(source, destination) + if cdist_type.explorers: + source = os.path.join(self.local.type_path, cdist_type.explorer_path) + destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) + self.remote.mkdir(destination) + self.remote.transfer(source, destination) def transfer_object_parameters(self, cdist_object): """Transfer the parameters for the given object to the remote side.""" From e2e2ddb33b4e187d3a3a0403ed1a628ddfabd253 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 17:05:53 +0200 Subject: [PATCH 0845/4212] add missing import Signed-off-by: Steven Armstrong --- bin/cdist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/cdist b/bin/cdist index fae83ff1..88cdf399 100755 --- a/bin/cdist +++ b/bin/cdist @@ -114,6 +114,8 @@ def configinstall(args, mode): time_start = time.time() + import cdist.context + for host in args.host: context = cdist.context.Context( target_host=host, From a822b64d9545e7603f36d460332005d3d00acedd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 13 Oct 2011 17:08:51 +0200 Subject: [PATCH 0846/4212] +output Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-13.output | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 doc/dev/logs/2011-10-13.output diff --git a/doc/dev/logs/2011-10-13.output b/doc/dev/logs/2011-10-13.output new file mode 100644 index 00000000..3eb68e1f --- /dev/null +++ b/doc/dev/logs/2011-10-13.output @@ -0,0 +1,10 @@ +[17:07] brief:cdist% ./bin/cdist config localhost +cat: /home/users/nico/.tmp/tmpfgy16_/out/object/__directory/tmp/foo/bar/.cdist/explorer/exists: No such file or directory +chgrp: cannot access `/tmp/foo/bar': No such file or directory +ERROR: localhost: Code that raised the error: +chgrp -R "postdrop" "/tmp/foo/bar" +chown -R "nico" "/tmp/foo/bar" + +ERROR: Remote script execution failed: /var/lib/cdist/object/__directory/tmp/foo/bar/.cdist/code-remote ['ssh', '-o', 'User=root', '-q', 'localhost', '/bin/sh', '-e', '/var/lib/cdist/object/__directory/tmp/foo/bar/.cdist/code-remote'] +[17:08] brief:cdist% + From 7abb33838107a5302f2e5c8f267295b5dab32010 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 17:11:03 +0200 Subject: [PATCH 0847/4212] bugfix test case Signed-off-by: Steven Armstrong --- lib/cdist/test/code/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index 2b4b1c87..0d7aec75 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -122,6 +122,7 @@ class CodeTestCase(unittest.TestCase): def test_run_code_remote_environment(self): self.cdist_object.code_remote = self.code.run_gencode_remote(self.cdist_object) + self.code.transfer_code_remote(self.cdist_object) output_string = self.code.run_code_remote(self.cdist_object) output_dict = {} for line in output_string.split('\n'): From 6271e27eb51030df9a8f5e65422c66a594616122 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 17:38:09 +0200 Subject: [PATCH 0848/4212] transfer object parameter before running type explorers Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index d20fb92d..22e836e2 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -107,6 +107,7 @@ class ConfigInstall(object): def run_type_explorers(self, cdist_object): """Run type explorers and save output in object.""" self.explorer.transfer_type_explorers(cdist_object.type) + self.explorer.transfer_object_parameters(cdist_object) for explorer in self.explorer.list_type_explorer_names(cdist_object.type): output = self.explorer.run_type_explorer(explorer, cdist_object) cdist_object.explorers[explorer] = output From 589b5a68b9dc3815e9595e64097d917659949945 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 17:59:23 +0200 Subject: [PATCH 0849/4212] FileList raise exception if write failse Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index 50b95ea2..e441533a 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -49,6 +49,7 @@ class FileList(collections.MutableSequence): def __read(self): lines = [] + # if file does not exist return empty list try: with open(self.path) as fd: for line in fd: @@ -59,13 +60,9 @@ class FileList(collections.MutableSequence): return lines def __write(self, lines): - try: - with open(self.path, 'w') as fd: - for line in lines: - fd.write(str(line) + '\n') - except EnvironmentError as e: - # error ignored - raise + with open(self.path, 'w') as fd: + for line in lines: + fd.write(str(line) + '\n') def __repr__(self): return repr(list(self)) From e70e0569ec24047966925bbba6fda2109f66624e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 18:01:46 +0200 Subject: [PATCH 0850/4212] FileList handle exception when deleting old/unused file Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index e441533a..cfdb007e 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -43,7 +43,11 @@ class FileList(collections.MutableSequence): self.path = path if initial: # delete existing file - os.unlink(self.path) + try: + os.unlink(self.path) + except EnvironmentError: + # ignored + pass for i in initial: self.append(i) From 9c04da1d4267adc713955b775e278f92c2e22939 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 21:21:59 +0200 Subject: [PATCH 0851/4212] DirectoryDictProperty: create directory if it doesnt exist Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index cfdb007e..f00ea98a 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -155,6 +155,9 @@ class DirectoryDict(collections.MutableMapping): if not os.path.isabs(path): raise AbsolutePathRequiredError(path) self.path = path + # create directory if it doesn't exist + if not os.path.isdir(self.path): + os.mkdir(self.path) if initial is not None: self.update(initial) if kwargs: @@ -210,6 +213,9 @@ class DirectoryDictProperty(DirectoryDict): path = path(*args, **kwargs) if not os.path.isabs(path): raise AbsolutePathRequiredError(path) + # create directory if it doesn't exist + if not os.path.isdir(path): + os.mkdir(path) self.path = path # Descriptor Protocol @@ -222,8 +228,6 @@ class DirectoryDictProperty(DirectoryDict): def __set__(self, obj, value): self._set_path(obj) if value is not None: - # create directory if it doesn't exist - os.makedirs(self.path, exist_ok=True) for name in self.keys(): del self[name] self.update(value) From 1b7ebc5885ce9f58466da7d48dbb7ef2465af3cf Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 21:23:04 +0200 Subject: [PATCH 0852/4212] more tests for different ways to access object.explorers Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 0953027b..982784f2 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -97,10 +97,27 @@ class ObjectTestCase(unittest.TestCase): def test_explorers(self): self.assertEqual(self.cdist_object.explorers, {}) - def test_explorers_after_changing(self): + # FIXME: actually testing fsproperty.DirectoryDictProperty here, move to their own test case + def test_explorers_assign_dict(self): expected = {'first': 'foo', 'second': 'bar'} # when set, written to file self.cdist_object.explorers = expected + object_explorer_path = os.path.join(self.cdist_object.base_path, self.cdist_object.explorer_path) + self.assertTrue(os.path.isdir(object_explorer_path)) + # when accessed, read from file + self.assertEqual(self.cdist_object.explorers, expected) + # remove dynamically created folder + self.cdist_object.explorers = {} + os.rmdir(os.path.join(self.cdist_object.base_path, self.cdist_object.explorer_path)) + + # FIXME: actually testing fsproperty.DirectoryDictProperty here, move to their own test case + def test_explorers_assign_key_value(self): + expected = {'first': 'foo', 'second': 'bar'} + object_explorer_path = os.path.join(self.cdist_object.base_path, self.cdist_object.explorer_path) + for key,value in expected.items(): + # when set, written to file + self.cdist_object.explorers[key] = value + self.assertTrue(os.path.isfile(os.path.join(object_explorer_path, key))) # when accessed, read from file self.assertEqual(self.cdist_object.explorers, expected) # remove dynamically created folder From 94724427fa36154cb9b175e089f658e3229d6c70 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 21:27:19 +0200 Subject: [PATCH 0853/4212] ++debug Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 22e836e2..c146d1da 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -110,6 +110,7 @@ class ConfigInstall(object): self.explorer.transfer_object_parameters(cdist_object) for explorer in self.explorer.list_type_explorer_names(cdist_object.type): output = self.explorer.run_type_explorer(explorer, cdist_object) + print("run_type_explorers: %s = %s" % (explorer, output)) cdist_object.explorers[explorer] = output def object_prepare(self, cdist_object): From a8e8d7b2274d38e353dd05ad6819b0a8e302b6b4 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 21:30:17 +0200 Subject: [PATCH 0854/4212] ++debug Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index f00ea98a..9b55be72 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -211,9 +211,11 @@ class DirectoryDictProperty(DirectoryDict): path = self.__path if callable(path): path = path(*args, **kwargs) + print("_set_path: %s" % path) if not os.path.isabs(path): raise AbsolutePathRequiredError(path) # create directory if it doesn't exist + print("os.path.isdir(%s): %s" % (path, os.path.isdir(path))) if not os.path.isdir(path): os.mkdir(path) self.path = path From cf6139504bbb94b92b755b6908834cc2bcedcc17 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 21:38:37 +0200 Subject: [PATCH 0855/4212] ++debug Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index c146d1da..96a1555d 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -106,10 +106,13 @@ class ConfigInstall(object): def run_type_explorers(self, cdist_object): """Run type explorers and save output in object.""" + self.log.debug("Transfering type explorers for type: %s", cdist_object.type) self.explorer.transfer_type_explorers(cdist_object.type) + self.log.debug("Transfering object parameters for object: %s", cdist_object.name) self.explorer.transfer_object_parameters(cdist_object) for explorer in self.explorer.list_type_explorer_names(cdist_object.type): output = self.explorer.run_type_explorer(explorer, cdist_object) + self.log.debug("Running type explorer '%s' for object '%s'", explorer, cdist_object.name) print("run_type_explorers: %s = %s" % (explorer, output)) cdist_object.explorers[explorer] = output From 0aa53bab4cfc88620b045b321dee67a396202474 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 21:51:16 +0200 Subject: [PATCH 0856/4212] ++debug Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index 9b55be72..3559fdcf 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -207,6 +207,7 @@ class DirectoryDictProperty(DirectoryDict): self.__path = path def _set_path(self, *args, **kwargs): + print("_set_path: self=%s, args=%s, kwargs=%s" % (self, args, kwargs)) if self.path is None: path = self.__path if callable(path): From 7fc63a380215c7694676f0cb3d80b26e46d35ca1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 21:53:37 +0200 Subject: [PATCH 0857/4212] ++debug Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index 3559fdcf..a6b7b414 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -207,7 +207,7 @@ class DirectoryDictProperty(DirectoryDict): self.__path = path def _set_path(self, *args, **kwargs): - print("_set_path: self=%s, args=%s, kwargs=%s" % (self, args, kwargs)) + print("_set_path: self=%s, args=%s, kwargs=%s" % (self, str(args), str(kwargs))) if self.path is None: path = self.__path if callable(path): From 17ce03f54dcfad34c233ce403f2d1160a8d4e448 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 21:54:53 +0200 Subject: [PATCH 0858/4212] ++debug Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index a6b7b414..d5c17d50 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -207,7 +207,7 @@ class DirectoryDictProperty(DirectoryDict): self.__path = path def _set_path(self, *args, **kwargs): - print("_set_path: self=%s, args=%s, kwargs=%s" % (self, str(args), str(kwargs))) + print("_set_path: self=%r, args=%r, kwargs=%r" % (self, args, kwargs)) if self.path is None: path = self.__path if callable(path): From a3e1ca9a186f429a895be8ccbbb7c73583ad7fcc Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 21:56:40 +0200 Subject: [PATCH 0859/4212] ++debug Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index d5c17d50..76e8b5ba 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -207,7 +207,9 @@ class DirectoryDictProperty(DirectoryDict): self.__path = path def _set_path(self, *args, **kwargs): - print("_set_path: self=%r, args=%r, kwargs=%r" % (self, args, kwargs)) + print("_set_path: self: %s" % self) + print("_set_path: args: %s" % args) + print("_set_path: kwargs: %s" % kwargs) if self.path is None: path = self.__path if callable(path): From 5bf0f24e6207d81437ec4ec0f317aa65232f7ddc Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 21:58:35 +0200 Subject: [PATCH 0860/4212] ++debug Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index 76e8b5ba..e17d1438 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -207,7 +207,7 @@ class DirectoryDictProperty(DirectoryDict): self.__path = path def _set_path(self, *args, **kwargs): - print("_set_path: self: %s" % self) + #print("_set_path: self: %s" % self) print("_set_path: args: %s" % args) print("_set_path: kwargs: %s" % kwargs) if self.path is None: From 453adefc9148eac265ae137415d22f3df7c3c21f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Oct 2011 21:59:57 +0200 Subject: [PATCH 0861/4212] ++debug Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index e17d1438..9ac7017f 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -210,6 +210,7 @@ class DirectoryDictProperty(DirectoryDict): #print("_set_path: self: %s" % self) print("_set_path: args: %s" % args) print("_set_path: kwargs: %s" % kwargs) + print("_set_path: self.path: %s" % self.path) if self.path is None: path = self.__path if callable(path): From be02dc5ff10a1cdb470e459bb082f155246544d1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 00:35:23 +0200 Subject: [PATCH 0862/4212] create object directory befor accessing it Signed-off-by: Steven Armstrong --- lib/cdist/test/explorer/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index 96206ae0..3b3a7e98 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -95,6 +95,7 @@ class ExplorerClassTestCase(unittest.TestCase): def test_transfer_object_parameters(self): cdist_type = core.Type(self.local.type_path, '__test_type') cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') + cdist_object.create() cdist_object.parameters = {'first': 'first value', 'second': 'second value'} self.explorer.transfer_object_parameters(cdist_object) source = os.path.join(self.local.object_path, cdist_object.parameter_path) From ede35ffd73b63c2cbf6dd4d07bb77861fb1b6770 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 01:15:08 +0200 Subject: [PATCH 0863/4212] completely rewrite file based property handling Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 225 ++++++++++++----------------------- 1 file changed, 76 insertions(+), 149 deletions(-) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index 9ac7017f..5b8aa708 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -98,55 +98,6 @@ class FileList(collections.MutableSequence): self.__write(lines) -class FileListProperty(FileList): - - def __init__(self, path): - """ - :param path: string or callable - - Usage: - - class Foo(object): - parameters = DirectoryDictProperty(lambda obj: os.path.join(obj.absolute_path, 'parameter')) - other_dict = DirectoryDictProperty('/tmp/folder') - - def __init__(self): - self.absolute_path = '/tmp/foo' - - """ - self.path = None - self.__path = path - - def _set_path(self, *args, **kwargs): - if self.path is None: - path = self.__path - if callable(path): - path = path(*args, **kwargs) - if not os.path.isabs(path): - raise AbsolutePathRequiredError(path) - self.path = path - - # Descriptor Protocol - def __get__(self, obj, objtype=None): - if obj is None: - return self.__class__ - self._set_path(obj) - return self - - def __set__(self, obj, value): - self._set_path(obj) - try: - os.unlink(self.path) - except EnvironmentError: - # ignored - pass - for item in value: - self.append(item) - - def __delete__(self, obj): - raise AttributeError("can't delete attribute") - - class DirectoryDict(collections.MutableMapping): """A dict that stores it's items as files in a directory. @@ -178,7 +129,10 @@ class DirectoryDict(collections.MutableMapping): fd.write(str(value)) def __delitem__(self, key): - os.remove(os.path.join(self.path, key)) + try: + os.remove(os.path.join(self.path, key)) + except EnvironmentError: + raise KeyError(key) def __iter__(self): return iter(os.listdir(self.path)) @@ -187,95 +141,98 @@ class DirectoryDict(collections.MutableMapping): return len(os.listdir(self.path)) -class DirectoryDictProperty(DirectoryDict): +class FileBasedProperty(object): + attribute_class = None def __init__(self, path): """ :param path: string or callable - Usage: + Abstract super class. Subclass and set the class member attribute_class accordingly. + + Usage with a sublcass: class Foo(object): - parameters = DirectoryDictProperty(lambda obj: os.path.join(obj.absolute_path, 'parameter')) - other_dict = DirectoryDictProperty('/tmp/folder') + # note that the actual DirectoryDict is stored as __parameters on the instance + parameters = DirectoryDictProperty(lambda instance: os.path.join(instance.absolute_path, 'parameter')) + # note that the actual DirectoryDict is stored as __other_dict on the instance + other_dict = DirectoryDictProperty('/tmp/other_dict') def __init__(self): self.absolute_path = '/tmp/foo' """ - self.path = None - self.__path = path + self.path = path - def _set_path(self, *args, **kwargs): - #print("_set_path: self: %s" % self) - print("_set_path: args: %s" % args) - print("_set_path: kwargs: %s" % kwargs) - print("_set_path: self.path: %s" % self.path) - if self.path is None: - path = self.__path - if callable(path): - path = path(*args, **kwargs) - print("_set_path: %s" % path) - if not os.path.isabs(path): - raise AbsolutePathRequiredError(path) - # create directory if it doesn't exist - print("os.path.isdir(%s): %s" % (path, os.path.isdir(path))) - if not os.path.isdir(path): - os.mkdir(path) - self.path = path + def _get_path(self, instance): + path = self.path + if callable(path): + path = path(instance) + return path - # Descriptor Protocol - def __get__(self, obj, objtype=None): - if obj is None: - return self.__class__ - self._set_path(obj) - return self + def _get_property_name(self, owner): + for name, prop in owner.__dict__.items(): + if self == prop: + return name - def __set__(self, obj, value): - self._set_path(obj) - if value is not None: - for name in self.keys(): - del self[name] - self.update(value) + def _get_attribute(self, instance, owner): + name = self._get_property_name(owner) + attribute_name = '__%s' % name + if not hasattr(instance, attribute_name): + path = self._get_path(instance) + attribute_instance = self.attribute_class(path) + setattr(instance, attribute_name, attribute_instance) + return getattr(instance, attribute_name) - def __delete__(self, obj): + def __get__(self, instance, owner): + if instance is None: + return self + return self._get_attribute(instance, owner) + + def __delete__(self, instance): raise AttributeError("can't delete attribute") -class FileBooleanProperty(object): - def __init__(self, path): - """ - :param path: string or callable +class DirectoryDictProperty(FileBasedProperty): + attribute_class = DirectoryDict - Usage: + def __set__(self, instance, value): + attribute_instance = self._get_attribute(instance, instance.__class__) + for name in attribute_instance.keys(): + del attribute_instance[name] + attribute_instance.update(value) - class Foo(object): - changed = FileBoolean(lambda obj: os.path.join(obj.absolute_path, 'changed')) - other_boolean = FileBoolean('/tmp/other_boolean') - def __init__(self): - self.absolute_path = '/tmp/foo_boolean' +class FileListProperty(FileBasedProperty): + attribute_class = FileList - """ - self._path = path + def __set__(self, instance, value): + path = self._get_path(instance) + try: + os.unlink(path) + except EnvironmentError: + # ignored + pass + attribute_instance = self._get_attribute(instance, instance.__class__) + for item in value: + attribute_instance.append(item) - def _get_path(self, *args, **kwargs): - path = self._path - if callable(path): - return path(*args, **kwargs) - if not os.path.isabs(path): - raise AbsolutePathRequiredError(path) - return path +class FileBooleanProperty(FileBasedProperty): + """A boolean property which uses a file to represent its value. + + File exists -> True + File does not exists -> False + """ # Descriptor Protocol - def __get__(self, obj, objtype=None): - if obj is None: - return self.__class__ - path = self._get_path(obj) + def __get__(self, instance, owner): + if instance is None: + return self + path = self._get_path(instance) return os.path.isfile(path) - def __set__(self, obj, value): - path = self._get_path(obj) + def __set__(self, instance, value): + path = self._get_path(instance) if value: open(path, "w").close() else: @@ -285,42 +242,15 @@ class FileBooleanProperty(object): # ignore pass - def __delete__(self, obj): - raise AttributeError("can't delete attribute") - -class FileStringProperty(object): +class FileStringProperty(FileBasedProperty): """A string property which stores its value in a file. """ - def __init__(self, path): - """ - :param path: string or callable - - Usage: - - class Foo(object): - source = FileStringProperty(lambda obj: os.path.join(obj.absolute_path, 'source')) - other = FileStringProperty('/tmp/other') - - def __init__(self): - self.absolute_path = '/tmp/foo_boolean' - - """ - self._path = path - - def _get_path(self, *args, **kwargs): - path = self._path - if callable(path): - return path(*args, **kwargs) - if not os.path.isabs(path): - raise AbsolutePathRequiredError(path) - return path - # Descriptor Protocol - def __get__(self, obj, objtype=None): - if obj is None: - return self.__class__ - path = self._get_path(obj) + def __get__(self, instance, owner): + if instance is None: + return self + path = self._get_path(instance) value = "" try: with open(path, "r") as fd: @@ -329,16 +259,13 @@ class FileStringProperty(object): pass return value - def __set__(self, obj, value): - path = self._get_path(obj) + def __set__(self, instance, value): + path = self._get_path(instance) if value: with open(path, "w") as fd: fd.write(str(value)) else: try: - os.unlink(path) + os.remove(path) except EnvironmentError: pass - - def __delete__(self, obj): - raise AttributeError("Can't delete attribute. Set it's value to an empty string to remove the underlying file.") From a8733c5b9b87214ebf922d99ed3f1b2543fb6c43 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 08:57:06 +0200 Subject: [PATCH 0864/4212] make base_path public Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index 58a147b7..8cf21ce7 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -57,10 +57,10 @@ class Type(object): return cls._instances[name] def __init__(self, base_path, name): - self._base_path = base_path + self.base_path = base_path self.name = name self.path = self.name - self.absolute_path = os.path.join(self._base_path, self.path) + self.absolute_path = os.path.join(self.base_path, self.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") From f4b12520631dbebec1e5927d9b9652f72dda2cb3 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 08:58:34 +0200 Subject: [PATCH 0865/4212] add test for Type base_path Signed-off-by: Steven Armstrong --- lib/cdist/test/type/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/cdist/test/type/__init__.py b/lib/cdist/test/type/__init__.py index 5ba1f4b9..42234069 100644 --- a/lib/cdist/test/type/__init__.py +++ b/lib/cdist/test/type/__init__.py @@ -62,6 +62,11 @@ class TypeTestCase(unittest.TestCase): cdist_type = cdist.core.Type(base_path, '__name_path') self.assertEqual(cdist_type.path, '__name_path') + def test_base_path(self): + base_path = fixtures + cdist_type = cdist.core.Type(base_path, '__name_path') + self.assertEqual(cdist_type.base_path, base_path) + def test_absolute_path(self): base_path = fixtures cdist_type = cdist.core.Type(base_path, '__name_path') From f6adefddec0c842df3b3c803079b0dfd08a844e2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 09:03:18 +0200 Subject: [PATCH 0866/4212] test for Object object_from_name Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 982784f2..790d6679 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -169,3 +169,11 @@ class ObjectTestCase(unittest.TestCase): def test_code_remote_after_changing(self): self.cdist_object.code_remote = 'Hello World' self.assertEqual(self.cdist_object.code_remote, 'Hello World') + + def test_object_from_name(self): + self.cdist_object.code_remote = 'Hello World' + other_name = '__first/man' + other_object = self.cdist_object.object_from_name(other_name) + self.assertTrue(isinstance(other_object, core.Object)) + self.assertEqual(other_object.type.name, '__first') + self.assertEqual(other_object.object_id, 'man') From 8e224b43c39e171f48503ba6c75d43342a83808b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 09:05:22 +0200 Subject: [PATCH 0867/4212] fix imports Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 790d6679..9ba3ed61 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -24,7 +24,7 @@ import tempfile import unittest import shutil -import cdist.core +from cdist import core import os.path as op my_dir = op.abspath(op.dirname(__file__)) @@ -35,19 +35,19 @@ type_base_path = op.join(fixtures, 'type') class ObjectClassTestCase(unittest.TestCase): def test_list_object_names(self): - object_names = list(cdist.core.Object.list_object_names(object_base_path)) + object_names = list(core.Object.list_object_names(object_base_path)) self.assertEqual(object_names, ['__first/man', '__second/on-the', '__third/moon']) def test_list_type_names(self): - type_names = list(cdist.core.Object.list_type_names(object_base_path)) + type_names = list(core.Object.list_type_names(object_base_path)) self.assertEqual(type_names, ['__first', '__second', '__third']) def test_list_objects(self): - objects = list(cdist.core.Object.list_objects(object_base_path, type_base_path)) + objects = list(core.Object.list_objects(object_base_path, type_base_path)) objects_expected = [ - cdist.core.Object(cdist.core.Type(type_base_path, '__first'), object_base_path, 'man'), - cdist.core.Object(cdist.core.Type(type_base_path, '__second'), object_base_path, 'on-the'), - cdist.core.Object(cdist.core.Type(type_base_path, '__third'), object_base_path, 'moon'), + core.Object(core.Type(type_base_path, '__first'), object_base_path, 'man'), + core.Object(core.Type(type_base_path, '__second'), object_base_path, 'on-the'), + core.Object(core.Type(type_base_path, '__third'), object_base_path, 'moon'), ] self.assertEqual(objects, objects_expected) @@ -55,8 +55,8 @@ class ObjectClassTestCase(unittest.TestCase): class ObjectTestCase(unittest.TestCase): def setUp(self): - self.cdist_type = cdist.core.Type(type_base_path, '__third') - self.cdist_object = cdist.core.Object(self.cdist_type, object_base_path, 'moon') + self.cdist_type = core.Type(type_base_path, '__third') + self.cdist_object = core.Object(self.cdist_type, object_base_path, 'moon') def tearDown(self): self.cdist_object.changed = False From b122b53d7338d507a13ad70b2dda097b9c80342a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 09:05:51 +0200 Subject: [PATCH 0868/4212] implement Object object_from_name Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index a170dd30..282e8be5 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -63,6 +63,21 @@ class Object(object): if DOT_CDIST in dirs: yield os.path.relpath(path, object_base_path) + def object_from_name(self, object_name): + """Convenience method for creating an object instance from an object name. + + Mainly intended to create objects when resolving requirements. + + e.g: + .object_from_name('__other/object') -> + + """ + type_path = self.type.base_path + object_path = self.base_path + type_name = object_name.split(os.sep)[0] + object_id = os.sep.join(object_name.split(os.sep)[1:]) + return self.__class__(self.type.__class__(type_path, type_name), object_path, object_id=object_id) + def __init__(self, cdist_type, base_path, object_id=None): self.type = cdist_type # instance of Type self.base_path = base_path From 74f4ec2f5d085f6a3b5f2065407055489deba6dc Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 09:06:32 +0200 Subject: [PATCH 0869/4212] resolve required objects using new object_from_name method Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 96a1555d..0d051685 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -136,7 +136,8 @@ class ConfigInstall(object): for requirement in cdist_object.requirements: self.log.debug("Object %s requires %s", cdist_object, requirement) # FIXME: requirement is a string, need to create object here - self.object_run(requirement) + required_object = cdist_object.object_from_name(requirement) + self.object_run(required_object) # Generate cdist_object.code_local = self.code.run_gencode_local(cdist_object) From 1c1cff37e3710c64917ab391671620274263a256 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 09:07:21 +0200 Subject: [PATCH 0870/4212] --debug Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 0d051685..e4ac2dde 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -113,7 +113,6 @@ class ConfigInstall(object): for explorer in self.explorer.list_type_explorer_names(cdist_object.type): output = self.explorer.run_type_explorer(explorer, cdist_object) self.log.debug("Running type explorer '%s' for object '%s'", explorer, cdist_object.name) - print("run_type_explorers: %s = %s" % (explorer, output)) cdist_object.explorers[explorer] = output def object_prepare(self, cdist_object): From 9f231a9ce7a93a80eb0637f8a1ba4fdae669b5af Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 09:47:59 +0200 Subject: [PATCH 0871/4212] suffix cache path with target_host Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index e4ac2dde..72ff7c6c 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -54,10 +54,11 @@ class ConfigInstall(object): def cleanup(self): # FIXME: move to local? - self.log.debug("Saving " + self.local.out_path + " to " + self.local.cache_path) - if os.path.exists(self.local.cache_path): - shutil.rmtree(self.local.cache_path) - shutil.move(self.local.out_path, self.local.cache_path) + destination = os.path.join(self.local.cache_path, self.context.target_host) + self.log.debug("Saving " + self.local.out_path + " to " + destination) + if os.path.exists(destination): + shutil.rmtree(destination) + shutil.move(self.local.out_path, destination) def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" From 69f8b74702331fa2effd5341cf783a00eb971cbe Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 09:49:37 +0200 Subject: [PATCH 0872/4212] +todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 93c6cab3..3209fe8c 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,3 +1,9 @@ +logging: + - logging from type emulator without clobbering stdout + maybe implement logging server as described here [1] + [1] http://docs.python.org/py3k/howto/logging-cookbook.html#configuration-server-example + + tests: __init__(): From 1375ed55b67c97774b275de1a88f92fd08ad54d2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 10:12:02 +0200 Subject: [PATCH 0873/4212] +todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 3209fe8c..6364c4d4 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -3,6 +3,13 @@ logging: maybe implement logging server as described here [1] [1] http://docs.python.org/py3k/howto/logging-cookbook.html#configuration-server-example + - use different logger to limit output to current area of interest, + e.g. + explorer.$target_host: explorer related messages for the run for $target_host + manifest.$target_host: manifest related messages for the run for $target_host + ... + then one could filter e.g. on explorer.* + tests: From 77813efdf369152d2616439c0cc320b072124931 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 10:30:56 +0200 Subject: [PATCH 0874/4212] +todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 6364c4d4..a602b753 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -10,6 +10,10 @@ logging: ... then one could filter e.g. on explorer.* +exec local & remote: + - don't capture output by default + - add new mechanism to capture output explicitly + tests: From 96d5d9b8e8a22256212ecd9fa9d924d5bca67ab8 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 10:32:25 +0200 Subject: [PATCH 0875/4212] +todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index a602b753..c7e93423 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -15,6 +15,10 @@ exec local & remote: - add new mechanism to capture output explicitly +config_install: + - move code for running global and type explorer run to cdist.core.explorer + + tests: __init__(): From 6067646ffa4855f357cc3f3902a96e3425934ad7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 10:40:10 +0200 Subject: [PATCH 0876/4212] +todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index c7e93423..90040ad6 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -10,6 +10,10 @@ logging: ... then one could filter e.g. on explorer.* + - more granular debug output, + [2] http://blog.ooz.ie/2011/03/python-logging-extending-standard.html + + exec local & remote: - don't capture output by default - add new mechanism to capture output explicitly @@ -18,6 +22,10 @@ exec local & remote: config_install: - move code for running global and type explorer run to cdist.core.explorer +tests: + - aufraeumen + - test suite + tests: From 8ac1406020dc567be29cafeaac995a9de5edc247 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 10:49:28 +0200 Subject: [PATCH 0877/4212] stage away obsolete tests Signed-off-by: Nico Schottelius --- lib/cdist/test/test_path.py | 78 ------------------- .../tests_reintegrate}/test_banner.py | 0 .../tests_reintegrate}/test_config.py | 0 .../tests_reintegrate}/test_exec.py | 0 .../tests_reintegrate}/test_install.py | 0 5 files changed, 78 deletions(-) delete mode 100644 lib/cdist/test/test_path.py rename {lib/cdist/test => other/tests_reintegrate}/test_banner.py (100%) rename {lib/cdist/test => other/tests_reintegrate}/test_config.py (100%) rename {lib/cdist/test => other/tests_reintegrate}/test_exec.py (100%) rename {lib/cdist/test => other/tests_reintegrate}/test_install.py (100%) diff --git a/lib/cdist/test/test_path.py b/lib/cdist/test/test_path.py deleted file mode 100644 index f86c8fad..00000000 --- a/lib/cdist/test/test_path.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 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 shutil -import sys -import tempfile -import unittest - -import cdist.path -import cdist.test - -class Path(unittest.TestCase): - def setUp(self): - self.temp_dir = tempfile.mkdtemp() - self.init_manifest = os.path.join(self.temp_dir, "manifest") - self.path = cdist.path.Path("localhost", "root", "ssh root@localhost", - initial_manifest=self.init_manifest, - base_dir=self.temp_dir) - - os.mkdir(self.path.conf_dir) - os.mkdir(self.path.type_base_dir) - - self.install_type_name = "__install_test" - self.config_type_name = "__config_test" - - # Create install type - self.install_type = os.path.join(self.path.type_base_dir, self.install_type_name) - os.mkdir(self.install_type) - open(os.path.join(self.install_type, "install"), "w").close() - - # Create config type - self.config_type = os.path.join(self.path.type_base_dir, self.config_type_name) - os.mkdir(self.config_type) - - def tearDown(self): - self.path.cleanup() - shutil.rmtree(self.temp_dir) - - def test_type_detection(self): - """Check that a type is identified as install or configuration correctly""" - - self.assertTrue(self.path.is_install_type(self.install_type)) - self.assertFalse(self.path.is_install_type(self.config_type)) - - def test_manifest_uses_install_types_only(self): - """Check that objects created from manifest are only of install type""" - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - self.install_type_name + "testid\n", - self.config_type_name + "testid\n", - ]) - manifest_fd.close() - - self.install.run_initial_manifest() - - # FIXME: check that only __partition_msdos objects are created! - - self.assertFalse(failed) diff --git a/lib/cdist/test/test_banner.py b/other/tests_reintegrate/test_banner.py similarity index 100% rename from lib/cdist/test/test_banner.py rename to other/tests_reintegrate/test_banner.py diff --git a/lib/cdist/test/test_config.py b/other/tests_reintegrate/test_config.py similarity index 100% rename from lib/cdist/test/test_config.py rename to other/tests_reintegrate/test_config.py diff --git a/lib/cdist/test/test_exec.py b/other/tests_reintegrate/test_exec.py similarity index 100% rename from lib/cdist/test/test_exec.py rename to other/tests_reintegrate/test_exec.py diff --git a/lib/cdist/test/test_install.py b/other/tests_reintegrate/test_install.py similarity index 100% rename from lib/cdist/test/test_install.py rename to other/tests_reintegrate/test_install.py From 9640c3a0981ce165ac4e552cf97de7062232b25f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 11:21:12 +0200 Subject: [PATCH 0878/4212] test for illegal object_id Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 9ba3ed61..9a13f524 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -52,6 +52,14 @@ class ObjectClassTestCase(unittest.TestCase): self.assertEqual(objects, objects_expected) +class ObjectIdTestCase(unittest.TestCase): + def test_illegal_object_id(self): + cdist_type = core.Type(type_base_path, '__third') + illegal_object_id = '/object_id/may/not/start/with/slash' + with self.assertRaises(core.IllegalObjectIdError): + core.Object(cdist_type, object_base_path, illegal_object_id) + + class ObjectTestCase(unittest.TestCase): def setUp(self): From 3e3919d15f00c62c670b3ab901d7274e43a2b770 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 11:25:39 +0200 Subject: [PATCH 0879/4212] implement fail if object_id starts with / Signed-off-by: Steven Armstrong --- lib/cdist/core/__init__.py | 1 + lib/cdist/core/object.py | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/lib/cdist/core/__init__.py b/lib/cdist/core/__init__.py index 1dec9e8f..507082a3 100644 --- a/lib/cdist/core/__init__.py +++ b/lib/cdist/core/__init__.py @@ -21,6 +21,7 @@ from cdist.core.type import Type from cdist.core.object import Object +from cdist.core.object import IllegalObjectIdError from cdist.core.explorer import Explorer from cdist.core.manifest import Manifest from cdist.core.code import Code diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 282e8be5..c447f243 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -33,6 +33,14 @@ log = logging.getLogger(__name__) DOT_CDIST = '.cdist' +class IllegalObjectIdError(cdist.Error): + def __init__(self, object_id): + self.object_id = object_id + + def __str__(self): + return 'Illegal object id: %s' % self.object_id + + class Object(object): """Represents a cdist object. @@ -79,6 +87,8 @@ class Object(object): return self.__class__(self.type.__class__(type_path, type_name), object_path, object_id=object_id) def __init__(self, cdist_type, base_path, object_id=None): + if object_id and object_id.startswith('/'): + raise IllegalObjectIdError(object_id) self.type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id From d346364544b0eea9f2687477103884caf3720c50 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 11:39:03 +0200 Subject: [PATCH 0880/4212] better error message Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index c447f243..eeb5799b 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -34,11 +34,12 @@ DOT_CDIST = '.cdist' class IllegalObjectIdError(cdist.Error): - def __init__(self, object_id): + def __init__(self, object_id, message=None): self.object_id = object_id + self.message = message or 'Illegal object id' def __str__(self): - return 'Illegal object id: %s' % self.object_id + return '%s: %s' % (self.message, self.object_id) class Object(object): @@ -88,7 +89,7 @@ class Object(object): def __init__(self, cdist_type, base_path, object_id=None): if object_id and object_id.startswith('/'): - raise IllegalObjectIdError(object_id) + raise IllegalObjectIdError(object_id, 'object_id may not start with /') self.type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id From f285d9e64ee1e3e3111eab7ccba0099097fac43e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 11:39:55 +0200 Subject: [PATCH 0881/4212] emulator: fail if object_id of requirement starts with slash Signed-off-by: Steven Armstrong --- lib/cdist/emulator.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 4445f0f7..ca65e731 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -106,8 +106,19 @@ def run(argv): # Record requirements if "require" in os.environ: requirements = os.environ['require'] - log.debug("%s:Writing requirements: %s" % (cdist_object.path, requirements)) - cdist_object.requirements.extend(requirements.split(" ")) + for requirement in requirements.split(" "): + requirement_parts = requirement.split(os.sep, 1) + requirement_parts.reverse() + requirement_type_name = requirement_parts.pop() + try: + requirement_object_id = requirement_parts.pop() + except IndexError: + # no object id, must be singleton + requirement_object_id = 'singleton' + if requirement_object_id.startswith('/'): + raise core.IllegalObjectIdError(requirement_object_id, 'object_id may not start with /') + log.debug("Recording requirement: %s -> %s" % (cdist_object.path, requirement)) + cdist_object.requirements.append(rement_object_id) # Record / Append source cdist_object.source.append(object_source) From 1c84e423d11b9535a940ed9f76f8e69a3b2ff40e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 11:49:37 +0200 Subject: [PATCH 0882/4212] include type name in error message Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 7 ++++--- lib/cdist/emulator.py | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index eeb5799b..60ae59f4 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -34,12 +34,13 @@ DOT_CDIST = '.cdist' class IllegalObjectIdError(cdist.Error): - def __init__(self, object_id, message=None): + def __init__(self, object_id, type_name, message=None): self.object_id = object_id + self.type_name = type_name self.message = message or 'Illegal object id' def __str__(self): - return '%s: %s' % (self.message, self.object_id) + return '%s: %s' % (self.message, os.path.join(self.type_name. self.object_id)) class Object(object): @@ -89,7 +90,7 @@ class Object(object): def __init__(self, cdist_type, base_path, object_id=None): if object_id and object_id.startswith('/'): - raise IllegalObjectIdError(object_id, 'object_id may not start with /') + raise IllegalObjectIdError(object_id, cdist_type.name, 'object_id may not start with /') self.type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index ca65e731..f37c3169 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -116,9 +116,9 @@ def run(argv): # no object id, must be singleton requirement_object_id = 'singleton' if requirement_object_id.startswith('/'): - raise core.IllegalObjectIdError(requirement_object_id, 'object_id may not start with /') + raise core.IllegalObjectIdError(requirement_object_id, requirement_type_name, 'object_id may not start with /') log.debug("Recording requirement: %s -> %s" % (cdist_object.path, requirement)) - cdist_object.requirements.append(rement_object_id) + cdist_object.requirements.append(requirement) # Record / Append source cdist_object.source.append(object_source) From f76a5abf6f1e97483bd974a905df26d1f6037c49 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 11:50:40 +0200 Subject: [PATCH 0883/4212] /./,/ Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 60ae59f4..a802a457 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -40,7 +40,7 @@ class IllegalObjectIdError(cdist.Error): self.message = message or 'Illegal object id' def __str__(self): - return '%s: %s' % (self.message, os.path.join(self.type_name. self.object_id)) + return '%s: %s' % (self.message, os.path.join(self.type_name, self.object_id)) class Object(object): From 2194368c0cdeb3728e4f72c610dd110471b6332c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 12:03:03 +0200 Subject: [PATCH 0884/4212] load all test classes Signed-off-by: Nico Schottelius --- lib/cdist/test/__main__.py | 39 ++++++++++--------- .../tests_reintegrate}/nico_ui.py | 0 2 files changed, 21 insertions(+), 18 deletions(-) rename {lib/cdist/test => other/tests_reintegrate}/nico_ui.py (100%) diff --git a/lib/cdist/test/__main__.py b/lib/cdist/test/__main__.py index 3b31a2cd..136e122a 100644 --- a/lib/cdist/test/__main__.py +++ b/lib/cdist/test/__main__.py @@ -1,3 +1,4 @@ +#c1406:!/usr/bin/env python3 #!/usr/bin/env python3 # -*- coding: utf-8 -*- # @@ -20,27 +21,29 @@ # # - +import imp import os import sys -import cdist.test import unittest -#class UI(unittest.TestCase): -# def test_banner(self): -# self.assertEqual(subprocess.call([cdist_exec_path, "banner"]), 0) -# -# def test_help(self): -# for cmd in cdist_commands: -# self.assertEqual(subprocess.call([cdist_exec_path, cmd, "-h"]), 0) -# -# # FIXME: mockup needed -# def test_config_localhost(self): -# for cmd in cdist_commands: -# self.assertEqual(subprocess.call([cdist_exec_path, "config", "localhost"]), 0) +base_dir = os.path.dirname(os.path.realpath(__file__)) + +test_modules = [] +for possible_test in os.listdir(base_dir): + filename = "__init__.py" + mod_path = os.path.join(base_dir, possible_test, filename) + + print(mod_path + "x") + + if os.path.isfile(mod_path): + test_modules.append(possible_test) + +print(sys.path) + +for test_module in test_modules: + module = imp.find_module(test_module, [base_dir]) + imp.load_module(test_module, *module) + +#suite = unittest.defaultTestLoader.loadTestsFromModule(cdist.test.code) -print(cdist.test.cdist_exec_path) -print(sys.argv) -suite = unittest.defaultTestLoader.discover(os.path.dirname(__file__)) -unittest.TextTestRunner(verbosity=1).run(suite) diff --git a/lib/cdist/test/nico_ui.py b/other/tests_reintegrate/nico_ui.py similarity index 100% rename from lib/cdist/test/nico_ui.py rename to other/tests_reintegrate/nico_ui.py From 588d789ee2c18a576547b4218393d0e930289a8d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 12:03:44 +0200 Subject: [PATCH 0885/4212] empty init Signed-off-by: Nico Schottelius --- lib/cdist/test/__init__.py | 46 -------------------------------------- 1 file changed, 46 deletions(-) diff --git a/lib/cdist/test/__init__.py b/lib/cdist/test/__init__.py index 2f88bf7e..e69de29b 100644 --- a/lib/cdist/test/__init__.py +++ b/lib/cdist/test/__init__.py @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 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 subprocess -import unittest - -cdist_commands=["banner", "config", "install"] - -cdist_base_path = os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../")) - -cdist_exec_path = os.path.join(cdist_base_path, "bin/cdist") - -#class UI(unittest.TestCase): -# def test_banner(self): -# self.assertEqual(subprocess.call([cdist_exec_path, "banner"]), 0) -# -# def test_help(self): -# for cmd in cdist_commands: -# self.assertEqual(subprocess.call([cdist_exec_path, cmd, "-h"]), 0) -# -# # FIXME: mockup needed -# def test_config_localhost(self): -# for cmd in cdist_commands: -# self.assertEqual(subprocess.call([cdist_exec_path, "config", "localhost"]), 0) From 93db0b58d64210f14539a3c79766e810c368423a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 12:05:30 +0200 Subject: [PATCH 0886/4212] append type to error message Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index a802a457..339591ad 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -40,7 +40,7 @@ class IllegalObjectIdError(cdist.Error): self.message = message or 'Illegal object id' def __str__(self): - return '%s: %s' % (self.message, os.path.join(self.type_name, self.object_id)) + return '%s: type: %s, object_id: %s' % (self.message, self.type_name, self.object_id) class Object(object): From 9aa064a0ae9ed103e09ce7760f7f0a4bed1e0e2e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 12:10:21 +0200 Subject: [PATCH 0887/4212] remove obsolete test Signed-off-by: Nico Schottelius --- lib/cdist/test/type_explorer/__init__.py | 39 ------------------- .../fixtures/type/__test_type/explorer/world | 2 - .../explorer/test_parameter | 3 -- 3 files changed, 44 deletions(-) delete mode 100644 lib/cdist/test/type_explorer/__init__.py delete mode 100755 lib/cdist/test/type_explorer/fixtures/type/__test_type/explorer/world delete mode 100755 lib/cdist/test/type_explorer/fixtures/type/__test_type_object_parameter/explorer/test_parameter diff --git a/lib/cdist/test/type_explorer/__init__.py b/lib/cdist/test/type_explorer/__init__.py deleted file mode 100644 index 19d59342..00000000 --- a/lib/cdist/test/type_explorer/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -# -# 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 unittest - -import cdist.core - -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 TypeExplorer(unittest.TestCase): - - def setUp(self): - - def test_explorer_output(self): - """Check for output of type explorer""" - diff --git a/lib/cdist/test/type_explorer/fixtures/type/__test_type/explorer/world b/lib/cdist/test/type_explorer/fixtures/type/__test_type/explorer/world deleted file mode 100755 index 21ba6825..00000000 --- a/lib/cdist/test/type_explorer/fixtures/type/__test_type/explorer/world +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -echo hello diff --git a/lib/cdist/test/type_explorer/fixtures/type/__test_type_object_parameter/explorer/test_parameter b/lib/cdist/test/type_explorer/fixtures/type/__test_type_object_parameter/explorer/test_parameter deleted file mode 100755 index 0778907c..00000000 --- a/lib/cdist/test/type_explorer/fixtures/type/__test_type_object_parameter/explorer/test_parameter +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -cat "$__object/parameter/test" From 97da16f4bc23b3de0dbf2ef38257246ba4b45b5b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 12:12:06 +0200 Subject: [PATCH 0888/4212] load test suites Signed-off-by: Nico Schottelius --- lib/cdist/test/__main__.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/cdist/test/__main__.py b/lib/cdist/test/__main__.py index 136e122a..eba262fa 100644 --- a/lib/cdist/test/__main__.py +++ b/lib/cdist/test/__main__.py @@ -33,17 +33,19 @@ for possible_test in os.listdir(base_dir): filename = "__init__.py" mod_path = os.path.join(base_dir, possible_test, filename) - print(mod_path + "x") - if os.path.isfile(mod_path): test_modules.append(possible_test) print(sys.path) +suites = [] + for test_module in test_modules: module = imp.find_module(test_module, [base_dir]) imp.load_module(test_module, *module) -#suite = unittest.defaultTestLoader.loadTestsFromModule(cdist.test.code) - + print(module) + # module_name = + suite = unittest.defaultTestLoader.loadTestsFromModule("cdist.test." + test_module) + suites.append(suite) From fb705adc5d8af9d708dcfd11f7ac37c2ca803342 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 14:04:56 +0200 Subject: [PATCH 0889/4212] simplify object_id error handling Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 339591ad..eeb5799b 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -34,13 +34,12 @@ DOT_CDIST = '.cdist' class IllegalObjectIdError(cdist.Error): - def __init__(self, object_id, type_name, message=None): + def __init__(self, object_id, message=None): self.object_id = object_id - self.type_name = type_name self.message = message or 'Illegal object id' def __str__(self): - return '%s: type: %s, object_id: %s' % (self.message, self.type_name, self.object_id) + return '%s: %s' % (self.message, self.object_id) class Object(object): @@ -90,7 +89,7 @@ class Object(object): def __init__(self, cdist_type, base_path, object_id=None): if object_id and object_id.startswith('/'): - raise IllegalObjectIdError(object_id, cdist_type.name, 'object_id may not start with /') + raise IllegalObjectIdError(object_id, 'object_id may not start with /') self.type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id From 6d7620582db12bc7aa81c1d7f6c5da3f470a93b2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 14:16:15 +0200 Subject: [PATCH 0890/4212] run all test suites, if called as main Signed-off-by: Nico Schottelius --- lib/cdist/test/__main__.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/cdist/test/__main__.py b/lib/cdist/test/__main__.py index eba262fa..08e839d1 100644 --- a/lib/cdist/test/__main__.py +++ b/lib/cdist/test/__main__.py @@ -1,4 +1,3 @@ -#c1406:!/usr/bin/env python3 #!/usr/bin/env python3 # -*- coding: utf-8 -*- # @@ -36,16 +35,14 @@ for possible_test in os.listdir(base_dir): if os.path.isfile(mod_path): test_modules.append(possible_test) -print(sys.path) - suites = [] - for test_module in test_modules: - module = imp.find_module(test_module, [base_dir]) - imp.load_module(test_module, *module) + module_parameters = imp.find_module(test_module, [base_dir]) + module = imp.load_module("cdist.test." + test_module, *module_parameters) - print(module) - # module_name = - - suite = unittest.defaultTestLoader.loadTestsFromModule("cdist.test." + test_module) + suite = unittest.defaultTestLoader.loadTestsFromModule(module) + # print("Got suite: " + suite.__str__()) suites.append(suite) + +all_suites = unittest.TestSuite(suites) +unittest.TextTestRunner(verbosity=2).run(all_suites) From 516b172d75c8ca85a6245ec5cc168c09a7a6469c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 14:19:18 +0200 Subject: [PATCH 0891/4212] run new test instance by default if no test is specified Signed-off-by: Nico Schottelius --- build.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build.sh b/build.sh index 0464defc..69f0ad92 100755 --- a/build.sh +++ b/build.sh @@ -128,13 +128,13 @@ case "$1" in test) shift # skip t - set -x + export PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib + if [ $# -lt 1 ]; then - set -- cdist.test - fi - PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib \ + python3 -m cdist.test + else python3 -m unittest "$@" - + fi ;; *) From 1db1a3f6a77c994cbfbf6cf2420c860171277c12 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 14:19:38 +0200 Subject: [PATCH 0892/4212] build does not need suffix .sh Signed-off-by: Nico Schottelius --- build.sh => build | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename build.sh => build (100%) diff --git a/build.sh b/build similarity index 100% rename from build.sh rename to build From 62a6617bcd952b157910f876922376bffa807c34 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 14:39:05 +0200 Subject: [PATCH 0893/4212] add old benchmarks Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-04-21.benchmark-eth | 7 + doc/dev/logs/2011-04-27.debug-timing | 1725 ++++++ doc/dev/logs/2011-09-12.benchmark-home | 6960 ++++++++++++++++++++++++ 3 files changed, 8692 insertions(+) create mode 100644 doc/dev/logs/2011-04-21.benchmark-eth create mode 100644 doc/dev/logs/2011-04-27.debug-timing create mode 100644 doc/dev/logs/2011-09-12.benchmark-home diff --git a/doc/dev/logs/2011-04-21.benchmark-eth b/doc/dev/logs/2011-04-21.benchmark-eth new file mode 100644 index 00000000..f1dfa05a --- /dev/null +++ b/doc/dev/logs/2011-04-21.benchmark-eth @@ -0,0 +1,7 @@ +cdist-mass-deploy -p ikq02.ethz.ch; 142 +cdist-mass-deploy -p ikq02.ethz.ch ikq03.ethz.ch; 194 +cdist-mass-deploy -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch; 271 +cdist-mass-deploy -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch ikq05.ethz.ch; 328 +cdist-mass-deploy -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch ikq05.ethz.ch ikq06.ethz.ch; 456 +cdist-mass-deploy -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch ikq05.ethz.ch ikq06.ethz.ch ikq07.ethz.ch; 568 + diff --git a/doc/dev/logs/2011-04-27.debug-timing b/doc/dev/logs/2011-04-27.debug-timing new file mode 100644 index 00000000..e6c99d4d --- /dev/null +++ b/doc/dev/logs/2011-04-27.debug-timing @@ -0,0 +1,1725 @@ +core: cdist 1.6.2: Configuring ikq04.ethz.ch +core: Creating clean directory structure +core: Transferring cdist binaries to the target host +core: Debug: Mit Apr 27 14:17:37 CEST 2011 +core: Debug: Mit Apr 27 14:17:37 CEST 2011 +core: Running global explorers +core: Debug: Mit Apr 27 14:17:38 CEST 2011 +core: Running initial manifest for ikq04.ethz.ch +core: Debug: Mit Apr 27 14:17:39 CEST 2011 +__ethz_systems/singleton: Preparing object +__ethz_systems/singleton: Checking manifest +__ethz_systems/singleton: Executing manifest +__file/etc/cdist-configured: Preparing object +__file/etc/cdist-configured: Transfering explorers for __file +__file/etc/cdist-configured: Running explorers +__file/etc/cdist-configured: Checking manifest +__package/puppet: Preparing object +__package/puppet: Checking manifest +__package/puppet: Executing manifest +__ethz_systems_root_via_ssh/subasui: Preparing object +__ethz_systems_root_via_ssh/subasui: Checking manifest +__ethz_systems_root_via_ssh/subasui: Executing manifest +__ethz_systems_root_via_ssh/blukas: Preparing object +__ethz_systems_root_via_ssh/blukas: Checking manifest +__ethz_systems_root_via_ssh/blukas: Executing manifest +__ethz_systems_root_via_ssh/petfisch: Preparing object +__ethz_systems_root_via_ssh/petfisch: Checking manifest +__ethz_systems_root_via_ssh/petfisch: Executing manifest +__ethz_nullmailer/singleton: Preparing object +__ethz_nullmailer/singleton: Checking manifest +__ethz_nullmailer/singleton: Executing manifest +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__ethz_systems_ldap_krb5_autofs/singleton: Preparing object +__ethz_systems_ldap_krb5_autofs/singleton: Checking manifest +__ethz_systems_ldap_krb5_autofs/singleton: Executing manifest +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__etc_hosts/singleton: Preparing object +__etc_hosts/singleton: Checking manifest +__etc_hosts/singleton: Executing manifest +__directory/local: Preparing object +__directory/local: Transfering explorers for __directory +__directory/local: Running explorers +__directory/local: Checking manifest +__ethz_ntpd/singleton: Preparing object +__ethz_ntpd/singleton: Checking manifest +__ethz_ntpd/singleton: Executing manifest +__ethz_systems_packages/singleton: Preparing object +__ethz_systems_packages/singleton: Checking manifest +__ethz_systems_packages/singleton: Executing manifest +__package_apt/puppet: Preparing object +__package_apt/puppet: Transfering explorers for __package_apt +__package_apt/puppet: Running explorers +__package_apt/puppet: Checking manifest +__addifnosuchline/ssh-root-subasui: Preparing object +__addifnosuchline/ssh-root-subasui: Transfering explorers for __addifnosuchline +__addifnosuchline/ssh-root-subasui: Running explorers +__addifnosuchline/ssh-root-subasui: Checking manifest +__addifnosuchline/ssh-root-blukas: Preparing object +__addifnosuchline/ssh-root-blukas: Running explorers +__addifnosuchline/ssh-root-blukas: Checking manifest +__addifnosuchline/ssh-root-petfisch: Preparing object +__addifnosuchline/ssh-root-petfisch: Running explorers +__addifnosuchline/ssh-root-petfisch: Checking manifest +__ethz_systems_motd/singleton: Preparing object +__ethz_systems_motd/singleton: Checking manifest +__ethz_systems_motd/singleton: Executing manifest +__ethz_systems_sudo/singleton: Preparing object +__ethz_systems_sudo/singleton: Checking manifest +__ethz_systems_sudo/singleton: Executing manifest +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__ethz_sans_syslog/singleton: Preparing object +__ethz_sans_syslog/singleton: Checking manifest +__ethz_sans_syslog/singleton: Executing manifest +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto.pub: Preparing object +__file/etc/ethz/autofs/auto.pub: Running explorers +__file/etc/ethz/autofs/auto.pub: Checking manifest +__file/etc/default/openntpd: Preparing object +__file/etc/default/openntpd: Running explorers +__file/etc/default/openntpd: Checking manifest +__file/etc/hosts: Preparing object +__file/etc/hosts: Running explorers +__file/etc/hosts: Checking manifest +__file/etc/syslog-ng/syslog-ng.conf: Preparing object +__file/etc/syslog-ng/syslog-ng.conf: Running explorers +__file/etc/syslog-ng/syslog-ng.conf: Checking manifest +__file/etc/nullmailer/remotes: Preparing object +__file/etc/nullmailer/remotes: Running explorers +__file/etc/nullmailer/remotes: Checking manifest +__file/etc/openntpd/ntpd.conf: Preparing object +__file/etc/openntpd/ntpd.conf: Running explorers +__file/etc/openntpd/ntpd.conf: Checking manifest +__file/etc/sudoers.d/systems: Preparing object +__file/etc/sudoers.d/systems: Running explorers +__file/etc/sudoers.d/systems: Checking manifest +__link/etc/motd: Preparing object +__link/etc/motd: Checking manifest +__motd/singleton: Preparing object +__motd/singleton: Checking manifest +__motd/singleton: Executing manifest +__package/mc: Preparing object +__package/mc: Checking manifest +__package/mc: Executing manifest +__package/ant: Preparing object +__package/ant: Checking manifest +__package/ant: Executing manifest +__package/gcc: Preparing object +__package/gcc: Checking manifest +__package/gcc: Executing manifest +__package/gdb: Preparing object +__package/gdb: Checking manifest +__package/gdb: Executing manifest +__package/vim: Preparing object +__package/vim: Checking manifest +__package/vim: Executing manifest +__package/git-core: Preparing object +__package/git-core: Checking manifest +__package/git-core: Executing manifest +__package/atop: Preparing object +__package/atop: Checking manifest +__package/atop: Executing manifest +__package/flex: Preparing object +__package/flex: Checking manifest +__package/flex: Executing manifest +__package/gawk: Preparing object +__package/gawk: Checking manifest +__package/gawk: Executing manifest +__package/make: Preparing object +__package/make: Checking manifest +__package/make: Executing manifest +__package/sudo: Preparing object +__package/sudo: Checking manifest +__package/sudo: Executing manifest +__package/swig: Preparing object +__package/swig: Checking manifest +__package/swig: Executing manifest +__package/libreadline5-dev: Preparing object +__package/libreadline5-dev: Checking manifest +__package/libreadline5-dev: Executing manifest +__package/libexpat1-dev: Preparing object +__package/libexpat1-dev: Checking manifest +__package/libexpat1-dev: Executing manifest +__package/libnet-ssleay-perl: Preparing object +__package/libnet-ssleay-perl: Checking manifest +__package/libnet-ssleay-perl: Executing manifest +__package/subversion: Preparing object +__package/subversion: Checking manifest +__package/subversion: Executing manifest +__package/libcurl4-openssl-dev: Preparing object +__package/libcurl4-openssl-dev: Checking manifest +__package/libcurl4-openssl-dev: Executing manifest +__package/bison: Preparing object +__package/bison: Checking manifest +__package/bison: Executing manifest +__package/cmake: Preparing object +__package/cmake: Checking manifest +__package/cmake: Executing manifest +__package/emacs: Preparing object +__package/emacs: Checking manifest +__package/emacs: Executing manifest +__package/xfce4: Preparing object +__package/xfce4: Checking manifest +__package/xfce4: Executing manifest +__package/xterm: Preparing object +__package/xterm: Checking manifest +__package/xterm: Executing manifest +__package/tcl8.4-dev: Preparing object +__package/tcl8.4-dev: Checking manifest +__package/tcl8.4-dev: Executing manifest +__package/libio-socket-ssl-perl: Preparing object +__package/libio-socket-ssl-perl: Checking manifest +__package/libio-socket-ssl-perl: Executing manifest +__package/doxygen: Preparing object +__package/doxygen: Checking manifest +__package/doxygen: Executing manifest +__package/zlib1g-dev: Preparing object +__package/zlib1g-dev: Checking manifest +__package/zlib1g-dev: Executing manifest +__package/autoconf: Preparing object +__package/autoconf: Checking manifest +__package/autoconf: Executing manifest +__package/libtool: Preparing object +__package/libtool: Checking manifest +__package/libtool: Executing manifest +__package/syslog-ng: Preparing object +__package/syslog-ng: Checking manifest +__package/syslog-ng: Executing manifest +__package/traceroute-nanog: Preparing object +__package/traceroute-nanog: Checking manifest +__package/traceroute-nanog: Executing manifest +__package/libncurses5-dev: Preparing object +__package/libncurses5-dev: Checking manifest +__package/libncurses5-dev: Executing manifest +__package/libaio-dev: Preparing object +__package/libaio-dev: Checking manifest +__package/libaio-dev: Executing manifest +__package/libboost-dev: Preparing object +__package/libboost-dev: Checking manifest +__package/libboost-dev: Executing manifest +__package/xtightvncviewer: Preparing object +__package/xtightvncviewer: Checking manifest +__package/xtightvncviewer: Executing manifest +__package/nullmailer: Preparing object +__package/nullmailer: Checking manifest +__package/nullmailer: Executing manifest +__package/libxml2-dev: Preparing object +__package/libxml2-dev: Checking manifest +__package/libxml2-dev: Executing manifest +__package/libtidy-dev: Preparing object +__package/libtidy-dev: Checking manifest +__package/libtidy-dev: Executing manifest +__package/manpages: Preparing object +__package/manpages: Checking manifest +__package/manpages: Executing manifest +__package/gcc-doc: Preparing object +__package/gcc-doc: Checking manifest +__package/gcc-doc: Executing manifest +__package/fluxbox: Preparing object +__package/fluxbox: Checking manifest +__package/fluxbox: Executing manifest +__package/libicu-dev: Preparing object +__package/libicu-dev: Checking manifest +__package/libicu-dev: Executing manifest +__package/libc6-dev-i386: Preparing object +__package/libc6-dev-i386: Checking manifest +__package/libc6-dev-i386: Executing manifest +__package/mercurial: Preparing object +__package/mercurial: Checking manifest +__package/mercurial: Executing manifest +__package/git-doc: Preparing object +__package/git-doc: Checking manifest +__package/git-doc: Executing manifest +__package/git-svn: Preparing object +__package/git-svn: Checking manifest +__package/git-svn: Executing manifest +__package/libnuma-dev: Preparing object +__package/libnuma-dev: Checking manifest +__package/libnuma-dev: Executing manifest +__package/gnuplot: Preparing object +__package/gnuplot: Checking manifest +__package/gnuplot: Executing manifest +__package/screen: Preparing object +__package/screen: Checking manifest +__package/screen: Executing manifest +__package/openntpd: Preparing object +__package/openntpd: Checking manifest +__package/openntpd: Executing manifest +__package/gcc-multilib: Preparing object +__package/gcc-multilib: Checking manifest +__package/gcc-multilib: Executing manifest +__package/libboost-regex-dev: Preparing object +__package/libboost-regex-dev: Checking manifest +__package/libboost-regex-dev: Executing manifest +__package/g++-multilib: Preparing object +__package/g++-multilib: Checking manifest +__package/g++-multilib: Executing manifest +__package/xfonts-base: Preparing object +__package/xfonts-base: Checking manifest +__package/xfonts-base: Executing manifest +__package/rdesktop: Preparing object +__package/rdesktop: Checking manifest +__package/rdesktop: Executing manifest +__package/build-essential: Preparing object +__package/build-essential: Checking manifest +__package/build-essential: Executing manifest +__package/tightvncserver: Preparing object +__package/tightvncserver: Checking manifest +__package/tightvncserver: Executing manifest +__package/python-crypto: Preparing object +__package/python-crypto: Checking manifest +__package/python-crypto: Executing manifest +__package/libc6-dev: Preparing object +__package/libc6-dev: Checking manifest +__package/libc6-dev: Executing manifest +__package/manpages-dev: Preparing object +__package/manpages-dev: Checking manifest +__package/manpages-dev: Executing manifest +__package/ia32-libs: Preparing object +__package/ia32-libs: Checking manifest +__package/ia32-libs: Executing manifest +__package/libxml-checker-perl: Preparing object +__package/libxml-checker-perl: Checking manifest +__package/libxml-checker-perl: Executing manifest +__ethz_pam_krb5/singleton: Preparing object +__ethz_pam_krb5/singleton: Checking manifest +__ethz_pam_krb5/singleton: Executing manifest +__ethz_dinfk_autofs/singleton: Preparing object +__ethz_dinfk_autofs/singleton: Checking manifest +__ethz_dinfk_autofs/singleton: Executing manifest +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__ethz_dinfk_ldap/singleton: Preparing object +__ethz_dinfk_ldap/singleton: Checking manifest +__ethz_dinfk_ldap/singleton: Executing manifest +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__directory/etc/ethz/autofs: Preparing object +__directory/etc/ethz/autofs: Running explorers +__directory/etc/ethz/autofs: Checking manifest +__ethz_krb5/singleton: Preparing object +__ethz_krb5/singleton: Checking manifest +__ethz_krb5/singleton: Executing manifest +__package_apt/mc: Preparing object +__package_apt/mc: Running explorers +__package_apt/mc: Checking manifest +__package_apt/ant: Preparing object +__package_apt/ant: Running explorers +__package_apt/ant: Checking manifest +__package_apt/gcc: Preparing object +__package_apt/gcc: Running explorers +__package_apt/gcc: Checking manifest +__package_apt/gdb: Preparing object +__package_apt/gdb: Running explorers +__package_apt/gdb: Checking manifest +__package_apt/vim: Preparing object +__package_apt/vim: Running explorers +__package_apt/vim: Checking manifest +__package_apt/git-core: Preparing object +__package_apt/git-core: Running explorers +__package_apt/git-core: Checking manifest +__package_apt/atop: Preparing object +__package_apt/atop: Running explorers +__package_apt/atop: Checking manifest +__package_apt/flex: Preparing object +__package_apt/flex: Running explorers +__package_apt/flex: Checking manifest +__package_apt/gawk: Preparing object +__package_apt/gawk: Running explorers +__package_apt/gawk: Checking manifest +__package_apt/make: Preparing object +__package_apt/make: Running explorers +__package_apt/make: Checking manifest +__package_apt/sudo: Preparing object +__package_apt/sudo: Running explorers +__package_apt/sudo: Checking manifest +__package_apt/swig: Preparing object +__package_apt/swig: Running explorers +__package_apt/swig: Checking manifest +__package_apt/libreadline5-dev: Preparing object +__package_apt/libreadline5-dev: Running explorers +__package_apt/libreadline5-dev: Checking manifest +__package_apt/libexpat1-dev: Preparing object +__package_apt/libexpat1-dev: Running explorers +__package_apt/libexpat1-dev: Checking manifest +__package_apt/libnet-ssleay-perl: Preparing object +__package_apt/libnet-ssleay-perl: Running explorers +__package_apt/libnet-ssleay-perl: Checking manifest +__package_apt/subversion: Preparing object +__package_apt/subversion: Running explorers +__package_apt/subversion: Checking manifest +__package_apt/libcurl4-openssl-dev: Preparing object +__package_apt/libcurl4-openssl-dev: Running explorers +__package_apt/libcurl4-openssl-dev: Checking manifest +__package_apt/bison: Preparing object +__package_apt/bison: Running explorers +__package_apt/bison: Checking manifest +__package_apt/cmake: Preparing object +__package_apt/cmake: Running explorers +__package_apt/cmake: Checking manifest +__package_apt/emacs: Preparing object +__package_apt/emacs: Running explorers +__package_apt/emacs: Checking manifest +__package_apt/xfce4: Preparing object +__package_apt/xfce4: Running explorers +__package_apt/xfce4: Checking manifest +__package_apt/xterm: Preparing object +__package_apt/xterm: Running explorers +__package_apt/xterm: Checking manifest +__package_apt/tcl8.4-dev: Preparing object +__package_apt/tcl8.4-dev: Running explorers +__package_apt/tcl8.4-dev: Checking manifest +__package_apt/libio-socket-ssl-perl: Preparing object +__package_apt/libio-socket-ssl-perl: Running explorers +__package_apt/libio-socket-ssl-perl: Checking manifest +__package_apt/doxygen: Preparing object +__package_apt/doxygen: Running explorers +__package_apt/doxygen: Checking manifest +__package_apt/zlib1g-dev: Preparing object +__package_apt/zlib1g-dev: Running explorers +__package_apt/zlib1g-dev: Checking manifest +__package_apt/autoconf: Preparing object +__package_apt/autoconf: Running explorers +__package_apt/autoconf: Checking manifest +__package_apt/libtool: Preparing object +__package_apt/libtool: Running explorers +__package_apt/libtool: Checking manifest +__package_apt/syslog-ng: Preparing object +__package_apt/syslog-ng: Running explorers +__package_apt/syslog-ng: Checking manifest +__package_apt/traceroute-nanog: Preparing object +__package_apt/traceroute-nanog: Running explorers +__package_apt/traceroute-nanog: Checking manifest +__package_apt/libncurses5-dev: Preparing object +__package_apt/libncurses5-dev: Running explorers +__package_apt/libncurses5-dev: Checking manifest +__package_apt/libaio-dev: Preparing object +__package_apt/libaio-dev: Running explorers +__package_apt/libaio-dev: Checking manifest +__package_apt/libboost-dev: Preparing object +__package_apt/libboost-dev: Running explorers +__package_apt/libboost-dev: Checking manifest +__package_apt/xtightvncviewer: Preparing object +__package_apt/xtightvncviewer: Running explorers +__package_apt/xtightvncviewer: Checking manifest +__package_apt/nullmailer: Preparing object +__package_apt/nullmailer: Running explorers +__package_apt/nullmailer: Checking manifest +__package_apt/libxml2-dev: Preparing object +__package_apt/libxml2-dev: Running explorers +__package_apt/libxml2-dev: Checking manifest +__package_apt/libtidy-dev: Preparing object +__package_apt/libtidy-dev: Running explorers +__package_apt/libtidy-dev: Checking manifest +__package_apt/manpages: Preparing object +__package_apt/manpages: Running explorers +__package_apt/manpages: Checking manifest +__package_apt/gcc-doc: Preparing object +__package_apt/gcc-doc: Running explorers +__package_apt/gcc-doc: Checking manifest +__package_apt/fluxbox: Preparing object +__package_apt/fluxbox: Running explorers +__package_apt/fluxbox: Checking manifest +__package_apt/libicu-dev: Preparing object +__package_apt/libicu-dev: Running explorers +__package_apt/libicu-dev: Checking manifest +__package_apt/libc6-dev-i386: Preparing object +__package_apt/libc6-dev-i386: Running explorers +__package_apt/libc6-dev-i386: Checking manifest +__package_apt/mercurial: Preparing object +__package_apt/mercurial: Running explorers +__package_apt/mercurial: Checking manifest +__package_apt/git-doc: Preparing object +__package_apt/git-doc: Running explorers +__package_apt/git-doc: Checking manifest +__package_apt/git-svn: Preparing object +__package_apt/git-svn: Running explorers +__package_apt/git-svn: Checking manifest +__package_apt/libnuma-dev: Preparing object +__package_apt/libnuma-dev: Running explorers +__package_apt/libnuma-dev: Checking manifest +__package_apt/gnuplot: Preparing object +__package_apt/gnuplot: Running explorers +__package_apt/gnuplot: Checking manifest +__package_apt/screen: Preparing object +__package_apt/screen: Running explorers +__package_apt/screen: Checking manifest +__package_apt/openntpd: Preparing object +__package_apt/openntpd: Running explorers +__package_apt/openntpd: Checking manifest +__package_apt/gcc-multilib: Preparing object +__package_apt/gcc-multilib: Running explorers +__package_apt/gcc-multilib: Checking manifest +__package_apt/libboost-regex-dev: Preparing object +__package_apt/libboost-regex-dev: Running explorers +__package_apt/libboost-regex-dev: Checking manifest +__package_apt/g++-multilib: Preparing object +__package_apt/g++-multilib: Running explorers +__package_apt/g++-multilib: Checking manifest +__package_apt/xfonts-base: Preparing object +__package_apt/xfonts-base: Running explorers +__package_apt/xfonts-base: Checking manifest +__package_apt/rdesktop: Preparing object +__package_apt/rdesktop: Running explorers +__package_apt/rdesktop: Checking manifest +__package_apt/build-essential: Preparing object +__package_apt/build-essential: Running explorers +__package_apt/build-essential: Checking manifest +__package_apt/tightvncserver: Preparing object +__package_apt/tightvncserver: Running explorers +__package_apt/tightvncserver: Checking manifest +__package_apt/python-crypto: Preparing object +__package_apt/python-crypto: Running explorers +__package_apt/python-crypto: Checking manifest +__package_apt/libc6-dev: Preparing object +__package_apt/libc6-dev: Running explorers +__package_apt/libc6-dev: Checking manifest +__package_apt/manpages-dev: Preparing object +__package_apt/manpages-dev: Running explorers +__package_apt/manpages-dev: Checking manifest +__package_apt/ia32-libs: Preparing object +__package_apt/ia32-libs: Running explorers +__package_apt/ia32-libs: Checking manifest +__package_apt/libxml-checker-perl: Preparing object +__package_apt/libxml-checker-perl: Running explorers +__package_apt/libxml-checker-perl: Checking manifest +__file/etc/nsswitch.conf: Preparing object +__file/etc/nsswitch.conf: Running explorers +__file/etc/nsswitch.conf: Checking manifest +__file/etc/ethz/autofs/auto_home: Preparing object +__file/etc/ethz/autofs/auto_home: Running explorers +__file/etc/ethz/autofs/auto_home: Checking manifest +__file/etc/auto.master: Preparing object +__file/etc/auto.master: Running explorers +__file/etc/auto.master: Checking manifest +__file/etc/motd.tail: Preparing object +__file/etc/motd.tail: Running explorers +__file/etc/motd.tail: Checking manifest +__file/etc/nslcd.conf: Preparing object +__file/etc/nslcd.conf: Running explorers +__file/etc/nslcd.conf: Checking manifest +__package/python-ldap: Preparing object +__package/python-ldap: Checking manifest +__package/python-ldap: Executing manifest +__package/libnss-ldapd: Preparing object +__package/libnss-ldapd: Checking manifest +__package/libnss-ldapd: Executing manifest +__package/autofs: Preparing object +__package/autofs: Checking manifest +__package/autofs: Executing manifest +__package/libpam-krb5: Preparing object +__package/libpam-krb5: Checking manifest +__package/libpam-krb5: Executing manifest +__package_apt/python-ldap: Preparing object +__package_apt/python-ldap: Running explorers +__package_apt/python-ldap: Checking manifest +__package_apt/libnss-ldapd: Preparing object +__package_apt/libnss-ldapd: Running explorers +__package_apt/libnss-ldapd: Checking manifest +__package_apt/autofs: Preparing object +__package_apt/autofs: Running explorers +__package_apt/autofs: Checking manifest +__package_apt/libpam-krb5: Preparing object +__package_apt/libpam-krb5: Running explorers +__package_apt/libpam-krb5: Checking manifest +__file/etc/krb5.conf: Preparing object +__file/etc/krb5.conf: Running explorers +__file/etc/krb5.conf: Checking manifest +core: Debug: Mit Apr 27 14:18:44 CEST 2011 +__ethz_nullmailer/singleton: Generating local code +__ethz_nullmailer/singleton: Generating remote code +__ethz_nullmailer/singleton: Transferring object +__ethz_nullmailer/singleton: Checking code-local +__ethz_nullmailer/singleton: Executing code-local +__ethz_nullmailer/singleton: Checking code-remote +__ethz_nullmailer/singleton: Executing code-remote +__ethz_systems_ldap_krb5_autofs/singleton: Generating local code +__ethz_systems_ldap_krb5_autofs/singleton: Generating remote code +__ethz_systems_ldap_krb5_autofs/singleton: Transferring object +__ethz_systems_ldap_krb5_autofs/singleton: Checking code-local +__ethz_systems_ldap_krb5_autofs/singleton: Executing code-local +__ethz_systems_ldap_krb5_autofs/singleton: Checking code-remote +__ethz_systems_ldap_krb5_autofs/singleton: Executing code-remote +__etc_hosts/singleton: Generating local code +__etc_hosts/singleton: Generating remote code +__etc_hosts/singleton: Transferring object +__etc_hosts/singleton: Checking code-local +__etc_hosts/singleton: Executing code-local +__etc_hosts/singleton: Checking code-remote +__etc_hosts/singleton: Executing code-remote +__directory/etc/ethz/autofs: Generating local code +__directory/etc/ethz/autofs: Generating remote code +__directory/etc/ethz/autofs: Transferring object +__directory/etc/ethz/autofs: Checking code-local +__directory/etc/ethz/autofs: Executing code-local +__directory/etc/ethz/autofs: Checking code-remote +__directory/etc/ethz/autofs: Executing code-remote +__directory/local: Generating local code +__directory/local: Generating remote code +__directory/local: Transferring object +__directory/local: Checking code-local +__directory/local: Executing code-local +__directory/local: Checking code-remote +__directory/local: Executing code-remote +__ethz_krb5/singleton: Generating local code +__ethz_krb5/singleton: Generating remote code +__ethz_krb5/singleton: Transferring object +__ethz_krb5/singleton: Checking code-local +__ethz_krb5/singleton: Executing code-local +__ethz_krb5/singleton: Checking code-remote +__ethz_krb5/singleton: Executing code-remote +__ethz_ntpd/singleton: Generating local code +__ethz_ntpd/singleton: Generating remote code +__ethz_ntpd/singleton: Transferring object +__ethz_ntpd/singleton: Checking code-local +__ethz_ntpd/singleton: Executing code-local +__ethz_ntpd/singleton: Checking code-remote +__ethz_ntpd/singleton: Executing code-remote +__ethz_systems_packages/singleton: Generating local code +__ethz_systems_packages/singleton: Generating remote code +__ethz_systems_packages/singleton: Transferring object +__ethz_systems_packages/singleton: Checking code-local +__ethz_systems_packages/singleton: Executing code-local +__ethz_systems_packages/singleton: Checking code-remote +__ethz_systems_packages/singleton: Executing code-remote +__package_apt/mc: Generating local code +__package_apt/mc: Generating remote code +__package_apt/mc: Transferring object +__package_apt/mc: Checking code-local +__package_apt/mc: Executing code-local +__package_apt/mc: Checking code-remote +__package_apt/mc: Executing code-remote +__package_apt/ant: Generating local code +__package_apt/ant: Generating remote code +__package_apt/ant: Transferring object +__package_apt/ant: Checking code-local +__package_apt/ant: Executing code-local +__package_apt/ant: Checking code-remote +__package_apt/ant: Executing code-remote +__package_apt/gcc: Generating local code +__package_apt/gcc: Generating remote code +__package_apt/gcc: Transferring object +__package_apt/gcc: Checking code-local +__package_apt/gcc: Executing code-local +__package_apt/gcc: Checking code-remote +__package_apt/gcc: Executing code-remote +__package_apt/gdb: Generating local code +__package_apt/gdb: Generating remote code +__package_apt/gdb: Transferring object +__package_apt/gdb: Checking code-local +__package_apt/gdb: Executing code-local +__package_apt/gdb: Checking code-remote +__package_apt/gdb: Executing code-remote +__package_apt/vim: Generating local code +__package_apt/vim: Generating remote code +__package_apt/vim: Transferring object +__package_apt/vim: Checking code-local +__package_apt/vim: Executing code-local +__package_apt/vim: Checking code-remote +__package_apt/vim: Executing code-remote +__package_apt/git-core: Generating local code +__package_apt/git-core: Generating remote code +__package_apt/git-core: Transferring object +__package_apt/git-core: Checking code-local +__package_apt/git-core: Executing code-local +__package_apt/git-core: Checking code-remote +__package_apt/git-core: Executing code-remote +__package_apt/atop: Generating local code +__package_apt/atop: Generating remote code +__package_apt/atop: Transferring object +__package_apt/atop: Checking code-local +__package_apt/atop: Executing code-local +__package_apt/atop: Checking code-remote +__package_apt/atop: Executing code-remote +__package_apt/flex: Generating local code +__package_apt/flex: Generating remote code +__package_apt/flex: Transferring object +__package_apt/flex: Checking code-local +__package_apt/flex: Executing code-local +__package_apt/flex: Checking code-remote +__package_apt/flex: Executing code-remote +__package_apt/gawk: Generating local code +__package_apt/gawk: Generating remote code +__package_apt/gawk: Transferring object +__package_apt/gawk: Checking code-local +__package_apt/gawk: Executing code-local +__package_apt/gawk: Checking code-remote +__package_apt/gawk: Executing code-remote +__package_apt/make: Generating local code +__package_apt/make: Generating remote code +__package_apt/make: Transferring object +__package_apt/make: Checking code-local +__package_apt/make: Executing code-local +__package_apt/make: Checking code-remote +__package_apt/make: Executing code-remote +__package_apt/sudo: Generating local code +__package_apt/sudo: Generating remote code +__package_apt/sudo: Transferring object +__package_apt/sudo: Checking code-local +__package_apt/sudo: Executing code-local +__package_apt/sudo: Checking code-remote +__package_apt/sudo: Executing code-remote +__package_apt/swig: Generating local code +__package_apt/swig: Generating remote code +__package_apt/swig: Transferring object +__package_apt/swig: Checking code-local +__package_apt/swig: Executing code-local +__package_apt/swig: Checking code-remote +__package_apt/swig: Executing code-remote +__package_apt/libreadline5-dev: Generating local code +__package_apt/libreadline5-dev: Generating remote code +__package_apt/libreadline5-dev: Transferring object +__package_apt/libreadline5-dev: Checking code-local +__package_apt/libreadline5-dev: Executing code-local +__package_apt/libreadline5-dev: Checking code-remote +__package_apt/libreadline5-dev: Executing code-remote +__package_apt/libexpat1-dev: Generating local code +__package_apt/libexpat1-dev: Generating remote code +__package_apt/libexpat1-dev: Transferring object +__package_apt/libexpat1-dev: Checking code-local +__package_apt/libexpat1-dev: Executing code-local +__package_apt/libexpat1-dev: Checking code-remote +__package_apt/libexpat1-dev: Executing code-remote +__package_apt/libnet-ssleay-perl: Generating local code +__package_apt/libnet-ssleay-perl: Generating remote code +__package_apt/libnet-ssleay-perl: Transferring object +__package_apt/libnet-ssleay-perl: Checking code-local +__package_apt/libnet-ssleay-perl: Executing code-local +__package_apt/libnet-ssleay-perl: Checking code-remote +__package_apt/libnet-ssleay-perl: Executing code-remote +__package_apt/subversion: Generating local code +__package_apt/subversion: Generating remote code +__package_apt/subversion: Transferring object +__package_apt/subversion: Checking code-local +__package_apt/subversion: Executing code-local +__package_apt/subversion: Checking code-remote +__package_apt/subversion: Executing code-remote +__package_apt/libcurl4-openssl-dev: Generating local code +__package_apt/libcurl4-openssl-dev: Generating remote code +__package_apt/libcurl4-openssl-dev: Transferring object +__package_apt/libcurl4-openssl-dev: Checking code-local +__package_apt/libcurl4-openssl-dev: Executing code-local +__package_apt/libcurl4-openssl-dev: Checking code-remote +__package_apt/libcurl4-openssl-dev: Executing code-remote +__package_apt/bison: Generating local code +__package_apt/bison: Generating remote code +__package_apt/bison: Transferring object +__package_apt/bison: Checking code-local +__package_apt/bison: Executing code-local +__package_apt/bison: Checking code-remote +__package_apt/bison: Executing code-remote +__package_apt/cmake: Generating local code +__package_apt/cmake: Generating remote code +__package_apt/cmake: Transferring object +__package_apt/cmake: Checking code-local +__package_apt/cmake: Executing code-local +__package_apt/cmake: Checking code-remote +__package_apt/cmake: Executing code-remote +__package_apt/emacs: Generating local code +__package_apt/emacs: Generating remote code +__package_apt/emacs: Transferring object +__package_apt/emacs: Checking code-local +__package_apt/emacs: Executing code-local +__package_apt/emacs: Checking code-remote +__package_apt/emacs: Executing code-remote +__package_apt/xfce4: Generating local code +__package_apt/xfce4: Generating remote code +__package_apt/xfce4: Transferring object +__package_apt/xfce4: Checking code-local +__package_apt/xfce4: Executing code-local +__package_apt/xfce4: Checking code-remote +__package_apt/xfce4: Executing code-remote +__package_apt/xterm: Generating local code +__package_apt/xterm: Generating remote code +__package_apt/xterm: Transferring object +__package_apt/xterm: Checking code-local +__package_apt/xterm: Executing code-local +__package_apt/xterm: Checking code-remote +__package_apt/xterm: Executing code-remote +__package_apt/tcl8.4-dev: Generating local code +__package_apt/tcl8.4-dev: Generating remote code +__package_apt/tcl8.4-dev: Transferring object +__package_apt/tcl8.4-dev: Checking code-local +__package_apt/tcl8.4-dev: Executing code-local +__package_apt/tcl8.4-dev: Checking code-remote +__package_apt/tcl8.4-dev: Executing code-remote +__package_apt/libio-socket-ssl-perl: Generating local code +__package_apt/libio-socket-ssl-perl: Generating remote code +__package_apt/libio-socket-ssl-perl: Transferring object +__package_apt/libio-socket-ssl-perl: Checking code-local +__package_apt/libio-socket-ssl-perl: Executing code-local +__package_apt/libio-socket-ssl-perl: Checking code-remote +__package_apt/libio-socket-ssl-perl: Executing code-remote +__package_apt/doxygen: Generating local code +__package_apt/doxygen: Generating remote code +__package_apt/doxygen: Transferring object +__package_apt/doxygen: Checking code-local +__package_apt/doxygen: Executing code-local +__package_apt/doxygen: Checking code-remote +__package_apt/doxygen: Executing code-remote +__package_apt/zlib1g-dev: Generating local code +__package_apt/zlib1g-dev: Generating remote code +__package_apt/zlib1g-dev: Transferring object +__package_apt/zlib1g-dev: Checking code-local +__package_apt/zlib1g-dev: Executing code-local +__package_apt/zlib1g-dev: Checking code-remote +__package_apt/zlib1g-dev: Executing code-remote +__package_apt/autoconf: Generating local code +__package_apt/autoconf: Generating remote code +__package_apt/autoconf: Transferring object +__package_apt/autoconf: Checking code-local +__package_apt/autoconf: Executing code-local +__package_apt/autoconf: Checking code-remote +__package_apt/autoconf: Executing code-remote +__package_apt/python-ldap: Generating local code +__package_apt/python-ldap: Generating remote code +__package_apt/python-ldap: Transferring object +__package_apt/python-ldap: Checking code-local +__package_apt/python-ldap: Executing code-local +__package_apt/python-ldap: Checking code-remote +__package_apt/python-ldap: Executing code-remote +__package_apt/libtool: Generating local code +__package_apt/libtool: Generating remote code +__package_apt/libtool: Transferring object +__package_apt/libtool: Checking code-local +__package_apt/libtool: Executing code-local +__package_apt/libtool: Checking code-remote +__package_apt/libtool: Executing code-remote +__package_apt/syslog-ng: Generating local code +__package_apt/syslog-ng: Generating remote code +__package_apt/syslog-ng: Transferring object +__package_apt/syslog-ng: Checking code-local +__package_apt/syslog-ng: Executing code-local +__package_apt/syslog-ng: Checking code-remote +__package_apt/syslog-ng: Executing code-remote +__package_apt/traceroute-nanog: Generating local code +__package_apt/traceroute-nanog: Generating remote code +__package_apt/traceroute-nanog: Transferring object +__package_apt/traceroute-nanog: Checking code-local +__package_apt/traceroute-nanog: Executing code-local +__package_apt/traceroute-nanog: Checking code-remote +__package_apt/traceroute-nanog: Executing code-remote +__package_apt/libnss-ldapd: Generating local code +__package_apt/libnss-ldapd: Generating remote code +__package_apt/libnss-ldapd: Transferring object +__package_apt/libnss-ldapd: Checking code-local +__package_apt/libnss-ldapd: Executing code-local +__package_apt/libnss-ldapd: Checking code-remote +__package_apt/libnss-ldapd: Executing code-remote +__package_apt/libncurses5-dev: Generating local code +__package_apt/libncurses5-dev: Generating remote code +__package_apt/libncurses5-dev: Transferring object +__package_apt/libncurses5-dev: Checking code-local +__package_apt/libncurses5-dev: Executing code-local +__package_apt/libncurses5-dev: Checking code-remote +__package_apt/libncurses5-dev: Executing code-remote +__package_apt/libaio-dev: Generating local code +__package_apt/libaio-dev: Generating remote code +__package_apt/libaio-dev: Transferring object +__package_apt/libaio-dev: Checking code-local +__package_apt/libaio-dev: Executing code-local +__package_apt/libaio-dev: Checking code-remote +__package_apt/libaio-dev: Executing code-remote +__package_apt/libboost-dev: Generating local code +__package_apt/libboost-dev: Generating remote code +__package_apt/libboost-dev: Transferring object +__package_apt/libboost-dev: Checking code-local +__package_apt/libboost-dev: Executing code-local +__package_apt/libboost-dev: Checking code-remote +__package_apt/libboost-dev: Executing code-remote +__package_apt/xtightvncviewer: Generating local code +__package_apt/xtightvncviewer: Generating remote code +__package_apt/xtightvncviewer: Transferring object +__package_apt/xtightvncviewer: Checking code-local +__package_apt/xtightvncviewer: Executing code-local +__package_apt/xtightvncviewer: Checking code-remote +__package_apt/xtightvncviewer: Executing code-remote +__package_apt/nullmailer: Generating local code +__package_apt/nullmailer: Generating remote code +__package_apt/nullmailer: Transferring object +__package_apt/nullmailer: Checking code-local +__package_apt/nullmailer: Executing code-local +__package_apt/nullmailer: Checking code-remote +__package_apt/nullmailer: Executing code-remote +__package_apt/libxml2-dev: Generating local code +__package_apt/libxml2-dev: Generating remote code +__package_apt/libxml2-dev: Transferring object +__package_apt/libxml2-dev: Checking code-local +__package_apt/libxml2-dev: Executing code-local +__package_apt/libxml2-dev: Checking code-remote +__package_apt/libxml2-dev: Executing code-remote +__package_apt/libtidy-dev: Generating local code +__package_apt/libtidy-dev: Generating remote code +__package_apt/libtidy-dev: Transferring object +__package_apt/libtidy-dev: Checking code-local +__package_apt/libtidy-dev: Executing code-local +__package_apt/libtidy-dev: Checking code-remote +__package_apt/libtidy-dev: Executing code-remote +__package_apt/manpages: Generating local code +__package_apt/manpages: Generating remote code +__package_apt/manpages: Transferring object +__package_apt/manpages: Checking code-local +__package_apt/manpages: Executing code-local +__package_apt/manpages: Checking code-remote +__package_apt/manpages: Executing code-remote +__package_apt/autofs: Generating local code +__package_apt/autofs: Generating remote code +__package_apt/autofs: Transferring object +__package_apt/autofs: Checking code-local +__package_apt/autofs: Executing code-local +__package_apt/autofs: Checking code-remote +__package_apt/autofs: Executing code-remote +__package_apt/gcc-doc: Generating local code +__package_apt/gcc-doc: Generating remote code +__package_apt/gcc-doc: Transferring object +__package_apt/gcc-doc: Checking code-local +__package_apt/gcc-doc: Executing code-local +__package_apt/gcc-doc: Checking code-remote +__package_apt/gcc-doc: Executing code-remote +__package_apt/fluxbox: Generating local code +__package_apt/fluxbox: Generating remote code +__package_apt/fluxbox: Transferring object +__package_apt/fluxbox: Checking code-local +__package_apt/fluxbox: Executing code-local +__package_apt/fluxbox: Checking code-remote +__package_apt/fluxbox: Executing code-remote +__package_apt/libicu-dev: Generating local code +__package_apt/libicu-dev: Generating remote code +__package_apt/libicu-dev: Transferring object +__package_apt/libicu-dev: Checking code-local +__package_apt/libicu-dev: Executing code-local +__package_apt/libicu-dev: Checking code-remote +__package_apt/libicu-dev: Executing code-remote +__package_apt/libc6-dev-i386: Generating local code +__package_apt/libc6-dev-i386: Generating remote code +__package_apt/libc6-dev-i386: Transferring object +__package_apt/libc6-dev-i386: Checking code-local +__package_apt/libc6-dev-i386: Executing code-local +__package_apt/libc6-dev-i386: Checking code-remote +__package_apt/libc6-dev-i386: Executing code-remote +__package_apt/mercurial: Generating local code +__package_apt/mercurial: Generating remote code +__package_apt/mercurial: Transferring object +__package_apt/mercurial: Checking code-local +__package_apt/mercurial: Executing code-local +__package_apt/mercurial: Checking code-remote +__package_apt/mercurial: Executing code-remote +__package_apt/git-doc: Generating local code +__package_apt/git-doc: Generating remote code +__package_apt/git-doc: Transferring object +__package_apt/git-doc: Checking code-local +__package_apt/git-doc: Executing code-local +__package_apt/git-doc: Checking code-remote +__package_apt/git-doc: Executing code-remote +__package_apt/git-svn: Generating local code +__package_apt/git-svn: Generating remote code +__package_apt/git-svn: Transferring object +__package_apt/git-svn: Checking code-local +__package_apt/git-svn: Executing code-local +__package_apt/git-svn: Checking code-remote +__package_apt/git-svn: Executing code-remote +__package_apt/libnuma-dev: Generating local code +__package_apt/libnuma-dev: Generating remote code +__package_apt/libnuma-dev: Transferring object +__package_apt/libnuma-dev: Checking code-local +__package_apt/libnuma-dev: Executing code-local +__package_apt/libnuma-dev: Checking code-remote +__package_apt/libnuma-dev: Executing code-remote +__package_apt/gnuplot: Generating local code +__package_apt/gnuplot: Generating remote code +__package_apt/gnuplot: Transferring object +__package_apt/gnuplot: Checking code-local +__package_apt/gnuplot: Executing code-local +__package_apt/gnuplot: Checking code-remote +__package_apt/gnuplot: Executing code-remote +__package_apt/puppet: Generating local code +__package_apt/puppet: Generating remote code +__package_apt/puppet: Transferring object +__package_apt/puppet: Checking code-local +__package_apt/puppet: Executing code-local +__package_apt/puppet: Checking code-remote +__package_apt/puppet: Executing code-remote +__package_apt/screen: Generating local code +__package_apt/screen: Generating remote code +__package_apt/screen: Transferring object +__package_apt/screen: Checking code-local +__package_apt/screen: Executing code-local +__package_apt/screen: Checking code-remote +__package_apt/screen: Executing code-remote +__package_apt/openntpd: Generating local code +__package_apt/openntpd: Generating remote code +__package_apt/openntpd: Transferring object +__package_apt/openntpd: Checking code-local +__package_apt/openntpd: Executing code-local +__package_apt/openntpd: Checking code-remote +__package_apt/openntpd: Executing code-remote +__package_apt/gcc-multilib: Generating local code +__package_apt/gcc-multilib: Generating remote code +__package_apt/gcc-multilib: Transferring object +__package_apt/gcc-multilib: Checking code-local +__package_apt/gcc-multilib: Executing code-local +__package_apt/gcc-multilib: Checking code-remote +__package_apt/gcc-multilib: Executing code-remote +__package_apt/libboost-regex-dev: Generating local code +__package_apt/libboost-regex-dev: Generating remote code +__package_apt/libboost-regex-dev: Transferring object +__package_apt/libboost-regex-dev: Checking code-local +__package_apt/libboost-regex-dev: Executing code-local +__package_apt/libboost-regex-dev: Checking code-remote +__package_apt/libboost-regex-dev: Executing code-remote +__package_apt/g++-multilib: Generating local code +__package_apt/g++-multilib: Generating remote code +__package_apt/g++-multilib: Transferring object +__package_apt/g++-multilib: Checking code-local +__package_apt/g++-multilib: Executing code-local +__package_apt/g++-multilib: Checking code-remote +__package_apt/g++-multilib: Executing code-remote +__package_apt/xfonts-base: Generating local code +__package_apt/xfonts-base: Generating remote code +__package_apt/xfonts-base: Transferring object +__package_apt/xfonts-base: Checking code-local +__package_apt/xfonts-base: Executing code-local +__package_apt/xfonts-base: Checking code-remote +__package_apt/xfonts-base: Executing code-remote +__package_apt/rdesktop: Generating local code +__package_apt/rdesktop: Generating remote code +__package_apt/rdesktop: Transferring object +__package_apt/rdesktop: Checking code-local +__package_apt/rdesktop: Executing code-local +__package_apt/rdesktop: Checking code-remote +__package_apt/rdesktop: Executing code-remote +__package_apt/build-essential: Generating local code +__package_apt/build-essential: Generating remote code +__package_apt/build-essential: Transferring object +__package_apt/build-essential: Checking code-local +__package_apt/build-essential: Executing code-local +__package_apt/build-essential: Checking code-remote +__package_apt/build-essential: Executing code-remote +__package_apt/tightvncserver: Generating local code +__package_apt/tightvncserver: Generating remote code +__package_apt/tightvncserver: Transferring object +__package_apt/tightvncserver: Checking code-local +__package_apt/tightvncserver: Executing code-local +__package_apt/tightvncserver: Checking code-remote +__package_apt/tightvncserver: Executing code-remote +__package_apt/python-crypto: Generating local code +__package_apt/python-crypto: Generating remote code +__package_apt/python-crypto: Transferring object +__package_apt/python-crypto: Checking code-local +__package_apt/python-crypto: Executing code-local +__package_apt/python-crypto: Checking code-remote +__package_apt/python-crypto: Executing code-remote +__package_apt/libpam-krb5: Generating local code +__package_apt/libpam-krb5: Generating remote code +__package_apt/libpam-krb5: Transferring object +__package_apt/libpam-krb5: Checking code-local +__package_apt/libpam-krb5: Executing code-local +__package_apt/libpam-krb5: Checking code-remote +__package_apt/libpam-krb5: Executing code-remote +__package_apt/libc6-dev: Generating local code +__package_apt/libc6-dev: Generating remote code +__package_apt/libc6-dev: Transferring object +__package_apt/libc6-dev: Checking code-local +__package_apt/libc6-dev: Executing code-local +__package_apt/libc6-dev: Checking code-remote +__package_apt/libc6-dev: Executing code-remote +__package_apt/manpages-dev: Generating local code +__package_apt/manpages-dev: Generating remote code +__package_apt/manpages-dev: Transferring object +__package_apt/manpages-dev: Checking code-local +__package_apt/manpages-dev: Executing code-local +__package_apt/manpages-dev: Checking code-remote +__package_apt/manpages-dev: Executing code-remote +__package_apt/ia32-libs: Generating local code +__package_apt/ia32-libs: Generating remote code +__package_apt/ia32-libs: Transferring object +__package_apt/ia32-libs: Checking code-local +__package_apt/ia32-libs: Executing code-local +__package_apt/ia32-libs: Checking code-remote +__package_apt/ia32-libs: Executing code-remote +__package_apt/libxml-checker-perl: Generating local code +__package_apt/libxml-checker-perl: Generating remote code +__package_apt/libxml-checker-perl: Transferring object +__package_apt/libxml-checker-perl: Checking code-local +__package_apt/libxml-checker-perl: Executing code-local +__package_apt/libxml-checker-perl: Checking code-remote +__package_apt/libxml-checker-perl: Executing code-remote +__addifnosuchline/ssh-root-subasui: Generating local code +__addifnosuchline/ssh-root-subasui: Generating remote code +__addifnosuchline/ssh-root-subasui: Transferring object +__addifnosuchline/ssh-root-subasui: Checking code-local +__addifnosuchline/ssh-root-subasui: Executing code-local +__addifnosuchline/ssh-root-subasui: Checking code-remote +__addifnosuchline/ssh-root-subasui: Executing code-remote +__addifnosuchline/ssh-root-blukas: Generating local code +__addifnosuchline/ssh-root-blukas: Generating remote code +__addifnosuchline/ssh-root-blukas: Transferring object +__addifnosuchline/ssh-root-blukas: Checking code-local +__addifnosuchline/ssh-root-blukas: Executing code-local +__addifnosuchline/ssh-root-blukas: Checking code-remote +__addifnosuchline/ssh-root-blukas: Executing code-remote +__addifnosuchline/ssh-root-petfisch: Generating local code +__addifnosuchline/ssh-root-petfisch: Generating remote code +__addifnosuchline/ssh-root-petfisch: Transferring object +__addifnosuchline/ssh-root-petfisch: Checking code-local +__addifnosuchline/ssh-root-petfisch: Executing code-local +__addifnosuchline/ssh-root-petfisch: Checking code-remote +__addifnosuchline/ssh-root-petfisch: Executing code-remote +__ethz_systems/singleton: Generating local code +__ethz_systems/singleton: Generating remote code +__ethz_systems/singleton: Transferring object +__ethz_systems/singleton: Checking code-local +__ethz_systems/singleton: Executing code-local +__ethz_systems/singleton: Checking code-remote +__ethz_systems/singleton: Executing code-remote +__file/etc/nsswitch.conf: Resolving requirement __package/libnss-ldapd +__package/libnss-ldapd: Generating local code +__package/libnss-ldapd: Generating remote code +__package/libnss-ldapd: Transferring object +__package/libnss-ldapd: Checking code-local +__package/libnss-ldapd: Executing code-local +__package/libnss-ldapd: Checking code-remote +__package/libnss-ldapd: Executing code-remote +__file/etc/nsswitch.conf: Resolving requirement __file//etc/nslcd.conf +__file//etc/nslcd.conf: Generating local code +__file//etc/nslcd.conf: Generating remote code +__file//etc/nslcd.conf: Transferring object +__file//etc/nslcd.conf: Checking code-local +__file//etc/nslcd.conf: Executing code-local +__file//etc/nslcd.conf: Checking code-remote +__file//etc/nslcd.conf: Executing code-remote +__file/etc/nsswitch.conf: Generating local code +__file/etc/nsswitch.conf: Generating remote code +__file/etc/nsswitch.conf: Transferring object +__file/etc/nsswitch.conf: Checking code-local +__file/etc/nsswitch.conf: Executing code-local +__file/etc/nsswitch.conf: Checking code-remote +__file/etc/nsswitch.conf: Executing code-remote +__file/etc/ethz/autofs/auto.pub: Resolving requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Generating local code +__file/etc/ethz/autofs/auto.pub: Generating remote code +__file/etc/ethz/autofs/auto.pub: Transferring object +__file/etc/ethz/autofs/auto.pub: Checking code-local +__file/etc/ethz/autofs/auto.pub: Executing code-local +__file/etc/ethz/autofs/auto.pub: Checking code-remote +__file/etc/ethz/autofs/auto.pub: Executing code-remote +__file/etc/ethz/autofs/auto_home: Resolving requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Resolving requirement __package/python-ldap +__package/python-ldap: Generating local code +__package/python-ldap: Generating remote code +__package/python-ldap: Transferring object +__package/python-ldap: Checking code-local +__package/python-ldap: Executing code-local +__package/python-ldap: Checking code-remote +__package/python-ldap: Executing code-remote +__file/etc/ethz/autofs/auto_home: Generating local code +__file/etc/ethz/autofs/auto_home: Generating remote code +__file/etc/ethz/autofs/auto_home: Transferring object +__file/etc/ethz/autofs/auto_home: Checking code-local +__file/etc/ethz/autofs/auto_home: Executing code-local +__file/etc/ethz/autofs/auto_home: Checking code-remote +__file/etc/ethz/autofs/auto_home: Executing code-remote +__file/etc/default/openntpd: Generating local code +__file/etc/default/openntpd: Generating remote code +__file/etc/default/openntpd: Transferring object +__file/etc/default/openntpd: Checking code-local +__file/etc/default/openntpd: Executing code-local +__file/etc/default/openntpd: Checking code-remote +__file/etc/default/openntpd: Executing code-remote +__file/etc/auto.master: Resolving requirement __package/autofs +__package/autofs: Generating local code +__package/autofs: Generating remote code +__package/autofs: Transferring object +__package/autofs: Checking code-local +__package/autofs: Executing code-local +__package/autofs: Checking code-remote +__package/autofs: Executing code-remote +__file/etc/auto.master: Generating local code +__file/etc/auto.master: Generating remote code +__file/etc/auto.master: Transferring object +__file/etc/auto.master: Checking code-local +__file/etc/auto.master: Executing code-local +__file/etc/auto.master: Checking code-remote +__file/etc/auto.master: Executing code-remote +__file/etc/hosts: Generating local code +__file/etc/hosts: Generating remote code +__file/etc/hosts: Transferring object +__file/etc/hosts: Checking code-local +__file/etc/hosts: Executing code-local +__file/etc/hosts: Checking code-remote +__file/etc/hosts: Executing code-remote +__file/etc/krb5.conf: Generating local code +__file/etc/krb5.conf: Generating remote code +__file/etc/krb5.conf: Transferring object +__file/etc/krb5.conf: Checking code-local +__file/etc/krb5.conf: Executing code-local +__file/etc/krb5.conf: Checking code-remote +__file/etc/krb5.conf: Executing code-remote +__file/etc/syslog-ng/syslog-ng.conf: Resolving requirement __package/syslog-ng +__package/syslog-ng: Generating local code +__package/syslog-ng: Generating remote code +__package/syslog-ng: Transferring object +__package/syslog-ng: Checking code-local +__package/syslog-ng: Executing code-local +__package/syslog-ng: Checking code-remote +__package/syslog-ng: Executing code-remote +__file/etc/syslog-ng/syslog-ng.conf: Generating local code +__file/etc/syslog-ng/syslog-ng.conf: Generating remote code +__file/etc/syslog-ng/syslog-ng.conf: Transferring object +__file/etc/syslog-ng/syslog-ng.conf: Checking code-local +__file/etc/syslog-ng/syslog-ng.conf: Executing code-local +__file/etc/syslog-ng/syslog-ng.conf: Checking code-remote +__file/etc/syslog-ng/syslog-ng.conf: Executing code-remote +__file/etc/nullmailer/remotes: Resolving requirement __package/nullmailer +__package/nullmailer: Generating local code +__package/nullmailer: Generating remote code +__package/nullmailer: Transferring object +__package/nullmailer: Checking code-local +__package/nullmailer: Executing code-local +__package/nullmailer: Checking code-remote +__package/nullmailer: Executing code-remote +__file/etc/nullmailer/remotes: Generating local code +__file/etc/nullmailer/remotes: Generating remote code +__file/etc/nullmailer/remotes: Transferring object +__file/etc/nullmailer/remotes: Checking code-local +__file/etc/nullmailer/remotes: Executing code-local +__file/etc/nullmailer/remotes: Checking code-remote +__file/etc/nullmailer/remotes: Executing code-remote +__file/etc/cdist-configured: Generating local code +__file/etc/cdist-configured: Generating remote code +__file/etc/cdist-configured: Transferring object +__file/etc/cdist-configured: Checking code-local +__file/etc/cdist-configured: Executing code-local +__file/etc/cdist-configured: Checking code-remote +__file/etc/cdist-configured: Executing code-remote +__file/etc/motd.tail: Generating local code +__file/etc/motd.tail: Generating remote code +__file/etc/motd.tail: Transferring object +__file/etc/motd.tail: Checking code-local +__file/etc/motd.tail: Executing code-local +__file/etc/motd.tail: Checking code-remote +__file/etc/motd.tail: Executing code-remote +__file/etc/openntpd/ntpd.conf: Generating local code +__file/etc/openntpd/ntpd.conf: Generating remote code +__file/etc/openntpd/ntpd.conf: Transferring object +__file/etc/openntpd/ntpd.conf: Checking code-local +__file/etc/openntpd/ntpd.conf: Executing code-local +__file/etc/openntpd/ntpd.conf: Checking code-remote +__file/etc/openntpd/ntpd.conf: Executing code-remote +__file/etc/sudoers.d/systems: Resolving requirement __package/sudo +__package/sudo: Generating local code +__package/sudo: Generating remote code +__package/sudo: Transferring object +__package/sudo: Checking code-local +__package/sudo: Executing code-local +__package/sudo: Checking code-remote +__package/sudo: Executing code-remote +__file/etc/sudoers.d/systems: Generating local code +__file/etc/sudoers.d/systems: Generating remote code +__file/etc/sudoers.d/systems: Transferring object +__file/etc/sudoers.d/systems: Checking code-local +__file/etc/sudoers.d/systems: Executing code-local +__file/etc/sudoers.d/systems: Checking code-remote +__file/etc/sudoers.d/systems: Executing code-remote +__link/etc/motd: Generating local code +__link/etc/motd: Generating remote code +__link/etc/motd: Transferring object +__link/etc/motd: Checking code-local +__link/etc/motd: Executing code-local +__link/etc/motd: Checking code-remote +__link/etc/motd: Executing code-remote +__motd/singleton: Generating local code +__motd/singleton: Generating remote code +__motd/singleton: Transferring object +__motd/singleton: Checking code-local +__motd/singleton: Executing code-local +__motd/singleton: Checking code-remote +__motd/singleton: Executing code-remote +__package/mc: Generating local code +__package/mc: Generating remote code +__package/mc: Transferring object +__package/mc: Checking code-local +__package/mc: Executing code-local +__package/mc: Checking code-remote +__package/mc: Executing code-remote +__package/ant: Generating local code +__package/ant: Generating remote code +__package/ant: Transferring object +__package/ant: Checking code-local +__package/ant: Executing code-local +__package/ant: Checking code-remote +__package/ant: Executing code-remote +__package/gcc: Generating local code +__package/gcc: Generating remote code +__package/gcc: Transferring object +__package/gcc: Checking code-local +__package/gcc: Executing code-local +__package/gcc: Checking code-remote +__package/gcc: Executing code-remote +__package/gdb: Generating local code +__package/gdb: Generating remote code +__package/gdb: Transferring object +__package/gdb: Checking code-local +__package/gdb: Executing code-local +__package/gdb: Checking code-remote +__package/gdb: Executing code-remote +__package/vim: Generating local code +__package/vim: Generating remote code +__package/vim: Transferring object +__package/vim: Checking code-local +__package/vim: Executing code-local +__package/vim: Checking code-remote +__package/vim: Executing code-remote +__package/git-core: Generating local code +__package/git-core: Generating remote code +__package/git-core: Transferring object +__package/git-core: Checking code-local +__package/git-core: Executing code-local +__package/git-core: Checking code-remote +__package/git-core: Executing code-remote +__package/atop: Generating local code +__package/atop: Generating remote code +__package/atop: Transferring object +__package/atop: Checking code-local +__package/atop: Executing code-local +__package/atop: Checking code-remote +__package/atop: Executing code-remote +__package/flex: Generating local code +__package/flex: Generating remote code +__package/flex: Transferring object +__package/flex: Checking code-local +__package/flex: Executing code-local +__package/flex: Checking code-remote +__package/flex: Executing code-remote +__package/gawk: Generating local code +__package/gawk: Generating remote code +__package/gawk: Transferring object +__package/gawk: Checking code-local +__package/gawk: Executing code-local +__package/gawk: Checking code-remote +__package/gawk: Executing code-remote +__package/make: Generating local code +__package/make: Generating remote code +__package/make: Transferring object +__package/make: Checking code-local +__package/make: Executing code-local +__package/make: Checking code-remote +__package/make: Executing code-remote +__package/swig: Generating local code +__package/swig: Generating remote code +__package/swig: Transferring object +__package/swig: Checking code-local +__package/swig: Executing code-local +__package/swig: Checking code-remote +__package/swig: Executing code-remote +__package/libreadline5-dev: Generating local code +__package/libreadline5-dev: Generating remote code +__package/libreadline5-dev: Transferring object +__package/libreadline5-dev: Checking code-local +__package/libreadline5-dev: Executing code-local +__package/libreadline5-dev: Checking code-remote +__package/libreadline5-dev: Executing code-remote +__package/libexpat1-dev: Generating local code +__package/libexpat1-dev: Generating remote code +__package/libexpat1-dev: Transferring object +__package/libexpat1-dev: Checking code-local +__package/libexpat1-dev: Executing code-local +__package/libexpat1-dev: Checking code-remote +__package/libexpat1-dev: Executing code-remote +__package/libnet-ssleay-perl: Generating local code +__package/libnet-ssleay-perl: Generating remote code +__package/libnet-ssleay-perl: Transferring object +__package/libnet-ssleay-perl: Checking code-local +__package/libnet-ssleay-perl: Executing code-local +__package/libnet-ssleay-perl: Checking code-remote +__package/libnet-ssleay-perl: Executing code-remote +__package/subversion: Generating local code +__package/subversion: Generating remote code +__package/subversion: Transferring object +__package/subversion: Checking code-local +__package/subversion: Executing code-local +__package/subversion: Checking code-remote +__package/subversion: Executing code-remote +__package/libcurl4-openssl-dev: Generating local code +__package/libcurl4-openssl-dev: Generating remote code +__package/libcurl4-openssl-dev: Transferring object +__package/libcurl4-openssl-dev: Checking code-local +__package/libcurl4-openssl-dev: Executing code-local +__package/libcurl4-openssl-dev: Checking code-remote +__package/libcurl4-openssl-dev: Executing code-remote +__package/bison: Generating local code +__package/bison: Generating remote code +__package/bison: Transferring object +__package/bison: Checking code-local +__package/bison: Executing code-local +__package/bison: Checking code-remote +__package/bison: Executing code-remote +__package/cmake: Generating local code +__package/cmake: Generating remote code +__package/cmake: Transferring object +__package/cmake: Checking code-local +__package/cmake: Executing code-local +__package/cmake: Checking code-remote +__package/cmake: Executing code-remote +__package/emacs: Generating local code +__package/emacs: Generating remote code +__package/emacs: Transferring object +__package/emacs: Checking code-local +__package/emacs: Executing code-local +__package/emacs: Checking code-remote +__package/emacs: Executing code-remote +__package/xfce4: Generating local code +__package/xfce4: Generating remote code +__package/xfce4: Transferring object +__package/xfce4: Checking code-local +__package/xfce4: Executing code-local +__package/xfce4: Checking code-remote +__package/xfce4: Executing code-remote +__package/xterm: Generating local code +__package/xterm: Generating remote code +__package/xterm: Transferring object +__package/xterm: Checking code-local +__package/xterm: Executing code-local +__package/xterm: Checking code-remote +__package/xterm: Executing code-remote +__package/tcl8.4-dev: Generating local code +__package/tcl8.4-dev: Generating remote code +__package/tcl8.4-dev: Transferring object +__package/tcl8.4-dev: Checking code-local +__package/tcl8.4-dev: Executing code-local +__package/tcl8.4-dev: Checking code-remote +__package/tcl8.4-dev: Executing code-remote +__package/libio-socket-ssl-perl: Generating local code +__package/libio-socket-ssl-perl: Generating remote code +__package/libio-socket-ssl-perl: Transferring object +__package/libio-socket-ssl-perl: Checking code-local +__package/libio-socket-ssl-perl: Executing code-local +__package/libio-socket-ssl-perl: Checking code-remote +__package/libio-socket-ssl-perl: Executing code-remote +__package/doxygen: Generating local code +__package/doxygen: Generating remote code +__package/doxygen: Transferring object +__package/doxygen: Checking code-local +__package/doxygen: Executing code-local +__package/doxygen: Checking code-remote +__package/doxygen: Executing code-remote +__package/zlib1g-dev: Generating local code +__package/zlib1g-dev: Generating remote code +__package/zlib1g-dev: Transferring object +__package/zlib1g-dev: Checking code-local +__package/zlib1g-dev: Executing code-local +__package/zlib1g-dev: Checking code-remote +__package/zlib1g-dev: Executing code-remote +__package/autoconf: Generating local code +__package/autoconf: Generating remote code +__package/autoconf: Transferring object +__package/autoconf: Checking code-local +__package/autoconf: Executing code-local +__package/autoconf: Checking code-remote +__package/autoconf: Executing code-remote +__package/libtool: Generating local code +__package/libtool: Generating remote code +__package/libtool: Transferring object +__package/libtool: Checking code-local +__package/libtool: Executing code-local +__package/libtool: Checking code-remote +__package/libtool: Executing code-remote +__package/traceroute-nanog: Generating local code +__package/traceroute-nanog: Generating remote code +__package/traceroute-nanog: Transferring object +__package/traceroute-nanog: Checking code-local +__package/traceroute-nanog: Executing code-local +__package/traceroute-nanog: Checking code-remote +__package/traceroute-nanog: Executing code-remote +__package/libncurses5-dev: Generating local code +__package/libncurses5-dev: Generating remote code +__package/libncurses5-dev: Transferring object +__package/libncurses5-dev: Checking code-local +__package/libncurses5-dev: Executing code-local +__package/libncurses5-dev: Checking code-remote +__package/libncurses5-dev: Executing code-remote +__package/libaio-dev: Generating local code +__package/libaio-dev: Generating remote code +__package/libaio-dev: Transferring object +__package/libaio-dev: Checking code-local +__package/libaio-dev: Executing code-local +__package/libaio-dev: Checking code-remote +__package/libaio-dev: Executing code-remote +__package/libboost-dev: Generating local code +__package/libboost-dev: Generating remote code +__package/libboost-dev: Transferring object +__package/libboost-dev: Checking code-local +__package/libboost-dev: Executing code-local +__package/libboost-dev: Checking code-remote +__package/libboost-dev: Executing code-remote +__package/xtightvncviewer: Generating local code +__package/xtightvncviewer: Generating remote code +__package/xtightvncviewer: Transferring object +__package/xtightvncviewer: Checking code-local +__package/xtightvncviewer: Executing code-local +__package/xtightvncviewer: Checking code-remote +__package/xtightvncviewer: Executing code-remote +__package/libxml2-dev: Generating local code +__package/libxml2-dev: Generating remote code +__package/libxml2-dev: Transferring object +__package/libxml2-dev: Checking code-local +__package/libxml2-dev: Executing code-local +__package/libxml2-dev: Checking code-remote +__package/libxml2-dev: Executing code-remote +__package/libtidy-dev: Generating local code +__package/libtidy-dev: Generating remote code +__package/libtidy-dev: Transferring object +__package/libtidy-dev: Checking code-local +__package/libtidy-dev: Executing code-local +__package/libtidy-dev: Checking code-remote +__package/libtidy-dev: Executing code-remote +__package/manpages: Generating local code +__package/manpages: Generating remote code +__package/manpages: Transferring object +__package/manpages: Checking code-local +__package/manpages: Executing code-local +__package/manpages: Checking code-remote +__package/manpages: Executing code-remote +__package/gcc-doc: Generating local code +__package/gcc-doc: Generating remote code +__package/gcc-doc: Transferring object +__package/gcc-doc: Checking code-local +__package/gcc-doc: Executing code-local +__package/gcc-doc: Checking code-remote +__package/gcc-doc: Executing code-remote +__package/fluxbox: Generating local code +__package/fluxbox: Generating remote code +__package/fluxbox: Transferring object +__package/fluxbox: Checking code-local +__package/fluxbox: Executing code-local +__package/fluxbox: Checking code-remote +__package/fluxbox: Executing code-remote +__package/libicu-dev: Generating local code +__package/libicu-dev: Generating remote code +__package/libicu-dev: Transferring object +__package/libicu-dev: Checking code-local +__package/libicu-dev: Executing code-local +__package/libicu-dev: Checking code-remote +__package/libicu-dev: Executing code-remote +__package/libc6-dev-i386: Generating local code +__package/libc6-dev-i386: Generating remote code +__package/libc6-dev-i386: Transferring object +__package/libc6-dev-i386: Checking code-local +__package/libc6-dev-i386: Executing code-local +__package/libc6-dev-i386: Checking code-remote +__package/libc6-dev-i386: Executing code-remote +__package/mercurial: Generating local code +__package/mercurial: Generating remote code +__package/mercurial: Transferring object +__package/mercurial: Checking code-local +__package/mercurial: Executing code-local +__package/mercurial: Checking code-remote +__package/mercurial: Executing code-remote +__package/git-doc: Generating local code +__package/git-doc: Generating remote code +__package/git-doc: Transferring object +__package/git-doc: Checking code-local +__package/git-doc: Executing code-local +__package/git-doc: Checking code-remote +__package/git-doc: Executing code-remote +__package/git-svn: Generating local code +__package/git-svn: Generating remote code +__package/git-svn: Transferring object +__package/git-svn: Checking code-local +__package/git-svn: Executing code-local +__package/git-svn: Checking code-remote +__package/git-svn: Executing code-remote +__package/libnuma-dev: Generating local code +__package/libnuma-dev: Generating remote code +__package/libnuma-dev: Transferring object +__package/libnuma-dev: Checking code-local +__package/libnuma-dev: Executing code-local +__package/libnuma-dev: Checking code-remote +__package/libnuma-dev: Executing code-remote +__package/gnuplot: Generating local code +__package/gnuplot: Generating remote code +__package/gnuplot: Transferring object +__package/gnuplot: Checking code-local +__package/gnuplot: Executing code-local +__package/gnuplot: Checking code-remote +__package/gnuplot: Executing code-remote +__package/puppet: Generating local code +__package/puppet: Generating remote code +__package/puppet: Transferring object +__package/puppet: Checking code-local +__package/puppet: Executing code-local +__package/puppet: Checking code-remote +__package/puppet: Executing code-remote +__package/screen: Generating local code +__package/screen: Generating remote code +__package/screen: Transferring object +__package/screen: Checking code-local +__package/screen: Executing code-local +__package/screen: Checking code-remote +__package/screen: Executing code-remote +__package/openntpd: Generating local code +__package/openntpd: Generating remote code +__package/openntpd: Transferring object +__package/openntpd: Checking code-local +__package/openntpd: Executing code-local +__package/openntpd: Checking code-remote +__package/openntpd: Executing code-remote +__package/gcc-multilib: Generating local code +__package/gcc-multilib: Generating remote code +__package/gcc-multilib: Transferring object +__package/gcc-multilib: Checking code-local +__package/gcc-multilib: Executing code-local +__package/gcc-multilib: Checking code-remote +__package/gcc-multilib: Executing code-remote +__package/libboost-regex-dev: Generating local code +__package/libboost-regex-dev: Generating remote code +__package/libboost-regex-dev: Transferring object +__package/libboost-regex-dev: Checking code-local +__package/libboost-regex-dev: Executing code-local +__package/libboost-regex-dev: Checking code-remote +__package/libboost-regex-dev: Executing code-remote +__package/g++-multilib: Generating local code +__package/g++-multilib: Generating remote code +__package/g++-multilib: Transferring object +__package/g++-multilib: Checking code-local +__package/g++-multilib: Executing code-local +__package/g++-multilib: Checking code-remote +__package/g++-multilib: Executing code-remote +__package/xfonts-base: Generating local code +__package/xfonts-base: Generating remote code +__package/xfonts-base: Transferring object +__package/xfonts-base: Checking code-local +__package/xfonts-base: Executing code-local +__package/xfonts-base: Checking code-remote +__package/xfonts-base: Executing code-remote +__package/rdesktop: Generating local code +__package/rdesktop: Generating remote code +__package/rdesktop: Transferring object +__package/rdesktop: Checking code-local +__package/rdesktop: Executing code-local +__package/rdesktop: Checking code-remote +__package/rdesktop: Executing code-remote +__package/build-essential: Generating local code +__package/build-essential: Generating remote code +__package/build-essential: Transferring object +__package/build-essential: Checking code-local +__package/build-essential: Executing code-local +__package/build-essential: Checking code-remote +__package/build-essential: Executing code-remote +__package/tightvncserver: Generating local code +__package/tightvncserver: Generating remote code +__package/tightvncserver: Transferring object +__package/tightvncserver: Checking code-local +__package/tightvncserver: Executing code-local +__package/tightvncserver: Checking code-remote +__package/tightvncserver: Executing code-remote +__package/python-crypto: Generating local code +__package/python-crypto: Generating remote code +__package/python-crypto: Transferring object +__package/python-crypto: Checking code-local +__package/python-crypto: Executing code-local +__package/python-crypto: Checking code-remote +__package/python-crypto: Executing code-remote +__package/libpam-krb5: Generating local code +__package/libpam-krb5: Generating remote code +__package/libpam-krb5: Transferring object +__package/libpam-krb5: Checking code-local +__package/libpam-krb5: Executing code-local +__package/libpam-krb5: Checking code-remote +__package/libpam-krb5: Executing code-remote +__package/libc6-dev: Generating local code +__package/libc6-dev: Generating remote code +__package/libc6-dev: Transferring object +__package/libc6-dev: Checking code-local +__package/libc6-dev: Executing code-local +__package/libc6-dev: Checking code-remote +__package/libc6-dev: Executing code-remote +__package/manpages-dev: Generating local code +__package/manpages-dev: Generating remote code +__package/manpages-dev: Transferring object +__package/manpages-dev: Checking code-local +__package/manpages-dev: Executing code-local +__package/manpages-dev: Checking code-remote +__package/manpages-dev: Executing code-remote +__package/ia32-libs: Generating local code +__package/ia32-libs: Generating remote code +__package/ia32-libs: Transferring object +__package/ia32-libs: Checking code-local +__package/ia32-libs: Executing code-local +__package/ia32-libs: Checking code-remote +__package/ia32-libs: Executing code-remote +__package/libxml-checker-perl: Generating local code +__package/libxml-checker-perl: Generating remote code +__package/libxml-checker-perl: Transferring object +__package/libxml-checker-perl: Checking code-local +__package/libxml-checker-perl: Executing code-local +__package/libxml-checker-perl: Checking code-remote +__package/libxml-checker-perl: Executing code-remote +__ethz_systems_root_via_ssh/subasui: Generating local code +__ethz_systems_root_via_ssh/subasui: Generating remote code +__ethz_systems_root_via_ssh/subasui: Transferring object +__ethz_systems_root_via_ssh/subasui: Checking code-local +__ethz_systems_root_via_ssh/subasui: Executing code-local +__ethz_systems_root_via_ssh/subasui: Checking code-remote +__ethz_systems_root_via_ssh/subasui: Executing code-remote +__ethz_systems_root_via_ssh/blukas: Generating local code +__ethz_systems_root_via_ssh/blukas: Generating remote code +__ethz_systems_root_via_ssh/blukas: Transferring object +__ethz_systems_root_via_ssh/blukas: Checking code-local +__ethz_systems_root_via_ssh/blukas: Executing code-local +__ethz_systems_root_via_ssh/blukas: Checking code-remote +__ethz_systems_root_via_ssh/blukas: Executing code-remote +__ethz_systems_root_via_ssh/petfisch: Generating local code +__ethz_systems_root_via_ssh/petfisch: Generating remote code +__ethz_systems_root_via_ssh/petfisch: Transferring object +__ethz_systems_root_via_ssh/petfisch: Checking code-local +__ethz_systems_root_via_ssh/petfisch: Executing code-local +__ethz_systems_root_via_ssh/petfisch: Checking code-remote +__ethz_systems_root_via_ssh/petfisch: Executing code-remote +__ethz_systems_motd/singleton: Generating local code +__ethz_systems_motd/singleton: Generating remote code +__ethz_systems_motd/singleton: Transferring object +__ethz_systems_motd/singleton: Checking code-local +__ethz_systems_motd/singleton: Executing code-local +__ethz_systems_motd/singleton: Checking code-remote +__ethz_systems_motd/singleton: Executing code-remote +__ethz_systems_sudo/singleton: Generating local code +__ethz_systems_sudo/singleton: Generating remote code +__ethz_systems_sudo/singleton: Transferring object +__ethz_systems_sudo/singleton: Checking code-local +__ethz_systems_sudo/singleton: Executing code-local +__ethz_systems_sudo/singleton: Checking code-remote +__ethz_systems_sudo/singleton: Executing code-remote +__ethz_sans_syslog/singleton: Generating local code +__ethz_sans_syslog/singleton: Generating remote code +__ethz_sans_syslog/singleton: Transferring object +__ethz_sans_syslog/singleton: Checking code-local +__ethz_sans_syslog/singleton: Executing code-local +__ethz_sans_syslog/singleton: Checking code-remote +__ethz_sans_syslog/singleton: Executing code-remote +__ethz_pam_krb5/singleton: Generating local code +__ethz_pam_krb5/singleton: Generating remote code +__ethz_pam_krb5/singleton: Transferring object +__ethz_pam_krb5/singleton: Checking code-local +__ethz_pam_krb5/singleton: Executing code-local +__ethz_pam_krb5/singleton: Checking code-remote +__ethz_pam_krb5/singleton: Executing code-remote +__ethz_dinfk_autofs/singleton: Generating local code +__ethz_dinfk_autofs/singleton: Generating remote code +__ethz_dinfk_autofs/singleton: Transferring object +__ethz_dinfk_autofs/singleton: Checking code-local +__ethz_dinfk_autofs/singleton: Executing code-local +__ethz_dinfk_autofs/singleton: Checking code-remote +__ethz_dinfk_autofs/singleton: Executing code-remote +__ethz_dinfk_ldap/singleton: Generating local code +__ethz_dinfk_ldap/singleton: Generating remote code +__ethz_dinfk_ldap/singleton: Transferring object +__ethz_dinfk_ldap/singleton: Checking code-local +__ethz_dinfk_ldap/singleton: Executing code-local +__ethz_dinfk_ldap/singleton: Checking code-remote +__ethz_dinfk_ldap/singleton: Executing code-remote +core: Debug: Mit Apr 27 14:19:30 CEST 2011 +core: Saving cache to /home/users/nico/oeffentlich/rechner/projekte/cdist-nutzung/cache/ikq04.ethz.ch +core: Debug: Mit Apr 27 14:19:31 CEST 2011 +core: cdist 1.6.2: Successfully finished run diff --git a/doc/dev/logs/2011-09-12.benchmark-home b/doc/dev/logs/2011-09-12.benchmark-home new file mode 100644 index 00000000..8cfc4971 --- /dev/null +++ b/doc/dev/logs/2011-09-12.benchmark-home @@ -0,0 +1,6960 @@ +INFO: Deploying to ikq02.ethz.ch +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq02.ethz.ch in 72.155556 seconds +I should cleanup /home/users/nico/.tmp/tmp013zxv +INFO: Total processing time for 1 hosts: 72.166661 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq03.ethz.ch in 76.556882 seconds +I should cleanup /home/users/nico/.tmp/tmpduad9n +INFO: Finished run of ikq02.ethz.ch in 76.617933 seconds +I should cleanup /home/users/nico/.tmp/tmpjqi6ey +INFO: Total processing time for 2 hosts: 76.633228 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq03.ethz.ch in 75.974003 seconds +I should cleanup /home/users/nico/.tmp/tmpg1dcf2 +INFO: Finished run of ikq04.ethz.ch in 76.961455 seconds +I should cleanup /home/users/nico/.tmp/tmp_bsndy +INFO: Finished run of ikq02.ethz.ch in 77.188361 seconds +I should cleanup /home/users/nico/.tmp/tmp9b0x11 +INFO: Total processing time for 3 host(s): 77.199817 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq04.ethz.ch in 75.857977 seconds +I should cleanup /home/users/nico/.tmp/tmpxhc33m +INFO: Finished run of ikq02.ethz.ch in 76.034966 seconds +I should cleanup /home/users/nico/.tmp/tmp0za5q0 +INFO: Finished run of ikq03.ethz.ch in 77.967854 seconds +I should cleanup /home/users/nico/.tmp/tmp_nt6ju +INFO: Finished run of ikq05.ethz.ch in 94.015012 seconds +I should cleanup /home/users/nico/.tmp/tmpihxpq1 +INFO: Total processing time for 4 host(s): 94.045175 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq03.ethz.ch in 84.249886 seconds +I should cleanup /home/users/nico/.tmp/tmp9pwps4 +INFO: Finished run of ikq04.ethz.ch in 84.70692 seconds +I should cleanup /home/users/nico/.tmp/tmp5q2_ov +INFO: Finished run of ikq06.ethz.ch in 84.831273 seconds +I should cleanup /home/users/nico/.tmp/tmpo5o5fi +INFO: Finished run of ikq02.ethz.ch in 85.648583 seconds +I should cleanup /home/users/nico/.tmp/tmp04au_u +INFO: Finished run of ikq05.ethz.ch in 103.18759 seconds +I should cleanup /home/users/nico/.tmp/tmpw5hgcq +INFO: Total processing time for 5 host(s): 103.226354 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq06.ethz.ch in 88.717419 seconds +I should cleanup /home/users/nico/.tmp/tmp463z4s +INFO: Finished run of ikq04.ethz.ch in 88.791926 seconds +I should cleanup /home/users/nico/.tmp/tmpbdipwj +INFO: Finished run of ikq02.ethz.ch in 89.046225 seconds +I should cleanup /home/users/nico/.tmp/tmpk832sn +INFO: Finished run of ikq03.ethz.ch in 89.067941 seconds +I should cleanup /home/users/nico/.tmp/tmpvmj5rq +INFO: Finished run of ikq07.ethz.ch in 89.412403 seconds +I should cleanup /home/users/nico/.tmp/tmpyljtcf +INFO: Finished run of ikq05.ethz.ch in 107.729915 seconds +I should cleanup /home/users/nico/.tmp/tmpmfc384 +INFO: Total processing time for 6 host(s): 107.76097 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq06.ethz.ch in 85.171819 seconds +I should cleanup /home/users/nico/.tmp/tmpjb2ow1 +INFO: Finished run of ikq02.ethz.ch in 85.507466 seconds +I should cleanup /home/users/nico/.tmp/tmpnql8_x +INFO: Finished run of ikq07.ethz.ch in 85.526465 seconds +I should cleanup /home/users/nico/.tmp/tmpl_34em +INFO: Finished run of ikq04.ethz.ch in 85.759357 seconds +I should cleanup /home/users/nico/.tmp/tmp807dx7 +INFO: Finished run of ikq03.ethz.ch in 85.897374 seconds +I should cleanup /home/users/nico/.tmp/tmpyjynp8 +INFO: Finished run of ikq05.ethz.ch in 101.540372 seconds +I should cleanup /home/users/nico/.tmp/tmpqgnkn1 +INFO: Total processing time for 7 host(s): 101.571705 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq07.ethz.ch in 88.958072 seconds +I should cleanup /home/users/nico/.tmp/tmpj824nd +INFO: Finished run of ikq04.ethz.ch in 89.290431 seconds +I should cleanup /home/users/nico/.tmp/tmpxi0eml +INFO: Finished run of ikq03.ethz.ch in 89.699189 seconds +I should cleanup /home/users/nico/.tmp/tmppx9o9p +INFO: Finished run of ikq06.ethz.ch in 89.807729 seconds +I should cleanup /home/users/nico/.tmp/tmpf3_ow_ +INFO: Finished run of ikq02.ethz.ch in 90.018545 seconds +I should cleanup /home/users/nico/.tmp/tmp6_ozkd +INFO: Finished run of ikr02.ethz.ch in 97.221764 seconds +I should cleanup /home/users/nico/.tmp/tmpsg71wy +INFO: Finished run of ikq05.ethz.ch in 107.564915 seconds +I should cleanup /home/users/nico/.tmp/tmp5zptvo +INFO: Total processing time for 8 host(s): 107.600093 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq02.ethz.ch in 97.849914 seconds +I should cleanup /home/users/nico/.tmp/tmp3nnh2u +INFO: Finished run of ikq07.ethz.ch in 97.975998 seconds +I should cleanup /home/users/nico/.tmp/tmpbb7tm2 +INFO: Finished run of ikq06.ethz.ch in 98.577879 seconds +I should cleanup /home/users/nico/.tmp/tmpz03p9m +INFO: Finished run of ikq03.ethz.ch in 98.676198 seconds +I should cleanup /home/users/nico/.tmp/tmpye5yk9 +INFO: Finished run of ikq04.ethz.ch in 98.671269 seconds +I should cleanup /home/users/nico/.tmp/tmphuyj_f +INFO: Finished run of ikr02.ethz.ch in 109.003609 seconds +I should cleanup /home/users/nico/.tmp/tmpwepj8y +INFO: Finished run of ikr03.ethz.ch in 109.930106 seconds +I should cleanup /home/users/nico/.tmp/tmp6kinml +INFO: Finished run of ikq05.ethz.ch in 116.455232 seconds +I should cleanup /home/users/nico/.tmp/tmpxrp5bs +INFO: Total processing time for 9 host(s): 116.500371 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq04.ethz.ch in 103.832242 seconds +I should cleanup /home/users/nico/.tmp/tmp9o5jfq +INFO: Finished run of ikq02.ethz.ch in 104.073833 seconds +I should cleanup /home/users/nico/.tmp/tmpip0crc +INFO: Finished run of ikq06.ethz.ch in 104.439403 seconds +I should cleanup /home/users/nico/.tmp/tmpcf69h4 +INFO: Finished run of ikq07.ethz.ch in 104.863176 seconds +I should cleanup /home/users/nico/.tmp/tmpg0cr4s +INFO: Finished run of ikq03.ethz.ch in 104.975989 seconds +I should cleanup /home/users/nico/.tmp/tmp086l_6 +INFO: Finished run of ikr05.ethz.ch in 112.545759 seconds +I should cleanup /home/users/nico/.tmp/tmpdtb7q2 +INFO: Finished run of ikr02.ethz.ch in 113.6572 seconds +I should cleanup /home/users/nico/.tmp/tmp8n7m4x +INFO: Finished run of ikr03.ethz.ch in 113.657078 seconds +I should cleanup /home/users/nico/.tmp/tmpcyi98d +INFO: Finished run of ikq05.ethz.ch in 119.403885 seconds +I should cleanup /home/users/nico/.tmp/tmpjow046 +INFO: Total processing time for 10 host(s): 119.445805 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq02.ethz.ch in 107.594849 seconds +I should cleanup /home/users/nico/.tmp/tmpam7130 +INFO: Finished run of ikq04.ethz.ch in 108.012557 seconds +I should cleanup /home/users/nico/.tmp/tmpksan74 +INFO: Finished run of ikq07.ethz.ch in 108.044124 seconds +I should cleanup /home/users/nico/.tmp/tmpbtfim0 +INFO: Finished run of ikq06.ethz.ch in 108.341489 seconds +I should cleanup /home/users/nico/.tmp/tmprweak0 +INFO: Finished run of ikq03.ethz.ch in 108.389863 seconds +I should cleanup /home/users/nico/.tmp/tmp0vl1nl +INFO: Finished run of ikr05.ethz.ch in 118.315184 seconds +I should cleanup /home/users/nico/.tmp/tmpcnj64y +INFO: Finished run of ikr07.ethz.ch in 119.454786 seconds +I should cleanup /home/users/nico/.tmp/tmp5f6dcf +INFO: Finished run of ikr02.ethz.ch in 119.734442 seconds +I should cleanup /home/users/nico/.tmp/tmpgx6lga +INFO: Finished run of ikr03.ethz.ch in 119.813266 seconds +I should cleanup /home/users/nico/.tmp/tmpza8ftn +INFO: Finished run of ikq05.ethz.ch in 123.912563 seconds +I should cleanup /home/users/nico/.tmp/tmpokg3bw +INFO: Total processing time for 11 host(s): 123.944385 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq06.ethz.ch in 112.532755 seconds +I should cleanup /home/users/nico/.tmp/tmpkwi6o4 +INFO: Finished run of ikq03.ethz.ch in 113.655432 seconds +I should cleanup /home/users/nico/.tmp/tmpheiprp +INFO: Finished run of ikq02.ethz.ch in 114.308282 seconds +I should cleanup /home/users/nico/.tmp/tmp1krz1m +INFO: Finished run of ikq07.ethz.ch in 114.580586 seconds +I should cleanup /home/users/nico/.tmp/tmpg23sal +INFO: Finished run of ikq04.ethz.ch in 114.981261 seconds +I should cleanup /home/users/nico/.tmp/tmplged7b +INFO: Finished run of ikr05.ethz.ch in 124.918792 seconds +I should cleanup /home/users/nico/.tmp/tmpsijvc9 +INFO: Finished run of ikr02.ethz.ch in 125.388647 seconds +I should cleanup /home/users/nico/.tmp/tmpw1e4ji +INFO: Finished run of ikr07.ethz.ch in 125.691531 seconds +I should cleanup /home/users/nico/.tmp/tmpx_9iz6 +INFO: Finished run of ikr03.ethz.ch in 126.951817 seconds +I should cleanup /home/users/nico/.tmp/tmpuikakt +INFO: Finished run of ikr09.ethz.ch in 126.947601 seconds +I should cleanup /home/users/nico/.tmp/tmpoyxlah +INFO: Finished run of ikq05.ethz.ch in 130.467261 seconds +I should cleanup /home/users/nico/.tmp/tmpobh15j +INFO: Total processing time for 12 host(s): 130.499098 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq02.ethz.ch in 121.864821 seconds +I should cleanup /home/users/nico/.tmp/tmpfgqxt5 +INFO: Finished run of ikq04.ethz.ch in 121.929722 seconds +I should cleanup /home/users/nico/.tmp/tmps2c8x0 +INFO: Finished run of ikq03.ethz.ch in 122.486316 seconds +I should cleanup /home/users/nico/.tmp/tmpnmea2b +INFO: Finished run of ikq06.ethz.ch in 123.168465 seconds +I should cleanup /home/users/nico/.tmp/tmp_5ns1o +INFO: Finished run of ikq07.ethz.ch in 123.623172 seconds +I should cleanup /home/users/nico/.tmp/tmp86yazu +INFO: Finished run of ikr05.ethz.ch in 131.530627 seconds +I should cleanup /home/users/nico/.tmp/tmp_wjz4q +INFO: Finished run of ikr10.ethz.ch in 132.29461 seconds +I should cleanup /home/users/nico/.tmp/tmpd9b7e6 +INFO: Finished run of ikr02.ethz.ch in 132.860874 seconds +I should cleanup /home/users/nico/.tmp/tmp5ruwiq +INFO: Finished run of ikr07.ethz.ch in 133.120448 seconds +I should cleanup /home/users/nico/.tmp/tmpdg8gnz +INFO: Finished run of ikr09.ethz.ch in 133.144026 seconds +I should cleanup /home/users/nico/.tmp/tmpdqnwj8 +INFO: Finished run of ikr03.ethz.ch in 133.569501 seconds +I should cleanup /home/users/nico/.tmp/tmp0ib7vd +INFO: Finished run of ikq05.ethz.ch in 137.219204 seconds +I should cleanup /home/users/nico/.tmp/tmpjnp_34 +INFO: Total processing time for 13 host(s): 137.250861 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq04.ethz.ch in 137.290435 seconds +I should cleanup /home/users/nico/.tmp/tmp3qrvii +INFO: Finished run of ikq06.ethz.ch in 137.430914 seconds +I should cleanup /home/users/nico/.tmp/tmpbut7j0 +INFO: Finished run of ikq02.ethz.ch in 137.888909 seconds +I should cleanup /home/users/nico/.tmp/tmp4vyy9p +INFO: Finished run of ikq03.ethz.ch in 138.237095 seconds +I should cleanup /home/users/nico/.tmp/tmpfj1yim +INFO: Finished run of ikq07.ethz.ch in 138.392173 seconds +I should cleanup /home/users/nico/.tmp/tmpfw3bx4 +INFO: Finished run of ikr05.ethz.ch in 150.274366 seconds +I should cleanup /home/users/nico/.tmp/tmpyn7rh1 +INFO: Finished run of ikr10.ethz.ch in 150.478504 seconds +I should cleanup /home/users/nico/.tmp/tmpn50v6l +INFO: Finished run of ikr07.ethz.ch in 150.514287 seconds +I should cleanup /home/users/nico/.tmp/tmp_mvlp2 +INFO: Finished run of ikr09.ethz.ch in 151.015286 seconds +I should cleanup /home/users/nico/.tmp/tmpm549_r +INFO: Finished run of ikr03.ethz.ch in 151.541814 seconds +I should cleanup /home/users/nico/.tmp/tmpynae4z +INFO: Finished run of ikr11.ethz.ch in 151.624163 seconds +I should cleanup /home/users/nico/.tmp/tmpyerp4y +INFO: Finished run of ikr02.ethz.ch in 151.81055 seconds +I should cleanup /home/users/nico/.tmp/tmp1t9rdc +INFO: Finished run of ikq05.ethz.ch in 154.945986 seconds +I should cleanup /home/users/nico/.tmp/tmpwxljjr +INFO: Total processing time for 14 host(s): 154.9841 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +Warning: Permanently added 'ikr13.ethz.ch,129.132.186.26' (RSA) to the list of known hosts. +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq03.ethz.ch in 120.523743 seconds +I should cleanup /home/users/nico/.tmp/tmp0_7fgv +INFO: Finished run of ikq02.ethz.ch in 121.060225 seconds +I should cleanup /home/users/nico/.tmp/tmpjxa6qw +INFO: Finished run of ikq04.ethz.ch in 121.754777 seconds +I should cleanup /home/users/nico/.tmp/tmpvnzs7k +INFO: Finished run of ikq07.ethz.ch in 121.782193 seconds +I should cleanup /home/users/nico/.tmp/tmp1o26v7 +INFO: Finished run of ikq06.ethz.ch in 122.575204 seconds +I should cleanup /home/users/nico/.tmp/tmp592kot +INFO: Finished run of ikr10.ethz.ch in 131.920153 seconds +I should cleanup /home/users/nico/.tmp/tmp_iwf_6 +INFO: Finished run of ikr05.ethz.ch in 132.153554 seconds +I should cleanup /home/users/nico/.tmp/tmpbk7wid +INFO: Finished run of ikr02.ethz.ch in 132.330635 seconds +I should cleanup /home/users/nico/.tmp/tmp9n2a4e +INFO: Finished run of ikr09.ethz.ch in 132.486383 seconds +I should cleanup /home/users/nico/.tmp/tmp__xwmz +INFO: Finished run of ikr07.ethz.ch in 136.013244 seconds +I should cleanup /home/users/nico/.tmp/tmp2gdyhj +INFO: Finished run of ikr11.ethz.ch in 136.471268 seconds +I should cleanup /home/users/nico/.tmp/tmphgxzio +INFO: Finished run of ikr03.ethz.ch in 136.565002 seconds +I should cleanup /home/users/nico/.tmp/tmpsdws1m +INFO: Finished run of ikq05.ethz.ch in 139.613692 seconds +I should cleanup /home/users/nico/.tmp/tmpp0lh4k +INFO: Total processing time for 15 host(s): 139.659637 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq06.ethz.ch in 123.802602 seconds +I should cleanup /home/users/nico/.tmp/tmpoag3uo +INFO: Finished run of ikq04.ethz.ch in 125.244272 seconds +I should cleanup /home/users/nico/.tmp/tmpzc8p8r +INFO: Finished run of ikq07.ethz.ch in 126.049417 seconds +I should cleanup /home/users/nico/.tmp/tmpg0wjs1 +INFO: Finished run of ikq02.ethz.ch in 126.635092 seconds +I should cleanup /home/users/nico/.tmp/tmpnhuefm +INFO: Finished run of ikq03.ethz.ch in 126.683252 seconds +I should cleanup /home/users/nico/.tmp/tmp569klp +INFO: Finished run of ikr10.ethz.ch in 135.902786 seconds +I should cleanup /home/users/nico/.tmp/tmp_pepbg +INFO: Finished run of ikr05.ethz.ch in 137.519519 seconds +I should cleanup /home/users/nico/.tmp/tmpog_4d2 +INFO: Finished run of ikr14.ethz.ch in 137.486553 seconds +I should cleanup /home/users/nico/.tmp/tmp35z1n7 +INFO: Finished run of ikr09.ethz.ch in 139.393357 seconds +I should cleanup /home/users/nico/.tmp/tmpa3d3le +INFO: Finished run of ikr11.ethz.ch in 139.367952 seconds +I should cleanup /home/users/nico/.tmp/tmpdyzpgw +INFO: Finished run of ikr03.ethz.ch in 139.772987 seconds +I should cleanup /home/users/nico/.tmp/tmprxzbm6 +INFO: Finished run of ikr02.ethz.ch in 139.962957 seconds +I should cleanup /home/users/nico/.tmp/tmpyrnk23 +INFO: Finished run of ikr07.ethz.ch in 140.554612 seconds +I should cleanup /home/users/nico/.tmp/tmpob7r8v +INFO: Finished run of ikq05.ethz.ch in 142.669111 seconds +I should cleanup /home/users/nico/.tmp/tmp8qcpjv +INFO: Total processing time for 16 host(s): 142.70005 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq03.ethz.ch in 132.945203 seconds +I should cleanup /home/users/nico/.tmp/tmpzot_mg +INFO: Finished run of ikq07.ethz.ch in 132.982484 seconds +I should cleanup /home/users/nico/.tmp/tmpgsp6q2 +INFO: Finished run of ikq02.ethz.ch in 133.229802 seconds +I should cleanup /home/users/nico/.tmp/tmpd4zxn8 +INFO: Finished run of ikq04.ethz.ch in 133.299541 seconds +I should cleanup /home/users/nico/.tmp/tmp4zq45z +INFO: Finished run of ikq06.ethz.ch in 133.802036 seconds +I should cleanup /home/users/nico/.tmp/tmpzwrs5v +INFO: Finished run of ikr14.ethz.ch in 145.03485 seconds +I should cleanup /home/users/nico/.tmp/tmpbqcwz0 +INFO: Finished run of ikr02.ethz.ch in 145.416967 seconds +I should cleanup /home/users/nico/.tmp/tmp1lse41 +INFO: Finished run of ikr10.ethz.ch in 145.693574 seconds +I should cleanup /home/users/nico/.tmp/tmpur3wfv +INFO: Finished run of ikr07.ethz.ch in 145.978708 seconds +I should cleanup /home/users/nico/.tmp/tmpr0an2_ +INFO: Finished run of ikr05.ethz.ch in 146.286686 seconds +I should cleanup /home/users/nico/.tmp/tmpl29did +INFO: Finished run of ikr09.ethz.ch in 146.501529 seconds +I should cleanup /home/users/nico/.tmp/tmpydoin6 +INFO: Finished run of ikr15.ethz.ch in 147.016223 seconds +I should cleanup /home/users/nico/.tmp/tmpbcp5p8 +INFO: Finished run of ikr03.ethz.ch in 147.12484 seconds +I should cleanup /home/users/nico/.tmp/tmpuowz74 +INFO: Finished run of ikr11.ethz.ch in 147.286151 seconds +I should cleanup /home/users/nico/.tmp/tmph25hy8 +INFO: Finished run of ikq05.ethz.ch in 148.506819 seconds +I should cleanup /home/users/nico/.tmp/tmp7brn95 +INFO: Total processing time for 17 host(s): 148.541452 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr16.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq04.ethz.ch in 143.675686 seconds +I should cleanup /home/users/nico/.tmp/tmp82nal9 +INFO: Finished run of ikq06.ethz.ch in 144.765412 seconds +I should cleanup /home/users/nico/.tmp/tmppxbr5e +INFO: Finished run of ikq07.ethz.ch in 144.895368 seconds +I should cleanup /home/users/nico/.tmp/tmp2waolo +INFO: Finished run of ikq03.ethz.ch in 145.051027 seconds +I should cleanup /home/users/nico/.tmp/tmp4984jk +INFO: Finished run of ikq02.ethz.ch in 145.822406 seconds +I should cleanup /home/users/nico/.tmp/tmpaz8a8n +INFO: Finished run of ikr14.ethz.ch in 154.113672 seconds +I should cleanup /home/users/nico/.tmp/tmpxy2kg4 +INFO: Finished run of ikr10.ethz.ch in 156.984583 seconds +I should cleanup /home/users/nico/.tmp/tmp6ppd8k +INFO: Finished run of ikr02.ethz.ch in 157.091568 seconds +I should cleanup /home/users/nico/.tmp/tmpxxou_a +INFO: Finished run of ikr07.ethz.ch in 157.520308 seconds +I should cleanup /home/users/nico/.tmp/tmpow0v1c +INFO: Finished run of ikr09.ethz.ch in 157.634227 seconds +I should cleanup /home/users/nico/.tmp/tmpi3gg17 +INFO: Finished run of ikr03.ethz.ch in 157.85916 seconds +I should cleanup /home/users/nico/.tmp/tmp3aybb1 +INFO: Finished run of ikr05.ethz.ch in 157.896262 seconds +I should cleanup /home/users/nico/.tmp/tmphqwu6l +INFO: Finished run of ikr16.ethz.ch in 158.078375 seconds +I should cleanup /home/users/nico/.tmp/tmptkh_yn +INFO: Finished run of ikr11.ethz.ch in 158.379867 seconds +I should cleanup /home/users/nico/.tmp/tmp1mdfoi +INFO: Finished run of ikr15.ethz.ch in 158.426851 seconds +I should cleanup /home/users/nico/.tmp/tmp4lcx43 +INFO: Finished run of ikq05.ethz.ch in 159.319045 seconds +I should cleanup /home/users/nico/.tmp/tmp2f_gug +INFO: Total processing time for 18 host(s): 159.360809 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr16.ethz.ch +INFO: Deploying to ikr17.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq07.ethz.ch in 151.304278 seconds +I should cleanup /home/users/nico/.tmp/tmpqkb2pc +INFO: Finished run of ikq06.ethz.ch in 156.467966 seconds +I should cleanup /home/users/nico/.tmp/tmp35zxo7 +INFO: Finished run of ikq04.ethz.ch in 157.188747 seconds +I should cleanup /home/users/nico/.tmp/tmpvb0nxt +INFO: Finished run of ikq03.ethz.ch in 157.955866 seconds +I should cleanup /home/users/nico/.tmp/tmp4k7jgo +INFO: Finished run of ikq02.ethz.ch in 158.316461 seconds +I should cleanup /home/users/nico/.tmp/tmpeddhr1 +INFO: Finished run of ikr10.ethz.ch in 167.801774 seconds +I should cleanup /home/users/nico/.tmp/tmpn_7hlf +INFO: Finished run of ikr14.ethz.ch in 167.906681 seconds +I should cleanup /home/users/nico/.tmp/tmpdemdfp +INFO: Finished run of ikr02.ethz.ch in 169.536628 seconds +I should cleanup /home/users/nico/.tmp/tmpcaeatj +INFO: Finished run of ikr17.ethz.ch in 169.68007 seconds +I should cleanup /home/users/nico/.tmp/tmpzz1gwu +INFO: Finished run of ikr05.ethz.ch in 170.014506 seconds +I should cleanup /home/users/nico/.tmp/tmpksj9is +INFO: Finished run of ikr15.ethz.ch in 170.512682 seconds +I should cleanup /home/users/nico/.tmp/tmpdb72hk +INFO: Finished run of ikr09.ethz.ch in 170.696373 seconds +I should cleanup /home/users/nico/.tmp/tmpe3dz9b +INFO: Finished run of ikr07.ethz.ch in 170.923977 seconds +I should cleanup /home/users/nico/.tmp/tmpuvt1ke +INFO: Finished run of ikr11.ethz.ch in 170.89362 seconds +I should cleanup /home/users/nico/.tmp/tmpuk0_7g +INFO: Finished run of ikr03.ethz.ch in 171.598123 seconds +I should cleanup /home/users/nico/.tmp/tmp4i12vh +INFO: Finished run of ikr16.ethz.ch in 171.502924 seconds +I should cleanup /home/users/nico/.tmp/tmp55ix1x +INFO: Finished run of ikq05.ethz.ch in 171.874543 seconds +I should cleanup /home/users/nico/.tmp/tmp417ofh +INFO: Total processing time for 19 host(s): 171.907864 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr16.ethz.ch +INFO: Deploying to ikr17.ethz.ch +INFO: Deploying to ikr19.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq02.ethz.ch in 157.829713 seconds +I should cleanup /home/users/nico/.tmp/tmpqf9wcb +INFO: Finished run of ikq04.ethz.ch in 161.470424 seconds +I should cleanup /home/users/nico/.tmp/tmpaxrqmo +INFO: Finished run of ikq06.ethz.ch in 163.020342 seconds +I should cleanup /home/users/nico/.tmp/tmpt5dwxt +INFO: Finished run of ikq03.ethz.ch in 164.391855 seconds +I should cleanup /home/users/nico/.tmp/tmpd_5zb6 +INFO: Finished run of ikq07.ethz.ch in 165.180659 seconds +I should cleanup /home/users/nico/.tmp/tmp97ikmr +INFO: Finished run of ikr14.ethz.ch in 173.059971 seconds +I should cleanup /home/users/nico/.tmp/tmpefe37g +INFO: Finished run of ikr07.ethz.ch in 173.134127 seconds +I should cleanup /home/users/nico/.tmp/tmp7vam9i +INFO: Finished run of ikr05.ethz.ch in 174.793465 seconds +I should cleanup /home/users/nico/.tmp/tmplu772y +INFO: Finished run of ikr19.ethz.ch in 175.448245 seconds +I should cleanup /home/users/nico/.tmp/tmpkrzksf +INFO: Finished run of ikr02.ethz.ch in 175.624194 seconds +I should cleanup /home/users/nico/.tmp/tmpln5e7p +INFO: Finished run of ikr10.ethz.ch in 177.161247 seconds +I should cleanup /home/users/nico/.tmp/tmp04oa95 +INFO: Finished run of ikr17.ethz.ch in 177.641062 seconds +I should cleanup /home/users/nico/.tmp/tmpuke4jq +INFO: Finished run of ikr03.ethz.ch in 177.805503 seconds +I should cleanup /home/users/nico/.tmp/tmp9m6kgk +INFO: Finished run of ikr09.ethz.ch in 178.068981 seconds +I should cleanup /home/users/nico/.tmp/tmpwsvt18 +INFO: Finished run of ikr11.ethz.ch in 178.26438 seconds +I should cleanup /home/users/nico/.tmp/tmpvsc9oz +INFO: Finished run of ikr15.ethz.ch in 178.416205 seconds +I should cleanup /home/users/nico/.tmp/tmpmzzacs +INFO: Finished run of ikr16.ethz.ch in 178.473477 seconds +I should cleanup /home/users/nico/.tmp/tmplh_80t +INFO: Finished run of ikq05.ethz.ch in 178.735551 seconds +I should cleanup /home/users/nico/.tmp/tmpslnq9v +INFO: Total processing time for 20 host(s): 178.76695 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr16.ethz.ch +INFO: Deploying to ikr17.ethz.ch +INFO: Deploying to ikr19.ethz.ch +INFO: Deploying to ikr20.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq02.ethz.ch in 170.169321 seconds +I should cleanup /home/users/nico/.tmp/tmpdgynh9 +INFO: Finished run of ikq06.ethz.ch in 171.461174 seconds +I should cleanup /home/users/nico/.tmp/tmpwxtd79 +INFO: Finished run of ikq03.ethz.ch in 171.626668 seconds +I should cleanup /home/users/nico/.tmp/tmpiqc3ji +INFO: Finished run of ikq04.ethz.ch in 171.724653 seconds +I should cleanup /home/users/nico/.tmp/tmpdt2og0 +INFO: Finished run of ikq07.ethz.ch in 171.78001 seconds +I should cleanup /home/users/nico/.tmp/tmpl4krs7 +INFO: Finished run of ikr10.ethz.ch in 177.048099 seconds +I should cleanup /home/users/nico/.tmp/tmpne6_s_ +INFO: Finished run of ikr17.ethz.ch in 180.562186 seconds +I should cleanup /home/users/nico/.tmp/tmpl199q5 +INFO: Finished run of ikr19.ethz.ch in 181.223109 seconds +I should cleanup /home/users/nico/.tmp/tmpoky1qz +INFO: Finished run of ikr11.ethz.ch in 182.462812 seconds +I should cleanup /home/users/nico/.tmp/tmp2xfmtx +INFO: Finished run of ikr14.ethz.ch in 182.498966 seconds +I should cleanup /home/users/nico/.tmp/tmpbaa_1v +INFO: Finished run of ikr20.ethz.ch in 182.598193 seconds +I should cleanup /home/users/nico/.tmp/tmp0goxf_ +INFO: Finished run of ikr03.ethz.ch in 183.01005 seconds +I should cleanup /home/users/nico/.tmp/tmpa7d_j6 +INFO: Finished run of ikr15.ethz.ch in 182.994708 seconds +I should cleanup /home/users/nico/.tmp/tmphvktgk +INFO: Finished run of ikr07.ethz.ch in 183.413644 seconds +I should cleanup /home/users/nico/.tmp/tmpxfe884 +INFO: Finished run of ikr02.ethz.ch in 183.470895 seconds +I should cleanup /home/users/nico/.tmp/tmphd7ynb +INFO: Finished run of ikr05.ethz.ch in 183.46156 seconds +I should cleanup /home/users/nico/.tmp/tmpfniywk +INFO: Finished run of ikr16.ethz.ch in 183.371318 seconds +I should cleanup /home/users/nico/.tmp/tmpqsd782 +INFO: Finished run of ikr09.ethz.ch in 183.467264 seconds +I should cleanup /home/users/nico/.tmp/tmph84dh1 +INFO: Finished run of ikq05.ethz.ch in 183.813915 seconds +I should cleanup /home/users/nico/.tmp/tmp_w3anv +INFO: Total processing time for 21 host(s): 183.856671 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr16.ethz.ch +INFO: Deploying to ikr17.ethz.ch +INFO: Deploying to ikr19.ethz.ch +INFO: Deploying to ikr20.ethz.ch +INFO: Deploying to ikr21.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq06.ethz.ch in 169.955614 seconds +I should cleanup /home/users/nico/.tmp/tmplmg5_y +INFO: Finished run of ikq02.ethz.ch in 170.411064 seconds +I should cleanup /home/users/nico/.tmp/tmpwr3ygp +INFO: Finished run of ikq07.ethz.ch in 173.554952 seconds +I should cleanup /home/users/nico/.tmp/tmpso42zx +INFO: Finished run of ikq04.ethz.ch in 173.63845 seconds +I should cleanup /home/users/nico/.tmp/tmpsqgh9o +INFO: Finished run of ikq03.ethz.ch in 173.951844 seconds +I should cleanup /home/users/nico/.tmp/tmp8fjghd +INFO: Finished run of ikr20.ethz.ch in 185.922176 seconds +I should cleanup /home/users/nico/.tmp/tmpt3rtcq +INFO: Finished run of ikr07.ethz.ch in 191.153275 seconds +I should cleanup /home/users/nico/.tmp/tmpr39dmz +INFO: Finished run of ikr10.ethz.ch in 191.982504 seconds +I should cleanup /home/users/nico/.tmp/tmpz_ear7 +INFO: Finished run of ikr14.ethz.ch in 192.653998 seconds +I should cleanup /home/users/nico/.tmp/tmp7wvfhq +INFO: Finished run of ikr17.ethz.ch in 192.652562 seconds +I should cleanup /home/users/nico/.tmp/tmp51k0hh +INFO: Finished run of ikr19.ethz.ch in 192.814789 seconds +I should cleanup /home/users/nico/.tmp/tmp760hc3 +INFO: Finished run of ikr05.ethz.ch in 193.44574 seconds +I should cleanup /home/users/nico/.tmp/tmp73204x +INFO: Finished run of ikr09.ethz.ch in 193.537 seconds +I should cleanup /home/users/nico/.tmp/tmpf4z4q5 +INFO: Finished run of ikr16.ethz.ch in 193.584303 seconds +I should cleanup /home/users/nico/.tmp/tmp12jwnj +INFO: Finished run of ikr11.ethz.ch in 193.668931 seconds +I should cleanup /home/users/nico/.tmp/tmptudl3_ +INFO: Finished run of ikr02.ethz.ch in 193.800381 seconds +I should cleanup /home/users/nico/.tmp/tmpf588if +INFO: Finished run of ikr15.ethz.ch in 193.754252 seconds +I should cleanup /home/users/nico/.tmp/tmpp71hsb +INFO: Finished run of ikr03.ethz.ch in 193.866005 seconds +I should cleanup /home/users/nico/.tmp/tmppevhzu +INFO: Finished run of ikr21.ethz.ch in 193.84791 seconds +I should cleanup /home/users/nico/.tmp/tmpe0umjh +INFO: Finished run of ikq05.ethz.ch in 194.471906 seconds +I should cleanup /home/users/nico/.tmp/tmp6y2zuq +INFO: Total processing time for 22 host(s): 194.504221 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr16.ethz.ch +INFO: Deploying to ikr17.ethz.ch +INFO: Deploying to ikr19.ethz.ch +INFO: Deploying to ikr20.ethz.ch +INFO: Deploying to ikr21.ethz.ch +INFO: Deploying to ikr23.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq06.ethz.ch in 183.331036 seconds +I should cleanup /home/users/nico/.tmp/tmp3zzf35 +INFO: Finished run of ikq04.ethz.ch in 188.245634 seconds +I should cleanup /home/users/nico/.tmp/tmppsfm7g +INFO: Finished run of ikq07.ethz.ch in 189.097252 seconds +I should cleanup /home/users/nico/.tmp/tmpckmmbr +INFO: Finished run of ikq02.ethz.ch in 189.168067 seconds +I should cleanup /home/users/nico/.tmp/tmp_wbxqv +INFO: Finished run of ikq03.ethz.ch in 191.178122 seconds +I should cleanup /home/users/nico/.tmp/tmp4xyb0h +INFO: Finished run of ikr17.ethz.ch in 200.405666 seconds +I should cleanup /home/users/nico/.tmp/tmpwl3901 +INFO: Finished run of ikr20.ethz.ch in 201.125398 seconds +I should cleanup /home/users/nico/.tmp/tmpt4gwst +INFO: Finished run of ikr05.ethz.ch in 204.457668 seconds +I should cleanup /home/users/nico/.tmp/tmpquc21r +INFO: Finished run of ikr19.ethz.ch in 204.61935 seconds +I should cleanup /home/users/nico/.tmp/tmpth2imd +INFO: Finished run of ikr03.ethz.ch in 205.782259 seconds +I should cleanup /home/users/nico/.tmp/tmp5qgmy3 +INFO: Finished run of ikr02.ethz.ch in 206.089122 seconds +I should cleanup /home/users/nico/.tmp/tmp_0yydj +INFO: Finished run of ikr10.ethz.ch in 206.344087 seconds +I should cleanup /home/users/nico/.tmp/tmprppnti +INFO: Finished run of ikr14.ethz.ch in 206.487929 seconds +I should cleanup /home/users/nico/.tmp/tmpg1sm5o +INFO: Finished run of ikr07.ethz.ch in 206.592221 seconds +I should cleanup /home/users/nico/.tmp/tmpz8h8u7 +INFO: Finished run of ikr21.ethz.ch in 206.574162 seconds +I should cleanup /home/users/nico/.tmp/tmp29bf91 +INFO: Finished run of ikr09.ethz.ch in 206.757285 seconds +I should cleanup /home/users/nico/.tmp/tmpkfk0tl +INFO: Finished run of ikr16.ethz.ch in 206.751199 seconds +I should cleanup /home/users/nico/.tmp/tmpjxql2a +INFO: Finished run of ikr15.ethz.ch in 206.951335 seconds +I should cleanup /home/users/nico/.tmp/tmpslol4l +INFO: Finished run of ikq05.ethz.ch in 207.10716 seconds +I should cleanup /home/users/nico/.tmp/tmpryt7ok +INFO: Finished run of ikr23.ethz.ch in 207.047179 seconds +I should cleanup /home/users/nico/.tmp/tmph8jagj +INFO: Finished run of ikr11.ethz.ch in 207.16906 seconds +I should cleanup /home/users/nico/.tmp/tmpl2hbm8 +INFO: Total processing time for 23 host(s): 207.314842 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr16.ethz.ch +INFO: Deploying to ikr19.ethz.ch +INFO: Deploying to ikr17.ethz.ch +INFO: Deploying to ikr20.ethz.ch +INFO: Deploying to ikr21.ethz.ch +INFO: Deploying to ikr23.ethz.ch +INFO: Deploying to ikr24.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq07.ethz.ch in 187.618723 seconds +I should cleanup /home/users/nico/.tmp/tmpyoqguq +INFO: Finished run of ikq03.ethz.ch in 187.750961 seconds +I should cleanup /home/users/nico/.tmp/tmpjwp515 +INFO: Finished run of ikq02.ethz.ch in 196.709864 seconds +I should cleanup /home/users/nico/.tmp/tmpm221lr +INFO: Finished run of ikq06.ethz.ch in 197.81424 seconds +I should cleanup /home/users/nico/.tmp/tmpkyt260 +INFO: Finished run of ikq04.ethz.ch in 198.512346 seconds +I should cleanup /home/users/nico/.tmp/tmpkwgaqh +INFO: Finished run of ikr14.ethz.ch in 208.879349 seconds +I should cleanup /home/users/nico/.tmp/tmpnshneg +INFO: Finished run of ikr19.ethz.ch in 211.066451 seconds +I should cleanup /home/users/nico/.tmp/tmpc0tm26 +INFO: Finished run of ikr20.ethz.ch in 212.537745 seconds +I should cleanup /home/users/nico/.tmp/tmpw16xze +INFO: Finished run of ikr03.ethz.ch in 213.771479 seconds +I should cleanup /home/users/nico/.tmp/tmpa4pj9v +INFO: Finished run of ikr10.ethz.ch in 214.089014 seconds +I should cleanup /home/users/nico/.tmp/tmpbbmh5z +INFO: Finished run of ikr15.ethz.ch in 214.168849 seconds +I should cleanup /home/users/nico/.tmp/tmp_hj_82 +INFO: Finished run of ikr17.ethz.ch in 214.377309 seconds +I should cleanup /home/users/nico/.tmp/tmpvltd85 +INFO: Finished run of ikr21.ethz.ch in 214.424358 seconds +I should cleanup /home/users/nico/.tmp/tmp9fv334 +INFO: Finished run of ikr07.ethz.ch in 214.840774 seconds +I should cleanup /home/users/nico/.tmp/tmpqm165u +INFO: Finished run of ikr05.ethz.ch in 214.906573 seconds +I should cleanup /home/users/nico/.tmp/tmpsjzrd3 +INFO: Finished run of ikr02.ethz.ch in 214.947938 seconds +I should cleanup /home/users/nico/.tmp/tmpdomosr +INFO: Finished run of ikr09.ethz.ch in 214.892808 seconds +I should cleanup /home/users/nico/.tmp/tmpwv5fb2 +INFO: Finished run of ikr11.ethz.ch in 215.352163 seconds +I should cleanup /home/users/nico/.tmp/tmp0_c8kz +INFO: Finished run of ikq05.ethz.ch in 215.460435 seconds +I should cleanup /home/users/nico/.tmp/tmpypqk55 +INFO: Finished run of ikr16.ethz.ch in 215.318416 seconds +I should cleanup /home/users/nico/.tmp/tmpypq7ta +INFO: Finished run of ikr24.ethz.ch in 215.365107 seconds +I should cleanup /home/users/nico/.tmp/tmpri18dz +INFO: Finished run of ikr23.ethz.ch in 215.594156 seconds +I should cleanup /home/users/nico/.tmp/tmpglm4ku +INFO: Total processing time for 24 host(s): 215.846502 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr16.ethz.ch +INFO: Deploying to ikr19.ethz.ch +INFO: Deploying to ikr17.ethz.ch +INFO: Deploying to ikr20.ethz.ch +INFO: Deploying to ikr21.ethz.ch +INFO: Deploying to ikr23.ethz.ch +INFO: Deploying to ikr24.ethz.ch +INFO: Deploying to ikr25.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq07.ethz.ch in 188.442055 seconds +I should cleanup /home/users/nico/.tmp/tmprcj8hv +INFO: Finished run of ikq04.ethz.ch in 188.602631 seconds +I should cleanup /home/users/nico/.tmp/tmpe6svdv +INFO: Finished run of ikq02.ethz.ch in 191.545683 seconds +I should cleanup /home/users/nico/.tmp/tmpw7tyqo +INFO: Finished run of ikq06.ethz.ch in 191.972664 seconds +I should cleanup /home/users/nico/.tmp/tmpc3xcoh +INFO: Finished run of ikq03.ethz.ch in 200.27211 seconds +I should cleanup /home/users/nico/.tmp/tmpej_9wz +INFO: Finished run of ikr17.ethz.ch in 211.689402 seconds +I should cleanup /home/users/nico/.tmp/tmpab2j3n +INFO: Finished run of ikr20.ethz.ch in 213.782377 seconds +I should cleanup /home/users/nico/.tmp/tmpeb5m8a +INFO: Finished run of ikr25.ethz.ch in 214.437128 seconds +I should cleanup /home/users/nico/.tmp/tmpltec25 +INFO: Finished run of ikr10.ethz.ch in 214.723128 seconds +I should cleanup /home/users/nico/.tmp/tmpn3tnws +INFO: Finished run of ikr19.ethz.ch in 214.907271 seconds +I should cleanup /home/users/nico/.tmp/tmpimo16x +INFO: Finished run of ikr14.ethz.ch in 215.026046 seconds +I should cleanup /home/users/nico/.tmp/tmpf6wp_u +INFO: Finished run of ikr05.ethz.ch in 215.731064 seconds +I should cleanup /home/users/nico/.tmp/tmp_67b2k +INFO: Finished run of ikr24.ethz.ch in 215.736746 seconds +I should cleanup /home/users/nico/.tmp/tmpsj8gpp +INFO: Finished run of ikr11.ethz.ch in 216.207536 seconds +I should cleanup /home/users/nico/.tmp/tmpsvg8rs +INFO: Finished run of ikr09.ethz.ch in 216.40167 seconds +I should cleanup /home/users/nico/.tmp/tmpr76lo2 +INFO: Finished run of ikr02.ethz.ch in 216.476902 seconds +I should cleanup /home/users/nico/.tmp/tmpoa5woy +INFO: Finished run of ikr03.ethz.ch in 216.760169 seconds +I should cleanup /home/users/nico/.tmp/tmpoos_8z +INFO: Finished run of ikr23.ethz.ch in 216.673695 seconds +I should cleanup /home/users/nico/.tmp/tmphffunh +INFO: Finished run of ikr15.ethz.ch in 216.889297 seconds +I should cleanup /home/users/nico/.tmp/tmpaesns3 +INFO: Finished run of ikr07.ethz.ch in 217.052298 seconds +I should cleanup /home/users/nico/.tmp/tmpn87am6 +INFO: Finished run of ikr21.ethz.ch in 216.951911 seconds +I should cleanup /home/users/nico/.tmp/tmps2kfri +INFO: Finished run of ikr16.ethz.ch in 217.021147 seconds +I should cleanup /home/users/nico/.tmp/tmpfyxjsx +INFO: Finished run of ikq05.ethz.ch in 217.191655 seconds +I should cleanup /home/users/nico/.tmp/tmpx5i4km +INFO: Total processing time for 25 host(s): 217.223581 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr16.ethz.ch +INFO: Deploying to ikr17.ethz.ch +INFO: Deploying to ikr19.ethz.ch +INFO: Deploying to ikr20.ethz.ch +INFO: Deploying to ikr21.ethz.ch +INFO: Deploying to ikr23.ethz.ch +INFO: Deploying to ikr24.ethz.ch +INFO: Deploying to ikr25.ethz.ch +INFO: Deploying to ikr26.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq06.ethz.ch in 209.543172 seconds +I should cleanup /home/users/nico/.tmp/tmpb51g1n +INFO: Finished run of ikq03.ethz.ch in 210.337092 seconds +I should cleanup /home/users/nico/.tmp/tmpce1qe3 +INFO: Finished run of ikq02.ethz.ch in 210.760602 seconds +I should cleanup /home/users/nico/.tmp/tmpfnduir +INFO: Finished run of ikq07.ethz.ch in 211.315784 seconds +I should cleanup /home/users/nico/.tmp/tmpq3tw15 +INFO: Finished run of ikq04.ethz.ch in 213.717476 seconds +I should cleanup /home/users/nico/.tmp/tmp9b4_69 +INFO: Finished run of ikr03.ethz.ch in 233.40723 seconds +I should cleanup /home/users/nico/.tmp/tmpk_n0av +INFO: Finished run of ikr10.ethz.ch in 233.780751 seconds +I should cleanup /home/users/nico/.tmp/tmp91phvb +INFO: Finished run of ikr07.ethz.ch in 234.993885 seconds +I should cleanup /home/users/nico/.tmp/tmpexumzi +INFO: Finished run of ikr14.ethz.ch in 236.126748 seconds +I should cleanup /home/users/nico/.tmp/tmpyjxqk5 +INFO: Finished run of ikr05.ethz.ch in 236.907114 seconds +I should cleanup /home/users/nico/.tmp/tmp2mfxb9 +INFO: Finished run of ikr19.ethz.ch in 236.805215 seconds +I should cleanup /home/users/nico/.tmp/tmpmlyizv +INFO: Finished run of ikr20.ethz.ch in 237.000427 seconds +I should cleanup /home/users/nico/.tmp/tmpwy_utm +INFO: Finished run of ikr25.ethz.ch in 237.06996 seconds +I should cleanup /home/users/nico/.tmp/tmpgqrsfd +INFO: Finished run of ikr11.ethz.ch in 237.62119 seconds +I should cleanup /home/users/nico/.tmp/tmpwd0a1c +INFO: Finished run of ikr26.ethz.ch in 237.554682 seconds +I should cleanup /home/users/nico/.tmp/tmp7wsaqu +INFO: Finished run of ikr17.ethz.ch in 237.715835 seconds +I should cleanup /home/users/nico/.tmp/tmparrgy1 +INFO: Finished run of ikr15.ethz.ch in 237.961549 seconds +I should cleanup /home/users/nico/.tmp/tmpt74239 +INFO: Finished run of ikq05.ethz.ch in 238.126596 seconds +I should cleanup /home/users/nico/.tmp/tmpvfigmw +INFO: Finished run of ikr02.ethz.ch in 238.134702 seconds +I should cleanup /home/users/nico/.tmp/tmpb7v16x +INFO: Finished run of ikr16.ethz.ch in 238.099716 seconds +I should cleanup /home/users/nico/.tmp/tmpb0x56o +INFO: Finished run of ikr09.ethz.ch in 238.20569 seconds +I should cleanup /home/users/nico/.tmp/tmpl5qoyz +INFO: Finished run of ikr24.ethz.ch in 238.230154 seconds +I should cleanup /home/users/nico/.tmp/tmp93hwbz +INFO: Finished run of ikr21.ethz.ch in 238.300384 seconds +I should cleanup /home/users/nico/.tmp/tmp619s6n +INFO: Finished run of ikr23.ethz.ch in 238.322157 seconds +I should cleanup /home/users/nico/.tmp/tmpvb2kh5 +INFO: Total processing time for 26 host(s): 238.591705 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr17.ethz.ch +INFO: Deploying to ikr16.ethz.ch +INFO: Deploying to ikr19.ethz.ch +INFO: Deploying to ikr20.ethz.ch +INFO: Deploying to ikr21.ethz.ch +INFO: Deploying to ikr23.ethz.ch +INFO: Deploying to ikr24.ethz.ch +INFO: Deploying to ikr25.ethz.ch +INFO: Deploying to ikr26.ethz.ch +INFO: Deploying to ikr27.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq03.ethz.ch in 215.332411 seconds +I should cleanup /home/users/nico/.tmp/tmpjvsfb6 +INFO: Finished run of ikq02.ethz.ch in 217.196822 seconds +I should cleanup /home/users/nico/.tmp/tmptbx4cl +INFO: Finished run of ikq06.ethz.ch in 217.198258 seconds +I should cleanup /home/users/nico/.tmp/tmpm7ducc +INFO: Finished run of ikq07.ethz.ch in 220.168978 seconds +I should cleanup /home/users/nico/.tmp/tmpzum8_c +INFO: Finished run of ikq04.ethz.ch in 220.311359 seconds +I should cleanup /home/users/nico/.tmp/tmpf8oh_z +E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem. +ERROR: Command failed: ssh root@ikr27.ethz.ch /var/lib/cdist/object/__package_apt/collectd/.cdist/code-remote +INFO: Finished run of ikr25.ethz.ch in 231.729276 seconds +I should cleanup /home/users/nico/.tmp/tmpkw4l8y +INFO: Finished run of ikr14.ethz.ch in 235.616386 seconds +I should cleanup /home/users/nico/.tmp/tmpierma3 +INFO: Finished run of ikr26.ethz.ch in 235.793067 seconds +I should cleanup /home/users/nico/.tmp/tmpf9hmfe +INFO: Finished run of ikr02.ethz.ch in 236.019716 seconds +I should cleanup /home/users/nico/.tmp/tmpd1x7cn +INFO: Finished run of ikr17.ethz.ch in 236.038355 seconds +I should cleanup /home/users/nico/.tmp/tmpwla840 +INFO: Finished run of ikr19.ethz.ch in 236.343239 seconds +I should cleanup /home/users/nico/.tmp/tmp16gann +INFO: Finished run of ikr20.ethz.ch in 236.550018 seconds +I should cleanup /home/users/nico/.tmp/tmpmfhiu3 +INFO: Finished run of ikr09.ethz.ch in 236.68465 seconds +I should cleanup /home/users/nico/.tmp/tmpm_jeke +INFO: Finished run of ikr07.ethz.ch in 237.023632 seconds +I should cleanup /home/users/nico/.tmp/tmpwpb50n +INFO: Finished run of ikr10.ethz.ch in 237.252747 seconds +I should cleanup /home/users/nico/.tmp/tmps57avh +INFO: Finished run of ikr05.ethz.ch in 237.343652 seconds +I should cleanup /home/users/nico/.tmp/tmpcz9apl +INFO: Finished run of ikq05.ethz.ch in 237.564124 seconds +I should cleanup /home/users/nico/.tmp/tmpgo8u_q +INFO: Finished run of ikr03.ethz.ch in 237.561235 seconds +I should cleanup /home/users/nico/.tmp/tmp37xbfa +INFO: Finished run of ikr16.ethz.ch in 237.55441 seconds +I should cleanup /home/users/nico/.tmp/tmp_y6cb0 +INFO: Finished run of ikr23.ethz.ch in 237.589377 seconds +I should cleanup /home/users/nico/.tmp/tmpmswsnx +INFO: Finished run of ikr11.ethz.ch in 237.791683 seconds +I should cleanup /home/users/nico/.tmp/tmprlbap0 +INFO: Finished run of ikr24.ethz.ch in 237.819221 seconds +I should cleanup /home/users/nico/.tmp/tmpjywrgt +INFO: Finished run of ikr15.ethz.ch in 238.148722 seconds +I should cleanup /home/users/nico/.tmp/tmpdefzkg +INFO: Finished run of ikr21.ethz.ch in 238.227193 seconds +I should cleanup /home/users/nico/.tmp/tmppsg0pc +INFO: Total processing time for 27 host(s): 238.478493 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr17.ethz.ch +INFO: Deploying to ikr16.ethz.ch +INFO: Deploying to ikr19.ethz.ch +INFO: Deploying to ikr20.ethz.ch +INFO: Deploying to ikr21.ethz.ch +INFO: Deploying to ikr23.ethz.ch +INFO: Deploying to ikr24.ethz.ch +INFO: Deploying to ikr25.ethz.ch +INFO: Deploying to ikr26.ethz.ch +INFO: Deploying to ikr27.ethz.ch +INFO: Deploying to ikr28.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +ERROR: Command failed: ssh root@ikr17.ethz.ch mkdir -p /var/lib/cdist/conf/type/__package_apt +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq04.ethz.ch in 215.567874 seconds +I should cleanup /home/users/nico/.tmp/tmp99c8j5 +INFO: Finished run of ikq06.ethz.ch in 219.752235 seconds +I should cleanup /home/users/nico/.tmp/tmpb1628u +INFO: Finished run of ikq07.ethz.ch in 221.491529 seconds +I should cleanup /home/users/nico/.tmp/tmpjr3i7w +INFO: Finished run of ikq02.ethz.ch in 222.054742 seconds +I should cleanup /home/users/nico/.tmp/tmpia1edb +INFO: Finished run of ikq03.ethz.ch in 229.509667 seconds +I should cleanup /home/users/nico/.tmp/tmpvdfr2q +INFO: Finished run of ikq05.ethz.ch in 231.337049 seconds +I should cleanup /home/users/nico/.tmp/tmpwz_8tv +E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem. +ERROR: Command failed: ssh root@ikr27.ethz.ch /var/lib/cdist/object/__package_apt/collectd/.cdist/code-remote +INFO: Finished run of ikr20.ethz.ch in 239.14496 seconds +I should cleanup /home/users/nico/.tmp/tmpx63vlh +INFO: Finished run of ikr02.ethz.ch in 241.402815 seconds +I should cleanup /home/users/nico/.tmp/tmp_bmfp_ +INFO: Finished run of ikr25.ethz.ch in 241.948038 seconds +I should cleanup /home/users/nico/.tmp/tmpohdpq5 +INFO: Finished run of ikr05.ethz.ch in 243.861596 seconds +I should cleanup /home/users/nico/.tmp/tmpr_vxd_ +INFO: Finished run of ikr19.ethz.ch in 244.322837 seconds +I should cleanup /home/users/nico/.tmp/tmpripuph +INFO: Finished run of ikr10.ethz.ch in 244.439443 seconds +I should cleanup /home/users/nico/.tmp/tmp8wacqr +INFO: Finished run of ikr14.ethz.ch in 244.572394 seconds +I should cleanup /home/users/nico/.tmp/tmpuw2ppx +INFO: Finished run of ikr26.ethz.ch in 244.781803 seconds +I should cleanup /home/users/nico/.tmp/tmpt_4vqo +INFO: Finished run of ikr23.ethz.ch in 244.916033 seconds +I should cleanup /home/users/nico/.tmp/tmp9lgge8 +INFO: Finished run of ikr03.ethz.ch in 245.12315 seconds +I should cleanup /home/users/nico/.tmp/tmpb072wd +INFO: Finished run of ikr16.ethz.ch in 245.353491 seconds +I should cleanup /home/users/nico/.tmp/tmpsq8pj3 +INFO: Finished run of ikr11.ethz.ch in 245.445685 seconds +I should cleanup /home/users/nico/.tmp/tmpsomf09 +INFO: Finished run of ikr07.ethz.ch in 245.47506 seconds +I should cleanup /home/users/nico/.tmp/tmppu7tq2 +INFO: Finished run of ikr09.ethz.ch in 245.576609 seconds +I should cleanup /home/users/nico/.tmp/tmpoliguo +INFO: Finished run of ikr15.ethz.ch in 245.57091 seconds +I should cleanup /home/users/nico/.tmp/tmpic_4ln +INFO: Finished run of ikr28.ethz.ch in 245.673558 seconds +I should cleanup /home/users/nico/.tmp/tmpceanz0 +INFO: Finished run of ikr21.ethz.ch in 245.785506 seconds +I should cleanup /home/users/nico/.tmp/tmphd9b_a +INFO: Finished run of ikr24.ethz.ch in 245.762761 seconds +I should cleanup /home/users/nico/.tmp/tmp6q4lt_ +INFO: Total processing time for 28 host(s): 246.058718 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr16.ethz.ch +INFO: Deploying to ikr17.ethz.ch +INFO: Deploying to ikr19.ethz.ch +INFO: Deploying to ikr20.ethz.ch +INFO: Deploying to ikr21.ethz.ch +INFO: Deploying to ikr23.ethz.ch +INFO: Deploying to ikr24.ethz.ch +INFO: Deploying to ikr25.ethz.ch +INFO: Deploying to ikr26.ethz.ch +INFO: Deploying to ikr27.ethz.ch +INFO: Deploying to ikr28.ethz.ch +INFO: Deploying to ikr29.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq06.ethz.ch in 235.403198 seconds +I should cleanup /home/users/nico/.tmp/tmplh0yub +INFO: Finished run of ikq03.ethz.ch in 237.3758 seconds +I should cleanup /home/users/nico/.tmp/tmpnwzceq +INFO: Finished run of ikq07.ethz.ch in 238.054173 seconds +I should cleanup /home/users/nico/.tmp/tmpezdl2v +INFO: Finished run of ikq02.ethz.ch in 240.123134 seconds +I should cleanup /home/users/nico/.tmp/tmph4zyv1 +INFO: Finished run of ikq04.ethz.ch in 240.240325 seconds +I should cleanup /home/users/nico/.tmp/tmp1hgnqr +INFO: Finished run of ikr07.ethz.ch in 255.212756 seconds +I should cleanup /home/users/nico/.tmp/tmpu4etp8 +E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem. +ERROR: Command failed: ssh root@ikr27.ethz.ch /var/lib/cdist/object/__package_apt/collectd/.cdist/code-remote +INFO: Finished run of ikr20.ethz.ch in 257.655047 seconds +I should cleanup /home/users/nico/.tmp/tmpraen0m +INFO: Finished run of ikr26.ethz.ch in 260.095529 seconds +I should cleanup /home/users/nico/.tmp/tmptw0mi2 +INFO: Finished run of ikq05.ethz.ch in 260.533335 seconds +I should cleanup /home/users/nico/.tmp/tmp8d93a8 +INFO: Finished run of ikr14.ethz.ch in 262.082391 seconds +I should cleanup /home/users/nico/.tmp/tmpcq9jn8 +INFO: Finished run of ikr09.ethz.ch in 262.202072 seconds +I should cleanup /home/users/nico/.tmp/tmpdvdnr6 +INFO: Finished run of ikr11.ethz.ch in 262.398554 seconds +I should cleanup /home/users/nico/.tmp/tmp78uy18 +INFO: Finished run of ikr17.ethz.ch in 262.513191 seconds +I should cleanup /home/users/nico/.tmp/tmpr97wjm +INFO: Finished run of ikr25.ethz.ch in 262.614397 seconds +I should cleanup /home/users/nico/.tmp/tmpjc9obd +INFO: Finished run of ikr02.ethz.ch in 263.127853 seconds +I should cleanup /home/users/nico/.tmp/tmpvkl1m9 +INFO: Finished run of ikr05.ethz.ch in 263.338641 seconds +I should cleanup /home/users/nico/.tmp/tmplyywfq +INFO: Finished run of ikr21.ethz.ch in 263.232372 seconds +I should cleanup /home/users/nico/.tmp/tmpatqdlm +INFO: Finished run of ikr15.ethz.ch in 263.457294 seconds +I should cleanup /home/users/nico/.tmp/tmprddqa0 +INFO: Finished run of ikr19.ethz.ch in 263.424671 seconds +I should cleanup /home/users/nico/.tmp/tmpq1ap51 +INFO: Finished run of ikr03.ethz.ch in 263.622373 seconds +I should cleanup /home/users/nico/.tmp/tmp_7rzac +INFO: Finished run of ikr16.ethz.ch in 263.564308 seconds +INFO: Finished run of ikr10.ethz.ch in 263.634145 seconds +I should cleanup /home/users/nico/.tmp/tmpspg21e +I should cleanup /home/users/nico/.tmp/tmpb1swlv +INFO: Finished run of ikr28.ethz.ch in 263.507415 seconds +I should cleanup /home/users/nico/.tmp/tmp54z8g_ +INFO: Finished run of ikr29.ethz.ch in 263.598878 seconds +I should cleanup /home/users/nico/.tmp/tmp2kr9cs +INFO: Finished run of ikr23.ethz.ch in 263.668785 seconds +I should cleanup /home/users/nico/.tmp/tmpxb7jsn +INFO: Finished run of ikr24.ethz.ch in 263.903858 seconds +I should cleanup /home/users/nico/.tmp/tmplikdv8 +INFO: Total processing time for 29 host(s): 264.208372 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr16.ethz.ch +INFO: Deploying to ikr19.ethz.ch +INFO: Deploying to ikr17.ethz.ch +INFO: Deploying to ikr20.ethz.ch +INFO: Deploying to ikr21.ethz.ch +INFO: Deploying to ikr24.ethz.ch +INFO: Deploying to ikr23.ethz.ch +INFO: Deploying to ikr25.ethz.ch +INFO: Deploying to ikr26.ethz.ch +INFO: Deploying to ikr27.ethz.ch +INFO: Deploying to ikr28.ethz.ch +INFO: Deploying to ikr29.ethz.ch +INFO: Deploying to ikr30.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq03.ethz.ch in 229.360922 seconds +I should cleanup /home/users/nico/.tmp/tmplykkga +INFO: Finished run of ikq02.ethz.ch in 231.154059 seconds +I should cleanup /home/users/nico/.tmp/tmppmmhz3 +INFO: Finished run of ikq04.ethz.ch in 233.577996 seconds +I should cleanup /home/users/nico/.tmp/tmppdxzl3 +INFO: Finished run of ikq07.ethz.ch in 237.22933 seconds +I should cleanup /home/users/nico/.tmp/tmpiomb4i +INFO: Finished run of ikq06.ethz.ch in 239.725816 seconds +I should cleanup /home/users/nico/.tmp/tmpqj3pl6 +E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem. +ERROR: Command failed: ssh root@ikr27.ethz.ch /var/lib/cdist/object/__package_apt/collectd/.cdist/code-remote +INFO: Finished run of ikr20.ethz.ch in 258.466225 seconds +I should cleanup /home/users/nico/.tmp/tmpve9wdi +INFO: Finished run of ikr14.ethz.ch in 259.177486 seconds +I should cleanup /home/users/nico/.tmp/tmp_d36bl +INFO: Finished run of ikr17.ethz.ch in 260.754277 seconds +I should cleanup /home/users/nico/.tmp/tmpv5frqn +INFO: Finished run of ikr11.ethz.ch in 261.107312 seconds +I should cleanup /home/users/nico/.tmp/tmp5oacup +INFO: Finished run of ikr05.ethz.ch in 261.154726 seconds +I should cleanup /home/users/nico/.tmp/tmpghnptx +INFO: Finished run of ikq05.ethz.ch in 262.048584 seconds +I should cleanup /home/users/nico/.tmp/tmpugqfjj +INFO: Finished run of ikr25.ethz.ch in 262.233978 seconds +I should cleanup /home/users/nico/.tmp/tmppf3xu8 +INFO: Finished run of ikr10.ethz.ch in 262.713893 seconds +I should cleanup /home/users/nico/.tmp/tmpu2nkra +INFO: Finished run of ikr19.ethz.ch in 263.068704 seconds +I should cleanup /home/users/nico/.tmp/tmpi_jrg4 +INFO: Finished run of ikr02.ethz.ch in 264.085429 seconds +I should cleanup /home/users/nico/.tmp/tmpu6hfym +INFO: Finished run of ikr03.ethz.ch in 264.10239 seconds +I should cleanup /home/users/nico/.tmp/tmpzj0tpo +INFO: Finished run of ikr09.ethz.ch in 264.294349 seconds +I should cleanup /home/users/nico/.tmp/tmpkeo6qa +INFO: Finished run of ikr26.ethz.ch in 264.343501 seconds +I should cleanup /home/users/nico/.tmp/tmpofeovc +INFO: Finished run of ikr15.ethz.ch in 264.650148 seconds +I should cleanup /home/users/nico/.tmp/tmp2tooi_ +INFO: Finished run of ikr24.ethz.ch in 264.585275 seconds +I should cleanup /home/users/nico/.tmp/tmpk0vvl3 +INFO: Finished run of ikr07.ethz.ch in 264.743286 seconds +I should cleanup /home/users/nico/.tmp/tmp9lk9_m +INFO: Finished run of ikr30.ethz.ch in 264.505029 seconds +I should cleanup /home/users/nico/.tmp/tmpygy8g0 +INFO: Finished run of ikr23.ethz.ch in 264.681778 seconds +I should cleanup /home/users/nico/.tmp/tmpgd7nqn +INFO: Finished run of ikr29.ethz.ch in 264.590897 seconds +I should cleanup /home/users/nico/.tmp/tmp7m95p2 +INFO: Finished run of ikr16.ethz.ch in 264.863193 seconds +I should cleanup /home/users/nico/.tmp/tmpzqsbdu +INFO: Finished run of ikr21.ethz.ch in 264.933458 seconds +I should cleanup /home/users/nico/.tmp/tmphlqu6i +INFO: Finished run of ikr28.ethz.ch in 265.162021 seconds +I should cleanup /home/users/nico/.tmp/tmplpjyze +INFO: Total processing time for 30 host(s): 265.560685 +INFO: Deploying to ikq02.ethz.ch +INFO: Deploying to ikq03.ethz.ch +INFO: Deploying to ikq04.ethz.ch +INFO: Deploying to ikq05.ethz.ch +INFO: Deploying to ikq07.ethz.ch +INFO: Deploying to ikq06.ethz.ch +INFO: Deploying to ikr01.ethz.ch +INFO: Deploying to ikr02.ethz.ch +INFO: Deploying to ikr03.ethz.ch +INFO: Deploying to ikr05.ethz.ch +INFO: Deploying to ikr07.ethz.ch +INFO: Deploying to ikr09.ethz.ch +INFO: Deploying to ikr10.ethz.ch +INFO: Deploying to ikr11.ethz.ch +INFO: Deploying to ikr13.ethz.ch +INFO: Deploying to ikr14.ethz.ch +INFO: Deploying to ikr15.ethz.ch +INFO: Deploying to ikr16.ethz.ch +INFO: Deploying to ikr17.ethz.ch +INFO: Deploying to ikr19.ethz.ch +INFO: Deploying to ikr20.ethz.ch +INFO: Deploying to ikr21.ethz.ch +INFO: Deploying to ikr23.ethz.ch +INFO: Deploying to ikr24.ethz.ch +INFO: Deploying to ikr25.ethz.ch +INFO: Deploying to ikr27.ethz.ch +INFO: Deploying to ikr26.ethz.ch +INFO: Deploying to ikr28.ethz.ch +INFO: Deploying to ikr29.ethz.ch +INFO: Deploying to ikr30.ethz.ch +INFO: Deploying to ikr31.ethz.ch +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr01.ethz.ch:/var/lib/cdist/conf/explorer +scp: /var/lib/cdist/conf/explorer: No such file or directory +ERROR: Command failed: scp -qr /home/users/nico/p/cdist-nutzung/conf/explorer root@ikr13.ethz.ch:/var/lib/cdist/conf/explorer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/collectd/collectd.conf: Recording requirement __package/collectd +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/nullmailer/remotes: Recording requirement __package/nullmailer +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto.pub: Recording requirement __directory/etc/ethz/autofs +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/openntpd/ntpd.conf: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/default/openntpd_rc_config: Recording requirement __package/openntpd +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/sudoers.d/systems: Recording requirement __package/sudo +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/syslog-ng/syslog-ng.conf: Recording requirement __package/syslog-ng +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __directory/etc/ethz/autofs +__file/etc/ethz/autofs/auto_home: Recording requirement __package/python-ldap +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/auto.master: Recording requirement __package/autofs +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __package/libnss-ldapd +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +__file/etc/nsswitch.conf: Recording requirement __file//etc/nslcd.conf +INFO: Finished run of ikq03.ethz.ch in 245.694879 seconds +I should cleanup /home/users/nico/.tmp/tmp0aaihh +INFO: Finished run of ikq07.ethz.ch in 248.839127 seconds +I should cleanup /home/users/nico/.tmp/tmp4tv23i +INFO: Finished run of ikq04.ethz.ch in 250.96365 seconds +I should cleanup /home/users/nico/.tmp/tmp9oaog8 +INFO: Finished run of ikq02.ethz.ch in 251.910723 seconds +I should cleanup /home/users/nico/.tmp/tmpcy7p6n +INFO: Finished run of ikq06.ethz.ch in 252.163352 seconds +I should cleanup /home/users/nico/.tmp/tmp74it6k +E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem. +ERROR: Command failed: ssh root@ikr27.ethz.ch /var/lib/cdist/object/__package_apt/collectd/.cdist/code-remote +E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem. +ERROR: Command failed: ssh root@ikr31.ethz.ch /var/lib/cdist/object/__package_apt/collectd/.cdist/code-remote +INFO: Finished run of ikr05.ethz.ch in 277.210317 seconds +I should cleanup /home/users/nico/.tmp/tmp34x6v6 +INFO: Finished run of ikr10.ethz.ch in 277.482534 seconds +I should cleanup /home/users/nico/.tmp/tmprellu1 +INFO: Finished run of ikr14.ethz.ch in 279.009467 seconds +I should cleanup /home/users/nico/.tmp/tmpxxp654 +INFO: Finished run of ikr20.ethz.ch in 279.292188 seconds +I should cleanup /home/users/nico/.tmp/tmpw5ck4p +INFO: Finished run of ikr21.ethz.ch in 279.423259 seconds +I should cleanup /home/users/nico/.tmp/tmpe94eay +INFO: Finished run of ikr25.ethz.ch in 279.533419 seconds +I should cleanup /home/users/nico/.tmp/tmpbdgd2g +INFO: Finished run of ikq05.ethz.ch in 279.9565 seconds +I should cleanup /home/users/nico/.tmp/tmp5opdkg +INFO: Finished run of ikr07.ethz.ch in 280.496576 seconds +I should cleanup /home/users/nico/.tmp/tmpmqujdo +INFO: Finished run of ikr26.ethz.ch in 280.333344 seconds +I should cleanup /home/users/nico/.tmp/tmp63f8d8 +INFO: Finished run of ikr29.ethz.ch in 280.291517 seconds +I should cleanup /home/users/nico/.tmp/tmpnqfqpz +INFO: Finished run of ikr15.ethz.ch in 281.228734 seconds +I should cleanup /home/users/nico/.tmp/tmp42p3g5 +INFO: Finished run of ikr17.ethz.ch in 281.222566 seconds +I should cleanup /home/users/nico/.tmp/tmpn97co2 +INFO: Finished run of ikr19.ethz.ch in 281.258219 seconds +I should cleanup /home/users/nico/.tmp/tmpdc5pcf +INFO: Finished run of ikr30.ethz.ch in 281.333785 seconds +I should cleanup /home/users/nico/.tmp/tmp8t0k25 +INFO: Finished run of ikr11.ethz.ch in 281.610303 seconds +I should cleanup /home/users/nico/.tmp/tmph9g41k +INFO: Finished run of ikr28.ethz.ch in 281.513334 seconds +I should cleanup /home/users/nico/.tmp/tmpj44fq4 +INFO: Finished run of ikr02.ethz.ch in 281.870902 seconds +I should cleanup /home/users/nico/.tmp/tmprmqa8b +INFO: Finished run of ikr24.ethz.ch in 281.668327 seconds +I should cleanup /home/users/nico/.tmp/tmpcglj4f +INFO: Finished run of ikr03.ethz.ch in 282.150378 seconds +INFO: Finished run of ikr16.ethz.ch in 282.022936 seconds +I should cleanup /home/users/nico/.tmp/tmpa5nbnv +I should cleanup /home/users/nico/.tmp/tmpkpwd2x +INFO: Finished run of ikr23.ethz.ch in 281.993304 seconds +I should cleanup /home/users/nico/.tmp/tmpw0ts8q +INFO: Finished run of ikr09.ethz.ch in 282.136105 seconds +I should cleanup /home/users/nico/.tmp/tmp882egu +INFO: Total processing time for 31 host(s): 282.264488 From 525fb7aa312f905a21970a42d8bc9916cf74613b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 14:42:06 +0200 Subject: [PATCH 0894/4212] +links of existing articles on slashdot without publishing Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-04-20.slashdot-articles | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 doc/dev/logs/2011-04-20.slashdot-articles diff --git a/doc/dev/logs/2011-04-20.slashdot-articles b/doc/dev/logs/2011-04-20.slashdot-articles new file mode 100644 index 00000000..24b3baf0 --- /dev/null +++ b/doc/dev/logs/2011-04-20.slashdot-articles @@ -0,0 +1,2 @@ +http://slashdot.org/submission/1533922/cdist-162---usable-configuration-management +http://slashdot.org/submission/1522134/Cdist-Configuration-management-that-makes-fun# From e715dbb8017de2401a85c105abe2a701cc00eaa6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 15:50:10 +0200 Subject: [PATCH 0895/4212] update test: dont return command output by default Signed-off-by: Steven Armstrong --- lib/cdist/test/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/test/exec/local.py b/lib/cdist/test/exec/local.py index 8585f87a..f19bf55c 100644 --- a/lib/cdist/test/exec/local.py +++ b/lib/cdist/test/exec/local.py @@ -114,7 +114,7 @@ class LocalTestCase(unittest.TestCase): fd = open(script, "w") fd.writelines(["#!/bin/sh\n", "echo foobar"]) fd.close() - self.assertEqual(self.local.run_script(script), "foobar\n") + self.assertEqual(self.local.run_script(script, return_output=True), "foobar\n") def test_mkdir(self): temp_dir = self.mkdtemp(dir=self.temp_dir) From ab1d3d16f16c94e42174ccdcedd791c69bb970c8 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 15:51:00 +0200 Subject: [PATCH 0896/4212] implement: dont return command output by default Signed-off-by: Steven Armstrong --- lib/cdist/exec/local.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index bef44e21..56c29cb7 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -87,7 +87,7 @@ class Local(object): # FIXME: dont set mode here, fix unittest mkdtemp instead os.makedirs(path, mode=0o700, exist_ok=True) - def run(self, command, env=None): + def run(self, command, env=None, return_output=False): """Run the given command with the given environment. Return the output as a string. @@ -95,13 +95,16 @@ class Local(object): assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %s" % command self.log.debug("Local run: %s", command) try: - return subprocess.check_output(command, env=env).decode() + if return_output: + return subprocess.check_output(command, env=env).decode() + else: + subprocess.check_call(command, env=env) except subprocess.CalledProcessError: raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: raise cdist.Error(" ".join(*args) + ": " + error.args[1]) - def run_script(self, script, env=None): + def run_script(self, script, env=None, return_output=False): """Run the given script with the given environment. Return the output as a string. @@ -114,7 +117,10 @@ class Local(object): self.log.debug("Local run script env: %s", env) try: - return subprocess.check_output(command, env=env).decode() + if return_output: + return subprocess.check_output(command, env=env).decode() + else: + subprocess.check_call(command, env=env) except subprocess.CalledProcessError as error: script_content = self.run(["cat", script]) self.log.error("Code that raised the error:\n%s", script_content) From 86cb65cd9ce81ba24ccfc420c7e80d6a3a6aefec Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 15:51:40 +0200 Subject: [PATCH 0897/4212] update test: dont return command output by default Signed-off-by: Steven Armstrong --- lib/cdist/test/exec/remote.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/test/exec/remote.py b/lib/cdist/test/exec/remote.py index ea9a17aa..f5151156 100644 --- a/lib/cdist/test/exec/remote.py +++ b/lib/cdist/test/exec/remote.py @@ -92,7 +92,7 @@ class RemoteTestCase(unittest.TestCase): fd = open(script, "w") fd.writelines(["#!/bin/sh\n", "echo foobar"]) fd.close() - self.assertEqual(self.remote.run_script(script), "foobar\n") + self.assertEqual(self.remote.run_script(script, return_output=True), "foobar\n") def test_mkdir(self): temp_dir = self.mkdtemp(dir=self.temp_dir) From 829b0b2d0b3faa10366d2c8fcd95b01f01093b74 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 15:52:16 +0200 Subject: [PATCH 0898/4212] implement: dont return command output by default Signed-off-by: Steven Armstrong --- lib/cdist/exec/remote.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 2ffc73fd..2de16426 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -85,7 +85,7 @@ class Remote(object): command.extend(["-r", source, self.target_host + ":" + destination]) self.run_command(command) - def run(self, command, env=None): + def run(self, command, env=None, return_output=False): """Run the given command with the given environment on the remote side. Return the output as a string. @@ -94,9 +94,9 @@ class Remote(object): cmd = self._exec.split() cmd.append(self.target_host) cmd.extend(command) - return self.run_command(cmd, env=env) + return self.run_command(cmd, env=env, return_output=return_output) - def run_command(self, command, env=None): + def run_command(self, command, env=None, return_output=False): """Run the given command with the given environment. Return the output as a string. @@ -113,13 +113,16 @@ class Remote(object): self.log.debug("Remote run: %s", command) try: - return subprocess.check_output(cmd).decode() + if return_output: + return subprocess.check_output(command, env=env).decode() + else: + subprocess.check_call(command, env=env) except subprocess.CalledProcessError: raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: raise cdist.Error(" ".join(*args) + ": " + error.args[1]) - def run_script(self, script, env=None): + def run_script(self, script, env=None, return_output=False): """Run the given script with the given environment on the remote side. Return the output as a string. @@ -140,7 +143,10 @@ class Remote(object): self.log.debug("Remote run script env: %s", env) try: - return subprocess.check_output(command).decode() + if return_output: + return subprocess.check_output(command, env=env).decode() + else: + subprocess.check_call(command, env=env) except subprocess.CalledProcessError as error: script_content = self.run(["cat", script]) self.log.error("Code that raised the error:\n%s", script_content) From 1e622f91280c57174db8eabfc00cbf0d61737404 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 15:52:53 +0200 Subject: [PATCH 0899/4212] raise IllegalRequirementError if requirements object_id starts with a / Signed-off-by: Steven Armstrong --- lib/cdist/emulator.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index f37c3169..0b303b23 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -28,6 +28,16 @@ from cdist import core log = logging.getLogger(__name__) + +class IllegalRequirementError(cdist.Error): + def __init__(self, requirement, message=None): + self.requirement = requirement + self.message = message or 'Illegal requirement' + + def __str__(self): + return '%s: %s' % (self.message, self.requirement) + + def run(argv): """Emulate type commands (i.e. __file and co)""" global_path = os.environ['__global'] @@ -116,7 +126,7 @@ def run(argv): # no object id, must be singleton requirement_object_id = 'singleton' if requirement_object_id.startswith('/'): - raise core.IllegalObjectIdError(requirement_object_id, requirement_type_name, 'object_id may not start with /') + raise IllegalRequirementError(requirement, 'requirements object_id may not start with /') log.debug("Recording requirement: %s -> %s" % (cdist_object.path, requirement)) cdist_object.requirements.append(requirement) From 63ad8825127cfa75f0ae74c25cf5538b596aab93 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 15:58:42 +0200 Subject: [PATCH 0900/4212] update test: run_code* should no longer return output Signed-off-by: Steven Armstrong --- lib/cdist/test/code/__init__.py | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index 0d7aec75..f661ad24 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -105,33 +105,11 @@ class CodeTestCase(unittest.TestCase): destination = os.path.join(self.remote.object_path, self.cdist_object.code_remote_path) self.assertTrue(os.path.isfile(destination)) - def test_run_code_local_environment(self): + def test_run_code_local(self): self.cdist_object.code_local = self.code.run_gencode_local(self.cdist_object) - output_string = self.code.run_code_local(self.cdist_object) - output_dict = {} - for line in output_string.split('\n'): - if line: - key,value = line.split(': ') - 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['__type'], self.cdist_type.absolute_path) - self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) - self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) - self.assertEqual(output_dict['__object_fq'], self.cdist_object.path) + self.code.run_code_local(self.cdist_object) def test_run_code_remote_environment(self): self.cdist_object.code_remote = self.code.run_gencode_remote(self.cdist_object) self.code.transfer_code_remote(self.cdist_object) - output_string = self.code.run_code_remote(self.cdist_object) - output_dict = {} - for line in output_string.split('\n'): - if line: - key,value = line.split(': ') - 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['__type'], self.cdist_type.absolute_path) - self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) - self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) - self.assertEqual(output_dict['__object_fq'], self.cdist_object.path) + self.code.run_code_remote(self.cdist_object) From c9bb10551820c4b2f8017ea290791d500d34716a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 15:59:58 +0200 Subject: [PATCH 0901/4212] run_code* no longer returns output Signed-off-by: Steven Armstrong --- lib/cdist/core/code.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index af756263..e81f7954 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -104,7 +104,7 @@ class Code(object): '__object_id': cdist_object.object_id, '__object_fq': cdist_object.path, }) - return self.local.run_script(script, env=env) + return self.local.run_script(script, env=env, return_output=True) def run_gencode_local(self, cdist_object): """Run the gencode-local script for the given cdist object.""" From bbef928a6d02a43efb11a855b0951fd4db3d6381 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 16:04:55 +0200 Subject: [PATCH 0902/4212] --copy paste error Signed-off-by: Steven Armstrong --- lib/cdist/exec/remote.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 2de16426..e1d9f920 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -114,9 +114,9 @@ class Remote(object): self.log.debug("Remote run: %s", command) try: if return_output: - return subprocess.check_output(command, env=env).decode() + return subprocess.check_output(command).decode() else: - subprocess.check_call(command, env=env) + subprocess.check_call(command) except subprocess.CalledProcessError: raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: @@ -144,9 +144,9 @@ class Remote(object): try: if return_output: - return subprocess.check_output(command, env=env).decode() + return subprocess.check_output(command).decode() else: - subprocess.check_call(command, env=env) + subprocess.check_call(command) except subprocess.CalledProcessError as error: script_content = self.run(["cat", script]) self.log.error("Code that raised the error:\n%s", script_content) From c30e112e4a2773bee50bc440e1a740fbc2465fff Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 16:07:50 +0200 Subject: [PATCH 0903/4212] explorer: make tests pass again Signed-off-by: Steven Armstrong --- lib/cdist/core/explorer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index ee1008fe..46230bcd 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -88,7 +88,7 @@ class Explorer(object): def run_global_explorer(self, explorer): """Run the given global explorer and return it's output.""" script = os.path.join(self.remote.global_explorer_path, explorer) - return self.remote.run_script(script, env=self.env) + return self.remote.run_script(script, env=self.env, return_output=True) ### type @@ -126,4 +126,4 @@ class Explorer(object): '__type_explorer': os.path.join(self.remote.type_path, cdist_type.explorer_path) }) script = os.path.join(self.remote.type_path, cdist_type.explorer_path, explorer) - return self.remote.run_script(script, env=env) + return self.remote.run_script(script, env=env, return_output=True) From d1930e983cb3d0f32d08c10813974e886680d364 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 16:14:04 +0200 Subject: [PATCH 0904/4212] update test: run_*_manifest should no longer return output Signed-off-by: Steven Armstrong --- lib/cdist/test/manifest/__init__.py | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index 341f4893..879c4c1a 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -63,33 +63,9 @@ class ManifestTestCase(unittest.TestCase): def test_initial_manifest_environment(self): initial_manifest = os.path.join(self.local.manifest_path, "dump_environment") - output_string = self.manifest.run_initial_manifest(initial_manifest) - output_dict = {} - for line in output_string.split('\n'): - if line: - key,value = line.split(': ') - output_dict[key] = value - self.assertTrue(output_dict['PATH'].startswith(self.local.bin_path)) - self.assertEqual(output_dict['__target_host'], self.local.target_host) - self.assertEqual(output_dict['__global'], self.local.out_path) - self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) - self.assertEqual(output_dict['__manifest'], self.local.manifest_path) + self.manifest.run_initial_manifest(initial_manifest) def test_type_manifest_environment(self): cdist_type = core.Type(self.local.type_path, '__dump_environment') cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') - - output_string = self.manifest.run_type_manifest(cdist_object) - output_dict = {} - for line in output_string.split('\n'): - if line: - key,value = line.split(': ') - output_dict[key] = value - self.assertTrue(output_dict['PATH'].startswith(self.local.bin_path)) - self.assertEqual(output_dict['__target_host'], self.local.target_host) - self.assertEqual(output_dict['__global'], self.local.out_path) - self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) - self.assertEqual(output_dict['__type'], cdist_type.absolute_path) - self.assertEqual(output_dict['__object'], cdist_object.absolute_path) - self.assertEqual(output_dict['__object_id'], cdist_object.object_id) - self.assertEqual(output_dict['__object_fq'], cdist_object.path) + self.manifest.run_type_manifest(cdist_object) From f723bede109b3352f099179d0a4bc61df5090c99 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 16:14:39 +0200 Subject: [PATCH 0905/4212] no longer return output from run_*_manifest Signed-off-by: Steven Armstrong --- lib/cdist/core/manifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index 93eb6f2d..3eca166c 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -80,7 +80,7 @@ class Manifest(object): env.update(self.env) env['__manifest'] = self.local.manifest_path env['__cdist_manifest'] = script - return self.local.run_script(script, env=env) + self.local.run_script(script, env=env) def run_type_manifest(self, cdist_object): script = os.path.join(self.local.type_path, cdist_object.type.manifest_path) @@ -94,4 +94,4 @@ class Manifest(object): '__type': cdist_object.type.absolute_path, '__cdist_manifest': script, }) - return self.local.run_script(script, env=env) + self.local.run_script(script, env=env) From eac3cc31c46d26a0a0d3e5f786ba266a29268c17 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 16:33:56 +0200 Subject: [PATCH 0906/4212] export __debug in environment Signed-off-by: Steven Armstrong --- lib/cdist/context.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index cf314409..ed1fd31d 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -41,6 +41,8 @@ class Context(object): debug=False): self.debug = debug + if self.debug: + os.environ['__debug'] = 'yes' self.target_host = target_host From c24b20de0871eab0b6e2334a2479898db4dbef2d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 16:42:14 +0200 Subject: [PATCH 0907/4212] make nico happy Signed-off-by: Steven Armstrong --- lib/cdist/context.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index ed1fd31d..cf314409 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -41,8 +41,6 @@ class Context(object): debug=False): self.debug = debug - if self.debug: - os.environ['__debug'] = 'yes' self.target_host = target_host From 92ff7e630da8882cf1c67e043ff5eef89c3e9ea4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 21:50:16 +0200 Subject: [PATCH 0908/4212] add banner to tests again Signed-off-by: Nico Schottelius --- .../test_banner.py => lib/cdist/test/banner/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename other/tests_reintegrate/test_banner.py => lib/cdist/test/banner/__init__.py (100%) diff --git a/other/tests_reintegrate/test_banner.py b/lib/cdist/test/banner/__init__.py similarity index 100% rename from other/tests_reintegrate/test_banner.py rename to lib/cdist/test/banner/__init__.py From 422800ab9898332f7f9ef7e88579b03425770fe6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 22:45:23 +0200 Subject: [PATCH 0909/4212] get back some constants needed for testing Signed-off-by: Nico Schottelius --- lib/cdist/test/__init__.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/cdist/test/__init__.py b/lib/cdist/test/__init__.py index e69de29b..2c6abd36 100644 --- a/lib/cdist/test/__init__.py +++ b/lib/cdist/test/__init__.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# +# 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 + +cdist_base_path = os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../")) + +cdist_exec_path = os.path.join(cdist_base_path, "bin/cdist") From dd05a9b0d75196f5b7154a46a2ea6f23febded8d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 23:02:47 +0200 Subject: [PATCH 0910/4212] add test to verify code setups debug env Signed-off-by: Nico Schottelius --- lib/cdist/test/code/__init__.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index f661ad24..c9761a4b 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -24,6 +24,7 @@ import tempfile import unittest import shutil import getpass +import logging import cdist from cdist import core @@ -46,25 +47,27 @@ class CodeTestCase(unittest.TestCase): return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) def setUp(self): - target_host = 'localhost' + self.target_host = 'localhost' self.local_base_path = local_base_path self.out_path = self.mkdtemp() - self.local = local.Local(target_host, self.local_base_path, self.out_path) + self.local = local.Local(self.target_host, self.local_base_path, self.out_path) self.local.create_directories() self.remote_base_path = self.mkdtemp() self.user = getpass.getuser() remote_exec = "ssh -o User=%s -q" % self.user remote_copy = "scp -o User=%s -q" % self.user - self.remote = remote.Remote(target_host, self.remote_base_path, remote_exec, remote_copy) + self.remote = remote.Remote(self.target_host, self.remote_base_path, remote_exec, remote_copy) - self.code = code.Code(target_host, self.local, self.remote) + self.code = code.Code(self.target_host, self.local, self.remote) self.cdist_type = core.Type(self.local.type_path, '__dump_environment') self.cdist_object = core.Object(self.cdist_type, self.local.object_path, 'whatever') self.cdist_object.create() + self.log = logging.getLogger("cdist") + def tearDown(self): shutil.rmtree(self.out_path) shutil.rmtree(self.remote_base_path) @@ -108,8 +111,13 @@ class CodeTestCase(unittest.TestCase): def test_run_code_local(self): self.cdist_object.code_local = self.code.run_gencode_local(self.cdist_object) self.code.run_code_local(self.cdist_object) - + def test_run_code_remote_environment(self): self.cdist_object.code_remote = self.code.run_gencode_remote(self.cdist_object) self.code.transfer_code_remote(self.cdist_object) self.code.run_code_remote(self.cdist_object) + + def test_debug_env_setup(self): + self.log.setLevel(logging.DEBUG) + code = cdist.core.code.Code(self.target_host, self.local, self.remote) + self.assertTrue("__debug" in code.env) From bc85237eaab020ee71e44b31822693b5312e0871 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 23:04:19 +0200 Subject: [PATCH 0911/4212] make code setup debug env Signed-off-by: Nico Schottelius --- doc/man/cdist-reference.text.sh | 2 +- lib/cdist/core/code.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 7196c3b3..57dbde4a 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -170,7 +170,7 @@ __debug:: If this variable is setup, cdist runs in debug mode. You can use this information, to only output stuff in debug mode as well. - Available for: initial manifest, type manifest + Available for: initial manifest, type manifest, gencode, code __explorer:: Directory that contains all global explorers. Available for: explorer diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index e81f7954..0f2591b3 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -92,6 +92,9 @@ class Code(object): '__global': self.local.out_path, } + if log.getEffectiveLevel() == logging.DEBUG: + self.env.update({'__debug': "yes" }) + def _run_gencode(self, cdist_object, which): cdist_type = cdist_object.type script = os.path.join(self.local.type_path, getattr(cdist_type, 'gencode_%s_path' % which)) From db04ec0473eab51115ee31cbac6a936b940633b1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 23:11:57 +0200 Subject: [PATCH 0912/4212] test whether debug is setup in explorer env Signed-off-by: Nico Schottelius --- lib/cdist/test/explorer/__init__.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index 3b3a7e98..a3a0c9f8 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -24,6 +24,7 @@ import tempfile import unittest import shutil import getpass +import logging import cdist from cdist import core @@ -46,20 +47,22 @@ class ExplorerClassTestCase(unittest.TestCase): return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) def setUp(self): - target_host = 'localhost' + self.target_host = 'localhost' self.local_base_path = local_base_path self.out_path = self.mkdtemp() - self.local = local.Local(target_host, self.local_base_path, self.out_path) + self.local = local.Local(self.target_host, self.local_base_path, self.out_path) self.local.create_directories() self.remote_base_path = self.mkdtemp() self.user = getpass.getuser() remote_exec = "ssh -o User=%s -q" % self.user remote_copy = "scp -o User=%s -q" % self.user - self.remote = remote.Remote(target_host, self.remote_base_path, remote_exec, remote_copy) + self.remote = remote.Remote(self.target_host, self.remote_base_path, remote_exec, remote_copy) - self.explorer = explorer.Explorer(target_host, self.local, self.remote) + self.explorer = explorer.Explorer(self.target_host, self.local, self.remote) + + self.log = logging.getLogger("cdist") def tearDown(self): shutil.rmtree(self.out_path) @@ -109,3 +112,7 @@ class ExplorerClassTestCase(unittest.TestCase): output = self.explorer.run_type_explorer('world', cdist_object) self.assertEqual(output, 'hello\n') + def test_debug_env_setup(self): + self.log.setLevel(logging.DEBUG) + explorer = cdist.core.explorer.Explorer(self.target_host, self.local, self.remote) + self.assertTrue("__debug" in explorer.env) From 02934055e749ea2fe3406842b8ef6d76351a6ab4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 23:14:05 +0200 Subject: [PATCH 0913/4212] make debug test work for explorer Signed-off-by: Nico Schottelius --- lib/cdist/core/explorer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 46230bcd..9dd5d210 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -73,6 +73,8 @@ class Explorer(object): '__target_host': self.target_host, '__explorer': self.remote.global_explorer_path, } + if log.getEffectiveLevel() == logging.DEBUG: + self.env.update({'__debug': "yes" }) ### global From f80520090bad3968742974d0607e3a7c82ad1d98 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 23:14:49 +0200 Subject: [PATCH 0914/4212] remove obsolete global_explorer Signed-off-by: Nico Schottelius --- lib/cdist/core/global_explorer.py | 59 ------------------------------- 1 file changed, 59 deletions(-) delete mode 100644 lib/cdist/core/global_explorer.py diff --git a/lib/cdist/core/global_explorer.py b/lib/cdist/core/global_explorer.py deleted file mode 100644 index fe0ea018..00000000 --- a/lib/cdist/core/global_explorer.py +++ /dev/null @@ -1,59 +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 io -import logging -import os -#import stat -#import shutil -#import sys -#import tempfile -#import time -# -#import cdist.exec - -import cdist - -log = logging.getLogger(__name__) - -class GlobalExplorer(object): - def __init__(self, local_path, remote_path): - self.local_path = local_path - self.remote_path = remote_path - - def run(self): - """Run global explorers""" - log.info("Running global explorers") - - outputs = {} - for explorer in os.listdir(src_path): - outputs[explorer] = io.StringIO() - cmd = [] - cmd.append("__explorer=" + remote_dst_path) - cmd.append(os.path.join(remote_dst_path, explorer)) - cdist.exec.run_or_fail(cmd, stdout=outputs[explorer], remote_prefix=True) - - def transfer(self): - """Transfer the global explorers""" - self.remote_mkdir(self.remote_global_explorer_path) - self.transfer_path(self.global_explorer_path, - self.remote_global_explorer_path) From df8be73c109499f406ac0f6d1a4d1fb91f0f5257 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 23:18:58 +0200 Subject: [PATCH 0915/4212] test for debug in manifest Signed-off-by: Nico Schottelius --- lib/cdist/test/manifest/__init__.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index 879c4c1a..86885a59 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -26,9 +26,7 @@ import getpass import shutil import string import random - -#import logging -#logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s') +import logging import cdist from cdist.exec import local @@ -51,12 +49,13 @@ class ManifestTestCase(unittest.TestCase): def setUp(self): self.temp_dir = self.mkdtemp() - target_host = 'localhost' + self.target_host = 'localhost' out_path = self.temp_dir - self.local = local.Local(target_host, local_base_path, out_path) + self.local = local.Local(self.target_host, local_base_path, out_path) self.local.create_directories() self.local.link_emulator(cdist.test.cdist_exec_path) - self.manifest = manifest.Manifest(target_host, self.local) + self.manifest = manifest.Manifest(self.target_host, self.local) + self.log = logging.getLogger("cdist") def tearDown(self): shutil.rmtree(self.temp_dir) @@ -69,3 +68,8 @@ class ManifestTestCase(unittest.TestCase): cdist_type = core.Type(self.local.type_path, '__dump_environment') cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') self.manifest.run_type_manifest(cdist_object) + + def test_debug_env_setup(self): + self.log.setLevel(logging.DEBUG) + manifest = cdist.core.manifest.Manifest(self.target_host, self.local) + self.assertTrue("__debug" in manifest.env) From ba59339f67efda5f8f2a81870e25a99b6153146d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 23:21:22 +0200 Subject: [PATCH 0916/4212] fixup code and manifest Signed-off-by: Nico Schottelius --- lib/cdist/core/manifest.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index 3eca166c..f031ac35 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -74,6 +74,9 @@ class Manifest(object): '__global': self.local.out_path, '__cdist_type_base_path': self.local.type_path, # for use in type emulator } + if log.getEffectiveLevel() == logging.DEBUG: + self.env.update({'__debug': "yes" }) + def run_initial_manifest(self, script): env = os.environ.copy() From 57f4aae2a1c427417f6eb68bde11dc469b651e7b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 23:23:44 +0200 Subject: [PATCH 0917/4212] --obsolete files Signed-off-by: Nico Schottelius --- lib/cdist/exec.py | 96 ------------- lib/cdist/manifest.py | 272 ------------------------------------- lib/cdist/type_explorer.py | 118 ---------------- 3 files changed, 486 deletions(-) delete mode 100644 lib/cdist/exec.py delete mode 100644 lib/cdist/manifest.py delete mode 100644 lib/cdist/type_explorer.py diff --git a/lib/cdist/exec.py b/lib/cdist/exec.py deleted file mode 100644 index a2282347..00000000 --- a/lib/cdist/exec.py +++ /dev/null @@ -1,96 +0,0 @@ -# -*- coding: utf-8 -*- -# -# 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 logging -import subprocess - -import cdist - - -class Wrapper(object): - def __init__(self, target_host, remote_exec, remote_copy): - self.target_host = target_host - self.remote_exec = remote_exec - self.remote_copy = remote_copy - self.log = logging.getLogger(self.target_host) - - def remote_mkdir(self, directory): - """Create directory on remote side""" - self.run_or_fail(["mkdir", "-p", directory], remote=True) - - def remove_remote_path(self, destination): - """Ensure path on remote side vanished""" - self.run_or_fail(["rm", "-rf", destination], remote=True) - - def transfer_path(self, source, destination): - """Transfer directory and previously delete the remote destination""" - self.remove_remote_path(destination) - self.run_or_fail(self.remote_copy.split() + - ["-r", source, self.target_host + ":" + destination]) - - def shell_run_or_debug_fail(self, script, *args, remote=False, **kargs): - # Manually execute /bin/sh, because sh -e does what we want - # and sh -c -e does not exit if /bin/false called - args[0][:0] = [ "/bin/sh", "-e" ] - - if remote: - remote_prefix = self.remote_exec.split() - remote_prefix.append(self.target_host) - args[0][:0] = remote_prefix - - self.log.debug("Shell exec cmd: %s", args) - - if 'env' in kargs: - self.log.debug("Shell exec env: %s", kargs['env']) - - try: - subprocess.check_call(*args, **kargs) - except subprocess.CalledProcessError: - self.log.error("Code that raised the error:\n") - - if remote: - self.run_or_fail(["cat", script], remote=remote) - - else: - try: - script_fd = open(script) - print(script_fd.read()) - script_fd.close() - except IOError as error: - raise cdist.Error(str(error)) - - raise cdist.Error("Command failed (shell): " + " ".join(*args)) - except OSError as error: - raise cdist.Error(" ".join(*args) + ": " + error.args[1]) - - def run_or_fail(self, *args, remote=False, **kargs): - if remote: - remote_prefix = self.remote_exec.split() - remote_prefix.append(self.target_host) - args[0][:0] = remote_prefix - - self.log.debug("Exec: " + " ".join(*args)) - try: - subprocess.check_call(*args, **kargs) - except subprocess.CalledProcessError: - raise cdist.Error("Command failed: " + " ".join(*args)) - except OSError as error: - raise cdist.Error(" ".join(*args) + ": " + error.args[1]) diff --git a/lib/cdist/manifest.py b/lib/cdist/manifest.py deleted file mode 100644 index ab5f7284..00000000 --- a/lib/cdist/manifest.py +++ /dev/null @@ -1,272 +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 logging -import os -import stat -import shutil -import sys -import tempfile -import time - -import cdist.core -import cdist.exec - -CODE_HEADER = "#!/bin/sh -e\n" - -class ConfigInstall: - """Cdist main class to hold arbitrary data""" - - def __init__(self, - target_host, - initial_manifest=False, - base_path=False, - exec_path=sys.argv[0], - debug=False): - - self.context = cdist.context.Context( - target_host=target_host, - initial_manifest=initial_manifest, - base_path=base_path, - exec_path=sys.argv[0], - debug=debug) - - - - self.exec_wrapper = cdist.exec.Wrapper( - targe_host = self.target_host, - remote_exec=os.environ['__remote_exec'].split(), - remote_copy=os.environ['__remote_copy'].split() - ) - - self.log = logging.getLogger(self.context.target_host) - - # Setup env to be used by others - FIXME - self.__init_env() - - # Create directories - self.__init_local_paths() - self.__init_remote_paths() - - def __init_remote_paths(self): - """Initialise remote directory structure""" - self.remove_remote_path(self.context.remote_base_path) - self.remote_mkdir(self.context.remote_base_path) - self.remote_mkdir(self.context.remote_conf_path) - - def __init_local_paths(self): - """Initialise local directory structure""" - - # Create base dir, if user supplied and not existing - if not os.path.isdir(self.context.base_path): - os.mkdir(self.context.base_path) - - # FIXME: raise more beautiful exception / Steven: handle exception - os.mkdir(self.out_path) - os.mkdir(self.global_explorer_out_path) - os.mkdir(self.bin_path) - - # FIXME: remove this function, only expose ENV - # explicitly! - def __init_env(self): - """Environment usable for other stuff""" - os.environ['__target_host'] = self.target_host - if self.debug: - os.environ['__debug'] = "yes" - - def cleanup(self): - self.context.cleanup() - - def run_initial_manifest(self): - """Run the initial manifest""" - log.info("Running initial manifest %s", self.initial_manifest) - env = { "__manifest" : self.manifest_path } - self.run_manifest(self.initial_manifest, extra_env=env) - - def run_type_manifest(self, cdist_object): - """Run manifest for a specific object""" - cdist_type = cdist_object.type - manifest_path = os.path.join(self.type_base_path, - cdist_type.manifest_path) - - log.debug("%s: Running %s", cdist_object.name, manifest_path) - if os.path.exists(manifest_path): - env = { "__object" : os.path.join(self.object_base_path, - cdist_object.path), - "__object_id": cdist_object.object_id, - "__object_fq": cdist_object.name, - "__type": os.path.join(self.type_base_path, - cdist_type.path) - } - self.run_manifest(manifest_path, extra_env=env) - - def run_manifest(self, manifest_path, extra_env=None): - """Run a manifest""" - log.debug("Running manifest %s, env=%s", manifest_path, extra_env) - env = os.environ.copy() - env['PATH'] = self.bin_path + ":" + env['PATH'] - - # Information required in every manifest - env['__target_host'] = self.target_host - env['__global'] = self.out_path - - # Required for recording source in emulator - env['__cdist_manifest'] = manifest_path - - # Required to find types in emulator - env['__cdist_type_base_path'] = self.type_base_path - - # Other environment stuff - if extra_env: - env.update(extra_env) - - cdist.exec.shell_run_or_debug_fail(manifest_path, [manifest_path], env=env) - - def object_prepare(self, cdist_object): - """Prepare object: Run type explorer + manifest""" - log.debug("Preparing object: " + cdist_object.name) - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) - cdist_object.prepared = True - - def object_run(self, cdist_object): - """Run gencode and code for an object""" - log.debug("Running object %s", cdist_object) - - # Catch requirements, which re-call us - if cdist_object.ran: - return - - cdist_type = cdist_object.type - - for requirement in cdist_object.requirements: - log.debug("Object %s requires %s", cdist_object, requirement) - self.object_run(requirement) - - # - # Setup env Variable: - # - env = os.environ.copy() - env['__target_host'] = self.target_host - env['__global'] = self.out_path - env["__object"] = os.path.join(self.object_base_path, cdist_object.path) - env["__object_id"] = cdist_object.object_id - env["__object_fq"] = cdist_object.name - env["__type"] = cdist_type.name - - # gencode - for cmd in ["local", "remote"]: - bin = os.path.join(self.type_base_path, - getattr(cdist_type, "gencode_" + cmd + "_path")) - - if os.path.isfile(bin): - outfile = os.path.join(self.object_base_path, - getattr(cdist_object, "code_" + cmd + "_path")) - - outfile_fd = open(outfile, "w") - - # Need to flush to ensure our write is done before stdout write - # FIXME: code header still needed? - outfile_fd.write(CODE_HEADER) - outfile_fd.flush() - - cdist.exec.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd) - outfile_fd.close() - - status = os.stat(outfile) - - # Remove output if empty, else make it executable - if status.st_size == len(CODE_HEADER): - os.unlink(outfile) - else: - # Add header and make executable - identically to 0o700 - os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) - cdist_object.changed=True - - # code local - code_local = cdist_object.code_local_path - if os.path.isfile(code_local): - cdist.exec.run_or_fail([code_local]) - - # code remote - local_remote_code = os.path.join(self.object_base_path, - cdist_object.code_remote_path) - remote_remote_code = os.path.join(self.remote_object_path, - cdist_object.code_remote_path) - if os.path.isfile(local_remote_code): - self.transfer_path(local_remote_code, remote_remote_code) - cdist.exec.run_or_fail([remote_remote_code], remote_prefix=True) - - cdist_object.ran = True - - def link_emulator(self): - """Link emulator to types""" - src = os.path.abspath(self.exec_path) - for cdist_type in cdist.core.Type.list_types(self.type_base_path): - dst = os.path.join(self.bin_path, cdist_type.name) - log.debug("Linking emulator: %s to %s", src, dst) - - # FIXME: handle exception / make it more beautiful / Steven: raise except :-) - os.symlink(src, dst) - - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" - log.info("Deploying to " + self.target_host) - self.stage_prepare() - self.stage_run() - - def deploy_and_cleanup(self): - """Do what is most often done: deploy & cleanup""" - start_time = time.time() - self.deploy_to() - self.cleanup() - log.info("Finished run of %s in %s seconds", - self.target_host, time.time() - start_time) - - def stage_prepare(self): - """Do everything for a deploy, minus the actual code stage""" - self.link_emulator() - self.run_global_explorers() - self.run_initial_manifest() - - 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 cdist.core.Object.list_objects(self.object_base_path, - self.type_base_path): - if cdist_object.prepared: - log.debug("Skipping rerun of object %s", cdist_object) - continue - else: - self.object_prepare(cdist_object) - new_objects_created = True - - def stage_run(self): - """The final (and real) step of deployment""" - log.info("Generating and executing code") - for cdist_object in cdist.core.Object.list_objects(self.object_base_path, - self.type_base_path): - log.debug("Run object: %s", cdist_object) - self.object_run(cdist_object) diff --git a/lib/cdist/type_explorer.py b/lib/cdist/type_explorer.py deleted file mode 100644 index 9e3c99bf..00000000 --- a/lib/cdist/type_explorer.py +++ /dev/null @@ -1,118 +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 io -import logging -import os -#import stat -#import shutil -#import sys -#import tempfile -#import time -# -#import cdist.exec - -import cdist - -# FIXME: Logging with hostname -log = logging.getLogger(__name__) - -class TypeExplorer(object): - def __init__(self, - remote_global_explorer_path, - object_base_path, - type_base_path, - remote_object_base_path, - remote_type_base_path - ): - - self.object_base_path = object_base_path - self.global_explorer_path = global_explorer_path - self.type_base_path = type_base_path - self.remote_type_base_path = remote_type_base_path - self.remote_object_path = remote_object_path - - def run(self, cdist_object): - """Run type specific explorers for objects""" - - cdist_type = cdist_object.type - - cmd = [] - cmd.append("__explorer=" + self.remote_global_explorer_path) - cmd.append("__type_explorer=" + os.path.join( - self.remote_type_path, - cdist_type.explorer_path)) - cmd.append("__object=" + os.path.join( - self.remote_object_base_path, - cdist_object.path)) - cmd.append("__object_id=" + cdist_object.object_id) - cmd.append("__object_fq=" + cdist_object.name) - - outputs = {} - for explorer in cdist_type.explorers: - remote_cmd = cmd + [os.path.join(self.remote_type_path, - cdist_type.explorer_path, explorer)] - outputs[explorer] = io.StringIO() - log.debug("%s exploring %s using %s storing to %s", - cdist_object, explorer, remote_cmd, output) - - # FIXME: change to new style - cdist.exec.run_or_fail(remote_cmd, stdout=outputs[explorer], - remote_prefix=True) - - return outputs - - def transfer_object_parameter(self, cdist_object): - """Transfer the object parameter to the remote destination""" - src = os.path.join(self.object_base_path, - cdist_object.parameter_path) - dst = os.path.join(self.remote_object_base_path, - cdist_object.parameter_path) - - # FIXME: new style - # Synchronise parameter dir afterwards - self.remote_mkdir(dst) - self.transfer_path(src, dst) - - def transfer_type_explorers(self, cdist_type): - """Transfer explorers of a type, but only once""" - if cdist_type.transferred_explorers: - log.debug("Skipping retransfer for explorers of %s", cdist_type) - return - else: - log.debug("Ensure no retransfer for %s", cdist_type) - # Do not retransfer - cdist_type.transferred_explorers = True - - explorers = cdist_type.explorers - - if len(explorers) > 0: - rel_path = cdist_type.explorer_path - src = os.path.join(self.type_base_path, rel_path) - dst = os.path.join(self.remote_type_path, rel_path) - - # Ensure full path until type exists: - # /var/lib/cdist/conf/type/__directory/explorer - # /var/lib/cdist/conf/type/__directory may not exist, - # but remote_mkdir uses -p to fix this - self.remote_mkdir(dst) - self.transfer_path(src, dst) From 2a0f7512b7c689ae11a5dfc18dbbe9787ea5fad9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 23:27:55 +0200 Subject: [PATCH 0918/4212] add full output of error Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-14.error-output | 46 ++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 doc/dev/logs/2011-10-14.error-output diff --git a/doc/dev/logs/2011-10-14.error-output b/doc/dev/logs/2011-10-14.error-output new file mode 100644 index 00000000..4414de13 --- /dev/null +++ b/doc/dev/logs/2011-10-14.error-output @@ -0,0 +1,46 @@ +[23:24] brief:cdist% ./bin/cdist config -c ~/p/cdist-nutzung -v ikq04.ethz.ch +INFO: ikq04.ethz.ch: Deploying to ikq04.ethz.ch +INFO: ikq04.ethz.ch: Running object manifests and type explorers +cat: /home/users/nico/.tmp/tmpf969y2/out/object/__addifnosuchline/ssh-root-blukas/.cdist/parameter/line: No such file or directory +#!/bin/sh +# +# 2010-2011 Daniel Roth (dani-cdist@d-roth.li) +# +# 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/file" ]; then + file=$(cat "$__object/parameter/file") +else + file="/$__object_id" +fi + +regex=$(cat "$__object/parameter/line") +if [ -f "$file" ]; then + grep -q "^$regex\$" "$file" + if [ $? -eq 1 ]; then + echo "NOTFOUND" + else + echo "FOUND" + fi +else + echo "NOTFOUND" +fi +ERROR: ikq04.ethz.ch: Code that raised the error: +None +ERROR: Remote script execution failed: /var/lib/cdist/conf/type/__addifnosuchline/explorer/findline ['ssh', '-o', 'User=root', '-q', 'ikq04.ethz.ch', '__explorer=/var/lib/cdist/conf/explorer', '__object_fq=__addifnosuchline/ssh-root-blukas/.cdist', '__target_host=ikq04.ethz.ch', '__object_id=ssh-root-blukas', '__type_explorer=/var/lib/cdist/conf/type/__addifnosuchline/explorer', '__object=/home/users/nico/.tmp/tmpf969y2/out/object/__addifnosuchline/ssh-root-blukas/.cdist', '/bin/sh', '-e', '/var/lib/cdist/conf/type/__addifnosuchline/explorer/findline'] +[23:25] brief:cdist% From c38959699f5cbd23809e6e6516a8eac3d4982cfc Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 23:42:16 +0200 Subject: [PATCH 0919/4212] test for: transfer_type_explorers_only_once Signed-off-by: Steven Armstrong --- lib/cdist/test/explorer/__init__.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index a3a0c9f8..e6858812 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -95,6 +95,20 @@ class ExplorerClassTestCase(unittest.TestCase): destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) self.assertEqual(os.listdir(source), os.listdir(destination)) + def test_transfer_type_explorers_only_once(self): + cdist_type = core.Type(self.local.type_path, '__test_type') + # first transfer + self.explorer.transfer_type_explorers(cdist_type) + source = os.path.join(self.local.type_path, cdist_type.explorer_path) + destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) + self.assertEqual(os.listdir(source), os.listdir(destination)) + # nuke destination folder content, but recreate directory + shutil.rmtree(destination) + os.makedirs(destination) + # second transfer, should not happen + self.explorer.transfer_type_explorers(cdist_type) + self.assertFalse(os.listdir(destination)) + def test_transfer_object_parameters(self): cdist_type = core.Type(self.local.type_path, '__test_type') cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') From 814b46f0c7f5a26a200b8fe01a8a292b127da02c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 23:44:27 +0200 Subject: [PATCH 0920/4212] /transfered_explorers/explorers_transferred/ Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index 8cf21ce7..6c3cd757 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -67,7 +67,7 @@ class Type(object): self.gencode_remote_path = os.path.join(self.name, "gencode-remote") self.manifest_path = os.path.join(self.name, "manifest") - self.transferred_explorers = False + self.explorers_transferred = False self.__explorers = None self.__required_parameters = None From 325a13088cfc80765644e30eebbe77b8087aacdc Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 23:47:05 +0200 Subject: [PATCH 0921/4212] implement that type explorers are only transfered once Signed-off-by: Steven Armstrong --- lib/cdist/core/explorer.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 9dd5d210..7a868b31 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -105,10 +105,14 @@ class Explorer(object): def transfer_type_explorers(self, cdist_type): """Transfer the type explorers for the given type to the remote side.""" if cdist_type.explorers: - source = os.path.join(self.local.type_path, cdist_type.explorer_path) - destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) - self.remote.mkdir(destination) - self.remote.transfer(source, destination) + if cdist_type.explorers_transferred: + log.debug("Skipping retransfer of type explorers for: %s", cdist_type) + else: + source = os.path.join(self.local.type_path, cdist_type.explorer_path) + destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) + self.remote.mkdir(destination) + self.remote.transfer(source, destination) + cdist_type.explorers_transferred = True def transfer_object_parameters(self, cdist_object): """Transfer the parameters for the given object to the remote side.""" From 1e31721ad995144f03614a261517ce8156f9a9bb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 23:50:31 +0200 Subject: [PATCH 0922/4212] BUGFIX: remote path for explorer in __object variable Signed-off-by: Nico Schottelius --- lib/cdist/core/explorer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 9dd5d210..14a66ff4 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -122,7 +122,7 @@ class Explorer(object): cdist_type = cdist_object.type env = self.env.copy() env.update({ - '__object': cdist_object.absolute_path, + '__object': os.path.join(self.remote.object_path, cdist_object.path), '__object_id': cdist_object.object_id, '__object_fq': cdist_object.path, '__type_explorer': os.path.join(self.remote.type_path, cdist_type.explorer_path) From 9223663136f8b9a90d20eb58a9b67ae2f4cf1c5a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 23:51:01 +0200 Subject: [PATCH 0923/4212] CLEANUP: return flat name, not python list to user Signed-off-by: Nico Schottelius --- lib/cdist/exec/local.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index 56c29cb7..59f1ee4d 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -40,7 +40,8 @@ class LocalScriptError(cdist.Error): self.script_content = script_content def __str__(self): - return "Local script execution failed: %s %s" % (self.script, self.command) + plain_command = " ".join(self.command) + return "Local script execution failed: %s %s" % (self.script, plain_command) class Local(object): From b5b7d8e7271602e0289fe392bfd831be9b3dd38e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 14 Oct 2011 23:52:05 +0200 Subject: [PATCH 0924/4212] add missing return_output=True argument when fetching script content Signed-off-by: Steven Armstrong --- lib/cdist/exec/local.py | 2 +- lib/cdist/exec/remote.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index 56c29cb7..679d847b 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -122,7 +122,7 @@ class Local(object): else: subprocess.check_call(command, env=env) except subprocess.CalledProcessError as error: - script_content = self.run(["cat", script]) + script_content = self.run(["cat", script], return_output=True) self.log.error("Code that raised the error:\n%s", script_content) raise LocalScriptError(script, command, script_content) except EnvironmentError as error: diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index e1d9f920..9610290b 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -148,7 +148,7 @@ class Remote(object): else: subprocess.check_call(command) except subprocess.CalledProcessError as error: - script_content = self.run(["cat", script]) + script_content = self.run(["cat", script], return_output=True) self.log.error("Code that raised the error:\n%s", script_content) raise RemoteScriptError(script, command, script_content) except EnvironmentError as error: From ef1ebbd0b747e8495422e50c510ce83469f1945e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 23:56:33 +0200 Subject: [PATCH 0925/4212] remove senseless message superseeded by new logging prefix Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 72ff7c6c..f843167b 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -62,7 +62,6 @@ class ConfigInstall(object): def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" - self.log.info("Deploying to " + self.context.target_host) self.stage_prepare() self.stage_run() From 85c9c3e28339c1b84d71c4981c53afed58e419b5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Oct 2011 23:57:58 +0200 Subject: [PATCH 0926/4212] more changes for next release Signed-off-by: Nico Schottelius --- doc/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/changelog b/doc/changelog index 3540498e..04679bec 100644 --- a/doc/changelog +++ b/doc/changelog @@ -2,6 +2,9 @@ * Improved logging, added --verbose, by more quiet by default * Bugfix __user: Correct quoting (Steven Armstrong) * Bugfix requirements: Restore original require="" behaviour + * Feature requirements: Check for broken object_ids and abort + * Massive refactoring and unittesting introduced (Steven Armstrong) + * Feature: Initial undocumented support for replacing the remote exec and remote copy commands * Feature: Initial undocumented support for installations in core From 3f76f03239b6fd9aca43e5a1b0714994ae0fb77b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 00:10:35 +0200 Subject: [PATCH 0927/4212] return full command only in local mode Signed-off-by: Nico Schottelius --- lib/cdist/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index ad31a909..6157c0bc 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -41,7 +41,7 @@ class LocalScriptError(cdist.Error): def __str__(self): plain_command = " ".join(self.command) - return "Local script execution failed: %s %s" % (self.script, plain_command) + return "Local script execution failed: %s" % plain_command class Local(object): From 0d441eb378af97c4d4a73c8f024cba4d582caa58 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 00:12:08 +0200 Subject: [PATCH 0928/4212] report info when running initial manifest (it may take some time) Signed-off-by: Nico Schottelius --- lib/cdist/core/manifest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index f031ac35..8f9903a5 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -83,6 +83,7 @@ class Manifest(object): env.update(self.env) env['__manifest'] = self.local.manifest_path env['__cdist_manifest'] = script + log.info("Running initial manifest " + self.local.manifest_path) self.local.run_script(script, env=env) def run_type_manifest(self, cdist_object): From db6fdeebfe7db928e69a8297ee418ad863eec6b0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 00:14:25 +0200 Subject: [PATCH 0929/4212] log.info for global explorers (may also take some time) Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index f843167b..ce7c5736 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -97,6 +97,7 @@ class ConfigInstall(object): def run_global_explorers(self): """Run global explorers and save output""" # FIXME: move to explorer, pass global_explorer_out_path as argument + self.log.info("Running global explorers") self.explorer.transfer_global_explorers() for explorer in self.explorer.list_global_explorer_names(): output = self.explorer.run_global_explorer(explorer) From cba202186e70d17f15eb62a571d7ba52675df6f5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 00:16:34 +0200 Subject: [PATCH 0930/4212] missing prefix documented Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-15.prefix-output-missing | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 doc/dev/logs/2011-10-15.prefix-output-missing diff --git a/doc/dev/logs/2011-10-15.prefix-output-missing b/doc/dev/logs/2011-10-15.prefix-output-missing new file mode 100644 index 00000000..05788fd5 --- /dev/null +++ b/doc/dev/logs/2011-10-15.prefix-output-missing @@ -0,0 +1,10 @@ +Prefix is missing in some parts for a run, they all need to include +the hostname (required for clean parallel processing) + +[0:13] brief:cdist% ./bin/cdist config -c ~/p/cdist-nutzung -v ikq04.ethz.ch +INFO: ikq04.ethz.ch: Running global explorers +INFO: Running initial manifest /home/users/nico/p/cdist-nutzung/conf/manifest +INFO: ikq04.ethz.ch: Running object manifests and type explorers +ERROR: requirements object_id may not start with /: __file//etc/nslcd.conf +ERROR: ikq04.ethz.ch: Code that raised the error: + From c64ab97f2a592ed782cee0d888c3341fef10d14a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 00:25:55 +0200 Subject: [PATCH 0931/4212] irrrrrrgs, ugly output Signed-off-by: Nico Schottelius --- ...011-10-15.ugly-output-on-breaking-explorer | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 doc/dev/logs/2011-10-15.ugly-output-on-breaking-explorer diff --git a/doc/dev/logs/2011-10-15.ugly-output-on-breaking-explorer b/doc/dev/logs/2011-10-15.ugly-output-on-breaking-explorer new file mode 100644 index 00000000..921f0c90 --- /dev/null +++ b/doc/dev/logs/2011-10-15.ugly-output-on-breaking-explorer @@ -0,0 +1,43 @@ +[0:15] brief:cdist% ./bin/cdist config -c ~/p/cdist-nutzung -v ikq04.ethz.ch +INFO: ikq04.ethz.ch: Running global explorers +INFO: Running initial manifest /home/users/nico/p/cdist-nutzung/conf/manifest +INFO: ikq04.ethz.ch: Running object manifests and type explorers +/var/lib/cdist/conf/type/__file/explorer/.exists.swp: 1: Syntax error: ")" unexpected +Traceback (most recent call last): + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/lib/cdist/exec/remote.py", line 147, in run_script + return subprocess.check_output(command).decode() + File "/usr/lib/python3.2/subprocess.py", line 518, in check_output + raise CalledProcessError(retcode, cmd, output=output) +subprocess.CalledProcessError: Command '['ssh', '-o', 'User=root', '-q', 'ikq04.ethz.ch', '__explorer=/var/lib/cdist/conf/explorer', '__object_fq=__file/etc/cdist-configured/.cdist', '__target_host=ikq04.ethz.ch', '__object_id=etc/cdist-configured', '__type_explorer=/var/lib/cdist/conf/type/__file/explorer', '__object=/var/lib/cdist/object/__file/etc/cdist-configured/.cdist', '/bin/sh', '-e', '/var/lib/cdist/conf/type/__file/explorer/.exists.swp']' returned non-zero exit status 2 + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "./bin/cdist", line 161, in + commandline() + File "./bin/cdist", line 103, in commandline + args.func(args) + File "./bin/cdist", line 106, in config + configinstall(args, mode=cdist.config.Config) + File "./bin/cdist", line 133, in configinstall + c.deploy_and_cleanup() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/lib/cdist/config_install.py", line 71, in deploy_and_cleanup + self.deploy_to() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/lib/cdist/config_install.py", line 65, in deploy_to + self.stage_prepare() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/lib/cdist/config_install.py", line 94, in stage_prepare + self.object_prepare(cdist_object) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/lib/cdist/config_install.py", line 122, in object_prepare + self.run_type_explorers(cdist_object) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/lib/cdist/config_install.py", line 115, in run_type_explorers + output = self.explorer.run_type_explorer(explorer, cdist_object) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/lib/cdist/core/explorer.py", line 135, in run_type_explorer + return self.remote.run_script(script, env=env, return_output=True) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/lib/cdist/exec/remote.py", line 151, in run_script + script_content = self.run(["cat", script], return_output=True) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/lib/cdist/exec/remote.py", line 97, in run + return self.run_command(cmd, env=env, return_output=return_output) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/lib/cdist/exec/remote.py", line 117, in run_command + return subprocess.check_output(command).decode() +UnicodeDecodeError: 'utf8' codec can't decode byte 0xb6 in position 17: invalid start byte + From d83de257749c7b5d080f8c0bf1fba0496319afd0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 15 Oct 2011 00:26:00 +0200 Subject: [PATCH 0932/4212] Stripp leading slash from requirements object_id Signed-off-by: Steven Armstrong --- lib/cdist/emulator.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 0b303b23..f861dfda 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -125,8 +125,10 @@ def run(argv): except IndexError: # no object id, must be singleton requirement_object_id = 'singleton' + # strip leading slash from object_id if requirement_object_id.startswith('/'): - raise IllegalRequirementError(requirement, 'requirements object_id may not start with /') + log.debug("Stripping leading slash from requirements object_id: %s", requirement) + requirement_object_id = requirement_object_id.lstrip('/') log.debug("Recording requirement: %s -> %s" % (cdist_object.path, requirement)) cdist_object.requirements.append(requirement) From 889e6c23cba937eef5106554521def5e5a486f77 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 15 Oct 2011 00:44:54 +0200 Subject: [PATCH 0933/4212] Explorer tracks which type explorers have been transferred instad of Type Signed-off-by: Steven Armstrong --- lib/cdist/core/explorer.py | 5 +++-- lib/cdist/core/type.py | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 90201072..f2bfc153 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -75,6 +75,7 @@ class Explorer(object): } if log.getEffectiveLevel() == logging.DEBUG: self.env.update({'__debug': "yes" }) + self._type_explorers_transferred = [] ### global @@ -105,14 +106,14 @@ class Explorer(object): def transfer_type_explorers(self, cdist_type): """Transfer the type explorers for the given type to the remote side.""" if cdist_type.explorers: - if cdist_type.explorers_transferred: + if cdist_type.name in self._type_explorers_transferred: log.debug("Skipping retransfer of type explorers for: %s", cdist_type) else: source = os.path.join(self.local.type_path, cdist_type.explorer_path) destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) self.remote.mkdir(destination) self.remote.transfer(source, destination) - cdist_type.explorers_transferred = True + self._type_explorers_transferred.append(cdist_type.name) def transfer_object_parameters(self, cdist_object): """Transfer the parameters for the given object to the remote side.""" diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index 6c3cd757..ce37769e 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -54,6 +54,7 @@ class Type(object): if not name in cls._instances: instance = super(Type, cls).__new__(cls) cls._instances[name] = instance + # return instance so __init__ is called return cls._instances[name] def __init__(self, base_path, name): @@ -67,8 +68,6 @@ class Type(object): self.gencode_remote_path = os.path.join(self.name, "gencode-remote") self.manifest_path = os.path.join(self.name, "manifest") - self.explorers_transferred = False - self.__explorers = None self.__required_parameters = None self.__optional_parameters = None From ad1e51cb2e75799831ed8d89ce1c2bc2bb8ac43a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 01:11:54 +0200 Subject: [PATCH 0934/4212] catch unicodedecodeerror Signed-off-by: Nico Schottelius --- lib/cdist/exec/remote.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 9610290b..c876adf1 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -40,6 +40,13 @@ class RemoteScriptError(cdist.Error): def __str__(self): return "Remote script execution failed: %s %s" % (self.script, self.command) +class DecodeError(cdist.Error): + def __init__(self, command): + self.command = command + + def __str__(self): + return "Cannot decode output of " + " ".join(self.command) + class Remote(object): """Execute commands remotely. @@ -121,6 +128,8 @@ class Remote(object): raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: raise cdist.Error(" ".join(*args) + ": " + error.args[1]) + except UnicodeDecodeError: + raise DecodeError(command) def run_script(self, script, env=None, return_output=False): """Run the given script with the given environment on the remote side. From 67b109471257b11dc3d5c2b6bc844d0bcc2bb2c8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 01:25:57 +0200 Subject: [PATCH 0935/4212] flatten error message in remotescripterror as well Signed-off-by: Nico Schottelius --- lib/cdist/exec/remote.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index c876adf1..943b8992 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -38,7 +38,8 @@ class RemoteScriptError(cdist.Error): self.script_content = script_content def __str__(self): - return "Remote script execution failed: %s %s" % (self.script, self.command) + plain_command = " ".join(self.command) + return "Remote script execution failed: %s" % plain_command class DecodeError(cdist.Error): def __init__(self, command): From a415cc4b91e531ac6eb5a53c578403fd878d480c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 01:38:22 +0200 Subject: [PATCH 0936/4212] add correct logger in manifest Signed-off-by: Nico Schottelius --- lib/cdist/core/manifest.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index 8f9903a5..50964fdc 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -25,9 +25,6 @@ import os import cdist -log = logging.getLogger(__name__) - - ''' common: runs only locally, does not need remote @@ -68,13 +65,16 @@ class Manifest(object): def __init__(self, target_host, local): self.target_host = target_host self.local = local + + self.log = logging.getLogger(self.target_host) + self.env = { 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), '__target_host': self.target_host, '__global': self.local.out_path, '__cdist_type_base_path': self.local.type_path, # for use in type emulator } - if log.getEffectiveLevel() == logging.DEBUG: + if self.log.getEffectiveLevel() == logging.DEBUG: self.env.update({'__debug': "yes" }) @@ -83,7 +83,7 @@ class Manifest(object): env.update(self.env) env['__manifest'] = self.local.manifest_path env['__cdist_manifest'] = script - log.info("Running initial manifest " + self.local.manifest_path) + self.log.info("Running initial manifest " + self.local.manifest_path) self.local.run_script(script, env=env) def run_type_manifest(self, cdist_object): From 00a1f1eeb9b7c718eb451e366d7d42a8ecc9c6c0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 01:41:11 +0200 Subject: [PATCH 0937/4212] ++ more host prefixing log code Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 4 ++-- lib/cdist/core/explorer.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index ce7c5736..a71998f7 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -70,8 +70,8 @@ class ConfigInstall(object): start_time = time.time() self.deploy_to() self.cleanup() - self.log.info("Finished run of %s in %s seconds", - self.context.target_host, time.time() - start_time) + self.log.info("Finished run in %s seconds", + time.time() - start_time) def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 90201072..b4f8531e 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -25,9 +25,6 @@ import os import cdist -log = logging.getLogger(__name__) - - ''' common: runs only remotely, needs local and remote to construct paths @@ -67,13 +64,16 @@ class Explorer(object): """ def __init__(self, target_host, local, remote): self.target_host = target_host + + self.log = logging.getLogger(target_host) + self.local = local self.remote = remote self.env = { '__target_host': self.target_host, '__explorer': self.remote.global_explorer_path, } - if log.getEffectiveLevel() == logging.DEBUG: + if self.log.getEffectiveLevel() == logging.DEBUG: self.env.update({'__debug': "yes" }) ### global @@ -106,7 +106,7 @@ class Explorer(object): """Transfer the type explorers for the given type to the remote side.""" if cdist_type.explorers: if cdist_type.explorers_transferred: - log.debug("Skipping retransfer of type explorers for: %s", cdist_type) + self.log.debug("Skipping retransfer of type explorers for: %s", cdist_type) else: source = os.path.join(self.local.type_path, cdist_type.explorer_path) destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) From e002710c4c8170a8a5e144b3bf559b3ba8eb4a91 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 02:31:40 +0200 Subject: [PATCH 0938/4212] rewrite emulator to class based approach for better logging Signed-off-by: Nico Schottelius --- bin/cdist | 7 +- lib/cdist/emulator.py | 191 ++++++++++++++++++++++++------------------ 2 files changed, 116 insertions(+), 82 deletions(-) diff --git a/bin/cdist b/bin/cdist index 88cdf399..4d93842e 100755 --- a/bin/cdist +++ b/bin/cdist @@ -145,6 +145,10 @@ def configinstall(args, mode): log.info("Total processing time for %s host(s): %s", len(args.host), (time_end - time_start)) +def emulator(): + """Prepare and run emulator""" + emulator = cdist.emulator.Emulator(sys.argv) + emulator.run() if __name__ == "__main__": try: @@ -152,7 +156,8 @@ if __name__ == "__main__": if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): import cdist.emulator - cdist.emulator.run(sys.argv) + + emulator() else: import cdist.banner import cdist.config diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 0b303b23..edf7ab1c 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -26,8 +26,6 @@ import os import cdist from cdist import core -log = logging.getLogger(__name__) - class IllegalRequirementError(cdist.Error): def __init__(self, requirement, message=None): @@ -37,100 +35,131 @@ class IllegalRequirementError(cdist.Error): def __str__(self): return '%s: %s' % (self.message, self.requirement) +class Emulator(object): + def __init__(self, argv): + self.argv = argv + self.object_id = False -def run(argv): - """Emulate type commands (i.e. __file and co)""" - global_path = os.environ['__global'] - object_source = os.environ['__cdist_manifest'] - target_host = os.environ['__target_host'] - type_name = os.path.basename(argv[0]) + self.global_path = os.environ['__global'] + self.object_source = os.environ['__cdist_manifest'] + self.target_host = os.environ['__target_host'] + self.type_base_path = os.environ['__cdist_type_base_path'] + + self.object_base_path = os.path.join(self.global_path, "object") - # Logsetup - FIXME: add object_fq as soon as setup! - #id = target_host + ": " + cdist_type + '/' + object_id - id = target_host + ": " - # logformat = '%(levelname)s: ' + target_host + ": " + cdist_type + '/' + object_id + ': %(message)s' - logformat = '%(levelname)s: ' + id + ': %(message)s' - logging.basicConfig(format=logformat) + self.type_name = os.path.basename(argv[0]) + self.cdist_type = core.Type(self.type_base_path, self.type_name) - if '__debug' in os.environ: - logging.root.setLevel(logging.DEBUG) - else: - logging.root.setLevel(logging.INFO) + self.__init_log() - object_base_path = os.path.join(global_path, "object") - type_base_path = os.environ['__cdist_type_base_path'] - cdist_type = core.Type(type_base_path, type_name) + def filter(self, record): + """Add hostname and object to logs via logging Filter""" - if '__install' in os.environ: - if not cdist_type.is_install: - log.debug("Running in install mode, ignoring non install type") - return True + prefix = self.target_host + ": " - parser = argparse.ArgumentParser(add_help=False) + if self.object_id: + prefix = prefix + self.type_name + "/" + self.object_id - for parameter in cdist_type.optional_parameters: - argument = "--" + parameter - parser.add_argument(argument, action='store', required=False) - for parameter in cdist_type.required_parameters: - argument = "--" + parameter - parser.add_argument(argument, action='store', required=True) + record.msg = prefix + ": " + record.msg - # If not singleton support one positional parameter - if not cdist_type.is_singleton: - parser.add_argument("object_id", nargs=1) + return True - # And finally verify parameter - args = parser.parse_args(argv[1:]) + def run(self): + """Emulate type commands (i.e. __file and co)""" - # Setup object_id - if cdist_type.is_singleton: - object_id = "singleton" - else: - object_id = args.object_id[0] - del args.object_id + if '__install' in os.environ: + if not self.cdist_type.is_install: + self.log.debug("Running in install mode, ignoring non install type") + return True - # strip leading slash from object_id - object_id = object_id.lstrip('/') + self.commandline() + self.setup_object() + self.record_requirements() + self.log.debug("Finished %s %s" % (self.cdist_object.path, self.parameters)) - # Instantiate the cdist object whe are defining - cdist_object = core.Object(cdist_type, object_base_path, object_id) + def __init_log(self): + """Setup logging facility""" + logformat = '%(levelname)s: %(message)s' + logging.basicConfig(format=logformat) - # FIXME: verify object id - log.debug('#### emulator args: %s' % args) + if '__debug' in os.environ: + logging.root.setLevel(logging.DEBUG) + else: + logging.root.setLevel(logging.INFO) - # Create object with given parameters - parameters = {} - for key,value in vars(args).items(): - if value is not None: - parameters[key] = value - - if cdist_object.exists: - if cdist_object.parameters != parameters: - raise cdist.Error("Object %s already exists with conflicting parameters:\n%s: %s\n%s: %s" - % (cdist_object, " ".join(cdist_object.source), cdist_object.parameters, object_source, parameters) + self.log = logging.getLogger(__name__) + self.log.addFilter(self) + + def commandline(self): + """Parse command line""" + + parser = argparse.ArgumentParser(add_help=False) + + for parameter in self.cdist_type.optional_parameters: + argument = "--" + parameter + parser.add_argument(argument, action='store', required=False) + for parameter in self.cdist_type.required_parameters: + argument = "--" + parameter + parser.add_argument(argument, action='store', required=True) + + # If not singleton support one positional parameter + if not self.cdist_type.is_singleton: + parser.add_argument("object_id", nargs=1) + + # And finally parse/verify parameter + self.args = parser.parse_args(self.argv[1:]) + self.log.debug('Emulator args: %s' % self.args) + + + def setup_object(self): + # FIXME: verify object id + + # Setup object_id + if self.cdist_type.is_singleton: + self.object_id = "singleton" + else: + self.object_id = self.args.object_id[0] + del self.args.object_id + + # strip leading slash from object_id + self.object_id = self.object_id.lstrip('/') + + # Instantiate the cdist object we are defining + self.cdist_object = core.Object(self.cdist_type, self.object_base_path, self.object_id) + + # Create object with given parameters + self.parameters = {} + for key,value in vars(self.args).items(): + if value is not None: + self.parameters[key] = value + + if self.cdist_object.exists: + if cdist_object.parameters != self.parameters: + raise cdist.Error("Object %s already exists with conflicting parameters:\n%s: %s\n%s: %s" + % (self.cdist_object, " ".join(self.cdist_object.source), self.cdist_object.parameters, self.object_source, self.parameters) ) - else: - cdist_object.create() - cdist_object.parameters = parameters + else: + self.cdist_object.create() + self.cdist_object.parameters = self.parameters - # Record requirements - if "require" in os.environ: - requirements = os.environ['require'] - for requirement in requirements.split(" "): - requirement_parts = requirement.split(os.sep, 1) - requirement_parts.reverse() - requirement_type_name = requirement_parts.pop() - try: - requirement_object_id = requirement_parts.pop() - except IndexError: - # no object id, must be singleton - requirement_object_id = 'singleton' - if requirement_object_id.startswith('/'): - raise IllegalRequirementError(requirement, 'requirements object_id may not start with /') - log.debug("Recording requirement: %s -> %s" % (cdist_object.path, requirement)) - cdist_object.requirements.append(requirement) + def record_requirements(self): + """record requirements""" - # Record / Append source - cdist_object.source.append(object_source) + if "require" in os.environ: + requirements = os.environ['require'] + for requirement in requirements.split(" "): + requirement_parts = requirement.split(os.sep, 1) + requirement_parts.reverse() + requirement_type_name = requirement_parts.pop() + try: + requirement_object_id = requirement_parts.pop() + except IndexError: + # no object id, must be singleton + requirement_object_id = 'singleton' + if requirement_object_id.startswith('/'): + raise IllegalRequirementError(requirement, 'requirements object_id may not start with /') + self.log.debug("Recording requirement: %s -> %s" % (self.cdist_object.path, requirement)) + self.cdist_object.requirements.append(requirement) - log.debug("Finished %s %s" % (cdist_object.path, parameters)) + # Record / Append source + self.cdist_object.source.append(self.object_source) From a7a3ee6f1908575dbe5d06b9ced6432acd7ffdea Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 02:36:33 +0200 Subject: [PATCH 0939/4212] adjust prefix Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index edf7ab1c..a5e9d306 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -55,10 +55,10 @@ class Emulator(object): def filter(self, record): """Add hostname and object to logs via logging Filter""" - prefix = self.target_host + ": " + prefix = self.target_host + ": (emulator)" if self.object_id: - prefix = prefix + self.type_name + "/" + self.object_id + prefix = prefix + " " + self.type_name + "/" + self.object_id record.msg = prefix + ": " + record.msg @@ -108,7 +108,7 @@ class Emulator(object): # And finally parse/verify parameter self.args = parser.parse_args(self.argv[1:]) - self.log.debug('Emulator args: %s' % self.args) + self.log.debug('Args: %s' % self.args) def setup_object(self): From 0dd38f75c28a8745259b1086a5e46e7d040edfc5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 02:46:28 +0200 Subject: [PATCH 0940/4212] remove leading / from object_id of requirement Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index a5e9d306..3aa8ab14 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -156,8 +156,8 @@ class Emulator(object): except IndexError: # no object id, must be singleton requirement_object_id = 'singleton' - if requirement_object_id.startswith('/'): - raise IllegalRequirementError(requirement, 'requirements object_id may not start with /') + + requirement_object_id = requirement_object_id.lstrip('/') self.log.debug("Recording requirement: %s -> %s" % (self.cdist_object.path, requirement)) self.cdist_object.requirements.append(requirement) From ee1c568c7bf832806e8201f1b0a15c4a7ce7eb52 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 02:54:54 +0200 Subject: [PATCH 0941/4212] almost finish correct requirement loading, but need sleep Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 7 ++- other/tests_reintegrate/test_exec.py | 79 ---------------------------- 2 files changed, 5 insertions(+), 81 deletions(-) delete mode 100644 other/tests_reintegrate/test_exec.py diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 3aa8ab14..70f491ac 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -148,8 +148,12 @@ class Emulator(object): if "require" in os.environ: requirements = os.environ['require'] for requirement in requirements.split(" "): + self.log.debug("Recording requirement: " + requirement) requirement_parts = requirement.split(os.sep, 1) - requirement_parts.reverse() + # FIXME: continue here + FAILHERE,PLEASE()[]! + print(requirement) + print(requirement_parts) requirement_type_name = requirement_parts.pop() try: requirement_object_id = requirement_parts.pop() @@ -158,7 +162,6 @@ class Emulator(object): requirement_object_id = 'singleton' requirement_object_id = requirement_object_id.lstrip('/') - self.log.debug("Recording requirement: %s -> %s" % (self.cdist_object.path, requirement)) self.cdist_object.requirements.append(requirement) # Record / Append source diff --git a/other/tests_reintegrate/test_exec.py b/other/tests_reintegrate/test_exec.py deleted file mode 100644 index c2bb52f6..00000000 --- a/other/tests_reintegrate/test_exec.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 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 shutil -import tempfile -import unittest - -import cdist.exec - - -class ExecTestCase(unittest.TestCase): - def setUp(self): - """Create shell code and co.""" - - self.temp_dir = tempfile.mkdtemp() - self.shell_false = os.path.join(self.temp_dir, "shell_false") - self.shell_true = os.path.join(self.temp_dir, "shell_true") - - true_fd = open(self.shell_true, "w") - true_fd.writelines(["#!/bin/sh\n", "/bin/true"]) - true_fd.close() - - false_fd = open(self.shell_false, "w") - false_fd.writelines(["#!/bin/sh\n", "/bin/false"]) - false_fd.close() - - target_host = "does.not.exist" - remote_exec = "ssh -o User=root -q" - remote_copy = "scp -o User=root -q" - self.wrapper = cdist.exec.Wrapper(target_host, remote_exec, remote_copy) - - def tearDown(self): - shutil.rmtree(self.temp_dir) - - def test_local_success_shell(self): - try: - self.wrapper.shell_run_or_debug_fail(self.shell_true, [self.shell_true]) - except cdist.Error: - failed = True - else: - failed = False - self.assertFalse(failed) - - def test_local_fail_shell(self): - self.assertRaises(cdist.Error, self.wrapper.shell_run_or_debug_fail, - self.shell_false, [self.shell_false]) - - def test_local_success(self): - try: - self.wrapper.run_or_fail(["/bin/true"]) - except cdist.Error: - failed = True - else: - failed = False - self.assertFalse(failed) - - def test_local_fail(self): - self.assertRaises(cdist.Error, self.wrapper.run_or_fail, ["/bin/false"]) From 053903bb694043607cc540d972c5ecfd5b483a84 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 12:00:46 +0200 Subject: [PATCH 0942/4212] use instance logger in explorer Signed-off-by: Nico Schottelius --- lib/cdist/core/explorer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 0ca7188b..2e13cc78 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -107,7 +107,7 @@ class Explorer(object): """Transfer the type explorers for the given type to the remote side.""" if cdist_type.explorers: if cdist_type.name in self._type_explorers_transferred: - log.debug("Skipping retransfer of type explorers for: %s", cdist_type) + self.log.debug("Skipping retransfer of type explorers for: %s", cdist_type) else: source = os.path.join(self.local.type_path, cdist_type.explorer_path) destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) From 92de3d2f101db1bfd3828b33b29c806c7bf90d0d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 23:23:30 +0200 Subject: [PATCH 0943/4212] need cdist module for various constens Signed-off-by: Nico Schottelius --- bin/cdist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/cdist b/bin/cdist index 4d93842e..5ea6c6ce 100755 --- a/bin/cdist +++ b/bin/cdist @@ -33,6 +33,8 @@ log = logging.getLogger("cdist") sys.path.insert(0, os.path.abspath( os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) +import cdist + TYPE_PREFIX = "__" def commandline(): From 5a72223ae3bf95518b23ab605be8e5fbca68cb46 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 23:23:57 +0200 Subject: [PATCH 0944/4212] strip away / in emulator in requirements Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index e94060eb..875d3153 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -147,21 +147,24 @@ class Emulator(object): if "require" in os.environ: requirements = os.environ['require'] + self.log.debug("reqs = " + requirements) for requirement in requirements.split(" "): + # Ignore empty fields - probably the only field anyway + if len(requirement) == 0: + continue + self.log.debug("Recording requirement: " + requirement) requirement_parts = requirement.split(os.sep, 1) - requirement_parts.reverse() - # FIXME: continue here - FAILHERE,PLEASE()[]! - print(requirement) - print(requirement_parts) - requirement_type_name = requirement_parts.pop() - try: - requirement_object_id = requirement_parts.pop() - except IndexError: - # no object id, must be singleton - requirement_object_id = 'singleton' + requirement_type_name = requirement_parts[0] + requirement_object_id = requirement_parts[1] + # FIXME: Add support for omitted object id == singleton + #if len(requirement_parts) == 1: + #except IndexError: + # # no object id, must be singleton + # requirement_object_id = 'singleton' + + # Remove / if existent in object id requirement_object_id = requirement_object_id.lstrip('/') self.cdist_object.requirements.append(requirement) From 42e1c21f430d6298b7263ad0dccba8a04224e7b8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 23:26:54 +0200 Subject: [PATCH 0945/4212] print progress output in info level for object prepare Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index a71998f7..0c1b6a6f 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -91,6 +91,7 @@ class ConfigInstall(object): self.log.debug("Skipping rerun of object %s", cdist_object) continue else: + self.log.info("Running manifest and explorer for " + cdist_object.name) self.object_prepare(cdist_object) new_objects_created = True From 950424d4781209ebdccba916c8fe8e4d3d99db54 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 23:29:27 +0200 Subject: [PATCH 0946/4212] move log output into correct function, also log object code run/gencode Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 0c1b6a6f..fe705b95 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -91,7 +91,6 @@ class ConfigInstall(object): self.log.debug("Skipping rerun of object %s", cdist_object) continue else: - self.log.info("Running manifest and explorer for " + cdist_object.name) self.object_prepare(cdist_object) new_objects_created = True @@ -119,14 +118,14 @@ class ConfigInstall(object): def object_prepare(self, cdist_object): """Prepare object: Run type explorer + manifest""" - self.log.debug("Preparing object: " + cdist_object.name) + self.log.info("Running manifest and explorers for " + cdist_object.name) self.run_type_explorers(cdist_object) self.manifest.run_type_manifest(cdist_object) cdist_object.prepared = True def object_run(self, cdist_object): """Run gencode and code for an object""" - self.log.debug("Running object %s", cdist_object) + self.log.info("Running gencode and code for " + cdist_object.name) # Catch requirements, which re-call us if cdist_object.ran: From 3c31b4f9a33ba9089a10caa6d91b7919be2689ea Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Oct 2011 23:40:11 +0200 Subject: [PATCH 0947/4212] and finally also adjust the requirement itself Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 875d3153..ddd9dfdb 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -166,6 +166,9 @@ class Emulator(object): # Remove / if existent in object id requirement_object_id = requirement_object_id.lstrip('/') + + # Construct cleaned up requirement with only one / :-) + requirement = requirement_type_name + '/' + requirement_object_id self.cdist_object.requirements.append(requirement) # Record / Append source From 3883fe4247c4cbae5c6d9d4cfa8eef9a794f95db Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 00:12:32 +0200 Subject: [PATCH 0948/4212] raise cdist error instead of oserror Signed-off-by: Nico Schottelius --- lib/cdist/exec/local.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index 6157c0bc..264279a2 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -136,5 +136,7 @@ class Local(object): dst = os.path.join(self.bin_path, cdist_type.name) self.log.debug("Linking emulator: %s to %s", src, dst) - # FIXME: handle exceptions - os.symlink(src, dst) + try: + os.symlink(src, dst) + except OSError as e: + raise cdist.Error("Linking emulator from " + src + " to " + dst + " failed: " + e.__str__()) From 72687b5aeb1fd80f21874013e62c085c58aa45d1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 00:12:51 +0200 Subject: [PATCH 0949/4212] create new method to encapsulate configinstall run of one host Signed-off-by: Nico Schottelius --- bin/cdist | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/bin/cdist b/bin/cdist index 5ea6c6ce..5179734d 100755 --- a/bin/cdist +++ b/bin/cdist @@ -22,6 +22,7 @@ import argparse import logging +import multiprocessing import os import re import sys @@ -116,37 +117,44 @@ def configinstall(args, mode): time_start = time.time() - import cdist.context - for host in args.host: - context = cdist.context.Context( - target_host=host, - initial_manifest=args.manifest, - base_path=args.cdist_home, - exec_path=sys.argv[0], - debug=args.debug) - - c = mode(context) if args.parallel: log.debug("Creating child process for %s", host) - process[host] = multiprocessing.Process(target=c.deploy_and_cleanup) + process[host] = multiprocessing.Process(target=configinstall_onehost, args=(host, args, mode)) process[host].start() else: - c.deploy_and_cleanup() - - context.cleanup() + configinstall_onehost(host, args, mode) + # FIXME: error handling for parallel mode! if args.parallel: for p in process.keys(): log.debug("Joining process %s", p) process[p].join() - # FIXME: error handling for parallel mode! time_end = time.time() log.info("Total processing time for %s host(s): %s", len(args.host), (time_end - time_start)) + +def configinstall_onehost(host, args, mode): + """Configure or install remote system""" + process = {} + + import cdist.context + + context = cdist.context.Context( + target_host=host, + initial_manifest=args.manifest, + base_path=args.cdist_home, + exec_path=sys.argv[0], + debug=args.debug) + + c = mode(context) + c.deploy_and_cleanup() + context.cleanup() + + def emulator(): """Prepare and run emulator""" emulator = cdist.emulator.Emulator(sys.argv) @@ -168,6 +176,7 @@ if __name__ == "__main__": commandline() except KeyboardInterrupt: + # FIXME: catch children if in parallel mode sys.exit(0) except cdist.Error as e: log.error(e) From 15ae422cb28bd7db918b7b96a2ebbaede6c21dc2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 00:15:41 +0200 Subject: [PATCH 0950/4212] catch cdist errors in emulator or config install, not in main, because catching there does not work in multiprocess env Signed-off-by: Nico Schottelius --- bin/cdist | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/bin/cdist b/bin/cdist index 5179734d..7ff19943 100755 --- a/bin/cdist +++ b/bin/cdist @@ -40,6 +40,10 @@ TYPE_PREFIX = "__" def commandline(): """Parse command line""" + import cdist.banner + import cdist.config + import cdist.install + # Construct parser others can reuse parser = {} # Options _all_ parsers have in common @@ -141,43 +145,44 @@ def configinstall_onehost(host, args, mode): """Configure or install remote system""" process = {} - import cdist.context + try: + import cdist.context - context = cdist.context.Context( - target_host=host, - initial_manifest=args.manifest, - base_path=args.cdist_home, - exec_path=sys.argv[0], - debug=args.debug) + context = cdist.context.Context( + target_host=host, + initial_manifest=args.manifest, + base_path=args.cdist_home, + exec_path=sys.argv[0], + debug=args.debug) - c = mode(context) - c.deploy_and_cleanup() - context.cleanup() + c = mode(context) + c.deploy_and_cleanup() + context.cleanup() + except cdist.Error as e: + log.error(e) + sys.exit(1) def emulator(): """Prepare and run emulator""" - emulator = cdist.emulator.Emulator(sys.argv) - emulator.run() + try: + import cdist.emulator + emulator = cdist.emulator.Emulator(sys.argv) + emulator.run() + + except cdist.Error as e: + log.error(e) + sys.exit(1) if __name__ == "__main__": try: logging.basicConfig(format='%(levelname)s: %(message)s') if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): - import cdist.emulator - emulator() else: - import cdist.banner - import cdist.config - import cdist.install - commandline() except KeyboardInterrupt: # FIXME: catch children if in parallel mode sys.exit(0) - except cdist.Error as e: - log.error(e) - sys.exit(1) From 46fdc5ca6e63a5c641393091ea5fca5f74948a48 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 00:21:24 +0200 Subject: [PATCH 0951/4212] ugly output on random ctrl-c actions Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-16keyboardirqoutputs | 76 +++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 doc/dev/logs/2011-10-16keyboardirqoutputs diff --git a/doc/dev/logs/2011-10-16keyboardirqoutputs b/doc/dev/logs/2011-10-16keyboardirqoutputs new file mode 100644 index 00000000..187487de --- /dev/null +++ b/doc/dev/logs/2011-10-16keyboardirqoutputs @@ -0,0 +1,76 @@ +1) + +[0:19] brief:~% ./p/cdist/bin/cdist config -v localhost +INFO: localhost: Running global explorers +INFO: localhost: Running initial manifest /home/users/nico/oeffentlich/rechner/projekte/cdist/conf/manifest +^Chandling in config +Traceback (most recent call last): + File "/usr/lib/python3.2/functools.py", line 176, in wrapper + result = cache[key] +KeyError: (, '[ \\f\\t]*(\\\\\\r?\\n[ \\f\\t]*)*(#[^\\r\\n]*)?((([0-9]+[jJ]|(([0-9]+\\.[0-9]*|\\.[0-9]+)([eE][-+]?[0-9]+)?|[0-9]+[eE][-+]?[0-9]+)[jJ])|(([0-9]+\\.[0-9]*|\\.[0-9]+)([eE][-+]?[0-9]+)?|[0-9]+[eE][-+]?[0-9]+)|(0[xX][0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+|(?:0+|[1-9][0-9]*)))|((\\*\\*=?|>>=?|<<=?|!=|//=?|->|[+\\-*/%&|^=<>]=?|~)|[][(){}]|(\\r?\\n|\\.\\.\\.|[:;.,@]))|([bB]?[rR]?\'[^\\n\'\\\\]*(?:\\\\.[^\\n\'\\\\]*)*\'|[bB]?[rR]?"[^\\n"\\\\]*(?:\\\\.[^\\n"\\\\]*)*")|\\w+)', 32) + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "/usr/lib/python3.2/site.py", line 58, in + import traceback + File "/usr/lib/python3.2/traceback.py", line 3, in + import linecache + File "/usr/lib/python3.2/linecache.py", line 10, in + import tokenize + File "/usr/lib/python3.2/tokenize.py", line 118, in + _compile, (Token, PseudoToken, Single3, Double3)) + File "/usr/lib/python3.2/tokenize.py", line 115, in _compile + return re.compile(expr, re.UNICODE) + File "/usr/lib/python3.2/re.py", line 206, in compile + return _compile(pattern, flags) + File "/usr/lib/python3.2/re.py", line 255, in _compile + return _compile_typed(type(pattern), pattern, flags) + File "/usr/lib/python3.2/functools.py", line 180, in wrapper + result = user_function(*args, **kwds) + File "/usr/lib/python3.2/re.py", line 267, in _compile_typed + return sre_compile.compile(pattern, flags) + File "/usr/lib/python3.2/sre_compile.py", line 495, in compile + code = _code(p, flags) + File "/usr/lib/python3.2/sre_compile.py", line 477, in _code + _compile_info(code, p, flags) + File "/usr/lib/python3.2/sre_compile.py", line 366, in _compile_info +[0:19] brief:~% lo, hi = pattern.getwidth() + File "/usr/lib/python3.2/sre_parse.py", line 163, in getwidth + i, j = av[1].getwidth() + File "/usr/lib/python3.2/sre_parse.py", line 153, in getwidth + l, h = av.getwidth() + File "/usr/lib/python3.2/sre_parse.py", line 163, in getwidth + i, j = av[1].getwidth() + File "/usr/lib/python3.2/sre_parse.py", line 153, in getwidth + l, h = av.getwidth() + File "/usr/lib/python3.2/sre_parse.py", line 163, in getwidth + i, j = av[1].getwidth() + File "/usr/lib/python3.2/sre_parse.py", line 153, in getwidth + l, h = av.getwidth() + File "/usr/lib/python3.2/sre_parse.py", line 163, in getwidth + i, j = av[1].getwidth() + File "/usr/lib/python3.2/sre_parse.py", line 153, in getwidth + l, h = av.getwidth() + File "/usr/lib/python3.2/sre_parse.py", line 163, in getwidth + i, j = av[1].getwidth() + File "/usr/lib/python3.2/sre_parse.py", line 148, in getwidth + for op, av in self.data: +KeyboardInterrupt + +2) +[0:19] brief:~% ./p/cdist/bin/cdist config -v localhost +INFO: localhost: Running global explorers +INFO: localhost: Running initial manifest /home/users/nico/oeffentlich/rechner/projekte/cdist/conf/manifest +^CFatal Python error: Py_Initialize: can't initialize sys standard streams +Traceback (most recent call last): + File "/usr/lib/python3.2/io.py", line 60, in +handling in config + import _io + File "/usr/lib/python3.2/os.py", line 26, in +[0:19] brief:~% import sys, errno +KeyboardInterrupt +/home/users/nico/oeffentlich/rechner/projekte/cdist/conf/manifest/init: line 6: 8370 Aborted __directory /tmp/foo/bar --parents yes --owner nico --group postdrop --recursive yes + +[0:19] brief:~% + From e8a81551f8408623ac07da9ba6ce8ada0b022f53 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 00:31:52 +0200 Subject: [PATCH 0952/4212] implement error reporting for failed hosts at the end Signed-off-by: Nico Schottelius --- bin/cdist | 50 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/bin/cdist b/bin/cdist index 7ff19943..ad2cb858 100755 --- a/bin/cdist +++ b/bin/cdist @@ -117,28 +117,45 @@ def install(args): def configinstall(args, mode): """Configure or install remote system""" - process = {} + try: + process = {} + failed_hosts = [] + time_start = time.time() - 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)) + process[host].start() + else: + configinstall_onehost(host, args, mode) - 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)) - process[host].start() - else: - configinstall_onehost(host, args, mode) + for p in process.keys(): + log.debug("Joining process %s", p) + process[p].join() - # FIXME: error handling for parallel mode! - if args.parallel: - for p in process.keys(): - log.debug("Joining process %s", p) - process[p].join() + if not process[p].exitcode == 0: + failed_hosts.append(p) + if len(failed_hosts) > 0: + log.warn("Failed to deploy to the following hosts: " + + " ".join(failed_hosts)) - time_end = time.time() - log.info("Total processing time for %s host(s): %s", len(args.host), - (time_end - time_start)) + time_end = time.time() + log.info("Total processing time for %s host(s): %s", len(args.host), + (time_end - time_start)) + + except KeyboardInterrupt: + print("handling in config") + if args.parallel: + for p in process.keys(): + log.debug("Terminating process %s", p) + # FIXME: check whether alive or just terminate? + process[p].terminate() + + # FIXME: catch children if in parallel mode + sys.exit(0) def configinstall_onehost(host, args, mode): @@ -185,4 +202,5 @@ if __name__ == "__main__": except KeyboardInterrupt: # FIXME: catch children if in parallel mode + print("handling in main") sys.exit(0) From 84e102eb29466f3cab0f8c5a1595923d7e0c5af1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 00:45:37 +0200 Subject: [PATCH 0953/4212] also report failed hosts in sequential mode, terminate processes on interrupt, continue deploy even if one or more hosts failed Signed-off-by: Nico Schottelius --- bin/cdist | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/bin/cdist b/bin/cdist index ad2cb858..650ad853 100755 --- a/bin/cdist +++ b/bin/cdist @@ -128,7 +128,8 @@ def configinstall(args, mode): process[host] = multiprocessing.Process(target=configinstall_onehost, args=(host, args, mode)) process[host].start() else: - configinstall_onehost(host, args, mode) + if not configinstall_onehost(host, args, mode): + failed_hosts.append(host) if args.parallel: for p in process.keys(): @@ -147,20 +148,16 @@ def configinstall(args, mode): (time_end - time_start)) except KeyboardInterrupt: - print("handling in config") if args.parallel: for p in process.keys(): - log.debug("Terminating process %s", p) - # FIXME: check whether alive or just terminate? + log.warn("Terminating deploy " + p + "(" + p.pid + ")") process[p].terminate() - # FIXME: catch children if in parallel mode sys.exit(0) def configinstall_onehost(host, args, mode): - """Configure or install remote system""" - process = {} + """Configure or install ONE remote system""" try: import cdist.context @@ -178,7 +175,9 @@ def configinstall_onehost(host, args, mode): except cdist.Error as e: log.error(e) - sys.exit(1) + return False + + return True def emulator(): """Prepare and run emulator""" @@ -201,6 +200,6 @@ if __name__ == "__main__": commandline() except KeyboardInterrupt: - # FIXME: catch children if in parallel mode - print("handling in main") sys.exit(0) + + sys.exit(0) From 7b770b7b357071cd62746ce0367c5cbacc92469d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 00:49:04 +0200 Subject: [PATCH 0954/4212] correctly report pid when killing subprocess Signed-off-by: Nico Schottelius --- bin/cdist | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 650ad853..9786960c 100755 --- a/bin/cdist +++ b/bin/cdist @@ -150,7 +150,8 @@ def configinstall(args, mode): except KeyboardInterrupt: if args.parallel: for p in process.keys(): - log.warn("Terminating deploy " + p + "(" + p.pid + ")") + pid = process[p].pid.__str__() + log.warn("Terminating deploy " + p + " (" + pid + ")") process[p].terminate() sys.exit(0) From a587975a99373e0c1c79940e95fc9d9104f41380 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 01:05:47 +0200 Subject: [PATCH 0955/4212] catch keyboardirq in parallel mode, so it's not raised into multiprocess Signed-off-by: Nico Schottelius --- bin/cdist | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index 9786960c..c00bb73a 100755 --- a/bin/cdist +++ b/bin/cdist @@ -125,10 +125,10 @@ def configinstall(args, mode): 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)) + process[host] = multiprocessing.Process(target=configinstall_onehost, args=(host, args, mode, True)) process[host].start() else: - if not configinstall_onehost(host, args, mode): + if not configinstall_onehost(host, args, mode, parallel=False): failed_hosts.append(host) if args.parallel: @@ -157,7 +157,7 @@ def configinstall(args, mode): sys.exit(0) -def configinstall_onehost(host, args, mode): +def configinstall_onehost(host, args, mode, parallel): """Configure or install ONE remote system""" try: @@ -177,6 +177,10 @@ def configinstall_onehost(host, args, mode): except cdist.Error as e: log.error(e) return False + except KeyboardInterrupt: + # Do not care in sequential mode, catch in parallel mode + if not parallel: + raise return True From 1d1bff88b7e0af70447eae1f0b859ffce1a1e2c3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 01:06:33 +0200 Subject: [PATCH 0956/4212] just as a marker: return false, so in theory even multiprocess noticed that we did something stuped Signed-off-by: Nico Schottelius --- bin/cdist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/cdist b/bin/cdist index c00bb73a..a07763f9 100755 --- a/bin/cdist +++ b/bin/cdist @@ -181,6 +181,8 @@ def configinstall_onehost(host, args, mode, parallel): # Do not care in sequential mode, catch in parallel mode if not parallel: raise + else: + return False return True From ede8fd7518ef228aac1737118cc32783882aff44 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 01:14:17 +0200 Subject: [PATCH 0957/4212] ++output errors Signed-off-by: Nico Schottelius --- ...qoutputs => 2011-10-16.keyboardirqoutputs} | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) rename doc/dev/logs/{2011-10-16keyboardirqoutputs => 2011-10-16.keyboardirqoutputs} (52%) diff --git a/doc/dev/logs/2011-10-16keyboardirqoutputs b/doc/dev/logs/2011-10-16.keyboardirqoutputs similarity index 52% rename from doc/dev/logs/2011-10-16keyboardirqoutputs rename to doc/dev/logs/2011-10-16.keyboardirqoutputs index 187487de..5d843dac 100644 --- a/doc/dev/logs/2011-10-16keyboardirqoutputs +++ b/doc/dev/logs/2011-10-16.keyboardirqoutputs @@ -74,3 +74,70 @@ KeyboardInterrupt [0:19] brief:~% +3) + +[1:12] brief:cdist% ./bin/cdist config -vp -c ~/p/cdist-nutzung ikq05.ethz.ch ikq06.ethz.ch ikq07.ethz.ch +INFO: ikq06.ethz.ch: Running global explorers +INFO: ikq05.ethz.ch: Running global explorers +INFO: ikq07.ethz.ch: Running global explorers +INFO: ikq07.ethz.ch: Running initial manifest /home/users/nico/p/cdist-nutzung/conf/manifest +INFO: ikq06.ethz.ch: Running initial manifest /home/users/nico/p/cdist-nutzung/conf/manifest +INFO: ikq05.ethz.ch: Running initial manifest /home/users/nico/p/cdist-nutzung/conf/manifest +INFO: ikq07.ethz.ch: Running object manifests and type explorers +INFO: ikq07.ethz.ch: Running manifest and explorers for __ethz_collectd/singleton +INFO: ikq05.ethz.ch: Running object manifests and type explorers +INFO: ikq05.ethz.ch: Running manifest and explorers for __ethz_collectd/singleton +^Ccatch, ikq05.ethz.ch +catch, ikq07.ethz.ch +[1:12] brief:cdist% ./bin/cdist config -vp -c ~/p/cdist-nutzung ikq05.ethz.ch ikq06.ethz.ch ikq07.ethz.ch +INFO: ikq05.ethz.ch: Running global explorers +INFO: ikq06.ethz.ch: Running global explorers +INFO: ikq07.ethz.ch: Running global explorers +INFO: ikq05.ethz.ch: Running initial manifest /home/users/nico/p/cdist-nutzung/conf/manifest +INFO: ikq06.ethz.ch: Running initial manifest /home/users/nico/p/cdist-nutzung/conf/manifest +INFO: ikq07.ethz.ch: Running initial manifest /home/users/nico/p/cdist-nutzung/conf/manifest +^CTraceback (most recent call last): + File "/usr/lib/python3.2/site.py", line 529, in +catch, ikq05.ethz.ch +Fatal Python error: Py_Initialize: can't initialize sys standard streams +Traceback (most recent call last): + File "/usr/lib/python3.2/io.py", line 60, in +catch, ikq07.ethz.ch + main() + File "/usr/lib/python3.2/site.py", line 517, in main +catch, ikq06.ethz.ch + known_paths = addusersitepackages(known_paths) + File "/usr/lib/python3.2/site.py", line 263, in addusersitepackages +Fatal Python error: Py_Initialize: can't initialize sys standard streams +Traceback (most recent call last): + File "/usr/lib/python3.2/io.py", line 60, in + user_site = getusersitepackages() + File "/usr/lib/python3.2/site.py", line 238, in getusersitepackages + user_base = getuserbase() # this will also set USER_BASE + File "/usr/lib/python3.2/site.py", line 228, in getuserbase + USER_BASE = get_config_var('userbase') + File "/usr/lib/python3.2/sysconfig.py", line 577, in get_config_var + return get_config_vars().get(name) + File "/usr/lib/python3.2/sysconfig.py", line 474, in get_config_vars + _init_posix(_CONFIG_VARS) + File "/usr/lib/python3.2/sysconfig.py", line 344, in _init_posix + parse_config_h(f, vars) + File "/usr/lib/python3.2/sysconfig.py", line 386, in parse_config_h + line = fp.readline() + File "/usr/lib/python3.2/codecs.py", line 302, in decode + self.buffer = data[consumed:] +KeyboardInterrupt + import _io + File "/usr/lib/python3.2/os.py", line 49, in + import posixpath as path + File "/usr/lib/python3.2/posixpath.py", line 11, in + import _io + File "/usr/lib/python3.2/os.py", line 44, in + """ from posix import * +KeyboardInterrupt +/home/users/nico/p/cdist-nutzung/conf/manifest/init: line 10: 19830 Aborted __ethz_systems_root_via_ssh $ik --state present + +KeyboardInterrupt +[1:12] brief:cdist% /home/users/nico/p/cdist-nutzung/conf/manifest/init: line 10: 19829 Aborted __ethz_systems_root_via_ssh $ik --state present + + From dbdf036787a00c16919b2cfdbad9ef7bb01614c0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 12:04:04 +0200 Subject: [PATCH 0958/4212] do not need to use terminate()/SIGTERM Signed-off-by: Nico Schottelius --- bin/cdist | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index a07763f9..14cff65a 100755 --- a/bin/cdist +++ b/bin/cdist @@ -150,9 +150,12 @@ def configinstall(args, mode): except KeyboardInterrupt: if args.parallel: for p in process.keys(): - pid = process[p].pid.__str__() - log.warn("Terminating deploy " + p + " (" + pid + ")") - process[p].terminate() + # NOT needed: KeyBoardInterrupet (aka SIGINT) + # is forwarded to processes spawned by multiprocess! + # pid = process[p].pid.__str__() + #log.warn("Terminating deploy " + p + " (" + pid + ")") + # process[p].terminate() + pass sys.exit(0) @@ -182,6 +185,7 @@ def configinstall_onehost(host, args, mode, parallel): if not parallel: raise else: + # Catch here, above does not need to know about our errors return False return True From 32b2c49d32c5d4ad7f2b53062dc3e19ee0d5761a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 12:39:06 +0200 Subject: [PATCH 0959/4212] found 2 bugs in transfer_code_remote Signed-off-by: Nico Schottelius --- lib/cdist/core/code.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index 0f2591b3..2505925c 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -121,6 +121,10 @@ class Code(object): """Transfer the code_remote script for the given object to the remote side.""" source = os.path.join(self.local.object_path, cdist_object.code_remote_path) destination = os.path.join(self.remote.object_path, cdist_object.code_remote_path) + # 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) From 420b6aeae7ac700870951c75ba9a4cd5130b56d4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 15:08:00 +0200 Subject: [PATCH 0960/4212] ensure object is not ran twice Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index fe705b95..fa5cf2b0 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -88,7 +88,7 @@ class ConfigInstall(object): for cdist_object in core.Object.list_objects(self.local.object_path, self.local.type_path): if cdist_object.prepared: - self.log.debug("Skipping rerun of object %s", cdist_object) + self.log.debug("Skipping re-prepare of object %s", cdist_object) continue else: self.object_prepare(cdist_object) @@ -128,8 +128,11 @@ class ConfigInstall(object): self.log.info("Running gencode and code for " + cdist_object.name) # Catch requirements, which re-call us + # FIXME: change .ran to running if cdist_object.ran: return + else: + cdist_object.ran = True cdist_type = cdist_object.type From 69293efd0053a25ca4d8c7182b88c720c162c595 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 15:27:03 +0200 Subject: [PATCH 0961/4212] --todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 520128cc..8f5c6e4f 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,6 +1,5 @@ 2.0.3: -- fix emulator / require - sanity checks: implement tests stage_run() From eb7234df51c947091bd9c86e7703be4cb432d6ad Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 16:05:58 +0200 Subject: [PATCH 0962/4212] also publish to sourceforge Signed-off-by: Nico Schottelius --- build | 1 + 1 file changed, 1 insertion(+) diff --git a/build b/build index 69f0ad92..9e9fbf21 100755 --- a/build +++ b/build @@ -114,6 +114,7 @@ case "$1" in p|pu|pub) git push --mirror git push --mirror github + git push --mirror sf ;; clean) From 4e6c3ee686e83b67b958ffb93440a4a704b064c2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 16:11:22 +0200 Subject: [PATCH 0963/4212] ++mirror Signed-off-by: Nico Schottelius --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index 3dff690f..91f1efa1 100644 --- a/README +++ b/README @@ -171,6 +171,7 @@ may vanish at any point. To select a specific branch use ### Mirrors * git://github.com/telmich/cdist.git ([github](https://github.com/telmich/cdist)) + * git://git.code.sf.net/p/cdist/code ([sourceforge](https://sourceforge.net/p/cdist/code) ## Update From 65a82b517cc58792ad0c89cb177ace2afb718c1c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 16:20:35 +0200 Subject: [PATCH 0964/4212] --typo Signed-off-by: Nico Schottelius --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 91f1efa1..1c2139cc 100644 --- a/README +++ b/README @@ -171,7 +171,7 @@ may vanish at any point. To select a specific branch use ### Mirrors * git://github.com/telmich/cdist.git ([github](https://github.com/telmich/cdist)) - * git://git.code.sf.net/p/cdist/code ([sourceforge](https://sourceforge.net/p/cdist/code) + * git://git.code.sf.net/p/cdist/code ([sourceforge](https://sourceforge.net/p/cdist/code)) ## Update From 03ea7787d2bf55212e33e077fe7d4970f50b1422 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 18:38:22 +0200 Subject: [PATCH 0965/4212] +self Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index ddd9dfdb..103ea8c0 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -134,7 +134,7 @@ class Emulator(object): self.parameters[key] = value if self.cdist_object.exists: - if cdist_object.parameters != self.parameters: + 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, " ".join(self.cdist_object.source), self.cdist_object.parameters, self.object_source, self.parameters) ) From 0700fc6bc9f737211a83167273f264b762f641d1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 18:43:52 +0200 Subject: [PATCH 0966/4212] cleanup needed here as well Signed-off-by: Nico Schottelius --- .../nico/conf/type/__nico_afs/files/afs/CellServDB | 0 .../nico/conf/type/__nico_afs/files/afs/ThisCell | 0 .../nico/conf/type/__nico_afs/files/krb5/krb5.conf | 0 .../nico/conf/type/__nico_afs/files/ssh/JAS.pub | 0 .../nico/conf/type/__nico_afs/files/ssh/bugblue.pub | 0 .../nico/conf/type/__nico_afs/files/ssh/docsteel.pub | 0 .../nico/conf/type/__nico_afs/files/ssh/downhill.pub | 0 .../nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub | 0 .../nico/conf/type/__nico_afs/manifest | 0 .../nico/conf/type/__nico_afs/singleton | 0 .../nico/conf/type/__nico_desktop/files/hostname | 0 .../nico/conf/type/__nico_desktop/files/slim-preseed | 0 .../nico/conf/type/__nico_desktop/manifest | 0 .../nico/conf/type/__nico_desktop/parameter/required | 0 .../nico/conf/type/__nico_desktop/singleton | 0 .../nico/conf/type/__nico_mpd/files/slim-preseed | 0 .../nico/conf/type/__nico_mpd/manifest | 0 .../nico/conf/type/__nico_mpd/parameter/required | 0 .../nico/conf/type/__nico_mpd/singleton | 0 .../nico/conf/type/__nico_network/files/interfaces-eth0 | 0 .../nico/conf/type/__nico_network/files/interfaces-wlan0 | 0 .../nico/conf/type/__nico_network/manifest | 0 .../nico/conf/type/__nico_network/parameter/required | 0 .../nico/conf/type/__nico_network/singleton | 0 .../nico/conf/type/__nico_nfs_client/files/slim-preseed | 0 .../nico/conf/type/__nico_nfs_client/manifest | 0 .../nico/conf/type/__nico_nfs_client/singleton | 0 .../nico/conf/type/__nico_notebook/manifest | 0 .../nico/conf/type/__nico_notebook/singleton | 0 .../nico/conf/type/__nico_packages/manifest | 0 .../nico/conf/type/__nico_packages/singleton | 0 .../nico/conf/type/__nico_sudo/files/sudo-nico | 0 .../nico/conf/type/__nico_sudo/manifest | 0 .../nico/conf/type/__nico_sudo/parameter/gencode | 0 .../nico/conf/type/__nico_sudo/parameter/manifest | 0 .../nico/conf/type/__nico_sudo/parameter/optional | 0 .../nico/conf/type/__nico_sudo/parameter/required | 0 .../nico/conf/type/__nico_sudo/singleton | 0 .../nico/conf/type/__nico_tee/files/99-apt-nico | 0 .../nico/conf/type/__nico_tee/files/hostname | 0 .../nico/conf/type/__nico_tee/manifest | 0 .../nico/conf/type/__nico_tee/singleton | 0 42 files changed, 0 insertions(+), 0 deletions(-) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_afs/files/afs/CellServDB (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_afs/files/afs/ThisCell (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_afs/files/krb5/krb5.conf (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_afs/files/ssh/JAS.pub (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_afs/files/ssh/bugblue.pub (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_afs/files/ssh/docsteel.pub (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_afs/files/ssh/downhill.pub (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_afs/manifest (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_afs/singleton (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_desktop/files/hostname (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_desktop/files/slim-preseed (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_desktop/manifest (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_desktop/parameter/required (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_desktop/singleton (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_mpd/files/slim-preseed (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_mpd/manifest (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_mpd/parameter/required (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_mpd/singleton (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_network/files/interfaces-eth0 (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_network/files/interfaces-wlan0 (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_network/manifest (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_network/parameter/required (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_network/singleton (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_nfs_client/files/slim-preseed (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_nfs_client/manifest (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_nfs_client/singleton (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_notebook/manifest (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_notebook/singleton (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_packages/manifest (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_packages/singleton (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_sudo/files/sudo-nico (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_sudo/manifest (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_sudo/parameter/gencode (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_sudo/parameter/manifest (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_sudo/parameter/optional (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_sudo/parameter/required (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_sudo/singleton (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_tee/files/99-apt-nico (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_tee/files/hostname (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_tee/manifest (100%) rename other/{examples => examples_needing_cleanup}/nico/conf/type/__nico_tee/singleton (100%) diff --git a/other/examples/nico/conf/type/__nico_afs/files/afs/CellServDB b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/afs/CellServDB similarity index 100% rename from other/examples/nico/conf/type/__nico_afs/files/afs/CellServDB rename to other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/afs/CellServDB diff --git a/other/examples/nico/conf/type/__nico_afs/files/afs/ThisCell b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/afs/ThisCell similarity index 100% rename from other/examples/nico/conf/type/__nico_afs/files/afs/ThisCell rename to other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/afs/ThisCell diff --git a/other/examples/nico/conf/type/__nico_afs/files/krb5/krb5.conf b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/krb5/krb5.conf similarity index 100% rename from other/examples/nico/conf/type/__nico_afs/files/krb5/krb5.conf rename to other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/krb5/krb5.conf diff --git a/other/examples/nico/conf/type/__nico_afs/files/ssh/JAS.pub b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/JAS.pub similarity index 100% rename from other/examples/nico/conf/type/__nico_afs/files/ssh/JAS.pub rename to other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/JAS.pub diff --git a/other/examples/nico/conf/type/__nico_afs/files/ssh/bugblue.pub b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/bugblue.pub similarity index 100% rename from other/examples/nico/conf/type/__nico_afs/files/ssh/bugblue.pub rename to other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/bugblue.pub diff --git a/other/examples/nico/conf/type/__nico_afs/files/ssh/docsteel.pub b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/docsteel.pub similarity index 100% rename from other/examples/nico/conf/type/__nico_afs/files/ssh/docsteel.pub rename to other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/docsteel.pub diff --git a/other/examples/nico/conf/type/__nico_afs/files/ssh/downhill.pub b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/downhill.pub similarity index 100% rename from other/examples/nico/conf/type/__nico_afs/files/ssh/downhill.pub rename to other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/downhill.pub diff --git a/other/examples/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub similarity index 100% rename from other/examples/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub rename to other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub diff --git a/other/examples/nico/conf/type/__nico_afs/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/manifest similarity index 100% rename from other/examples/nico/conf/type/__nico_afs/manifest rename to other/examples_needing_cleanup/nico/conf/type/__nico_afs/manifest diff --git a/other/examples/nico/conf/type/__nico_afs/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/singleton similarity index 100% rename from other/examples/nico/conf/type/__nico_afs/singleton rename to other/examples_needing_cleanup/nico/conf/type/__nico_afs/singleton diff --git a/other/examples/nico/conf/type/__nico_desktop/files/hostname b/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/files/hostname similarity index 100% rename from other/examples/nico/conf/type/__nico_desktop/files/hostname rename to other/examples_needing_cleanup/nico/conf/type/__nico_desktop/files/hostname diff --git a/other/examples/nico/conf/type/__nico_desktop/files/slim-preseed b/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/files/slim-preseed similarity index 100% rename from other/examples/nico/conf/type/__nico_desktop/files/slim-preseed rename to other/examples_needing_cleanup/nico/conf/type/__nico_desktop/files/slim-preseed diff --git a/other/examples/nico/conf/type/__nico_desktop/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/manifest similarity index 100% rename from other/examples/nico/conf/type/__nico_desktop/manifest rename to other/examples_needing_cleanup/nico/conf/type/__nico_desktop/manifest diff --git a/other/examples/nico/conf/type/__nico_desktop/parameter/required b/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/parameter/required similarity index 100% rename from other/examples/nico/conf/type/__nico_desktop/parameter/required rename to other/examples_needing_cleanup/nico/conf/type/__nico_desktop/parameter/required diff --git a/other/examples/nico/conf/type/__nico_desktop/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/singleton similarity index 100% rename from other/examples/nico/conf/type/__nico_desktop/singleton rename to other/examples_needing_cleanup/nico/conf/type/__nico_desktop/singleton diff --git a/other/examples/nico/conf/type/__nico_mpd/files/slim-preseed b/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/files/slim-preseed similarity index 100% rename from other/examples/nico/conf/type/__nico_mpd/files/slim-preseed rename to other/examples_needing_cleanup/nico/conf/type/__nico_mpd/files/slim-preseed diff --git a/other/examples/nico/conf/type/__nico_mpd/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/manifest similarity index 100% rename from other/examples/nico/conf/type/__nico_mpd/manifest rename to other/examples_needing_cleanup/nico/conf/type/__nico_mpd/manifest diff --git a/other/examples/nico/conf/type/__nico_mpd/parameter/required b/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/parameter/required similarity index 100% rename from other/examples/nico/conf/type/__nico_mpd/parameter/required rename to other/examples_needing_cleanup/nico/conf/type/__nico_mpd/parameter/required diff --git a/other/examples/nico/conf/type/__nico_mpd/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/singleton similarity index 100% rename from other/examples/nico/conf/type/__nico_mpd/singleton rename to other/examples_needing_cleanup/nico/conf/type/__nico_mpd/singleton diff --git a/other/examples/nico/conf/type/__nico_network/files/interfaces-eth0 b/other/examples_needing_cleanup/nico/conf/type/__nico_network/files/interfaces-eth0 similarity index 100% rename from other/examples/nico/conf/type/__nico_network/files/interfaces-eth0 rename to other/examples_needing_cleanup/nico/conf/type/__nico_network/files/interfaces-eth0 diff --git a/other/examples/nico/conf/type/__nico_network/files/interfaces-wlan0 b/other/examples_needing_cleanup/nico/conf/type/__nico_network/files/interfaces-wlan0 similarity index 100% rename from other/examples/nico/conf/type/__nico_network/files/interfaces-wlan0 rename to other/examples_needing_cleanup/nico/conf/type/__nico_network/files/interfaces-wlan0 diff --git a/other/examples/nico/conf/type/__nico_network/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_network/manifest similarity index 100% rename from other/examples/nico/conf/type/__nico_network/manifest rename to other/examples_needing_cleanup/nico/conf/type/__nico_network/manifest diff --git a/other/examples/nico/conf/type/__nico_network/parameter/required b/other/examples_needing_cleanup/nico/conf/type/__nico_network/parameter/required similarity index 100% rename from other/examples/nico/conf/type/__nico_network/parameter/required rename to other/examples_needing_cleanup/nico/conf/type/__nico_network/parameter/required diff --git a/other/examples/nico/conf/type/__nico_network/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_network/singleton similarity index 100% rename from other/examples/nico/conf/type/__nico_network/singleton rename to other/examples_needing_cleanup/nico/conf/type/__nico_network/singleton diff --git a/other/examples/nico/conf/type/__nico_nfs_client/files/slim-preseed b/other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/files/slim-preseed similarity index 100% rename from other/examples/nico/conf/type/__nico_nfs_client/files/slim-preseed rename to other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/files/slim-preseed diff --git a/other/examples/nico/conf/type/__nico_nfs_client/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/manifest similarity index 100% rename from other/examples/nico/conf/type/__nico_nfs_client/manifest rename to other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/manifest diff --git a/other/examples/nico/conf/type/__nico_nfs_client/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/singleton similarity index 100% rename from other/examples/nico/conf/type/__nico_nfs_client/singleton rename to other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/singleton diff --git a/other/examples/nico/conf/type/__nico_notebook/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_notebook/manifest similarity index 100% rename from other/examples/nico/conf/type/__nico_notebook/manifest rename to other/examples_needing_cleanup/nico/conf/type/__nico_notebook/manifest diff --git a/other/examples/nico/conf/type/__nico_notebook/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_notebook/singleton similarity index 100% rename from other/examples/nico/conf/type/__nico_notebook/singleton rename to other/examples_needing_cleanup/nico/conf/type/__nico_notebook/singleton diff --git a/other/examples/nico/conf/type/__nico_packages/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_packages/manifest similarity index 100% rename from other/examples/nico/conf/type/__nico_packages/manifest rename to other/examples_needing_cleanup/nico/conf/type/__nico_packages/manifest diff --git a/other/examples/nico/conf/type/__nico_packages/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_packages/singleton similarity index 100% rename from other/examples/nico/conf/type/__nico_packages/singleton rename to other/examples_needing_cleanup/nico/conf/type/__nico_packages/singleton diff --git a/other/examples/nico/conf/type/__nico_sudo/files/sudo-nico b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/files/sudo-nico similarity index 100% rename from other/examples/nico/conf/type/__nico_sudo/files/sudo-nico rename to other/examples_needing_cleanup/nico/conf/type/__nico_sudo/files/sudo-nico diff --git a/other/examples/nico/conf/type/__nico_sudo/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/manifest similarity index 100% rename from other/examples/nico/conf/type/__nico_sudo/manifest rename to other/examples_needing_cleanup/nico/conf/type/__nico_sudo/manifest diff --git a/other/examples/nico/conf/type/__nico_sudo/parameter/gencode b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/gencode similarity index 100% rename from other/examples/nico/conf/type/__nico_sudo/parameter/gencode rename to other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/gencode diff --git a/other/examples/nico/conf/type/__nico_sudo/parameter/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/manifest similarity index 100% rename from other/examples/nico/conf/type/__nico_sudo/parameter/manifest rename to other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/manifest diff --git a/other/examples/nico/conf/type/__nico_sudo/parameter/optional b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/optional similarity index 100% rename from other/examples/nico/conf/type/__nico_sudo/parameter/optional rename to other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/optional diff --git a/other/examples/nico/conf/type/__nico_sudo/parameter/required b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/required similarity index 100% rename from other/examples/nico/conf/type/__nico_sudo/parameter/required rename to other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/required diff --git a/other/examples/nico/conf/type/__nico_sudo/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/singleton similarity index 100% rename from other/examples/nico/conf/type/__nico_sudo/singleton rename to other/examples_needing_cleanup/nico/conf/type/__nico_sudo/singleton diff --git a/other/examples/nico/conf/type/__nico_tee/files/99-apt-nico b/other/examples_needing_cleanup/nico/conf/type/__nico_tee/files/99-apt-nico similarity index 100% rename from other/examples/nico/conf/type/__nico_tee/files/99-apt-nico rename to other/examples_needing_cleanup/nico/conf/type/__nico_tee/files/99-apt-nico diff --git a/other/examples/nico/conf/type/__nico_tee/files/hostname b/other/examples_needing_cleanup/nico/conf/type/__nico_tee/files/hostname similarity index 100% rename from other/examples/nico/conf/type/__nico_tee/files/hostname rename to other/examples_needing_cleanup/nico/conf/type/__nico_tee/files/hostname diff --git a/other/examples/nico/conf/type/__nico_tee/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_tee/manifest similarity index 100% rename from other/examples/nico/conf/type/__nico_tee/manifest rename to other/examples_needing_cleanup/nico/conf/type/__nico_tee/manifest diff --git a/other/examples/nico/conf/type/__nico_tee/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_tee/singleton similarity index 100% rename from other/examples/nico/conf/type/__nico_tee/singleton rename to other/examples_needing_cleanup/nico/conf/type/__nico_tee/singleton From 74920d53a674f4c33e98877c0562af4b19c6e1a7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 18:44:36 +0200 Subject: [PATCH 0967/4212] ++cleanup Signed-off-by: Nico Schottelius --- other/{tests_reintegrate => tests_needing_cleanup}/nico_ui.py | 0 other/{tests_reintegrate => tests_needing_cleanup}/test_config.py | 0 .../{tests_reintegrate => tests_needing_cleanup}/test_install.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename other/{tests_reintegrate => tests_needing_cleanup}/nico_ui.py (100%) rename other/{tests_reintegrate => tests_needing_cleanup}/test_config.py (100%) rename other/{tests_reintegrate => tests_needing_cleanup}/test_install.py (100%) diff --git a/other/tests_reintegrate/nico_ui.py b/other/tests_needing_cleanup/nico_ui.py similarity index 100% rename from other/tests_reintegrate/nico_ui.py rename to other/tests_needing_cleanup/nico_ui.py diff --git a/other/tests_reintegrate/test_config.py b/other/tests_needing_cleanup/test_config.py similarity index 100% rename from other/tests_reintegrate/test_config.py rename to other/tests_needing_cleanup/test_config.py diff --git a/other/tests_reintegrate/test_install.py b/other/tests_needing_cleanup/test_install.py similarity index 100% rename from other/tests_reintegrate/test_install.py rename to other/tests_needing_cleanup/test_install.py From bd13fbab3a99ff83712d3a2d3b3628cf26292770 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 18:45:09 +0200 Subject: [PATCH 0968/4212] remove old tests from config install and co. Signed-off-by: Nico Schottelius --- other/tests_needing_cleanup/nico_ui.py | 45 ------- other/tests_needing_cleanup/test_config.py | 101 --------------- other/tests_needing_cleanup/test_install.py | 131 -------------------- 3 files changed, 277 deletions(-) delete mode 100644 other/tests_needing_cleanup/nico_ui.py delete mode 100644 other/tests_needing_cleanup/test_config.py delete mode 100644 other/tests_needing_cleanup/test_install.py diff --git a/other/tests_needing_cleanup/nico_ui.py b/other/tests_needing_cleanup/nico_ui.py deleted file mode 100644 index 8ce98043..00000000 --- a/other/tests_needing_cleanup/nico_ui.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 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 subprocess -import unittest - -cdist_commands=["banner", "config", "install"] - -cdist_exec_path = os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "../bin/cdist")) - -class UI(unittest.TestCase): - def test_banner(self): - self.assertEqual(subprocess.call([cdist_exec_path, "banner"]), 0) - - def test_help(self): - for cmd in cdist_commands: - self.assertEqual(subprocess.call([cdist_exec_path, cmd, "-h"]), 0) - - # FIXME: mockup needed - def test_config_localhost(self): - for cmd in cdist_commands: - self.assertEqual(subprocess.call([cdist_exec_path, "config", "localhost"]), 0) - diff --git a/other/tests_needing_cleanup/test_config.py b/other/tests_needing_cleanup/test_config.py deleted file mode 100644 index 0632ebcc..00000000 --- a/other/tests_needing_cleanup/test_config.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 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 sys -import tempfile -import unittest - -sys.path.insert(0, os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) - -import cdist.config - -cdist_exec_path = os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "bin/cdist")) - - -class Config(unittest.TestCase): - def setUp(self): - self.temp_dir = tempfile.mkdtemp() - self.init_manifest = os.path.join(self.temp_dir, "manifest") - self.config = cdist.config.Config("localhost", - initial_manifest=self.init_manifest, - exec_path=cdist_exec_path) - self.config.link_emulator() - - def test_initial_manifest_different_parameter(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + " --mode 0700\n", - "__file " + self.temp_dir + " --mode 0600\n", - ]) - manifest_fd.close() - - self.assertRaises(cdist.Error, self.config.run_initial_manifest) - - def test_initial_manifest_parameter_added(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + '\n', - "__file " + self.temp_dir + " --mode 0600\n", - ]) - manifest_fd.close() - - self.assertRaises(cdist.Error, self.config.run_initial_manifest) - - def test_initial_manifest_parameter_removed(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + " --mode 0600\n", - "__file " + self.temp_dir + "\n", - ]) - manifest_fd.close() - - self.assertRaises(cdist.Error, self.config.run_initial_manifest) - - def test_initial_manifest_non_existent_command(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "thereisdefinitelynosuchcommend"]) - manifest_fd.close() - - self.assertRaises(cdist.Error, self.config.run_initial_manifest) - - def test_initial_manifest_parameter_twice(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + " --mode 0600\n", - "__file " + self.temp_dir + " --mode 0600\n", - ]) - manifest_fd.close() - - try: - self.config.run_initial_manifest() - except cdist.Error: - failed = True - else: - failed = False - - self.assertFalse(failed) - - diff --git a/other/tests_needing_cleanup/test_install.py b/other/tests_needing_cleanup/test_install.py deleted file mode 100644 index d6502b46..00000000 --- a/other/tests_needing_cleanup/test_install.py +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 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 sys -import tempfile -import unittest - -sys.path.insert(0, os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) - -import cdist.config -import cdist.test - -class Install(unittest.TestCase): - def setUp(self): - self.temp_dir = tempfile.mkdtemp() - self.init_manifest = os.path.join(self.temp_dir, "manifest") - - os.environ['__remote_exec'] = "ssh -o User=root -q" - os.environ['__remote_copy'] = "scp -o User=root -q" - - self.config = cdist.config.Config("localhost", - initial_manifest=self.init_manifest, - exec_path=cdist.test.cdist_exec_path) - self.config.link_emulator() - - -### NEW FOR INSTALL ############################################################ - - def test_explorer_ran(self): - """Check that all explorers returned a result""" - self.config.run_global_explores() - explorers = self.config.path.list_global_explorers() - - for explorer in explorers: - output = self.config.path.global_explorer_output_path(explorer) - self.assertTrue(os.path.isfile(output)) - - def test_manifest_uses_install_types_only(self): - """Check that objects created from manifest are only of install type""" - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + " --mode 0700\n", - "__partition_msdos /dev/null --type 82\n", - ]) - manifest_fd.close() - - self.config.run_initial_manifest() - - # FIXME: check that only __partition_msdos objects are created! - - self.assertFalse(failed) - - -### OLD FROM CONFIG ############################################################ - def test_initial_manifest_different_parameter(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + " --mode 0700\n", - "__file " + self.temp_dir + " --mode 0600\n", - ]) - manifest_fd.close() - - self.assertRaises(cdist.Error, self.config.run_initial_manifest) - - def test_initial_manifest_parameter_added(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + '\n', - "__file " + self.temp_dir + " --mode 0600\n", - ]) - manifest_fd.close() - - self.assertRaises(cdist.Error, self.config.run_initial_manifest) - - def test_initial_manifest_parameter_removed(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + " --mode 0600\n", - "__file " + self.temp_dir + "\n", - ]) - manifest_fd.close() - - self.assertRaises(cdist.Error, self.config.run_initial_manifest) - - def test_initial_manifest_non_existent_command(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "thereisdefinitelynosuchcommend"]) - manifest_fd.close() - - self.assertRaises(cdist.Error, self.config.run_initial_manifest) - - def test_initial_manifest_parameter_twice(self): - manifest_fd = open(self.init_manifest, "w") - manifest_fd.writelines(["#!/bin/sh\n", - "__file " + self.temp_dir + " --mode 0600\n", - "__file " + self.temp_dir + " --mode 0600\n", - ]) - manifest_fd.close() - - try: - self.config.run_initial_manifest() - except cdist.Error: - failed = True - else: - failed = False - - self.assertFalse(failed) - - From a69069f28cfc3ea9b348e8a42ca9bec7420da69c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 18:45:36 +0200 Subject: [PATCH 0969/4212] make unfinished examples disappear Signed-off-by: Nico Schottelius --- .../conf/type/__nico_afs/files/afs/CellServDB | 2 - .../conf/type/__nico_afs/files/afs/ThisCell | 1 - .../conf/type/__nico_afs/files/krb5/krb5.conf | 28 ----------- .../conf/type/__nico_afs/files/ssh/JAS.pub | 1 - .../type/__nico_afs/files/ssh/bugblue.pub | 1 - .../type/__nico_afs/files/ssh/docsteel.pub | 1 - .../type/__nico_afs/files/ssh/downhill.pub | 1 - .../type/__nico_afs/files/ssh/sur5r@samsa.pub | 1 - .../nico/conf/type/__nico_afs/manifest | 45 ------------------ .../nico/conf/type/__nico_afs/singleton | 0 .../conf/type/__nico_desktop/files/hostname | 1 - .../type/__nico_desktop/files/slim-preseed | 4 -- .../nico/conf/type/__nico_desktop/manifest | 47 ------------------- .../type/__nico_desktop/parameter/required | 1 - .../nico/conf/type/__nico_desktop/singleton | 0 .../conf/type/__nico_mpd/files/slim-preseed | 4 -- .../nico/conf/type/__nico_mpd/manifest | 24 ---------- .../conf/type/__nico_mpd/parameter/required | 1 - .../nico/conf/type/__nico_mpd/singleton | 0 .../type/__nico_network/files/interfaces-eth0 | 6 --- .../__nico_network/files/interfaces-wlan0 | 11 ----- .../nico/conf/type/__nico_network/manifest | 43 ----------------- .../type/__nico_network/parameter/required | 1 - .../nico/conf/type/__nico_network/singleton | 0 .../type/__nico_nfs_client/files/slim-preseed | 4 -- .../nico/conf/type/__nico_nfs_client/manifest | 47 ------------------- .../conf/type/__nico_nfs_client/singleton | 0 .../nico/conf/type/__nico_notebook/manifest | 38 --------------- .../nico/conf/type/__nico_notebook/singleton | 0 .../nico/conf/type/__nico_packages/manifest | 33 ------------- .../nico/conf/type/__nico_packages/singleton | 0 .../conf/type/__nico_sudo/files/sudo-nico | 13 ----- .../nico/conf/type/__nico_sudo/manifest | 27 ----------- .../conf/type/__nico_sudo/parameter/gencode | 31 ------------ .../conf/type/__nico_sudo/parameter/manifest | 31 ------------ .../conf/type/__nico_sudo/parameter/optional | 0 .../conf/type/__nico_sudo/parameter/required | 0 .../nico/conf/type/__nico_sudo/singleton | 0 .../conf/type/__nico_tee/files/99-apt-nico | 2 - .../nico/conf/type/__nico_tee/files/hostname | 1 - .../nico/conf/type/__nico_tee/manifest | 28 ----------- .../nico/conf/type/__nico_tee/singleton | 0 42 files changed, 479 deletions(-) delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/afs/CellServDB delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/afs/ThisCell delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/krb5/krb5.conf delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/JAS.pub delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/bugblue.pub delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/docsteel.pub delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/downhill.pub delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub delete mode 100755 other/examples_needing_cleanup/nico/conf/type/__nico_afs/manifest delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_afs/singleton delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_desktop/files/hostname delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_desktop/files/slim-preseed delete mode 100755 other/examples_needing_cleanup/nico/conf/type/__nico_desktop/manifest delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_desktop/parameter/required delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_desktop/singleton delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_mpd/files/slim-preseed delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_mpd/manifest delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_mpd/parameter/required delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_mpd/singleton delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_network/files/interfaces-eth0 delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_network/files/interfaces-wlan0 delete mode 100755 other/examples_needing_cleanup/nico/conf/type/__nico_network/manifest delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_network/parameter/required delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_network/singleton delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/files/slim-preseed delete mode 100755 other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/manifest delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/singleton delete mode 100755 other/examples_needing_cleanup/nico/conf/type/__nico_notebook/manifest delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_notebook/singleton delete mode 100755 other/examples_needing_cleanup/nico/conf/type/__nico_packages/manifest delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_packages/singleton delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_sudo/files/sudo-nico delete mode 100755 other/examples_needing_cleanup/nico/conf/type/__nico_sudo/manifest delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/gencode delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/manifest delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/optional delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/required delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_sudo/singleton delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_tee/files/99-apt-nico delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_tee/files/hostname delete mode 100755 other/examples_needing_cleanup/nico/conf/type/__nico_tee/manifest delete mode 100644 other/examples_needing_cleanup/nico/conf/type/__nico_tee/singleton diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/afs/CellServDB b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/afs/CellServDB deleted file mode 100644 index dbd238d7..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/afs/CellServDB +++ /dev/null @@ -1,2 +0,0 @@ ->eof -129.132.186.89 # sgv-afs-sur5r diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/afs/ThisCell b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/afs/ThisCell deleted file mode 100644 index 37fb719b..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/afs/ThisCell +++ /dev/null @@ -1 +0,0 @@ -eof diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/krb5/krb5.conf b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/krb5/krb5.conf deleted file mode 100644 index 3b8259cb..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/krb5/krb5.conf +++ /dev/null @@ -1,28 +0,0 @@ -[libdefaults] - default_realm = EOF - -# The following krb5.conf variables are only for MIT Kerberos. - krb4_config = /etc/krb.conf - krb4_realms = /etc/krb.realms - kdc_timesync = 1 - ccache_type = 4 - forwardable = true - proxiable = true - allow_weak_crypto = true - -[realms] - EOF = { - kdc = sgv-afs-sur5r.ethz.ch - admin_server = sgv-afs-sur5r.ethz.ch - } - - -[login] - krb4_convert = true - krb4_get_tickets = false - -[logging] - default = FILE:/var/log/krb5.log - kdc = FILE:/var/log/krb5kdc/kdc.log - admin_server = FILE:/var/log/krb5kdc/kadmin.log - diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/JAS.pub b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/JAS.pub deleted file mode 100644 index 222410d5..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/JAS.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/Gbl64LT3VD5hsVtk1w670S2gue1OaW9XLg/Vk/iBqsYYrLGZh+TXJsAsXOSF1sZH6QSdNlpzTPsno9KFCTQTNlYe0IrWPGRrFGw1or3M6OugJrMeSiMYQ5nhH6HMjhzCFHH8Xh4Yku8fgi3ejPpySW8umx7nBL7ndiEJ9Y+lixNWMirEPLpz9YufFm9u8GX6bPrmjIBz6EhfxaqJ2N/N6gQB+4PmNopzqWHm+n4LToA9N8qwetSfhgEg7DVaD9SrJNjNTGSgii6CritT9sF8ZBq5CZG58DTyrxCndhhHte5OCGMb5ENgO4OBHA0MrD56unHrdAZCCosa9rI+pIll abr@cltHome03 diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/bugblue.pub b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/bugblue.pub deleted file mode 100644 index cccbe02f..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/bugblue.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA17fnWJMTAuIvWcdnsasdfEkBabeXEhYaR03Qc/KBpS+iToSeUzlc5SeXoAczqSMsC0uYpDnhll9q3aAN82Xo06RI2ytd7TeXvFcVwzvXB+sNUsvtyPZ5Uyx7d2WTI87bm169KhGTJCaww8p+qa2UhkjOOaXZwMGjkHlvZ3WSZr5mLar9O3r4PG8SIqoFF0m+tcc2fcWIK3df3jWIk8g6j/jTaoIa18qsK/rtO90Ql20FMQJOZTKGKjHIOx2FLnXY5WKrXmXyyffgFpqi1rUAkCkjCKnm65fDjecn6FplzSUuZo/IB2GnHGNQVnNkU/18/G8KQKu9clkMxuUl8DYJBQ== bugblue@jabber.eof.name diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/docsteel.pub b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/docsteel.pub deleted file mode 100644 index 4b40d089..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/docsteel.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA1xfKoN8D3I0uGvc66E2cpnutdgALbSVIIWy0SBGV1ZLA4CehAL5BpMO0EI1TfH4LGgpjg+CnLXOSMd+bnvWjPTxGUbGcmK45UYCyn1LzSAfVKi9Mr06wbvQj0h5w1zEAwDqt63SHGjGOHO4TeCSrPxEROPMbZ1mP1ECsb4f+3WLWE5icbzOb/QMx2zNDd29rVvFJiJMOg4AiIs7pl/T7Qxg2yN6YlDIXSXLiE2i98O26kBNWRgAFcTNBqoUs5AkZ2F4LPUGbyuLpV+wtlpYcQXOUTLoRlKw+ovBQH3L6ae9n6+rFTIEEAS08C0MOzQPC3QjmfRMC8mxVkn22XnpHbQ== default diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/downhill.pub b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/downhill.pub deleted file mode 100644 index bde07c29..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/downhill.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss 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 downhill@downhill.homelinux.net diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub deleted file mode 100644 index a1fcba83..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/files/ssh/sur5r@samsa.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAABIwAABAEApDTX05FmMS1ArryWL6MmgcQeRFRU6E4Rgg+cPTeBuHCtBnnUoCUw7lhD2OICHIzQnfyMQasJOHH/4PnsrAxyO1Lm4KtK3zsdSdA5auunxAy0n7PZwaRKDTXCgpfXvi7ZAlzA+Mq/OjqtltfqdJgToYKxWoehwmltlwibuU1fke2v85VcTbCQRAttc6+0Y+3fToyTWecZM+X0uCsz1B5s07CLrMddo3lPVAlhYStSCbHflsM6C+NQAbxlsjkVFavii7WDYMYOd5FU0jIJt2Fy6u7Lx0ubY6hgGsP+mDOCCaRGA0JdjvWctBruj227CLswtAnYIFxvPi82R/okfx2X4YPtbqUPyLaUbr0G93g+raJEr/uXbour+wRd0TewOLq4VstwOsDfj9pm0wMFyIbsY2y97k6UZc0TE5pu3USGyW9/ainy5zD4TK4Al8lMkDHil6eItlud66KDZ4p5n5gzwuBj+ZOpOcBD5ZqLqDKst3YlHx6EuA1ddObBTrfy/nGphYYhWl1rbJ9+XOhSD8f/LIr5mjLEpSta6rHS/3dpLpSRGIy8ReG0RLbfay/fS74Iw0rEGOe/XgrfNDT0VwsgJMNV81sReepk27DaFD/vES/iPAymbbId8e8IQ7kDbhV0yK0yTkCZ5capqa9HXcut0SFRVJYGxzGT+ji5o/DcyAcaQHK9IW5i89sp04aVtZO+KZZDd2GmcDy+v9+fmBsSx2AFsoOQSXX31jJVdAXNw8idTNb88/3XDZIIEl+1KJ8Pv4UFXBW72RArpOxOrsDZYQjtaLQ4ZjTP3h823ZrBh4W3osb1znS7x4MmWBLPkmLCS0zmN8nbqhKi5EsTmSheCjCzySGShkyeqSGRIRGFk5PUsgh7hYvE+f7BhWD6x8MHbuUp9y0ODQonp022Dc4WzTc6Aa023MSNRuwV373tOqPYveuoPXDTS6vzV3IjXfv9a844HIkUTZbErxkavGBN5TEMgrALJkc8LS6M6Zg8odou8N2vWoNaKPn/DC5+H+FxJ2PSrK93hfzRMgvFvPSFzzDnixUFJClSqxf1Wvx9OW2pUuePAXBlcuFhAAnWV6w7fkmII8+qGk3m438dt2Sq6owmItzqIeJ6bohMsb9ejxeDyfk9DAQwmjS7S+BY47bYgAfsesZNRnlbeffp4rP0MAx4KoUXoNzb8tl1Jljulq58C0e5+EzRILqOYLM7WytY3+giqxN4zQJsqDp3mgSUaZ5SEHnA8JVi77MvABSoVclrEaujSLVEkxTBOiR252SFUWp3lWbxpGzBjd7gX4JAiytJql5xr+o4+nCy2O2laE6c2xS7en6SVEgC7jWflCsbDfvy9U+w1qOxa0j9fXE9Rw== sur5r@samsa diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/manifest deleted file mode 100755 index 7b4cc493..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/manifest +++ /dev/null @@ -1,45 +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 . -# -# - - -__directory /root/.ssh --mode 0700 - -__file /root/.ssh/authorized_keys --mode 0600 - -cd "$__type/files/ssh" -for key in *; do - require="__directory/root/.ssh" \ - __addifnosuchline ssh-$key --file /root/.ssh/authorized_keys \ - --line "$(cat "$key")" -done - -for pkg in openafs-client openafs-krb5 krb5-user; do - __package $pkg --state installed -done - -# Kerberos Config -__file /etc/krb5.conf --source "$__type/files/krb5/krb5.conf" - -# AFS config -cd "$__type/files/afs" -for afsconf in *; do - __file /etc/openafs/$afsconf --source "$__type/files/afs/$afsconf" -done diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_afs/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_afs/singleton deleted file mode 100644 index e69de29b..00000000 diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/files/hostname b/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/files/hostname deleted file mode 100644 index a4df6242..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/files/hostname +++ /dev/null @@ -1 +0,0 @@ -scheibe diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/files/slim-preseed b/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/files/slim-preseed deleted file mode 100644 index 01448d74..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/files/slim-preseed +++ /dev/null @@ -1,4 +0,0 @@ -# Use slim, not gdm, if both are available -# Setup for slim, but value is available for gdm as well: -# gdm shared/default-x-display-manager select slim -slim shared/default-x-display-manager select slim diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/manifest deleted file mode 100755 index 7fbbe70f..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/manifest +++ /dev/null @@ -1,47 +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 . -# -# - -# -# Ensure hostname is setup -# -__file /etc/hostname --source "$__object/parameter/hostname" - -# All Linux distros have those -for pkg in dvdbackup mplayer x11vnc xfmpc; do - __package $pkg --state installed -done - -case "$(cat "$__global/explorer/os")" in - debian|ubuntu) - require="__package/zsh" __user lyni --uid 1000 --shell /bin/zsh - - for pkg in chromium-browser xfce4 xtightvncviewer; do - __package $pkg --state installed - done - - # Make slim default desktop on Debian/Ubuntu - __debconf_set_selections slim --file "$__type/files/slim-preseed" - require="__debconf_set_selections/slim" __package_apt slim --state installed - ;; -esac - -# Including gaming fun - not within examples, too big for core inclusion :-p -# __nico_dosbox diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/parameter/required b/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/parameter/required deleted file mode 100644 index ecd88aee..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/parameter/required +++ /dev/null @@ -1 +0,0 @@ -hostname diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_desktop/singleton deleted file mode 100644 index e69de29b..00000000 diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/files/slim-preseed b/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/files/slim-preseed deleted file mode 100644 index 01448d74..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/files/slim-preseed +++ /dev/null @@ -1,4 +0,0 @@ -# Use slim, not gdm, if both are available -# Setup for slim, but value is available for gdm as well: -# gdm shared/default-x-display-manager select slim -slim shared/default-x-display-manager select slim diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/manifest deleted file mode 100644 index d339bdf3..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/manifest +++ /dev/null @@ -1,24 +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 . -# -# - -__package mpd --state installed - -require="__package/mpd" __file /etc/mpd.conf --source "$__type/files/mpd.conf" diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/parameter/required b/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/parameter/required deleted file mode 100644 index ecd88aee..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/parameter/required +++ /dev/null @@ -1 +0,0 @@ -hostname diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_mpd/singleton deleted file mode 100644 index e69de29b..00000000 diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_network/files/interfaces-eth0 b/other/examples_needing_cleanup/nico/conf/type/__nico_network/files/interfaces-eth0 deleted file mode 100644 index 2a92eade..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_network/files/interfaces-eth0 +++ /dev/null @@ -1,6 +0,0 @@ -# generated by cdist -auto lo eth0 - -iface lo inet loopback - -iface eth0 inet dhcp diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_network/files/interfaces-wlan0 b/other/examples_needing_cleanup/nico/conf/type/__nico_network/files/interfaces-wlan0 deleted file mode 100644 index 49508eb2..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_network/files/interfaces-wlan0 +++ /dev/null @@ -1,11 +0,0 @@ -# This file describes the network interfaces available on your system -# and how to activate them. For more information, see interfaces(5). - -# The loopback network interface -auto lo -iface lo inet loopback - -auto wlan0 -iface wlan0 inet dhcp - wpa-ssid undef - wpa-psk rotrussland diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_network/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_network/manifest deleted file mode 100755 index 012c47f7..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_network/manifest +++ /dev/null @@ -1,43 +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 . -# -# - -case "$(cat "$__global/explorer/os")" in - debian|ubuntu) - - interface="$(cat $__object/parameter/interface)" - - # - # Only Debian and alike supported currently - # - destination=/etc/network/interfaces - case "$interface" in - eth0|wlan0) - source="$__type/files/interfaces-${interface}" - ;; - *) - echo "Unknown interface: $interface" >&2 - exit 1 - ;; - esac - - __file "$destination" --source "$source" - ;; -esac diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_network/parameter/required b/other/examples_needing_cleanup/nico/conf/type/__nico_network/parameter/required deleted file mode 100644 index b529896a..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_network/parameter/required +++ /dev/null @@ -1 +0,0 @@ -interface diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_network/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_network/singleton deleted file mode 100644 index e69de29b..00000000 diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/files/slim-preseed b/other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/files/slim-preseed deleted file mode 100644 index 01448d74..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/files/slim-preseed +++ /dev/null @@ -1,4 +0,0 @@ -# Use slim, not gdm, if both are available -# Setup for slim, but value is available for gdm as well: -# gdm shared/default-x-display-manager select slim -slim shared/default-x-display-manager select slim diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/manifest deleted file mode 100755 index ed1a872b..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/manifest +++ /dev/null @@ -1,47 +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 . -# -# - -__directory /home/services - -for nfsshare in audio video; do - dir="/home/services/$nfsshare" - __addifnosuchline nfs-$nfsshare --file /etc/fstab \ - --line "192.168.42.1:$dir $dir nfs defaults 0 0" - require="__directory/home/services" __directory $dir -done - -__directory /home/services/eingehend -for nfsshare in bibliothek buch spiegel; do - dir="/home/services/eingehend/$nfsshare" - __addifnosuchline nfs-$nfsshare --file /etc/fstab \ - --line "192.168.42.1:$dir $dir nfs defaults,noauto 0 0" - require="__directory/home/services" __directory $dir -done - -case "$(cat "$__global/explorer/os")" in - debian|ubuntu) - __package nfs-common --state installed - ;; - - fedora|archlinux) - __package nfs-utils --state installed - ;; -esac diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_nfs_client/singleton deleted file mode 100644 index e69de29b..00000000 diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_notebook/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_notebook/manifest deleted file mode 100755 index 7b010230..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_notebook/manifest +++ /dev/null @@ -1,38 +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 . -# -# - -require="__package/zsh" __user nico --uid 1000 --shell /bin/zsh - -# -# Backup HD -# -for hd in usbhd eth-usbhd; do - dir="/home/services/$hd" - __addifnosuchline hd-$hd --file /etc/fstab \ - --line "/dev/mapper/$hd $dir auto defaults,noauto 0 0" - __directory $dir -done - -# -# Standard everywhere packages -# -__nico_packages -__motd diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_notebook/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_notebook/singleton deleted file mode 100644 index e69de29b..00000000 diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_packages/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_packages/manifest deleted file mode 100755 index a1e663f7..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_packages/manifest +++ /dev/null @@ -1,33 +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 . -# -# - -for pkg in atop screen vim wget zsh; do - __package "$pkg" --state installed -done - -case "$(cat "$__global/explorer/os")" in - fedora) - __package nc --state installed - ;; - *) - __package netcat --state installed - ;; -esac diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_packages/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_packages/singleton deleted file mode 100644 index e69de29b..00000000 diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/files/sudo-nico b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/files/sudo-nico deleted file mode 100644 index d904c319..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/files/sudo-nico +++ /dev/null @@ -1,13 +0,0 @@ -# -# Cdist managed file -# - -# Personal one: nico, shared one: lyni -User_Alias NICO = nico, lyni - -Defaults timestamp_timeout=5 -Defaults !tty_tickets - -# Give out permissions -NICO ALL=(ALL) ALL -NICO ALL=(ALL) NOPASSWD: /usr/sbin/pm-suspend diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/manifest deleted file mode 100755 index 59315313..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/manifest +++ /dev/null @@ -1,27 +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 . -# -# - -destination=/etc/sudoers.d/nico -source="$__type/files/sudo-nico" - -require="__package/sudo" __file "$destination" --source "$source" --mode 0440 - -__package sudo --state installed diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/gencode b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/gencode deleted file mode 100644 index 74792abf..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/gencode +++ /dev/null @@ -1,31 +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 . -# -# -# USEFUL DESCRIPTION -# - -# -# This file should generate code on stdout, which will be collected by cdist -# and run on the target. -# -# To tell cdist to make use of it, you need to make it executable (chmod +x) -# -# - diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/manifest deleted file mode 100644 index c696eda6..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/manifest +++ /dev/null @@ -1,31 +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 . -# -# -# USEFUL DESCRIPTION -# - -# -# This is the manifest, which can be used to create other objects like this: -# __file /path/to/destination --source /from/where/ -# -# To tell cdist to make use of it, you need to make it executable (chmod +x) -# -# - diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/optional b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/optional deleted file mode 100644 index e69de29b..00000000 diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/required b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/parameter/required deleted file mode 100644 index e69de29b..00000000 diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_sudo/singleton deleted file mode 100644 index e69de29b..00000000 diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_tee/files/99-apt-nico b/other/examples_needing_cleanup/nico/conf/type/__nico_tee/files/99-apt-nico deleted file mode 100644 index 8d6d7c82..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_tee/files/99-apt-nico +++ /dev/null @@ -1,2 +0,0 @@ -APT::Periodic::Update-Package-Lists "1"; -APT::Periodic::Unattended-Upgrade "1"; diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_tee/files/hostname b/other/examples_needing_cleanup/nico/conf/type/__nico_tee/files/hostname deleted file mode 100644 index a4df6242..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_tee/files/hostname +++ /dev/null @@ -1 +0,0 @@ -scheibe diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_tee/manifest b/other/examples_needing_cleanup/nico/conf/type/__nico_tee/manifest deleted file mode 100755 index 4c614027..00000000 --- a/other/examples_needing_cleanup/nico/conf/type/__nico_tee/manifest +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# 2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# - - - -__package unattended-upgrades --state installed - -__file /etc/apt/apt.conf.d/99-apt-nico \ - --source "$__type/files/99-apt-nico" \ - --mode 0644 diff --git a/other/examples_needing_cleanup/nico/conf/type/__nico_tee/singleton b/other/examples_needing_cleanup/nico/conf/type/__nico_tee/singleton deleted file mode 100644 index e69de29b..00000000 From 8adb467304f5e124c13ec5620a74498065926996 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 18:47:51 +0200 Subject: [PATCH 0970/4212] +readme Signed-off-by: Nico Schottelius --- other/examples/types/README | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 other/examples/types/README diff --git a/other/examples/types/README b/other/examples/types/README new file mode 100644 index 00000000..f6ea90d6 --- /dev/null +++ b/other/examples/types/README @@ -0,0 +1,3 @@ +This directory contains examples types as being used in real world. + +If you'd like to see your type here, just submit it for inclusion. From 4849149af5e40b4b466401d7d7ee38cc17bf72d8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 18:49:41 +0200 Subject: [PATCH 0971/4212] add example type Signed-off-by: Nico Schottelius --- .../__nico_acpi_supend_on_lid_close/README | 3 ++ .../files/lid.sh | 5 +++ .../files/lid_event | 2 + .../__nico_acpi_supend_on_lid_close/manifest | 43 +++++++++++++++++++ .../__nico_acpi_supend_on_lid_close/singleton | 0 5 files changed, 53 insertions(+) create mode 100644 other/examples/types/__nico_acpi_supend_on_lid_close/README create mode 100755 other/examples/types/__nico_acpi_supend_on_lid_close/files/lid.sh create mode 100644 other/examples/types/__nico_acpi_supend_on_lid_close/files/lid_event create mode 100644 other/examples/types/__nico_acpi_supend_on_lid_close/manifest create mode 100644 other/examples/types/__nico_acpi_supend_on_lid_close/singleton diff --git a/other/examples/types/__nico_acpi_supend_on_lid_close/README b/other/examples/types/__nico_acpi_supend_on_lid_close/README new file mode 100644 index 00000000..b1924140 --- /dev/null +++ b/other/examples/types/__nico_acpi_supend_on_lid_close/README @@ -0,0 +1,3 @@ +This type is used on notebooks to ensure they suspend when the lid is closed. + +It is tested on Archlinux. diff --git a/other/examples/types/__nico_acpi_supend_on_lid_close/files/lid.sh b/other/examples/types/__nico_acpi_supend_on_lid_close/files/lid.sh new file mode 100755 index 00000000..929fbffb --- /dev/null +++ b/other/examples/types/__nico_acpi_supend_on_lid_close/files/lid.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# Nico Schottelius, 20111016 +# Just suspend, my wife does not like to enter a password + +/usr/sbin/pm-suspend diff --git a/other/examples/types/__nico_acpi_supend_on_lid_close/files/lid_event b/other/examples/types/__nico_acpi_supend_on_lid_close/files/lid_event new file mode 100644 index 00000000..294f6d78 --- /dev/null +++ b/other/examples/types/__nico_acpi_supend_on_lid_close/files/lid_event @@ -0,0 +1,2 @@ +event=button/lid.* +action=/etc/acpi/actions/lid.sh "%e" diff --git a/other/examples/types/__nico_acpi_supend_on_lid_close/manifest b/other/examples/types/__nico_acpi_supend_on_lid_close/manifest new file mode 100644 index 00000000..3ef4e971 --- /dev/null +++ b/other/examples/types/__nico_acpi_supend_on_lid_close/manifest @@ -0,0 +1,43 @@ +#!/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 . +# +# + +__package acpid --state installed +__package pm-utils --state installed + +event_dir=/etc/acpi/events +event_file="$event_dir/lid" + +action_dir=/etc/acpi/actions +action_file="$action_dir/lid.sh" + +__directory "$event_dir" --owner root --group root \ + --mode 0755 --parents yes + +__directory "$action_dir" --owner root --group root \ + --mode 0755 --parents yes + +require="__directory/$event_dir" __file "$event_file" \ + --owner root --group root --mode 0644 \ + --source "$__type/files/lid_event" + +require="__directory/$action_dir" __file "$action_file" \ + --owner root --group root --mode 0755 \ + --source "$__type/files/lid.sh" diff --git a/other/examples/types/__nico_acpi_supend_on_lid_close/singleton b/other/examples/types/__nico_acpi_supend_on_lid_close/singleton new file mode 100644 index 00000000..e69de29b From 1e4de3521ac7c611a5e25e8e68acce7f58d90645 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 19:38:50 +0200 Subject: [PATCH 0972/4212] skip errer detection in findline explorer Signed-off-by: Nico Schottelius --- conf/type/__addifnosuchline/explorer/findline | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/conf/type/__addifnosuchline/explorer/findline b/conf/type/__addifnosuchline/explorer/findline index c1633626..ac69a827 100755 --- a/conf/type/__addifnosuchline/explorer/findline +++ b/conf/type/__addifnosuchline/explorer/findline @@ -1,6 +1,7 @@ #!/bin/sh # # 2010-2011 Daniel Roth (dani-cdist@d-roth.li) +# 2011 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -27,6 +28,9 @@ fi regex=$(cat "$__object/parameter/line") if [ -f "$file" ]; then + # sh -e is our environment, we know what we do, + # skip error detection for now + set +e grep -q "^$regex\$" "$file" if [ $? -eq 1 ]; then echo "NOTFOUND" From e64f46ba4eaf67def2f41d4646a6862dffa6eed7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Oct 2011 19:40:02 +0200 Subject: [PATCH 0973/4212] document bugfix for next version Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 04679bec..bc527304 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,6 +1,7 @@ 2.0.3: * Improved logging, added --verbose, by more quiet by default * Bugfix __user: Correct quoting (Steven Armstrong) + * Bugfix __addifnosuchline: Falsely exited * Bugfix requirements: Restore original require="" behaviour * Feature requirements: Check for broken object_ids and abort * Massive refactoring and unittesting introduced (Steven Armstrong) From 71b6616d1e873aef7b1f3cdc58cf4f1809c02f9e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 17 Oct 2011 09:30:22 +0200 Subject: [PATCH 0974/4212] --todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 5 ----- 1 file changed, 5 deletions(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 90040ad6..0bba2132 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -14,11 +14,6 @@ logging: [2] http://blog.ooz.ie/2011/03/python-logging-extending-standard.html -exec local & remote: - - don't capture output by default - - add new mechanism to capture output explicitly - - config_install: - move code for running global and type explorer run to cdist.core.explorer From 22a599185c0228996fc44aa71f94ad942d01f7bd Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 17 Oct 2011 09:33:34 +0200 Subject: [PATCH 0975/4212] todo++ Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index 0bba2132..ede09083 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,3 +1,18 @@ +metaparameters: + - steal the metaparameters from puppet: + + # if I change, tell the other one about it + __file /etc/ssh/sshd_config \ + --notify __init_script/etc/rc.d/sshd + + # whenever the other one changes, I want to know + __init_script /etc/rc.d/sshd \ + --subscribe __file/etc/ssh/sshd_config + + ? how does a type react to a received 'event' + + + logging: - logging from type emulator without clobbering stdout maybe implement logging server as described here [1] From 4dd74687257bcf988957a8624b174eab2a6fe465 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 17 Oct 2011 09:49:33 +0200 Subject: [PATCH 0976/4212] todo++ Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index ede09083..ba18b34c 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,6 +1,14 @@ metaparameters: - steal the metaparameters from puppet: + # I have to be there before the other one + __directory /etc/ssh \ + --before __file/etc/ssh/sshd_config + + # the other one has to be there before me + __file /etc/ssh/sshd_config \ + --after __directory/etc/ssh + # if I change, tell the other one about it __file /etc/ssh/sshd_config \ --notify __init_script/etc/rc.d/sshd From 077a04b89e9c11575deedbe0f3f1d95c0315f0db Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 17 Oct 2011 13:52:45 +0200 Subject: [PATCH 0977/4212] todo++ Signed-off-by: Steven Armstrong --- doc/dev/todo/install | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 doc/dev/todo/install diff --git a/doc/dev/todo/install b/doc/dev/todo/install new file mode 100644 index 00000000..f0e7a040 --- /dev/null +++ b/doc/dev/todo/install @@ -0,0 +1,8 @@ +missing types: + __bootloader + __taball_get + __mount + __mount-point-create + __fstab + - run user postinstall script + - for e.g. reboot, chroot && start sshd From a1b9bec8ce72f1d093ce0182cd78652041c2619f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 09:55:30 +0200 Subject: [PATCH 0978/4212] changes for 2.0.3 Signed-off-by: Nico Schottelius --- doc/changelog | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/doc/changelog b/doc/changelog index bc527304..aae0e04a 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,4 +1,4 @@ -2.0.3: +2.0.3: 2011-10-18 * Improved logging, added --verbose, by more quiet by default * Bugfix __user: Correct quoting (Steven Armstrong) * Bugfix __addifnosuchline: Falsely exited @@ -6,10 +6,6 @@ * Feature requirements: Check for broken object_ids and abort * Massive refactoring and unittesting introduced (Steven Armstrong) - * Feature: Initial undocumented support for replacing - the remote exec and remote copy commands - * Feature: Initial undocumented support for installations in core - 2.0.2: 2011-09-27 * Add support for detection of OpenWall Linux (Matthias Teege) * Add support for __debug variable in manifests From 50cb8807bfaaf9bf8295b00a5edde64539396a20 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 09:57:50 +0200 Subject: [PATCH 0979/4212] fix tests to work (not code :-) Signed-off-by: Nico Schottelius --- lib/cdist/test/explorer/__init__.py | 3 ++- lib/cdist/test/manifest/__init__.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index e6858812..fe23b7e2 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -62,7 +63,7 @@ class ExplorerClassTestCase(unittest.TestCase): self.explorer = explorer.Explorer(self.target_host, self.local, self.remote) - self.log = logging.getLogger("cdist") + self.log = logging.getLogger(self.target_host) def tearDown(self): shutil.rmtree(self.out_path) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index 86885a59..efda5b0a 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -55,7 +55,7 @@ class ManifestTestCase(unittest.TestCase): self.local.create_directories() self.local.link_emulator(cdist.test.cdist_exec_path) self.manifest = manifest.Manifest(self.target_host, self.local) - self.log = logging.getLogger("cdist") + self.log = logging.getLogger(self.target_host) def tearDown(self): shutil.rmtree(self.temp_dir) From 10114dccee00299063f41966750ebc9d09b15476 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 10:44:09 +0200 Subject: [PATCH 0980/4212] add traceback output, uncaught Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-18.traceback-gencode | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 doc/dev/logs/2011-10-18.traceback-gencode diff --git a/doc/dev/logs/2011-10-18.traceback-gencode b/doc/dev/logs/2011-10-18.traceback-gencode new file mode 100644 index 00000000..3de967c1 --- /dev/null +++ b/doc/dev/logs/2011-10-18.traceback-gencode @@ -0,0 +1,28 @@ +[...] +INFO: sgv-sysadmin-01: Running gencode and code for __director/home/services/nfs +Traceback (most recent call last): + File "./bin/cdist", line 211, in + commandline() + File "./bin/cdist", line 110, in commandline + args.func(args) + File "./bin/cdist", line 113, in config + configinstall(args, mode=cdist.config.Config) + File "./bin/cdist", line 131, in configinstall + if not configinstall_onehost(host, args, mode, parallel=False): + File "./bin/cdist", line 177, in configinstall_onehost + c.deploy_and_cleanup() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist-nutzung/lib/cdist/config_install.py", line 71, in deploy_and_cleanup + self.deploy_to() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist-nutzung/lib/cdist/config_install.py", line 66, in deploy_to + self.stage_run() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist-nutzung/lib/cdist/config_install.py", line 164, in stage_run + self.object_run(cdist_object) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist-nutzung/lib/cdist/config_install.py", line 143, in object_run + self.object_run(required_object) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist-nutzung/lib/cdist/config_install.py", line 135, in object_run + cdist_object.ran = True + File "/home/users/nico/oeffentlich/rechner/projekte/cdist-nutzung/lib/cdist/util/fsproperty.py", line 237, in __set__ + open(path, "w").close() +IOError: [Errno 2] No such file or directory: '/home/users/nico/.tmp/tmp2gau4p/out/object/__director/home/services/nfs/.cdist/ran' +[10:43] brief:cdist-nutzung% + From fc3382f976cf3eb581dcead2bea280064d29556f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 12:24:47 +0200 Subject: [PATCH 0981/4212] add log for requirement for non-existent type bug Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-10-18.requirement-object | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 doc/dev/logs/2011-10-18.requirement-object diff --git a/doc/dev/logs/2011-10-18.requirement-object b/doc/dev/logs/2011-10-18.requirement-object new file mode 100644 index 00000000..7e064ef0 --- /dev/null +++ b/doc/dev/logs/2011-10-18.requirement-object @@ -0,0 +1,6 @@ +require="__broken_type/foo" breaks too late + +- always catch OSError/IOError: (check all occurences) +- type __director does not exist, abort in emulator + - if called type is not existing + - if required type is not existing From 16ab49462899bb8a076860f72fc6c180704a24de Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 12:39:36 +0200 Subject: [PATCH 0982/4212] doc++ Signed-off-by: Steven Armstrong --- doc/dev/logs/2011-10-18.requirement-object | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/logs/2011-10-18.requirement-object b/doc/dev/logs/2011-10-18.requirement-object index 7e064ef0..47873aa4 100644 --- a/doc/dev/logs/2011-10-18.requirement-object +++ b/doc/dev/logs/2011-10-18.requirement-object @@ -4,3 +4,5 @@ require="__broken_type/foo" breaks too late - type __director does not exist, abort in emulator - if called type is not existing - if required type is not existing +- type constructor fails if type does not exist +- test type emulator with non existent types -> should raise NoSuchTypeError From bd81045caff97395c98629482b61e40c90813082 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 12:43:14 +0200 Subject: [PATCH 0983/4212] test for nonexistent type Signed-off-by: Steven Armstrong --- lib/cdist/test/type/__init__.py | 56 ++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/lib/cdist/test/type/__init__.py b/lib/cdist/test/type/__init__.py index 42234069..dee9d7a6 100644 --- a/lib/cdist/test/type/__init__.py +++ b/lib/cdist/test/type/__init__.py @@ -22,7 +22,7 @@ import os import unittest -import cdist.core +from cdist import core import os.path as op my_dir = op.abspath(op.dirname(__file__)) @@ -33,113 +33,117 @@ class TypeTestCase(unittest.TestCase): def test_list_type_names(self): base_path = op.join(fixtures, 'list_types') - type_names = cdist.core.Type.list_type_names(base_path) + type_names = core.Type.list_type_names(base_path) self.assertEqual(type_names, ['__first', '__second', '__third']) def test_list_types(self): base_path = op.join(fixtures, 'list_types') - types = list(cdist.core.Type.list_types(base_path)) + types = list(core.Type.list_types(base_path)) types_expected = [ - cdist.core.Type(base_path, '__first'), - cdist.core.Type(base_path, '__second'), - cdist.core.Type(base_path, '__third'), + core.Type(base_path, '__first'), + core.Type(base_path, '__second'), + core.Type(base_path, '__third'), ] self.assertEqual(types, types_expected) def test_only_one_instance(self): base_path = fixtures - cdist_type1 = cdist.core.Type(base_path, '__name_path') - cdist_type2 = cdist.core.Type(base_path, '__name_path') + cdist_type1 = core.Type(base_path, '__name_path') + cdist_type2 = core.Type(base_path, '__name_path') self.assertEqual(id(cdist_type1), id(cdist_type2)) + def test_nonexistent_type(self): + base_path = fixtures + self.assertRaises(core.NoSuchTypeError, core.Type, base_path, '__i-dont-exist') + def test_name(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') + cdist_type = core.Type(base_path, '__name_path') self.assertEqual(cdist_type.name, '__name_path') def test_path(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') + cdist_type = core.Type(base_path, '__name_path') self.assertEqual(cdist_type.path, '__name_path') def test_base_path(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') + cdist_type = core.Type(base_path, '__name_path') self.assertEqual(cdist_type.base_path, base_path) def test_absolute_path(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') + cdist_type = core.Type(base_path, '__name_path') self.assertEqual(cdist_type.absolute_path, os.path.join(base_path, '__name_path')) def test_manifest_path(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') + cdist_type = core.Type(base_path, '__name_path') self.assertEqual(cdist_type.manifest_path, os.path.join('__name_path', 'manifest')) def test_explorer_path(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') + cdist_type = core.Type(base_path, '__name_path') self.assertEqual(cdist_type.explorer_path, os.path.join('__name_path', 'explorer')) def test_gencode_local_path(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') + cdist_type = core.Type(base_path, '__name_path') self.assertEqual(cdist_type.gencode_local_path, os.path.join('__name_path', 'gencode-local')) def test_gencode_remote_path(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__name_path') + cdist_type = core.Type(base_path, '__name_path') self.assertEqual(cdist_type.gencode_remote_path, os.path.join('__name_path', 'gencode-remote')) def test_singleton_is_singleton(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__singleton') + cdist_type = core.Type(base_path, '__singleton') self.assertTrue(cdist_type.is_singleton) def test_not_singleton_is_singleton(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__not_singleton') + cdist_type = core.Type(base_path, '__not_singleton') self.assertFalse(cdist_type.is_singleton) def test_install_is_install(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__install') + cdist_type = core.Type(base_path, '__install') self.assertTrue(cdist_type.is_install) def test_not_install_is_install(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__not_install') + cdist_type = core.Type(base_path, '__not_install') self.assertFalse(cdist_type.is_install) def test_with_explorers(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__with_explorers') + cdist_type = core.Type(base_path, '__with_explorers') self.assertEqual(cdist_type.explorers, ['whatever']) def test_without_explorers(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__without_explorers') + cdist_type = core.Type(base_path, '__without_explorers') self.assertEqual(cdist_type.explorers, []) def test_with_required_parameters(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__with_required_parameters') + cdist_type = core.Type(base_path, '__with_required_parameters') self.assertEqual(cdist_type.required_parameters, ['required1', 'required2']) def test_without_required_parameters(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__without_required_parameters') + cdist_type = core.Type(base_path, '__without_required_parameters') self.assertEqual(cdist_type.required_parameters, []) def test_with_optional_parameters(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__with_optional_parameters') + cdist_type = core.Type(base_path, '__with_optional_parameters') self.assertEqual(cdist_type.optional_parameters, ['optional1', 'optional2']) def test_without_optional_parameters(self): base_path = fixtures - cdist_type = cdist.core.Type(base_path, '__without_optional_parameters') + cdist_type = core.Type(base_path, '__without_optional_parameters') self.assertEqual(cdist_type.optional_parameters, []) ''' From a0a4a7382d27cf79d111fc7efcc1f6892c3bccb0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 12:44:07 +0200 Subject: [PATCH 0984/4212] import NoSuchTypeError into cdist.core namespace Signed-off-by: Steven Armstrong --- lib/cdist/core/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/core/__init__.py b/lib/cdist/core/__init__.py index 507082a3..ac5bbf2f 100644 --- a/lib/cdist/core/__init__.py +++ b/lib/cdist/core/__init__.py @@ -20,6 +20,7 @@ # from cdist.core.type import Type +from cdist.core.type import NoSuchTypeError from cdist.core.object import Object from cdist.core.object import IllegalObjectIdError from cdist.core.explorer import Explorer From 95a858c35085ae2218058de73ca589410977d213 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 12:46:06 +0200 Subject: [PATCH 0985/4212] implement: fail if type does not exist on the filesystem Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index ce37769e..678120aa 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -25,6 +25,15 @@ import os import cdist +class NoSuchTypeError(cdist.Error): + def __init__(self, type_path, type_absolute_path): + self.type_path = type_path + self.type_absolute_path = type_absolute_path + + def __str__(self): + return "Type '%' does not exist at %s" % (self.type_path, self.type_absolute_path) + + class Type(object): """Represents a cdist type. @@ -62,6 +71,8 @@ class Type(object): self.name = name self.path = self.name self.absolute_path = os.path.join(self.base_path, self.path) + if not os.path.isdir(self.absolute_path): + raise NoSuchTypeError(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") From 4975b4643a7a16203d5ddb2ef6923fa04d4d973c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 13:11:53 +0200 Subject: [PATCH 0986/4212] --typo Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index 678120aa..02648b76 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -31,7 +31,7 @@ class NoSuchTypeError(cdist.Error): self.type_absolute_path = type_absolute_path def __str__(self): - return "Type '%' does not exist at %s" % (self.type_path, self.type_absolute_path) + return "Type '%s' does not exist at %s" % (self.type_path, self.type_absolute_path) class Type(object): From 64edfc464038215bbf969ef7a5c775b4524f08af Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 13:19:37 +0200 Subject: [PATCH 0987/4212] add tests for emulator Signed-off-by: Steven Armstrong --- lib/cdist/test/emulator/__init__.py | 75 +++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 lib/cdist/test/emulator/__init__.py diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py new file mode 100644 index 00000000..66e7918a --- /dev/null +++ b/lib/cdist/test/emulator/__init__.py @@ -0,0 +1,75 @@ +# -*- 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 tempfile +import unittest +import shutil + +from cdist import test +from cdist.exec import local +from cdist import emulator +from cdist import core + +local_base_path = test.cdist_base_path + + +class EmulatorTestCase(unittest.TestCase): + + def mkdtemp(self, **kwargs): + return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) + + def mkstemp(self, **kwargs): + return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) + + def setUp(self): + self.orig_environ = os.environ + os.environ = os.environ.copy() + self.temp_dir = self.mkdtemp() + handle, self.script = self.mkstemp(dir=self.temp_dir) + self.target_host = 'localhost' + out_path = self.temp_dir + self.local = local.Local(self.target_host, local_base_path, out_path) + self.local.create_directories() + self.env = { + 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), + '__target_host': self.target_host, + '__global': self.local.out_path, + '__cdist_type_base_path': self.local.type_path, # for use in type emulator + '__manifest': self.local.manifest_path, + '__cdist_manifest': self.script, + } + + def tearDown(self): + os.environ = self.orig_environ + shutil.rmtree(self.temp_dir) + + def test_nonexistent_type_exec(self): + argv = ['__does-not-exist'] + os.environ.update(self.env) + self.assertRaises(core.NoSuchTypeError, emulator.Emulator, argv) + + def test_nonexistent_type_requirement(self): + argv = ['__file', '/tmp/foobar'] + os.environ.update(self.env) + os.environ['require'] = '__does-not-exist/some-id' + emu = emulator.Emulator(argv) + self.assertRaises(core.NoSuchTypeError, emu.run) From e9a0aa186328c034af0ba0ec253d666657c0d859 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 13:20:14 +0200 Subject: [PATCH 0988/4212] fail if requirements type does not exist Signed-off-by: Steven Armstrong --- lib/cdist/emulator.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 103ea8c0..b5682342 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -158,6 +158,9 @@ class Emulator(object): requirement_type_name = requirement_parts[0] requirement_object_id = requirement_parts[1] + # Instantiate type which fails if type does not exist + requirement_type = core.Type(self.type_base_path, requirement_type_name) + # FIXME: Add support for omitted object id == singleton #if len(requirement_parts) == 1: #except IndexError: From 91c1215566004e0fdb3420a5f36165f190fafea0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 13:27:44 +0200 Subject: [PATCH 0989/4212] wrap exceptions in cdist.Error Signed-off-by: Steven Armstrong --- lib/cdist/util/fsproperty.py | 48 ++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index 5b8aa708..5c95d1b4 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -64,9 +64,13 @@ class FileList(collections.MutableSequence): return lines def __write(self, lines): - with open(self.path, 'w') as fd: - for line in lines: - fd.write(str(line) + '\n') + try: + with open(self.path, 'w') as fd: + for line in lines: + fd.write(str(line) + '\n') + except EnvironmentError as e: + # should never happen + raise cdist.Error(str(e)) def __repr__(self): return repr(list(self)) @@ -106,9 +110,12 @@ class DirectoryDict(collections.MutableMapping): if not os.path.isabs(path): raise AbsolutePathRequiredError(path) self.path = path - # create directory if it doesn't exist - if not os.path.isdir(self.path): - os.mkdir(self.path) + try: + # create directory if it doesn't exist + if not os.path.isdir(self.path): + os.mkdir(self.path) + except EnvironmentError as e: + raise cdist.Error(str(e)) if initial is not None: self.update(initial) if kwargs: @@ -125,8 +132,11 @@ class DirectoryDict(collections.MutableMapping): raise KeyError(key) def __setitem__(self, key, value): - with open(os.path.join(self.path, key), "w") as fd: - fd.write(str(value)) + try: + with open(os.path.join(self.path, key), "w") as fd: + fd.write(str(value)) + except EnvironmentError as e: + raise cdist.Error(str(e)) def __delitem__(self, key): try: @@ -135,10 +145,16 @@ class DirectoryDict(collections.MutableMapping): raise KeyError(key) def __iter__(self): - return iter(os.listdir(self.path)) + try: + return iter(os.listdir(self.path)) + except EnvironmentError as e: + raise cdist.Error(str(e)) def __len__(self): - return len(os.listdir(self.path)) + try: + return len(os.listdir(self.path)) + except EnvironmentError as e: + raise cdist.Error(str(e)) class FileBasedProperty(object): @@ -234,7 +250,10 @@ class FileBooleanProperty(FileBasedProperty): def __set__(self, instance, value): path = self._get_path(instance) if value: - open(path, "w").close() + try: + open(path, "w").close() + except EnvironmentError as e: + raise cdist.Error(str(e)) else: try: os.remove(path) @@ -262,8 +281,11 @@ class FileStringProperty(FileBasedProperty): def __set__(self, instance, value): path = self._get_path(instance) if value: - with open(path, "w") as fd: - fd.write(str(value)) + try: + with open(path, "w") as fd: + fd.write(str(value)) + except EnvironmentError as e: + raise cdist.Error(str(e)) else: try: os.remove(path) From 71606370148a0b20ab34d9c15af7f0612cb5ede3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 13:29:44 +0200 Subject: [PATCH 0990/4212] remove trailing whitespace: :%s/ *$//g Signed-off-by: Nico Schottelius --- lib/cdist/util/fsproperty.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index 5c95d1b4..55428c4d 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/cdist/util/fsproperty.py @@ -77,7 +77,7 @@ class FileList(collections.MutableSequence): def __getitem__(self, index): return self.__read()[index] - + def __setitem__(self, index, value): lines = self.__read() lines[index] = value @@ -134,7 +134,7 @@ class DirectoryDict(collections.MutableMapping): def __setitem__(self, key, value): try: with open(os.path.join(self.path, key), "w") as fd: - fd.write(str(value)) + fd.write(str(value)) except EnvironmentError as e: raise cdist.Error(str(e)) From 7bb81e2f188148902ecfe2424e81c25e63c5186f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 13:32:36 +0200 Subject: [PATCH 0991/4212] Whitespace does not not weigh anything - remove - sed -i 's/ *$//g' *py */*py Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 2 +- lib/cdist/config_install.py | 6 +++--- lib/cdist/context.py | 2 +- lib/cdist/core/manifest.py | 2 +- lib/cdist/core/object.py | 2 +- lib/cdist/core/type.py | 2 +- lib/cdist/emulator.py | 4 ++-- lib/cdist/exec/local.py | 4 ++-- lib/cdist/exec/remote.py | 6 +++--- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index a3dc01cc..abdadf62 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -19,7 +19,7 @@ # # -BANNER = """ +BANNER = """ .. . .x+=:. s dF @88> z` ^% :8 '88bu. %8P . Date: Tue, 18 Oct 2011 14:23:06 +0200 Subject: [PATCH 0992/4212] verify manifest environment Signed-off-by: Steven Armstrong --- lib/cdist/test/manifest/__init__.py | 41 +++++++++++++++++++ .../fixtures/conf/manifest/dump_environment | 12 +++--- .../conf/type/__dump_environment/manifest | 19 +++++---- 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index efda5b0a..f091e494 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -27,6 +27,8 @@ import shutil import string import random import logging +import io +import sys import cdist from cdist.exec import local @@ -48,6 +50,8 @@ class ManifestTestCase(unittest.TestCase): return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) def setUp(self): + self.orig_environ = os.environ + os.environ = os.environ.copy() self.temp_dir = self.mkdtemp() self.target_host = 'localhost' out_path = self.temp_dir @@ -58,17 +62,54 @@ class ManifestTestCase(unittest.TestCase): self.log = logging.getLogger(self.target_host) def tearDown(self): + os.environ = self.orig_environ shutil.rmtree(self.temp_dir) def test_initial_manifest_environment(self): initial_manifest = os.path.join(self.local.manifest_path, "dump_environment") + handle, output_file = self.mkstemp(dir=self.temp_dir) + os.environ['__cdist_test_out'] = output_file self.manifest.run_initial_manifest(initial_manifest) + with open(output_file, 'r') as fd: + output_string = fd.read() + print("output_string: %s" % output_string) + output_dict = {} + for line in output_string.split('\n'): + if line: + key,value = line.split(': ') + output_dict[key] = value + self.assertTrue(output_dict['PATH'].startswith(self.local.bin_path)) + self.assertEqual(output_dict['__target_host'], self.local.target_host) + self.assertEqual(output_dict['__global'], self.local.out_path) + self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) + self.assertEqual(output_dict['__manifest'], self.local.manifest_path) + def test_type_manifest_environment(self): cdist_type = core.Type(self.local.type_path, '__dump_environment') cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') + handle, output_file = self.mkstemp(dir=self.temp_dir) + os.environ['__cdist_test_out'] = output_file self.manifest.run_type_manifest(cdist_object) + with open(output_file, 'r') as fd: + output_string = fd.read() + print("output_string: %s" % output_string) + output_dict = {} + for line in output_string.split('\n'): + if line: + key,value = line.split(': ') + output_dict[key] = value + self.assertTrue(output_dict['PATH'].startswith(self.local.bin_path)) + self.assertEqual(output_dict['__target_host'], self.local.target_host) + self.assertEqual(output_dict['__global'], self.local.out_path) + self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) + self.assertEqual(output_dict['__type'], cdist_type.absolute_path) + self.assertEqual(output_dict['__object'], cdist_object.absolute_path) + self.assertEqual(output_dict['__self'], cdist_object.path) + self.assertEqual(output_dict['__object_id'], cdist_object.object_id) + self.assertEqual(output_dict['__object_fq'], cdist_object.path) + def test_debug_env_setup(self): self.log.setLevel(logging.DEBUG) manifest = cdist.core.manifest.Manifest(self.target_host, self.local) diff --git a/lib/cdist/test/manifest/fixtures/conf/manifest/dump_environment b/lib/cdist/test/manifest/fixtures/conf/manifest/dump_environment index 1abe7755..7ce983ab 100755 --- a/lib/cdist/test/manifest/fixtures/conf/manifest/dump_environment +++ b/lib/cdist/test/manifest/fixtures/conf/manifest/dump_environment @@ -1,7 +1,9 @@ #!/bin/sh -echo "PATH: $PATH" -echo "__target_host: $__target_host" -echo "__global: $__global" -echo "__cdist_type_base_path: $__cdist_type_base_path" -echo "__manifest: $__manifest" +cat > $__cdist_test_out << DONE +PATH: $PATH +__target_host: $__target_host +__global: $__global +__cdist_type_base_path: $__cdist_type_base_path +__manifest: $__manifest +DONE diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest b/lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest index 92f533a8..212de64d 100755 --- a/lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest +++ b/lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest @@ -1,10 +1,13 @@ #!/bin/sh -echo "PATH: $PATH" -echo "__target_host: $__target_host" -echo "__global: $__global" -echo "__cdist_type_base_path: $__cdist_type_base_path" -echo "__type: $__type" -echo "__object: $__object" -echo "__object_id: $__object_id" -echo "__object_fq: $__object_fq" +cat > $__cdist_test_out << DONE +PATH: $PATH +__target_host: $__target_host +__global: $__global +__cdist_type_base_path: $__cdist_type_base_path +__type: $__type +__self: $__self +__object: $__object +__object_id: $__object_id +__object_fq: $__object_fq +DONE From 1805c16fd4cd94372f6ec33466e5185a5ac56f83 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 14:23:46 +0200 Subject: [PATCH 0993/4212] --debug Signed-off-by: Steven Armstrong --- lib/cdist/test/manifest/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index f091e494..45902477 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -73,7 +73,6 @@ class ManifestTestCase(unittest.TestCase): with open(output_file, 'r') as fd: output_string = fd.read() - print("output_string: %s" % output_string) output_dict = {} for line in output_string.split('\n'): if line: @@ -94,7 +93,6 @@ class ManifestTestCase(unittest.TestCase): with open(output_file, 'r') as fd: output_string = fd.read() - print("output_string: %s" % output_string) output_dict = {} for line in output_string.split('\n'): if line: From e58b52592b36120a21969690a1da9f1350224eba Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 14:24:52 +0200 Subject: [PATCH 0994/4212] add missing environment variable __self Signed-off-by: Steven Armstrong --- lib/cdist/core/manifest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index 50964fdc..84092892 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -92,6 +92,7 @@ class Manifest(object): env = os.environ.copy() env.update(self.env) env.update({ + '__self': cdist_object.path, '__object': cdist_object.absolute_path, '__object_id': cdist_object.object_id, '__object_fq': cdist_object.path, From af367a76f8f1c9c2ea838b5f8f28db3d6e4e2d6f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 14:41:38 +0200 Subject: [PATCH 0995/4212] test for: .cdist may not be used in object_id Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 9a13f524..84d2cf8f 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -53,12 +53,18 @@ class ObjectClassTestCase(unittest.TestCase): class ObjectIdTestCase(unittest.TestCase): - def test_illegal_object_id(self): + def test_object_id_starts_with_slash(self): cdist_type = core.Type(type_base_path, '__third') illegal_object_id = '/object_id/may/not/start/with/slash' with self.assertRaises(core.IllegalObjectIdError): core.Object(cdist_type, object_base_path, illegal_object_id) + def test_object_id_contains_dotcdist(self): + cdist_type = core.Type(type_base_path, '__third') + illegal_object_id = 'object_id/may/not/contain/.cdist/anywhere' + with self.assertRaises(core.IllegalObjectIdError): + core.Object(cdist_type, object_base_path, illegal_object_id) + class ObjectTestCase(unittest.TestCase): From 030d5919e621cc696ba647d571a73373c3d92664 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 14:42:57 +0200 Subject: [PATCH 0996/4212] raise exception if object_id contains .cdist Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index eeb5799b..f22c206a 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -88,8 +88,11 @@ class Object(object): return self.__class__(self.type.__class__(type_path, type_name), object_path, object_id=object_id) def __init__(self, cdist_type, base_path, object_id=None): - if object_id and object_id.startswith('/'): - raise IllegalObjectIdError(object_id, 'object_id may not start with /') + if object_id: + if object_id.startswith('/'): + raise IllegalObjectIdError(object_id, 'object_id may not start with /') + if '.cdist' in object_id: + raise IllegalObjectIdError(object_id, 'object_id may not contain \'.cdist\'') self.type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id From 2a5465c03cac30523f8fa5159e738e655f8ebe66 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 14:48:06 +0200 Subject: [PATCH 0997/4212] test that emulator fails if requirement has illegal object_id Signed-off-by: Steven Armstrong --- lib/cdist/test/emulator/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index 66e7918a..ccdda265 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -73,3 +73,10 @@ class EmulatorTestCase(unittest.TestCase): os.environ['require'] = '__does-not-exist/some-id' emu = emulator.Emulator(argv) self.assertRaises(core.NoSuchTypeError, emu.run) + + def test_illegal_object_id_requirement(self): + argv = ['__file', '/tmp/foobar'] + os.environ.update(self.env) + os.environ['require'] = '__file/bad/id/with/.cdist/inside' + emu = emulator.Emulator(argv) + self.assertRaises(core.IllegalObjectIdError, emu.run) From 2246b7496ba8c21ecca5737dff5dbe0d963fe4c2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 14:50:28 +0200 Subject: [PATCH 0998/4212] fails if requirement has illegal object_id Signed-off-by: Steven Armstrong --- lib/cdist/emulator.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index b5682342..10c2dbaa 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -158,9 +158,6 @@ class Emulator(object): requirement_type_name = requirement_parts[0] requirement_object_id = requirement_parts[1] - # Instantiate type which fails if type does not exist - requirement_type = core.Type(self.type_base_path, requirement_type_name) - # FIXME: Add support for omitted object id == singleton #if len(requirement_parts) == 1: #except IndexError: @@ -170,6 +167,11 @@ class Emulator(object): # Remove / if existent in object id requirement_object_id = requirement_object_id.lstrip('/') + # Instantiate type which fails if type does not exist + requirement_type = core.Type(self.type_base_path, requirement_type_name) + # Instantiate object which fails if the object_id is illegal + requirement_object = core.Object(requirement_type, self.object_base_path, requirement_object_id) + # Construct cleaned up requirement with only one / :-) requirement = requirement_type_name + '/' + requirement_object_id self.cdist_object.requirements.append(requirement) From 205cd7b28ad4396cafe59d4e492e8e9a2a4503aa Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 14:55:20 +0200 Subject: [PATCH 0999/4212] fix the test Signed-off-by: Steven Armstrong --- lib/cdist/test/manifest/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index 45902477..14d6be8a 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -104,7 +104,7 @@ class ManifestTestCase(unittest.TestCase): self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) self.assertEqual(output_dict['__type'], cdist_type.absolute_path) self.assertEqual(output_dict['__object'], cdist_object.absolute_path) - self.assertEqual(output_dict['__self'], cdist_object.path) + self.assertEqual(output_dict['__self'], cdist_object.name) self.assertEqual(output_dict['__object_id'], cdist_object.object_id) self.assertEqual(output_dict['__object_fq'], cdist_object.path) From d427e3f5856df6bb87e8f349c998805dcaf1845d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 18 Oct 2011 14:56:35 +0200 Subject: [PATCH 1000/4212] __self should not contain .cdist Signed-off-by: Steven Armstrong --- lib/cdist/core/manifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index 84092892..bae44ebc 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -92,10 +92,10 @@ class Manifest(object): env = os.environ.copy() env.update(self.env) env.update({ - '__self': cdist_object.path, + '__self': cdist_object.name, '__object': cdist_object.absolute_path, '__object_id': cdist_object.object_id, - '__object_fq': cdist_object.path, + '__object_fq': cdist_object.name, '__type': cdist_object.type.absolute_path, '__cdist_manifest': script, }) From 837489ce8546806ae765fcc96eca0795a016a0bb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 15:54:08 +0200 Subject: [PATCH 1001/4212] remove obsolete preseed code from __package_apt Signed-off-by: Nico Schottelius --- conf/type/__package_apt/gencode-remote | 7 ------- 1 file changed, 7 deletions(-) diff --git a/conf/type/__package_apt/gencode-remote b/conf/type/__package_apt/gencode-remote index df8fd823..a5384ee3 100755 --- a/conf/type/__package_apt/gencode-remote +++ b/conf/type/__package_apt/gencode-remote @@ -27,13 +27,6 @@ else name="$__object_id" fi -# Check for preseeding and add preseed as here document -if [ -f "$__object/parameter/preseed" ]; then - echo "debconf-set-selections << __file-eof" - cat "$(cat "$__object/parameter/preseed")" - echo "__file-eof" -fi - state="$(cat "$__object/parameter/state")" is_installed="$(grep "^Status: install ok installed" "$__object/explorer/pkg_status" || true)" From 27fd9cd61be398d9cabe14ee09ee66a73d89a381 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 16:05:47 +0200 Subject: [PATCH 1002/4212] add sudo example Signed-off-by: Nico Schottelius --- other/examples/types/__nico_sudo/README | 2 ++ .../types/__nico_sudo/files/sudo-nico | 13 ++++++++ other/examples/types/__nico_sudo/manifest | 30 ++++++++++++++++++ .../types/__nico_sudo/parameter/gencode | 31 +++++++++++++++++++ .../types/__nico_sudo/parameter/manifest | 31 +++++++++++++++++++ .../types/__nico_sudo/parameter/optional | 0 .../types/__nico_sudo/parameter/required | 0 other/examples/types/__nico_sudo/singleton | 0 8 files changed, 107 insertions(+) create mode 100644 other/examples/types/__nico_sudo/README create mode 100644 other/examples/types/__nico_sudo/files/sudo-nico create mode 100755 other/examples/types/__nico_sudo/manifest create mode 100644 other/examples/types/__nico_sudo/parameter/gencode create mode 100644 other/examples/types/__nico_sudo/parameter/manifest create mode 100644 other/examples/types/__nico_sudo/parameter/optional create mode 100644 other/examples/types/__nico_sudo/parameter/required create mode 100644 other/examples/types/__nico_sudo/singleton diff --git a/other/examples/types/__nico_sudo/README b/other/examples/types/__nico_sudo/README new file mode 100644 index 00000000..5e4cf0d3 --- /dev/null +++ b/other/examples/types/__nico_sudo/README @@ -0,0 +1,2 @@ +Configure sudoers file to be included. Different types may do so, +this one simply uses the "nico" file to store the configuration. diff --git a/other/examples/types/__nico_sudo/files/sudo-nico b/other/examples/types/__nico_sudo/files/sudo-nico new file mode 100644 index 00000000..d904c319 --- /dev/null +++ b/other/examples/types/__nico_sudo/files/sudo-nico @@ -0,0 +1,13 @@ +# +# Cdist managed file +# + +# Personal one: nico, shared one: lyni +User_Alias NICO = nico, lyni + +Defaults timestamp_timeout=5 +Defaults !tty_tickets + +# Give out permissions +NICO ALL=(ALL) ALL +NICO ALL=(ALL) NOPASSWD: /usr/sbin/pm-suspend diff --git a/other/examples/types/__nico_sudo/manifest b/other/examples/types/__nico_sudo/manifest new file mode 100755 index 00000000..5de33973 --- /dev/null +++ b/other/examples/types/__nico_sudo/manifest @@ -0,0 +1,30 @@ +#!/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 . +# +# + +destination=/etc/sudoers.d/nico +source="$__type/files/sudo-nico" + +__package sudo --state installed +__directory /etc/sudoers.d --parents yes + +require="__directory/etc/sudoers.d" \ + __file "$destination" --source "$source" --mode 0440 + diff --git a/other/examples/types/__nico_sudo/parameter/gencode b/other/examples/types/__nico_sudo/parameter/gencode new file mode 100644 index 00000000..74792abf --- /dev/null +++ b/other/examples/types/__nico_sudo/parameter/gencode @@ -0,0 +1,31 @@ +#!/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 . +# +# +# USEFUL DESCRIPTION +# + +# +# This file should generate code on stdout, which will be collected by cdist +# and run on the target. +# +# To tell cdist to make use of it, you need to make it executable (chmod +x) +# +# + diff --git a/other/examples/types/__nico_sudo/parameter/manifest b/other/examples/types/__nico_sudo/parameter/manifest new file mode 100644 index 00000000..c696eda6 --- /dev/null +++ b/other/examples/types/__nico_sudo/parameter/manifest @@ -0,0 +1,31 @@ +#!/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 . +# +# +# USEFUL DESCRIPTION +# + +# +# This is the manifest, which can be used to create other objects like this: +# __file /path/to/destination --source /from/where/ +# +# To tell cdist to make use of it, you need to make it executable (chmod +x) +# +# + diff --git a/other/examples/types/__nico_sudo/parameter/optional b/other/examples/types/__nico_sudo/parameter/optional new file mode 100644 index 00000000..e69de29b diff --git a/other/examples/types/__nico_sudo/parameter/required b/other/examples/types/__nico_sudo/parameter/required new file mode 100644 index 00000000..e69de29b diff --git a/other/examples/types/__nico_sudo/singleton b/other/examples/types/__nico_sudo/singleton new file mode 100644 index 00000000..e69de29b From e3f3c48b220180fcfe61af953abe4c6610675444 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 20:34:35 +0200 Subject: [PATCH 1003/4212] wrap the whole program in the try...except KeyboardInterrupt block Signed-off-by: Nico Schottelius --- bin/cdist | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/bin/cdist b/bin/cdist index 14cff65a..78893b60 100755 --- a/bin/cdist +++ b/bin/cdist @@ -20,26 +20,10 @@ # # -import argparse -import logging -import multiprocessing -import os -import re -import sys -import time - -log = logging.getLogger("cdist") - -# Ensure our /lib/ is included into PYTHON_PATH -sys.path.insert(0, os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) - -import cdist - -TYPE_PREFIX = "__" - def commandline(): """Parse command line""" + import argparse + import cdist.banner import cdist.config import cdist.install @@ -203,6 +187,23 @@ def emulator(): if __name__ == "__main__": try: + import logging + import multiprocessing + import os + import re + import sys + import time + + log = logging.getLogger("cdist") + + # Ensure our /lib/ is included into PYTHON_PATH + sys.path.insert(0, os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) + + import cdist + + TYPE_PREFIX = "__" + logging.basicConfig(format='%(levelname)s: %(message)s') if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): @@ -214,3 +215,5 @@ if __name__ == "__main__": sys.exit(0) sys.exit(0) + + From 0344796d31f4cfdf5305b09b3e85d0aa162f3cfb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 20:36:35 +0200 Subject: [PATCH 1004/4212] restructure imports Signed-off-by: Nico Schottelius --- bin/cdist | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 78893b60..0705f5bd 100755 --- a/bin/cdist +++ b/bin/cdist @@ -101,6 +101,9 @@ def install(args): def configinstall(args, mode): """Configure or install remote system""" + import multiprocessing + import time + try: process = {} failed_hosts = [] @@ -188,11 +191,9 @@ def emulator(): if __name__ == "__main__": try: import logging - import multiprocessing import os import re import sys - import time log = logging.getLogger("cdist") From 8b9e6780b8ec8de7781da3024fbb4eb18c16cbd8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 20:42:09 +0200 Subject: [PATCH 1005/4212] no need for a constant that's used two lines below Signed-off-by: Nico Schottelius --- bin/cdist | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/bin/cdist b/bin/cdist index 0705f5bd..6a7a2d6d 100755 --- a/bin/cdist +++ b/bin/cdist @@ -195,19 +195,17 @@ if __name__ == "__main__": import re import sys + import cdist + log = logging.getLogger("cdist") # Ensure our /lib/ is included into PYTHON_PATH sys.path.insert(0, os.path.abspath( os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) - import cdist - - TYPE_PREFIX = "__" - logging.basicConfig(format='%(levelname)s: %(message)s') - if re.match(TYPE_PREFIX, os.path.basename(sys.argv[0])): + if re.match("__", os.path.basename(sys.argv[0])): emulator() else: commandline() From 68d87c3023f280b5d017d5082c0c17939afefde8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 22:34:51 +0200 Subject: [PATCH 1006/4212] reference new and old variable, remove reference to cdist-config Signed-off-by: Nico Schottelius --- doc/man/cdist-reference.text.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 57dbde4a..a80a6ce3 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -133,7 +133,6 @@ out/object//explorers:: tmp_dir:: A tempdir and a tempfile is used by cdist internally, which will be removed when the scripts end automatically. - See cdist-config(1). TYPES ----- @@ -186,6 +185,7 @@ __object:: __object_id:: The type unique object id. Available for: type manifest, type explorer, type gencode +__self:: __object_fq:: The full qualified name of the current object. Available for: type manifest, type explorer, type gencode From 7d749540d83d4fb1417fc4798bb5b31322e403cf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 22:40:17 +0200 Subject: [PATCH 1007/4212] changes for 2.0.4 Signed-off-by: Nico Schottelius --- doc/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/changelog b/doc/changelog index aae0e04a..7403b466 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,3 +1,6 @@ +2.0.4: + * Bugfix core: Remove traceback when sending SIGINT (aka Ctrl-C) + 2.0.3: 2011-10-18 * Improved logging, added --verbose, by more quiet by default * Bugfix __user: Correct quoting (Steven Armstrong) From b7fdfb12e6952d6a047307b159999252339cd89b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 22:40:29 +0200 Subject: [PATCH 1008/4212] cleanups Signed-off-by: Nico Schottelius --- bin/cdist | 2 -- build | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index 6a7a2d6d..0f37db2e 100755 --- a/bin/cdist +++ b/bin/cdist @@ -214,5 +214,3 @@ if __name__ == "__main__": sys.exit(0) sys.exit(0) - - diff --git a/build b/build index 9e9fbf21..38fdac07 100755 --- a/build +++ b/build @@ -144,8 +144,9 @@ case "$1" in echo '' echo 'Here are the possible targets:' echo '' - echo ' man: Build manpages (requires Asciidoc)' echo ' clean: Remove build stuff' + echo ' man: Build manpages (requires Asciidoc)' + echo ' test: Run tests' echo '' echo '' echo "Unknown target, \"$1\"" >&2 From 3814dcd7287eaffdfdf6241c46d517dcffea8cf7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Oct 2011 23:12:35 +0200 Subject: [PATCH 1009/4212] remove old test ideas from todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 54 ------------------------------------------- 1 file changed, 54 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 8f5c6e4f..cb5b9158 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -2,60 +2,6 @@ - sanity checks: implement tests - stage_run() - - ensure that for every object in - cdist.core.Object.list_objects() is passed into - self.object_run() - - instantiate + overwrite + test - - object_prepare(): - - calls (in this order): - self.run_type_explorer(cdist_object) - self.run_type_manifest(cdist_object) - cdist_object.prepared = True - - object is prepared after function call - - - stage_prepare(): - - calls (in this order): - self.link_emulator() - self.run_global_explorers() - self.run_initial_manifest() - - - ensure that all objects are created :-) - - as defined in inital manifest + type manifests - - deploy_to() - - ensure self.stage_prepare() and self.stage_run() are - run. [ORDER] - - instantiate + overwrite + test - - deploy_and_cleanup() - - ensure self.deploy_to() + self.cleanup() are are run - run. [ORDER] - - instantiate + overwrite + test - - transfer_object_parameter() - - check that object parameters are transferred - - paths are setup correctly - - test via mock of remote_mkdir and transfer_path - - ensure self.remote_mkdir, self.transfer_path are run. [ORDER] - - instantiate + overwrite + test - - transfer_global_explorers() - - paths are setup correctly - - test via mock of self.remote_mkdir() and self.transfer_path() - - ensure self.remote_mkdir, self.transfer_path are run. [ORDER] - - instantiate + overwrite + test - - transfer_type_explorers(): - - Explorers are not transferred twice - - paths are setup correctly - - test via mock of self.remote_mkdir() and self.transfer_path() - - Explorers are transferred - - test via mock of self.remote_mkdir() and self.transfer_path() - - -------------------------------------------------------------------------------- - insert prefix into logger to distinguish between modules From 02de3969059430fe4520957f318cb3bf72fc6666 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 14:50:16 +0200 Subject: [PATCH 1010/4212] tests for Object state Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 84d2cf8f..7064b34d 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -79,6 +79,7 @@ class ObjectTestCase(unittest.TestCase): self.cdist_object.source = [] self.cdist_object.code_local = '' self.cdist_object.code_remote = '' + self.cdist_object.state = '' def test_name(self): self.assertEqual(self.cdist_object.name, '__third/moon') @@ -163,6 +164,21 @@ class ObjectTestCase(unittest.TestCase): self.cdist_object.ran = True self.assertTrue(self.cdist_object.ran) + def test_state(self): + self.assertEqual(self.cdist_object.state, '') + + def test_state_ran(self): + self.cdist_object.state = core.Object.STATE_RAN + self.assertEqual(self.cdist_object.state, core.Object.STATE_RAN) + + def test_state_running(self): + self.cdist_object.state = core.Object.STATE_RUNNING + self.assertEqual(self.cdist_object.state, core.Object.STATE_RUNNING) + + def test_state_prepared(self): + self.cdist_object.state = core.Object.STATE_PREPARED + self.assertEqual(self.cdist_object.state, core.Object.STATE_PREPARED) + def test_source(self): self.assertEqual(list(self.cdist_object.source), []) From 4f398a834fbd0095bad54bda0f14c43416951c52 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 14:53:06 +0200 Subject: [PATCH 1011/4212] /ran/done/ Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 7064b34d..c5e9e2dd 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -167,17 +167,17 @@ class ObjectTestCase(unittest.TestCase): def test_state(self): self.assertEqual(self.cdist_object.state, '') - def test_state_ran(self): - self.cdist_object.state = core.Object.STATE_RAN - self.assertEqual(self.cdist_object.state, core.Object.STATE_RAN) + def test_state_prepared(self): + self.cdist_object.state = core.Object.STATE_PREPARED + self.assertEqual(self.cdist_object.state, core.Object.STATE_PREPARED) def test_state_running(self): self.cdist_object.state = core.Object.STATE_RUNNING self.assertEqual(self.cdist_object.state, core.Object.STATE_RUNNING) - def test_state_prepared(self): - self.cdist_object.state = core.Object.STATE_PREPARED - self.assertEqual(self.cdist_object.state, core.Object.STATE_PREPARED) + def test_state_done(self): + self.cdist_object.state = core.Object.STATE_DONE + self.assertEqual(self.cdist_object.state, core.Object.STATE_DONE) def test_source(self): self.assertEqual(list(self.cdist_object.source), []) From 022b17d70067c933505925c3c5b5920ed664be6f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 14:53:31 +0200 Subject: [PATCH 1012/4212] implement Object state Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 8cecfe6d..a35182d2 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -51,6 +51,11 @@ class Object(object): """ + # Constants for use with Object.state + STATE_PREPARED = "prepared" + STATE_RUNNING = "running" + STATE_DONE = "done" + @classmethod def list_objects(cls, object_base_path, type_base_path): """Return a list of object instances""" @@ -127,6 +132,7 @@ class Object(object): changed = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "changed")) prepared = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "prepared")) ran = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "ran")) + state = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.absolute_path, "state")) source = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, "source")) code_local = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.base_path, obj.code_local_path)) code_remote = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.base_path, obj.code_remote_path)) From ff2192f6dea1a6899fb662e8e355ae0b92bfc689 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 14:54:15 +0200 Subject: [PATCH 1013/4212] remove legacy attributes: ran, prepared Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index a35182d2..5157d86a 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -130,8 +130,6 @@ class Object(object): 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")) - prepared = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "prepared")) - ran = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "ran")) 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)) From f732220e7794cd4bbf568d58816c2aba940db7b7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 14:54:38 +0200 Subject: [PATCH 1014/4212] remove legacy tests Signed-off-by: Steven Armstrong --- lib/cdist/test/object/__init__.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index c5e9e2dd..ab05c7af 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -150,20 +150,6 @@ class ObjectTestCase(unittest.TestCase): self.cdist_object.changed = True self.assertTrue(self.cdist_object.changed) - def test_prepared(self): - self.assertFalse(self.cdist_object.prepared) - - def test_prepared_after_changing(self): - self.cdist_object.prepared = True - self.assertTrue(self.cdist_object.prepared) - - def test_ran(self): - self.assertFalse(self.cdist_object.ran) - - def test_ran_after_changing(self): - self.cdist_object.ran = True - self.assertTrue(self.cdist_object.ran) - def test_state(self): self.assertEqual(self.cdist_object.state, '') From c621af1e9f354e24b4dd1c00d60a3a29c796a7fc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Oct 2011 14:55:16 +0200 Subject: [PATCH 1015/4212] begin tutorial sections Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-tutorial.text | 91 ++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 80135da9..c547b3e5 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -6,6 +6,97 @@ Nico Schottelius NAME ---- cdist-tutorial - a guided introduction into cdist + + + +YOUR FIRST CONFIGURATION +------------------------ + + +DEFINE STATE IN THE INITAL MANIFEST +----------------------------------- + +The initial manifest is used to map +configurations to a host. + +USING SOME BASIC TYPES +---------------------- +what is a type, how to use it, + + +CREATING YOUR FIRST OWN TYPE +---------------------------- + + + +USE A TYPE TO BUNDLE FUNCTIONALITY +---------------------------------- + + +USING EXPLORERS +--------------- +global, type explorer + + +DEBUGGING YOUR TYPES +-------------------- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + INTRODUCTION From ef5eb34274c6770810abeb5f0c7b5b13b2cb3a67 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 14:57:32 +0200 Subject: [PATCH 1016/4212] update test for upcomming change: /__debug/__cdist_debug/ Signed-off-by: Steven Armstrong --- lib/cdist/test/code/__init__.py | 2 +- lib/cdist/test/explorer/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index c9761a4b..514acb4a 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -120,4 +120,4 @@ class CodeTestCase(unittest.TestCase): def test_debug_env_setup(self): self.log.setLevel(logging.DEBUG) code = cdist.core.code.Code(self.target_host, self.local, self.remote) - self.assertTrue("__debug" in code.env) + self.assertTrue("__cdist_debug" in code.env) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index fe23b7e2..341371cd 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -130,4 +130,4 @@ class ExplorerClassTestCase(unittest.TestCase): def test_debug_env_setup(self): self.log.setLevel(logging.DEBUG) explorer = cdist.core.explorer.Explorer(self.target_host, self.local, self.remote) - self.assertTrue("__debug" in explorer.env) + self.assertTrue("__cdist_debug" in explorer.env) From 1fb96c0fc20448c9c13f90839c6cc8c1d600908f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 14:58:25 +0200 Subject: [PATCH 1017/4212] update test for upcomming change: /__debug/__cdist_debug/ Signed-off-by: Steven Armstrong --- lib/cdist/test/manifest/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index 14d6be8a..bf573a9c 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -111,4 +111,4 @@ class ManifestTestCase(unittest.TestCase): def test_debug_env_setup(self): self.log.setLevel(logging.DEBUG) manifest = cdist.core.manifest.Manifest(self.target_host, self.local) - self.assertTrue("__debug" in manifest.env) + self.assertTrue("__cdist_debug" in manifest.env) From 07ef08938b25f0fd1f3af2de2fa6fc666df9ff67 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Oct 2011 15:01:55 +0200 Subject: [PATCH 1018/4212] remove __debug, should not be setup by cdist Signed-off-by: Nico Schottelius --- doc/man/cdist-reference.text.sh | 5 ----- doc/man/man7/cdist-tutorial.text | 6 +++++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index a80a6ce3..257ca36e 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -165,11 +165,6 @@ changed:: ENVIRONMENT VARIABLES --------------------- -__debug:: - If this variable is setup, cdist runs in debug mode. - You can use this information, to only output stuff in debug - mode as well. - Available for: initial manifest, type manifest, gencode, code __explorer:: Directory that contains all global explorers. Available for: explorer diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index c547b3e5..71bf18c0 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -40,7 +40,11 @@ global, type explorer DEBUGGING YOUR TYPES -------------------- - +__debug:: + If this variable is setup, cdist runs in debug mode. + You can use this information, to only output stuff in debug + mode as well. + Available for: initial manifest, type manifest, gencode, code From eb5b80d132fd7a9acb30b546e7491392b7352ee1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 15:02:17 +0200 Subject: [PATCH 1019/4212] remove legacy tests Signed-off-by: Steven Armstrong --- lib/cdist/test/code/__init__.py | 5 ----- lib/cdist/test/explorer/__init__.py | 5 ----- 2 files changed, 10 deletions(-) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index 514acb4a..c177f49c 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -116,8 +116,3 @@ class CodeTestCase(unittest.TestCase): self.cdist_object.code_remote = self.code.run_gencode_remote(self.cdist_object) self.code.transfer_code_remote(self.cdist_object) self.code.run_code_remote(self.cdist_object) - - def test_debug_env_setup(self): - self.log.setLevel(logging.DEBUG) - code = cdist.core.code.Code(self.target_host, self.local, self.remote) - self.assertTrue("__cdist_debug" in code.env) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index 341371cd..42b83ee8 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -126,8 +126,3 @@ class ExplorerClassTestCase(unittest.TestCase): self.explorer.transfer_type_explorers(cdist_type) output = self.explorer.run_type_explorer('world', cdist_object) self.assertEqual(output, 'hello\n') - - def test_debug_env_setup(self): - self.log.setLevel(logging.DEBUG) - explorer = cdist.core.explorer.Explorer(self.target_host, self.local, self.remote) - self.assertTrue("__cdist_debug" in explorer.env) From dc3ed07153543a58c24a9bf31f93b3c4ec781e89 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 15:03:47 +0200 Subject: [PATCH 1020/4212] /__debug/__cdist_debug/ Signed-off-by: Steven Armstrong --- lib/cdist/core/manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index f7b08c20..38d2ee98 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -75,7 +75,7 @@ class Manifest(object): '__cdist_type_base_path': self.local.type_path, # for use in type emulator } if self.log.getEffectiveLevel() == logging.DEBUG: - self.env.update({'__debug': "yes" }) + self.env.update({'__cdist_debug': "yes" }) def run_initial_manifest(self, script): From 8f306a748484b5151098cb233260a22fd0c42045 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 15:04:14 +0200 Subject: [PATCH 1021/4212] /__debug/__cdist_debug/ Signed-off-by: Steven Armstrong --- lib/cdist/emulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 7e7e12b4..4880c6e6 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -82,7 +82,7 @@ class Emulator(object): logformat = '%(levelname)s: %(message)s' logging.basicConfig(format=logformat) - if '__debug' in os.environ: + if '__cdist_debug' in os.environ: logging.root.setLevel(logging.DEBUG) else: logging.root.setLevel(logging.INFO) From b56925d24a7cfd197df358d9226f830f78900dd2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 15:15:05 +0200 Subject: [PATCH 1022/4212] /__object_fq/__object_name/ Signed-off-by: Steven Armstrong --- lib/cdist/test/code/__init__.py | 6 ++++-- .../fixtures/conf/type/__dump_environment/gencode-local | 3 ++- lib/cdist/test/manifest/__init__.py | 4 ++-- .../manifest/fixtures/conf/type/__dump_environment/manifest | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index c177f49c..68e8a41d 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -85,7 +85,8 @@ class CodeTestCase(unittest.TestCase): self.assertEqual(output_dict['__type'], self.cdist_type.absolute_path) self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) - self.assertEqual(output_dict['__object_fq'], self.cdist_object.path) + self.assertEqual(output_dict['__object_name'], self.cdist_object.name) + self.assertEqual(output_dict['__self'], self.cdist_object.name) def test_run_gencode_remote_environment(self): output_string = self.code.run_gencode_remote(self.cdist_object) @@ -100,7 +101,8 @@ class CodeTestCase(unittest.TestCase): self.assertEqual(output_dict['__type'], self.cdist_type.absolute_path) self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) - self.assertEqual(output_dict['__object_fq'], self.cdist_object.path) + self.assertEqual(output_dict['__object_name'], self.cdist_object.name) + self.assertEqual(output_dict['__self'], self.cdist_object.name) def test_transfer_code_remote(self): self.cdist_object.code_remote = self.code.run_gencode_remote(self.cdist_object) diff --git a/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local b/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local index ac292546..ed1265c9 100755 --- a/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local +++ b/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local @@ -5,4 +5,5 @@ echo "echo __global: $__global" echo "echo __type: $__type" echo "echo __object: $__object" echo "echo __object_id: $__object_id" -echo "echo __object_fq: $__object_fq" +echo "echo __object_name: $__object_name" +echo "echo __self: $__self" diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index bf573a9c..257311d7 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -104,9 +104,9 @@ class ManifestTestCase(unittest.TestCase): self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) self.assertEqual(output_dict['__type'], cdist_type.absolute_path) self.assertEqual(output_dict['__object'], cdist_object.absolute_path) - self.assertEqual(output_dict['__self'], cdist_object.name) self.assertEqual(output_dict['__object_id'], cdist_object.object_id) - self.assertEqual(output_dict['__object_fq'], cdist_object.path) + self.assertEqual(output_dict['__object_name'], cdist_object.name) + self.assertEqual(output_dict['__self'], cdist_object.name) def test_debug_env_setup(self): self.log.setLevel(logging.DEBUG) diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest b/lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest index 212de64d..e135de35 100755 --- a/lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest +++ b/lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest @@ -9,5 +9,5 @@ __type: $__type __self: $__self __object: $__object __object_id: $__object_id -__object_fq: $__object_fq +__object_name: $__object_name DONE From d6cf85e6f6407c7b9b5fec96c55a7799da4c0db7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 15:17:45 +0200 Subject: [PATCH 1023/4212] implement /__object_fq/__object_name/ Signed-off-by: Steven Armstrong --- lib/cdist/core/code.py | 3 ++- lib/cdist/core/manifest.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index 2505925c..51912559 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -105,7 +105,8 @@ class Code(object): '__type': cdist_object.type.absolute_path, '__object': cdist_object.absolute_path, '__object_id': cdist_object.object_id, - '__object_fq': cdist_object.path, + '__object_name': cdist_object.name, + '__self': cdist_object.name, }) return self.local.run_script(script, env=env, return_output=True) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index 38d2ee98..704a3978 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -92,10 +92,10 @@ class Manifest(object): env = os.environ.copy() env.update(self.env) env.update({ - '__self': cdist_object.name, '__object': cdist_object.absolute_path, '__object_id': cdist_object.object_id, - '__object_fq': cdist_object.name, + '__object_name': cdist_object.name, + '__self': cdist_object.name, '__type': cdist_object.type.absolute_path, '__cdist_manifest': script, }) From 28614b3dd408ad7e5119188da3d68a173d84e30d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Oct 2011 15:19:08 +0200 Subject: [PATCH 1024/4212] DEPRECATE __self environment variable, use __object_name (documentation) Signed-off-by: Nico Schottelius --- doc/changelog | 3 +++ doc/man/cdist-reference.text.sh | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 7403b466..aad067b7 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,5 +1,8 @@ 2.0.4: * Bugfix core: Remove traceback when sending SIGINT (aka Ctrl-C) + * Cleanup: __object_fq variable removed (never used) + * Cleanup: Environment variable __self DEPRECATED, use __object_name instead + * Cleanup: Environment variable __self scheduled for removal in cdist 2.1 2.0.3: 2011-10-18 * Improved logging, added --verbose, by more quiet by default diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 257ca36e..9127096c 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -181,7 +181,8 @@ __object_id:: The type unique object id. Available for: type manifest, type explorer, type gencode __self:: -__object_fq:: + DEPRECATED: Same as __object_name, do not use anymore, use __object_name instead. +__object_name:: The full qualified name of the current object. Available for: type manifest, type explorer, type gencode __target_host:: From ba6371c5849ca847f5ef3dd33b70721ed5e5852a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Oct 2011 15:20:53 +0200 Subject: [PATCH 1025/4212] fix import error... stupid one Signed-off-by: Nico Schottelius --- bin/cdist | 8 +++++--- doc/dev/todo/niconext | 9 --------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/bin/cdist b/bin/cdist index 0f37db2e..466604fa 100755 --- a/bin/cdist +++ b/bin/cdist @@ -195,13 +195,15 @@ if __name__ == "__main__": import re import sys + # Ensure our /lib/ is included into PYTHON_PATH + sys.path.insert(0, os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) + + # And now import our stuff import cdist log = logging.getLogger("cdist") - # Ensure our /lib/ is included into PYTHON_PATH - sys.path.insert(0, os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) logging.basicConfig(format='%(levelname)s: %(message)s') diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index cb5b9158..2f9bb844 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,12 +1,3 @@ -2.0.3: - -- sanity checks: implement tests - --------------------------------------------------------------------------------- - -- insert prefix into logger to distinguish between modules - - in debug/info only? - - Fix / rewrite cdist-quickstart - write tutorial!!!!!!!!! From 0e7c532870f60f3edc19fab58d4d65ef71a263a2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Oct 2011 15:32:06 +0200 Subject: [PATCH 1026/4212] add new state code, begin to detect circular dependencies Signed-off-by: Nico Schottelius --- bin/cdist | 1 - lib/cdist/config_install.py | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/bin/cdist b/bin/cdist index 466604fa..ffda3e42 100755 --- a/bin/cdist +++ b/bin/cdist @@ -204,7 +204,6 @@ if __name__ == "__main__": log = logging.getLogger("cdist") - logging.basicConfig(format='%(levelname)s: %(message)s') if re.match("__", os.path.basename(sys.argv[0])): diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 2d921aaf..7ba8be75 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -87,7 +87,7 @@ class ConfigInstall(object): new_objects_created = False for cdist_object in core.Object.list_objects(self.local.object_path, self.local.type_path): - if cdist_object.prepared: + if cdist_object.state == cdist.core.object.STATE_PREPARED: self.log.debug("Skipping re-prepare of object %s", cdist_object) continue else: @@ -121,18 +121,18 @@ class ConfigInstall(object): self.log.info("Running manifest and explorers for " + cdist_object.name) self.run_type_explorers(cdist_object) self.manifest.run_type_manifest(cdist_object) - cdist_object.prepared = True + cdist_object.state = cdist.core.object.STATE_PREPARED def object_run(self, cdist_object): """Run gencode and code for an object""" self.log.info("Running gencode and code for " + cdist_object.name) - # Catch requirements, which re-call us - # FIXME: change .ran to running - if cdist_object.ran: + if cdist_object.state == cdist.core.object.STATE_RUNNING: + raise cdist.Error("Detected circular dependency in " + cdist_object.__str__()) + elif cdist_object.state == cdist.core.object.STATE_DONE: return else: - cdist_object.ran = True + cdist_object.state = cdist.core.object.STATE_RUNNING cdist_type = cdist_object.type From e98272e0c5bc68de623748d90fa509aea113d366 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Oct 2011 15:34:24 +0200 Subject: [PATCH 1027/4212] move log.info down Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 7ba8be75..9c2b6e4c 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -125,8 +125,7 @@ class ConfigInstall(object): def object_run(self, cdist_object): """Run gencode and code for an object""" - self.log.info("Running gencode and code for " + cdist_object.name) - + self.log.info("" + cdist_object.name) if cdist_object.state == cdist.core.object.STATE_RUNNING: raise cdist.Error("Detected circular dependency in " + cdist_object.__str__()) elif cdist_object.state == cdist.core.object.STATE_DONE: @@ -142,6 +141,8 @@ class ConfigInstall(object): required_object = cdist_object.object_from_name(requirement) self.object_run(required_object) + self.log.info("Running gencode and code for " + cdist_object.name) + # Generate cdist_object.code_local = self.code.run_gencode_local(cdist_object) cdist_object.code_remote = self.code.run_gencode_remote(cdist_object) From 6734ff693f88f0ba6dfa6d76a75a9014fa53794f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 15:39:38 +0200 Subject: [PATCH 1028/4212] fix object_prepare to use object.state Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 9c2b6e4c..74412f96 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -87,7 +87,7 @@ class ConfigInstall(object): new_objects_created = False for cdist_object in core.Object.list_objects(self.local.object_path, self.local.type_path): - if cdist_object.state == cdist.core.object.STATE_PREPARED: + if cdist_object.state == core.Object.STATE_PREPARED: self.log.debug("Skipping re-prepare of object %s", cdist_object) continue else: @@ -121,7 +121,7 @@ class ConfigInstall(object): self.log.info("Running manifest and explorers for " + cdist_object.name) self.run_type_explorers(cdist_object) self.manifest.run_type_manifest(cdist_object) - cdist_object.state = cdist.core.object.STATE_PREPARED + cdist_object.state = core.Object.STATE_PREPARED def object_run(self, cdist_object): """Run gencode and code for an object""" From 8cfc16cd76a1b4cda5bf834a8bd63e60f1050181 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 15:48:22 +0200 Subject: [PATCH 1029/4212] finish migration to cdist_object.state Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 74412f96..c95b9f27 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -125,20 +125,21 @@ class ConfigInstall(object): def object_run(self, cdist_object): """Run gencode and code for an object""" - self.log.info("" + cdist_object.name) - if cdist_object.state == cdist.core.object.STATE_RUNNING: - raise cdist.Error("Detected circular dependency in " + cdist_object.__str__()) - elif cdist_object.state == cdist.core.object.STATE_DONE: + self.log.info("Starting run of " + cdist_object.name) + if cdist_object.state == core.Object.STATE_RUNNING: + raise cdist.Error("Detected circular dependency in " + cdist_object.name) + elif cdist_object.state == core.Object.STATE_DONE: + self.log.debug("Ignoring run of already finished object %s", cdist_object) return else: - cdist_object.state = cdist.core.object.STATE_RUNNING + cdist_object.state = core.Object.STATE_RUNNING cdist_type = cdist_object.type for requirement in cdist_object.requirements: self.log.debug("Object %s requires %s", cdist_object, requirement) - # FIXME: requirement is a string, need to create object here required_object = cdist_object.object_from_name(requirement) + self.log.info("Resolving dependency %s for %s" % (required_object.name, cdist_object.name)) self.object_run(required_object) self.log.info("Running gencode and code for " + cdist_object.name) @@ -156,6 +157,9 @@ class ConfigInstall(object): self.code.transfer_code_remote(cdist_object) self.code.run_code_remote(cdist_object) + # Mark this object as done + cdist_object.state == core.Object.STATE_DONE + def stage_run(self): """The final (and real) step of deployment""" self.log.info("Generating and executing code") From 50eead577c5934a9531cfb9d2ea0640a6571ee1c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 15:49:32 +0200 Subject: [PATCH 1030/4212] +missing import Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index c95b9f27..fd704135 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -28,6 +28,7 @@ import sys import tempfile import time +import cdist from cdist import core From 24bf7369d940c6c9981fa6ab6085eca814baff5a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 15:54:26 +0200 Subject: [PATCH 1031/4212] ++info Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index fd704135..cfd7e4c9 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -159,6 +159,7 @@ class ConfigInstall(object): self.code.run_code_remote(cdist_object) # Mark this object as done + self.log.info("Finishing run of " + cdist_object.name) cdist_object.state == core.Object.STATE_DONE def stage_run(self): From c45c9cd702098a22693ed24c5ad9b68a6db42034 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 16:07:13 +0200 Subject: [PATCH 1032/4212] dont re-run already fulfilled requirements Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index cfd7e4c9..cdb76ccd 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -140,8 +140,11 @@ class ConfigInstall(object): for requirement in cdist_object.requirements: self.log.debug("Object %s requires %s", cdist_object, requirement) required_object = cdist_object.object_from_name(requirement) - self.log.info("Resolving dependency %s for %s" % (required_object.name, cdist_object.name)) - self.object_run(required_object) + if required_object.state == core.Object.STATE_DONE: + self.log.debug("Skipping fulfilled dependency %s for %s", required_object, cdist_object) + else: + self.log.info("Resolving dependency %s for %s" % (required_object.name, cdist_object.name)) + self.object_run(required_object) self.log.info("Running gencode and code for " + cdist_object.name) From 9156d2f5ac56ded6ad1a43e9209e403c5da18d5e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 16:15:52 +0200 Subject: [PATCH 1033/4212] trust in telmich we do (or should) Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index cdb76ccd..cfd7e4c9 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -140,11 +140,8 @@ class ConfigInstall(object): for requirement in cdist_object.requirements: self.log.debug("Object %s requires %s", cdist_object, requirement) required_object = cdist_object.object_from_name(requirement) - if required_object.state == core.Object.STATE_DONE: - self.log.debug("Skipping fulfilled dependency %s for %s", required_object, cdist_object) - else: - self.log.info("Resolving dependency %s for %s" % (required_object.name, cdist_object.name)) - self.object_run(required_object) + self.log.info("Resolving dependency %s for %s" % (required_object.name, cdist_object.name)) + self.object_run(required_object) self.log.info("Running gencode and code for " + cdist_object.name) From de8a09b45dd8d6f1549526953c2247693afcd57e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 16:16:52 +0200 Subject: [PATCH 1034/4212] ++FIXME Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index cfd7e4c9..7dd001c6 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -128,6 +128,7 @@ class ConfigInstall(object): """Run gencode and code for an object""" self.log.info("Starting run of " + cdist_object.name) if cdist_object.state == core.Object.STATE_RUNNING: + # FIXME: resolve dependency circle raise cdist.Error("Detected circular dependency in " + cdist_object.name) elif cdist_object.state == core.Object.STATE_DONE: self.log.debug("Ignoring run of already finished object %s", cdist_object) From e9541b2a2a6b1e35e735b2f718adb23b7b188e7a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 16:29:30 +0200 Subject: [PATCH 1035/4212] == is not = :-/ Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 7dd001c6..59cd9f55 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -160,8 +160,8 @@ class ConfigInstall(object): self.code.run_code_remote(cdist_object) # Mark this object as done - self.log.info("Finishing run of " + cdist_object.name) - cdist_object.state == core.Object.STATE_DONE + self.log.debug("Finishing run of " + cdist_object.name) + cdist_object.state = core.Object.STATE_DONE def stage_run(self): """The final (and real) step of deployment""" From ca1ef28fe1319dd0273d117a27cc3b04eb4bddd8 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 16:42:14 +0200 Subject: [PATCH 1036/4212] change order of log.info Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 59cd9f55..dae2a029 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -144,15 +144,15 @@ class ConfigInstall(object): self.log.info("Resolving dependency %s for %s" % (required_object.name, cdist_object.name)) self.object_run(required_object) - self.log.info("Running gencode and code for " + cdist_object.name) - # Generate + self.log.info("Generating 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 + self.log.info("Executing code for " + cdist_object.name) if cdist_object.code_local: self.code.run_code_local(cdist_object) if cdist_object.code_remote: From c189bd9daf7ed4be810563f0c4dfd0ece7598159 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Oct 2011 16:47:52 +0200 Subject: [PATCH 1037/4212] resort output in object_run Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index dae2a029..8bc8adf5 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -126,7 +126,7 @@ class ConfigInstall(object): def object_run(self, cdist_object): """Run gencode and code for an object""" - self.log.info("Starting run of " + cdist_object.name) + self.log.debug("Trying to run object " + cdist_object.name) if cdist_object.state == core.Object.STATE_RUNNING: # FIXME: resolve dependency circle raise cdist.Error("Detected circular dependency in " + cdist_object.name) @@ -141,18 +141,16 @@ class ConfigInstall(object): for requirement in cdist_object.requirements: self.log.debug("Object %s requires %s", cdist_object, requirement) required_object = cdist_object.object_from_name(requirement) - self.log.info("Resolving dependency %s for %s" % (required_object.name, cdist_object.name)) self.object_run(required_object) # Generate - self.log.info("Generating code for " + cdist_object.name) + 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 - self.log.info("Executing code for " + cdist_object.name) if cdist_object.code_local: self.code.run_code_local(cdist_object) if cdist_object.code_remote: From 56787617d05965d27ddbda6e6831a17570bc82f8 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 17:44:30 +0200 Subject: [PATCH 1038/4212] ++todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index ba18b34c..b6e07eac 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -17,7 +17,15 @@ metaparameters: __init_script /etc/rc.d/sshd \ --subscribe __file/etc/ssh/sshd_config - ? how does a type react to a received 'event' + - how does a type react to a received 'event'? + - maybe something like: + __some_type/ + manifest + ... + gencode-refresh + ... + - gencode-refresh -> code-refresh -> ssh $target sh -e code-refresh + From 97ab6effa486c25c04d6c2fd8c7169b524c3bf88 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 19 Oct 2011 17:59:21 +0200 Subject: [PATCH 1039/4212] introduce new cdist.test.CdistTestCase base class which handles common tasks Signed-off-by: Steven Armstrong --- lib/cdist/test/__init__.py | 11 +++++++++++ lib/cdist/test/code/__init__.py | 10 +--------- lib/cdist/test/emulator/__init__.py | 10 +--------- lib/cdist/test/exec/local.py | 11 ++--------- lib/cdist/test/exec/remote.py | 10 +--------- lib/cdist/test/explorer/__init__.py | 10 +--------- lib/cdist/test/manifest/__init__.py | 11 ++--------- lib/cdist/test/object/__init__.py | 9 ++++----- lib/cdist/test/type/__init__.py | 12 ++---------- 9 files changed, 25 insertions(+), 69 deletions(-) diff --git a/lib/cdist/test/__init__.py b/lib/cdist/test/__init__.py index 2c6abd36..faa9dc2d 100644 --- a/lib/cdist/test/__init__.py +++ b/lib/cdist/test/__init__.py @@ -20,8 +20,19 @@ # import os +import unittest +import tempfile cdist_base_path = os.path.abspath( os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../")) cdist_exec_path = os.path.join(cdist_base_path, "bin/cdist") + + +class CdistTestCase(unittest.TestCase): + + def mkdtemp(self, **kwargs): + return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) + + def mkstemp(self, **kwargs): + return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index 68e8a41d..2f061086 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -20,8 +20,6 @@ # import os -import tempfile -import unittest import shutil import getpass import logging @@ -38,13 +36,7 @@ my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') local_base_path = fixtures -class CodeTestCase(unittest.TestCase): - - def mkdtemp(self, **kwargs): - return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) - - def mkstemp(self, **kwargs): - return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) +class CodeTestCase(test.CdistTestCase): def setUp(self): self.target_host = 'localhost' diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index ccdda265..386969e5 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -20,8 +20,6 @@ # import os -import tempfile -import unittest import shutil from cdist import test @@ -32,13 +30,7 @@ from cdist import core local_base_path = test.cdist_base_path -class EmulatorTestCase(unittest.TestCase): - - def mkdtemp(self, **kwargs): - return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) - - def mkstemp(self, **kwargs): - return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) +class EmulatorTestCase(test.CdistTestCase): def setUp(self): self.orig_environ = os.environ diff --git a/lib/cdist/test/exec/local.py b/lib/cdist/test/exec/local.py index f19bf55c..d73aa079 100644 --- a/lib/cdist/test/exec/local.py +++ b/lib/cdist/test/exec/local.py @@ -19,9 +19,7 @@ # # -import unittest import os -import tempfile import getpass import shutil import string @@ -31,6 +29,7 @@ import random #logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s') import cdist +from cdist import test from cdist.exec import local import os.path as op @@ -39,13 +38,7 @@ fixtures = op.join(my_dir, 'fixtures') local_base_path = fixtures -class LocalTestCase(unittest.TestCase): - - def mkdtemp(self, **kwargs): - return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) - - def mkstemp(self, **kwargs): - return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) +class LocalTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() diff --git a/lib/cdist/test/exec/remote.py b/lib/cdist/test/exec/remote.py index f5151156..191cbd43 100644 --- a/lib/cdist/test/exec/remote.py +++ b/lib/cdist/test/exec/remote.py @@ -19,9 +19,7 @@ # # -import unittest import os -import tempfile import getpass import shutil import string @@ -31,13 +29,7 @@ import cdist from cdist.exec import remote -class RemoteTestCase(unittest.TestCase): - - def mkdtemp(self, **kwargs): - return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) - - def mkstemp(self, **kwargs): - return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) +class RemoteTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index 42b83ee8..18815f07 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -21,8 +21,6 @@ # import os -import tempfile -import unittest import shutil import getpass import logging @@ -39,13 +37,7 @@ my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') local_base_path = fixtures -class ExplorerClassTestCase(unittest.TestCase): - - def mkdtemp(self, **kwargs): - return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) - - def mkstemp(self, **kwargs): - return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) +class ExplorerClassTestCase(test.CdistTestCase): def setUp(self): self.target_host = 'localhost' diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index 257311d7..00789aec 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -19,9 +19,7 @@ # # -import unittest import os -import tempfile import getpass import shutil import string @@ -31,6 +29,7 @@ import io import sys import cdist +from cdist import test from cdist.exec import local from cdist import core from cdist.core import manifest @@ -41,13 +40,7 @@ fixtures = op.join(my_dir, 'fixtures') local_base_path = fixtures -class ManifestTestCase(unittest.TestCase): - - def mkdtemp(self, **kwargs): - return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) - - def mkstemp(self, **kwargs): - return tempfile.mkstemp(prefix='tmp.cdist.test.', **kwargs) +class ManifestTestCase(test.CdistTestCase): def setUp(self): self.orig_environ = os.environ diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index ab05c7af..6681c916 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -20,10 +20,9 @@ # import os -import tempfile -import unittest import shutil +from cdist import test from cdist import core import os.path as op @@ -32,7 +31,7 @@ fixtures = op.join(my_dir, 'fixtures') object_base_path = op.join(fixtures, 'object') type_base_path = op.join(fixtures, 'type') -class ObjectClassTestCase(unittest.TestCase): +class ObjectClassTestCase(test.CdistTestCase): def test_list_object_names(self): object_names = list(core.Object.list_object_names(object_base_path)) @@ -52,7 +51,7 @@ class ObjectClassTestCase(unittest.TestCase): self.assertEqual(objects, objects_expected) -class ObjectIdTestCase(unittest.TestCase): +class ObjectIdTestCase(test.CdistTestCase): def test_object_id_starts_with_slash(self): cdist_type = core.Type(type_base_path, '__third') illegal_object_id = '/object_id/may/not/start/with/slash' @@ -66,7 +65,7 @@ class ObjectIdTestCase(unittest.TestCase): core.Object(cdist_type, object_base_path, illegal_object_id) -class ObjectTestCase(unittest.TestCase): +class ObjectTestCase(test.CdistTestCase): def setUp(self): self.cdist_type = core.Type(type_base_path, '__third') diff --git a/lib/cdist/test/type/__init__.py b/lib/cdist/test/type/__init__.py index dee9d7a6..7bb8654c 100644 --- a/lib/cdist/test/type/__init__.py +++ b/lib/cdist/test/type/__init__.py @@ -20,8 +20,8 @@ # import os -import unittest +from cdist import test from cdist import core import os.path as op @@ -29,7 +29,7 @@ my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') -class TypeTestCase(unittest.TestCase): +class TypeTestCase(test.CdistTestCase): def test_list_type_names(self): base_path = op.join(fixtures, 'list_types') @@ -145,11 +145,3 @@ class TypeTestCase(unittest.TestCase): base_path = fixtures cdist_type = core.Type(base_path, '__without_optional_parameters') self.assertEqual(cdist_type.optional_parameters, []) - -''' -suite = unittest.TestLoader().loadTestsFromTestCase(ObjectTestCase) - -def suite(): - tests = [] - return unittest.TestSuite(map(ObjectTestCase, tests)) -''' From 6f82aef7048fa33c25130970147af312de55caff Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 20 Oct 2011 10:55:11 +0200 Subject: [PATCH 1040/4212] add test for Explorer run_global_explorers Signed-off-by: Steven Armstrong --- lib/cdist/test/explorer/__init__.py | 8 +++++++- lib/cdist/test/explorer/fixtures/conf/explorer/foobar | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100755 lib/cdist/test/explorer/fixtures/conf/explorer/foobar diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index 18815f07..6743ee26 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -62,7 +62,7 @@ class ExplorerClassTestCase(test.CdistTestCase): shutil.rmtree(self.remote_base_path) def test_list_global_explorer_names(self): - expected = ['global'] + expected = ['foobar', 'global'] self.assertEqual(self.explorer.list_global_explorer_names(), expected) def test_transfer_global_explorers(self): @@ -76,6 +76,12 @@ class ExplorerClassTestCase(test.CdistTestCase): output = self.explorer.run_global_explorer('global') self.assertEqual(output, 'global\n') + def test_run_global_explorers(self): + out_path = self.mkdtemp() + self.explorer.run_global_explorers(out_path) + self.assertEqual(os.listdir(out_path), ['foobar', 'global']) + shutil.rmtree(out_path) + def test_list_type_explorer_names(self): cdist_type = core.Type(self.local.type_path, '__test_type') expected = cdist_type.explorers diff --git a/lib/cdist/test/explorer/fixtures/conf/explorer/foobar b/lib/cdist/test/explorer/fixtures/conf/explorer/foobar new file mode 100755 index 00000000..33533edd --- /dev/null +++ b/lib/cdist/test/explorer/fixtures/conf/explorer/foobar @@ -0,0 +1,2 @@ +#!/bin/sh +echo foobar From 40971208f24fe0377ce353c1acc8131b80c0decb Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 20 Oct 2011 11:04:41 +0200 Subject: [PATCH 1041/4212] add test for Explorer run_type_explorers Signed-off-by: Steven Armstrong --- lib/cdist/test/explorer/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index 6743ee26..1f7a2e35 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -124,3 +124,10 @@ class ExplorerClassTestCase(test.CdistTestCase): self.explorer.transfer_type_explorers(cdist_type) output = self.explorer.run_type_explorer('world', cdist_object) self.assertEqual(output, 'hello\n') + + def test_run_type_explorers(self): + cdist_type = core.Type(self.local.type_path, '__test_type') + cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') + cdist_object.create() + self.explorer.run_type_explorers(cdist_object) + self.assertEqual(cdist_object.explorers, {'world': 'hello'}) From 60c4e21981390676deec431b3884332a7c7e39b9 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 20 Oct 2011 11:05:50 +0200 Subject: [PATCH 1042/4212] implement Explorer run_global_explorers and run_type_explorers Signed-off-by: Steven Armstrong --- lib/cdist/core/explorer.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 2e13cc78..0a8c6986 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -83,6 +83,19 @@ class Explorer(object): """Return a list of global explorer names.""" return os.listdir(self.local.global_explorer_path) + def run_global_explorers(self, out_path): + """Run global explorers and save output to files in the given + out_path directory. + + """ + self.log.info("Running global explorers") + self.transfer_global_explorers() + for explorer in self.list_global_explorer_names(): + output = self.run_global_explorer(explorer) + path = os.path.join(out_path, explorer) + with open(path, 'w') as fd: + fd.write(output) + def transfer_global_explorers(self): """Transfer the global explorers to the remote side.""" self.remote.mkdir(self.remote.global_explorer_path) @@ -103,6 +116,20 @@ class Explorer(object): except EnvironmentError: return [] + def run_type_explorers(self, cdist_object): + """Run the type explorers for the given object and save their output + in the object. + + """ + self.log.debug("Transfering type explorers for type: %s", cdist_object.type) + self.transfer_type_explorers(cdist_object.type) + self.log.debug("Transfering object parameters for object: %s", cdist_object.name) + self.transfer_object_parameters(cdist_object) + for explorer in self.list_type_explorer_names(cdist_object.type): + output = self.run_type_explorer(explorer, cdist_object) + self.log.debug("Running type explorer '%s' for object '%s'", explorer, cdist_object.name) + cdist_object.explorers[explorer] = output + def transfer_type_explorers(self, cdist_type): """Transfer the type explorers for the given type to the remote side.""" if cdist_type.explorers: From 6223402b9ecb26d974e71e529e7aa2b63e1cfdf3 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 20 Oct 2011 11:07:48 +0200 Subject: [PATCH 1043/4212] bugfix: only attempt to transfer object parameters it their are any Signed-off-by: Steven Armstrong --- lib/cdist/core/explorer.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 2e13cc78..86926c27 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -117,10 +117,11 @@ class Explorer(object): def transfer_object_parameters(self, cdist_object): """Transfer the parameters for the given object to the remote side.""" - source = os.path.join(self.local.object_path, cdist_object.parameter_path) - destination = os.path.join(self.remote.object_path, cdist_object.parameter_path) - self.remote.mkdir(destination) - self.remote.transfer(source, destination) + if cdist_object.parameters: + source = os.path.join(self.local.object_path, cdist_object.parameter_path) + destination = os.path.join(self.remote.object_path, cdist_object.parameter_path) + self.remote.mkdir(destination) + self.remote.transfer(source, destination) def run_type_explorer(self, explorer, cdist_object): """Run the given type explorer for the given object and return it's output.""" From 81e4c0a418c1e9cee3f30d14133c013bc919847c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 20 Oct 2011 11:10:30 +0200 Subject: [PATCH 1044/4212] move run_*_explorers from config_install to core.explorer Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 8bc8adf5..75b07e78 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -77,7 +77,7 @@ class ConfigInstall(object): def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" self.local.link_emulator(self.context.exec_path) - self.run_global_explorers() + self.explorer.run_global_explorers(self.local.global_explorer_out_path) self.manifest.run_initial_manifest(self.context.initial_manifest) self.log.info("Running object manifests and type explorers") @@ -95,32 +95,10 @@ class ConfigInstall(object): self.object_prepare(cdist_object) new_objects_created = True - def run_global_explorers(self): - """Run global explorers and save output""" - # FIXME: move to explorer, pass global_explorer_out_path as argument - self.log.info("Running global explorers") - self.explorer.transfer_global_explorers() - for explorer in self.explorer.list_global_explorer_names(): - output = self.explorer.run_global_explorer(explorer) - path = os.path.join(self.local.global_explorer_out_path, explorer) - with open(path, 'w') as fd: - fd.write(output) - - def run_type_explorers(self, cdist_object): - """Run type explorers and save output in object.""" - self.log.debug("Transfering type explorers for type: %s", cdist_object.type) - self.explorer.transfer_type_explorers(cdist_object.type) - self.log.debug("Transfering object parameters for object: %s", cdist_object.name) - self.explorer.transfer_object_parameters(cdist_object) - for explorer in self.explorer.list_type_explorer_names(cdist_object.type): - output = self.explorer.run_type_explorer(explorer, cdist_object) - self.log.debug("Running type explorer '%s' for object '%s'", explorer, cdist_object.name) - cdist_object.explorers[explorer] = output - def object_prepare(self, cdist_object): """Prepare object: Run type explorer + manifest""" self.log.info("Running manifest and explorers for " + cdist_object.name) - self.run_type_explorers(cdist_object) + self.explorer.run_type_explorers(cdist_object) self.manifest.run_type_manifest(cdist_object) cdist_object.state = core.Object.STATE_PREPARED From a2cda1ccce87d62fc93cff291a61427134ee242b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 20 Oct 2011 11:16:38 +0200 Subject: [PATCH 1045/4212] --todo Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 7 ------- 1 file changed, 7 deletions(-) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index b6e07eac..f8e13a45 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -45,13 +45,6 @@ logging: [2] http://blog.ooz.ie/2011/03/python-logging-extending-standard.html -config_install: - - move code for running global and type explorer run to cdist.core.explorer - -tests: - - aufraeumen - - test suite - tests: From 1e354387f98b0767561507c96cdbf02f4a3f52af Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 21 Oct 2011 14:48:47 +0200 Subject: [PATCH 1046/4212] add missing import Signed-off-by: Steven Armstrong --- lib/cdist/test/exec/remote.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/cdist/test/exec/remote.py b/lib/cdist/test/exec/remote.py index 191cbd43..92b68d06 100644 --- a/lib/cdist/test/exec/remote.py +++ b/lib/cdist/test/exec/remote.py @@ -26,6 +26,7 @@ import string import random import cdist +from cdist import test from cdist.exec import remote @@ -33,12 +34,12 @@ class RemoteTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() - target_host = 'localhost' + self.target_host = 'localhost' self.base_path = self.temp_dir user = getpass.getuser() remote_exec = "ssh -o User=%s -q" % user remote_copy = "scp -o User=%s -q" % user - self.remote = remote.Remote(target_host, self.base_path, remote_exec, remote_copy) + self.remote = remote.Remote(self.target_host, self.base_path, remote_exec, remote_copy) def tearDown(self): shutil.rmtree(self.temp_dir) From 8e2b9e4337cbc55996a2b626855dbcaa652b9cbf Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 21 Oct 2011 15:10:41 +0200 Subject: [PATCH 1047/4212] add test for: __target_host exported to remote exec Signed-off-by: Steven Armstrong --- lib/cdist/test/exec/remote.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/cdist/test/exec/remote.py b/lib/cdist/test/exec/remote.py index 92b68d06..1334e330 100644 --- a/lib/cdist/test/exec/remote.py +++ b/lib/cdist/test/exec/remote.py @@ -118,3 +118,16 @@ class RemoteTestCase(test.CdistTestCase): self.remote.create_directories() self.assertTrue(os.path.isdir(self.remote.base_path)) self.assertTrue(os.path.isdir(self.remote.conf_path)) + + def test_run_script_target_host_in_env(self): + handle, remote_exec_path = self.mkstemp(dir=self.temp_dir) + with os.fdopen(handle, 'w') as fd: + fd.writelines(["#!/bin/sh\n", "echo $__target_host"]) + os.chmod(remote_exec_path, 0o755) + remote_exec = remote_exec_path + remote_copy = "echo" + r = remote.Remote(self.target_host, self.base_path, remote_exec, remote_copy) + handle, script = self.mkstemp(dir=self.temp_dir) + with os.fdopen(handle, "w") as fd: + fd.writelines(["#!/bin/sh\n", "echo foobar"]) + self.assertEqual(r.run_script(script, return_output=True), "%s\n" % self.target_host) From 16b118b38e541edc3256bf9f08566ca9b0cc34cb Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 21 Oct 2011 15:16:38 +0200 Subject: [PATCH 1048/4212] add test for: __target_host exported to remote exec run Signed-off-by: Steven Armstrong --- lib/cdist/test/exec/remote.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/cdist/test/exec/remote.py b/lib/cdist/test/exec/remote.py index 1334e330..a09a334f 100644 --- a/lib/cdist/test/exec/remote.py +++ b/lib/cdist/test/exec/remote.py @@ -119,6 +119,16 @@ class RemoteTestCase(test.CdistTestCase): self.assertTrue(os.path.isdir(self.remote.base_path)) self.assertTrue(os.path.isdir(self.remote.conf_path)) + def test_run_target_host_in_env(self): + handle, remote_exec_path = self.mkstemp(dir=self.temp_dir) + with os.fdopen(handle, 'w') as fd: + fd.writelines(["#!/bin/sh\n", "echo $__target_host"]) + os.chmod(remote_exec_path, 0o755) + remote_exec = remote_exec_path + remote_copy = "echo" + r = remote.Remote(self.target_host, self.base_path, remote_exec, remote_copy) + self.assertEqual(r.run('/bin/true', return_output=True), "%s\n" % self.target_host) + def test_run_script_target_host_in_env(self): handle, remote_exec_path = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, 'w') as fd: @@ -129,5 +139,5 @@ class RemoteTestCase(test.CdistTestCase): r = remote.Remote(self.target_host, self.base_path, remote_exec, remote_copy) handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: - fd.writelines(["#!/bin/sh\n", "echo foobar"]) + fd.writelines(["#!/bin/sh\n", "/bin/true"]) self.assertEqual(r.run_script(script, return_output=True), "%s\n" % self.target_host) From 17e76426158069ab4ba16d765f4b988d64dedb4f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 21 Oct 2011 15:17:19 +0200 Subject: [PATCH 1049/4212] implement: export __target_host in remote exec Signed-off-by: Steven Armstrong --- lib/cdist/exec/remote.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 2847d89c..259f72d8 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -111,6 +111,10 @@ class Remote(object): """ assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %s" % command + # export target_host for use in __remote_{exec,copy} scripts + os_environ = os.environ.copy() + os_environ['__target_host'] = self.target_host + # can't pass environment to remote side, so prepend command with # variable declarations if env: @@ -122,7 +126,7 @@ class Remote(object): self.log.debug("Remote run: %s", command) try: if return_output: - return subprocess.check_output(command).decode() + return subprocess.check_output(command, env=os_environ).decode() else: subprocess.check_call(command) except subprocess.CalledProcessError: @@ -140,6 +144,10 @@ class Remote(object): command = self._exec.split() command.append(self.target_host) + # export target_host for use in __remote_{exec,copy} scripts + os_environ = os.environ.copy() + os_environ['__target_host'] = self.target_host + # can't pass environment to remote side, so prepend command with # variable declarations if env: @@ -154,7 +162,7 @@ class Remote(object): try: if return_output: - return subprocess.check_output(command).decode() + return subprocess.check_output(command, env=os_environ).decode() else: subprocess.check_call(command) except subprocess.CalledProcessError as error: From d4e715f0520c8699fe5bebc8cf85d7c6a5830a98 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 21 Oct 2011 15:26:27 +0200 Subject: [PATCH 1050/4212] close file handles opened with tempfile.mkstemp Signed-off-by: Steven Armstrong --- lib/cdist/test/emulator/__init__.py | 1 + lib/cdist/test/exec/local.py | 15 ++++++--------- lib/cdist/test/exec/remote.py | 17 ++++++++--------- lib/cdist/test/manifest/__init__.py | 2 ++ lib/cdist/test/util/__init__.py | 0 lib/cdist/test/util/fsproperty.py | 0 6 files changed, 17 insertions(+), 18 deletions(-) create mode 100644 lib/cdist/test/util/__init__.py create mode 100644 lib/cdist/test/util/fsproperty.py diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index 386969e5..91150334 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -37,6 +37,7 @@ class EmulatorTestCase(test.CdistTestCase): os.environ = os.environ.copy() self.temp_dir = self.mkdtemp() handle, self.script = self.mkstemp(dir=self.temp_dir) + os.close(handle) self.target_host = 'localhost' out_path = self.temp_dir self.local = local.Local(self.target_host, local_base_path, out_path) diff --git a/lib/cdist/test/exec/local.py b/lib/cdist/test/exec/local.py index d73aa079..e6f2c2b0 100644 --- a/lib/cdist/test/exec/local.py +++ b/lib/cdist/test/exec/local.py @@ -90,23 +90,20 @@ class LocalTestCase(test.CdistTestCase): def test_run_script_success(self): handle, script = self.mkstemp(dir=self.temp_dir) - fd = open(script, "w") - fd.writelines(["#!/bin/sh\n", "/bin/true"]) - fd.close() + with os.fdopen(handle, "w") as fd: + fd.writelines(["#!/bin/sh\n", "/bin/true"]) self.local.run_script(script) def test_run_script_fail(self): handle, script = self.mkstemp(dir=self.temp_dir) - fd = open(script, "w") - fd.writelines(["#!/bin/sh\n", "/bin/false"]) - fd.close() + with os.fdopen(handle, "w") as fd: + fd.writelines(["#!/bin/sh\n", "/bin/false"]) self.assertRaises(local.LocalScriptError, self.local.run_script, script) def test_run_script_get_output(self): handle, script = self.mkstemp(dir=self.temp_dir) - fd = open(script, "w") - fd.writelines(["#!/bin/sh\n", "echo foobar"]) - fd.close() + with os.fdopen(handle, "w") as fd: + fd.writelines(["#!/bin/sh\n", "echo foobar"]) self.assertEqual(self.local.run_script(script, return_output=True), "foobar\n") def test_mkdir(self): diff --git a/lib/cdist/test/exec/remote.py b/lib/cdist/test/exec/remote.py index 92b68d06..e111a302 100644 --- a/lib/cdist/test/exec/remote.py +++ b/lib/cdist/test/exec/remote.py @@ -68,23 +68,20 @@ class RemoteTestCase(test.CdistTestCase): def test_run_script_success(self): handle, script = self.mkstemp(dir=self.temp_dir) - fd = open(script, "w") - fd.writelines(["#!/bin/sh\n", "/bin/true"]) - fd.close() + with os.fdopen(handle, "w") as fd: + fd.writelines(["#!/bin/sh\n", "/bin/true"]) self.remote.run_script(script) def test_run_script_fail(self): handle, script = self.mkstemp(dir=self.temp_dir) - fd = open(script, "w") - fd.writelines(["#!/bin/sh\n", "/bin/false"]) - fd.close() + with os.fdopen(handle, "w") as fd: + fd.writelines(["#!/bin/sh\n", "/bin/false"]) self.assertRaises(remote.RemoteScriptError, self.remote.run_script, script) def test_run_script_get_output(self): handle, script = self.mkstemp(dir=self.temp_dir) - fd = open(script, "w") - fd.writelines(["#!/bin/sh\n", "echo foobar"]) - fd.close() + with os.fdopen(handle, "w") as fd: + fd.writelines(["#!/bin/sh\n", "echo foobar"]) self.assertEqual(self.remote.run_script(script, return_output=True), "foobar\n") def test_mkdir(self): @@ -100,6 +97,7 @@ class RemoteTestCase(test.CdistTestCase): def test_transfer_file(self): handle, source = self.mkstemp(dir=self.temp_dir) + os.close(handle) target = self.mkdtemp(dir=self.temp_dir) self.remote.transfer(source, target) self.assertTrue(os.path.isfile(target)) @@ -108,6 +106,7 @@ class RemoteTestCase(test.CdistTestCase): source = self.mkdtemp(dir=self.temp_dir) # put a file in the directory as payload handle, source_file = self.mkstemp(dir=source) + os.close(handle) source_file_name = os.path.split(source_file)[-1] target = self.mkdtemp(dir=self.temp_dir) self.remote.transfer(source, target) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index 00789aec..2383adf7 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -61,6 +61,7 @@ class ManifestTestCase(test.CdistTestCase): def test_initial_manifest_environment(self): initial_manifest = os.path.join(self.local.manifest_path, "dump_environment") handle, output_file = self.mkstemp(dir=self.temp_dir) + os.close(handle) os.environ['__cdist_test_out'] = output_file self.manifest.run_initial_manifest(initial_manifest) @@ -81,6 +82,7 @@ class ManifestTestCase(test.CdistTestCase): cdist_type = core.Type(self.local.type_path, '__dump_environment') cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') handle, output_file = self.mkstemp(dir=self.temp_dir) + os.close(handle) os.environ['__cdist_test_out'] = output_file self.manifest.run_type_manifest(cdist_object) diff --git a/lib/cdist/test/util/__init__.py b/lib/cdist/test/util/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/util/fsproperty.py b/lib/cdist/test/util/fsproperty.py new file mode 100644 index 00000000..e69de29b From c29c419f61e40311ee273088bad40a716dac655c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 21 Oct 2011 15:50:19 +0200 Subject: [PATCH 1051/4212] also export __target_host to check_call Signed-off-by: Steven Armstrong --- lib/cdist/exec/remote.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 259f72d8..433f4cbc 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -128,7 +128,7 @@ class Remote(object): if return_output: return subprocess.check_output(command, env=os_environ).decode() else: - subprocess.check_call(command) + subprocess.check_call(command, env=os_environ) except subprocess.CalledProcessError: raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: @@ -164,7 +164,7 @@ class Remote(object): if return_output: return subprocess.check_output(command, env=os_environ).decode() else: - subprocess.check_call(command) + subprocess.check_call(command, env=os_environ) except subprocess.CalledProcessError as error: script_content = self.run(["cat", script], return_output=True) self.log.error("Code that raised the error:\n%s", script_content) From 18f08d893cdffc498725358dc8f9ed6948156263 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 21 Oct 2011 15:59:39 +0200 Subject: [PATCH 1052/4212] export defaults for __remote_{exec,copy} Signed-off-by: Steven Armstrong --- lib/cdist/context.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index 77a6028f..ab8677a7 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -72,8 +72,8 @@ class Context(object): # Remote self.remote_base_path = os.environ.get('__cdist_remote_out_dir', "/var/lib/cdist") - self.remote_exec = os.environ.get('__remote_exec', "ssh -o User=root -q") - self.remote_copy = os.environ.get('__remote_copy', "scp -o User=root -q") + self.remote_exec = os.environ.setdefault('__remote_exec', "ssh -o User=root -q") + self.remote_copy = os.environ.setdefault('__remote_copy', "scp -o User=root -q") self.remote = remote.Remote(self.target_host, self.remote_base_path, self.remote_exec, self.remote_copy) From 4775c93a6e08bac9c6b8cd6a3528f99396d31760 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 21 Oct 2011 16:01:39 +0200 Subject: [PATCH 1053/4212] use __remote_copy in __file type Signed-off-by: Steven Armstrong --- conf/type/__file/gencode-local | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/conf/type/__file/gencode-local b/conf/type/__file/gencode-local index 1168919e..0c6c249d 100755 --- a/conf/type/__file/gencode-local +++ b/conf/type/__file/gencode-local @@ -31,11 +31,7 @@ if [ -f "$__object/parameter/source" ]; then remote_cksum="$(cat "$__object/explorer/cksum")" if [ "$local_cksum" != "$remote_cksum" ]; then - # FIXME: The username is ugly and hardcoded, replace after 1.0! - # Probably a better aproach is to have the user configured - # ~/.ssh/config to contain the right username - # Probably describe it in cdist-quickstart... - echo scp "$source" "root@${__target_host}:${destination}" + echo "$__remote_copy" "$source" "${__target_host}:${destination}" fi else echo "Source \"$source\" does not exist." >&2 From 9fedf314cfd84f9b77629b42acd0586fc98f8be2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 31 Oct 2011 11:09:42 +0100 Subject: [PATCH 1054/4212] add explorers for lsb_* Signed-off-by: Steven Armstrong --- conf/explorer/lsb_codename | 24 ++++++++++++++++++++++++ conf/explorer/lsb_description | 24 ++++++++++++++++++++++++ conf/explorer/lsb_id | 24 ++++++++++++++++++++++++ conf/explorer/lsb_release | 24 ++++++++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100755 conf/explorer/lsb_codename create mode 100755 conf/explorer/lsb_description create mode 100755 conf/explorer/lsb_id create mode 100755 conf/explorer/lsb_release diff --git a/conf/explorer/lsb_codename b/conf/explorer/lsb_codename new file mode 100755 index 00000000..eec12710 --- /dev/null +++ b/conf/explorer/lsb_codename @@ -0,0 +1,24 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +lsb_release=$(which lsb_release) +[ -x $lsb_release ] && $lsb_release --short --codename \ +|| echo lsb not supported diff --git a/conf/explorer/lsb_description b/conf/explorer/lsb_description new file mode 100755 index 00000000..7349ddeb --- /dev/null +++ b/conf/explorer/lsb_description @@ -0,0 +1,24 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +lsb_release=$(which lsb_release) +[ -x $lsb_release ] && $lsb_release --short --description \ +|| echo lsb not supported diff --git a/conf/explorer/lsb_id b/conf/explorer/lsb_id new file mode 100755 index 00000000..eac173cd --- /dev/null +++ b/conf/explorer/lsb_id @@ -0,0 +1,24 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +lsb_release=$(which lsb_release) +[ -x $lsb_release ] && $lsb_release --short --id \ +|| echo lsb not supported diff --git a/conf/explorer/lsb_release b/conf/explorer/lsb_release new file mode 100755 index 00000000..b3ac4093 --- /dev/null +++ b/conf/explorer/lsb_release @@ -0,0 +1,24 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +lsb_release=$(which lsb_release) +[ -x $lsb_release ] && $lsb_release --short --release \ +|| echo lsb not supported From 7641c04438e01408ac685879f1363f1cea562c69 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 31 Oct 2011 13:40:39 +0100 Subject: [PATCH 1055/4212] +fancy-ideas Signed-off-by: Steven Armstrong --- doc/dev/fancy-ideas | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 doc/dev/fancy-ideas diff --git a/doc/dev/fancy-ideas b/doc/dev/fancy-ideas new file mode 100644 index 00000000..f125a884 --- /dev/null +++ b/doc/dev/fancy-ideas @@ -0,0 +1,7 @@ +== types with namespaces == +- allow types to have namespaces, e.g. + __path/my/type +implemented as a proof of concept at: +https://github.com/asteven/cdist/tree/type-namespaces + + From de84542579d410ef268941f26a4be993c0cbc59f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 31 Oct 2011 14:36:58 +0100 Subject: [PATCH 1056/4212] no lsb_release -> no output Signed-off-by: Steven Armstrong --- conf/explorer/lsb_codename | 3 +-- conf/explorer/lsb_description | 3 +-- conf/explorer/lsb_id | 3 +-- conf/explorer/lsb_release | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/conf/explorer/lsb_codename b/conf/explorer/lsb_codename index eec12710..a8cb2cc4 100755 --- a/conf/explorer/lsb_codename +++ b/conf/explorer/lsb_codename @@ -20,5 +20,4 @@ # lsb_release=$(which lsb_release) -[ -x $lsb_release ] && $lsb_release --short --codename \ -|| echo lsb not supported +[ -x $lsb_release ] && $lsb_release --short --codename diff --git a/conf/explorer/lsb_description b/conf/explorer/lsb_description index 7349ddeb..da0dd74d 100755 --- a/conf/explorer/lsb_description +++ b/conf/explorer/lsb_description @@ -20,5 +20,4 @@ # lsb_release=$(which lsb_release) -[ -x $lsb_release ] && $lsb_release --short --description \ -|| echo lsb not supported +[ -x $lsb_release ] && $lsb_release --short --description diff --git a/conf/explorer/lsb_id b/conf/explorer/lsb_id index eac173cd..44eb7eaa 100755 --- a/conf/explorer/lsb_id +++ b/conf/explorer/lsb_id @@ -20,5 +20,4 @@ # lsb_release=$(which lsb_release) -[ -x $lsb_release ] && $lsb_release --short --id \ -|| echo lsb not supported +[ -x $lsb_release ] && $lsb_release --short --id diff --git a/conf/explorer/lsb_release b/conf/explorer/lsb_release index b3ac4093..6e0d3a8a 100755 --- a/conf/explorer/lsb_release +++ b/conf/explorer/lsb_release @@ -20,5 +20,4 @@ # lsb_release=$(which lsb_release) -[ -x $lsb_release ] && $lsb_release --short --release \ -|| echo lsb not supported +[ -x $lsb_release ] && $lsb_release --short --release From b38262f858077f8f57781d60e4439ad07b0be0ab Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 31 Oct 2011 16:07:33 +0100 Subject: [PATCH 1057/4212] implement reading initial manifest from stdin Signed-off-by: Steven Armstrong --- bin/cdist | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index ffda3e42..4d9cd8a2 100755 --- a/bin/cdist +++ b/bin/cdist @@ -60,7 +60,7 @@ def commandline(): help='Change cdist home (default: .. from bin directory)', action='store') parser['configinstall'].add_argument('-i', '--initial-manifest', - help='Path to a cdist manifest', + help='Path to a cdist manifest or \'-\' to read from stdin.', dest='manifest', required=False) parser['configinstall'].add_argument('-p', '--parallel', help='Operate on multiple hosts in parallel', @@ -104,6 +104,17 @@ def configinstall(args, mode): import multiprocessing import time + initial_manifest_tempfile = None + if args.manifest == '-': + # read initial manifest from stdin + import tempfile + handle, initial_manifest_temp_path = tempfile.mkstemp(prefix='cdist.stdin.') + with os.fdopen(handle, 'w') as fd: + fd.write(sys.stdin.read()) + args.manifest = initial_manifest_temp_path + import atexit + atexit.register(lambda: os.remove(initial_manifest_temp_path)) + try: process = {} failed_hosts = [] From d4aa04f35d6745fd48852c381057dcee2a93d419 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 31 Oct 2011 16:16:10 +0100 Subject: [PATCH 1058/4212] dont fail if lsb_release does not exist Signed-off-by: Steven Armstrong --- conf/explorer/lsb_codename | 6 ++++-- conf/explorer/lsb_description | 6 ++++-- conf/explorer/lsb_id | 6 ++++-- conf/explorer/lsb_release | 6 ++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/conf/explorer/lsb_codename b/conf/explorer/lsb_codename index a8cb2cc4..08bf75be 100755 --- a/conf/explorer/lsb_codename +++ b/conf/explorer/lsb_codename @@ -19,5 +19,7 @@ # # -lsb_release=$(which lsb_release) -[ -x $lsb_release ] && $lsb_release --short --codename +lsb_release=$(which lsb_release 2>/dev/null) +if [ -x "$lsb_release" ]; then + $lsb_release --short --codename +fi diff --git a/conf/explorer/lsb_description b/conf/explorer/lsb_description index da0dd74d..14e59e76 100755 --- a/conf/explorer/lsb_description +++ b/conf/explorer/lsb_description @@ -19,5 +19,7 @@ # # -lsb_release=$(which lsb_release) -[ -x $lsb_release ] && $lsb_release --short --description +lsb_release=$(which lsb_release 2>/dev/null) +if [ -x "$lsb_release" ]; then + $lsb_release --short --description +fi diff --git a/conf/explorer/lsb_id b/conf/explorer/lsb_id index 44eb7eaa..10d6ce52 100755 --- a/conf/explorer/lsb_id +++ b/conf/explorer/lsb_id @@ -19,5 +19,7 @@ # # -lsb_release=$(which lsb_release) -[ -x $lsb_release ] && $lsb_release --short --id +lsb_release=$(which lsb_release 2>/dev/null) +if [ -x "$lsb_release" ]; then + $lsb_release --short --id +fi diff --git a/conf/explorer/lsb_release b/conf/explorer/lsb_release index 6e0d3a8a..2139c2e6 100755 --- a/conf/explorer/lsb_release +++ b/conf/explorer/lsb_release @@ -19,5 +19,7 @@ # # -lsb_release=$(which lsb_release) -[ -x $lsb_release ] && $lsb_release --short --release +lsb_release=$(which lsb_release 2>/dev/null) +if [ -x "$lsb_release" ]; then + $lsb_release --short --release +fi From 5ac857a87ce69f79aa260f7589cdf90829a560c8 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 31 Oct 2011 16:20:48 +0100 Subject: [PATCH 1059/4212] realy, dont fail if lsb_release does not exist Signed-off-by: Steven Armstrong --- conf/explorer/lsb_codename | 1 + conf/explorer/lsb_description | 1 + conf/explorer/lsb_id | 1 + conf/explorer/lsb_release | 1 + 4 files changed, 4 insertions(+) diff --git a/conf/explorer/lsb_codename b/conf/explorer/lsb_codename index 08bf75be..bc742cf7 100755 --- a/conf/explorer/lsb_codename +++ b/conf/explorer/lsb_codename @@ -19,6 +19,7 @@ # # +set +e lsb_release=$(which lsb_release 2>/dev/null) if [ -x "$lsb_release" ]; then $lsb_release --short --codename diff --git a/conf/explorer/lsb_description b/conf/explorer/lsb_description index 14e59e76..f6c30322 100755 --- a/conf/explorer/lsb_description +++ b/conf/explorer/lsb_description @@ -19,6 +19,7 @@ # # +set +e lsb_release=$(which lsb_release 2>/dev/null) if [ -x "$lsb_release" ]; then $lsb_release --short --description diff --git a/conf/explorer/lsb_id b/conf/explorer/lsb_id index 10d6ce52..6cb2359b 100755 --- a/conf/explorer/lsb_id +++ b/conf/explorer/lsb_id @@ -19,6 +19,7 @@ # # +set +e lsb_release=$(which lsb_release 2>/dev/null) if [ -x "$lsb_release" ]; then $lsb_release --short --id diff --git a/conf/explorer/lsb_release b/conf/explorer/lsb_release index 2139c2e6..5787b71f 100755 --- a/conf/explorer/lsb_release +++ b/conf/explorer/lsb_release @@ -19,6 +19,7 @@ # # +set +e lsb_release=$(which lsb_release 2>/dev/null) if [ -x "$lsb_release" ]; then $lsb_release --short --release From d6d4d374bd11136287e987c438d76bad74883fd5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 31 Oct 2011 18:26:36 +0100 Subject: [PATCH 1060/4212] remove unecessary whitespace :-) Signed-off-by: Nico Schottelius --- conf/explorer/lsb_release | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/explorer/lsb_release b/conf/explorer/lsb_release index 5787b71f..a96ac50b 100755 --- a/conf/explorer/lsb_release +++ b/conf/explorer/lsb_release @@ -23,4 +23,4 @@ set +e lsb_release=$(which lsb_release 2>/dev/null) if [ -x "$lsb_release" ]; then $lsb_release --short --release -fi +fi From bf1b995908823fb7e29401d169c4e76a73b953f9 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 1 Nov 2011 22:20:46 +0100 Subject: [PATCH 1061/4212] implement __lt__ and __eq__ to support sorting a list of types Signed-off-by: Steven Armstrong --- lib/cdist/core/type.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/cdist/core/type.py b/lib/cdist/core/type.py index e9cb375a..20365b8d 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/type.py @@ -86,6 +86,12 @@ class Type(object): def __repr__(self): return '' % self.name + def __eq__(self, other): + return isinstance(other, self.__class__) and self.name == other.name + + def __lt__(self, other): + return isinstance(other, self.__class__) and self.name < other.name + @property def is_singleton(self): """Check whether a type is a singleton.""" From 70ee0f1681b2495bc429d3ff9af3b947408e4b70 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 1 Nov 2011 22:46:46 +0100 Subject: [PATCH 1062/4212] implement __lt__ to support sorting a list of objects Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 5157d86a..29dc16e9 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -115,6 +115,10 @@ class Object(object): """define equality as 'attributes are the same'""" return self.__dict__ == other.__dict__ + def __lt__(self, other): + return isinstance(other, self.__class__) and self.name < other.name + + # FIXME: still needed? @property def explorer_path(self): From afba5e92804e537b372b8548aca0d619aa66488b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 2 Nov 2011 07:52:08 +0100 Subject: [PATCH 1063/4212] add utilitly method to split an object name into its type name and object_id Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 29dc16e9..b62417b7 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -60,9 +60,7 @@ class Object(object): def list_objects(cls, object_base_path, type_base_path): """Return a list of object instances""" for object_name in cls.list_object_names(object_base_path): - 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:]) + type_name, object_id = cls.split_name(object_name) yield cls(cdist.core.Type(type_base_path, type_name), object_base_path, object_id=object_id) @classmethod @@ -77,20 +75,17 @@ class Object(object): if DOT_CDIST in dirs: yield os.path.relpath(path, object_base_path) - def object_from_name(self, object_name): - """Convenience method for creating an object instance from an object name. + @staticmethod + def split_name(object_name): + """split_name('__type_name/the/object_id') -> ('__type_name', 'the/object_id') - Mainly intended to create objects when resolving requirements. - - e.g: - .object_from_name('__other/object') -> + Split the given object name into it's type and object_id parts. """ - type_path = self.type.base_path - object_path = self.base_path 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 self.__class__(self.type.__class__(type_path, type_name), object_path, object_id=object_id) + return type_name, object_id def __init__(self, cdist_type, base_path, object_id=None): if object_id: @@ -118,6 +113,19 @@ class Object(object): def __lt__(self, other): return isinstance(other, self.__class__) and self.name < other.name + def object_from_name(self, object_name): + """Convenience method for creating an object instance from an object name. + + Mainly intended to create objects when resolving requirements. + + e.g: + .object_from_name('__other/object') -> + + """ + type_path = self.type.base_path + object_path = self.base_path + type_name, object_id = self.split_name(object_name) + return self.__class__(self.type.__class__(type_path, type_name), object_path, object_id=object_id) # FIXME: still needed? @property From 792ddf0a5bf2b26139373586200550f442994dbe Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 2 Nov 2011 09:13:23 +0100 Subject: [PATCH 1064/4212] add utility method to join object name from type and object_id Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index b62417b7..778bebe8 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -87,6 +87,15 @@ class Object(object): object_id = os.sep.join(object_name.split(os.sep)[1:]) return type_name, object_id + @staticmethod + def join_name(type_name, object_id): + """join_name('__type_name', 'the/object_id') -> __type_name/the/object_id' + + Join the given type_name and object_id into an object name. + + """ + return os.path.join(type_name, object_id) + def __init__(self, cdist_type, base_path, object_id=None): if object_id: if object_id.startswith('/'): @@ -96,7 +105,7 @@ class Object(object): self.type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id - self.name = os.path.join(self.type.name, self.object_id) + self.name = self.join_name(self.type.name, self.object_id) self.path = os.path.join(self.type.path, self.object_id, DOT_CDIST) self.absolute_path = os.path.join(self.base_path, self.path) self.code_local_path = os.path.join(self.path, "code-local") From e36e538f819b4991291a24455ece844180497c50 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 2 Nov 2011 09:15:44 +0100 Subject: [PATCH 1065/4212] sort lists before testing for equality Signed-off-by: Steven Armstrong --- lib/cdist/test/explorer/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index 1f7a2e35..cafe34fc 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -69,7 +69,7 @@ class ExplorerClassTestCase(test.CdistTestCase): self.explorer.transfer_global_explorers() source = self.local.global_explorer_path destination = self.remote.global_explorer_path - self.assertEqual(os.listdir(source), os.listdir(destination)) + self.assertEqual(sorted(os.listdir(source)), sorted(os.listdir(destination))) def test_run_global_explorer(self): self.explorer.transfer_global_explorers() @@ -79,7 +79,7 @@ class ExplorerClassTestCase(test.CdistTestCase): def test_run_global_explorers(self): out_path = self.mkdtemp() self.explorer.run_global_explorers(out_path) - self.assertEqual(os.listdir(out_path), ['foobar', 'global']) + self.assertEqual(sorted(os.listdir(out_path)), sorted(['foobar', 'global'])) shutil.rmtree(out_path) def test_list_type_explorer_names(self): @@ -116,7 +116,7 @@ class ExplorerClassTestCase(test.CdistTestCase): self.explorer.transfer_object_parameters(cdist_object) source = os.path.join(self.local.object_path, cdist_object.parameter_path) destination = os.path.join(self.remote.object_path, cdist_object.parameter_path) - self.assertEqual(os.listdir(source), os.listdir(destination)) + self.assertEqual(sorted(os.listdir(source)), sorted(os.listdir(destination))) def test_run_type_explorer(self): cdist_type = core.Type(self.local.type_path, '__test_type') From e195eb46c495d42562607bfcf128563412732312 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 2 Nov 2011 16:30:35 +0100 Subject: [PATCH 1066/4212] new type __cron: installs and manages cron jobs Signed-off-by: Steven Armstrong --- conf/type/__cron/explorer/entry | 39 +++++++++++++++++ conf/type/__cron/gencode-remote | 63 +++++++++++++++++++++++++++ conf/type/__cron/man.text | 61 ++++++++++++++++++++++++++ conf/type/__cron/manifest | 66 +++++++++++++++++++++++++++++ conf/type/__cron/parameter/optional | 6 +++ conf/type/__cron/parameter/required | 2 + 6 files changed, 237 insertions(+) create mode 100755 conf/type/__cron/explorer/entry create mode 100755 conf/type/__cron/gencode-remote create mode 100644 conf/type/__cron/man.text create mode 100755 conf/type/__cron/manifest create mode 100644 conf/type/__cron/parameter/optional create mode 100644 conf/type/__cron/parameter/required diff --git a/conf/type/__cron/explorer/entry b/conf/type/__cron/explorer/entry new file mode 100755 index 00000000..362c96fe --- /dev/null +++ b/conf/type/__cron/explorer/entry @@ -0,0 +1,39 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +name="$__object_id" +user="$(cat "$__object/parameter/user")" + +prefix="#cdist:__cron/$name" +suffix="#/cdist:__cron/$name" + +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 + } + print + } +} +' diff --git a/conf/type/__cron/gencode-remote b/conf/type/__cron/gencode-remote new file mode 100755 index 00000000..90b53451 --- /dev/null +++ b/conf/type/__cron/gencode-remote @@ -0,0 +1,63 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +user="$(cat "$__object/parameter/user")" +state_should="$(cat "$__object/parameter/state")" +state_is=$(cmp --quiet "$__object/parameter/entry" "$__object/explorer/entry" \ + && echo present \ + || echo absent +) + +if [ "$state_is" != "$state_should" ]; then + case "$state_should" in + present) + cat << DONE +tmp=\$(mktemp) +crontab -u $user -l > \$tmp +cat >> \$tmp << EOC +$(cat "$__object/parameter/entry")" +EOC +crontab -u $user \$tmp +rm \$tmp +DONE + ;; + absent) + # defined in type manifest + prefix="$(cat "$__object/parameter/prefix")" + suffix="$(cat "$__object/parameter/suffix")" + 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 +fi diff --git a/conf/type/__cron/man.text b/conf/type/__cron/man.text new file mode 100644 index 00000000..c4852b7f --- /dev/null +++ b/conf/type/__cron/man.text @@ -0,0 +1,61 @@ +cdist-type__cron(7) +=================== +Steven Armstrong + + +NAME +---- +cdist-type__cron - installs and manages cron jobs + + +DESCRIPTION +----------- +This cdist type allows you to manage entries in a users crontab. + + +REQUIRED PARAMETERS +------------------- +user:: + The user who's crontab is edited +command:: + The command to run. + + +OPTIONAL PARAMETERS +------------------- +state:: + Either present or absent. Defaults to present. +minute:: + See crontab(5). Defaults to * +hour:: + See crontab(5). Defaults to * +day_of_month:: + See crontab(5). Defaults to * +month:: + See crontab(5). Defaults to * +day_of_week:: + See crontab(5). Defaults to * + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# add cronjob +__cron some-id --user root --command "/path/to/script" + +# remove cronjob +__cron some-id --user root --command "/path/to/script" --state absent +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- crontab(5) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__cron/manifest b/conf/type/__cron/manifest new file mode 100755 index 00000000..01c4358c --- /dev/null +++ b/conf/type/__cron/manifest @@ -0,0 +1,66 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +name="$__object_id" +user="$(cat "$__object/parameter/user")" +command="$(cat "$__object/parameter/command")" + +# set defaults +if [ ! -f "$__object/parameter/state" ]; then + echo "present" > "$__object/parameter/state" +fi +if [ -f "$__object/parameter/minute" ]; then + minute="$(cat "$__object/parameter/minute")" +else + minute="*" + echo "$minute" > "$__object/parameter/minute" +fi +if [ -f "$__object/parameter/hour" ]; then + hour="$(cat "$__object/parameter/hour")" +else + hour="*" + echo "$hour" > "$__object/parameter/hour" +fi +if [ -f "$__object/parameter/day_of_month" ]; then + day_of_month="$(cat "$__object/parameter/day_of_month")" +else + day_of_month="*" + echo "$day_of_month" > "$__object/parameter/day_of_month" +fi +if [ -f "$__object/parameter/month" ]; then + month="$(cat "$__object/parameter/month")" +else + month="*" + echo "$month" > "$__object/parameter/month" +fi +if [ -f "$__object/parameter/day_of_week" ]; then + day_of_week="$(cat "$__object/parameter/day_of_week")" +else + day_of_week="*" + echo "$day_of_week" > "$__object/parameter/day_of_week" +fi + +# NOTE: if changed, also change in explorers +prefix="#cdist:__cron/$name" +suffix="#/cdist:__cron/$name" +echo "$prefix" | tee "$__object/parameter/prefix" > "$__object/parameter/entry" +echo "$minute $hour $day_of_month $month $day_of_week $command" >> "$__object/parameter/entry" +echo "$suffix" | tee "$__object/parameter/suffix" >> "$__object/parameter/entry" + diff --git a/conf/type/__cron/parameter/optional b/conf/type/__cron/parameter/optional new file mode 100644 index 00000000..1a4aae3d --- /dev/null +++ b/conf/type/__cron/parameter/optional @@ -0,0 +1,6 @@ +state +minute +hour +day_of_month +month +day_of_week diff --git a/conf/type/__cron/parameter/required b/conf/type/__cron/parameter/required new file mode 100644 index 00000000..711a59ab --- /dev/null +++ b/conf/type/__cron/parameter/required @@ -0,0 +1,2 @@ +user +command From f42dbb91036ac7d060d44ea1812b063d6e415a92 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 2 Nov 2011 16:39:52 +0100 Subject: [PATCH 1067/4212] --todo Signed-off-by: Steven Armstrong --- doc/dev/todo/TAKEME | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 4cdb6fcf..7974ef7d 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -43,7 +43,6 @@ TYPES - __file_edit - regexp replace (can probably cover all?) -> aka sed. -- __cron - __user add option to include --create-home From 77b1c676ca08d66ee654a373d44ef555aec75f7c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 2 Nov 2011 16:41:56 +0100 Subject: [PATCH 1068/4212] +/- todo Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 5 ++--- doc/man/man7/cdist-tutorial.text | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 4cdb6fcf..a96b3684 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -5,9 +5,8 @@ Feel free to pick one! CORE ---- -- probably remove or improve cdist-type-template -- allow cdist to run without $PATH setup: ./bin/cdist-deploy-to -- support non-ssh access? +- Add subcommand to create template of a type with working manpage + (cdist type-template or so) TESTS ----- diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 71bf18c0..65f3811c 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -9,6 +9,28 @@ cdist-tutorial - a guided introduction into cdist +PREPARING YOUR MACHINE / SETUP +------------------------------ + +- ensure sshd is running on the target host: + +ssh target_host + +- ensure you can login as root + +ssh root@target host + +- ensure login as root works without keys +(see ssh... manpage) + +cdist will do a lot of requests to the target +host, thus you'll have to enter your password +many times, if you don't do this :-) + +- speedup processing with ControlMaster option of +ssh + + YOUR FIRST CONFIGURATION ------------------------ From fa95291cbcc16f48430ada0b018749d128ecb305 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 2 Nov 2011 16:46:50 +0100 Subject: [PATCH 1069/4212] use diff instad of cmp Signed-off-by: Steven Armstrong --- conf/type/__cron/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__cron/gencode-remote b/conf/type/__cron/gencode-remote index 90b53451..947c75ae 100755 --- a/conf/type/__cron/gencode-remote +++ b/conf/type/__cron/gencode-remote @@ -20,7 +20,7 @@ user="$(cat "$__object/parameter/user")" state_should="$(cat "$__object/parameter/state")" -state_is=$(cmp --quiet "$__object/parameter/entry" "$__object/explorer/entry" \ +state_is=$(diff -q "$__object/parameter/entry" "$__object/explorer/entry" \ && echo present \ || echo absent ) From 6e7ebf6de1c221446ec5dbe1cc569230792c7e29 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 2 Nov 2011 17:54:03 +0100 Subject: [PATCH 1070/4212] todo++ Signed-off-by: Steven Armstrong --- doc/dev/todo/steven | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index f8e13a45..2aacaa42 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,3 +1,10 @@ +autorequire: + - objects defined in type manifests should be automatically prerequisites of the current object + - __foo/some-id + __other other-id --state present + => require="__other/other-id" __foo/some-id + + metaparameters: - steal the metaparameters from puppet: From 0d05e61b85cb6a82ea9f15a068b4deb4d763e70a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 2 Nov 2011 23:57:13 +0100 Subject: [PATCH 1071/4212] tests and fixtures for emulator autorequire Signed-off-by: Steven Armstrong --- lib/cdist/test/emulator/__init__.py | 31 ++++++++++++++++++- .../test/emulator/fixtures/conf/manifest/init | 3 ++ .../fixtures/conf/type/__moon/manifest | 8 +++++ .../conf/type/__moon/parameter/optional | 1 + .../conf/type/__moon/parameter/required | 1 + .../fixtures/conf/type/__planet/manifest | 8 +++++ .../conf/type/__planet/parameter/optional | 1 + .../fixtures/conf/type/__saturn/manifest | 4 +++ .../fixtures/conf/type/__saturn/singleton | 0 9 files changed, 56 insertions(+), 1 deletion(-) create mode 100755 lib/cdist/test/emulator/fixtures/conf/manifest/init create mode 100755 lib/cdist/test/emulator/fixtures/conf/type/__moon/manifest create mode 100644 lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/optional create mode 100644 lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/required create mode 100755 lib/cdist/test/emulator/fixtures/conf/type/__planet/manifest create mode 100644 lib/cdist/test/emulator/fixtures/conf/type/__planet/parameter/optional create mode 100755 lib/cdist/test/emulator/fixtures/conf/type/__saturn/manifest create mode 100644 lib/cdist/test/emulator/fixtures/conf/type/__saturn/singleton diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index 91150334..7b30fba1 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -22,6 +22,7 @@ import os import shutil +import cdist from cdist import test from cdist.exec import local from cdist import emulator @@ -29,7 +30,6 @@ from cdist import core local_base_path = test.cdist_base_path - class EmulatorTestCase(test.CdistTestCase): def setUp(self): @@ -73,3 +73,32 @@ class EmulatorTestCase(test.CdistTestCase): os.environ['require'] = '__file/bad/id/with/.cdist/inside' emu = emulator.Emulator(argv) self.assertRaises(core.IllegalObjectIdError, emu.run) + + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') + +class AutoRequireEmulatorTestCase(test.CdistTestCase): + + def setUp(self): + self.temp_dir = self.mkdtemp() + self.target_host = 'localhost' + out_path = self.temp_dir + _local_base_path = fixtures + self.local = local.Local(self.target_host, _local_base_path, out_path) + self.local.create_directories() + self.local.link_emulator(cdist.test.cdist_exec_path) + self.manifest = core.Manifest(self.target_host, self.local) + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_autorequire(self): + initial_manifest = os.path.join(self.local.manifest_path, "init") + self.manifest.run_initial_manifest(initial_manifest) + cdist_type = core.Type(self.local.type_path, '__saturn') + cdist_object = core.Object(cdist_type, self.local.object_path, 'singleton') + self.manifest.run_type_manifest(cdist_object) + expected = ['__planet/Saturn', '__moon/Prometheus'] + self.assertEqual(sorted(cdist_object.requirements), sorted(expected)) diff --git a/lib/cdist/test/emulator/fixtures/conf/manifest/init b/lib/cdist/test/emulator/fixtures/conf/manifest/init new file mode 100755 index 00000000..9fa1aa53 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/manifest/init @@ -0,0 +1,3 @@ +#!/bin/sh + +__saturn diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__moon/manifest b/lib/cdist/test/emulator/fixtures/conf/type/__moon/manifest new file mode 100755 index 00000000..362be5a1 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__moon/manifest @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ -f "$__object/parameter/name" ]; then + name="(cat "$__object/parameter/name")" +else + name="$__object_id" + echo "$name" > "$__object/parameter/name" +fi diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/optional b/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/optional @@ -0,0 +1 @@ +name diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/required b/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/required new file mode 100644 index 00000000..729a5167 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/required @@ -0,0 +1 @@ +planet diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__planet/manifest b/lib/cdist/test/emulator/fixtures/conf/type/__planet/manifest new file mode 100755 index 00000000..362be5a1 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__planet/manifest @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ -f "$__object/parameter/name" ]; then + name="(cat "$__object/parameter/name")" +else + name="$__object_id" + echo "$name" > "$__object/parameter/name" +fi diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__planet/parameter/optional b/lib/cdist/test/emulator/fixtures/conf/type/__planet/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__planet/parameter/optional @@ -0,0 +1 @@ +name diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__saturn/manifest b/lib/cdist/test/emulator/fixtures/conf/type/__saturn/manifest new file mode 100755 index 00000000..38b8cbf3 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__saturn/manifest @@ -0,0 +1,4 @@ +#!/bin/sh + +__planet Saturn +require="__planet/Saturn" __moon Prometheus --planet Saturn diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__saturn/singleton b/lib/cdist/test/emulator/fixtures/conf/type/__saturn/singleton new file mode 100644 index 00000000..e69de29b From 7d0238682b1f9eac6ad8ce3b4d0e636433f93eae Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 2 Nov 2011 23:58:18 +0100 Subject: [PATCH 1072/4212] implement autorequire in emulator Signed-off-by: Steven Armstrong --- lib/cdist/emulator.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 4880c6e6..5b842a91 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -75,6 +75,7 @@ class Emulator(object): self.commandline() self.setup_object() self.record_requirements() + self.record_auto_requirements() self.log.debug("Finished %s %s" % (self.cdist_object.path, self.parameters)) def __init_log(self): @@ -178,3 +179,12 @@ class Emulator(object): # Record / Append source self.cdist_object.source.append(self.object_source) + + def record_auto_requirements(self): + """An object shall automatically depend on all objects that it defined in it's type manifest. + """ + # __object_name is the name of the object whose type manifest is currenlty executed + __object_name = os.environ.get('__object_name', None) + if __object_name: + _object = self.cdist_object.object_from_name(__object_name) + _object.requirements.append(self.cdist_object.name) From c58ec7e4efbf700309c60277baf8a3c91c408a09 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 3 Nov 2011 00:25:06 +0100 Subject: [PATCH 1073/4212] prevent circular dependencies Signed-off-by: Steven Armstrong --- lib/cdist/emulator.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 5b842a91..481e734a 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -187,4 +187,6 @@ class Emulator(object): __object_name = os.environ.get('__object_name', None) if __object_name: _object = self.cdist_object.object_from_name(__object_name) - _object.requirements.append(self.cdist_object.name) + # prevent circular dependencies + if not _object.name in self.cdist_object.requirements: + _object.requirements.append(self.cdist_object.name) From ddebf5b1537e6c3203383927a80390dbb4b14868 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 3 Nov 2011 10:37:10 +0100 Subject: [PATCH 1074/4212] __cron for 2.0.4 Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index aad067b7..7217a6f2 100644 --- a/doc/changelog +++ b/doc/changelog @@ -3,6 +3,7 @@ * Cleanup: __object_fq variable removed (never used) * Cleanup: Environment variable __self DEPRECATED, use __object_name instead * Cleanup: Environment variable __self scheduled for removal in cdist 2.1 + * New Type: __cron (Steven Armstrong) 2.0.3: 2011-10-18 * Improved logging, added --verbose, by more quiet by default From efedfbf47c2cd184d8827c050ba23ffb4b5cb227 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 3 Nov 2011 15:44:12 +0100 Subject: [PATCH 1075/4212] test for singleton requirement Signed-off-by: Steven Armstrong --- lib/cdist/test/emulator/__init__.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index 91150334..8f1b9776 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -73,3 +73,18 @@ class EmulatorTestCase(test.CdistTestCase): os.environ['require'] = '__file/bad/id/with/.cdist/inside' emu = emulator.Emulator(argv) self.assertRaises(core.IllegalObjectIdError, emu.run) + + def test_missing_object_id_requirement(self): + argv = ['__file', '/tmp/foobar'] + os.environ.update(self.env) + os.environ['require'] = '__file' + emu = emulator.Emulator(argv) + self.assertRaises(emulator.IllegalRequirementError, emu.run) + + def test_singleton_object_requirement(self): + argv = ['__file', '/tmp/foobar'] + os.environ.update(self.env) + os.environ['require'] = '__issue' + emu = emulator.Emulator(argv) + emu.run() + # if we get here all is fine From d0123acc2a6f7f2db05f25b4e63abce2f22a8649 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 3 Nov 2011 15:44:51 +0100 Subject: [PATCH 1076/4212] implement singleton as requirement Signed-off-by: Steven Armstrong --- lib/cdist/emulator.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 4880c6e6..7ae89294 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -156,19 +156,22 @@ class Emulator(object): self.log.debug("Recording requirement: " + requirement) requirement_parts = requirement.split(os.sep, 1) requirement_type_name = requirement_parts[0] - requirement_object_id = requirement_parts[1] - - # FIXME: Add support for omitted object id == singleton - #if len(requirement_parts) == 1: - #except IndexError: - # # no object id, must be singleton - # requirement_object_id = 'singleton' - - # Remove / if existent in object id + try: + requirement_object_id = requirement_parts[1] + except IndexError: + # no object id, assume singleton + requirement_object_id = 'singleton' + + # Remove leading / from object id requirement_object_id = requirement_object_id.lstrip('/') # Instantiate type which fails if type does not exist requirement_type = core.Type(self.type_base_path, requirement_type_name) + + if requirement_object_id == 'singleton' \ + and not requirement_type.is_singleton: + raise IllegalRequirementError(requirement, "Missing object_id and type is not a singleton.") + # Instantiate object which fails if the object_id is illegal requirement_object = core.Object(requirement_type, self.object_base_path, requirement_object_id) From 360a03a34940b59fdf2fa449f184f225d059a6fd Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 3 Nov 2011 17:21:14 +0100 Subject: [PATCH 1077/4212] add examples for __remote_{copy,exec} scripts Signed-off-by: Steven Armstrong --- other/examples/remote/README | 2 ++ other/examples/remote/chroot/copy | 28 +++++++++++++++++++++++++ other/examples/remote/chroot/exec | 35 +++++++++++++++++++++++++++++++ other/examples/remote/ssh/copy | 10 +++++++++ other/examples/remote/ssh/exec | 10 +++++++++ 5 files changed, 85 insertions(+) create mode 100644 other/examples/remote/README create mode 100755 other/examples/remote/chroot/copy create mode 100755 other/examples/remote/chroot/exec create mode 100755 other/examples/remote/ssh/copy create mode 100755 other/examples/remote/ssh/exec diff --git a/other/examples/remote/README b/other/examples/remote/README new file mode 100644 index 00000000..288fc293 --- /dev/null +++ b/other/examples/remote/README @@ -0,0 +1,2 @@ +Some examples of using alternative __remote_copy and __remote_exec prefixes. +This allows you to change how cdist interacts with the target host (or directory, or whatever :-) diff --git a/other/examples/remote/chroot/copy b/other/examples/remote/chroot/copy new file mode 100755 index 00000000..eb284ced --- /dev/null +++ b/other/examples/remote/chroot/copy @@ -0,0 +1,28 @@ +#!/bin/sh +# +# __remote_copy script to run cdist against a local chroot instead of via ssh +# to a remote target host. +# +# Usage: +# __remote_copy="/path/to/this/script /path/to/your/chroot" cdist config target-id +# + +log() { + #echo "$@" | logger -t "cdist-chroot-copy" + : +} + +chroot="$1"; shift +target_host="$__target_host" + +# replace target_host with chroot location +code="$(echo "$@" | sed "s|$target_host:|$chroot|g")" + +log "$@" +log "target_host: $target_host" +log "$code" + +# copy files into chroot +cp $code + +log "-----" diff --git a/other/examples/remote/chroot/exec b/other/examples/remote/chroot/exec new file mode 100755 index 00000000..21efe421 --- /dev/null +++ b/other/examples/remote/chroot/exec @@ -0,0 +1,35 @@ +#!/bin/sh +# +# __remote_exec script to run cdist against a local chroot instead of via ssh +# on a remote target host. +# +# Usage: +# __remote_exec="/path/to/this/script /path/to/your/chroot" cdist config target-id +# + +log() { + #echo "$@" | logger -t "cdist-chroot-exec" + : +} + +chroot="$1"; shift +target_host="$1"; shift +script=$(mktemp "${chroot}/tmp/chroot-${0##*/}.XXXXXXXXXX") +trap cleanup INT TERM EXIT +cleanup() { + [ $__cdist_debug ] || rm "$script" +} + +log "$script" +log "$@" +echo "#!/bin/sh -l" > "$script" +echo "$@" >> "$script" +chmod +x "$script" + +relative_script="${script#$chroot}" +log "relative_script: $relative_script" + +# run in chroot +chroot "$chroot" "$relative_script" + +log "-----" diff --git a/other/examples/remote/ssh/copy b/other/examples/remote/ssh/copy new file mode 100755 index 00000000..76c0b2c8 --- /dev/null +++ b/other/examples/remote/ssh/copy @@ -0,0 +1,10 @@ +#!/bin/sh +# +# same as cdist default +# +# Usage: +# __remote_copy="/path/to/this/script" cdist config target_host +# + +#echo "$@" | logger -t "cdist-ssh-copy" +scp -o User=root -q $@ diff --git a/other/examples/remote/ssh/exec b/other/examples/remote/ssh/exec new file mode 100755 index 00000000..63994973 --- /dev/null +++ b/other/examples/remote/ssh/exec @@ -0,0 +1,10 @@ +#!/bin/sh +# +# same as cdist default +# +# Usage: +# __remote_exec="/path/to/this/script" cdist config target_host +# + +#echo "$@" | logger -t "cdist-ssh-exec" +ssh -o User=root -q $@ From f864d307be95aec568a05a401784822ae21923e6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 3 Nov 2011 22:35:06 +0100 Subject: [PATCH 1078/4212] +licence, +logging Signed-off-by: Steven Armstrong --- other/examples/remote/chroot/copy | 21 ++++++++++++++++++++- other/examples/remote/chroot/exec | 24 ++++++++++++++++++++++-- other/examples/remote/ssh/copy | 18 ++++++++++++++++++ other/examples/remote/ssh/exec | 18 ++++++++++++++++++ 4 files changed, 78 insertions(+), 3 deletions(-) diff --git a/other/examples/remote/chroot/copy b/other/examples/remote/chroot/copy index eb284ced..528a5faf 100755 --- a/other/examples/remote/chroot/copy +++ b/other/examples/remote/chroot/copy @@ -1,5 +1,23 @@ #!/bin/sh # +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# # __remote_copy script to run cdist against a local chroot instead of via ssh # to a remote target host. # @@ -18,8 +36,9 @@ target_host="$__target_host" # replace target_host with chroot location code="$(echo "$@" | sed "s|$target_host:|$chroot|g")" -log "$@" log "target_host: $target_host" +log "chroot: $chroot" +log "$@" log "$code" # copy files into chroot diff --git a/other/examples/remote/chroot/exec b/other/examples/remote/chroot/exec index 21efe421..19e76b0e 100755 --- a/other/examples/remote/chroot/exec +++ b/other/examples/remote/chroot/exec @@ -1,5 +1,23 @@ #!/bin/sh # +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# # __remote_exec script to run cdist against a local chroot instead of via ssh # on a remote target host. # @@ -14,14 +32,16 @@ log() { chroot="$1"; shift target_host="$1"; shift + script=$(mktemp "${chroot}/tmp/chroot-${0##*/}.XXXXXXXXXX") trap cleanup INT TERM EXIT cleanup() { [ $__cdist_debug ] || rm "$script" } -log "$script" -log "$@" +log "target_host: $target_host" +log "script: $script" +log "@: $@" echo "#!/bin/sh -l" > "$script" echo "$@" >> "$script" chmod +x "$script" diff --git a/other/examples/remote/ssh/copy b/other/examples/remote/ssh/copy index 76c0b2c8..0ecd8c52 100755 --- a/other/examples/remote/ssh/copy +++ b/other/examples/remote/ssh/copy @@ -1,5 +1,23 @@ #!/bin/sh # +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# # same as cdist default # # Usage: diff --git a/other/examples/remote/ssh/exec b/other/examples/remote/ssh/exec index 63994973..b597a47f 100755 --- a/other/examples/remote/ssh/exec +++ b/other/examples/remote/ssh/exec @@ -1,5 +1,23 @@ #!/bin/sh # +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# # same as cdist default # # Usage: From dad14af100453d467ded44647196d538a5cf9959 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 3 Nov 2011 22:37:05 +0100 Subject: [PATCH 1079/4212] add example for __remote_{copy,exec} scripts using schroot over ssh on remote host Signed-off-by: Steven Armstrong --- other/examples/remote/schroot/copy | 50 ++++++++++++++++++++++++++++++ other/examples/remote/schroot/exec | 45 +++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100755 other/examples/remote/schroot/copy create mode 100755 other/examples/remote/schroot/exec diff --git a/other/examples/remote/schroot/copy b/other/examples/remote/schroot/copy new file mode 100755 index 00000000..3587a4f2 --- /dev/null +++ b/other/examples/remote/schroot/copy @@ -0,0 +1,50 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# __remote_copy script to run cdist against a chroot on the target host over ssh. +# +# Usage: +# __remote_copy="/path/to/this/script schroot-chroot-name" cdist config target_host +# + +log() { + #echo "$@" | logger -t "cdist-schroot-copy" + : +} + +chroot_name="$1"; shift +target_host="$__target_host" + +# get directory for given chroot_name +chroot="$(ssh -o User=root -q $target_host schroot $chroot_name --config | awk -F = '/directory=/ {print $2}')" + +# prefix destination with chroot +code="$(echo "$@" | sed "s|$target_host:|$target_host:$chroot|g")" + +log "target_host: $target_host" +log "chroot_name: $chroot_name" +log "chroot: $chroot" +log "@: $@" +log "code: $code" + +# copy files into remote chroot +scp -o User=root -q $code + +log "-----" diff --git a/other/examples/remote/schroot/exec b/other/examples/remote/schroot/exec new file mode 100755 index 00000000..5b561de0 --- /dev/null +++ b/other/examples/remote/schroot/exec @@ -0,0 +1,45 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# __remote_exec script to run cdist against a chroot on the target host over ssh. +# +# Usage: +# __remote_exec="/path/to/this/script schroot-chroot-name" cdist config target_host +# + +log() { + #echo "$@" | logger -t "cdist-schroot-exec" + : +} + +chroot_name="$1"; shift +target_host="$1"; shift + +code="ssh -o User=root -q $target_host schroot -c $chroot_name -- $@" + +log "target_host: $target_host" +log "chroot_name: $chroot_name" +log "@: $@" +log "code: $code" + +# run in remote chroot +$code + +log "-----" From e18bd97c862af7e9f683a349ddbd0418a75667d6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 8 Nov 2011 08:28:04 +0100 Subject: [PATCH 1080/4212] SUCESSFUL is very helpful to grep for :-) Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 75b07e78..c109e131 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -71,7 +71,7 @@ class ConfigInstall(object): start_time = time.time() self.deploy_to() self.cleanup() - self.log.info("Finished run in %s seconds", + self.log.info("Finished successful run in %s seconds", time.time() - start_time) def stage_prepare(self): From 45c9f629ae2cccae44c2dd790ff44352a837ab6b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 8 Nov 2011 13:29:11 +0100 Subject: [PATCH 1081/4212] another more complete __remote_{copy,exec} example, including usage instructions for dispatching in .../manifest/init Signed-off-by: Steven Armstrong --- other/examples/remote/schroot-uri | 132 ++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100755 other/examples/remote/schroot-uri diff --git a/other/examples/remote/schroot-uri b/other/examples/remote/schroot-uri new file mode 100755 index 00000000..06dce369 --- /dev/null +++ b/other/examples/remote/schroot-uri @@ -0,0 +1,132 @@ +#!/bin/sh -e +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# __remote_{exec,copy} script to run cdist against a schroot target uri +# +# Usage: +# __remote_exec="/path/to/this/script exec" cdist config target_uri +# __remote_copy="/path/to/this/script copy" cdist config target_uri +# +# # target_uri examples: +# schroot:///chroot-name +# schroot://foo.ethz.ch/chroot-name +# schroot://user-name@foo.ethz.ch/chroot-name +# +# # and how to match them in .../manifest/init +# case "$target_host" in +# schroot://*) +# # any schroot +# ;; +# schroot://foo.ethz.ch/*) +# # any schroot on specific host +# ;; +# schroot://foo.ethz.ch/chroot-name) +# # specific schroot on specific host +# ;; +# schroot:///chroot-name) +# # specific schroot on localhost +# ;; +# esac + +my_name="${0##*/}" +mode="$1"; shift + +log() { + #echo "$@" | logger -t "cdist-$my_name-$mode" + : +} + +die() { + echo "$@" >&2 + exit 1 +} + + +uri="$__target_host" + +scheme="${uri%%:*}"; rest="${uri#$scheme:}"; rest="${rest#//}" +authority="${rest%%/*}"; rest="${rest#$authority}" +path="${rest%\?*}"; rest="${rest#$path}" +schroot_name="${path#/}" + +[ "$scheme" = "schroot" ] || die "Failed to parse scheme from __target_host ($__target_host). Expected 'schroot', got '$scheme'" +[ -n "$schroot_name" ] || die "Failed to parse schroot name from __target_host: $__target_host" + +case "$authority" in + '') + # authority is empty, neither user nor host given + user="" + host="" + ;; + *@*) + # authority contains @, take user from authority + user="${authority%@*}" + host="${authority#*@}" + ;; + *) + # no user in authority, default to root + user="root" + host="$authority" + ;; +esac + +log "mode: $mode" +log "@: $@" +log "uri: $uri" +log "scheme: $scheme" +log "authority: $authority" +log "user: $user" +log "host: $host" +log "path: $path" +log "schroot_name: $schroot_name" + +exec_prefix="" +copy_prefix="" +if [ -n "$host" ]; then + # we are working on a remote host + exec_prefix="ssh -o User=$user -q $host" + copy_prefix="scp -o User=$user -q" + copy_destination_prefix="$host:" +else + # working on local machine + copy_prefix="cp" + copy_destination_prefix="" +fi + +case "$mode" in + exec) + code="$exec_prefix schroot -c $schroot_name -- $@" + ;; + copy) + # get directory for given chroot_name + schroot_directory="$($exec_prefix schroot $chroot_name --config | awk -F = '/directory=/ {print $2}')" + [ -n "$schroot_directory" ] || die "Failed to retreive schroot directory for schroot: $schroot_name" + # prefix destination with chroot + code="$copy_prefix $(echo "$@" | sed "s|$uri:|${copy_destination_prefix}${schroot_directory}|g")" + ;; + *) die "Unknown mode: $mode";; +esac + +log "code: $code" + +# Run the code +$code + +log "-----" From b3337a18b9718fbaf4cda2424589d1bbfe49fe17 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 9 Nov 2011 18:30:12 +0100 Subject: [PATCH 1082/4212] in theory catch error when requiring an undefined object (in practise not) Error message trying to fix: ERROR: [Errno 2] No such file or directory: '/home/users/nico/.tmp/tmptvy1ic/out/object/__localch_yum_repos/singleton/.cdist/state' Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index c109e131..055a3b89 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -106,7 +106,7 @@ class ConfigInstall(object): """Run gencode and code for an object""" self.log.debug("Trying to run object " + cdist_object.name) if cdist_object.state == core.Object.STATE_RUNNING: - # FIXME: resolve dependency circle + # FIXME: resolve dependency circle / show problem source raise cdist.Error("Detected circular dependency in " + cdist_object.name) elif cdist_object.state == core.Object.STATE_DONE: self.log.debug("Ignoring run of already finished object %s", cdist_object) @@ -119,6 +119,13 @@ class ConfigInstall(object): for requirement in cdist_object.requirements: self.log.debug("Object %s requires %s", cdist_object, requirement) required_object = cdist_object.object_from_name(requirement) + + # The user may have created dependencies without satisfying them + if not required_object.exists(): + raise cdist.Error(cdist_object.name + " requires non-existing " + requirement.name) + else + self.log.debug("Required object %s exists", requirement.name) + self.object_run(required_object) # Generate From c7d0d581b1bf044d42d5ffadea64a1ce840e6c0e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 9 Nov 2011 18:41:46 +0100 Subject: [PATCH 1083/4212] we pass base_path, not object_path (clearification) Signed-off-by: Nico Schottelius --- lib/cdist/core/object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 778bebe8..db818f11 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -132,9 +132,9 @@ class Object(object): """ type_path = self.type.base_path - object_path = self.base_path + base_path = self.base_path type_name, object_id = self.split_name(object_name) - return self.__class__(self.type.__class__(type_path, type_name), object_path, object_id=object_id) + return self.__class__(self.type.__class__(type_path, type_name), base_path, object_id=object_id) # FIXME: still needed? @property From f95ee8062f6584d40eb0c54ee0397c554e8a411f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 9 Nov 2011 20:28:04 +0100 Subject: [PATCH 1084/4212] --SyntaxError Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 055a3b89..0391dbc5 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -123,7 +123,7 @@ class ConfigInstall(object): # The user may have created dependencies without satisfying them if not required_object.exists(): raise cdist.Error(cdist_object.name + " requires non-existing " + requirement.name) - else + else: self.log.debug("Required object %s exists", requirement.name) self.object_run(required_object) From ae23f1576f8ce8fa93d88a0b73820538c7d573c4 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 9 Nov 2011 20:28:51 +0100 Subject: [PATCH 1085/4212] --TypeError Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 0391dbc5..fbb863c3 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -121,7 +121,7 @@ class ConfigInstall(object): required_object = cdist_object.object_from_name(requirement) # The user may have created dependencies without satisfying them - if not required_object.exists(): + if not required_object.exists: raise cdist.Error(cdist_object.name + " requires non-existing " + requirement.name) else: self.log.debug("Required object %s exists", requirement.name) From e1cf8d094b0ee74f62613ab5b81d1f08767986a0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 9 Nov 2011 20:29:36 +0100 Subject: [PATCH 1086/4212] --AttributeError Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index fbb863c3..3b347eb1 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -122,7 +122,7 @@ class ConfigInstall(object): # The user may have created dependencies without satisfying them if not required_object.exists: - raise cdist.Error(cdist_object.name + " requires non-existing " + requirement.name) + raise cdist.Error(cdist_object.name + " requires non-existing " + required_object.name) else: self.log.debug("Required object %s exists", requirement.name) From b92ea62f72ad26a54c4a17dcfac688d714c1eb3a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 9 Nov 2011 20:36:40 +0100 Subject: [PATCH 1087/4212] export OBJECT_MARKER for use in tests Signed-off-by: Steven Armstrong --- lib/cdist/core/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/core/__init__.py b/lib/cdist/core/__init__.py index ac5bbf2f..c61c659b 100644 --- a/lib/cdist/core/__init__.py +++ b/lib/cdist/core/__init__.py @@ -23,6 +23,7 @@ from cdist.core.type import Type from cdist.core.type import NoSuchTypeError from cdist.core.object import Object from cdist.core.object import IllegalObjectIdError +from cdist.core.object import OBJECT_MARKER from cdist.core.explorer import Explorer from cdist.core.manifest import Manifest from cdist.core.code import Code From 1729516414715d95ac71ac5c645ecd1683f6d279 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 9 Nov 2011 20:38:22 +0100 Subject: [PATCH 1088/4212] allow .cdist (OBJECT_MARKER) inside file names but not as _the_ file/folder name Signed-off-by: Steven Armstrong --- lib/cdist/core/object.py | 10 +++++----- lib/cdist/test/object/__init__.py | 10 ++++++++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index db818f11..9abb11eb 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -30,7 +30,7 @@ from cdist.util import fsproperty log = logging.getLogger(__name__) -DOT_CDIST = '.cdist' +OBJECT_MARKER = '.cdist' class IllegalObjectIdError(cdist.Error): @@ -72,7 +72,7 @@ class Object(object): def list_object_names(cls, object_base_path): """Return a list of object names""" for path, dirs, files in os.walk(object_base_path): - if DOT_CDIST in dirs: + if OBJECT_MARKER in dirs: yield os.path.relpath(path, object_base_path) @staticmethod @@ -100,13 +100,13 @@ class Object(object): if object_id: if object_id.startswith('/'): raise IllegalObjectIdError(object_id, 'object_id may not start with /') - if '.cdist' in object_id: - raise IllegalObjectIdError(object_id, 'object_id may not contain \'.cdist\'') + if OBJECT_MARKER in object_id.split(os.sep): + raise IllegalObjectIdError(object_id, 'object_id may not contain \'%s\'' % OBJECT_MARKER) self.type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id self.name = self.join_name(self.type.name, self.object_id) - self.path = os.path.join(self.type.path, self.object_id, DOT_CDIST) + self.path = os.path.join(self.type.path, self.object_id, OBJECT_MARKER) self.absolute_path = os.path.join(self.base_path, self.path) self.code_local_path = os.path.join(self.path, "code-local") self.code_remote_path = os.path.join(self.path, "code-remote") diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 6681c916..f199ffb5 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -58,12 +58,18 @@ class ObjectIdTestCase(test.CdistTestCase): with self.assertRaises(core.IllegalObjectIdError): core.Object(cdist_type, object_base_path, illegal_object_id) - def test_object_id_contains_dotcdist(self): + def test_object_id_contains_object_marker(self): cdist_type = core.Type(type_base_path, '__third') - illegal_object_id = 'object_id/may/not/contain/.cdist/anywhere' + illegal_object_id = 'object_id/may/not/contain/%s/anywhere' % core.OBJECT_MARKER with self.assertRaises(core.IllegalObjectIdError): core.Object(cdist_type, object_base_path, illegal_object_id) + def test_object_id_contains_object_marker_string(self): + cdist_type = core.Type(type_base_path, '__third') + illegal_object_id = 'object_id/may/contain_%s_in_filename' % core.OBJECT_MARKER + core.Object(cdist_type, object_base_path, illegal_object_id) + # if we get here, the test passed + class ObjectTestCase(test.CdistTestCase): From 6dd1465aa8b43a31915002ddfbfc9dd79c3f536e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 14 Nov 2011 15:29:07 +0100 Subject: [PATCH 1089/4212] --AttributeError Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 3b347eb1..2d2ab949 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -124,7 +124,7 @@ class ConfigInstall(object): if not required_object.exists: raise cdist.Error(cdist_object.name + " requires non-existing " + required_object.name) else: - self.log.debug("Required object %s exists", requirement.name) + self.log.debug("Required object %s exists", required_object.name) self.object_run(required_object) From 6d45a492191458f35235b95e8d1107abde610d1b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 14 Nov 2011 17:30:52 +0100 Subject: [PATCH 1090/4212] new type: __nfs_export manage /etc/exports Signed-off-by: Steven Armstrong --- conf/type/__nfs_export/explorer/entry | 42 +++++++++++++++ conf/type/__nfs_export/explorer/exports.d | 25 +++++++++ conf/type/__nfs_export/gencode-remote | 62 +++++++++++++++++++++++ conf/type/__nfs_export/man.text | 55 ++++++++++++++++++++ conf/type/__nfs_export/manifest | 49 ++++++++++++++++++ conf/type/__nfs_export/parameter/optional | 3 ++ conf/type/__nfs_export/parameter/required | 1 + 7 files changed, 237 insertions(+) create mode 100755 conf/type/__nfs_export/explorer/entry create mode 100755 conf/type/__nfs_export/explorer/exports.d create mode 100755 conf/type/__nfs_export/gencode-remote create mode 100644 conf/type/__nfs_export/man.text create mode 100755 conf/type/__nfs_export/manifest create mode 100644 conf/type/__nfs_export/parameter/optional create mode 100644 conf/type/__nfs_export/parameter/required diff --git a/conf/type/__nfs_export/explorer/entry b/conf/type/__nfs_export/explorer/entry new file mode 100755 index 00000000..4cb10883 --- /dev/null +++ b/conf/type/__nfs_export/explorer/entry @@ -0,0 +1,42 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +export="$(cat "$__object/parameter/export" 2>/dev/null || echo "/$__object_id")" + +name="$(echo "${export#/}" | sed 's;/;-;g')" +prefix="#cdist:__cron/$export" +suffix="#/cdist:__cron/$export" + +if [ -f "/etc/exports.d/$name" ]; then + cat "/etc/exports.d/$name" +else + awk -v prefix="$prefix" -v suffix="$suffix" '{ + if (index($0,prefix)) { + triggered=1 + } + if (triggered) { + if (index($0,suffix)) { + triggered=0 + } + print + } +}' /etc/exports +fi + diff --git a/conf/type/__nfs_export/explorer/exports.d b/conf/type/__nfs_export/explorer/exports.d new file mode 100755 index 00000000..ce370573 --- /dev/null +++ b/conf/type/__nfs_export/explorer/exports.d @@ -0,0 +1,25 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +if [ -d /etc/exports.d ]; then + echo present +else + echo absent +fi diff --git a/conf/type/__nfs_export/gencode-remote b/conf/type/__nfs_export/gencode-remote new file mode 100755 index 00000000..d0e1e1a1 --- /dev/null +++ b/conf/type/__nfs_export/gencode-remote @@ -0,0 +1,62 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +exports_d="$(cat "$__object/explorer/exports.d")" +state_should="$(cat "$__object/parameter/state")" +state_is=$(diff -q "$__object/parameter/entry" "$__object/explorer/entry" \ + && echo present \ + || echo absent +) + +if [ "$exports_d" != "present" ]; then + if [ "$state_is" != "$state_should" ]; then + case "$state_should" in + present) + cat << DONE +cat >> /etc/exports << EOC +$(cat "$__object/parameter/entry")" +EOC +DONE + ;; + absent) + # defined in type manifest + prefix="$(cat "$__object/parameter/prefix")" + suffix="$(cat "$__object/parameter/suffix")" + cat << DONE +cat /etc/exports +awk -v prefix="$prefix" -v suffix="$suffix" ' +{ + if (index(\$0,prefix)) { + triggered=1 + } + if (triggered) { + if (index(\$0,suffix)) { + triggered=0 + } + } else { + print + } +}' /etc/exports > /etc/exports+ +mv -f /etc/exports+ /etc/exports +DONE + ;; + esac + fi +fi diff --git a/conf/type/__nfs_export/man.text b/conf/type/__nfs_export/man.text new file mode 100644 index 00000000..41ff64e8 --- /dev/null +++ b/conf/type/__nfs_export/man.text @@ -0,0 +1,55 @@ +cdist-type__nfs_export(7) +========================= +Steven Armstrong + + +NAME +---- +cdist-type__nfs_export - manage nfs exports + + +DESCRIPTION +----------- +This cdist type allows you to manage entries in /etc/exports.d. +For older distributions (currently ubuntu lucid) that don't support +/etc/exports.d the entries are merged into the /etc/exports file. + + +REQUIRED PARAMETERS +------------------- +client:: + space delimited list of client ip/networks for use in /etc/exports. See exports(5) + + +OPTIONAL PARAMETERS +------------------- +options:: + export options for use in /etc/exports. See exports(5) + +export:: + the directory to export. Defaults to object_id + +state:: + Either present or absent. Defaults to present. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__nfs_export /local/chroot/lucid-amd64 \ + --client "192.168.0.1/24 10.0.0.1/16" \ + --options "ro,async,no_all_squash,no_root_squash,subtree_check" +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- exports(5) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__nfs_export/manifest b/conf/type/__nfs_export/manifest new file mode 100755 index 00000000..1a267412 --- /dev/null +++ b/conf/type/__nfs_export/manifest @@ -0,0 +1,49 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# required +client="$(cat "$__object/parameter/client")" + +# optional +export="$(cat "$__object/parameter/export" 2>/dev/null \ + || echo "/$__object_id" | tee "$__object/parameter/export")" +options="$(cat "$__object/parameter/options" 2>/dev/null || true)" +state="$(cat "$__object/parameter/state" 2>/dev/null \ + || echo "present" | tee "$__object/parameter/state")" + +entry="$export" +[ -n "$options" ] && entry="$entry -${options}" +entry="$entry $client" + +# NOTE: if changed, also change in explorers +prefix="#cdist:__nfs_export/$export" +suffix="#/cdist:__nfs_export/$export" +echo "$prefix" | tee "$__object/parameter/prefix" > "$__object/parameter/entry" +echo "$entry" >> "$__object/parameter/entry" +echo "$suffix" | tee "$__object/parameter/suffix" >> "$__object/parameter/entry" + +exports_d="$(cat "$__object/explorer/exports.d")" +if [ "$exports_d" = "present" ]; then + name="$(echo "$export" | sed 's;/;-;g')" + __file "/etc/exports.d/$name" \ + --source "$__object/parameter/entry" \ + --owner root --group root --mode 644 +# --state "$state" +fi diff --git a/conf/type/__nfs_export/parameter/optional b/conf/type/__nfs_export/parameter/optional new file mode 100644 index 00000000..f6cd84ea --- /dev/null +++ b/conf/type/__nfs_export/parameter/optional @@ -0,0 +1,3 @@ +options +export +state diff --git a/conf/type/__nfs_export/parameter/required b/conf/type/__nfs_export/parameter/required new file mode 100644 index 00000000..b051c6c5 --- /dev/null +++ b/conf/type/__nfs_export/parameter/required @@ -0,0 +1 @@ +client From 71260c77825a224ad3c6160cd68272dc9984e1ef Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 14 Nov 2011 16:20:36 +0100 Subject: [PATCH 1091/4212] new type: __nfs_server Signed-off-by: Steven Armstrong --- conf/type/__nfs_server/man.text | 42 ++++++++++++++++++++++++++++++++ conf/type/__nfs_server/manifest | 28 +++++++++++++++++++++ conf/type/__nfs_server/singleton | 0 3 files changed, 70 insertions(+) create mode 100644 conf/type/__nfs_server/man.text create mode 100755 conf/type/__nfs_server/manifest create mode 100644 conf/type/__nfs_server/singleton diff --git a/conf/type/__nfs_server/man.text b/conf/type/__nfs_server/man.text new file mode 100644 index 00000000..41fc1d75 --- /dev/null +++ b/conf/type/__nfs_server/man.text @@ -0,0 +1,42 @@ +cdist-type__nfs_server(7) +========================= +Steven Armstrong + + +NAME +---- +cdist-type__nfs_server - nfs server + + +DESCRIPTION +----------- +Install, start, do whatever is necessary to have a working nfs server. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__nfs_server +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__nfs_server/manifest b/conf/type/__nfs_server/manifest new file mode 100755 index 00000000..d1946b4c --- /dev/null +++ b/conf/type/__nfs_server/manifest @@ -0,0 +1,28 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +__nfs_client + +__package nfs-kernel-server --state installed + +require="__package/nfs-kernel-server" \ + __process nfs-kernel-server --state running \ + --start "/etc/init.d/portmap start" \ + --name rpc.mountd diff --git a/conf/type/__nfs_server/singleton b/conf/type/__nfs_server/singleton new file mode 100644 index 00000000..e69de29b From d88a4ea55f4fbdc32566a5c3fe54f75257ad2203 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 14 Nov 2011 16:11:50 +0100 Subject: [PATCH 1092/4212] new type: __nfs_client Signed-off-by: Steven Armstrong --- conf/type/__nfs_client/man.text | 42 ++++++++++++++++++++++++++++++++ conf/type/__nfs_client/manifest | 29 ++++++++++++++++++++++ conf/type/__nfs_client/singleton | 0 3 files changed, 71 insertions(+) create mode 100644 conf/type/__nfs_client/man.text create mode 100755 conf/type/__nfs_client/manifest create mode 100644 conf/type/__nfs_client/singleton diff --git a/conf/type/__nfs_client/man.text b/conf/type/__nfs_client/man.text new file mode 100644 index 00000000..3f0808a7 --- /dev/null +++ b/conf/type/__nfs_client/man.text @@ -0,0 +1,42 @@ +cdist-type__nfs_client(7) +========================= +Steven Armstrong + + +NAME +---- +cdist-type__nfs_client - nfs client + + +DESCRIPTION +----------- +Install, start, do whatever is necessary to have a working nfs client. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__nfs_client +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__nfs_client/manifest b/conf/type/__nfs_client/manifest new file mode 100755 index 00000000..a22f487a --- /dev/null +++ b/conf/type/__nfs_client/manifest @@ -0,0 +1,29 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +__package nfs-common --state installed + +require="__package/nfs-common" \ + __process portmap --state running --start "/etc/init.d/portmap start" + +require="__package/nfs-common" \ + __process statd --state running \ + --start "/etc/init.d/statd start" \ + --name rpc.statd diff --git a/conf/type/__nfs_client/singleton b/conf/type/__nfs_client/singleton new file mode 100644 index 00000000..e69de29b From b9301c8194e5a2fcf153ac5e27d04047773ac64e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 14 Nov 2011 23:05:13 +0100 Subject: [PATCH 1093/4212] bugfix: process names dont start with slash Signed-off-by: Steven Armstrong --- conf/type/__process/explorer/runs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__process/explorer/runs b/conf/type/__process/explorer/runs index 2bfa8f84..240ebef9 100755 --- a/conf/type/__process/explorer/runs +++ b/conf/type/__process/explorer/runs @@ -24,7 +24,7 @@ if [ -f "$__object/parameter/name" ]; then name="$(cat "$__object/parameter/name")" else - name="/$__object_id" + name="$__object_id" fi pgrep -x -f "$name" || true From d7623fcf217e5872ab60794b567c97068566b6df Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 14 Nov 2011 23:18:44 +0100 Subject: [PATCH 1094/4212] pgrep -x -f is to restrictive -> impossible to guess/match Signed-off-by: Steven Armstrong --- conf/type/__process/explorer/runs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__process/explorer/runs b/conf/type/__process/explorer/runs index 240ebef9..3ac9ce2f 100755 --- a/conf/type/__process/explorer/runs +++ b/conf/type/__process/explorer/runs @@ -27,4 +27,4 @@ else name="$__object_id" fi -pgrep -x -f "$name" || true +pgrep -x "$name" || true From 98ff723b2406f8cef902d5fab87c794092e42904 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 15 Nov 2011 09:20:27 +0100 Subject: [PATCH 1095/4212] add another example for __process Signed-off-by: Nico Schottelius --- conf/type/__process/man.text | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/conf/type/__process/man.text b/conf/type/__process/man.text index fd3bcf49..065beeef 100644 --- a/conf/type/__process/man.text +++ b/conf/type/__process/man.text @@ -50,6 +50,10 @@ __process /usr/sbin/sshd --state stopped --stop "/etc/rc.d/sshd stop" # Ensure cups is running, which runs with -C ...: __process cups --start "/etc/rc.d/cups start" --state running \ --name "/usr/sbin/cupsd -C /etc/cups/cupsd.conf" + +# Ensure rpc.statd is running (which usually runs with -L) using a regexp +__process rpcstatd --state running --start "/etc/init.d/statd start" \ + --name "rpc.statd.*" -------------------------------------------------------------------------------- From 7d10560a6145f2e6fe8baf2330fd941a92e1689a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 15 Nov 2011 09:21:07 +0100 Subject: [PATCH 1096/4212] Revert "pgrep -x -f is to restrictive -> impossible to guess/match" It's not, regexp are your friends :-) This reverts commit d7623fcf217e5872ab60794b567c97068566b6df. --- conf/type/__process/explorer/runs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__process/explorer/runs b/conf/type/__process/explorer/runs index 3ac9ce2f..240ebef9 100755 --- a/conf/type/__process/explorer/runs +++ b/conf/type/__process/explorer/runs @@ -27,4 +27,4 @@ else name="$__object_id" fi -pgrep -x "$name" || true +pgrep -x -f "$name" || true From d706e8ef03eb45cc13f3161598ecf227290718b7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 16 Nov 2011 08:07:19 +0100 Subject: [PATCH 1097/4212] more changes for 2.0.4 Signed-off-by: Nico Schottelius --- doc/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 7217a6f2..87fad8c0 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,9 +1,10 @@ -2.0.4: +2.0.4: 2011-11-16 * Bugfix core: Remove traceback when sending SIGINT (aka Ctrl-C) * Cleanup: __object_fq variable removed (never used) * Cleanup: Environment variable __self DEPRECATED, use __object_name instead * Cleanup: Environment variable __self scheduled for removal in cdist 2.1 * New Type: __cron (Steven Armstrong) + * Documentation: Many examples for use of __remote_* (Steven Armstrong) 2.0.3: 2011-10-18 * Improved logging, added --verbose, by more quiet by default From ff5fb5dbdb60f76db62e48ae94e3eb279311d326 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 16 Nov 2011 08:10:50 +0100 Subject: [PATCH 1098/4212] remove obsolete cdist video link (to be replaced with new video) Signed-off-by: Nico Schottelius --- README | 2 -- build | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README b/README index 1c2139cc..c3105e26 100644 --- a/README +++ b/README @@ -53,8 +53,6 @@ UNIX, simplicity, familar environment | cdist is configured in POSIX shell The cdist documentation is included as manpages in the distribution. * You can [browse the documentation of the latest version online](man) as well. - * Or you can watch the youtube **video** -[cdist installation and first usage in less than 60 seconds][http://www.youtube.com/watch?v=PRMjzy48eTI). * Have a look at the [given speeches](speeches) ### OS support diff --git a/build b/build index 38fdac07..919360ae 100755 --- a/build +++ b/build @@ -26,13 +26,16 @@ # exit on any error #set -e +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" # Developer webbase WEBDIR=$HOME/niconetz -WEBBASE=software/cdist +WEBBASE=$WEBDIR/software/cdist +WEBDOCBASE=$WEBBASE/$version WEBPAGE=${WEBBASE}.mdwn # Documentation From 56d783f612e03bc4bc570112fc9711953c5c2ffa Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 17 Nov 2011 13:03:56 +0100 Subject: [PATCH 1099/4212] tests and fixtures for type parameters with dashes Signed-off-by: Steven Armstrong --- lib/cdist/test/emulator/__init__.py | 39 +++++++++++++++++++ .../parameter/required | 1 + 2 files changed, 40 insertions(+) create mode 100644 lib/cdist/test/emulator/fixtures/conf/type/__arguments_with_dashes/parameter/required diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index 8f1b9776..5c920770 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -88,3 +88,42 @@ class EmulatorTestCase(test.CdistTestCase): emu = emulator.Emulator(argv) emu.run() # if we get here all is fine + + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') + +class ArgumentsWithDashesTestCase(test.CdistTestCase): + + def setUp(self): + self.temp_dir = self.mkdtemp() + self.target_host = 'localhost' + out_path = self.temp_dir + handle, self.script = self.mkstemp(dir=self.temp_dir) + os.close(handle) + _local_base_path = fixtures + self.local = local.Local(self.target_host, _local_base_path, out_path) + self.local.create_directories() + self.local.link_emulator(test.cdist_exec_path) + self.env = { + 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), + '__target_host': self.target_host, + '__global': self.local.out_path, + '__cdist_type_base_path': self.local.type_path, # for use in type emulator + '__manifest': self.local.manifest_path, + '__cdist_manifest': self.script, + } + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_arguments_with_dashes(self): + argv = ['__arguments_with_dashes', 'some-id', '--with-dash', 'some value'] + os.environ.update(self.env) + emu = emulator.Emulator(argv) + emu.run() + + cdist_type = core.Type(self.local.type_path, '__arguments_with_dashes') + cdist_object = core.Object(cdist_type, self.local.object_path, 'some-id') + self.assertTrue('with-dash' in cdist_object.parameters) diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__arguments_with_dashes/parameter/required b/lib/cdist/test/emulator/fixtures/conf/type/__arguments_with_dashes/parameter/required new file mode 100644 index 00000000..02fabce1 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__arguments_with_dashes/parameter/required @@ -0,0 +1 @@ +with-dash From 68f66af21a2ed23f36d926dde0e7d24e54bc7346 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 17 Nov 2011 13:04:39 +0100 Subject: [PATCH 1100/4212] implement: accept parameters with dashes Signed-off-by: Steven Armstrong --- lib/cdist/emulator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 7ae89294..8fd03d4d 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -97,10 +97,10 @@ class Emulator(object): for parameter in self.cdist_type.optional_parameters: argument = "--" + parameter - parser.add_argument(argument, action='store', required=False) + parser.add_argument(argument, dest=parameter, action='store', required=False) for parameter in self.cdist_type.required_parameters: argument = "--" + parameter - parser.add_argument(argument, action='store', required=True) + parser.add_argument(argument, dest=parameter, action='store', required=True) # If not singleton support one positional parameter if not self.cdist_type.is_singleton: From 79c1f4cb4d018a5c72ef566f2743dea0fdee9af3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 17 Nov 2011 13:25:47 +0100 Subject: [PATCH 1101/4212] document - support Signed-off-by: Nico Schottelius --- build | 8 ++++---- doc/changelog | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/build b/build index 919360ae..085bcdf1 100755 --- a/build +++ b/build @@ -35,7 +35,7 @@ A2XH="a2x -f xhtml --no-xmllint -a encoding=UTF-8" # Developer webbase WEBDIR=$HOME/niconetz WEBBASE=$WEBDIR/software/cdist -WEBDOCBASE=$WEBBASE/$version +WEBMAN=$WEBBASE/man/$version WEBPAGE=${WEBBASE}.mdwn # Documentation @@ -98,9 +98,9 @@ case "$1" in ;; web) - cp README ${WEBDIR}/${WEBPAGE} - rm -rf ${WEBDIR}/${WEBBASE}/man - mkdir -p ${WEBDIR}/${WEBBASE}/man/man1 ${WEBDIR}/${WEBBASE}/man/man7 + cp README ${WEBPAGE} + rm -rf ${WEBMAN} + mkdir -p ${WEBMAN}/man1 ${WEBMAN}/man7 rm -rf ${WEBDIR}/${WEBBASE}/speeches && mkdir ${WEBDIR}/${WEBBASE}/speeches diff --git a/doc/changelog b/doc/changelog index 87fad8c0..e0841f67 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,10 +1,11 @@ -2.0.4: 2011-11-16 +2.0.4: * Bugfix core: Remove traceback when sending SIGINT (aka Ctrl-C) + * Bugfix core: Accept parameters with - in the name (Steven Armstrong) * Cleanup: __object_fq variable removed (never used) * Cleanup: Environment variable __self DEPRECATED, use __object_name instead * Cleanup: Environment variable __self scheduled for removal in cdist 2.1 - * New Type: __cron (Steven Armstrong) * Documentation: Many examples for use of __remote_* (Steven Armstrong) + * New Type: __cron (Steven Armstrong) 2.0.3: 2011-10-18 * Improved logging, added --verbose, by more quiet by default From e380cdf7de5b981b3fa0c80df05be2775652d68e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 17 Nov 2011 15:30:21 +0100 Subject: [PATCH 1102/4212] build.sh is old Signed-off-by: Nico Schottelius --- README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README b/README index c3105e26..ff1293e8 100644 --- a/README +++ b/README @@ -131,7 +131,7 @@ To install cdist, execute the following commands: export PATH=$PATH:$(pwd -P)/bin # If you want the manpages - ./build.sh man + ./build man export MANPATH=$MANPATH:$(pwd -P)/doc/man @@ -178,7 +178,7 @@ To upgrade cdist in the current branch use git pull # Also update the manpages - ./build.sh man + ./build man export MANPATH=$MANPATH:$(pwd -P)/doc/man If you stay on a version branche (i.e. 1.0, 1.1., ...), nothing should break. From cbfcd01d4fff773e1e2824cc526869e682915d85 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 17 Nov 2011 21:51:50 +0100 Subject: [PATCH 1103/4212] ++bugfix Signed-off-by: Steven Armstrong --- other/examples/remote/schroot-uri | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/other/examples/remote/schroot-uri b/other/examples/remote/schroot-uri index 06dce369..a23277ec 100755 --- a/other/examples/remote/schroot-uri +++ b/other/examples/remote/schroot-uri @@ -49,7 +49,7 @@ my_name="${0##*/}" mode="$1"; shift log() { - #echo "$@" | logger -t "cdist-$my_name-$mode" + echo "$@" | logger -t "cdist-$my_name-$mode" : } @@ -112,7 +112,9 @@ fi case "$mode" in exec) - code="$exec_prefix schroot -c $schroot_name -- $@" + # In exec mode the first argument is the __target_host which we already got from env. Get rid of it. + shift + code="$exec_prefix schroot -c $schroot_name -- sh -c '$@'" ;; copy) # get directory for given chroot_name From c59b2839cd2be04b7c7ebb4873a3e3a390ec597a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 18 Nov 2011 08:56:29 +0100 Subject: [PATCH 1104/4212] Export target_host so remote_copy script has access to it Signed-off-by: Steven Armstrong --- conf/type/__file/gencode-local | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/type/__file/gencode-local b/conf/type/__file/gencode-local index 0c6c249d..ae8625b5 100755 --- a/conf/type/__file/gencode-local +++ b/conf/type/__file/gencode-local @@ -31,6 +31,8 @@ if [ -f "$__object/parameter/source" ]; then remote_cksum="$(cat "$__object/explorer/cksum")" if [ "$local_cksum" != "$remote_cksum" ]; then + # Export target_host so remote_copy script has access to it + echo "export __target_host=\"$__target_host\"" echo "$__remote_copy" "$source" "${__target_host}:${destination}" fi else From d76d013b3c280d9641697bffe28441a30b14b107 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 Nov 2011 10:39:21 +0100 Subject: [PATCH 1105/4212] check env [TODO] Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index f424a81d..14a643ea 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -13,6 +13,8 @@ TESTS - multiple defines of object: - fail if different parameters - succeed if same parameters +- verify that all env variables in doc/man/cdist-reference.text.sh + exist in the right stages USER INTERFACE -------------- From df258cf330cb015ac233a09fda0c863190582942 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 Nov 2011 11:10:32 +0100 Subject: [PATCH 1106/4212] +__target_user comment Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 14a643ea..de043a07 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -16,6 +16,8 @@ TESTS - verify that all env variables in doc/man/cdist-reference.text.sh exist in the right stages + __target_user - unneeded? + USER INTERFACE -------------- - add support $__tmp? From 7c8f9e8b9873f5324eff0cbe8d8b00b80136c018 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 Nov 2011 14:05:26 +0100 Subject: [PATCH 1107/4212] remove reference to __target_user - has never been used and is not implemented anymore Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 2 -- doc/man/cdist-reference.text.sh | 3 --- 2 files changed, 5 deletions(-) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index de043a07..14a643ea 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -16,8 +16,6 @@ TESTS - verify that all env variables in doc/man/cdist-reference.text.sh exist in the right stages - __target_user - unneeded? - USER INTERFACE -------------- - add support $__tmp? diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 9127096c..0a7b551e 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -188,9 +188,6 @@ __object_name:: __target_host:: The host we are deploying to. Available for: initial manifest, type manifest, type gencode -__target_user:: - User to use for authentication on remote host. - Currently static in core. __type:: Path to the current type. Available for: type manifest, type gencode From 31403722ce240e9a42518639987eaa80b4afdf25 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 18 Nov 2011 14:36:51 +0100 Subject: [PATCH 1108/4212] todo++ Signed-off-by: Steven Armstrong --- doc/dev/todo/TAKEME | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 14a643ea..be76b040 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -15,6 +15,8 @@ TESTS - succeed if same parameters - verify that all env variables in doc/man/cdist-reference.text.sh exist in the right stages +- test DependencyResolver + USER INTERFACE -------------- From 654e19f28bf1d78b84d30bf3b616c4e75c2b258d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 18 Nov 2011 14:40:25 +0100 Subject: [PATCH 1109/4212] mark _run_command as private Signed-off-by: Steven Armstrong --- conf/type/__file/gencode-local | 2 -- lib/cdist/exec/remote.py | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/conf/type/__file/gencode-local b/conf/type/__file/gencode-local index ae8625b5..0c6c249d 100755 --- a/conf/type/__file/gencode-local +++ b/conf/type/__file/gencode-local @@ -31,8 +31,6 @@ if [ -f "$__object/parameter/source" ]; then remote_cksum="$(cat "$__object/explorer/cksum")" if [ "$local_cksum" != "$remote_cksum" ]; then - # Export target_host so remote_copy script has access to it - echo "export __target_host=\"$__target_host\"" echo "$__remote_copy" "$source" "${__target_host}:${destination}" fi else diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 433f4cbc..87db7273 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -91,7 +91,7 @@ class Remote(object): self.rmdir(destination) command = self._copy.split() command.extend(["-r", source, self.target_host + ":" + destination]) - self.run_command(command) + self._run_command(command) def run(self, command, env=None, return_output=False): """Run the given command with the given environment on the remote side. @@ -102,9 +102,9 @@ class Remote(object): cmd = self._exec.split() cmd.append(self.target_host) cmd.extend(command) - return self.run_command(cmd, env=env, return_output=return_output) + return self._run_command(cmd, env=env, return_output=return_output) - def run_command(self, command, env=None, return_output=False): + def _run_command(self, command, env=None, return_output=False): """Run the given command with the given environment. Return the output as a string. From 98dec302a603c599a9300f0259166854e96d32d1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 18 Nov 2011 14:44:32 +0100 Subject: [PATCH 1110/4212] export __target_host for use in __remote_{copy,exec} scripts Signed-off-by: Steven Armstrong --- lib/cdist/exec/local.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index 41094faa..0b67c747 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -95,6 +95,12 @@ class Local(object): """ assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %s" % command self.log.debug("Local run: %s", command) + + if env is None: + env = {} + # Export __target_host for use in __remote_{copy,exec} scripts + env['__target_host'] = self.target_host + try: if return_output: return subprocess.check_output(command, env=env).decode() @@ -114,8 +120,13 @@ class Local(object): command.append(script) self.log.debug("Local run script: %s", command) - if env: - self.log.debug("Local run script env: %s", env) + + if env is None: + env = {} + # Export __target_host for use in __remote_{copy,exec} scripts + env['__target_host'] = self.target_host + + self.log.debug("Local run script env: %s", env) try: if return_output: From bf133253039a409479463902cb2c9fb74ceb59e0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 18 Nov 2011 14:56:59 +0100 Subject: [PATCH 1111/4212] if env is not given, os.environ is used -> need to also do that Signed-off-by: Steven Armstrong --- lib/cdist/exec/local.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index 0b67c747..613f5cf2 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -97,7 +97,7 @@ class Local(object): self.log.debug("Local run: %s", command) if env is None: - env = {} + env = os.environ.copy() # Export __target_host for use in __remote_{copy,exec} scripts env['__target_host'] = self.target_host @@ -122,7 +122,7 @@ class Local(object): self.log.debug("Local run script: %s", command) if env is None: - env = {} + env = os.environ.copy() # Export __target_host for use in __remote_{copy,exec} scripts env['__target_host'] = self.target_host From be29ce0f2e8453621ab339dc04b477c04695692e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 Nov 2011 15:26:10 +0100 Subject: [PATCH 1112/4212] 2.0.4 has autorequire enabled Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index e0841f67..91b21259 100644 --- a/doc/changelog +++ b/doc/changelog @@ -5,6 +5,7 @@ * Cleanup: Environment variable __self DEPRECATED, use __object_name instead * Cleanup: Environment variable __self scheduled for removal in cdist 2.1 * Documentation: Many examples for use of __remote_* (Steven Armstrong) + * Feature: Automatically require all used objects (Steven Armstrong) * New Type: __cron (Steven Armstrong) 2.0.3: 2011-10-18 From 3c823c9192e00fddf908b6505640f32e05775502 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 Nov 2011 15:36:31 +0100 Subject: [PATCH 1113/4212] setup release date Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 91b21259..7e17a75c 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,4 +1,4 @@ -2.0.4: +2.0.4: 2011-11-18 * Bugfix core: Remove traceback when sending SIGINT (aka Ctrl-C) * Bugfix core: Accept parameters with - in the name (Steven Armstrong) * Cleanup: __object_fq variable removed (never used) From 092a9aa5b89ad072cdb3f3bbecd7de999f53ef24 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 Nov 2011 15:37:53 +0100 Subject: [PATCH 1114/4212] update version in lib/ Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index abdadf62..85892fec 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -34,7 +34,7 @@ BANNER = """ "P' "" "" """ DOT_CDIST = ".cdist" -VERSION = "2.0.3" +VERSION = "2.0.4" import os From 6b0935c2074cd4b4a3f8901735499901de87e381 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 18 Nov 2011 15:43:06 +0100 Subject: [PATCH 1115/4212] /__self/__object_name/ Signed-off-by: Steven Armstrong --- conf/type/__apt_ppa/manifest | 2 +- conf/type/__autofs_map/manifest | 2 +- conf/type/__autofs_master/manifest | 2 +- conf/type/__package/manifest | 2 +- conf/type/__partition_msdos/manifest | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/conf/type/__apt_ppa/manifest b/conf/type/__apt_ppa/manifest index 5aa84931..04c66ce0 100755 --- a/conf/type/__apt_ppa/manifest +++ b/conf/type/__apt_ppa/manifest @@ -27,4 +27,4 @@ require="__package/python-software-properties" \ --source "$__type/files/remove-apt-repository" \ --mode 0755 -require="$__self" __apt_update_index +require="$__object_name" __apt_update_index diff --git a/conf/type/__autofs_map/manifest b/conf/type/__autofs_map/manifest index 74672e46..d86ea799 100755 --- a/conf/type/__autofs_map/manifest +++ b/conf/type/__autofs_map/manifest @@ -38,5 +38,5 @@ if [ -f "$__object/parameter/comment" ]; then fi echo "$entry" >> "$__object/parameter/entry" -require="$__self" __autofs_master +require="$__object_name" __autofs_master diff --git a/conf/type/__autofs_master/manifest b/conf/type/__autofs_master/manifest index e37a5d34..e429842e 100755 --- a/conf/type/__autofs_master/manifest +++ b/conf/type/__autofs_master/manifest @@ -24,7 +24,7 @@ if [ ! -f "$__object/parameter/header" ]; then fi [ -d "$__object/files" ] || mkdir "$__object/files" -require="$__self" __file /etc/auto.master --source "$__object/files/auto.master" \ +require="$__object_name" __file /etc/auto.master --source "$__object/files/auto.master" \ --mode 644 \ --owner root \ --group root diff --git a/conf/type/__package/manifest b/conf/type/__package/manifest index b331d32d..765ece36 100755 --- a/conf/type/__package/manifest +++ b/conf/type/__package/manifest @@ -49,4 +49,4 @@ for property in $(ls .); do fi done -require="$__self" __package_$type "$@" +require="$__object_name" __package_$type "$@" diff --git a/conf/type/__partition_msdos/manifest b/conf/type/__partition_msdos/manifest index 0d73c405..21e43856 100755 --- a/conf/type/__partition_msdos/manifest +++ b/conf/type/__partition_msdos/manifest @@ -38,4 +38,4 @@ if [ ! -f "$__object/parameter/size" ]; then fi # pull in the type that actually does something with the above parameters -require="$__self" __partition_msdos_apply +require="$__object_name" __partition_msdos_apply From 32fa32bd52520cfad49d1887066ef5a1f8593df8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 Nov 2011 15:45:59 +0100 Subject: [PATCH 1116/4212] improve release script Signed-off-by: Nico Schottelius --- doc/dev/releasechecklist | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index fef1f53b..6bc0a77c 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -1,25 +1,32 @@ -#!/bin/sh -e +#!/bin/sh +# Nico Schottelius -files="bin/cdist-config doc/changelog" +files="doc/changelog lib/cdist/__init__.py" # Stuff to take care of when doing a release echo "Preparing next release" # Ensure documentation builds cleanly -./build.sh clean && ./build.sh man +echo "Testing documentation..." +./build clean && ./build man || exit 1 + +echo "Ensure you fixed/prepared version files: $files" +read wait # get version -version=$(awk -F'=' '/^__cdist_version/ { print $2 }' bin/cdist-config | sed 's/"//g') +lib_version=$(grep ^VERSION lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g') +changelog_version=$(head -n1 doc/changelog | sed 's/:.*//') +git_version=$(git describe) + +if [ "$lib_version" != "$changelog_version -o "$changelog_version" != "$git_version" ]; then + echo "Messed up versions, not releasing" + exit 1 +fi +version=$git_version # get target branch branch=${version%.?} -# adjust version and release date -vi $files - -# Commit stuff -git commit $files - # add tag printf "Enter description for %s>" "$version" read tagmessage @@ -31,5 +38,5 @@ git merge master git checkout master # Publish manpages and sourcecode -./build.sh web -./build.sh pub +./build web +./build pub From 6495bc872f27f4ba2b59cceafd12041b6447aa2f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 Nov 2011 15:48:36 +0100 Subject: [PATCH 1117/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 2f9bb844..f8c2d6da 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,6 +1,10 @@ +- check speech publishing + - and speeches, which may be outdated as well + +- write tutorial + - Fix / rewrite cdist-quickstart -- write tutorial!!!!!!!!! - like ccollect! - include ssh control master! - add local/ hint (and add to git) From ee7f30c052ebb46ab90a3f2ecca4233071942025 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 Nov 2011 15:51:18 +0100 Subject: [PATCH 1118/4212] more version support for documentation Signed-off-by: Nico Schottelius --- build | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/build b/build index 085bcdf1..e3a6e7f9 100755 --- a/build +++ b/build @@ -102,13 +102,14 @@ case "$1" in rm -rf ${WEBMAN} mkdir -p ${WEBMAN}/man1 ${WEBMAN}/man7 - rm -rf ${WEBDIR}/${WEBBASE}/speeches && mkdir ${WEBDIR}/${WEBBASE}/speeches + # old stuff + # rm -rf ${WEBDIR}/${WEBBASE}/speeches && mkdir ${WEBDIR}/${WEBBASE}/speeches + # cp ${SPEECHESDIR}/*.pdf ${WEBDIR}/${WEBBASE}/speeches + # git describe > ${WEBDIR}/${WEBBASE}/man/VERSION - cp ${MAN1DSTDIR}/*.html ${WEBDIR}/${WEBBASE}/man/man1 - cp ${MAN7DSTDIR}/*.html ${WEBDIR}/${WEBBASE}/man/man7 - cp ${SPEECHESDIR}/*.pdf ${WEBDIR}/${WEBBASE}/speeches + cp ${MAN1DSTDIR}/*.html ${WEBMAN}/man1 + cp ${MAN7DSTDIR}/*.html ${WEBMAN}/man7 - git describe > ${WEBDIR}/${WEBBASE}/man/VERSION cd ${WEBDIR} && git add ${WEBBASE} cd ${WEBDIR} && git commit -m "cdist update" ${WEBBASE} ${WEBPAGE} cd ${WEBDIR} && make pub From e33000289986cff3e04dce0ad14f189a3ba49664 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 Nov 2011 15:58:26 +0100 Subject: [PATCH 1119/4212] more verbose, add git tag during release, check lib and changelog Signed-off-by: Nico Schottelius --- doc/dev/releasechecklist | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index 6bc0a77c..cf7d2df8 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -10,33 +10,38 @@ echo "Preparing next release" echo "Testing documentation..." ./build clean && ./build man || exit 1 +# get version +changelog_version=$(head -n1 doc/changelog | sed 's/:.*//') +#git_version=$(git describe) +lib_version=$(grep ^VERSION lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g') + echo "Ensure you fixed/prepared version files: $files" +echo "changelog: $changelog_version" +#echo "git: $git_version" +echo "lib: $lib_version" read wait -# get version -lib_version=$(grep ^VERSION lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g') -changelog_version=$(head -n1 doc/changelog | sed 's/:.*//') -git_version=$(git describe) - -if [ "$lib_version" != "$changelog_version -o "$changelog_version" != "$git_version" ]; then +if [ "$lib_version" != "$changelog_version ]; then echo "Messed up versions, not releasing" exit 1 fi -version=$git_version +version=$lib_version # get target branch branch=${version%.?} # add tag -printf "Enter description for %s>" "$version" +printf "Enter tag description for %s>" "$version" read tagmessage git tag "$version" -m "$tagmessage" # Import into current version branch +echo "git merge into $branch" git checkout $branch git merge master git checkout master # Publish manpages and sourcecode +echo "publising doc/ and code/" ./build web ./build pub From 3605e478e613be1e7e45e619b55a83bdd2ee4234 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 Nov 2011 15:59:36 +0100 Subject: [PATCH 1120/4212] -typo Signed-off-by: Nico Schottelius --- doc/dev/releasechecklist | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index cf7d2df8..188ce474 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -19,12 +19,13 @@ echo "Ensure you fixed/prepared version files: $files" echo "changelog: $changelog_version" #echo "git: $git_version" echo "lib: $lib_version" -read wait -if [ "$lib_version" != "$changelog_version ]; then +if [ "$lib_version" != "$changelog_version" ]; then echo "Messed up versions, not releasing" exit 1 fi +echo "Press enter to continue" +read wait version=$lib_version # get target branch From 55ec36b562d40cfbb4163fe1d4cfcad0a0d922d7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 Nov 2011 16:04:19 +0100 Subject: [PATCH 1121/4212] beautify release script Signed-off-by: Nico Schottelius --- doc/dev/releasechecklist | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index 188ce474..1ef36703 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -23,6 +23,8 @@ echo "lib: $lib_version" if [ "$lib_version" != "$changelog_version" ]; then echo "Messed up versions, not releasing" exit 1 +else + echo "Version are sane, continuing" fi echo "Press enter to continue" read wait @@ -32,7 +34,7 @@ version=$lib_version branch=${version%.?} # add tag -printf "Enter tag description for %s>" "$version" +printf "Enter tag description for %s> " "$version" read tagmessage git tag "$version" -m "$tagmessage" From dd588016a0ba5805474dd4fc190775605b96d9c9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 Nov 2011 16:11:51 +0100 Subject: [PATCH 1122/4212] plural... Signed-off-by: Nico Schottelius --- doc/dev/releasechecklist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index 1ef36703..55d6221b 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -24,7 +24,7 @@ if [ "$lib_version" != "$changelog_version" ]; then echo "Messed up versions, not releasing" exit 1 else - echo "Version are sane, continuing" + echo "Versions are sane, continuing" fi echo "Press enter to continue" read wait From b0e25e8784e2cb528140dc4ffe3d5d070d30721c Mon Sep 17 00:00:00 2001 From: "Christian G. Warden" Date: Wed, 4 Jan 2012 07:58:51 -0800 Subject: [PATCH 1123/4212] fix typo --- conf/explorer/os | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/explorer/os b/conf/explorer/os index e59301e7..1aafb468 100755 --- a/conf/explorer/os +++ b/conf/explorer/os @@ -49,7 +49,7 @@ if grep -q ^Fedora /etc/redhat-release 2>/dev/null; then exit 0 fi -# CentOS is also based on Redhat, this return before redhat! +# CentOS is also based on Redhat, thus return before redhat! if grep -q ^CentOS /etc/redhat-release 2>/dev/null; then echo centos exit 0 From bdafb4ffef39b38721e8c27ff1f1735f6fde396f Mon Sep 17 00:00:00 2001 From: "Christian G. Warden" Date: Wed, 4 Jan 2012 10:08:45 -0800 Subject: [PATCH 1124/4212] A new type for managing luarocks packages The __package_luarocks type manages the installation of Lua modules distribued using LuaRocks. It is based on __package_rubygem. --- .../__package_luarocks/explorer/pkg_status | 31 +++++++++++ conf/type/__package_luarocks/gencode-remote | 52 +++++++++++++++++++ conf/type/__package_luarocks/man.text | 49 +++++++++++++++++ conf/type/__package_luarocks/manifest | 23 ++++++++ .../__package_luarocks/parameter/optional | 1 + .../__package_luarocks/parameter/required | 1 + 6 files changed, 157 insertions(+) create mode 100755 conf/type/__package_luarocks/explorer/pkg_status create mode 100755 conf/type/__package_luarocks/gencode-remote create mode 100644 conf/type/__package_luarocks/man.text create mode 100644 conf/type/__package_luarocks/manifest create mode 100644 conf/type/__package_luarocks/parameter/optional create mode 100644 conf/type/__package_luarocks/parameter/required diff --git a/conf/type/__package_luarocks/explorer/pkg_status b/conf/type/__package_luarocks/explorer/pkg_status new file mode 100755 index 00000000..3eb73298 --- /dev/null +++ b/conf/type/__package_luarocks/explorer/pkg_status @@ -0,0 +1,31 @@ +#!/bin/sh +# +# 2012 SwellPath, Inc. +# Christian G. Warden +# +# 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 rock +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +# Accept luarocks failing if package is not known/installed +luarocks list "$name" | egrep -A1 "^$name$" || exit 0 diff --git a/conf/type/__package_luarocks/gencode-remote b/conf/type/__package_luarocks/gencode-remote new file mode 100755 index 00000000..179022b1 --- /dev/null +++ b/conf/type/__package_luarocks/gencode-remote @@ -0,0 +1,52 @@ +#!/bin/sh +# +# 2012 SwellPath, Inc. +# Christian G. Warden +# +# 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 LuaRocks packages +# + + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +state="$(cat "$__object/parameter/state")" +is_installed="$(grep "(installed)" "$__object/explorer/pkg_status" || true)" + +case "$state" in + installed) + # Install only if non-existent + if [ -z "$is_installed" ]; then + echo luarocks install \"$name\" + fi + ;; + removed) + # Remove only if existent + if [ -n "$is_installed" ]; then + echo luarocks remove \"$name\" + fi + ;; + *) + echo "Unknown state: $state" >&2 + exit 1 + ;; +esac diff --git a/conf/type/__package_luarocks/man.text b/conf/type/__package_luarocks/man.text new file mode 100644 index 00000000..6c1e6734 --- /dev/null +++ b/conf/type/__package_luarocks/man.text @@ -0,0 +1,49 @@ +cdist-type__package_luarocks(7) +============================== +Christian G. Warden + + +NAME +---- +cdist-type__package_luarocks - Manage luarocks packages + + +DESCRIPTION +----------- +LuaRocks is a deployment and management system for Lua modules. + + +REQUIRED PARAMETERS +------------------- +state:: + Either "installed" or "removed". + + +OPTIONAL PARAMETERS +------------------- +name:: + If supplied, use the name and not the object id as the package name. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure luasocket is installed +__package_luarocks luasocket --state installed + +# Remove package +__package_luarocks luasocket --state removed +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__package(7) + + +COPYING +------- +Copyright \(C) 2012 SwellPath, Inc. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__package_luarocks/manifest b/conf/type/__package_luarocks/manifest new file mode 100644 index 00000000..8e626714 --- /dev/null +++ b/conf/type/__package_luarocks/manifest @@ -0,0 +1,23 @@ +#!/bin/sh +# +# 2012 SwellPath, Inc. +# Christian G. Warden +# +# 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 luarocks --state installed +__package make --state installed diff --git a/conf/type/__package_luarocks/parameter/optional b/conf/type/__package_luarocks/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/conf/type/__package_luarocks/parameter/optional @@ -0,0 +1 @@ +name diff --git a/conf/type/__package_luarocks/parameter/required b/conf/type/__package_luarocks/parameter/required new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/conf/type/__package_luarocks/parameter/required @@ -0,0 +1 @@ +state From 745cf47e43837478026a141a321d4f3307f2c16b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Jan 2012 20:40:53 +0100 Subject: [PATCH 1125/4212] changes: +type __package_luarocks (thanks Christian) Signed-off-by: Nico Schottelius --- doc/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/changelog b/doc/changelog index 7e17a75c..81d78662 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,3 +1,6 @@ +2.0.5: + * New Type: __package_luarocks (Christian G. Warden) + 2.0.4: 2011-11-18 * Bugfix core: Remove traceback when sending SIGINT (aka Ctrl-C) * Bugfix core: Accept parameters with - in the name (Steven Armstrong) From 6d55d7ae82fde29c943cde649cc8b9c767ceea14 Mon Sep 17 00:00:00 2001 From: "phrawzty (dan)" Date: Thu, 5 Jan 2012 11:08:16 +0100 Subject: [PATCH 1126/4212] --regex to make __addifnosuchline more flexible --- conf/type/__addifnosuchline/explorer/findline | 10 ++++++++-- conf/type/__addifnosuchline/parameter/optional | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/conf/type/__addifnosuchline/explorer/findline b/conf/type/__addifnosuchline/explorer/findline index ac69a827..b45bd6ea 100755 --- a/conf/type/__addifnosuchline/explorer/findline +++ b/conf/type/__addifnosuchline/explorer/findline @@ -26,12 +26,18 @@ else file="/$__object_id" fi -regex=$(cat "$__object/parameter/line") +if [ -f "$__object/parameter/regex" ]; then + regex=$(cat "$__object/parameter/regex") +else + wrap=$(cat "$__object/parameter/line") + regex="^$wrap\$" +fi + if [ -f "$file" ]; then # sh -e is our environment, we know what we do, # skip error detection for now set +e - grep -q "^$regex\$" "$file" + grep -q "$regex" "$file" if [ $? -eq 1 ]; then echo "NOTFOUND" else diff --git a/conf/type/__addifnosuchline/parameter/optional b/conf/type/__addifnosuchline/parameter/optional index f73f3093..7ecfcde9 100644 --- a/conf/type/__addifnosuchline/parameter/optional +++ b/conf/type/__addifnosuchline/parameter/optional @@ -1 +1,2 @@ file +regex From 7cbc49430188836c706d0cca2970b67c701d86a1 Mon Sep 17 00:00:00 2001 From: "phrawzty (dan)" Date: Thu, 5 Jan 2012 11:13:30 +0100 Subject: [PATCH 1127/4212] Add --regex to manual --- conf/type/__addifnosuchline/man.text | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/conf/type/__addifnosuchline/man.text b/conf/type/__addifnosuchline/man.text index 722a3080..3051ff36 100644 --- a/conf/type/__addifnosuchline/man.text +++ b/conf/type/__addifnosuchline/man.text @@ -25,7 +25,9 @@ OPTIONAL PARAMETERS file:: If supplied, use this as the destination file. Otherwise the object_id is used. - +regex:: + If supplied, search for this regex. + Otherwise entire line must be matched. EXAMPLES -------- From 0f768040c2c19209ef5ce3c9bca5185a34aed5b4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Jan 2012 11:59:15 +0100 Subject: [PATCH 1128/4212] document --regexp in changes Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 81d78662..1f192304 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,5 +1,6 @@ 2.0.5: * New Type: __package_luarocks (Christian G. Warden) + * Feature: __addifnosuchline supports matching on regular expressions (dan) 2.0.4: 2011-11-18 * Bugfix core: Remove traceback when sending SIGINT (aka Ctrl-C) From 99099162577dce88429d04bbb2829f20403add4d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Jan 2012 13:41:32 +0100 Subject: [PATCH 1129/4212] add real life template example Signed-off-by: Nico Schottelius --- other/examples/types/__ethz_dinfk_ldap/README | 2 + .../files/nslcd.conf.template | 46 +++++++++++++++++++ .../__ethz_dinfk_ldap/files/nsswitch.conf | 22 +++++++++ .../examples/types/__ethz_dinfk_ldap/manifest | 39 ++++++++++++++++ .../__ethz_dinfk_ldap/parameter/required | 1 + .../types/__ethz_dinfk_ldap/singleton | 0 6 files changed, 110 insertions(+) create mode 100644 other/examples/types/__ethz_dinfk_ldap/README create mode 100755 other/examples/types/__ethz_dinfk_ldap/files/nslcd.conf.template create mode 100644 other/examples/types/__ethz_dinfk_ldap/files/nsswitch.conf create mode 100755 other/examples/types/__ethz_dinfk_ldap/manifest create mode 100644 other/examples/types/__ethz_dinfk_ldap/parameter/required create mode 100644 other/examples/types/__ethz_dinfk_ldap/singleton diff --git a/other/examples/types/__ethz_dinfk_ldap/README b/other/examples/types/__ethz_dinfk_ldap/README new file mode 100644 index 00000000..18c1574b --- /dev/null +++ b/other/examples/types/__ethz_dinfk_ldap/README @@ -0,0 +1,2 @@ +This type is used in production in the ETH and utilises a template to generate +the config file. diff --git a/other/examples/types/__ethz_dinfk_ldap/files/nslcd.conf.template b/other/examples/types/__ethz_dinfk_ldap/files/nslcd.conf.template new file mode 100755 index 00000000..d5b41c24 --- /dev/null +++ b/other/examples/types/__ethz_dinfk_ldap/files/nslcd.conf.template @@ -0,0 +1,46 @@ +#!/bin/sh +cat << DONE +# +# D-INFK SANS MANAGED FILE +# ======================== +# +# Do not change this file. Changes will be overwritten. +# + +# /etc/nslcd.conf +# nslcd configuration file. See nslcd.conf(5) +# for details. + +# The user and group nslcd should run as. +uid nslcd +gid nslcd + +# The location at which the LDAP server(s) should be reachable. +uri ldaps://ldaps01.ethz.ch +uri ldaps://ldaps02.ethz.ch +uri ldaps://ldaps03.ethz.ch + + +# The search base +base ou=${ou},ou=inf,ou=auth,o=ethz,c=ch +base passwd ou=users,ou=${ou},ou=inf,ou=auth,o=ethz,c=ch +base group ou=Group,ou=inf,ou=auth,o=ethz,c=ch +base netgroup ou=netgroup,ou=inf,ou=auth,o=ethz,c=ch + +binddn cn=REPLACE,ou=ME,ou=WITH,ou=YOUR,o=DETAILS,c=ch +bindpw VERYSECRETPASSWORD + +# The LDAP protocol version to use. +#ldap_version 3 + +# The DN to bind with for normal lookups. +#binddn cn=annonymous,dc=example,dc=net +#bindpw secret + +# SSL options +ssl on +tls_reqcert never + +# The search scope. +#scope sub +DONE diff --git a/other/examples/types/__ethz_dinfk_ldap/files/nsswitch.conf b/other/examples/types/__ethz_dinfk_ldap/files/nsswitch.conf new file mode 100644 index 00000000..f4185a86 --- /dev/null +++ b/other/examples/types/__ethz_dinfk_ldap/files/nsswitch.conf @@ -0,0 +1,22 @@ +# +# D-INFK SANS MANAGED FILE +# ======================== +# +# Do not change this file. Changes will be overwritten. +# +# /etc/nsswitch.conf +# + +passwd: files ldap +group: files ldap +shadow: files ldap + +hosts: files dns +networks: files + +services: db files +protocols: db files +rpc: db files +ethers: db files + +netgroup: files ldap diff --git a/other/examples/types/__ethz_dinfk_ldap/manifest b/other/examples/types/__ethz_dinfk_ldap/manifest new file mode 100755 index 00000000..c31d765d --- /dev/null +++ b/other/examples/types/__ethz_dinfk_ldap/manifest @@ -0,0 +1,39 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Configure nss_ldap for a machine at DINFK. +# + +ou="$(cat "$__object/parameter/ou")" + +ldap_config="/etc/nslcd.conf" +ldap_package="libnss-ldapd" + +# Install required packages +__package "$ldap_package" --state installed + +# Generate nss-ldap config file from template +mkdir "$__object/files" +. "$__type/files/nslcd.conf.template" > "$__object/files/nslcd.conf" +__file "$ldap_config" --source "$__object/files/nslcd.conf" + +# Configure nsswitch to use ldap +require="__package/$ldap_package __file/$ldap_config" \ + __file /etc/nsswitch.conf --source "$__type/files/nsswitch.conf" diff --git a/other/examples/types/__ethz_dinfk_ldap/parameter/required b/other/examples/types/__ethz_dinfk_ldap/parameter/required new file mode 100644 index 00000000..d96c19d8 --- /dev/null +++ b/other/examples/types/__ethz_dinfk_ldap/parameter/required @@ -0,0 +1 @@ +ou diff --git a/other/examples/types/__ethz_dinfk_ldap/singleton b/other/examples/types/__ethz_dinfk_ldap/singleton new file mode 100644 index 00000000..e69de29b From 2df42ebd910158bc772b18e5c8e8bd453f0156ff Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Jan 2012 14:43:35 +0100 Subject: [PATCH 1130/4212] rewrite/rephrase/check quick start section in tutorial Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-tutorial.text | 161 +++++++++++++++++-------------- 1 file changed, 91 insertions(+), 70 deletions(-) diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 65f3811c..24e665b5 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -8,9 +8,100 @@ NAME cdist-tutorial - a guided introduction into cdist +INTRODUCTION +------------ +This tutorial is aimed at people learning cdist and shows +typical approaches as well as gives an easy start into +the world of configuration management. + +This tutorial assumes you are configuring **localhost**, because +it is always available. Just replace **localhost** with your target +host for real life usage. + + + +QUICK START - GET YOUR HANDS DIRTY NOW +-------------------------------------- +For those who just want to configure a system with the +cdist configuration management and do not need (or want) +to understand everything. + +Cdist uses **ssh** for communication and transportation +and usually logs into the **target host** as the +**root** user. So you need to configure the **ssh server** +of the target host to allow root logins: Edit +the file **/etc/ssh/sshd_config** and add one of the following +lines: + +-------------------------------------------------------------------------------- +# Allow login only via public key +PermitRootLogin without-password + +# Allow login via password and public key +PermitRootLogin yes +-------------------------------------------------------------------------------- + +As cdist uses ssh intensively, it is recommended to setup authentication +with public keys: + +-------------------------------------------------------------------------------- +# Generate pubkey pair as a normal user +ssh-keygen + +# Copy pubkey over to target host +ssh-copy-id root@localhost +-------------------------------------------------------------------------------- + +Have a look at ssh-agent(1) and ssh-add(1) on how to cache the password for +your public key. Usually it looks like this: + +-------------------------------------------------------------------------------- +# Start agent and export variables +eval `ssh-agent` + +# Add keys (requires password for every identity file) +ssh-add +-------------------------------------------------------------------------------- + +At this point you should be able to ***ssh root@localhost*** without +re-entering the password. If something failed until here, ensure that +all steps went successfully and you have read and understood the +documentation. + +As soon as you are able to login without passwort to the target host, +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 +git clone git://git.schottelius.org/cdist + +# Create manifest (maps configuration to host(s) +cd cdist +echo '__file /etc/cdist-configured' > conf/manifest/init + +# Configure localhost in verbose mode +./bin/cdist config -v localhost + +# Find out that cdist created /etc/cdist-configured +ls -l /etc/cdist-configured +-------------------------------------------------------------------------------- + +That's it, you've successfully used cdist to configure your first host! +Continue reading the next sections, to understand what you did and how +to create a more sophisticated configuration. + +The file 'conf/manifest/init' is usually the entry point for cdist, +to find out what to configure on which host. All manifests are +essentially shell scripts. Every manifest can use the types known to +cdist, which are usually underline prefixed (__). + + + PREPARING YOUR MACHINE / SETUP ------------------------------ +Before you actually - ensure sshd is running on the target host: @@ -123,76 +214,6 @@ __debug:: - - -INTRODUCTION ------------- -This tutorial is aimed at people learning cdist and shows -typical approaches as well as gives an easy start into -the world of configuration management. - -This tutorial assumes you are configuring **localhost**, because -it is always available. Just repace **localhost** with your target -host for real life usage. - - - -QUICK START ------------ -For those who just want to configure a system with the -cdist configuration management and do not need (or want) -to understand everything. - -Cdist uses **ssh** for communication and transportation -and usually logs into the **target host** as the -**root** user. So you need to configure the **ssh server** -of the target host to allow root logins: Edit -the file **/etc/ssh/sshd_config** and add one of the following -lines: - --------------------------------------------------------------------------------- -# Allow login only via public key -PermitRootLogin without-password - -# Allow login via password and public key -PermitRootLogin yes --------------------------------------------------------------------------------- - -As cdist uses ssh intensively, it is recommended to setup authentication -with public keys: - --------------------------------------------------------------------------------- -# Generate pubkey pair as a normal user -ssh-keygen - -# Copy pubkey over to target host -ssh-copy-id root@localhost --------------------------------------------------------------------------------- - -As soon as you are able to login without passwort to the target host, -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 -git clone git://git.schottelius.org/cdist - -# Create manifest (maps configuration to host(s) -cd cdist -echo '__file /etc/cdist-configured' > conf/manifest/init -chmod 0700 conf/manifest/init - -# Configure localhost -./bin/cdist config localhost - -# Find out that cdist created /etc/cdist-configured -ls -l /etc/cdist-configured --------------------------------------------------------------------------------- - -The file 'conf/manifest/init' is usually the entry point for cdist, -to find out what to configure on which host. All manifests are -essentially shell scripts. Every manifest can use the types known to -cdist, which are usually underline prefixed (__). SEE ALSO From 46b23c507b22ce33869de36a7ca5b12af2089446 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Jan 2012 14:44:12 +0100 Subject: [PATCH 1131/4212] tutorial will be included in the next release Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 1f192304..7164e939 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,6 +1,7 @@ 2.0.5: * New Type: __package_luarocks (Christian G. Warden) * Feature: __addifnosuchline supports matching on regular expressions (dan) + * Documentation: (Re)write of the tutorial 2.0.4: 2011-11-18 * Bugfix core: Remove traceback when sending SIGINT (aka Ctrl-C) From f9d6ce349dacd5b2eb54ff038caa620c55a4500b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Jan 2012 17:50:50 +0100 Subject: [PATCH 1132/4212] begin section about the initial manifest Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-tutorial.text | 94 +++++--------------------------- 1 file changed, 15 insertions(+), 79 deletions(-) diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 24e665b5..91b5fdee 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -98,40 +98,20 @@ cdist, which are usually underline prefixed (__). +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. Objects are instances of +**types**, like in object orientated programming. An object is represented +by the type + slash + object name: ***__file/etc/cdist-configured*** is an +object of the type ***__file*** with the name ***etc/cdist-configured***. -PREPARING YOUR MACHINE / SETUP ------------------------------- -Before you actually - -- ensure sshd is running on the target host: - -ssh target_host - -- ensure you can login as root - -ssh root@target host - -- ensure login as root works without keys -(see ssh... manpage) - -cdist will do a lot of requests to the target -host, thus you'll have to enter your password -many times, if you don't do this :-) - -- speedup processing with ControlMaster option of -ssh +Cdist searches for the initial manifest at **conf/manifest/init** and +executes it as a shell script using **/bin/sh -e**. -YOUR FIRST CONFIGURATION ------------------------- -DEFINE STATE IN THE INITAL MANIFEST ------------------------------------ - -The initial manifest is used to map -configurations to a host. - USING SOME BASIC TYPES ---------------------- what is a type, how to use it, @@ -162,58 +142,14 @@ __debug:: +BRANCHES IN HERE? +------------ +TUNING CDIST +------------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +- speedup processing with ControlMaster option of +ssh SEE ALSO From 33763b72dd76be9c45acc97321f12c604ac77cc4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Jan 2012 18:13:25 +0100 Subject: [PATCH 1133/4212] more description on the initial manifest Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-tutorial.text | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 91b5fdee..577d633a 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -109,7 +109,35 @@ object of the type ***__file*** with the name ***etc/cdist-configured***. Cdist searches for the initial manifest at **conf/manifest/init** and executes it as a shell script using **/bin/sh -e**. +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: +-------------------------------------------------------------------------------- +__file /etc/cdist-configured + +case "$__target_host" in + localhost) + __directory /home/services/kvm-vm --parents yes + ;; +esac +-------------------------------------------------------------------------------- + +This manifest says: Independent of the host, always create the (empty) file +***/etc/cdist-configured***, but create the directory ***/home/services/kvm-vm***, +including all parent directories, only on the host ***localhost***. + +As you can see, there is no magic involved, the manifest is simple shell code that +utilises cdist types. + + +PARTS BELOW HERE ARE TO-BE-DONE + + +MORE ABOUT TYPES AND OBJECTS +---------------------------- +All available types in cdist can be called like normal executables. USING SOME BASIC TYPES From 5cd0ca6f8e43c1795aabadd39a71a472cec46baf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Jan 2012 18:13:52 +0100 Subject: [PATCH 1134/4212] big D Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 7164e939..4488c443 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,6 +1,6 @@ 2.0.5: * New Type: __package_luarocks (Christian G. Warden) - * Feature: __addifnosuchline supports matching on regular expressions (dan) + * Feature: __addifnosuchline supports matching on regular expressions (Dan) * Documentation: (Re)write of the tutorial 2.0.4: 2011-11-18 From 196a94f8cfd0fbac37160b99595c04df68390b20 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Jan 2012 18:49:37 +0100 Subject: [PATCH 1135/4212] add full name of author Signed-off-by: Nico Schottelius --- doc/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 4488c443..211cdcec 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,6 +1,7 @@ 2.0.5: * New Type: __package_luarocks (Christian G. Warden) - * Feature: __addifnosuchline supports matching on regular expressions (Dan) + * Feature: __addifnosuchline supports matching on + regular expressions (Daniel Maher) * Documentation: (Re)write of the tutorial 2.0.4: 2011-11-18 From 77350b0a1d31572331610f130195d6511a98f8b1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 6 Jan 2012 10:46:06 +0100 Subject: [PATCH 1136/4212] use pattern instead of string Signed-off-by: Steven Armstrong --- conf/type/__nfs_client/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__nfs_client/manifest b/conf/type/__nfs_client/manifest index a22f487a..1059141f 100755 --- a/conf/type/__nfs_client/manifest +++ b/conf/type/__nfs_client/manifest @@ -26,4 +26,4 @@ require="__package/nfs-common" \ require="__package/nfs-common" \ __process statd --state running \ --start "/etc/init.d/statd start" \ - --name rpc.statd + --name "rpc.statd.*" From 6fe66834fd3d5693ef92eefb74ed4ee7bf20efea Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 6 Jan 2012 10:46:32 +0100 Subject: [PATCH 1137/4212] use pattern instead of string Signed-off-by: Steven Armstrong --- conf/type/__nfs_server/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__nfs_server/manifest b/conf/type/__nfs_server/manifest index d1946b4c..780cf77a 100755 --- a/conf/type/__nfs_server/manifest +++ b/conf/type/__nfs_server/manifest @@ -25,4 +25,4 @@ __package nfs-kernel-server --state installed require="__package/nfs-kernel-server" \ __process nfs-kernel-server --state running \ --start "/etc/init.d/portmap start" \ - --name rpc.mountd + --name ".*rpc.mountd.*" From 4e4a1598b28ccee48eaa1d8dbdbfa95e0485f637 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 6 Jan 2012 10:47:51 +0100 Subject: [PATCH 1138/4212] run exportfs after changing /etc/exports, bugix: remove trailing quote Signed-off-by: Steven Armstrong --- conf/type/__nfs_export/gencode-remote | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/conf/type/__nfs_export/gencode-remote b/conf/type/__nfs_export/gencode-remote index d0e1e1a1..60b1c9a7 100755 --- a/conf/type/__nfs_export/gencode-remote +++ b/conf/type/__nfs_export/gencode-remote @@ -25,13 +25,13 @@ state_is=$(diff -q "$__object/parameter/entry" "$__object/explorer/entry" \ || echo absent ) -if [ "$exports_d" != "present" ]; then - if [ "$state_is" != "$state_should" ]; then +if [ "$state_is" != "$state_should" ]; then + if [ "$exports_d" != "present" ]; then case "$state_should" in present) - cat << DONE + cat << DONE cat >> /etc/exports << EOC -$(cat "$__object/parameter/entry")" +$(cat "$__object/parameter/entry") EOC DONE ;; @@ -59,4 +59,6 @@ DONE ;; esac fi + # re-export if we changed something + echo "exportfs -rf" fi From b67d785a24fb027e7b50daca6ad77aaf0049d958 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 6 Jan 2012 10:50:01 +0100 Subject: [PATCH 1139/4212] fix copy/paste error, use proper prefix and suffix Signed-off-by: Steven Armstrong --- conf/type/__nfs_export/explorer/entry | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/conf/type/__nfs_export/explorer/entry b/conf/type/__nfs_export/explorer/entry index 4cb10883..3922fbce 100755 --- a/conf/type/__nfs_export/explorer/entry +++ b/conf/type/__nfs_export/explorer/entry @@ -21,12 +21,11 @@ export="$(cat "$__object/parameter/export" 2>/dev/null || echo "/$__object_id")" name="$(echo "${export#/}" | sed 's;/;-;g')" -prefix="#cdist:__cron/$export" -suffix="#/cdist:__cron/$export" - if [ -f "/etc/exports.d/$name" ]; then cat "/etc/exports.d/$name" else + prefix="#cdist:__nfs_export${export}" + suffix="#/cdist:__nfs_export${export}" awk -v prefix="$prefix" -v suffix="$suffix" '{ if (index($0,prefix)) { triggered=1 From 865acf37714c12b1f93c40bd7c91729bfcc9add1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 6 Jan 2012 10:50:34 +0100 Subject: [PATCH 1140/4212] strip duplicate / Signed-off-by: Steven Armstrong --- conf/type/__nfs_export/manifest | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/type/__nfs_export/manifest b/conf/type/__nfs_export/manifest index 1a267412..d7cbd4df 100755 --- a/conf/type/__nfs_export/manifest +++ b/conf/type/__nfs_export/manifest @@ -33,8 +33,8 @@ entry="$export" entry="$entry $client" # NOTE: if changed, also change in explorers -prefix="#cdist:__nfs_export/$export" -suffix="#/cdist:__nfs_export/$export" +prefix="#cdist:__nfs_export${export}" +suffix="#/cdist:__nfs_export${export}" echo "$prefix" | tee "$__object/parameter/prefix" > "$__object/parameter/entry" echo "$entry" >> "$__object/parameter/entry" echo "$suffix" | tee "$__object/parameter/suffix" >> "$__object/parameter/entry" From e1b2b9e65f1b1fc1ff006bacb86813e198aef5bb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 6 Jan 2012 13:17:16 +0100 Subject: [PATCH 1141/4212] CentOS and XenServer are also supported by cdist Signed-off-by: Nico Schottelius --- README | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README b/README index ff1293e8..35a25099 100644 --- a/README +++ b/README @@ -61,12 +61,14 @@ cdist was tested or is know to run on at least * [Archlinux](http://www.archlinux.org/) * [Debian](http://www.debian.org/) + * [CentOS](http://www.centos.org/) * [Fedora](http://fedoraproject.org/) * [Gentoo](http://www.gentoo.org/) * [Mac OS X](http://www.apple.com/macosx/) * [OpenBSD](http://www.openbsd.org) * [Redhat](http://www.redhat.com/) * [Ubuntu](http://www.ubuntu.com/) + * [XenServer](http://www.citrix.com/xenserver/) ## Requirements From 81660b5d644f873d902142a1f18fde37983537c1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 6 Jan 2012 13:17:35 +0100 Subject: [PATCH 1142/4212] explicitly require python 3.2 on source host Signed-off-by: Nico Schottelius --- bin/cdist | 6 ++++++ doc/changelog | 1 + 2 files changed, 7 insertions(+) diff --git a/bin/cdist b/bin/cdist index 4d9cd8a2..06e82cc9 100755 --- a/bin/cdist +++ b/bin/cdist @@ -206,6 +206,12 @@ if __name__ == "__main__": import re import sys + cdistpythonversion = '3.2' + if sys.version < cdistpythonversion: + print('Cdist requires Python >= ' + cdistpythonversion + + ' on the source host.') + sys.exit(1) + # Ensure our /lib/ is included into PYTHON_PATH sys.path.insert(0, os.path.abspath( os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) diff --git a/doc/changelog b/doc/changelog index 211cdcec..3e1bed97 100644 --- a/doc/changelog +++ b/doc/changelog @@ -3,6 +3,7 @@ * Feature: __addifnosuchline supports matching on regular expressions (Daniel Maher) * Documentation: (Re)write of the tutorial + * Cleanup: Explicitly require Python >= 3.2 (do not fail implicitly) 2.0.4: 2011-11-18 * Bugfix core: Remove traceback when sending SIGINT (aka Ctrl-C) From 1a2ef4fcb0139cfbeefeb7dc708900e618ab9cfe Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 6 Jan 2012 14:39:50 +0100 Subject: [PATCH 1143/4212] python3 support in linux distros Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-01-06.python3-in-distros | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 doc/dev/logs/2012-01-06.python3-in-distros diff --git a/doc/dev/logs/2012-01-06.python3-in-distros b/doc/dev/logs/2012-01-06.python3-in-distros new file mode 100644 index 00000000..8bae04e9 --- /dev/null +++ b/doc/dev/logs/2012-01-06.python3-in-distros @@ -0,0 +1,39 @@ +Any: [supported everywhere [tm]] + Python 3.2.2 (via source) + => solution for distros with python < 3.2 + +Arch: [supported] + python 3.2.2-2 + +CentOS: [no python 3] + Python 2.6.6 + +Debian: [supported in testing] + Package python3 + squeeze (stable) (python): interactive high-level object-oriented language (default python3 version) 3.1.3-12: all + wheezy (testing) (python): interactive high-level object-oriented language (default python3 version) 3.2.2~rc1-2: all + sid (unstable) (python): interactive high-level object-oriented language (default python3 version) 3.2.2~rc1-2: all + +Fedora: [supported since 2011-05-24] + 14: python3-3.1.2-14.fc14 + 15: python3-3.2-1.fc15 + 16: python3-3.2.1-1.fc16 + 17: python3-3.2.2-8.fc17 + +OpenSuse [supported since 2011-11] + 11.4: python3-3.1.3-3.3.x86_64.rpm + 12.1: python3-3.2.1-5.1.3.x86_64.rpm + +Redhat 6: [no python 3] + See Centos 6 + +Slackware: [no python 3] + python-2.6.6-i486-1.txz + +Ubuntu: [>= natty, supported since 2011-04] + Package python3 + lucid (python): An interactive high-level object-oriented language (default python3 version) 3.1.2-0ubuntu1: all + maverick (python): interactive high-level object-oriented language (default python3 version) 3.1.3-3ubuntu5~really3.1.2: all + natty (python): interactive high-level object-oriented language (default python3 version) 3.2-1ubuntu1: all + oneiric (python): interactive high-level object-oriented language (default python3 version) 3.2.2-0ubuntu2: all + precise (python): interactive high-level object-oriented language (default python3 version) 3.2.2-0ubuntu2: all From 9de5f4c35725daa8f6bca26fadabdb8f269a6024 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 6 Jan 2012 14:52:35 +0100 Subject: [PATCH 1144/4212] +bsds +gentoo Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-01-06.python3-in-distros | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/dev/logs/2012-01-06.python3-in-distros b/doc/dev/logs/2012-01-06.python3-in-distros index 8bae04e9..81f7b844 100644 --- a/doc/dev/logs/2012-01-06.python3-in-distros +++ b/doc/dev/logs/2012-01-06.python3-in-distros @@ -20,6 +20,18 @@ Fedora: [supported since 2011-05-24] 16: python3-3.2.1-1.fc16 17: python3-3.2.2-8.fc17 +FreeBSD: + python32 - 3.2.2 + +Gentoo: + python 3.2.2 + +NetBSD: + python 3.1.4 + +OpenBSD: + python 3.2? (empty ports dir) + OpenSuse [supported since 2011-11] 11.4: python3-3.1.3-3.3.x86_64.rpm 12.1: python3-3.2.1-5.1.3.x86_64.rpm From dbf0767c4e0631364d4de909e3eb630c095a27f2 Mon Sep 17 00:00:00 2001 From: "phrawzty (dan)" Date: Fri, 6 Jan 2012 16:58:58 +0100 Subject: [PATCH 1145/4212] Add type __cdistmarker. --- conf/type/__cdistmarker/gencode-remote | 37 +++++++++++++++ conf/type/__cdistmarker/man.text | 55 ++++++++++++++++++++++ conf/type/__cdistmarker/parameter/optional | 2 + conf/type/__cdistmarker/singleton | 0 4 files changed, 94 insertions(+) create mode 100755 conf/type/__cdistmarker/gencode-remote create mode 100644 conf/type/__cdistmarker/man.text create mode 100644 conf/type/__cdistmarker/parameter/optional create mode 100644 conf/type/__cdistmarker/singleton diff --git a/conf/type/__cdistmarker/gencode-remote b/conf/type/__cdistmarker/gencode-remote new file mode 100755 index 00000000..e332df38 --- /dev/null +++ b/conf/type/__cdistmarker/gencode-remote @@ -0,0 +1,37 @@ +#!/bin/sh +# +# Copyright (C) 2011 Daniel Maher (phrawzty+cdist at gmail.com) +# +# This file is part of cdist (https://github.com/telmich/cdist/). +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# The marker file is established in the docs, but it isn't obligatory. +if [ -f "$__object/parameter/destination" ]; then + destination="$(cat "$__object/parameter/destination")" +else + destination='/etc/cdist-configured' +fi + +# The basic output of date is usually good enough, but variety is the +# spice of life... +if [ -f "$__object/parameter/format" ]; then + format="$(cat "$__object/parameter/format")" +else + format='-u' +fi + +# Dump the timestamp in UTC to the marker +echo "date $format > $destination" diff --git a/conf/type/__cdistmarker/man.text b/conf/type/__cdistmarker/man.text new file mode 100644 index 00000000..360598d8 --- /dev/null +++ b/conf/type/__cdistmarker/man.text @@ -0,0 +1,55 @@ +cdist-type__cdistmarker(7) +========================== +Daniel Maher + + +NAME +---- +cdist-type__cdistmarker - Add a timestamped cdist marker. + + +DESCRIPTION +----------- +This type is used to add a common marker file which indicates that a given +machine is being managed by cdist. The contents of this file consist of a +timestamp, which can be used to determine the most recent time at which cdist +was run against the machine in question. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +destination:: + The path and filename of the marker. + Default: /etc/cdist-configured + +format:: + The format of the timestamp. This is passed directly to system 'date'. + Default: -u + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Creates the marker as normal. +__cdistmarker + +# Creates the marker differently. +__cdistmarker --file /tmp/cdist_marker --format '+%s' +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011 Daniel Maher. Free use of this software is granted under +the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__cdistmarker/parameter/optional b/conf/type/__cdistmarker/parameter/optional new file mode 100644 index 00000000..c8e637c0 --- /dev/null +++ b/conf/type/__cdistmarker/parameter/optional @@ -0,0 +1,2 @@ +destination +format diff --git a/conf/type/__cdistmarker/singleton b/conf/type/__cdistmarker/singleton new file mode 100644 index 00000000..e69de29b From e5b3081b9f72a228e0059f126e4ca3706255becb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 10:01:44 +0100 Subject: [PATCH 1146/4212] redo commit due to broken .git repo Signed-off-by: Nico Schottelius --- README | 26 ++++++++++++++++++---- build | 6 +++++ doc/changelog | 1 + doc/dev/logs/2012-01-06.python3-in-distros | 3 ++- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/README b/README index 35a25099..46982d9f 100644 --- a/README +++ b/README @@ -90,8 +90,8 @@ cdist was tested or is know to run on at least ### Preperation -Ensure you have Python 3.x and the **argparse** module installed on -the machine you use to **deploy to the targets**. +Ensure you have Python 3.2 installed on the machine you use to **deploy to the targets** +(the ***source host***). #### Archlinux @@ -101,9 +101,27 @@ Archlinux already has python >= 3.2, so you only need to do: #### Debian - aptitude install python3 python3-setuptools - easy_install3 argparse +For Debian >= wheezy: + aptitude install python3 + +For older Debian versions, installing python 3.2 manually is required. + +#### Fedora + +For Fedora >= 15: + + yum install python3 + +#### FreeBSD + +For the port: + + cd /usr/ports/lang/python32/ && make install clean + +For the package: + + pkg_add -r python32 #### Gentoo diff --git a/build b/build index e3a6e7f9..5cc59b6d 100755 --- a/build +++ b/build @@ -97,6 +97,12 @@ case "$1" in done ;; + webmain) + cp README ${WEBPAGE} + cd ${WEBDIR} && git commit -m "cdist update" ${WEBPAGE} + cd ${WEBDIR} && make pub + ;; + web) cp README ${WEBPAGE} rm -rf ${WEBMAN} diff --git a/doc/changelog b/doc/changelog index 3e1bed97..7bea7632 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,5 +1,6 @@ 2.0.5: * New Type: __package_luarocks (Christian G. Warden) + * New Type: __cdistmarker (Daniel Maher) * Feature: __addifnosuchline supports matching on regular expressions (Daniel Maher) * Documentation: (Re)write of the tutorial diff --git a/doc/dev/logs/2012-01-06.python3-in-distros b/doc/dev/logs/2012-01-06.python3-in-distros index 81f7b844..38a4b30d 100644 --- a/doc/dev/logs/2012-01-06.python3-in-distros +++ b/doc/dev/logs/2012-01-06.python3-in-distros @@ -30,7 +30,8 @@ NetBSD: python 3.1.4 OpenBSD: - python 3.2? (empty ports dir) + 2.7.1 on -current + 2.5 & 3.2 maintained in ports OpenSuse [supported since 2011-11] 11.4: python3-3.1.3-3.3.x86_64.rpm From b8178778c80f2767ef23991cdfa90180d688831e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 10:46:29 +0100 Subject: [PATCH 1147/4212] add new README syntax for submitted, but not included types Signed-off-by: Nico Schottelius --- other/types_pending_inclusion/README | 6 ++++++ .../__init_script/{README => README.inclusion} | 0 .../__package_zypper/{README => README.inclusion} | 0 3 files changed, 6 insertions(+) create mode 100644 other/types_pending_inclusion/README rename other/types_pending_inclusion/__init_script/{README => README.inclusion} (100%) rename other/types_pending_inclusion/__package_zypper/{README => README.inclusion} (100%) diff --git a/other/types_pending_inclusion/README b/other/types_pending_inclusion/README new file mode 100644 index 00000000..b2b4972d --- /dev/null +++ b/other/types_pending_inclusion/README @@ -0,0 +1,6 @@ +The types in this directory were submitted / thought to be +included into cdist, but for some reason did not make it into +conf/type/. + +The reason for the type not being included into conf/type/ +is documented in README.inclusion. diff --git a/other/types_pending_inclusion/__init_script/README b/other/types_pending_inclusion/__init_script/README.inclusion similarity index 100% rename from other/types_pending_inclusion/__init_script/README rename to other/types_pending_inclusion/__init_script/README.inclusion diff --git a/other/types_pending_inclusion/__package_zypper/README b/other/types_pending_inclusion/__package_zypper/README.inclusion similarity index 100% rename from other/types_pending_inclusion/__package_zypper/README rename to other/types_pending_inclusion/__package_zypper/README.inclusion From ee18a30aac91c6d47adde2c47dccb4f221b1d0ab Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 10:46:58 +0100 Subject: [PATCH 1148/4212] rename type dir to more appropriate name Signed-off-by: Nico Schottelius --- .../README | 0 .../__init_script/README.inclusion | 0 .../__init_script/gencode-remote | 0 .../__init_script/man.text | 0 .../__init_script/parameter/optional | 0 .../__init_script/parameter/required | 0 .../__package_zypper/README.inclusion | 0 .../__package_zypper/explorer/pkg_version | 0 .../__package_zypper/gencode-remote | 0 .../__package_zypper/man.text | 0 .../__package_zypper/parameter/optional | 0 .../__package_zypper/parameter/required | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename other/{types_pending_inclusion => types_submitted_for_inclusion}/README (100%) rename other/{types_pending_inclusion => types_submitted_for_inclusion}/__init_script/README.inclusion (100%) rename other/{types_pending_inclusion => types_submitted_for_inclusion}/__init_script/gencode-remote (100%) rename other/{types_pending_inclusion => types_submitted_for_inclusion}/__init_script/man.text (100%) rename other/{types_pending_inclusion => types_submitted_for_inclusion}/__init_script/parameter/optional (100%) rename other/{types_pending_inclusion => types_submitted_for_inclusion}/__init_script/parameter/required (100%) rename other/{types_pending_inclusion => types_submitted_for_inclusion}/__package_zypper/README.inclusion (100%) rename other/{types_pending_inclusion => types_submitted_for_inclusion}/__package_zypper/explorer/pkg_version (100%) rename other/{types_pending_inclusion => types_submitted_for_inclusion}/__package_zypper/gencode-remote (100%) rename other/{types_pending_inclusion => types_submitted_for_inclusion}/__package_zypper/man.text (100%) rename other/{types_pending_inclusion => types_submitted_for_inclusion}/__package_zypper/parameter/optional (100%) rename other/{types_pending_inclusion => types_submitted_for_inclusion}/__package_zypper/parameter/required (100%) diff --git a/other/types_pending_inclusion/README b/other/types_submitted_for_inclusion/README similarity index 100% rename from other/types_pending_inclusion/README rename to other/types_submitted_for_inclusion/README diff --git a/other/types_pending_inclusion/__init_script/README.inclusion b/other/types_submitted_for_inclusion/__init_script/README.inclusion similarity index 100% rename from other/types_pending_inclusion/__init_script/README.inclusion rename to other/types_submitted_for_inclusion/__init_script/README.inclusion diff --git a/other/types_pending_inclusion/__init_script/gencode-remote b/other/types_submitted_for_inclusion/__init_script/gencode-remote similarity index 100% rename from other/types_pending_inclusion/__init_script/gencode-remote rename to other/types_submitted_for_inclusion/__init_script/gencode-remote diff --git a/other/types_pending_inclusion/__init_script/man.text b/other/types_submitted_for_inclusion/__init_script/man.text similarity index 100% rename from other/types_pending_inclusion/__init_script/man.text rename to other/types_submitted_for_inclusion/__init_script/man.text diff --git a/other/types_pending_inclusion/__init_script/parameter/optional b/other/types_submitted_for_inclusion/__init_script/parameter/optional similarity index 100% rename from other/types_pending_inclusion/__init_script/parameter/optional rename to other/types_submitted_for_inclusion/__init_script/parameter/optional diff --git a/other/types_pending_inclusion/__init_script/parameter/required b/other/types_submitted_for_inclusion/__init_script/parameter/required similarity index 100% rename from other/types_pending_inclusion/__init_script/parameter/required rename to other/types_submitted_for_inclusion/__init_script/parameter/required diff --git a/other/types_pending_inclusion/__package_zypper/README.inclusion b/other/types_submitted_for_inclusion/__package_zypper/README.inclusion similarity index 100% rename from other/types_pending_inclusion/__package_zypper/README.inclusion rename to other/types_submitted_for_inclusion/__package_zypper/README.inclusion diff --git a/other/types_pending_inclusion/__package_zypper/explorer/pkg_version b/other/types_submitted_for_inclusion/__package_zypper/explorer/pkg_version similarity index 100% rename from other/types_pending_inclusion/__package_zypper/explorer/pkg_version rename to other/types_submitted_for_inclusion/__package_zypper/explorer/pkg_version diff --git a/other/types_pending_inclusion/__package_zypper/gencode-remote b/other/types_submitted_for_inclusion/__package_zypper/gencode-remote similarity index 100% rename from other/types_pending_inclusion/__package_zypper/gencode-remote rename to other/types_submitted_for_inclusion/__package_zypper/gencode-remote diff --git a/other/types_pending_inclusion/__package_zypper/man.text b/other/types_submitted_for_inclusion/__package_zypper/man.text similarity index 100% rename from other/types_pending_inclusion/__package_zypper/man.text rename to other/types_submitted_for_inclusion/__package_zypper/man.text diff --git a/other/types_pending_inclusion/__package_zypper/parameter/optional b/other/types_submitted_for_inclusion/__package_zypper/parameter/optional similarity index 100% rename from other/types_pending_inclusion/__package_zypper/parameter/optional rename to other/types_submitted_for_inclusion/__package_zypper/parameter/optional diff --git a/other/types_pending_inclusion/__package_zypper/parameter/required b/other/types_submitted_for_inclusion/__package_zypper/parameter/required similarity index 100% rename from other/types_pending_inclusion/__package_zypper/parameter/required rename to other/types_submitted_for_inclusion/__package_zypper/parameter/required From 2e61f54c111d9218116d6142f530f799cd70587f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 9 Jan 2012 10:51:53 +0100 Subject: [PATCH 1149/4212] import latest changes from private repo Signed-off-by: Steven Armstrong --- conf/type/__directory/gencode-remote | 6 ------ conf/type/__directory/manifest | 8 +++----- conf/type/__file/gencode-local | 6 +----- conf/type/__file/manifest | 8 +++----- conf/type/__link/manifest | 8 +++----- 5 files changed, 10 insertions(+), 26 deletions(-) diff --git a/conf/type/__directory/gencode-remote b/conf/type/__directory/gencode-remote index 7fd589be..e9feecf4 100755 --- a/conf/type/__directory/gencode-remote +++ b/conf/type/__directory/gencode-remote @@ -17,12 +17,6 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# -# Handle directories -# -# -# __directory /etc [--mode --owner --group --parents [yes|no] ] -# destination="/$__object_id" state_should="$(cat "$__object/parameter/state")" diff --git a/conf/type/__directory/manifest b/conf/type/__directory/manifest index 2fcc085d..a8ee5a6f 100755 --- a/conf/type/__directory/manifest +++ b/conf/type/__directory/manifest @@ -18,8 +18,6 @@ # along with cdist. If not, see . # -if [ -f "$__object/parameter/state" ]; then - state="$(cat "$__object/parameter/state")" -else - echo "present" > "$__object/parameter/state" -fi +# set defaults +state="$(cat "$__object/parameter/state" 2>/dev/null \ + || echo "present" | tee "$__object/parameter/state")" diff --git a/conf/type/__file/gencode-local b/conf/type/__file/gencode-local index ee198fb1..d9839a19 100755 --- a/conf/type/__file/gencode-local +++ b/conf/type/__file/gencode-local @@ -33,11 +33,7 @@ if [ "$state_should" = "present" ]; then remote_cksum="$(cat "$__object/explorer/cksum")" if [ "$local_cksum" != "$remote_cksum" ]; then - # FIXME: The username is ugly and hardcoded, replace after 1.0! - # Probably a better aproach is to have the user configured - # ~/.ssh/config to contain the right username - # Probably describe it in cdist-quickstart... - echo scp "$source" "root@${__target_host}:${destination}" + echo "$__remote_copy" "$source" "${__target_host}:${destination}" fi else echo "Source \"$source\" does not exist." >&2 diff --git a/conf/type/__file/manifest b/conf/type/__file/manifest index 59f10e42..915a2ca9 100755 --- a/conf/type/__file/manifest +++ b/conf/type/__file/manifest @@ -20,8 +20,6 @@ name="$__object_id" -if [ -f "$__object/parameter/state" ]; then - state="$(cat "$__object/parameter/state")" -else - echo "present" > "$__object/parameter/state" -fi +# set defaults +state="$(cat "$__object/parameter/state" 2>/dev/null \ + || echo "present" | tee "$__object/parameter/state")" diff --git a/conf/type/__link/manifest b/conf/type/__link/manifest index 2fcc085d..a8ee5a6f 100755 --- a/conf/type/__link/manifest +++ b/conf/type/__link/manifest @@ -18,8 +18,6 @@ # along with cdist. If not, see . # -if [ -f "$__object/parameter/state" ]; then - state="$(cat "$__object/parameter/state")" -else - echo "present" > "$__object/parameter/state" -fi +# set defaults +state="$(cat "$__object/parameter/state" 2>/dev/null \ + || echo "present" | tee "$__object/parameter/state")" From 283b5eff6e6fe11b94b9abf696495a017b8b8fd5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 11:53:22 +0100 Subject: [PATCH 1150/4212] include __nfs_* into types_submitted_for_inclusion Signed-off-by: Nico Schottelius --- .../.readmes/README.inclusion.specific | 18 ++++++++++++++++++ .../__nfs_client/README.inclusion | 1 + .../__nfs_client/man.text | 0 .../__nfs_client/manifest | 0 .../__nfs_client/singleton | 0 .../__nfs_export/README.inclusion | 1 + .../__nfs_export/explorer/entry | 0 .../__nfs_export/explorer/exports.d | 0 .../__nfs_export/gencode-remote | 0 .../__nfs_export/man.text | 0 .../__nfs_export/manifest | 0 .../__nfs_export/parameter/optional | 0 .../__nfs_export/parameter/required | 0 .../__nfs_server/README.inclusion | 1 + .../__nfs_server/man.text | 0 .../__nfs_server/manifest | 0 .../__nfs_server/singleton | 0 17 files changed, 21 insertions(+) create mode 100644 other/types_submitted_for_inclusion/.readmes/README.inclusion.specific create mode 120000 other/types_submitted_for_inclusion/__nfs_client/README.inclusion rename {conf/type => other/types_submitted_for_inclusion}/__nfs_client/man.text (100%) rename {conf/type => other/types_submitted_for_inclusion}/__nfs_client/manifest (100%) rename {conf/type => other/types_submitted_for_inclusion}/__nfs_client/singleton (100%) create mode 120000 other/types_submitted_for_inclusion/__nfs_export/README.inclusion rename {conf/type => other/types_submitted_for_inclusion}/__nfs_export/explorer/entry (100%) rename {conf/type => other/types_submitted_for_inclusion}/__nfs_export/explorer/exports.d (100%) rename {conf/type => other/types_submitted_for_inclusion}/__nfs_export/gencode-remote (100%) rename {conf/type => other/types_submitted_for_inclusion}/__nfs_export/man.text (100%) rename {conf/type => other/types_submitted_for_inclusion}/__nfs_export/manifest (100%) rename {conf/type => other/types_submitted_for_inclusion}/__nfs_export/parameter/optional (100%) rename {conf/type => other/types_submitted_for_inclusion}/__nfs_export/parameter/required (100%) create mode 120000 other/types_submitted_for_inclusion/__nfs_server/README.inclusion rename {conf/type => other/types_submitted_for_inclusion}/__nfs_server/man.text (100%) rename {conf/type => other/types_submitted_for_inclusion}/__nfs_server/manifest (100%) rename {conf/type => other/types_submitted_for_inclusion}/__nfs_server/singleton (100%) diff --git a/other/types_submitted_for_inclusion/.readmes/README.inclusion.specific b/other/types_submitted_for_inclusion/.readmes/README.inclusion.specific new file mode 100644 index 00000000..0a1eb22e --- /dev/null +++ b/other/types_submitted_for_inclusion/.readmes/README.inclusion.specific @@ -0,0 +1,18 @@ +Description: + + Type that will probably only work in a very specific environnment + (like a specific distribution only). + +Problem: + + If included into core/ directory, many users would be disappointed, + because it does not work for them out of the box. + +Solutions: + + - Make visible for others (done: by integrating into other/types_submitted_for_inclusion) + - Improve: make usable for at least 80% of the standard cases + + or + + - Modify for yourself and use it diff --git a/other/types_submitted_for_inclusion/__nfs_client/README.inclusion b/other/types_submitted_for_inclusion/__nfs_client/README.inclusion new file mode 120000 index 00000000..573e1f5f --- /dev/null +++ b/other/types_submitted_for_inclusion/__nfs_client/README.inclusion @@ -0,0 +1 @@ +../.readmes/README.inclusion.specific \ No newline at end of file diff --git a/conf/type/__nfs_client/man.text b/other/types_submitted_for_inclusion/__nfs_client/man.text similarity index 100% rename from conf/type/__nfs_client/man.text rename to other/types_submitted_for_inclusion/__nfs_client/man.text diff --git a/conf/type/__nfs_client/manifest b/other/types_submitted_for_inclusion/__nfs_client/manifest similarity index 100% rename from conf/type/__nfs_client/manifest rename to other/types_submitted_for_inclusion/__nfs_client/manifest diff --git a/conf/type/__nfs_client/singleton b/other/types_submitted_for_inclusion/__nfs_client/singleton similarity index 100% rename from conf/type/__nfs_client/singleton rename to other/types_submitted_for_inclusion/__nfs_client/singleton diff --git a/other/types_submitted_for_inclusion/__nfs_export/README.inclusion b/other/types_submitted_for_inclusion/__nfs_export/README.inclusion new file mode 120000 index 00000000..52517640 --- /dev/null +++ b/other/types_submitted_for_inclusion/__nfs_export/README.inclusion @@ -0,0 +1 @@ +../.readmes/README.inclusion.dependent \ No newline at end of file diff --git a/conf/type/__nfs_export/explorer/entry b/other/types_submitted_for_inclusion/__nfs_export/explorer/entry similarity index 100% rename from conf/type/__nfs_export/explorer/entry rename to other/types_submitted_for_inclusion/__nfs_export/explorer/entry diff --git a/conf/type/__nfs_export/explorer/exports.d b/other/types_submitted_for_inclusion/__nfs_export/explorer/exports.d similarity index 100% rename from conf/type/__nfs_export/explorer/exports.d rename to other/types_submitted_for_inclusion/__nfs_export/explorer/exports.d diff --git a/conf/type/__nfs_export/gencode-remote b/other/types_submitted_for_inclusion/__nfs_export/gencode-remote similarity index 100% rename from conf/type/__nfs_export/gencode-remote rename to other/types_submitted_for_inclusion/__nfs_export/gencode-remote diff --git a/conf/type/__nfs_export/man.text b/other/types_submitted_for_inclusion/__nfs_export/man.text similarity index 100% rename from conf/type/__nfs_export/man.text rename to other/types_submitted_for_inclusion/__nfs_export/man.text diff --git a/conf/type/__nfs_export/manifest b/other/types_submitted_for_inclusion/__nfs_export/manifest similarity index 100% rename from conf/type/__nfs_export/manifest rename to other/types_submitted_for_inclusion/__nfs_export/manifest diff --git a/conf/type/__nfs_export/parameter/optional b/other/types_submitted_for_inclusion/__nfs_export/parameter/optional similarity index 100% rename from conf/type/__nfs_export/parameter/optional rename to other/types_submitted_for_inclusion/__nfs_export/parameter/optional diff --git a/conf/type/__nfs_export/parameter/required b/other/types_submitted_for_inclusion/__nfs_export/parameter/required similarity index 100% rename from conf/type/__nfs_export/parameter/required rename to other/types_submitted_for_inclusion/__nfs_export/parameter/required diff --git a/other/types_submitted_for_inclusion/__nfs_server/README.inclusion b/other/types_submitted_for_inclusion/__nfs_server/README.inclusion new file mode 120000 index 00000000..573e1f5f --- /dev/null +++ b/other/types_submitted_for_inclusion/__nfs_server/README.inclusion @@ -0,0 +1 @@ +../.readmes/README.inclusion.specific \ No newline at end of file diff --git a/conf/type/__nfs_server/man.text b/other/types_submitted_for_inclusion/__nfs_server/man.text similarity index 100% rename from conf/type/__nfs_server/man.text rename to other/types_submitted_for_inclusion/__nfs_server/man.text diff --git a/conf/type/__nfs_server/manifest b/other/types_submitted_for_inclusion/__nfs_server/manifest similarity index 100% rename from conf/type/__nfs_server/manifest rename to other/types_submitted_for_inclusion/__nfs_server/manifest diff --git a/conf/type/__nfs_server/singleton b/other/types_submitted_for_inclusion/__nfs_server/singleton similarity index 100% rename from conf/type/__nfs_server/singleton rename to other/types_submitted_for_inclusion/__nfs_server/singleton From 351a6521b0066e9b95a926ffbda402835d9331ee Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 12:22:38 +0100 Subject: [PATCH 1151/4212] +another generic readme Signed-off-by: Nico Schottelius --- .../.readmes/README.inclusion.dependent | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 other/types_submitted_for_inclusion/.readmes/README.inclusion.dependent diff --git a/other/types_submitted_for_inclusion/.readmes/README.inclusion.dependent b/other/types_submitted_for_inclusion/.readmes/README.inclusion.dependent new file mode 100644 index 00000000..b62c1a15 --- /dev/null +++ b/other/types_submitted_for_inclusion/.readmes/README.inclusion.dependent @@ -0,0 +1,15 @@ +Description: + + Type that depends on other types to be included. + +Problem: + + Does not make much sense on its own. + +Solutions: + + - Make dependent types includable. + + or + + - Modify for yourself and use it From cf58e8263d34131c3189d2043ac76ae461af5678 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 12:25:24 +0100 Subject: [PATCH 1152/4212] add old logfile from startup / yannick Signed-off-by: Nico Schottelius --- doc/dev/logs/2011-11-15.startup-yannick | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 doc/dev/logs/2011-11-15.startup-yannick diff --git a/doc/dev/logs/2011-11-15.startup-yannick b/doc/dev/logs/2011-11-15.startup-yannick new file mode 100644 index 00000000..e4a28587 --- /dev/null +++ b/doc/dev/logs/2011-11-15.startup-yannick @@ -0,0 +1,9 @@ +- create new branch +- entry point = conf/manifest/init +- make man for reference +- doc: change to version directory + +- add sudo example +- ports are configured in ~/.ssh/config +- cdist daustrap $rechner + - alles gut mit enimal passwort eingeben From 740fca84e5dd3cfd0a39966498ae2b46a244c906 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 12:26:03 +0100 Subject: [PATCH 1153/4212] +another news url Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-01-07.urls | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/dev/logs/2012-01-07.urls diff --git a/doc/dev/logs/2012-01-07.urls b/doc/dev/logs/2012-01-07.urls new file mode 100644 index 00000000..9139c3ce --- /dev/null +++ b/doc/dev/logs/2012-01-07.urls @@ -0,0 +1 @@ +https://news.ycombinator.com/item?id=3422678 From 7d0671e5290539362f9796f7176232c9aa69d13a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 15:26:49 +0100 Subject: [PATCH 1154/4212] force removal - to not trigger rm -i behaviour in type Signed-off-by: Nico Schottelius --- conf/type/__directory/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__directory/gencode-remote b/conf/type/__directory/gencode-remote index e9feecf4..19591266 100755 --- a/conf/type/__directory/gencode-remote +++ b/conf/type/__directory/gencode-remote @@ -62,7 +62,7 @@ case "$state_should" in absent) # Only delete if it exists if [ yes = "$(cat "$__object/explorer/exists")" ]; then - echo rm -r \"$destination\" + echo rm -rf \"$destination\" fi ;; From c1dc33a5a132445e4f7abbdd9cbecca9bd6eb692 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 15:27:11 +0100 Subject: [PATCH 1155/4212] display unknown state, be nice to the user Signed-off-by: Nico Schottelius --- conf/type/__directory/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__directory/gencode-remote b/conf/type/__directory/gencode-remote index 19591266..49ab789f 100755 --- a/conf/type/__directory/gencode-remote +++ b/conf/type/__directory/gencode-remote @@ -67,7 +67,7 @@ case "$state_should" in ;; *) - echo "Unknown state" >&2 + echo "Unknown state: $state_should" >&2 exit 1 ;; esac From 839986604d05f53af860ed60c18a84b42b80523e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 15:28:18 +0100 Subject: [PATCH 1156/4212] document new features in __directory, __file, __link Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index 7bea7632..b9c5cad7 100644 --- a/doc/changelog +++ b/doc/changelog @@ -5,6 +5,8 @@ regular expressions (Daniel Maher) * Documentation: (Re)write of the tutorial * Cleanup: Explicitly require Python >= 3.2 (do not fail implicitly) + * Feature: __directory, __file, __link: + Add --state parameter (Steven Armstrong) 2.0.4: 2011-11-18 * Bugfix core: Remove traceback when sending SIGINT (aka Ctrl-C) From f1273aa7a19de93f6d97c293ff8fbe7d0e20af25 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 15:29:17 +0100 Subject: [PATCH 1157/4212] --state not --ensure [DOC BUG] Signed-off-by: Nico Schottelius --- conf/type/__directory/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__directory/man.text b/conf/type/__directory/man.text index 315d1fb9..afba0875 100644 --- a/conf/type/__directory/man.text +++ b/conf/type/__directory/man.text @@ -49,7 +49,7 @@ EXAMPLES __directory /tmp/foobar # Remove a directory -__directory /tmp/foobar --ensure absent +__directory /tmp/foobar --state absent # Ensure /etc exists correctly __directory /etc --owner root --group root --mode 0755 From 8320327956e794068b1158f71282c8b50dc5a2de Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 15:37:16 +0100 Subject: [PATCH 1158/4212] rephrase if..elif..else to case..esac Signed-off-by: Nico Schottelius --- conf/type/__file/gencode-remote | 58 ++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/conf/type/__file/gencode-remote b/conf/type/__file/gencode-remote index ef42dd54..aedae218 100755 --- a/conf/type/__file/gencode-remote +++ b/conf/type/__file/gencode-remote @@ -25,30 +25,42 @@ destination="/$__object_id" state_should="$(cat "$__object/parameter/state")" exists="$(cat "$__object/explorer/exists")" -if [ "$state_should" = "present" ]; then - # No source? Create empty file - if [ ! -f "$__object/parameter/source" ]; then - if [ "$exists" = "no" ]; then - echo touch \"$destination\" +case "$state_should" in + present) + # No source? Create empty file + if [ ! -f "$__object/parameter/source" ]; then + if [ "$exists" = "no" ]; then + echo touch \"$destination\" + fi + fi + + # Mode settings + if [ -f "$__object/parameter/mode" ]; then + echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" fi - fi - # Mode settings - if [ -f "$__object/parameter/mode" ]; then - echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" - fi + # Group + if [ -f "$__object/parameter/group" ]; then + echo chgrp \"$(cat "$__object/parameter/group")\" \"$destination\" + 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 + ;; - # Owner - if [ -f "$__object/parameter/owner" ]; then - echo chown \"$(cat "$__object/parameter/owner")\" \"$destination\" - fi -elif [ "$state_should" = "absent" ]; then - if [ "$exists" = "yes" ]; then - echo rm -f \"$destination\" - fi -fi + absent) + + if [ "$exists" = "yes" ]; then + echo rm -f \"$destination\" + fi + + ;; + + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; + +esac From 228eb600bf33d60361955290a7fded938c2d8ff9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 15:40:05 +0100 Subject: [PATCH 1159/4212] simplify default value code a lot Signed-off-by: Nico Schottelius --- conf/type/__file/manifest | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/conf/type/__file/manifest b/conf/type/__file/manifest index 915a2ca9..6b5e1ca7 100755 --- a/conf/type/__file/manifest +++ b/conf/type/__file/manifest @@ -1,6 +1,7 @@ #!/bin/sh # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,8 +19,6 @@ # along with cdist. If not, see . # -name="$__object_id" - -# set defaults -state="$(cat "$__object/parameter/state" 2>/dev/null \ - || echo "present" | tee "$__object/parameter/state")" +# set default: present, if not setup +statefile="$__object/parameter/state" +[ -f "$statefile" ] || echo present > "$statefile" From 1092103500e0d41aa3fab5c1a86af0c1cbe6bbcf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 15:41:15 +0100 Subject: [PATCH 1160/4212] fix --ensure vs. --state bug [DOC] Signed-off-by: Nico Schottelius --- conf/type/__file/man.text | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/conf/type/__file/man.text b/conf/type/__file/man.text index fa6b7644..c787c930 100644 --- a/conf/type/__file/man.text +++ b/conf/type/__file/man.text @@ -44,17 +44,17 @@ EXAMPLES # Create /etc/cdist-configured as an empty file __file /etc/cdist-configured # The same thing -__file /etc/cdist-configured --ensure present +__file /etc/cdist-configured --state present # Delete existing file -__file /etc/cdist-configured --ensure absent +__file /etc/cdist-configured --state absent # Use __file from another type -__file /etc/issue --source "$__type/files/archlinux" --ensure present +__file /etc/issue --source "$__type/files/archlinux" --state present # Supply some more settings __file /etc/shadow --source "$__type/files/shadow" \ --owner root --group shadow --mode 0640 \ - --ensure present + --state present -------------------------------------------------------------------------------- @@ -65,5 +65,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is +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 7cc9b217daf336a6a154adef069465a756df5606 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 15:43:12 +0100 Subject: [PATCH 1161/4212] display wrong state to the user (__link) Signed-off-by: Nico Schottelius --- conf/type/__link/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__link/gencode-remote b/conf/type/__link/gencode-remote index bb43de2e..ca324902 100755 --- a/conf/type/__link/gencode-remote +++ b/conf/type/__link/gencode-remote @@ -48,7 +48,7 @@ case "$state_should" in echo rm -f \"$destination\" ;; *) - echo "Unknown state" >&2 + echo "Unknown state: $state_should" >&2 exit 1 ;; esac From a55dd390b1b4f6d7284c9ec3fc5277c76150791f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 15:46:24 +0100 Subject: [PATCH 1162/4212] simplify default value setting Signed-off-by: Nico Schottelius --- conf/type/__link/manifest | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/conf/type/__link/manifest b/conf/type/__link/manifest index a8ee5a6f..6b5e1ca7 100755 --- a/conf/type/__link/manifest +++ b/conf/type/__link/manifest @@ -1,6 +1,7 @@ #!/bin/sh # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,6 +19,6 @@ # along with cdist. If not, see . # -# set defaults -state="$(cat "$__object/parameter/state" 2>/dev/null \ - || echo "present" | tee "$__object/parameter/state")" +# set default: present, if not setup +statefile="$__object/parameter/state" +[ -f "$statefile" ] || echo present > "$statefile" From 0d04f0ba34612c61669623a6b2537f5275808d70 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 15:46:35 +0100 Subject: [PATCH 1163/4212] correct documentation Signed-off-by: Nico Schottelius --- conf/type/__link/gencode-remote | 1 - conf/type/__link/man.text | 11 +++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/conf/type/__link/gencode-remote b/conf/type/__link/gencode-remote index ca324902..0a367654 100755 --- a/conf/type/__link/gencode-remote +++ b/conf/type/__link/gencode-remote @@ -52,4 +52,3 @@ case "$state_should" in exit 1 ;; esac - diff --git a/conf/type/__link/man.text b/conf/type/__link/man.text index a7d33c59..663087db 100644 --- a/conf/type/__link/man.text +++ b/conf/type/__link/man.text @@ -5,13 +5,13 @@ Nico Schottelius NAME ---- -cdist-type__link - Create links +cdist-type__link - Manage links (hard and symbolic) DESCRIPTION ----------- -This cdist type allows you to hard and symoblic links. The given -object id is the destination for the link. +This cdist type allows you to manage hard and symbolic links. +The given object id is the destination for the link. REQUIRED PARAMETERS @@ -43,6 +43,9 @@ __link /etc/apache2/sites-enabled/www.test.ch \ # Absolute symbolic link __link /opt/plone --source /home/services/plone --type symbolic + +# Remove link +__link /opt/plone --state absent -------------------------------------------------------------------------------- @@ -53,5 +56,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is +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 c2c8e5f83924c2e8be16f300dff3b8d5d4e7e036 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 15:52:47 +0100 Subject: [PATCH 1164/4212] remove obsolete cdist(7) manpage Signed-off-by: Nico Schottelius --- doc/man/man7/cdist.text | 48 ----------------------------------------- 1 file changed, 48 deletions(-) delete mode 100644 doc/man/man7/cdist.text diff --git a/doc/man/man7/cdist.text b/doc/man/man7/cdist.text deleted file mode 100644 index 2a5d1fe5..00000000 --- a/doc/man/man7/cdist.text +++ /dev/null @@ -1,48 +0,0 @@ -cdist(7) -======== -Nico Schottelius - - -NAME ----- -cdist - Configuration management system - - -DESCRIPTION ------------ -Cdist is a usable configuration management system. -The easiest way to get started with cdist is to initialise -the environment and run cdist-quickstart: - --------------------------------------------------------------------------------- -eval `./bin/cdist-env` && cdist-quickstart --------------------------------------------------------------------------------- - -Cdist configurations are written in the shell scripting language. -The mapping of configurations to hosts is defined in so called manifests, -logical units of functionality are called "types" in cdist jargon. -Cdist ships with some types included. You can use or change them, create new -ones or even submit your types for inclusion into cdist. - -The main command is cdist-deploy-to, which runs several stages to push -configurations to a host. If you want to deeply understand cdist, reading -the source of cdist-deploy-to is recommended. -Cdist currently uses the push approach (a server pushes out the -configuration to the clients), but future version will also support the -pull mechanism (client requests configuration). - - -SEE ALSO --------- -- Website: http://www.nico.schottelius.org/software/cdist/[] -- cdist-hacker(7) -- cdist-manifest(7) -- cdist-type(7) -- cdist(1) -- cdist(7) - - -COPYING -------- -Copyright \(C) 2010-2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). From e0708b0e8fff3155d5741acd07bbcd89a40881cb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 16:05:13 +0100 Subject: [PATCH 1165/4212] add a bug note Signed-off-by: Nico Schottelius --- doc/dev/todo/BUGS | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 doc/dev/todo/BUGS diff --git a/doc/dev/todo/BUGS b/doc/dev/todo/BUGS new file mode 100644 index 00000000..80fc6232 --- /dev/null +++ b/doc/dev/todo/BUGS @@ -0,0 +1,7 @@ +Stuff that needs to repaired very soon as they may cause frustration... + +__process / name bug: + __process /usr/lib/postfix/master --start "/etc/rc.d/postfix start" --state running + => name="usr/lib/postfix/master" + => breaks! + => cannot detect if ^/ is needed or not automatically From 0b2a5cd4a16061375fbc725164e2549432e22364 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 16:07:50 +0100 Subject: [PATCH 1166/4212] --stuff todo Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index be76b040..701478e0 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -43,9 +43,6 @@ USER INTERFACE TYPES ------ - __ssh-keys (host/user) -- __file_edit - - regexp replace (can probably cover all?) - -> aka sed. - __user add option to include --create-home From b463fa6bf9f8445fad9948be4b15b691e51b07de Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 16:25:32 +0100 Subject: [PATCH 1167/4212] merge and cleanup todos Signed-off-by: Nico Schottelius --- doc/dev/todo/BUGS | 7 ------- doc/dev/todo/TAKEME | 25 +++++++++++-------------- doc/dev/todo/install | 8 -------- doc/dev/todo/niconext | 27 --------------------------- 4 files changed, 11 insertions(+), 56 deletions(-) delete mode 100644 doc/dev/todo/BUGS delete mode 100644 doc/dev/todo/install diff --git a/doc/dev/todo/BUGS b/doc/dev/todo/BUGS deleted file mode 100644 index 80fc6232..00000000 --- a/doc/dev/todo/BUGS +++ /dev/null @@ -1,7 +0,0 @@ -Stuff that needs to repaired very soon as they may cause frustration... - -__process / name bug: - __process /usr/lib/postfix/master --start "/etc/rc.d/postfix start" --state running - => name="usr/lib/postfix/master" - => breaks! - => cannot detect if ^/ is needed or not automatically diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 701478e0..d6bd81a3 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -3,10 +3,17 @@ UNASSIGNED TODOS The following list of todos has not been assigned to any developer. Feel free to pick one! -CORE + +BUGS ---- -- Add subcommand to create template of a type with working manpage - (cdist type-template or so) + +Stuff that needs to repaired very soon as they may cause frustration... + +__process / name bug: + __process /usr/lib/postfix/master --start "/etc/rc.d/postfix start" --state running + => name="usr/lib/postfix/master" + => breaks! + => cannot detect if ^/ is needed or not automatically TESTS ----- @@ -20,11 +27,8 @@ TESTS USER INTERFACE -------------- -- add support $__tmp? - - for use in manifest, code, etc.? - - for creating temporary files, etc. - - How to cleanly implement "restart service if config file changed" + -> document - Cache - add example how to use @@ -42,12 +46,5 @@ USER INTERFACE TYPES ------ -- __ssh-keys (host/user) - __user add option to include --create-home - -DOCUMENTATION --------------- -- asciidoc interprets __, which we use for variables - names -> seek through docs and replace with \_\_! -- reference explorers in cdist-reference! diff --git a/doc/dev/todo/install b/doc/dev/todo/install deleted file mode 100644 index f0e7a040..00000000 --- a/doc/dev/todo/install +++ /dev/null @@ -1,8 +0,0 @@ -missing types: - __bootloader - __taball_get - __mount - __mount-point-create - __fstab - - run user postinstall script - - for e.g. reboot, chroot && start sshd diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index f8c2d6da..66e1baee 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -297,32 +297,5 @@ pointers on where to continue to read: eof -------------------------------------------------------------------------------- -- Initial install support - - setup $__install = "yes" for - manifest(s), gencode-* - - - run standard manifest (?) - - creates initial objects - - only those having the installer flag? - - requires changegs to cdist-type-emulator! - - Goto Rewrite cdist-type-emulator - - - run all other manifests - - creates all objects - - what about type explorer? - - do not run, create empty output (types should be able - to handle this!) - via __global/ - -- Support parallel execution - - error handling / report failed hosts - - Create new video for cdist 2.0.0 http://www.youtube.com/watch?v=PRMjzy48eTI - -- Setup __debug, if -d is given, so other tools can reuse it - - implement everywhere to external! - -- remote_prefix: - scp vs. ssh issue -locale_type From 5bcb807ebd1aacbb9a3388a98faa90be489d1d95 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 16:29:28 +0100 Subject: [PATCH 1168/4212] update year Signed-off-by: Nico Schottelius --- doc/man/cdist-reference.text.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 0a7b551e..12f30d7f 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -45,7 +45,7 @@ cdist-reference - Variable, path and type reference for cdist EXPLORERS --------- -The following global explores are available: +The following global explorers are available: eof ( @@ -203,6 +203,6 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is +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). eof From 3818548d9aaec02b67875177c481107e5f94f063 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 16:30:52 +0100 Subject: [PATCH 1169/4212] find conf/type -type f -exec sed -i 's/ *$//' {} \; Signed-off-by: Nico Schottelius --- conf/type/__apt_ppa/man.text | 2 +- conf/type/__directory/gencode-remote | 4 ++-- conf/type/__file/gencode-remote | 4 ++-- conf/type/__file/man.text | 2 +- conf/type/__group/gencode-remote | 2 +- conf/type/__key_value/gencode-remote | 2 +- conf/type/__key_value/man.text | 2 +- conf/type/__package/man.text | 2 +- conf/type/__package_pkg_openbsd/gencode-remote | 2 +- conf/type/__package_pkg_openbsd/man.text | 2 +- conf/type/__partition_msdos_apply/gencode-remote | 2 +- conf/type/__postgres_role/man.text | 4 ++-- conf/type/__timezone/man.text | 2 +- conf/type/__user/explorer/group | 2 +- conf/type/__user/gencode-remote | 2 +- 15 files changed, 18 insertions(+), 18 deletions(-) diff --git a/conf/type/__apt_ppa/man.text b/conf/type/__apt_ppa/man.text index 5423a1a2..f986eb2d 100644 --- a/conf/type/__apt_ppa/man.text +++ b/conf/type/__apt_ppa/man.text @@ -17,7 +17,7 @@ REQUIRED PARAMETERS ------------------- state:: The state the ppa should be in, either "enabled" or "disabled". - + OPTIONAL PARAMETERS ------------------- diff --git a/conf/type/__directory/gencode-remote b/conf/type/__directory/gencode-remote index 49ab789f..e871547a 100755 --- a/conf/type/__directory/gencode-remote +++ b/conf/type/__directory/gencode-remote @@ -65,8 +65,8 @@ case "$state_should" in echo rm -rf \"$destination\" fi - ;; - *) + ;; + *) echo "Unknown state: $state_should" >&2 exit 1 ;; diff --git a/conf/type/__file/gencode-remote b/conf/type/__file/gencode-remote index aedae218..9e700934 100755 --- a/conf/type/__file/gencode-remote +++ b/conf/type/__file/gencode-remote @@ -33,7 +33,7 @@ case "$state_should" in echo touch \"$destination\" fi fi - + # Mode settings if [ -f "$__object/parameter/mode" ]; then echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" @@ -55,7 +55,7 @@ case "$state_should" in if [ "$exists" = "yes" ]; then echo rm -f \"$destination\" fi - + ;; *) diff --git a/conf/type/__file/man.text b/conf/type/__file/man.text index c787c930..5e91599f 100644 --- a/conf/type/__file/man.text +++ b/conf/type/__file/man.text @@ -10,7 +10,7 @@ cdist-type__file - Manage files DESCRIPTION ----------- -This cdist type allows you to create files, remove files and set file +This cdist type allows you to create files, remove files and set file attributes on the target. diff --git a/conf/type/__group/gencode-remote b/conf/type/__group/gencode-remote index 5d43a054..20e08738 100755 --- a/conf/type/__group/gencode-remote +++ b/conf/type/__group/gencode-remote @@ -47,7 +47,7 @@ if grep -q "^${name}:" "$__object/explorer/group"; then echo groupmod "$@" "$name" else true - fi + fi else for property in $(ls .); do new_value="$(cat "$property")" diff --git a/conf/type/__key_value/gencode-remote b/conf/type/__key_value/gencode-remote index 97da7349..184dfdf3 100755 --- a/conf/type/__key_value/gencode-remote +++ b/conf/type/__key_value/gencode-remote @@ -37,7 +37,7 @@ if [ "$value_is" != "$value_should" ]; then cat << DONE sed -i '/^${key}/d' "$file" DONE - else + else # change value cat << DONE awk -F "$delimiter" ' diff --git a/conf/type/__key_value/man.text b/conf/type/__key_value/man.text index 7b9381df..3e4e8013 100644 --- a/conf/type/__key_value/man.text +++ b/conf/type/__key_value/man.text @@ -35,7 +35,7 @@ EXAMPLES -------- -------------------------------------------------------------------------------- -# Set the maximum system user id +# Set the maximum system user id __key_value SYS_UID_MAX --file /etc/login.defs --value 666 --delimiter ' ' # Same with fancy id diff --git a/conf/type/__package/man.text b/conf/type/__package/man.text index 46af7b3d..d0460a31 100644 --- a/conf/type/__package/man.text +++ b/conf/type/__package/man.text @@ -26,7 +26,7 @@ name:: The name of the package to install. Default is to use the object_id as the package name. version:: - The version of the package to install. Default is to install the version + The version of the package to install. Default is to install the version choosen by the local package manager. type:: The package type to use. Default is determined based on the $os explorer diff --git a/conf/type/__package_pkg_openbsd/gencode-remote b/conf/type/__package_pkg_openbsd/gencode-remote index 0cafddd6..eee2a3d9 100755 --- a/conf/type/__package_pkg_openbsd/gencode-remote +++ b/conf/type/__package_pkg_openbsd/gencode-remote @@ -78,7 +78,7 @@ eof eof fi ;; - *) + *) echo "Unknown state: $state" >&2 exit 1 ;; diff --git a/conf/type/__package_pkg_openbsd/man.text b/conf/type/__package_pkg_openbsd/man.text index 98aeaccf..555bb0ac 100644 --- a/conf/type/__package_pkg_openbsd/man.text +++ b/conf/type/__package_pkg_openbsd/man.text @@ -5,7 +5,7 @@ Andi Brönnimann NAME ---- -cdist-type__package_pkg_openbsd - Manage OpenBSD packages +cdist-type__package_pkg_openbsd - Manage OpenBSD packages DESCRIPTION diff --git a/conf/type/__partition_msdos_apply/gencode-remote b/conf/type/__partition_msdos_apply/gencode-remote index 1d5c33cb..5dab7070 100755 --- a/conf/type/__partition_msdos_apply/gencode-remote +++ b/conf/type/__partition_msdos_apply/gencode-remote @@ -77,7 +77,7 @@ for object in $objects; do debug "current_device=$current_device" debug "available_device_size=$available_device_size" fi - + type="$(cat "$object/parameter/type")" partition="$(cat "$object/parameter/partition")" minor="$(cat "$object/parameter/minor")" diff --git a/conf/type/__postgres_role/man.text b/conf/type/__postgres_role/man.text index a7264870..bcc7b5d7 100644 --- a/conf/type/__postgres_role/man.text +++ b/conf/type/__postgres_role/man.text @@ -21,7 +21,7 @@ state:: OPTIONAL PARAMETERS ------------------- -All optional parameter map directly to the corresponding postgres createrole +All optional parameter map directly to the corresponding postgres createrole parameters. password:: @@ -36,7 +36,7 @@ EXAMPLES -------- -------------------------------------------------------------------------------- -__postgres_role myrole --state present +__postgres_role myrole --state present __postgres_role myrole --state present --password 'secret' diff --git a/conf/type/__timezone/man.text b/conf/type/__timezone/man.text index 97e85dd3..89136855 100644 --- a/conf/type/__timezone/man.text +++ b/conf/type/__timezone/man.text @@ -10,7 +10,7 @@ cdist-type__timezone - Allows to configure the desired localtime timezone. DESCRIPTION ----------- -This type creates a symlink (/etc/localtime) to the selected timezone +This type creates a symlink (/etc/localtime) to the selected timezone (which should be available in /usr/share/zoneinfo). diff --git a/conf/type/__user/explorer/group b/conf/type/__user/explorer/group index 9defba14..98ce39c6 100755 --- a/conf/type/__user/explorer/group +++ b/conf/type/__user/explorer/group @@ -24,5 +24,5 @@ if [ -f "$__object/parameter/gid" ]; then gid=$(cat "$__object/parameter/gid") getent group "$gid" || true -fi +fi diff --git a/conf/type/__user/gencode-remote b/conf/type/__user/gencode-remote index c4f9123a..ce50359b 100755 --- a/conf/type/__user/gencode-remote +++ b/conf/type/__user/gencode-remote @@ -42,7 +42,7 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then fi ;; password) - field=3 + field=3 file="$__object/explorer/shadow" ;; comment) field=5 ;; From 62b5af8fdbf9049bf2cb73973bc7413c8c59baf4 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 9 Jan 2012 21:07:03 +0100 Subject: [PATCH 1170/4212] bugfix for github issue 13 Signed-off-by: Steven Armstrong --- conf/type/__key_value/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__key_value/gencode-remote b/conf/type/__key_value/gencode-remote index 97da7349..08cbc38b 100755 --- a/conf/type/__key_value/gencode-remote +++ b/conf/type/__key_value/gencode-remote @@ -41,7 +41,7 @@ DONE # change value cat << DONE awk -F "$delimiter" ' -/${key}${delimiter}*/{gsub(/$value_is/, "$value_should")};{print}' "$file" > "${file}+" \ +/${key}${delimiter}*/{gsub("$value_is", "$value_should")};{print}' "$file" > "${file}+" \ && mv "${file}+" "$file" DONE From 60ca70b29afaf8bb8f484e26319f4ef8263704b9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 23:25:47 +0100 Subject: [PATCH 1171/4212] document bugfix for __key_value Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index b9c5cad7..2672cc90 100644 --- a/doc/changelog +++ b/doc/changelog @@ -7,6 +7,8 @@ * Cleanup: Explicitly require Python >= 3.2 (do not fail implicitly) * Feature: __directory, __file, __link: Add --state parameter (Steven Armstrong) + * Bugfix __key_value: Use correct delimiters + (Steven Armstrong, Daniel Maher) 2.0.4: 2011-11-18 * Bugfix core: Remove traceback when sending SIGINT (aka Ctrl-C) From 60ebefe820547892f1d87ff610cb724d2be99da0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 23:29:26 +0100 Subject: [PATCH 1172/4212] fix bug by documentation - has been solved before (__process) Signed-off-by: Nico Schottelius --- conf/type/__process/man.text | 4 ++++ doc/dev/todo/TAKEME | 11 ----------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/conf/type/__process/man.text b/conf/type/__process/man.text index 065beeef..fbd54847 100644 --- a/conf/type/__process/man.text +++ b/conf/type/__process/man.text @@ -24,6 +24,10 @@ OPTIONAL PARAMETERS name:: Process name to match on when using pgrep -f -x. + This is useful, if the name starts with a "/", + because the leading slash is stripped away from + the object id by cdist. + stop:: Executable to use for stopping the process. diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index d6bd81a3..56bb8284 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -4,17 +4,6 @@ The following list of todos has not been assigned to any developer. Feel free to pick one! -BUGS ----- - -Stuff that needs to repaired very soon as they may cause frustration... - -__process / name bug: - __process /usr/lib/postfix/master --start "/etc/rc.d/postfix start" --state running - => name="usr/lib/postfix/master" - => breaks! - => cannot detect if ^/ is needed or not automatically - TESTS ----- - multiple defines of object: From 05c9d320ec7d71f69d187c7bba817597f1c677a3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 23:36:58 +0100 Subject: [PATCH 1173/4212] reorder changelog for 2.0.5 release Signed-off-by: Nico Schottelius --- doc/changelog | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/changelog b/doc/changelog index 2672cc90..e6cb436e 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,14 +1,14 @@ -2.0.5: - * New Type: __package_luarocks (Christian G. Warden) - * New Type: __cdistmarker (Daniel Maher) - * Feature: __addifnosuchline supports matching on - regular expressions (Daniel Maher) - * Documentation: (Re)write of the tutorial - * Cleanup: Explicitly require Python >= 3.2 (do not fail implicitly) - * Feature: __directory, __file, __link: - Add --state parameter (Steven Armstrong) +2.0.5: [BLOCKED FOR DOCUMENTATION/TUTORIAL] * Bugfix __key_value: Use correct delimiters (Steven Armstrong, Daniel Maher) + * Cleanup: Explicitly require Python >= 3.2 (do not fail implicitly) + * Documentation: (Re)write of the tutorial + * Feature: __addifnosuchline supports matching on + regular expressions (Daniel Maher) + * Feature: __directory, __file, __link: + Add --state parameter (Steven Armstrong) + * New Type: __package_luarocks (Christian G. Warden) + * New Type: __cdistmarker (Daniel Maher) 2.0.4: 2011-11-18 * Bugfix core: Remove traceback when sending SIGINT (aka Ctrl-C) From 997efc14edb0f3dfb49492b84632295665273975 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 23:47:30 +0100 Subject: [PATCH 1174/4212] cleanup of tutorial Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-tutorial.text | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 577d633a..2802ab62 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -68,10 +68,9 @@ re-entering the password. If something failed until here, ensure that all steps went successfully and you have read and understood the documentation. -As soon as you are able to login without passwort to the target host, +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 git clone git://git.schottelius.org/cdist @@ -91,19 +90,15 @@ That's it, you've successfully used cdist to configure your first host! Continue reading the next sections, to understand what you did and how to create a more sophisticated configuration. -The file 'conf/manifest/init' is usually the entry point for cdist, -to find out what to configure on which host. All manifests are -essentially shell scripts. Every manifest can use the types known to -cdist, which are usually underline prefixed (__). - 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. Objects are instances of -**types**, like in object orientated programming. An object is represented -by the type + slash + object name: ***__file/etc/cdist-configured*** is an +**types**, like in object orientated programming languages. +An object is represented by the +type + slash + object name: ***__file/etc/cdist-configured*** is an object of the type ***__file*** with the name ***etc/cdist-configured***. Cdist searches for the initial manifest at **conf/manifest/init** and @@ -115,7 +110,7 @@ environment variable **__target_host**. Let's have a look at a simple example: -------------------------------------------------------------------------------- -__file /etc/cdist-configured +__cdistmarker case "$__target_host" in localhost) @@ -124,12 +119,15 @@ case "$__target_host" in esac -------------------------------------------------------------------------------- -This manifest says: Independent of the host, always create the (empty) file -***/etc/cdist-configured***, but create the directory ***/home/services/kvm-vm***, -including all parent directories, only on the host ***localhost***. +This manifest says: Independent of the host, always use the type +***__cdistmarker***, which creates the file **/etc/cdist-configured**, +with the timestamp as content. +The directory ***/home/services/kvm-vm***, including all parent directories, +is only created on the host ***localhost***. As you can see, there is no magic involved, the manifest is simple shell code that -utilises cdist types. +utilises cdist types. Every available type can be executed like a normal +command. Use **ls conf/type** to get a list of available types. PARTS BELOW HERE ARE TO-BE-DONE From 29e1dee264e86459aac8fc4177eba1cb2d0b4f70 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 23:51:47 +0100 Subject: [PATCH 1175/4212] remove __self in cdist 3.0 Signed-off-by: Nico Schottelius --- doc/man/cdist-reference.text.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 12f30d7f..a1757c43 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -182,6 +182,7 @@ __object_id:: Available for: type manifest, type explorer, type gencode __self:: DEPRECATED: Same as __object_name, do not use anymore, use __object_name instead. + Will be removed in cdist 3.x. __object_name:: The full qualified name of the current object. Available for: type manifest, type explorer, type gencode From 3fff9e87960e92420829945c0d13def66d3d9850 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jan 2012 23:52:05 +0100 Subject: [PATCH 1176/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/3.0 | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/dev/todo/3.0 diff --git a/doc/dev/todo/3.0 b/doc/dev/todo/3.0 new file mode 100644 index 00000000..97699879 --- /dev/null +++ b/doc/dev/todo/3.0 @@ -0,0 +1 @@ +- remove __self and all references to it From 6f828539728de793603a3418f3e1e7297a0daaa7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 10 Jan 2012 00:00:23 +0100 Subject: [PATCH 1177/4212] +linkedin link Signed-off-by: Nico Schottelius --- README | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README b/README index 46982d9f..bda6a197 100644 --- a/README +++ b/README @@ -261,6 +261,13 @@ You can join the development ***IRC channel*** Bug reports, questions, patches, etc. should be send to the [cdist mailing list](http://l.schottelius.org/mailman/listinfo/cdist). +### Linkedin + +If you have an account +at [Linked in](http://www.linkedin.com/), +you can join the +[cdist group](http://www.linkedin.com/groups/cdist-configuration-management-3952797). + ### Commercial support You can request commercial support for cdist from From 08c5882d401f79bfbb42471e57da7b6a9db3986b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 10 Jan 2012 00:01:02 +0100 Subject: [PATCH 1178/4212] prepare next chapters in tutorial Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-tutorial.text | 35 +++++++++++++++++++------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 2802ab62..883fcd73 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -127,12 +127,31 @@ is only created on the host ***localhost***. As you can see, there is no magic involved, the manifest is simple shell code that utilises cdist types. Every available type can be executed like a normal -command. Use **ls conf/type** to get a list of available types. - +command. Use **ls conf/type** to get a list of available types. If you have +setup the MANPATH correctly as, you can use **man cdist-reference** to access +the reference with pointers to the manpages. PARTS BELOW HERE ARE TO-BE-DONE +MANAGING YOUR OWN CONFIGURATION +------------------------------- + +CREATING YOUR FIRST OWN TYPE +---------------------------- +=> short example, reference to cdist-type(7)! + + + +Debug with var - can be used by yourself +__debug:: + If this variable is setup, cdist runs in debug mode. + You can use this information, to only output stuff in debug + mode as well. + Available for: initial manifest, type manifest, gencode, code + + + MORE ABOUT TYPES AND OBJECTS ---------------------------- All available types in cdist can be called like normal executables. @@ -143,9 +162,6 @@ USING SOME BASIC TYPES what is a type, how to use it, -CREATING YOUR FIRST OWN TYPE ----------------------------- - USE A TYPE TO BUNDLE FUNCTIONALITY @@ -159,18 +175,9 @@ global, type explorer DEBUGGING YOUR TYPES -------------------- -__debug:: - If this variable is setup, cdist runs in debug mode. - You can use this information, to only output stuff in debug - mode as well. - Available for: initial manifest, type manifest, gencode, code - -BRANCHES IN HERE? ------------- - TUNING CDIST ------------ From 039040e5c66f7b915995d516900f8d9e863b9c1b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 10 Jan 2012 00:01:09 +0100 Subject: [PATCH 1179/4212] add hint on pull request on github Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-type.text | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/man/man7/cdist-type.text b/doc/man/man7/cdist-type.text index 2439876c..a58283f9 100644 --- a/doc/man/man7/cdist-type.text +++ b/doc/man/man7/cdist-type.text @@ -192,7 +192,8 @@ 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 submit the git url containing the type for -inclusion to the mailinglist **cdist at cdist -- at -- l.schottelius.org**. +inclusion to the mailinglist **cdist at cdist -- at -- l.schottelius.org** +or open a pull request at http://github.com/telmich/cdist. Ensure a corresponding manpage named man.text in asciidoc format with the manpage-name "cdist-type__NAME" is included in the type directory. From 3111f1a7bda11dc7e9dc7c33dbb6689d6687625b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 11 Jan 2012 11:52:02 +0100 Subject: [PATCH 1180/4212] many cleanups Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 18 +++++++++++++++-- doc/man/man7/cdist-best-practice.text | 2 +- doc/man/man7/cdist-explorer.text | 2 +- doc/man/man7/cdist-tutorial.text | 29 ++++++++++----------------- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 66e1baee..47e12bf6 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,8 +1,22 @@ +- write tutorial + - remove cdist(7) reference everywhere + - check cross links + +- check other docs: + - cdist-best-practice.text + - cdist-explorer.text + - cdist-hacker.text + - cdist-manifest.text + - cdist-reference.text + - cdist-stages.text + - cdist-type.text + +-------------------------------------------------------------------------------- + + - check speech publishing - and speeches, which may be outdated as well -- write tutorial - - Fix / rewrite cdist-quickstart - like ccollect! diff --git a/doc/man/man7/cdist-best-practice.text b/doc/man/man7/cdist-best-practice.text index 5ec01d5f..7d947fce 100644 --- a/doc/man/man7/cdist-best-practice.text +++ b/doc/man/man7/cdist-best-practice.text @@ -141,7 +141,7 @@ you to push certain branches to certain remotes. SEE ALSO -------- -- cdist(7) +- cdist(1) COPYING diff --git a/doc/man/man7/cdist-explorer.text b/doc/man/man7/cdist-explorer.text index e1909ab5..b9c342a9 100644 --- a/doc/man/man7/cdist-explorer.text +++ b/doc/man/man7/cdist-explorer.text @@ -57,7 +57,7 @@ dpkg -s "$name" 2>/dev/null || exit 0 SEE ALSO -------- -- cdist(7) +- cdist(1) - cdist-reference(7) - cdist-stages(7) diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 883fcd73..9d068030 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -133,6 +133,8 @@ the reference with pointers to the manpages. PARTS BELOW HERE ARE TO-BE-DONE +-> ssh stuff double: cdist-best-practice and here + MANAGING YOUR OWN CONFIGURATION ------------------------------- @@ -140,6 +142,9 @@ MANAGING YOUR OWN CONFIGURATION CREATING YOUR FIRST OWN TYPE ---------------------------- => short example, reference to cdist-type(7)! +=> motivation + +Use a type to bundle functionalitY @@ -152,25 +157,9 @@ __debug:: -MORE ABOUT TYPES AND OBJECTS ----------------------------- -All available types in cdist can be called like normal executables. - - -USING SOME BASIC TYPES ----------------------- -what is a type, how to use it, - - - - -USE A TYPE TO BUNDLE FUNCTIONALITY ----------------------------------- - - USING EXPLORERS --------------- -global, type explorer +cdist-explorer.text DEBUGGING YOUR TYPES @@ -183,8 +172,12 @@ TUNING CDIST - speedup processing with ControlMaster option of ssh +=> different document SEE ALSO -------- -cdist(1), cdist-type(7), cdist-stages(7) +- cdist(1) +- cdist-type(7) +- cdist-best-practice(7) +- cdist-stages(7)? From d109c1bc3d981f6d7de240a8601357ff0b6a6096 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 11 Jan 2012 17:06:40 +0100 Subject: [PATCH 1181/4212] minimal changes to tutorial Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 7 +++++++ doc/man/man7/cdist-tutorial.text | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 47e12bf6..9b657ad3 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,4 +1,11 @@ - write tutorial + - containing many links?! + - quickstart + - cdist-environment/startup/initial-setup (setup env) + - cdist-type + - ... + - cdist-hacker + - remove cdist(7) reference everywhere - check cross links diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 9d068030..5e257824 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -136,6 +136,18 @@ PARTS BELOW HERE ARE TO-BE-DONE -> ssh stuff double: cdist-best-practice and here +CONTINUE READING +---------------- +So far you have seen how to get cdist up and running and +how the initial manifest is being used. + +own branch => very early [before first change?] + => no, first quick intro, then do it right +It is recommended to +- MANAGING YOUR OWN CONFIGURATION +- write own type + + MANAGING YOUR OWN CONFIGURATION ------------------------------- From c5cd1ce89a9627e2e9fd95dc492bd5d45894510a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 11 Jan 2012 17:11:11 +0100 Subject: [PATCH 1182/4212] split tutorial into quickstart, make tutorial a guide Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-best-practice.text | 2 +- doc/man/man7/cdist-quickstart.text | 109 ++++++++++++++++++++++++++ doc/man/man7/cdist-tutorial.text | 86 ++------------------ 3 files changed, 117 insertions(+), 80 deletions(-) create mode 100644 doc/man/man7/cdist-quickstart.text diff --git a/doc/man/man7/cdist-best-practice.text b/doc/man/man7/cdist-best-practice.text index 7d947fce..dfc06167 100644 --- a/doc/man/man7/cdist-best-practice.text +++ b/doc/man/man7/cdist-best-practice.text @@ -146,5 +146,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is +Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man7/cdist-quickstart.text b/doc/man/man7/cdist-quickstart.text new file mode 100644 index 00000000..5012a331 --- /dev/null +++ b/doc/man/man7/cdist-quickstart.text @@ -0,0 +1,109 @@ +cdist-quickstart(7) +=================== +Nico Schottelius + + +NAME +---- +cdist-quickstart - jump in and enjoy cdist + + +INTRODUCTION +------------ +This tutorial is aimed at people learning cdist and shows +typical approaches as well as gives an easy start into +the world of configuration management. + +This tutorial assumes you are configuring **localhost**, because +it is always available. Just replace **localhost** with your target +host for real life usage. + + + +QUICK START - GET YOUR HANDS DIRTY NOW +-------------------------------------- +For those who just want to configure a system with the +cdist configuration management and do not need (or want) +to understand everything. + +Cdist uses **ssh** for communication and transportation +and usually logs into the **target host** as the +**root** user. So you need to configure the **ssh server** +of the target host to allow root logins: Edit +the file **/etc/ssh/sshd_config** and add one of the following +lines: + +-------------------------------------------------------------------------------- +# Allow login only via public key +PermitRootLogin without-password + +# Allow login via password and public key +PermitRootLogin yes +-------------------------------------------------------------------------------- + +As cdist uses ssh intensively, it is recommended to setup authentication +with public keys: + +-------------------------------------------------------------------------------- +# Generate pubkey pair as a normal user +ssh-keygen + +# Copy pubkey over to target host +ssh-copy-id root@localhost +-------------------------------------------------------------------------------- + +Have a look at ssh-agent(1) and ssh-add(1) on how to cache the password for +your public key. Usually it looks like this: + +-------------------------------------------------------------------------------- +# Start agent and export variables +eval `ssh-agent` + +# Add keys (requires password for every identity file) +ssh-add +-------------------------------------------------------------------------------- + +At this point you should be able to ***ssh root@localhost*** without +re-entering the password. If something failed until here, ensure that +all steps went successfully and you have read and understood the +documentation. + +As soon as you are able to login without password to localhost, +we can use cdist to configure it. You can copy and paste the following +code into your shell to get started and configure localhost: +-------------------------------------------------------------------------------- +# Get cdist +git clone git://git.schottelius.org/cdist + +# Create manifest (maps configuration to host(s) +cd cdist +echo '__file /etc/cdist-configured' > conf/manifest/init + +# Configure localhost in verbose mode +./bin/cdist config -v localhost + +# Find out that cdist created /etc/cdist-configured +ls -l /etc/cdist-configured +-------------------------------------------------------------------------------- + +That's it, you've successfully used cdist to configure your first host! +Continue reading the next sections, to understand what you did and how +to create a more sophisticated configuration. + + +CONTINUE READING +----------------- + + +SEE ALSO +-------- +- cdist(1) +- cdist-type(7) +- cdist-best-practice(7) +- cdist-stages(7)? + + +COPYING +------- +Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 5e257824..d80a4fe2 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -10,85 +10,8 @@ cdist-tutorial - a guided introduction into cdist INTRODUCTION ------------ -This tutorial is aimed at people learning cdist and shows -typical approaches as well as gives an easy start into -the world of configuration management. - -This tutorial assumes you are configuring **localhost**, because -it is always available. Just replace **localhost** with your target -host for real life usage. - - - -QUICK START - GET YOUR HANDS DIRTY NOW --------------------------------------- -For those who just want to configure a system with the -cdist configuration management and do not need (or want) -to understand everything. - -Cdist uses **ssh** for communication and transportation -and usually logs into the **target host** as the -**root** user. So you need to configure the **ssh server** -of the target host to allow root logins: Edit -the file **/etc/ssh/sshd_config** and add one of the following -lines: - --------------------------------------------------------------------------------- -# Allow login only via public key -PermitRootLogin without-password - -# Allow login via password and public key -PermitRootLogin yes --------------------------------------------------------------------------------- - -As cdist uses ssh intensively, it is recommended to setup authentication -with public keys: - --------------------------------------------------------------------------------- -# Generate pubkey pair as a normal user -ssh-keygen - -# Copy pubkey over to target host -ssh-copy-id root@localhost --------------------------------------------------------------------------------- - -Have a look at ssh-agent(1) and ssh-add(1) on how to cache the password for -your public key. Usually it looks like this: - --------------------------------------------------------------------------------- -# Start agent and export variables -eval `ssh-agent` - -# Add keys (requires password for every identity file) -ssh-add --------------------------------------------------------------------------------- - -At this point you should be able to ***ssh root@localhost*** without -re-entering the password. If something failed until here, ensure that -all steps went successfully and you have read and understood the -documentation. - -As soon as you are able to login without password to localhost, -we can use cdist to configure it. You can copy and paste the following -code into your shell to get started and configure localhost: --------------------------------------------------------------------------------- -# Get cdist -git clone git://git.schottelius.org/cdist - -# Create manifest (maps configuration to host(s) -cd cdist -echo '__file /etc/cdist-configured' > conf/manifest/init - -# Configure localhost in verbose mode -./bin/cdist config -v localhost - -# Find out that cdist created /etc/cdist-configured -ls -l /etc/cdist-configured --------------------------------------------------------------------------------- - -That's it, you've successfully used cdist to configure your first host! -Continue reading the next sections, to understand what you did and how -to create a more sophisticated configuration. +This document gives you a pointer on what to read in +which order and is thus more a "guide to the right locations". @@ -193,3 +116,8 @@ SEE ALSO - cdist-type(7) - cdist-best-practice(7) - cdist-stages(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 ae8f2b35ca158a17026b2eccf4e666247c158c81 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 11 Jan 2012 17:21:38 +0100 Subject: [PATCH 1183/4212] move manifest stuff into manifest file from tutorial Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-manifest.text | 44 +++++++++++++++++++++-- doc/man/man7/cdist-tutorial.text | 60 +++++++++++--------------------- 2 files changed, 62 insertions(+), 42 deletions(-) diff --git a/doc/man/man7/cdist-manifest.text b/doc/man/man7/cdist-manifest.text index 43dd2b6a..e7e783a3 100644 --- a/doc/man/man7/cdist-manifest.text +++ b/doc/man/man7/cdist-manifest.text @@ -8,6 +8,46 @@ NAME cdist-manifest - Define types to be used +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. Objects are instances of +**types**, like in object orientated programming languages. +An object is represented by the +type + slash + object name: ***__file/etc/cdist-configured*** is an +object of the type ***__file*** with the name ***etc/cdist-configured***. + +Cdist searches for the initial manifest at **conf/manifest/init** and +executes it as a shell script using **/bin/sh -e**. + +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: + +-------------------------------------------------------------------------------- +__cdistmarker + +case "$__target_host" in + localhost) + __directory /home/services/kvm-vm --parents yes + ;; +esac +-------------------------------------------------------------------------------- + +This manifest says: Independent of the host, always use the type +***__cdistmarker***, which creates the file **/etc/cdist-configured**, +with the timestamp as content. +The directory ***/home/services/kvm-vm***, including all parent directories, +is only created on the host ***localhost***. + +As you can see, there is no magic involved, the manifest is simple shell code that +utilises cdist types. Every available type can be executed like a normal +command. Use **ls conf/type** to get a list of available types. If you have +setup the MANPATH correctly as, you can use **man cdist-reference** to access +the reference with pointers to the manpages. + + DESCRIPTION ----------- Manifests exist to define which configurations should be applied to a specific @@ -69,12 +109,10 @@ require="__file/etc/cdist-configured __link/tmp/cdist-testfile" \ SEE ALSO -------- -- cdist-manifest-run(1) -- cdist-manifest-run-init(1) - cdist-type(7) COPYING ------- -Copyright \(C) 2010-2011 Nico Schottelius. Free use of this software is +Copyright \(C) 2010-2012 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index d80a4fe2..3d6b11f4 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -13,49 +13,31 @@ INTRODUCTION This document gives you a pointer on what to read in which order and is thus more a "guide to the right locations". +cdist-quickstart:: + Read this, if you are brand new in the cdist world and just want + to get your hands dirty. - -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. Objects are instances of -**types**, like in object orientated programming languages. -An object is represented by the -type + slash + object name: ***__file/etc/cdist-configured*** is an -object of the type ***__file*** with the name ***etc/cdist-configured***. - -Cdist searches for the initial manifest at **conf/manifest/init** and -executes it as a shell script using **/bin/sh -e**. - -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: - --------------------------------------------------------------------------------- -__cdistmarker - -case "$__target_host" in - localhost) - __directory /home/services/kvm-vm --parents yes - ;; -esac --------------------------------------------------------------------------------- - -This manifest says: Independent of the host, always use the type -***__cdistmarker***, which creates the file **/etc/cdist-configured**, -with the timestamp as content. -The directory ***/home/services/kvm-vm***, including all parent directories, -is only created on the host ***localhost***. - -As you can see, there is no magic involved, the manifest is simple shell code that -utilises cdist types. Every available type can be executed like a normal -command. Use **ls conf/type** to get a list of available types. If you have -setup the MANPATH correctly as, you can use **man cdist-reference** to access -the reference with pointers to the manpages. +cdist-reference:: + Know everything about cdist: the types, explorers or environment + variables usable. PARTS BELOW HERE ARE TO-BE-DONE +cdist-installation:: + The comprehensive guide to your first cdist installation. + +cdist-manifest:: + initial in here + +cdist-best-practice:: +cdist-explorer:: +cdist-hacker:: + +cdist-stages:: +cdist-type:: + + + -> ssh stuff double: cdist-best-practice and here From c26058efcc6d96521fb4db2266024fae632a02d0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 11 Jan 2012 17:25:27 +0100 Subject: [PATCH 1184/4212] important to link explorer from type Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-type.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man/man7/cdist-type.text b/doc/man/man7/cdist-type.text index a58283f9..1dbb4a1d 100644 --- a/doc/man/man7/cdist-type.text +++ b/doc/man/man7/cdist-type.text @@ -201,7 +201,7 @@ the manpage-name "cdist-type__NAME" is included in the type directory. SEE ALSO -------- -- cdist-manifest-run(1) +- cdist-explorer(7) - cdist-stages(7) From f8e80d642268fe4ecddfac21027cf9b52593bdd3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 11 Jan 2012 17:34:09 +0100 Subject: [PATCH 1185/4212] cleanup document listing - now only worry about writing them Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 2 + doc/man/man7/cdist-tutorial.text | 116 +++++++++++++++---------------- 2 files changed, 57 insertions(+), 61 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 9b657ad3..64ff681b 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -18,6 +18,8 @@ - cdist-stages.text - cdist-type.text + 51 -> ssh stuff double: cdist-best-practice and here + -------------------------------------------------------------------------------- diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 3d6b11f4..87ace7cd 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -14,83 +14,77 @@ This document gives you a pointer on what to read in which order and is thus more a "guide to the right locations". cdist-quickstart:: - Read this, if you are brand new in the cdist world and just want - to get your hands dirty. - -cdist-reference:: - Know everything about cdist: the types, explorers or environment - variables usable. - -PARTS BELOW HERE ARE TO-BE-DONE + New to cdist? Want to get your hands dirty? Read this. [beginner] cdist-installation:: - The comprehensive guide to your first cdist installation. - -cdist-manifest:: - initial in here - -cdist-best-practice:: -cdist-explorer:: -cdist-hacker:: - -cdist-stages:: -cdist-type:: - - - --> ssh stuff double: cdist-best-practice and here - - -CONTINUE READING ----------------- -So far you have seen how to get cdist up and running and -how the initial manifest is being used. + The comprehensive guide to your first cdist installation [beginner] + - MANAGING YOUR OWN CONFIGURATION own branch => very early [before first change?] => no, first quick intro, then do it right -It is recommended to -- MANAGING YOUR OWN CONFIGURATION -- write own type + +cdist-initial-manifest:: + Learn how to define which hosts get which configurations [beginner] + +cdist-type:: + Understand how types are working and created [intermediate] + + CREATING YOUR FIRST OWN TYPE + ---------------------------- + => short example, reference to cdist-type(7)! + => motivation + + Use a type to bundle functionalitY + + + + Debug with var - can be used by yourself + __debug:: + If this variable is setup, cdist runs in debug mode. + You can use this information, to only output stuff in debug + mode as well. + Available for: initial manifest, type manifest, gencode, code -MANAGING YOUR OWN CONFIGURATION -------------------------------- + USING EXPLORERS + --------------- + cdist-explorer.text -CREATING YOUR FIRST OWN TYPE ----------------------------- -=> short example, reference to cdist-type(7)! -=> motivation - -Use a type to bundle functionalitY - - - -Debug with var - can be used by yourself -__debug:: - If this variable is setup, cdist runs in debug mode. - You can use this information, to only output stuff in debug - mode as well. - Available for: initial manifest, type manifest, gencode, code + DEBUGGING YOUR TYPES + -------------------- +cdist-best-practice:: + Hints from real life experience to help you to organise cdist [intermediate] -USING EXPLORERS ---------------- -cdist-explorer.text +cdist-reference:: + The type, explorers and environment variables reference [intermediate] + +cdist-explorer:: + Interested in getting more information about the target system? [intermediate] + +cdist-cache:: + How to get use information about the hosts we have been working on [advanced] + +cdist-scaling-tuning:: + How to scale out with cdist and which tunings to apply. [advanced] + + TUNING CDIST + ------------ + + - speedup processing with ControlMaster option of + ssh + => different document -DEBUGGING YOUR TYPES --------------------- +cdist-stages:: + Understand the internal workflow of cdist. [advanced] + +cdist-hacker:: + README, if you want to extend or modify cdist. [hacker] -TUNING CDIST ------------- - -- speedup processing with ControlMaster option of -ssh -=> different document - SEE ALSO -------- From 202e5b69d8447beb74a47053ba89389e1bf07534 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 11 Jan 2012 17:40:53 +0100 Subject: [PATCH 1186/4212] better intro, reference brave new world Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-tutorial.text | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 87ace7cd..5ef19c14 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -11,10 +11,13 @@ cdist-tutorial - a guided introduction into cdist INTRODUCTION ------------ This document gives you a pointer on what to read in -which order and is thus more a "guide to the right locations". +which order and is thus a "guide to the right locations". +So in case you are just starting, just "begin at the beginning" +(Brave New World). You can see the target audience in [] brackets +after the description. cdist-quickstart:: - New to cdist? Want to get your hands dirty? Read this. [beginner] + New to cdist? Want to get your hands dirty? Read this. [beginner] cdist-installation:: The comprehensive guide to your first cdist installation [beginner] @@ -92,6 +95,7 @@ SEE ALSO - cdist-type(7) - cdist-best-practice(7) - cdist-stages(7)? +- Brave New World by Aldous Huxley COPYING ------- From 38e5c3e4075e1f97241716040afbb3d483dc1259 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 12 Jan 2012 09:18:43 +0100 Subject: [PATCH 1187/4212] fix issues with requirements caused by legacy code conflicting with the new autorequire feature --- conf/type/__package/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__package/manifest b/conf/type/__package/manifest index 765ece36..48818dd8 100755 --- a/conf/type/__package/manifest +++ b/conf/type/__package/manifest @@ -49,4 +49,4 @@ for property in $(ls .); do fi done -require="$__object_name" __package_$type "$@" +__package_$type "$@" From 11be25116374e52ef734f6353f689c34010df37d Mon Sep 17 00:00:00 2001 From: Evax Software Date: Fri, 13 Jan 2012 08:28:13 +0100 Subject: [PATCH 1188/4212] add rvm types --- conf/type/__rvm/explorer/state | 26 +++++++++++ conf/type/__rvm/gencode-remote | 39 ++++++++++++++++ conf/type/__rvm/man.text | 45 +++++++++++++++++++ conf/type/__rvm/parameter/required | 1 + conf/type/__rvm_gem/explorer/state | 39 ++++++++++++++++ conf/type/__rvm_gem/gencode-remote | 43 ++++++++++++++++++ conf/type/__rvm_gem/man.text | 53 ++++++++++++++++++++++ conf/type/__rvm_gem/manifest | 38 ++++++++++++++++ conf/type/__rvm_gem/parameter/optional | 1 + conf/type/__rvm_gem/parameter/required | 3 ++ conf/type/__rvm_gemset/explorer/state | 37 +++++++++++++++ conf/type/__rvm_gemset/gencode-remote | 52 +++++++++++++++++++++ conf/type/__rvm_gemset/man.text | 55 +++++++++++++++++++++++ conf/type/__rvm_gemset/manifest | 35 +++++++++++++++ conf/type/__rvm_gemset/parameter/optional | 1 + conf/type/__rvm_gemset/parameter/required | 2 + conf/type/__rvm_ruby/explorer/state | 32 +++++++++++++ conf/type/__rvm_ruby/gencode-remote | 45 +++++++++++++++++++ conf/type/__rvm_ruby/man.text | 54 ++++++++++++++++++++++ conf/type/__rvm_ruby/manifest | 33 ++++++++++++++ conf/type/__rvm_ruby/parameter/optional | 1 + conf/type/__rvm_ruby/parameter/required | 2 + 22 files changed, 637 insertions(+) create mode 100755 conf/type/__rvm/explorer/state create mode 100755 conf/type/__rvm/gencode-remote create mode 100644 conf/type/__rvm/man.text create mode 100644 conf/type/__rvm/parameter/required create mode 100755 conf/type/__rvm_gem/explorer/state create mode 100755 conf/type/__rvm_gem/gencode-remote create mode 100644 conf/type/__rvm_gem/man.text create mode 100755 conf/type/__rvm_gem/manifest create mode 100644 conf/type/__rvm_gem/parameter/optional create mode 100644 conf/type/__rvm_gem/parameter/required create mode 100755 conf/type/__rvm_gemset/explorer/state create mode 100755 conf/type/__rvm_gemset/gencode-remote create mode 100644 conf/type/__rvm_gemset/man.text create mode 100755 conf/type/__rvm_gemset/manifest create mode 100644 conf/type/__rvm_gemset/parameter/optional create mode 100644 conf/type/__rvm_gemset/parameter/required create mode 100755 conf/type/__rvm_ruby/explorer/state create mode 100755 conf/type/__rvm_ruby/gencode-remote create mode 100644 conf/type/__rvm_ruby/man.text create mode 100755 conf/type/__rvm_ruby/manifest create mode 100644 conf/type/__rvm_ruby/parameter/optional create mode 100644 conf/type/__rvm_ruby/parameter/required diff --git a/conf/type/__rvm/explorer/state b/conf/type/__rvm/explorer/state new file mode 100755 index 00000000..92fa6e07 --- /dev/null +++ b/conf/type/__rvm/explorer/state @@ -0,0 +1,26 @@ +#!/bin/sh +# +# 2012 Evax Software +# +# 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 . +# + +user="$__object_id" +if su - $user -c "[ -d \"\$HOME/.rvm\" ]" ; then + echo "installed" +else + echo "removed" +fi diff --git a/conf/type/__rvm/gencode-remote b/conf/type/__rvm/gencode-remote new file mode 100755 index 00000000..f306979a --- /dev/null +++ b/conf/type/__rvm/gencode-remote @@ -0,0 +1,39 @@ +#!/bin/sh +# +# 2012 Evax Software +# +# 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 . +# + +user="$__object_id" +state_is="$(cat "$__object/explorer/state")" +state_should="$(cat "$__object/parameter/state")" +if [ "$state_is" != "$state_should" ]; then + case "$state_should" in + installed) + cat << DONE +su - $user -c "bash -s stable < <(curl -s \ +https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)" +DONE + ;; + removed) + cat << DONE +su - $user -c "rm -Rf \"\\\$HOME/.rvm\"; +sed -i '/rvm\/scripts\/rvm/d' \"\\\$HOME/.bashrc\"" +DONE + ;; + esac +fi diff --git a/conf/type/__rvm/man.text b/conf/type/__rvm/man.text new file mode 100644 index 00000000..d54e2d1b --- /dev/null +++ b/conf/type/__rvm/man.text @@ -0,0 +1,45 @@ +cdist-type__rvm(7) +================== +Evax Software + + +NAME +---- +cdist-type__rvm - Install rvm for a given user + + +DESCRIPTION +----------- +RVM is the Ruby enVironment Manager for the Ruby programming language. + + +REQUIRED PARAMETERS +------------------- +state:: + Either "installed" or "removed". + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Install rvm for user billie +__rvm billie --state installed + +# Remove rvm +__rvm billie --state removed +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__rvm_ruby(7) +- cdist-type__rvm_gemset(7) +- cdist-type__rvm_gem(7) + + +COPYING +------- +Copyright \(C) 2012 Evax Software. Free use of this software is granted under +the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__rvm/parameter/required b/conf/type/__rvm/parameter/required new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/conf/type/__rvm/parameter/required @@ -0,0 +1 @@ +state diff --git a/conf/type/__rvm_gem/explorer/state b/conf/type/__rvm_gem/explorer/state new file mode 100755 index 00000000..d4cca9cb --- /dev/null +++ b/conf/type/__rvm_gem/explorer/state @@ -0,0 +1,39 @@ +#!/bin/sh +# +# 2012 Evax Software +# +# 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 . +# + +gem="$__object_id" +gemset="$(cat "$__object/parameter/gemset")" +ruby="$(echo "$gemset" | cut -d '@' -f 1)" +gemsetname="$(echo "$gemset" | cut -d '@' -f2)" +user="$(cat "$__object/parameter/user")" +if su - $user -c "[ ! -d \"\$HOME/.rvm\" ]" ; then + echo "removed" + exit 0 +fi +if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" +rvm list | grep $ruby"; then + if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" +rvm use $ruby; rvm gemset list | grep $gemsetname > /dev/null && +rvm use $gemset && gem list | grep $gem"; then + echo "installed" + exit 0 + fi +fi +echo "removed" diff --git a/conf/type/__rvm_gem/gencode-remote b/conf/type/__rvm_gem/gencode-remote new file mode 100755 index 00000000..8b784ac3 --- /dev/null +++ b/conf/type/__rvm_gem/gencode-remote @@ -0,0 +1,43 @@ +#!/bin/sh +# +# 2012 Evax Software +# +# 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 . +# + +gem="$__object_id" +gemset="$(cat "$__object/parameter/gemset")" +ruby="$(echo "$gemset" | cut -d '@' -f 1)" +gemsetname="$(echo "$gemset" | cut -d '@' -f 2)" +state_is="$(cat "$__object/explorer/state")" +user="$(cat "$__object/parameter/user")" +state_should="$(cat "$__object/parameter/state")" +if [ "$state_is" != "$state_should" ]; then + case "$state_should" in + installed) + cat << DONE +su - $user -c "source \"\\\$HOME/.rvm/scripts/rvm\" +rvm use $gemset; gem install $gem" +DONE + ;; + removed) + cat << DONE +su - $user -c "source \"\\\$HOME/.rvm/scripts/rvm\" +rvm use $gemset; gem uninstall $gem" +DONE + ;; + esac +fi diff --git a/conf/type/__rvm_gem/man.text b/conf/type/__rvm_gem/man.text new file mode 100644 index 00000000..951884b8 --- /dev/null +++ b/conf/type/__rvm_gem/man.text @@ -0,0 +1,53 @@ +cdist-type__rvm_gemset(7) +========================== +Evax Software + + +NAME +---- +cdist-type__rvm_gem - Manage Ruby gems through rvm + + +DESCRIPTION +----------- +RVM is the Ruby enVironment Manager for the Ruby programming language. + + +REQUIRED PARAMETERS +------------------- +user:: + The remote user account to use +gemset:: + The gemset to use +state:: + Either "installed" or "removed". + +OPTIONAL PARAMETERS +------------------- +default:: + Make the selected gemset the default + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Install the rails gem in gemset ruby-1.9.3-p0@myset for user bill +__rvm_gemset rails --gemset ruby-1.9.3-p0@myset --user bill --state installed + +# Remove it +__rvm_ruby rails --gemset ruby-1.9.3-p0@myset --user bill --state removed +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__rvm(7) +- cdist-type__rvm_ruby(7) +- cdist-type__rvm_gemset(7) + + +COPYING +------- +Copyright \(C) 2012 Evax Software. Free use of this software is granted under +the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__rvm_gem/manifest b/conf/type/__rvm_gem/manifest new file mode 100755 index 00000000..737dbe75 --- /dev/null +++ b/conf/type/__rvm_gem/manifest @@ -0,0 +1,38 @@ +#!/bin/sh +# +# 2012 Evax Software +# +# 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 . +# + +gem="$__object_id" +gemset="$(cat "$__object/parameter/gemset")" +ruby="$(echo "$gemset" | cut -d '@' -f 1)" +gemsetname="$(echo "$gemset" | cut -d '@' -f 2)" +user="$(cat "$__object/parameter/user")" +state="$(cat "$__object/explorer/state")" +if [ -f "$__object/parameter/default" ]; then + default="$(cat "$__object/parameter/default")" +else + default="no" + echo $default > "$__object/parameter/default" +fi + +__rvm $user --state installed +require="__rvm/$user" \ + __rvm_ruby $ruby --user $user --state installed --default $default +require="__rvm_ruby/$ruby" \ + __rvm_gemset $gemset --user $user --state installed --default $default diff --git a/conf/type/__rvm_gem/parameter/optional b/conf/type/__rvm_gem/parameter/optional new file mode 100644 index 00000000..4ad96d51 --- /dev/null +++ b/conf/type/__rvm_gem/parameter/optional @@ -0,0 +1 @@ +default diff --git a/conf/type/__rvm_gem/parameter/required b/conf/type/__rvm_gem/parameter/required new file mode 100644 index 00000000..75f60bb8 --- /dev/null +++ b/conf/type/__rvm_gem/parameter/required @@ -0,0 +1,3 @@ +state +gemset +user diff --git a/conf/type/__rvm_gemset/explorer/state b/conf/type/__rvm_gemset/explorer/state new file mode 100755 index 00000000..132c376d --- /dev/null +++ b/conf/type/__rvm_gemset/explorer/state @@ -0,0 +1,37 @@ +#!/bin/sh +# +# 2012 Evax Software +# +# 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 . +# + +gemset="$__object_id" +ruby="$(echo "$gemset" | cut -d '@' -f 1)" +gemsetname="$(echo "$gemset" | cut -d '@' -f2)" +user="$(cat "$__object/parameter/user")" +if su - $user -c "[ ! -d \"\$HOME/.rvm\" ]" ; then + echo "removed" + exit 0 +fi +if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" +rvm list | grep $ruby"; then + if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" +rvm use $ruby; rvm gemset list | grep $gemsetname > /dev/null"; then + echo "installed" + exit 0 + fi +fi +echo "removed" diff --git a/conf/type/__rvm_gemset/gencode-remote b/conf/type/__rvm_gemset/gencode-remote new file mode 100755 index 00000000..5b934edb --- /dev/null +++ b/conf/type/__rvm_gemset/gencode-remote @@ -0,0 +1,52 @@ +#!/bin/sh +# +# 2012 Evax Software +# +# 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 . +# + +gemset="$__object_id" +ruby="$(echo "$gemset" | cut -d '@' -f 1)" +gemsetname="$(echo "$gemset" | cut -d '@' -f 2)" +state_is="$(cat "$__object/explorer/state")" +user="$(cat "$__object/parameter/user")" +state_should="$(cat "$__object/parameter/state")" +if [ "$state_is" != "$state_should" ]; then + case "$state_should" in + installed) + cat << DONE +su - $user -c "source \"\\\$HOME/.rvm/scripts/rvm\" +rvm $gemset --create" +DONE + case "$default" in + no) + ;; + *) + cat << DONE +su - $user -c "source \"\\\$HOME/.rvm/scripts/rvm\" +rvm use --default $gemset" +DONE + ;; + esac + ;; + removed) + cat << DONE +su - $user -c "source \"\\\$HOME/.rvm/scripts/rvm\" +rvm use $ruby; rvm --force gemset delete $gemsetname" +DONE + ;; + esac +fi diff --git a/conf/type/__rvm_gemset/man.text b/conf/type/__rvm_gemset/man.text new file mode 100644 index 00000000..d7b4c04c --- /dev/null +++ b/conf/type/__rvm_gemset/man.text @@ -0,0 +1,55 @@ +cdist-type__rvm_gemset(7) +========================== +Evax Software + + +NAME +---- +cdist-type__rvm_gemset - Manage gemsets through rvm + + +DESCRIPTION +----------- +RVM is the Ruby enVironment Manager for the Ruby programming language. + + +REQUIRED PARAMETERS +------------------- +user:: + The remote user account to use +ruby:: + The ruby version to use +name:: + The gemset name (including +state:: + Either "installed" or "removed". + +OPTIONAL PARAMETERS +------------------- +default:: + If set to anything but "no" (the default), set the give gemset as default. + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Install the gemset @myset for user charles on based on ruby-1.9.3-0 +__rvm_gemset ruby-1.9.3-p0@myset --user charles --state installed + +# Remove the gemset @myset for user john +__rvm_ruby ruby-1.9.3-p0@myset --user john --state removed +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__rvm(7) +- cdist-type__rvm_ruby(7) +- cdist-type__rvm_gem(7) + + +COPYING +------- +Copyright \(C) 2012 Evax Software. Free use of this software is granted under +the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__rvm_gemset/manifest b/conf/type/__rvm_gemset/manifest new file mode 100755 index 00000000..8e25251c --- /dev/null +++ b/conf/type/__rvm_gemset/manifest @@ -0,0 +1,35 @@ +#!/bin/sh +# +# 2012 Evax Software +# +# 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 . +# + +gemset="$__object_id" +ruby="$(echo "$gemset" | cut -d '@' -f 1)" +gemsetname="$(echo "$gemset" | cut -d '@' -f 2)" +user="$(cat "$__object/parameter/user")" +state="$(cat "$__object/explorer/state")" +if [ -f "$__object/parameter/default" ]; then + default="$(cat "$__object/parameter/default")" +else + default="no" +fi + +__rvm $user --state installed +require="__rvm/$user" \ + __rvm_ruby $ruby --user $user --state installed --default $default + diff --git a/conf/type/__rvm_gemset/parameter/optional b/conf/type/__rvm_gemset/parameter/optional new file mode 100644 index 00000000..4ad96d51 --- /dev/null +++ b/conf/type/__rvm_gemset/parameter/optional @@ -0,0 +1 @@ +default diff --git a/conf/type/__rvm_gemset/parameter/required b/conf/type/__rvm_gemset/parameter/required new file mode 100644 index 00000000..5aea6f1e --- /dev/null +++ b/conf/type/__rvm_gemset/parameter/required @@ -0,0 +1,2 @@ +state +user diff --git a/conf/type/__rvm_ruby/explorer/state b/conf/type/__rvm_ruby/explorer/state new file mode 100755 index 00000000..3cf392f1 --- /dev/null +++ b/conf/type/__rvm_ruby/explorer/state @@ -0,0 +1,32 @@ +#!/bin/sh +# +# 2012 Evax Software +# +# 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 . +# + +ruby="$__object_id" +user="$(cat "$__object/parameter/user")" +if su - $user -c "[ ! -d \"\$HOME/.rvm\" ]" ; then + echo "removed" + exit 0 +fi +if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" +rvm list | grep $ruby >/dev/null"; then + echo "installed" +else + echo "removed" +fi diff --git a/conf/type/__rvm_ruby/gencode-remote b/conf/type/__rvm_ruby/gencode-remote new file mode 100755 index 00000000..5dcb0e99 --- /dev/null +++ b/conf/type/__rvm_ruby/gencode-remote @@ -0,0 +1,45 @@ +#!/bin/sh +# +# 2012 Evax Software +# +# 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 . +# + +ruby="$__object_id" +state_is="$(cat "$__object/explorer/state")" +user="$(cat "$__object/parameter/user")" +default="$(cat "$__object/parameter/default")" +state_should="$(cat "$__object/parameter/state")" +if [ "$state_is" != "$state_should" ]; then + case "$state_should" in + installed) + echo "su - $user -c \"source \\\$HOME/.rvm/scripts/rvm;"\ + "rvm install $ruby\"" + case "$default" in + no) + ;; + *) + echo "su - $user -c \"source \\\$HOME/.rvm/scripts/rvm;"\ + "rvm use --default $ruby\"" + ;; + esac + ;; + removed) + echo "su - $user -c \"source \\\$HOME/.rvm/scripts/rvm;"\ + "rvm remove $ruby\"" + ;; + esac +fi diff --git a/conf/type/__rvm_ruby/man.text b/conf/type/__rvm_ruby/man.text new file mode 100644 index 00000000..c3183a7b --- /dev/null +++ b/conf/type/__rvm_ruby/man.text @@ -0,0 +1,54 @@ +cdist-type__rvm_ruby(7) +======================= +Evax Software + + +NAME +---- +cdist-type__rvm_ruby - Manage ruby installations through rvm + + +DESCRIPTION +----------- +RVM is the Ruby enVironment Manager for the Ruby programming language. + + +REQUIRED PARAMETERS +------------------- +user:: + The remote user account to use +state:: + Either "installed" or "removed". + +OPTIONAL PARAMETERS +------------------- +default: + If set to anything but "no" (the default), set the given version as default + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Install ruby 1.9.3 through rvm for user thelonious +__rvm_ruby ruby-1.9.3-p0 --user thelonious --state installed + +# Install ruby 1.9.3 through rvm for user ornette and make it the default +__rvm_ruby ruby-1.9.3-p0 --user ornette --state installed --default yes + +# Remove ruby 1.9.3 for user john +__rvm_ruby ruby-1.9.3-p0 --user john --state removed +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__rvm(7) +- cdist-type__rvm_gemset(7) +- cdist-type__rvm_gem(7) + + +COPYING +------- +Copyright \(C) 2012 Evax Software. Free use of this software is granted under +the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__rvm_ruby/manifest b/conf/type/__rvm_ruby/manifest new file mode 100755 index 00000000..4a4b2ac4 --- /dev/null +++ b/conf/type/__rvm_ruby/manifest @@ -0,0 +1,33 @@ +#!/bin/sh +# +# 2012 Evax Software +# +# 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/default" ]; then + default="$(cat "$__object/parameter/default")" +else + default="no" + echo "$default" > "$__object/parameter/default" +fi + +ruby="$__object_id" +user="$(cat "$__object/parameter/user")" +state="$(cat "$__object/explorer/state")" + +__rvm "$user" --state installed + diff --git a/conf/type/__rvm_ruby/parameter/optional b/conf/type/__rvm_ruby/parameter/optional new file mode 100644 index 00000000..4ad96d51 --- /dev/null +++ b/conf/type/__rvm_ruby/parameter/optional @@ -0,0 +1 @@ +default diff --git a/conf/type/__rvm_ruby/parameter/required b/conf/type/__rvm_ruby/parameter/required new file mode 100644 index 00000000..5aea6f1e --- /dev/null +++ b/conf/type/__rvm_ruby/parameter/required @@ -0,0 +1,2 @@ +state +user From 92a410913e06ce39fafcdf1eebe369489f34dd33 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 13 Jan 2012 13:18:09 +0100 Subject: [PATCH 1189/4212] finish quickstart; next: cdist-installation Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-quickstart.text | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/doc/man/man7/cdist-quickstart.text b/doc/man/man7/cdist-quickstart.text index 5012a331..51943d41 100644 --- a/doc/man/man7/cdist-quickstart.text +++ b/doc/man/man7/cdist-quickstart.text @@ -91,16 +91,10 @@ Continue reading the next sections, to understand what you did and how to create a more sophisticated configuration. -CONTINUE READING ------------------ - - SEE ALSO -------- - cdist(1) -- cdist-type(7) -- cdist-best-practice(7) -- cdist-stages(7)? +- cdist-tutorial(7) COPYING From 8af035cff986f0e5cc9893ab0594c33c0a0859a4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 13 Jan 2012 14:42:44 +0100 Subject: [PATCH 1190/4212] bootstrap, break best practise Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-best-practice.text | 5 +++++ doc/man/man7/cdist-tutorial.text | 8 +++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/doc/man/man7/cdist-best-practice.text b/doc/man/man7/cdist-best-practice.text index dfc06167..79bad2f9 100644 --- a/doc/man/man7/cdist-best-practice.text +++ b/doc/man/man7/cdist-best-practice.text @@ -139,9 +139,14 @@ Have a look at git-remote(1) to adjust the remote configuration, which allows you to push certain branches to certain remotes. +MULTI DEVELOPERS/DIFFERENT TRUST RELATIONSHIP/CENTRAL SERVER APPROACH +--------------------------------------------------------------------- +FIXME before 2.0.5 + SEE ALSO -------- - cdist(1) +- cdist-tutorial(7) COPYING diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 5ef19c14..efdd1e58 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -19,16 +19,14 @@ after the description. cdist-quickstart:: New to cdist? Want to get your hands dirty? Read this. [beginner] -cdist-installation:: +cdist-bootstrap:: The comprehensive guide to your first cdist installation [beginner] - - MANAGING YOUR OWN CONFIGURATION -own branch => very early [before first change?] - => no, first quick intro, then do it right - cdist-initial-manifest:: Learn how to define which hosts get which configurations [beginner] + MANAGING YOUR OWN CONFIGURATION + cdist-type:: Understand how types are working and created [intermediate] From 34fa123ed19856010582027c21d04d64cd2d52c0 Mon Sep 17 00:00:00 2001 From: Evax Software Date: Fri, 13 Jan 2012 15:19:29 +0100 Subject: [PATCH 1191/4212] prevent spurious output in __rvm_gem and __rvm_gemset explorers --- conf/type/__rvm_gem/explorer/state | 6 +++--- conf/type/__rvm_gemset/explorer/state | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/conf/type/__rvm_gem/explorer/state b/conf/type/__rvm_gem/explorer/state index d4cca9cb..b80a2a9e 100755 --- a/conf/type/__rvm_gem/explorer/state +++ b/conf/type/__rvm_gem/explorer/state @@ -28,10 +28,10 @@ if su - $user -c "[ ! -d \"\$HOME/.rvm\" ]" ; then exit 0 fi if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" -rvm list | grep $ruby"; then +rvm list | grep $ruby > /dev/null"; then if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" -rvm use $ruby; rvm gemset list | grep $gemsetname > /dev/null && -rvm use $gemset && gem list | grep $gem"; then +rvm use $ruby > /dev/null; rvm gemset list | grep $gemsetname > /dev/null && +rvm use $gemset > /dev/null && gem list | grep $gem > /dev/null"; then echo "installed" exit 0 fi diff --git a/conf/type/__rvm_gemset/explorer/state b/conf/type/__rvm_gemset/explorer/state index 132c376d..04d5af2d 100755 --- a/conf/type/__rvm_gemset/explorer/state +++ b/conf/type/__rvm_gemset/explorer/state @@ -27,9 +27,9 @@ if su - $user -c "[ ! -d \"\$HOME/.rvm\" ]" ; then exit 0 fi if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" -rvm list | grep $ruby"; then +rvm list | grep $ruby > /dev/null"; then if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" -rvm use $ruby; rvm gemset list | grep $gemsetname > /dev/null"; then +rvm use $ruby > /dev/null; rvm gemset list | grep $gemsetname > /dev/null"; then echo "installed" exit 0 fi From 84740cf651458f5d5d1a02800cbf0a9c0df31559 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 13 Jan 2012 16:30:46 +0100 Subject: [PATCH 1192/4212] add beginning of cdist-installation Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-installation.text | 110 +++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 doc/man/man7/cdist-installation.text diff --git a/doc/man/man7/cdist-installation.text b/doc/man/man7/cdist-installation.text new file mode 100644 index 00000000..45bd7907 --- /dev/null +++ b/doc/man/man7/cdist-installation.text @@ -0,0 +1,110 @@ +cdist-bootstrap(7) +================== +Nico Schottelius + + +NAME +---- +cdist-bootstrap - how to setup the cdist environment + + +INTRODUCTION +------------ +This document describes the usual steps recommended for a new +cdist setup. It is recommended that you have read and understood +cdist-quickstart(7) before digging into this. + + +LOCATION +--------- +First of all, you should think about where to store your configuration +database and who will be accessing or changing it. Secondly you have to +think about where to configure your hosts from, which may be a different +location. + +For starters, having cdist (which includes the configuration database) on +your notebook should be fine. +Additionally an external copy of the git repository the configuration +relies in is recommended, for use as backup as well to allow easy collaboration +with others. + +For more sophisticated setups developing cdist configurations with multiple +people, have a look at cdist-best-practice(7). + + +SETUP WORKING DIRECTORY +----------------------- +I assume you have a fresh copy of the cdist tree in ~/cdist, cloned from +one of the official urls (see cdist-quickstart(7) if you don't). +Entering the command "git branch" should show you "* master", which indicates +you are on the **master** branch. + +The master branch reflects the latest development of cdist. As this is the +development branch, it may or may not work. There are also version branches +available, which are kept in a stable state. Let's use **git branch -r** +to list all branches: + +-------------------------------------------------------------------------------- +cdist% git branch -r + origin/1.0 + origin/1.1 + origin/1.2 + origin/1.3 + origin/1.4 + origin/1.5 + origin/1.6 + origin/1.7 + origin/2.0 + origin/HEAD -> origin/master + origin/archive_shell_function_approach + origin/master +-------------------------------------------------------------------------------- + +So **2.0** is the latest version branch in this example. +All versions (2.0.x) within one version branch (2.0) are compatible to each +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: +master contains more recent changes, newer types, but may also break. +The versions branches are stable, but thus may miss the latest features. +Your decision can be changed later on, but may result in merge conflicts, +which you'd have 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 +local changes. I usually name it by the company/area I am working for: +ethz-systems, localch, customerX, ... But this is pretty much up to you. + +In this tutorial I use the branch **mycompany**: + + +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- + + + + + +own account / server, one/multiple users + +clone +update +branches +own branch => very early [before first change?] +=> no, first quick intro, then do it right +ssh-keys + +# Add keys (requires password for every identity file) + + +SEE ALSO +-------- +- cdist(1) +- cdist-tutorial(7) + + +COPYING +------- +Copyright \(C) 2012 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). From 3e1ae7948ddd2f56ce79ffa733cf9bd95179d69f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 13 Jan 2012 16:31:03 +0100 Subject: [PATCH 1193/4212] rename installation to bootstrap Signed-off-by: Nico Schottelius --- doc/man/man7/{cdist-installation.text => cdist-bootstrap.text} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/man/man7/{cdist-installation.text => cdist-bootstrap.text} (100%) diff --git a/doc/man/man7/cdist-installation.text b/doc/man/man7/cdist-bootstrap.text similarity index 100% rename from doc/man/man7/cdist-installation.text rename to doc/man/man7/cdist-bootstrap.text From 74f9a6e98a4be93076beeafe2d9a91be6434e928 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 13 Jan 2012 17:34:16 +0100 Subject: [PATCH 1194/4212] create working branch Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-bootstrap.text | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/doc/man/man7/cdist-bootstrap.text b/doc/man/man7/cdist-bootstrap.text index 45bd7907..c6f91ac3 100644 --- a/doc/man/man7/cdist-bootstrap.text +++ b/doc/man/man7/cdist-bootstrap.text @@ -32,8 +32,8 @@ For more sophisticated setups developing cdist configurations with multiple people, have a look at cdist-best-practice(7). -SETUP WORKING DIRECTORY ------------------------ +SETUP WORKING DIRECTORY AND BRANCH +---------------------------------- I assume you have a fresh copy of the cdist tree in ~/cdist, cloned from one of the official urls (see cdist-quickstart(7) if you don't). Entering the command "git branch" should show you "* master", which indicates @@ -77,15 +77,18 @@ ethz-systems, localch, customerX, ... But this is pretty much up to you. In this tutorial I use the branch **mycompany**: - -------------------------------------------------------------------------------- - +cdist% git checkout -b mycompany origin/master +Branch mycompany set up to track remote branch master from origin. +Switched to a new branch 'mycompany' +cdist-user% git branch + master +* mycompany -------------------------------------------------------------------------------- - own account / server, one/multiple users clone From 0a3705c4f2facd8a6f01aeec1bfe527f2bc2cde2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 13 Jan 2012 22:32:27 +0100 Subject: [PATCH 1195/4212] finish cdist bootstrap Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-bootstrap.text | 53 +++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/doc/man/man7/cdist-bootstrap.text b/doc/man/man7/cdist-bootstrap.text index c6f91ac3..19e864dd 100644 --- a/doc/man/man7/cdist-bootstrap.text +++ b/doc/man/man7/cdist-bootstrap.text @@ -81,24 +81,59 @@ In this tutorial I use the branch **mycompany**: cdist% git checkout -b mycompany origin/master Branch mycompany set up to track remote branch master from origin. Switched to a new branch 'mycompany' -cdist-user% git branch +cdist-user% git branch master * mycompany -------------------------------------------------------------------------------- +From now on, you can use git as usual to commit your changes in your own branch. +PUBLISHING THE CONFIGURATION +---------------------------- +Usually a development machine like a notebook should be considered +temporary only. For this reason and to enable shareability, the configuration +should be published to another device as early as possible. The following +example shows how to publish the configuration to another host that is +reachable via ssh and has git installed: -own account / server, one/multiple users +-------------------------------------------------------------------------------- +# Create bare git repository on the host named "loch" +cdist% ssh loch "GIT_DIR=/home/nutzer/cdist git init" +Initialized empty Git repository in /home/nutzer/cdist/ -clone -update -branches -own branch => very early [before first change?] -=> no, first quick intro, then do it right -ssh-keys +# Add remote git repo to git config +cdist% git remote add loch loch:/home/nutzer/cdist -# Add keys (requires password for every identity file) +# Configure the mycompany branch to push to loch +cdist% git config branch.mycompany.remote loch + +# Configure mycompany branch to push into remote master branch +cdist% git config branch.mycompany.merge refs/heads/master + +# Push mycompany branch to remote branch master initially +cdist% git push loch mycompany:refs/heads/master +-------------------------------------------------------------------------------- + +Now you have setup the git repository to synchronise the **mycompany** +branch with the **master** branch on the host **loch**. Thus you can commit +as usual in your branch and push out changes by entering ***git push***. + + +UPDATING FROM ORIGIN +-------------------- +Whenever you want to update your cdist installation, you can use git to do so: + +-------------------------------------------------------------------------------- +# Update git repository with latest changes from origin +cdist% git fetch origin + +# Update current branch with master branch from origin +cdist% git merge origin/master + +# Alternative: Update current branch with 2.0 branch from origin +cdist% git merge origin/2.0 +-------------------------------------------------------------------------------- SEE ALSO From a9162bd0e8f64ceb978d7bb936f031eb7cd03ec1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 14 Jan 2012 11:29:58 +0100 Subject: [PATCH 1196/4212] title short Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-bootstrap.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man/man7/cdist-bootstrap.text b/doc/man/man7/cdist-bootstrap.text index 19e864dd..7e1bff0f 100644 --- a/doc/man/man7/cdist-bootstrap.text +++ b/doc/man/man7/cdist-bootstrap.text @@ -5,7 +5,7 @@ Nico Schottelius NAME ---- -cdist-bootstrap - how to setup the cdist environment +cdist-bootstrap - setup cdist environment INTRODUCTION From eb83190efd72c1047771a31eb1fd039547700af7 Mon Sep 17 00:00:00 2001 From: Evax Software Date: Mon, 16 Jan 2012 12:29:51 +0100 Subject: [PATCH 1197/4212] use grep's -q option --- conf/type/__rvm_gem/explorer/state | 6 +++--- conf/type/__rvm_gemset/explorer/state | 4 ++-- conf/type/__rvm_ruby/explorer/state | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/conf/type/__rvm_gem/explorer/state b/conf/type/__rvm_gem/explorer/state index b80a2a9e..e7f50247 100755 --- a/conf/type/__rvm_gem/explorer/state +++ b/conf/type/__rvm_gem/explorer/state @@ -28,10 +28,10 @@ if su - $user -c "[ ! -d \"\$HOME/.rvm\" ]" ; then exit 0 fi if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" -rvm list | grep $ruby > /dev/null"; then +rvm list | grep -q $ruby"; then if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" -rvm use $ruby > /dev/null; rvm gemset list | grep $gemsetname > /dev/null && -rvm use $gemset > /dev/null && gem list | grep $gem > /dev/null"; then +rvm use $ruby > /dev/null; rvm gemset list | grep -q $gemsetname && +rvm use $gemset > /dev/null && gem list | grep -q $gem"; then echo "installed" exit 0 fi diff --git a/conf/type/__rvm_gemset/explorer/state b/conf/type/__rvm_gemset/explorer/state index 04d5af2d..43667126 100755 --- a/conf/type/__rvm_gemset/explorer/state +++ b/conf/type/__rvm_gemset/explorer/state @@ -27,9 +27,9 @@ if su - $user -c "[ ! -d \"\$HOME/.rvm\" ]" ; then exit 0 fi if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" -rvm list | grep $ruby > /dev/null"; then +rvm list | grep -q $ruby"; then if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" -rvm use $ruby > /dev/null; rvm gemset list | grep $gemsetname > /dev/null"; then +rvm use $ruby > /dev/null; rvm gemset list | grep -q $gemsetname"; then echo "installed" exit 0 fi diff --git a/conf/type/__rvm_ruby/explorer/state b/conf/type/__rvm_ruby/explorer/state index 3cf392f1..1fc9e0a8 100755 --- a/conf/type/__rvm_ruby/explorer/state +++ b/conf/type/__rvm_ruby/explorer/state @@ -25,7 +25,7 @@ if su - $user -c "[ ! -d \"\$HOME/.rvm\" ]" ; then exit 0 fi if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" -rvm list | grep $ruby >/dev/null"; then +rvm list | grep -q $ruby"; then echo "installed" else echo "removed" From 8cc0d6f0e780b3bdf1ac9f5d801a69ddf4256f73 Mon Sep 17 00:00:00 2001 From: Evax Software Date: Mon, 16 Jan 2012 12:30:19 +0100 Subject: [PATCH 1198/4212] properly handle rvm and ruby dependencies --- conf/type/__rvm/manifest | 25 +++++++++++++++++ conf/type/__rvm_ruby/manifest | 52 ++++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100755 conf/type/__rvm/manifest diff --git a/conf/type/__rvm/manifest b/conf/type/__rvm/manifest new file mode 100755 index 00000000..8e63a2c5 --- /dev/null +++ b/conf/type/__rvm/manifest @@ -0,0 +1,25 @@ +#!/bin/sh +# +# 2012 Evax Software +# +# 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 . +# + +# rvm core dependencies +__package bash --state installed +__package curl --state installed +__package git-core --state installed +__package patch --state installed diff --git a/conf/type/__rvm_ruby/manifest b/conf/type/__rvm_ruby/manifest index 4a4b2ac4..c6e31244 100755 --- a/conf/type/__rvm_ruby/manifest +++ b/conf/type/__rvm_ruby/manifest @@ -29,5 +29,55 @@ ruby="$__object_id" user="$(cat "$__object/parameter/user")" state="$(cat "$__object/explorer/state")" -__rvm "$user" --state installed +apt_ruby="build-essential openssl libreadline6 libreadline6-dev curl git-core +zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 +libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison +subversion" +apt_jruby="curl g++ openjdk-6-jre-headless" +apt_jruby_head="ant openjdk-6-jdk" +apt_ironruby="curl mono-2.0-devel" +emerge_ruby="libiconv readline zlib openssl curl git libyaml sqlite libxslt +libtool gcc autoconf automake bison m4" +emerge_jruby="dev-java/sun-jdk dev-java/sun-jre-bin" +emerge_ironruby="dev-lang/mono" + +pacman_ruby="gcc patch curl zlib readline libxml2 libxslt git autoconf +diffutils make libtool bison subversion" +pacman_jruby="jdk jre curl" +pacman_ironruby="mono" + +yum_ruby="gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel +libffi-devel openssl-devel make bzip2 autoconf automake libtool bison +iconv-devel" +yum_jruby="java" + +os="$(cat "$__global/explorer/os")" +case "$os" in + archlinux) type="pacman" ;; + debian|ubuntu) type="apt" ;; + gentoo) type="emerge" ;; + fedora|redhat|centos) type="yum" ;; + *);; +esac +case "$ruby" in + ruby-head*) + deps_list="${type}_ruby_head" + ;; + ruby*) + deps_list="${type}_ruby" + ;; + jruby-head*) + deps_list="${type}_jruby_head" + ;; + jruby*) + deps_list="${type}_jruby" + ;; + ironruby*) + deps_list="${type}_ironruby" + ;; +esac +deps=$(eval echo \$$deps_list) +for p in $deps; do __package_${type} $p --state installed; done + +__rvm "$user" --state installed From e4100e324adc1190751731ddc0994a64a40ab92d Mon Sep 17 00:00:00 2001 From: Evax Software Date: Mon, 16 Jan 2012 18:04:15 +0100 Subject: [PATCH 1199/4212] better handling of virtual packages in __package_apt --- conf/type/__package_apt/explorer/pkg_status | 9 ++++- conf/type/__package_apt/gencode-remote | 39 +++++++++++---------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/conf/type/__package_apt/explorer/pkg_status b/conf/type/__package_apt/explorer/pkg_status index 86b94825..249e4638 100755 --- a/conf/type/__package_apt/explorer/pkg_status +++ b/conf/type/__package_apt/explorer/pkg_status @@ -28,4 +28,11 @@ else fi # Except dpkg failing, if package is not known / installed -dpkg -s "$name" 2>/dev/null || exit 0 +packages="$(apt-cache showpkg "$name" | grep -A 20 "Reverse Provides:" | sed 1d | cut -d ' ' -f 1) $name" +for p in $packages; do + if [ -n "$(dpkg -s "$p" 2>/dev/null | grep "^Status: install ok installed$")" ]; then + echo "installed $p" + exit 0 + fi +done +echo "removed" diff --git a/conf/type/__package_apt/gencode-remote b/conf/type/__package_apt/gencode-remote index a5384ee3..594ab8cb 100755 --- a/conf/type/__package_apt/gencode-remote +++ b/conf/type/__package_apt/gencode-remote @@ -27,26 +27,29 @@ else name="$__object_id" fi -state="$(cat "$__object/parameter/state")" -is_installed="$(grep "^Status: install ok installed" "$__object/explorer/pkg_status" || true)" +state_should="$(cat "$__object/parameter/state")" +state_is="$(cat "$__object/explorer/pkg_status")" +case "$state_is" in + installed*) + name="$(echo "$state_is" | cut -d ' ' -f 2)" + state_is="installed" + ;; +esac aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes" -case "$state" in - installed) - # Install only if non-existent - if [ -z "$is_installed" ]; then +if [ "$state_is" != "$state_should" ]; then + case "$state_should" in + installed) echo $aptget install \"$name\" - fi - ;; - removed) - # Remove only if existent - if [ -n "$is_installed" ]; then + ;; + removed) echo $aptget remove \"$name\" - fi - ;; - *) - echo "Unknown state: $state" >&2 - exit 1 - ;; -esac + ;; + *) + echo "Unknown state: $state" >&2 + exit 1 + ;; + esac +fi + From c8e4d51396bedae937348334e7951fa5b5853a83 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 16 Jan 2012 18:11:28 +0100 Subject: [PATCH 1200/4212] manifest, not initial Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 3 +-- doc/man/man7/cdist-best-practice.text | 1 - doc/man/man7/cdist-manifest.text | 39 ++++++++++++++++----------- doc/man/man7/cdist-tutorial.text | 4 +-- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 64ff681b..e1c19869 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,7 +1,6 @@ - write tutorial - containing many links?! - - quickstart - - cdist-environment/startup/initial-setup (setup env) + - cdist-manifest - cdist-type - ... - cdist-hacker diff --git a/doc/man/man7/cdist-best-practice.text b/doc/man/man7/cdist-best-practice.text index 79bad2f9..6e5a476c 100644 --- a/doc/man/man7/cdist-best-practice.text +++ b/doc/man/man7/cdist-best-practice.text @@ -136,7 +136,6 @@ The following **.git/config** is taken from a a real world scenario: -------------------------------------------------------------------------------- Have a look at git-remote(1) to adjust the remote configuration, which allows -you to push certain branches to certain remotes. MULTI DEVELOPERS/DIFFERENT TRUST RELATIONSHIP/CENTRAL SERVER APPROACH diff --git a/doc/man/man7/cdist-manifest.text b/doc/man/man7/cdist-manifest.text index e7e783a3..917ea697 100644 --- a/doc/man/man7/cdist-manifest.text +++ b/doc/man/man7/cdist-manifest.text @@ -5,7 +5,20 @@ Nico Schottelius NAME ---- -cdist-manifest - Define types to be used +cdist-manifest - Using types + +DESCRIPTION +----------- +Manifests exist to define which configurations should be applied to a specific +host as well as to define which configurations should be applied within a +type. Manifests are executed locally and the resulting objects are stored in +an internal database. + +The same object can be redefined in multiple different manifests as long as +the parameters are exactly the same. + +In general, manifests are used to define which types are used depending +on given conditions. DEFINE STATE IN THE INITIAL MANIFEST @@ -47,23 +60,15 @@ command. Use **ls conf/type** to get a list of available types. If you have setup the MANPATH correctly as, you can use **man cdist-reference** to access the reference with pointers to the manpages. +INITIAL VS. TYPE MANIFEST +------------------------- -DESCRIPTION ------------ -Manifests exist to define which configurations should be applied to a specific -host as well as to define which configurations should be applied within a -type. Manifests are executed locally and the resulting objects are stored in -an internal database. - -The same object can be redefined in multiple different manifests as long as -the parameters are exactly the same. - -In general, manifests are used to define which types are used depending -on given conditions. +MANAGING YOUR OWN CONFIGURATION -EXAMPLE -------- + +EXAMPLES +-------- The initial manifest may for instance contain the following code: -------------------------------------------------------------------------------- @@ -106,10 +111,14 @@ require="__file/etc/cdist-configured __link/tmp/cdist-testfile" \ -------------------------------------------------------------------------------- +If you do not specify + +FIXME: autorequire SEE ALSO -------- - cdist-type(7) +- cdist-tutorial(7) COPYING diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index efdd1e58..e50ccc3c 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -22,11 +22,9 @@ cdist-quickstart:: cdist-bootstrap:: The comprehensive guide to your first cdist installation [beginner] -cdist-initial-manifest:: +cdist-manifest:: Learn how to define which hosts get which configurations [beginner] - MANAGING YOUR OWN CONFIGURATION - cdist-type:: Understand how types are working and created [intermediate] From 9c2ca52382d50dc259eaf230bee92b32c0cb97e5 Mon Sep 17 00:00:00 2001 From: Tim Kersten Date: Mon, 16 Jan 2012 23:50:12 +0000 Subject: [PATCH 1201/4212] When removing a ppa, don't forget deb-src line (Also remove the [ppa-name].list file if empty.) --- .../__apt_ppa/files/remove-apt-repository | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/conf/type/__apt_ppa/files/remove-apt-repository b/conf/type/__apt_ppa/files/remove-apt-repository index b57a07f6..3eb7d491 100755 --- a/conf/type/__apt_ppa/files/remove-apt-repository +++ b/conf/type/__apt_ppa/files/remove-apt-repository @@ -7,13 +7,19 @@ # 1: if not # 2: on other error - +import os import sys from aptsources import distro, sourceslist from softwareproperties import ppa from softwareproperties.SoftwareProperties import SoftwareProperties +def remove_if_empty(file_name): + with open(file_name, 'r') as f: + if f.read().strip(): + return + os.unlink(file_name) + def remove_repository(repository): #print 'repository:', repository codename = distro.get_distro().codename @@ -21,11 +27,18 @@ def remove_repository(repository): (line, file) = ppa.expand_ppa_line(repository.strip(), codename) #print 'line:', line #print 'file:', file - source_entry = sourceslist.SourceEntry(line, file) + deb_source_entry = sourceslist.SourceEntry(line, file) + src_source_entry = sourceslist.SourceEntry('deb-src{}'.format(line[3:]), file) try: sp = SoftwareProperties() - sp.remove_source(source_entry) + sp.remove_source(deb_source_entry) + try: + # If there's a deb-src entry, remove that too + sp.remove_source(src_source_entry) + except: + pass + remove_if_empty(file) return True except ValueError: print >> sys.stderr, "Error: '%s' doesn't exists in a sourcelist file" % line From 5e00ac702a5d65141afc9e4b3409120546be7f66 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 17 Jan 2012 21:57:32 +0100 Subject: [PATCH 1202/4212] finish rewrite of cdist-manifest Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-manifest.text | 127 ++++++++++++++++++++----------- 1 file changed, 82 insertions(+), 45 deletions(-) diff --git a/doc/man/man7/cdist-manifest.text b/doc/man/man7/cdist-manifest.text index 917ea697..1f0e253d 100644 --- a/doc/man/man7/cdist-manifest.text +++ b/doc/man/man7/cdist-manifest.text @@ -5,14 +5,38 @@ Nico Schottelius NAME ---- -cdist-manifest - Using types +cdist-manifest - (Re-)Use types + DESCRIPTION ----------- -Manifests exist to define which configurations should be applied to a specific -host as well as to define which configurations should be applied within a -type. Manifests are executed locally and the resulting objects are stored in -an internal database. +Manifests are used to define which objects to create. +Objects are instances of **types**, like in object orientated 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***. + +All available types can be found in the **conf/type/** directory, +use **ls conf/type** to get the list of available types. If you have +setup the MANPATH correctly, you can use **man cdist-reference** to access +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 + +# Same with the __directory type + __directory /tmp/cdist --state present +-------------------------------------------------------------------------------- + +These two lines create objects, which will later be used to realise the +configuration on the target host. + +Manifests are executed locally as a shell script using **/bin/sh -e**. +The resulting objects are stored in an internal database. The same object can be redefined in multiple different manifests as long as the parameters are exactly the same. @@ -21,17 +45,19 @@ In general, manifests are used to define which types are used depending on given conditions. +INITIAL AND TYPE MANIFESTS +-------------------------- +Cdist nows about two types of manifests: The initial manifest and type +manifests. The initial manifest is used to define, which configurations +to apply to which hosts. The type manifests are used to create objects +from types. More about manifests in types can be found in cdist-type(7). + + 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. Objects are instances of -**types**, like in object orientated programming languages. -An object is represented by the -type + slash + object name: ***__file/etc/cdist-configured*** is an -object of the type ***__file*** with the name ***etc/cdist-configured***. - -Cdist searches for the initial manifest at **conf/manifest/init** and -executes it as a shell script using **/bin/sh -e**. +**objects** to configure on the selected host. +Cdist searches for the initial manifest at **conf/manifest/init**. Within this initial manifest, you define, which objects should be created on which host. To distinguish between hosts, you can use the @@ -56,15 +82,51 @@ is only created on the host ***localhost***. As you can see, there is no magic involved, the manifest is simple shell code that utilises cdist types. Every available type can be executed like a normal -command. Use **ls conf/type** to get a list of available types. If you have -setup the MANPATH correctly as, you can use **man cdist-reference** to access -the reference with pointers to the manpages. +command. -INITIAL VS. TYPE MANIFEST -------------------------- -MANAGING YOUR OWN CONFIGURATION +SPLITTING UP THE INITIAL MANIFEST +--------------------------------- +If you want to split up your initial manifest, you can create other shell +scripts in **conf/manifest/** and include them in **conf/manifest/init**. +Cdist provides the environment variable ***__manifest*** to reference to +the directory containing the initial manifest (see cdist-reference(7)). +The following example would include every file with a **.sh** suffix: + +-------------------------------------------------------------------------------- +# Include *.sh +for manifest in $__manifest/*.sh; do + # And source scripts into our shell environment + . "$manifest" +done +-------------------------------------------------------------------------------- + + +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. + +-------------------------------------------------------------------------------- +# No dependency +__file /etc/cdist-configured + +# Require above object +require="__file/etc/cdist-configured" __link /tmp/cdist-testfile \ + --source /etc/cdist-configured --type symbolic + +# Require two objects +require="__file/etc/cdist-configured __link/tmp/cdist-testfile" \ + __file /tmp/cdist-another-testfile + + +-------------------------------------------------------------------------------- + +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. EXAMPLES @@ -89,36 +151,11 @@ The manifest of the type "nologin" may look like this: __file /etc/nologin --type file --source "$__type/files/default.nologin" -------------------------------------------------------------------------------- -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. - - --------------------------------------------------------------------------------- -# No dependency -__file /etc/cdist-configured - -# Require above object -require="__file/etc/cdist-configured" __link /tmp/cdist-testfile \ - --source /etc/cdist-configured --type symbolic - -# Require two objects -require="__file/etc/cdist-configured __link/tmp/cdist-testfile" \ - __file /tmp/cdist-another-testfile - - --------------------------------------------------------------------------------- - -If you do not specify - -FIXME: autorequire SEE ALSO -------- -- cdist-type(7) - cdist-tutorial(7) +- cdist-type(7) COPYING From 3d8f26b42a5a8e6feb2ee0144840ce2e219ac734 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 17 Jan 2012 23:22:29 +0100 Subject: [PATCH 1203/4212] cleanup cdist-type Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-tutorial.text | 25 ---------------- doc/man/man7/cdist-type.text | 49 ++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 46 deletions(-) diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index e50ccc3c..24846876 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -28,31 +28,6 @@ cdist-manifest:: cdist-type:: Understand how types are working and created [intermediate] - CREATING YOUR FIRST OWN TYPE - ---------------------------- - => short example, reference to cdist-type(7)! - => motivation - - Use a type to bundle functionalitY - - - - Debug with var - can be used by yourself - __debug:: - If this variable is setup, cdist runs in debug mode. - You can use this information, to only output stuff in debug - mode as well. - Available for: initial manifest, type manifest, gencode, code - - - USING EXPLORERS - --------------- - cdist-explorer.text - - DEBUGGING YOUR TYPES - -------------------- - - cdist-best-practice:: Hints from real life experience to help you to organise cdist [intermediate] diff --git a/doc/man/man7/cdist-type.text b/doc/man/man7/cdist-type.text index 1dbb4a1d..48d412f1 100644 --- a/doc/man/man7/cdist-type.text +++ b/doc/man/man7/cdist-type.text @@ -37,11 +37,12 @@ __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 me used only once. This -is useful for types which can be used only once on a system. If a type -can only be used once, it does not take an +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: -------------------------------------------------------------------------------- @@ -53,7 +54,6 @@ __myfancysingleton --colour green -------------------------------------------------------------------------------- - HOW TO WRITE A NEW TYPE ----------------------- A type consists of @@ -65,17 +65,16 @@ A type consists of - gencode (optional) Types are stored below conf/type/. Their name should always be prefixed with -two underscores (__) to prevent collisions with other binaries in $PATH. +two underscores (__) to prevent collisions with other executables in $PATH. -To begin a new type from a template, execute "cdist-type-template __NAME" -and cd conf/type/__NAME. +To begin a new type, just create the directory **conf/type/__NAME**. DEFINING PARAMETERS ------------------- Every type consists of optional and required parameters, which must -be created in a newline seperated file in parameters/required and -parameters/optional. If either or both missing, the type will have +be created in a newline seperated file in ***parameters/required*** and +***parameters/optional***. If either or both missing, the type will have no required, no optional or no parameters at all. Example: @@ -110,21 +109,27 @@ 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. +to execute it. For more information about manifests see cdist-manifest(7). SINGLETON - ONLY 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. This will also change the way your type must be called: +directory: + +-------------------------------------------------------------------------------- +touch conf/type/__NAME/singleton +-------------------------------------------------------------------------------- + +This will also change the way your type must be called: -------------------------------------------------------------------------------- __YOURTYPE --parameter value -------------------------------------------------------------------------------- -As you can see, the ID is omitted, because it does not make any sense, if your -type can be used only once. +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 @@ -134,7 +139,7 @@ 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 real type __file): +client, like this (shortened version from the type __file): -------------------------------------------------------------------------------- if [ -f "$__object/parameter/destination" ]; then @@ -151,15 +156,15 @@ fi WRITING THE GENCODE SCRIPT -------------------------- -There are two gencode scripts: gencode-local and gencode-remote. +There are two gencode scripts: ***gencode-local*** and ***gencode-remote***. The output of gencode-local is executed locally, whereas the output of gencode-remote is executed on the target. -The gencode script can make use of the parameters, the global explorers -and the type specific explorers. The output (stdout) of this script is +The gencode scripts can make use of the parameters, the global explorers +and the type specific explorers. The output (stdout) of these script is saved by cdist and will be executed on the target. -If the gencode script encounters an error, it should print diagnostic +If the gencode scripts encounter 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: @@ -181,13 +186,14 @@ 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. +"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 @@ -203,9 +209,10 @@ SEE ALSO -------- - cdist-explorer(7) - cdist-stages(7) +- cdist-tutorial(7) COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is +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 cae332dcf8fe157ba4d3565d33cdebe7f39a14c3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 17 Jan 2012 23:41:01 +0100 Subject: [PATCH 1204/4212] document multi developers/different trust levels setup Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-best-practice.text | 17 ++++++++++++++--- doc/man/man7/cdist-tutorial.text | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/doc/man/man7/cdist-best-practice.text b/doc/man/man7/cdist-best-practice.text index 6e5a476c..bbfd084a 100644 --- a/doc/man/man7/cdist-best-practice.text +++ b/doc/man/man7/cdist-best-practice.text @@ -138,9 +138,20 @@ The following **.git/config** is taken from a a real world scenario: Have a look at git-remote(1) to adjust the remote configuration, which allows -MULTI DEVELOPERS/DIFFERENT TRUST RELATIONSHIP/CENTRAL SERVER APPROACH ---------------------------------------------------------------------- -FIXME before 2.0.5 +MULTIPLE DEVELOPERS WITH DIFFERENT TRUST +---------------------------------------- +If you are working in an environment that requires different people to +work on the same configuration, but having different privileges, you can +implement this scenario with a gateway host and sudo: + +- Create a dedicated user (for instance **cdist**) +- Setup the ssh-pubkey for this user that has the right to configure all hosts +- Create a wrapper to update the cdist configuration in ~cdist/cdist +- Allow every developer to execute this script via sudo as the user cdist +- Allow run of cdist as user cdist on specific hosts on a per user/group base + - f.i. nico ALL=(ALL) NOPASSWD: /home/cdist/bin/cdist config hostabc + +For more details consult sudoers(5) SEE ALSO -------- diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 24846876..2bc703ce 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -65,7 +65,7 @@ SEE ALSO - cdist(1) - cdist-type(7) - cdist-best-practice(7) -- cdist-stages(7)? +- cdist-stages(7) - Brave New World by Aldous Huxley COPYING From 22f242b1d99fb14241dc6942a693a723ca18ef54 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 17 Jan 2012 23:53:58 +0100 Subject: [PATCH 1205/4212] huge documentation cleanup Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 22 ++++++---------------- doc/man/cdist-reference.text.sh | 8 ++++---- doc/man/man1/cdist.text | 2 +- doc/man/man7/cdist-explorer.text | 4 ++-- doc/man/man7/cdist-hacker.text | 8 +++++--- doc/man/man7/cdist-stages.text | 25 +++++-------------------- doc/man/man7/cdist-tutorial.text | 16 ---------------- 7 files changed, 23 insertions(+), 62 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index e1c19869..0d1b53bb 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,23 +1,13 @@ -- write tutorial - - containing many links?! - - cdist-manifest - - cdist-type - - ... - - cdist-hacker - - - remove cdist(7) reference everywhere - - check cross links - - check other docs: - - cdist-best-practice.text - - cdist-explorer.text - cdist-hacker.text - - cdist-manifest.text - - cdist-reference.text - cdist-stages.text - - cdist-type.text - 51 -> ssh stuff double: cdist-best-practice and here +- release 2.0.5 +- cdist-cache:: + How to get use information about the hosts we have been working on [advanced] +cdist-scaling-tuning:: + How to scale out with cdist and which tunings to apply. [advanced] + -------------------------------------------------------------------------------- diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index a1757c43..6b4e786f 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -74,7 +74,7 @@ conf/manifest/init:: conf/manifest/*:: All other files in this directory are not directly used by cdist, but you can seperate configuration mappings, if you have a lot of code in the - manifest/init file. This may also be very helpful to have different admins + manifest/init file. This may also be helpful to have different admins maintain different groups of hosts. conf/explorer/:: @@ -90,7 +90,7 @@ conf/type//:: This directory is referenced by the variable __type (see below). conf/type//man.text:: - Manpage in Asciidoc format (nequired for inclusion into upstream) + Manpage in Asciidoc format (required for inclusion into upstream) conf/type//manifest:: Used to generate additional objects from a type. @@ -199,7 +199,7 @@ __type_explorer:: SEE ALSO -------- -- cdist(7) +- cdist(1) COPYING diff --git a/doc/man/man1/cdist.text b/doc/man/man1/cdist.text index 03948036..99c28f8b 100644 --- a/doc/man/man1/cdist.text +++ b/doc/man/man1/cdist.text @@ -99,5 +99,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is +Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man7/cdist-explorer.text b/doc/man/man7/cdist-explorer.text index b9c342a9..2c25d845 100644 --- a/doc/man/man7/cdist-explorer.text +++ b/doc/man/man7/cdist-explorer.text @@ -39,7 +39,7 @@ A very simple explorer may look like this: hostname -------------------------------------------------------------------------------- -Which is in practise the "hostname" explorer. +Which is in practise the ***hostname*** explorer. A type explorer, which could check for the status of a package may look like this: @@ -64,5 +64,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2010-2011 Nico Schottelius. Free use of this software is +Copyright \(C) 2010-2012 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man7/cdist-hacker.text b/doc/man/man7/cdist-hacker.text index f8e3730e..9bdf63d4 100644 --- a/doc/man/man7/cdist-hacker.text +++ b/doc/man/man7/cdist-hacker.text @@ -23,7 +23,7 @@ REPORTING BUGS -------------- If you believe you've found a bug and verified that it is in the latest version, drop a mail to the cdist mailing list, -subject prefixed with "[BUG] ". +subject prefixed with "[BUG] " or create an issue on github. CODING CONVENTIONS (EVERYWHERE) @@ -31,6 +31,8 @@ CODING CONVENTIONS (EVERYWHERE) If something should be better done or needs to fixed, add the word FIXME nearby, so grepping for FIXME gives all positions that need to be fixed. +Indention is 4 spaces (welcome to the python world). + HOW TO SUBMIT STUFF FOR INCLUSION INTO UPSTREAM CDIST ----------------------------------------------------- @@ -47,7 +49,7 @@ work nor kill the authors brain: - Code to be included should be branched of the upstream "master" branch - Exception: Bugfixes to a version branch - On a merge request, always name the branch I should pull from -- Always ensure **all** manpages build: ./build.sh man +- 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 the other needs to be improved. @@ -73,5 +75,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is +Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man7/cdist-stages.text b/doc/man/man7/cdist-stages.text index 8ac30015..c1b73a8d 100644 --- a/doc/man/man7/cdist-stages.text +++ b/doc/man/man7/cdist-stages.text @@ -9,20 +9,8 @@ cdist-stages - Stages used during configuration deployment DESCRIPTION ----------- -Starting the execution of deployment with cdist-deploy-to(1), cdist passes -through different stages, each can be triggered and debugged on its own. -Reading the source of the cdist-deploy-to executable shows the scripts -responsible for each stage. - - -STAGE 0: INTERNAL PREPERATION ------------------------------ -Before running the user facing stages, cdist prepares the target host -to contain cdist binaries and creates a clean environment for the -configuration run. - -Related documentation: - - Source of cdist-deploy-to +Starting the execution of deployment with cdist, cdist passes +through different stages. STAGE 1: TARGET INFORMATION RETRIEVAL @@ -45,7 +33,7 @@ be created. STAGE 3: OBJECT INFORMATION RETRIEVAL ------------------------------------- Every object is checked whether its type has explorers and if so, these are -transfered to the target host and executed. The results are transfered back +executed on the target host. The results are transfered 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. @@ -86,19 +74,16 @@ The cache stores the information from the current run for later use. SUMMARY ------- If, and only if, all the stages complete without an errors, the configuration -will be applied to the target. Each stage can also be run individually, though -dependencies for each stage must be fulfilled and thus the stages must be run -in correct order. +will be applied to the target. SEE ALSO -------- - cdist(1) -- cdist(7) - cdist-reference(7) COPYING ------- -Copyright \(C) 2010-2011 Nico Schottelius, Steven Armstrong. Free use of this software is +Copyright \(C) 2010-2012 Nico Schottelius, Steven Armstrong. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 2bc703ce..85419025 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -37,20 +37,6 @@ cdist-reference:: cdist-explorer:: Interested in getting more information about the target system? [intermediate] -cdist-cache:: - How to get use information about the hosts we have been working on [advanced] - -cdist-scaling-tuning:: - How to scale out with cdist and which tunings to apply. [advanced] - - TUNING CDIST - ------------ - - - speedup processing with ControlMaster option of - ssh - => different document - - cdist-stages:: Understand the internal workflow of cdist. [advanced] @@ -58,8 +44,6 @@ cdist-hacker:: README, if you want to extend or modify cdist. [hacker] - - SEE ALSO -------- - cdist(1) From 2db2c2b321c4cbc59c1922f7f89f0b7f8980c510 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 17 Jan 2012 23:58:11 +0100 Subject: [PATCH 1206/4212] todo-- (much done) Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 327 ++---------------------------------------- 1 file changed, 15 insertions(+), 312 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 0d1b53bb..1b71f363 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,313 +1,16 @@ -- check other docs: - - cdist-hacker.text - - cdist-stages.text - - release 2.0.5 -- cdist-cache:: - How to get use information about the hosts we have been working on [advanced] -cdist-scaling-tuning:: - How to scale out with cdist and which tunings to apply. [advanced] - - --------------------------------------------------------------------------------- - - -- check speech publishing - - and speeches, which may be outdated as well - -- Fix / rewrite cdist-quickstart - - - like ccollect! - - include ssh control master! - - add local/ hint (and add to git) - - add hint for ssh StrictHostKeyChecking no - - and that ssh will wait for answer of prompt - - nasty if used in parallel mode (scroll up!) - -- rewrite cdist-stages, remove -- update man7! -- exec flag is not true for manifest anymore - -SSH HINTS ---------- -Control master, ssh agent - -Everything you specify in manifests - - -# Intro of quickstart -# -cat << eof -$banner cdist version $__cdist_version - -Welcome to the interactive guide to cdist! -This is the interactive tutorial and beginners help for cdist and here's -our schedule: - - - Stages: How cdist operates - - Explorer: Explore facts of the target host - - Manifest: Map configurations to hosts - - Types: Bundled functionality - - Deploy a configuration to the local host! - -eof -__prompt "$continue" - -################################################################################ -# Stages -# -cat << eof - -To deploy configurations to a host, you call - - cdist-deploy-to - -which makes calls to other scripts, which realise the so called "stages". -Usually you'll not notice this, but in case you want to debug or hack cdist, -you can run each stage on its own. Besides that, you just need to remember -that the command cdist-deploy-to is the main cdist command. - -See also: - - Source of cdist-deploy-to(1), cdist-stages(7) - -eof -__prompt "$continue" - -################################################################################ -# Explorer -# -cat << eof - -The first thing cdist always does is running different explorers on the -target host. The explorers can be found in the directory - - ${__cdist_explorer_dir} - -An explorer is executed on the target host and its output is saved to a file. -You can use these files later to decide what or how to configure the host. - -For a demonstration, we'll call the OS explorer locally now, but remember: -This is only for demonstration, normally it is run on the target host. -The os explorer will which either displays the detected operating system or -nothing if it does not know your OS. - -See also: - - cdist-explorer(7) - -eof -explorer="${__cdist_explorer_dir}/os" - -__prompt "Press enter to execute $explorer" - -set -x -"$explorer" -set +x - -################################################################################ -# Manifest -# -cat << eof - -The initial manifest is the entry point for cdist to find out, what you would -like to have configured. It is located at - - ${__cdist_manifest_init} - -And can be as simple as - --------------------------------------------------------------------------------- -__file /etc/cdist-configured --type file --------------------------------------------------------------------------------- - -See also: - - cdist-manifest(7) - -eof -__prompt "$continue" - -cat << eof - -Let's take a deeper look at the initial manifest to understand what it means: - - __file /etc/cdist-configured --type file - | | | \\ - | | The parameter type \\ With the value file - | | - | | - | | This is the object id - | - __file is a so called "type" - - -This essentially looks like a standard command executed in the shell. -eof -__prompt "$continue" - -cat << eof - -And that's exactly true. Manifests are shell snippets that can use -types as commands with arguments. cdist prepends a special path -that contain links to the cdist-type-emulator, to \$PATH, so you -can use your types as a command. - -This is also the reason why types should always be prefixed with -"__", to prevent collisions with existing binaries. - -The object id is unique per type and used to prevent you from creating -the same object twice. - -Parameters are type specific and are always specified as --parameter . - -See also: - - cdist-type-build-emulation(1), cdist-type-emulator(1) - -eof -__prompt "$continue" - -################################################################################ -# Types -# -cat << eof - -Types are bundled functionality and are the main component of cdist. -If you want to have a feature x, you write the type __x. Types are stored in - - ${__cdist_type_dir} - -And cdist ships with some types already! - -See also: - - cdist-type(7) - -eof -__prompt "Press enter to see available types" - -set -x -ls ${__cdist_type_dir} -set +x - -cat << eof - -Types consist of the following parts: - - - ${__cdist_name_parameter} (${__cdist_name_parameter_required}/${__cdist_name_parameter_optional} - - ${__cdist_name_manifest} - - ${__cdist_name_explorer} - - ${__cdist_name_gencode} - -eof -__prompt "$continue" - - -cat << eof - -Every type must have a directory named ${__cdist_name_parameter}, which -contains required or optional parameters (in newline seperated files). - -If an object of a specific type was created in the initial manifest, -the manifest of the type is run and may create other objects. - -A type may have ${__cdist_name_explorer}, which are very similar to the -${__cdist_name_explorer} seen above, but with a different purpose: -They are specific to the type and are not relevant for other types. - -You may use them for instance to find out details on the target host, -so you can decide what to do on the target host eventually. - -After the ${__cdist_name_manifest} and the ${__cdist_name_explorer} of -a type have been run, ${__cdist_name_gencode} is executed, which creates -code to be executed on the target on stdout. - -eof -__prompt "$continue" - -################################################################################ -# Deployment -# - -cat << eof - -Now you've got some basic knowledge about cdist, let's configure your a host! - -Ensure that you have a ssh server running on the host and that you can login as root. - -eof - -__prompt "Enter hostname or press enter for localhost: " - -if [ "$answer" ]; then - host="$answer" -else - host="localhost" -fi - -manifestinit="conf/manifest/init" -cat << eof - -I'll now setup $manifestinit, containing the following code: - --------------------------------------------------------------------------------- -# Every machine becomes a marker, so sysadmins know that automatic -# configurations are happening -__file /etc/cdist-configured - -case "\$__target_host" in - $host) - __link /tmp/cdist-testfile --source /etc/cdist-configured --type symbolic - __addifnosuchline /tmp/cdist-welcome --line "Welcome to cdist" - ;; -esac --------------------------------------------------------------------------------- - -WARNING: This will overwrite ${manifestinit}. - -eof - -cat > "$__cdist_abs_mydir/../$manifestinit" << eof - -# Every machine becomes a marker, so sysadmins know that automatic -# configurations are happening -__file /etc/cdist-configured - -case "\$__target_host" in - $host) - __link /tmp/cdist-testfile --source /etc/cdist-configured --type symbolic - __addifnosuchline /tmp/cdist-welcome --line "Welcome to cdist" - ;; -esac - -eof - -chmod u+x "$__cdist_abs_mydir/../$manifestinit" - -cmd="cdist-deploy-to $host" - -__prompt "Press enter to run \"$cmd\"" - -# No quotes, we need field splitting -$cmd - -################################################################################ -# End -# - -cat << eof - - --------------------------------------------------------------------------------- -That's it, this is the end of the cdist-quickstart. - -I hope you've got some impression on how cdist works, here are again some -pointers on where to continue to read: - - -eof --------------------------------------------------------------------------------- - -- Create new video for cdist 2.0.0 - http://www.youtube.com/watch?v=PRMjzy48eTI +- go through pull requests / check & include them +- update/create docs + - cdist-cache:: + How to get use information about the hosts we have been working on [advanced] + - cdist-scaling-tuning:: + How to scale out with cdist and which tunings to apply. [advanced] + - cdist-installation + How to use cdist to install hosts + - check speech publishing + - and speeches, which may be outdated as well + - Create new video for cdist 2.x + http://www.youtube.com/watch?v=PRMjzy48eTI + + - exec flag is not true for manifest anymore + - SSH HINTS - ssh agent From 9536bb7f8666f2cbbc63a0525f7def6d94c49c99 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 00:06:26 +0100 Subject: [PATCH 1207/4212] add url with cdist blog entry Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-01-18.url | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/dev/logs/2012-01-18.url diff --git a/doc/dev/logs/2012-01-18.url b/doc/dev/logs/2012-01-18.url new file mode 100644 index 00000000..f17f6815 --- /dev/null +++ b/doc/dev/logs/2012-01-18.url @@ -0,0 +1 @@ +http://haarts.tumblr.com/post/16015091140/cdist-the-setup From 3977c340530f18f031a00c099fa45208785ccc9f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 00:15:14 +0100 Subject: [PATCH 1208/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 3 +++ doc/dev/todo/niconext | 1 + 2 files changed, 4 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 56bb8284..875d2970 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -37,3 +37,6 @@ TYPES ------ - __user add option to include --create-home +- __init_script? + to enable/disable startup of init stuff + http://linuxhelp.blogspot.com/2006/04/enabling-and-disabling-services-during_01.html diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 1b71f363..41d02861 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -14,3 +14,4 @@ - exec flag is not true for manifest anymore - SSH HINTS - ssh agent + From 1cf56bccb920173b77b4fd306d48d81cfc45f615 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 00:31:18 +0100 Subject: [PATCH 1209/4212] release cleanups Signed-off-by: Nico Schottelius --- README | 9 +++------ doc/changelog | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/README b/README index bda6a197..3ab11928 100644 --- a/README +++ b/README @@ -77,13 +77,13 @@ cdist was tested or is know to run on at least * A posix like shell * Python (>= 3.2 required) - * SSH-Client + * SSH client * Asciidoc (for building the manpages) ### Client ("target host") * A posix like shell - * SSH-Server + * SSH server ## Installation @@ -155,15 +155,12 @@ To install cdist, execute the following commands: export MANPATH=$MANPATH:$(pwd -P)/doc/man -Afterwards you can run ***cdist-quickstart*** to get an impression on -how to use cdist. - ### Available versions There are at least the following branches available: * Development: master - * 2.0: Python rewrite of cdist core + * 2.0: Python rewrite of cdist core [stable branch] Old versions: diff --git a/doc/changelog b/doc/changelog index e6cb436e..bf16b8d3 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,4 +1,4 @@ -2.0.5: [BLOCKED FOR DOCUMENTATION/TUTORIAL] +2.0.5: 2012-01-18 * Bugfix __key_value: Use correct delimiters (Steven Armstrong, Daniel Maher) * Cleanup: Explicitly require Python >= 3.2 (do not fail implicitly) From facf8e961e1dbf9e2024680fe85a35c438ac5530 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 00:36:30 +0100 Subject: [PATCH 1210/4212] +url Signed-off-by: Nico Schottelius --- doc/dev/logs/{2012-01-18.url => 2012-01-18.urls} | 1 + 1 file changed, 1 insertion(+) rename doc/dev/logs/{2012-01-18.url => 2012-01-18.urls} (57%) diff --git a/doc/dev/logs/2012-01-18.url b/doc/dev/logs/2012-01-18.urls similarity index 57% rename from doc/dev/logs/2012-01-18.url rename to doc/dev/logs/2012-01-18.urls index f17f6815..5120faa1 100644 --- a/doc/dev/logs/2012-01-18.url +++ b/doc/dev/logs/2012-01-18.urls @@ -1 +1,2 @@ http://haarts.tumblr.com/post/16015091140/cdist-the-setup +http://d.hatena.ne.jp/kinneko/20120111/p26 From 5ca61189d93c5e7ae50fe202fe57b74784c2182b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 08:26:11 +0100 Subject: [PATCH 1211/4212] change version in lib Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 85892fec..09e4aacc 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -34,7 +34,7 @@ BANNER = """ "P' "" "" """ DOT_CDIST = ".cdist" -VERSION = "2.0.4" +VERSION = "2.0.5" import os From a05740ab25049e7723be67cea4a078eb9a4b8ddb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 08:34:15 +0100 Subject: [PATCH 1212/4212] add release notes (for releasing, not the release) Signed-off-by: Nico Schottelius --- doc/dev/releasechecklist | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index 55d6221b..188eecee 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -39,12 +39,23 @@ read tagmessage git tag "$version" -m "$tagmessage" # Import into current version branch -echo "git merge into $branch" +printf "Press enter to git merge into $branch > " +read prompt git checkout $branch git merge master git checkout master # Publish manpages and sourcecode -echo "publising doc/ and code/" +printf "Press enter to publish doc/ and code/ > " +read prompt ./build web ./build pub + +cat << notes +To be done manually... + + - freecode release + - blog entry + - mailinglist update + +notes From 9a89d9b6a79ba8c116a80b7f402f6b1c8b91584e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 08:36:26 +0100 Subject: [PATCH 1213/4212] ++notes Signed-off-by: Nico Schottelius --- doc/dev/releasechecklist | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index 188eecee..cb6d610d 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -56,6 +56,7 @@ To be done manually... - freecode release - blog entry + - linkedin entry - mailinglist update notes From 9317d57ff12a1575bdf5f6a053613d81a111e5c0 Mon Sep 17 00:00:00 2001 From: Evax Software Date: Wed, 18 Jan 2012 09:31:11 +0100 Subject: [PATCH 1214/4212] make virtual package detection more robust in __package_apt --- conf/type/__package_apt/explorer/pkg_status | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__package_apt/explorer/pkg_status b/conf/type/__package_apt/explorer/pkg_status index 249e4638..dbb3af3e 100755 --- a/conf/type/__package_apt/explorer/pkg_status +++ b/conf/type/__package_apt/explorer/pkg_status @@ -28,7 +28,7 @@ else fi # Except dpkg failing, if package is not known / installed -packages="$(apt-cache showpkg "$name" | grep -A 20 "Reverse Provides:" | sed 1d | cut -d ' ' -f 1) $name" +packages="$(apt-cache showpkg "$name" | sed -e "1,/Reverse Provides:/d" | cut -d ' ' -f 1) $name" for p in $packages; do if [ -n "$(dpkg -s "$p" 2>/dev/null | grep "^Status: install ok installed$")" ]; then echo "installed $p" From 41d3298a4e40ebe193df201e2020e6752cc35137 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 12:34:39 +0100 Subject: [PATCH 1215/4212] upcoming changes for 2.0.6 Signed-off-by: Nico Schottelius --- doc/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/changelog b/doc/changelog index bf16b8d3..8388eedd 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,3 +1,7 @@ +2.0.6: + * Bugfix __apt_ppa: + Also remove the [ppa-name].list file, if empty. (Tim Kersten) + 2.0.5: 2012-01-18 * Bugfix __key_value: Use correct delimiters (Steven Armstrong, Daniel Maher) From c893e54238be70ed4a1d92df2df6089022464d6a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 13:19:39 +0100 Subject: [PATCH 1216/4212] ++changes for 2.0.6 Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index 8388eedd..52af1f51 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,6 +1,8 @@ 2.0.6: * Bugfix __apt_ppa: Also remove the [ppa-name].list file, if empty. (Tim Kersten) + * Feature __package_apt: + Initial support for virtual packages (Evax Software) 2.0.5: 2012-01-18 * Bugfix __key_value: Use correct delimiters From ac36b5e18db16595c22cb43dfe673de77f2adb98 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 13:31:22 +0100 Subject: [PATCH 1217/4212] template for new type that starts stuff on boot Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/explorer/cksum | 34 ++++++++++ conf/type/__start_on_boot/explorer/exists | 30 +++++++++ conf/type/__start_on_boot/gencode-local | 43 ++++++++++++ conf/type/__start_on_boot/gencode-remote | 66 +++++++++++++++++++ conf/type/__start_on_boot/man.text | 69 ++++++++++++++++++++ conf/type/__start_on_boot/manifest | 24 +++++++ conf/type/__start_on_boot/parameter/optional | 5 ++ 7 files changed, 271 insertions(+) create mode 100755 conf/type/__start_on_boot/explorer/cksum create mode 100755 conf/type/__start_on_boot/explorer/exists create mode 100755 conf/type/__start_on_boot/gencode-local create mode 100755 conf/type/__start_on_boot/gencode-remote create mode 100644 conf/type/__start_on_boot/man.text create mode 100755 conf/type/__start_on_boot/manifest create mode 100644 conf/type/__start_on_boot/parameter/optional diff --git a/conf/type/__start_on_boot/explorer/cksum b/conf/type/__start_on_boot/explorer/cksum new file mode 100755 index 00000000..dcad99ba --- /dev/null +++ b/conf/type/__start_on_boot/explorer/cksum @@ -0,0 +1,34 @@ +#!/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 . +# +# +# 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/conf/type/__start_on_boot/explorer/exists b/conf/type/__start_on_boot/explorer/exists new file mode 100755 index 00000000..f8b85671 --- /dev/null +++ b/conf/type/__start_on_boot/explorer/exists @@ -0,0 +1,30 @@ +#!/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 yes +else + echo no +fi diff --git a/conf/type/__start_on_boot/gencode-local b/conf/type/__start_on_boot/gencode-local new file mode 100755 index 00000000..d9839a19 --- /dev/null +++ b/conf/type/__start_on_boot/gencode-local @@ -0,0 +1,43 @@ +#!/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 . +# +# +# __file is a very basic type, which will probably be reused quite often +# + +destination="/$__object_id" +state_should="$(cat "$__object/parameter/state")" + +if [ "$state_should" = "present" ]; then + if [ -f "$__object/parameter/source" ]; then + source="$(cat "$__object/parameter/source")" + + 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 + echo "Source \"$source\" does not exist." >&2 + exit 1 + fi + fi +fi diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote new file mode 100755 index 00000000..9e700934 --- /dev/null +++ b/conf/type/__start_on_boot/gencode-remote @@ -0,0 +1,66 @@ +#!/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 . +# +# +# __file is a very basic type, which will probably be reused quite often +# + +destination="/$__object_id" +state_should="$(cat "$__object/parameter/state")" +exists="$(cat "$__object/explorer/exists")" + +case "$state_should" in + present) + # No source? Create empty file + if [ ! -f "$__object/parameter/source" ]; then + if [ "$exists" = "no" ]; then + echo touch \"$destination\" + fi + fi + + # Mode settings + if [ -f "$__object/parameter/mode" ]; then + echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" + 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 + ;; + + absent) + + if [ "$exists" = "yes" ]; then + echo rm -f \"$destination\" + fi + + ;; + + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; + +esac diff --git a/conf/type/__start_on_boot/man.text b/conf/type/__start_on_boot/man.text new file mode 100644 index 00000000..5e91599f --- /dev/null +++ b/conf/type/__start_on_boot/man.text @@ -0,0 +1,69 @@ +cdist-type__file(7) +=================== +Nico Schottelius + + +NAME +---- +cdist-type__file - Manage files + + +DESCRIPTION +----------- +This cdist type allows you to create files, remove files and set file +attributes on the target. + + +REQUIRED PARAMETERS +------------------- +None. + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent', defaults to 'present' + +group:: + Group to chgrp to. + +mode:: + Unix permissions, suitable for chmod. + +owner:: + User to chown to. + +source:: + If supplied, copy this file from the host running cdist to the target. + If not supplied, an empty file or directory will be created. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Create /etc/cdist-configured as an empty file +__file /etc/cdist-configured +# The same thing +__file /etc/cdist-configured --state present +# Delete existing file +__file /etc/cdist-configured --state absent + +# Use __file from another type +__file /etc/issue --source "$__type/files/archlinux" --state present + +# Supply some more settings +__file /etc/shadow --source "$__type/files/shadow" \ + --owner root --group shadow --mode 0640 \ + --state present +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__start_on_boot/manifest b/conf/type/__start_on_boot/manifest new file mode 100755 index 00000000..6b5e1ca7 --- /dev/null +++ b/conf/type/__start_on_boot/manifest @@ -0,0 +1,24 @@ +#!/bin/sh +# +# 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 . +# + +# set default: present, if not setup +statefile="$__object/parameter/state" +[ -f "$statefile" ] || echo present > "$statefile" diff --git a/conf/type/__start_on_boot/parameter/optional b/conf/type/__start_on_boot/parameter/optional new file mode 100644 index 00000000..c696d592 --- /dev/null +++ b/conf/type/__start_on_boot/parameter/optional @@ -0,0 +1,5 @@ +state +group +mode +owner +source From 72dea3d930fbb8d02327af949990793b9cb76185 Mon Sep 17 00:00:00 2001 From: Evax Software Date: Wed, 18 Jan 2012 14:28:10 +0100 Subject: [PATCH 1218/4212] __rvm* types documentation cleanup --- conf/type/__rvm_gem/man.text | 4 ++++ conf/type/__rvm_gemset/man.text | 9 ++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/conf/type/__rvm_gem/man.text b/conf/type/__rvm_gem/man.text index 951884b8..27b16053 100644 --- a/conf/type/__rvm_gem/man.text +++ b/conf/type/__rvm_gem/man.text @@ -34,6 +34,10 @@ EXAMPLES # Install the rails gem in gemset ruby-1.9.3-p0@myset for user bill __rvm_gemset rails --gemset ruby-1.9.3-p0@myset --user bill --state installed +# Do the same and also make ruby-1.9.3-p0@myset the default gemset +__rvm_gemset rails --gemset ruby-1.9.3-p0@myset --user bill \ + --state installed --default yes + # Remove it __rvm_ruby rails --gemset ruby-1.9.3-p0@myset --user bill --state removed -------------------------------------------------------------------------------- diff --git a/conf/type/__rvm_gemset/man.text b/conf/type/__rvm_gemset/man.text index d7b4c04c..f1e3f2bf 100644 --- a/conf/type/__rvm_gemset/man.text +++ b/conf/type/__rvm_gemset/man.text @@ -17,17 +17,13 @@ REQUIRED PARAMETERS ------------------- user:: The remote user account to use -ruby:: - The ruby version to use -name:: - The gemset name (including state:: Either "installed" or "removed". OPTIONAL PARAMETERS ------------------- default:: - If set to anything but "no" (the default), set the give gemset as default. + If set to anything but "no" (the default), set the given gemset as default. EXAMPLES -------- @@ -36,6 +32,9 @@ EXAMPLES # Install the gemset @myset for user charles on based on ruby-1.9.3-0 __rvm_gemset ruby-1.9.3-p0@myset --user charles --state installed +# Do the same and make ruby-1.9.3-p0@myset the default gemset +__rvm_gemset ruby-1.9.3-p0@myset --user charles --state installed --default yes + # Remove the gemset @myset for user john __rvm_ruby ruby-1.9.3-p0@myset --user john --state removed -------------------------------------------------------------------------------- From 85876592e359ff61012d7de676113fb9a8bd817d Mon Sep 17 00:00:00 2001 From: "phrawzty (dan)" Date: Wed, 18 Jan 2012 14:30:31 +0100 Subject: [PATCH 1219/4212] New type: __rsyncer --- conf/type/__rsyncer/gencode-local | 44 ++++++++++++++++++ conf/type/__rsyncer/man.text | 62 ++++++++++++++++++++++++++ conf/type/__rsyncer/parameter/optional | 3 ++ conf/type/__rsyncer/parameter/required | 1 + 4 files changed, 110 insertions(+) create mode 100755 conf/type/__rsyncer/gencode-local create mode 100644 conf/type/__rsyncer/man.text create mode 100644 conf/type/__rsyncer/parameter/optional create mode 100644 conf/type/__rsyncer/parameter/required diff --git a/conf/type/__rsyncer/gencode-local b/conf/type/__rsyncer/gencode-local new file mode 100755 index 00000000..0d08e445 --- /dev/null +++ b/conf/type/__rsyncer/gencode-local @@ -0,0 +1,44 @@ +#!/bin/sh +# +# Copyright (C) 2011 Daniel Maher (phrawzty+cdist at gmail.com) +# +# This file is part of cdist (https://github.com/telmich/cdist/). +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +source="$(cat "$__object/parameter/source")" + +if [ -f "$__object/parameter/destination" ]; then + destination="$(cat "$__object/parameter/destination")" +else + destination="/$__object_id" +fi + +# The system binary is probably ok, but if not... +if [ -f "$__object/parameter/rsyncbin" ]; then + rsyncbin="$(cat "$__object/parameter/rsyncbin")" +else + rsyncbin=`which rsync` +fi + +args='-a --stats' + +# If the --delete argument should be passed to rsync. +if [ -f "$__object/parameter/delete" ]; then + args="$args --delete" +fi + +# Run rsync (locally). +echo "$rsyncbin $args $source root@$__target_host:$destination" diff --git a/conf/type/__rsyncer/man.text b/conf/type/__rsyncer/man.text new file mode 100644 index 00000000..6fab9fd3 --- /dev/null +++ b/conf/type/__rsyncer/man.text @@ -0,0 +1,62 @@ +cdist-type__rsyncer(7) +====================== +Daniel Maher + + +NAME +---- +cdist-type__rsyncer - Use rsync to copy files. + + +DESCRIPTION +----------- +This type is used to trigger rsync to copy files from the machine running cdist +(source) to the target machine in question (destination). The likely usage is +the rapid deployment of full directory trees, the cohorency of which can be +guarunteed with the optional --delete argument, which will remove any files +from the destination which are not present on the source. + + +REQUIRED PARAMETERS +------------------- +source:: + The full path of the source from which to copy. This is passed directly + to rsync. + + +OPTIONAL PARAMETERS +------------------- +destination:: + The full path of the destination. This is passed directly to rsync. + Default: object_id + +delete:: + If true, remove files from destination which are not in source. This is + effectively the --delete argument of rsync. + Default: false + +rsyncbin:: + Specify the full path to the rsync binary. + Default: `which rsync` + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Basic example +__rsyncer '/home/foo' --source '/opt/dist/foo' + +# Fancier example +__rsyncer FOO --source '/opt/dist/foo' --destination '/home/foo/' --delete true +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011 Daniel Maher. Free use of this software is granted under +the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__rsyncer/parameter/optional b/conf/type/__rsyncer/parameter/optional new file mode 100644 index 00000000..3bcb4dc7 --- /dev/null +++ b/conf/type/__rsyncer/parameter/optional @@ -0,0 +1,3 @@ +destination +delete +rsyncbin diff --git a/conf/type/__rsyncer/parameter/required b/conf/type/__rsyncer/parameter/required new file mode 100644 index 00000000..5a18cd2f --- /dev/null +++ b/conf/type/__rsyncer/parameter/required @@ -0,0 +1 @@ +source From f5d07a941b5b74fa7349564feeccdcf2513ef097 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 14:32:24 +0100 Subject: [PATCH 1220/4212] --todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 41d02861..ad859266 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,5 +1,3 @@ -- release 2.0.5 -- go through pull requests / check & include them - update/create docs - cdist-cache:: How to get use information about the hosts we have been working on [advanced] From 9551b2422f8d8185b659881bd13d875834a59292 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 14:37:29 +0100 Subject: [PATCH 1221/4212] ++changes for 2.0.6 Signed-off-by: Nico Schottelius --- doc/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/changelog b/doc/changelog index 52af1f51..062db392 100644 --- a/doc/changelog +++ b/doc/changelog @@ -3,6 +3,10 @@ Also remove the [ppa-name].list file, if empty. (Tim Kersten) * Feature __package_apt: Initial support for virtual packages (Evax Software) + * New Type: __rvm (Evax Software) + * New Type: __rvm_gem (Evax Software) + * New Type: __rvm_gemset (Evax Software) + * New Type: __rvm_ruby (Evax Software) 2.0.5: 2012-01-18 * Bugfix __key_value: Use correct delimiters From c567ade17a2072d502613a059e99ce7e812faf6e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 14:42:36 +0100 Subject: [PATCH 1222/4212] add manpage for __start_on_boot Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/man.text | 43 +++++++++--------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/conf/type/__start_on_boot/man.text b/conf/type/__start_on_boot/man.text index 5e91599f..e9691401 100644 --- a/conf/type/__start_on_boot/man.text +++ b/conf/type/__start_on_boot/man.text @@ -1,17 +1,17 @@ -cdist-type__file(7) -=================== +cdist-type__start_on_boot(7) +============================ Nico Schottelius NAME ---- -cdist-type__file - Manage files +cdist-type__start_on_boot - Manage stuff to be started at boot DESCRIPTION ----------- -This cdist type allows you to create files, remove files and set file -attributes on the target. +This cdist type allows you to enable or disable stuff to be started +at boot of your operating system. REQUIRED PARAMETERS @@ -23,38 +23,19 @@ OPTIONAL PARAMETERS state:: 'present' or 'absent', defaults to 'present' -group:: - Group to chgrp to. - -mode:: - Unix permissions, suitable for chmod. - -owner:: - User to chown to. - -source:: - If supplied, copy this file from the host running cdist to the target. - If not supplied, an empty file or directory will be created. - EXAMPLES -------- -------------------------------------------------------------------------------- -# Create /etc/cdist-configured as an empty file -__file /etc/cdist-configured -# The same thing -__file /etc/cdist-configured --state present -# Delete existing file -__file /etc/cdist-configured --state absent +# Ensure snmpd is started at boot +__start_on_boot snmpd -# Use __file from another type -__file /etc/issue --source "$__type/files/archlinux" --state present +# Same, but more explicit +__start_on_boot snmpd --state present -# Supply some more settings -__file /etc/shadow --source "$__type/files/shadow" \ - --owner root --group shadow --mode 0640 \ - --state present +# Ensure legacy configuration management will not be started +__start_on_boot puppet --state absent -------------------------------------------------------------------------------- @@ -65,5 +46,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +Copyright \(C) 2012 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). From aea107079899f2c76ca0f0aa7a9a62f278f4a9e7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 14:50:50 +0100 Subject: [PATCH 1223/4212] add global explorer runlevel Signed-off-by: Nico Schottelius --- conf/explorer/runlevel | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100755 conf/explorer/runlevel diff --git a/conf/explorer/runlevel b/conf/explorer/runlevel new file mode 100755 index 00000000..7cdd81ef --- /dev/null +++ b/conf/explorer/runlevel @@ -0,0 +1,26 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +set +e +executable=$(which runlevel 2>/dev/null) +if [ -x "$executable" ]; then + "$executable" | awk '{ print $2 }' +fi From 65be80f2c66971764553fe26bd972d43e6597c29 Mon Sep 17 00:00:00 2001 From: Evax Software Date: Wed, 18 Jan 2012 14:52:46 +0100 Subject: [PATCH 1224/4212] escape user parameter in __rvm* types --- conf/type/__rvm_gem/explorer/state | 6 +++--- conf/type/__rvm_gem/gencode-remote | 4 ++-- conf/type/__rvm_gem/manifest | 6 +++--- conf/type/__rvm_gemset/explorer/state | 6 +++--- conf/type/__rvm_gemset/gencode-remote | 6 +++--- conf/type/__rvm_gemset/manifest | 4 ++-- conf/type/__rvm_ruby/explorer/state | 4 ++-- conf/type/__rvm_ruby/gencode-remote | 6 +++--- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/conf/type/__rvm_gem/explorer/state b/conf/type/__rvm_gem/explorer/state index e7f50247..b0232985 100755 --- a/conf/type/__rvm_gem/explorer/state +++ b/conf/type/__rvm_gem/explorer/state @@ -23,13 +23,13 @@ gemset="$(cat "$__object/parameter/gemset")" ruby="$(echo "$gemset" | cut -d '@' -f 1)" gemsetname="$(echo "$gemset" | cut -d '@' -f2)" user="$(cat "$__object/parameter/user")" -if su - $user -c "[ ! -d \"\$HOME/.rvm\" ]" ; then +if su - "$user" -c "[ ! -d \"\$HOME/.rvm\" ]" ; then echo "removed" exit 0 fi -if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" +if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" rvm list | grep -q $ruby"; then - if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" + if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" rvm use $ruby > /dev/null; rvm gemset list | grep -q $gemsetname && rvm use $gemset > /dev/null && gem list | grep -q $gem"; then echo "installed" diff --git a/conf/type/__rvm_gem/gencode-remote b/conf/type/__rvm_gem/gencode-remote index 8b784ac3..80e1becf 100755 --- a/conf/type/__rvm_gem/gencode-remote +++ b/conf/type/__rvm_gem/gencode-remote @@ -29,13 +29,13 @@ if [ "$state_is" != "$state_should" ]; then case "$state_should" in installed) cat << DONE -su - $user -c "source \"\\\$HOME/.rvm/scripts/rvm\" +su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" rvm use $gemset; gem install $gem" DONE ;; removed) cat << DONE -su - $user -c "source \"\\\$HOME/.rvm/scripts/rvm\" +su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" rvm use $gemset; gem uninstall $gem" DONE ;; diff --git a/conf/type/__rvm_gem/manifest b/conf/type/__rvm_gem/manifest index 737dbe75..245c865d 100755 --- a/conf/type/__rvm_gem/manifest +++ b/conf/type/__rvm_gem/manifest @@ -31,8 +31,8 @@ else echo $default > "$__object/parameter/default" fi -__rvm $user --state installed +__rvm "$user" --state installed require="__rvm/$user" \ - __rvm_ruby $ruby --user $user --state installed --default $default + __rvm_ruby $ruby --user "$user" --state installed --default $default require="__rvm_ruby/$ruby" \ - __rvm_gemset $gemset --user $user --state installed --default $default + __rvm_gemset $gemset --user "$user" --state installed --default $default diff --git a/conf/type/__rvm_gemset/explorer/state b/conf/type/__rvm_gemset/explorer/state index 43667126..b33f570e 100755 --- a/conf/type/__rvm_gemset/explorer/state +++ b/conf/type/__rvm_gemset/explorer/state @@ -22,13 +22,13 @@ gemset="$__object_id" ruby="$(echo "$gemset" | cut -d '@' -f 1)" gemsetname="$(echo "$gemset" | cut -d '@' -f2)" user="$(cat "$__object/parameter/user")" -if su - $user -c "[ ! -d \"\$HOME/.rvm\" ]" ; then +if su - "$user" -c "[ ! -d \"\$HOME/.rvm\" ]" ; then echo "removed" exit 0 fi -if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" +if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" rvm list | grep -q $ruby"; then - if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" + if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" rvm use $ruby > /dev/null; rvm gemset list | grep -q $gemsetname"; then echo "installed" exit 0 diff --git a/conf/type/__rvm_gemset/gencode-remote b/conf/type/__rvm_gemset/gencode-remote index 5b934edb..a18e9a38 100755 --- a/conf/type/__rvm_gemset/gencode-remote +++ b/conf/type/__rvm_gemset/gencode-remote @@ -28,7 +28,7 @@ if [ "$state_is" != "$state_should" ]; then case "$state_should" in installed) cat << DONE -su - $user -c "source \"\\\$HOME/.rvm/scripts/rvm\" +su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" rvm $gemset --create" DONE case "$default" in @@ -36,7 +36,7 @@ DONE ;; *) cat << DONE -su - $user -c "source \"\\\$HOME/.rvm/scripts/rvm\" +su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" rvm use --default $gemset" DONE ;; @@ -44,7 +44,7 @@ DONE ;; removed) cat << DONE -su - $user -c "source \"\\\$HOME/.rvm/scripts/rvm\" +su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" rvm use $ruby; rvm --force gemset delete $gemsetname" DONE ;; diff --git a/conf/type/__rvm_gemset/manifest b/conf/type/__rvm_gemset/manifest index 8e25251c..f9941515 100755 --- a/conf/type/__rvm_gemset/manifest +++ b/conf/type/__rvm_gemset/manifest @@ -29,7 +29,7 @@ else default="no" fi -__rvm $user --state installed +__rvm "$user" --state installed require="__rvm/$user" \ - __rvm_ruby $ruby --user $user --state installed --default $default + __rvm_ruby $ruby --user "$user" --state installed --default $default diff --git a/conf/type/__rvm_ruby/explorer/state b/conf/type/__rvm_ruby/explorer/state index 1fc9e0a8..71d682be 100755 --- a/conf/type/__rvm_ruby/explorer/state +++ b/conf/type/__rvm_ruby/explorer/state @@ -20,11 +20,11 @@ ruby="$__object_id" user="$(cat "$__object/parameter/user")" -if su - $user -c "[ ! -d \"\$HOME/.rvm\" ]" ; then +if su - "$user" -c "[ ! -d \"\$HOME/.rvm\" ]" ; then echo "removed" exit 0 fi -if su - $user -c "source \"\$HOME/.rvm/scripts/rvm\" +if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" rvm list | grep -q $ruby"; then echo "installed" else diff --git a/conf/type/__rvm_ruby/gencode-remote b/conf/type/__rvm_ruby/gencode-remote index 5dcb0e99..a3bcf318 100755 --- a/conf/type/__rvm_ruby/gencode-remote +++ b/conf/type/__rvm_ruby/gencode-remote @@ -26,19 +26,19 @@ state_should="$(cat "$__object/parameter/state")" if [ "$state_is" != "$state_should" ]; then case "$state_should" in installed) - echo "su - $user -c \"source \\\$HOME/.rvm/scripts/rvm;"\ + echo "su - \"$user\" -c \"source \\\$HOME/.rvm/scripts/rvm;"\ "rvm install $ruby\"" case "$default" in no) ;; *) - echo "su - $user -c \"source \\\$HOME/.rvm/scripts/rvm;"\ + echo "su - \"$user\" -c \"source \\\$HOME/.rvm/scripts/rvm;"\ "rvm use --default $ruby\"" ;; esac ;; removed) - echo "su - $user -c \"source \\\$HOME/.rvm/scripts/rvm;"\ + echo "su - \"$user\" -c \"source \\\$HOME/.rvm/scripts/rvm;"\ "rvm remove $ruby\"" ;; esac From 5fa264601116ca4687cb48478bedf66974a93c10 Mon Sep 17 00:00:00 2001 From: Evax Software Date: Wed, 18 Jan 2012 15:13:53 +0100 Subject: [PATCH 1225/4212] fix default parameter handling in __rvm_gemset --- conf/type/__rvm_gemset/gencode-remote | 1 + conf/type/__rvm_gemset/manifest | 1 + 2 files changed, 2 insertions(+) diff --git a/conf/type/__rvm_gemset/gencode-remote b/conf/type/__rvm_gemset/gencode-remote index a18e9a38..0e240462 100755 --- a/conf/type/__rvm_gemset/gencode-remote +++ b/conf/type/__rvm_gemset/gencode-remote @@ -23,6 +23,7 @@ ruby="$(echo "$gemset" | cut -d '@' -f 1)" gemsetname="$(echo "$gemset" | cut -d '@' -f 2)" state_is="$(cat "$__object/explorer/state")" user="$(cat "$__object/parameter/user")" +default="$(cat "$__object/parameter/default")" state_should="$(cat "$__object/parameter/state")" if [ "$state_is" != "$state_should" ]; then case "$state_should" in diff --git a/conf/type/__rvm_gemset/manifest b/conf/type/__rvm_gemset/manifest index f9941515..4fdf9cb1 100755 --- a/conf/type/__rvm_gemset/manifest +++ b/conf/type/__rvm_gemset/manifest @@ -27,6 +27,7 @@ if [ -f "$__object/parameter/default" ]; then default="$(cat "$__object/parameter/default")" else default="no" + echo $default > "$__object/parameter/default" fi __rvm "$user" --state installed From 14127446191d92ed343145a50dc04c9e66507c20 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 15:52:19 +0100 Subject: [PATCH 1226/4212] begin state explorer Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/explorer/exists | 30 ---------------- .../__start_on_boot/explorer/{cksum => state} | 34 ++++++++++++------- 2 files changed, 22 insertions(+), 42 deletions(-) delete mode 100755 conf/type/__start_on_boot/explorer/exists rename conf/type/__start_on_boot/explorer/{cksum => state} (59%) diff --git a/conf/type/__start_on_boot/explorer/exists b/conf/type/__start_on_boot/explorer/exists deleted file mode 100755 index f8b85671..00000000 --- a/conf/type/__start_on_boot/explorer/exists +++ /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 yes -else - echo no -fi diff --git a/conf/type/__start_on_boot/explorer/cksum b/conf/type/__start_on_boot/explorer/state similarity index 59% rename from conf/type/__start_on_boot/explorer/cksum rename to conf/type/__start_on_boot/explorer/state index dcad99ba..c68ec2ba 100755 --- a/conf/type/__start_on_boot/explorer/cksum +++ b/conf/type/__start_on_boot/explorer/state @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,17 +18,27 @@ # along with cdist. If not, see . # # -# Retrieve the md5sum of a file to be created, if it is already existing. +# Check whether the given name will be started on boot or not # -destination="/$__object_id" +os=$(cat "$__global/explorer/os") + +case "$os" in + debian|ubuntu) + echo update-rc.d \"$name\" defaults + ;; + + gentoo) + echo rc-update add \"$name\" default + ;; + + centos|fedora|owl|redhat) + echo chkconfig \"$name\" on + ;; + + *) + echo "Unsupported os: $os" >&2 + exit 1 + ;; +esac -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 From 6b6ae1bde225765051f7be1972c2fd463f789b48 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 15:52:47 +0100 Subject: [PATCH 1227/4212] document more exported environment variables Signed-off-by: Nico Schottelius --- doc/man/cdist-reference.text.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 6b4e786f..ffc40ee3 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -167,7 +167,7 @@ ENVIRONMENT VARIABLES --------------------- __explorer:: Directory that contains all global explorers. - Available for: explorer + Available for: explorer, type explorer __manifest:: Directory that contains the initial manifest. Available for: initial manifest @@ -188,7 +188,7 @@ __object_name:: Available for: type manifest, type explorer, type gencode __target_host:: The host we are deploying to. - Available for: initial manifest, type manifest, type gencode + Available for: explorer, initial manifest, type explorer, type manifest, type gencode __type:: Path to the current type. Available for: type manifest, type gencode From 42e3c18d02823a47423ac194ef884a57fd741aa2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 15:54:32 +0100 Subject: [PATCH 1228/4212] +update of __start_on_boot Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/explorer/state | 2 +- conf/type/__start_on_boot/gencode-remote | 71 ++++++++++++------------ conf/type/__start_on_boot/man.text | 3 + 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/conf/type/__start_on_boot/explorer/state b/conf/type/__start_on_boot/explorer/state index c68ec2ba..136c1e05 100755 --- a/conf/type/__start_on_boot/explorer/state +++ b/conf/type/__start_on_boot/explorer/state @@ -21,7 +21,7 @@ # Check whether the given name will be started on boot or not # -os=$(cat "$__global/explorer/os") +os=$("$__explorer/os") case "$os" in debian|ubuntu) diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index 9e700934..5133810d 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,49 +18,48 @@ # along with cdist. If not, see . # # -# __file is a very basic type, which will probably be reused quite often -# -destination="/$__object_id" -state_should="$(cat "$__object/parameter/state")" -exists="$(cat "$__object/explorer/exists")" +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi + +os=$(cat "$__global/explorer/os") +name="$__object_id" + +# Support runlevels later +#runlevel=$(cat $__global/explorer/runlevel) case "$state_should" in - present) - # No source? Create empty file - if [ ! -f "$__object/parameter/source" ]; then - if [ "$exists" = "no" ]; then - echo touch \"$destination\" - fi - fi + present) + case "$os" in + debian|ubuntu) + echo update-rc.d \"$name\" defaults + ;; - # Mode settings - if [ -f "$__object/parameter/mode" ]; then - echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" - fi + gentoo) + echo rc-update add \"$name\" default + ;; - # Group - if [ -f "$__object/parameter/group" ]; then - echo chgrp \"$(cat "$__object/parameter/group")\" \"$destination\" - fi + centos|fedora|owl|redhat) + echo echo chkconfig \"$name\" on + ;; - # Owner - if [ -f "$__object/parameter/owner" ]; then - echo chown \"$(cat "$__object/parameter/owner")\" \"$destination\" - fi - ;; + *) + echo "Unsupported os: $os" >&2 + exit 1 + ;; + esac + ;; - absent) + absent) - if [ "$exists" = "yes" ]; then - echo rm -f \"$destination\" - fi + ;; - ;; - - *) - echo "Unknown state: $state_should" >&2 - exit 1 - ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; esac diff --git a/conf/type/__start_on_boot/man.text b/conf/type/__start_on_boot/man.text index e9691401..eb9dbe7f 100644 --- a/conf/type/__start_on_boot/man.text +++ b/conf/type/__start_on_boot/man.text @@ -23,6 +23,9 @@ OPTIONAL PARAMETERS state:: 'present' or 'absent', defaults to 'present' +runlevel:: + Specify runlevel(s) to affect. Defaults to default or current runlevel. + EXAMPLES -------- From 1e9940ae53b3b517b4e90896ee8fac2a722e3162 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 15:54:50 +0100 Subject: [PATCH 1229/4212] ++fixme of logging Signed-off-by: Nico Schottelius --- lib/cdist/core/explorer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 01c4c81d..19833d92 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -73,6 +73,7 @@ class Explorer(object): '__target_host': self.target_host, '__explorer': self.remote.global_explorer_path, } + # FIXME: remove soon with new logging infrastructure if self.log.getEffectiveLevel() == logging.DEBUG: self.env.update({'__debug': "yes" }) self._type_explorers_transferred = [] From 5a383fcbad5c99e0c16dd365c0b94ca85cf9585f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 15:54:58 +0100 Subject: [PATCH 1230/4212] ++todo for nico Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 3 --- doc/dev/todo/niconext | 6 +++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 875d2970..56bb8284 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -37,6 +37,3 @@ TYPES ------ - __user add option to include --create-home -- __init_script? - to enable/disable startup of init stuff - http://linuxhelp.blogspot.com/2006/04/enabling-and-disabling-services-during_01.html diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index ad859266..4543b32a 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,4 +1,9 @@ +- __init_script? + to enable/disable startup of init stuff + http://linuxhelp.blogspot.com/2006/04/enabling-and-disabling-services-during_01.html + - update/create docs + - document __remote_copy and __remote_exec - cdist-cache:: How to get use information about the hosts we have been working on [advanced] - cdist-scaling-tuning:: @@ -12,4 +17,3 @@ - exec flag is not true for manifest anymore - SSH HINTS - ssh agent - From 0ccf000713dc196686a80256fd543a15b499ce56 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 15:55:06 +0100 Subject: [PATCH 1231/4212] more stuff for 2.0.6 Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index 062db392..5867d54d 100644 --- a/doc/changelog +++ b/doc/changelog @@ -7,6 +7,8 @@ * New Type: __rvm_gem (Evax Software) * New Type: __rvm_gemset (Evax Software) * New Type: __rvm_ruby (Evax Software) + * New Explorer: runlevel + * Documentation: Update of reference (environment variables) 2.0.5: 2012-01-18 * Bugfix __key_value: Use correct delimiters From fe0fae69023eca7561c6c01831b97f6e50a8e2c4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 16:07:33 +0100 Subject: [PATCH 1232/4212] update explorer and gencode and parameter Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/explorer/state | 5 ++- conf/type/__start_on_boot/gencode-local | 43 -------------------- conf/type/__start_on_boot/gencode-remote | 25 +++++++++++- conf/type/__start_on_boot/man.text | 1 + conf/type/__start_on_boot/parameter/optional | 4 -- 5 files changed, 29 insertions(+), 49 deletions(-) delete mode 100755 conf/type/__start_on_boot/gencode-local diff --git a/conf/type/__start_on_boot/explorer/state b/conf/type/__start_on_boot/explorer/state index 136c1e05..8db4b9d2 100755 --- a/conf/type/__start_on_boot/explorer/state +++ b/conf/type/__start_on_boot/explorer/state @@ -22,6 +22,7 @@ # os=$("$__explorer/os") +runlevel=$("$__explorer/runlevel") case "$os" in debian|ubuntu) @@ -33,7 +34,8 @@ case "$os" in ;; centos|fedora|owl|redhat) - echo chkconfig \"$name\" on + state=$(chkconfig --level "$runlevel" \"$name\" || echo absent) + [ "$state" ] || state="present" ;; *) @@ -42,3 +44,4 @@ case "$os" in ;; esac +echo $state diff --git a/conf/type/__start_on_boot/gencode-local b/conf/type/__start_on_boot/gencode-local deleted file mode 100755 index d9839a19..00000000 --- a/conf/type/__start_on_boot/gencode-local +++ /dev/null @@ -1,43 +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 . -# -# -# __file is a very basic type, which will probably be reused quite often -# - -destination="/$__object_id" -state_should="$(cat "$__object/parameter/state")" - -if [ "$state_should" = "present" ]; then - if [ -f "$__object/parameter/source" ]; then - source="$(cat "$__object/parameter/source")" - - 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 - echo "Source \"$source\" does not exist." >&2 - exit 1 - fi - fi -fi diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index 5133810d..aa854658 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -25,6 +25,11 @@ else state_should="present" fi +state_is=$(cat "$__object/explorer/state") + +# Nothing todo, go away +[ "$state_should" = "$state_is" ] && exit 0 + os=$(cat "$__global/explorer/os") name="$__object_id" @@ -43,7 +48,7 @@ case "$state_should" in ;; centos|fedora|owl|redhat) - echo echo chkconfig \"$name\" on + echo chkconfig \"$name\" on ;; *) @@ -54,7 +59,25 @@ case "$state_should" in ;; absent) + case "$os" in + debian|ubuntu) + echo update-rc.d -f \"$name\" remove + ;; + gentoo) + echo rc-update del \"$name\" + ;; + + centos|fedora|owl|redhat) + echo chkconfig \"$name\" off + ;; + + *) + echo "Unsupported os: $os" >&2 + exit 1 + ;; + esac + ;; diff --git a/conf/type/__start_on_boot/man.text b/conf/type/__start_on_boot/man.text index eb9dbe7f..5614f16b 100644 --- a/conf/type/__start_on_boot/man.text +++ b/conf/type/__start_on_boot/man.text @@ -25,6 +25,7 @@ state:: runlevel:: Specify runlevel(s) to affect. Defaults to default or current runlevel. + NOT YET SUPPORTED, ALWAYS USING CURRENT RUNLEVEL. EXAMPLES diff --git a/conf/type/__start_on_boot/parameter/optional b/conf/type/__start_on_boot/parameter/optional index c696d592..ff72b5c7 100644 --- a/conf/type/__start_on_boot/parameter/optional +++ b/conf/type/__start_on_boot/parameter/optional @@ -1,5 +1 @@ state -group -mode -owner -source From 559670ab4f333b44831c29e18b70ab442275b8d9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 16:15:53 +0100 Subject: [PATCH 1233/4212] add debian / ubuntu support for checking state Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/explorer/state | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/conf/type/__start_on_boot/explorer/state b/conf/type/__start_on_boot/explorer/state index 8db4b9d2..2778e784 100755 --- a/conf/type/__start_on_boot/explorer/state +++ b/conf/type/__start_on_boot/explorer/state @@ -21,12 +21,19 @@ # Check whether the given name will be started on boot or not # +set -x +exec >&2 + os=$("$__explorer/os") runlevel=$("$__explorer/runlevel") +name="$__object_id" + +# default +state="present" case "$os" in debian|ubuntu) - echo update-rc.d \"$name\" defaults + [ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent" ;; gentoo) @@ -45,3 +52,4 @@ case "$os" in esac echo $state +exit 1 From aa870e012441a0a570aae87c35d45a11552609fb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Jan 2012 16:37:09 +0100 Subject: [PATCH 1234/4212] remove debug, remove gentoo support until tested Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/explorer/state | 8 -------- conf/type/__start_on_boot/gencode-remote | 15 ++++++++------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/conf/type/__start_on_boot/explorer/state b/conf/type/__start_on_boot/explorer/state index 2778e784..9d63b84e 100755 --- a/conf/type/__start_on_boot/explorer/state +++ b/conf/type/__start_on_boot/explorer/state @@ -21,9 +21,6 @@ # Check whether the given name will be started on boot or not # -set -x -exec >&2 - os=$("$__explorer/os") runlevel=$("$__explorer/runlevel") name="$__object_id" @@ -36,10 +33,6 @@ case "$os" in [ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent" ;; - gentoo) - echo rc-update add \"$name\" default - ;; - centos|fedora|owl|redhat) state=$(chkconfig --level "$runlevel" \"$name\" || echo absent) [ "$state" ] || state="present" @@ -52,4 +45,3 @@ case "$os" in esac echo $state -exit 1 diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index aa854658..ee2bdeb6 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -43,9 +43,10 @@ case "$state_should" in echo update-rc.d \"$name\" defaults ;; - gentoo) - echo rc-update add \"$name\" default - ;; +# Disabled until the explorer is checked +# gentoo) +# echo rc-update add \"$name\" default +# ;; centos|fedora|owl|redhat) echo chkconfig \"$name\" on @@ -64,9 +65,10 @@ case "$state_should" in echo update-rc.d -f \"$name\" remove ;; - gentoo) - echo rc-update del \"$name\" - ;; +# Disabled until the explorer is checked +# gentoo) +# echo rc-update del \"$name\" +# ;; centos|fedora|owl|redhat) echo chkconfig \"$name\" off @@ -80,7 +82,6 @@ case "$state_should" in ;; - *) echo "Unknown state: $state_should" >&2 exit 1 From 252ae5ea569f8a789f8605dc7f9e0be267d50d96 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 19 Jan 2012 07:51:02 +0100 Subject: [PATCH 1235/4212] new feature: dependency resolver --- doc/dev/todo/TAKEME | 1 - lib/cdist/config_install.py | 37 ++--- lib/cdist/core/object.py | 16 +- lib/cdist/emulator.py | 26 +--- lib/cdist/resolver.py | 139 ++++++++++++++++++ lib/cdist/test/emulator/__init__.py | 7 + lib/cdist/test/resolver/__init__.py | 88 +++++++++++ .../resolver/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 .../resolver/fixtures/object/__second/.keep | 0 .../object/__second/on-the/.cdist/.keep | 0 .../object/__second/under-the/.cdist/.keep | 0 .../resolver/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 + .../test/resolver/fixtures/type/__first/.keep | 0 .../resolver/fixtures/type/__second/.keep | 0 .../test/resolver/fixtures/type/__third/.keep | 0 22 files changed, 271 insertions(+), 45 deletions(-) create mode 100644 lib/cdist/resolver.py create mode 100644 lib/cdist/test/resolver/__init__.py create mode 100644 lib/cdist/test/resolver/fixtures/object/__first/.keep create mode 100644 lib/cdist/test/resolver/fixtures/object/__first/child/.cdist/.keep create mode 100644 lib/cdist/test/resolver/fixtures/object/__first/dog/.cdist/.keep create mode 100644 lib/cdist/test/resolver/fixtures/object/__first/man/.cdist/.keep create mode 100644 lib/cdist/test/resolver/fixtures/object/__first/woman/.cdist/.keep create mode 100644 lib/cdist/test/resolver/fixtures/object/__second/.keep create mode 100644 lib/cdist/test/resolver/fixtures/object/__second/on-the/.cdist/.keep create mode 100644 lib/cdist/test/resolver/fixtures/object/__second/under-the/.cdist/.keep create mode 100644 lib/cdist/test/resolver/fixtures/object/__third/.keep create mode 100644 lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/.keep create mode 100644 lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name create mode 100644 lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet create mode 100644 lib/cdist/test/resolver/fixtures/type/__first/.keep create mode 100644 lib/cdist/test/resolver/fixtures/type/__second/.keep create mode 100644 lib/cdist/test/resolver/fixtures/type/__third/.keep diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 875d2970..25d088b9 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -3,7 +3,6 @@ UNASSIGNED TODOS The following list of todos has not been assigned to any developer. Feel free to pick one! - TESTS ----- - multiple defines of object: diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 2d2ab949..542f2024 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -27,9 +27,12 @@ import shutil import sys import tempfile import time +import itertools +import pprint import cdist from cdist import core +from cdist import resolver class ConfigInstall(object): @@ -105,29 +108,12 @@ class ConfigInstall(object): def object_run(self, cdist_object): """Run gencode and code for an object""" self.log.debug("Trying to run object " + cdist_object.name) - if cdist_object.state == core.Object.STATE_RUNNING: - # FIXME: resolve dependency circle / show problem source - raise cdist.Error("Detected circular dependency in " + cdist_object.name) - elif cdist_object.state == core.Object.STATE_DONE: - self.log.debug("Ignoring run of already finished object %s", cdist_object) - return - else: - cdist_object.state = core.Object.STATE_RUNNING + if cdist_object.state == core.Object.STATE_DONE: + # TODO: remove once we are sure that this really never happens. + raise cdist.Error("Attempting to run an already finished object: %s", cdist_object) cdist_type = cdist_object.type - for requirement in cdist_object.requirements: - self.log.debug("Object %s requires %s", cdist_object, requirement) - required_object = cdist_object.object_from_name(requirement) - - # The user may have created dependencies without satisfying them - if not required_object.exists: - raise cdist.Error(cdist_object.name + " requires non-existing " + required_object.name) - else: - self.log.debug("Required object %s exists", required_object.name) - - self.object_run(required_object) - # Generate self.log.info("Generating and executing code for " + cdist_object.name) cdist_object.code_local = self.code.run_gencode_local(cdist_object) @@ -149,7 +135,14 @@ class ConfigInstall(object): def stage_run(self): """The final (and real) step of deployment""" self.log.info("Generating and executing code") - for cdist_object in core.Object.list_objects(self.local.object_path, - self.local.type_path): + + objects = core.Object.list_objects( + self.local.object_path, + self.local.type_path) + + dependency_resolver = resolver.DependencyResolver(objects) + self.log.debug(pprint.pformat(dependency_resolver.graph)) + + for cdist_object in dependency_resolver: self.log.debug("Run object: %s", cdist_object) self.object_run(cdist_object) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 9abb11eb..da2f21a6 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -96,12 +96,18 @@ class Object(object): """ return os.path.join(type_name, object_id) - def __init__(self, cdist_type, base_path, object_id=None): + @staticmethod + def validate_object_id(object_id): + """Validate the given object_id and raise IllegalObjectIdError if it's not valid. + """ if object_id: if object_id.startswith('/'): raise IllegalObjectIdError(object_id, 'object_id may not start with /') if OBJECT_MARKER in object_id.split(os.sep): raise IllegalObjectIdError(object_id, 'object_id may not contain \'%s\'' % OBJECT_MARKER) + + def __init__(self, cdist_type, base_path, object_id=None): + self.validate_object_id(object_id) self.type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id @@ -116,8 +122,12 @@ class Object(object): return '' % self.name def __eq__(self, other): - """define equality as 'attributes are the same'""" - return self.__dict__ == other.__dict__ + """define equality as 'name is the same'""" + return self.name == other.name + + def __hash__(self): + return hash(self.name) + def __lt__(self, other): return isinstance(other, self.__class__) and self.name < other.name diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index bb67e7ee..05202a39 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -154,30 +154,18 @@ class Emulator(object): if len(requirement) == 0: continue - self.log.debug("Recording requirement: " + requirement) - requirement_parts = requirement.split(os.sep, 1) - requirement_type_name = requirement_parts[0] - try: - requirement_object_id = requirement_parts[1] - except IndexError: - # no object id, assume singleton - requirement_object_id = 'singleton' - - # Remove leading / from object id - requirement_object_id = requirement_object_id.lstrip('/') - + requirement_type_name, requirement_object_id = core.Object.split_name(requirement) # Instantiate type which fails if type does not exist requirement_type = core.Type(self.type_base_path, requirement_type_name) - if requirement_object_id == 'singleton' \ - and not requirement_type.is_singleton: + if requirement_object_id: + # Validate object_id if any + core.Object.validate_object_id(requirement_object_id) + elif not requirement_type.is_singleton: + # Only singeltons have no object_id raise IllegalRequirementError(requirement, "Missing object_id and type is not a singleton.") - # Instantiate object which fails if the object_id is illegal - requirement_object = core.Object(requirement_type, self.object_base_path, requirement_object_id) - - # Construct cleaned up requirement with only one / :-) - requirement = requirement_type_name + '/' + requirement_object_id + self.log.debug("Recording requirement: " + requirement) self.cdist_object.requirements.append(requirement) # Record / Append source diff --git a/lib/cdist/resolver.py b/lib/cdist/resolver.py new file mode 100644 index 00000000..24a5e496 --- /dev/null +++ b/lib/cdist/resolver.py @@ -0,0 +1,139 @@ +# -*- 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 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) + from pprint import pprint + pprint(resolver.graph) + + for cdist_object in resolver: + do_something_with(cdist_object) + + """ + def __init__(self, objects, logger=None): + self.objects = list(objects) # make sure we store as list, not generator + self._object_index = dict((o.name, o) for o in self.objects) + self._graph = None + self.log = logger or log + + @property + def graph(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._graph is None: + graph = {} + for o in self.objects: + resolved = [] + unresolved = [] + self.resolve_object_dependencies(o, resolved, unresolved) + graph[o.name] = resolved + self._graph = graph + return self._graph + + 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._object_index.keys() + for pattern in requirements: + found = False + for requirement in fnmatch.filter(object_names, pattern): + found = True + yield self._object_index[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._object_index: + yield self._object_index[singleton] + else: + raise RequirementNotFoundError(pattern) + + 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: + raise CircularReferenceError(cdist_object, required_object) + self.resolve_object_dependencies(required_object, resolved, unresolved) + resolved.append(cdist_object) + unresolved.remove(cdist_object) + except RequirementNotFoundError as e: + raise cdist.Error(cdist_object.name + " requires non-existing " + e.requirement) + + def __iter__(self): + """Iterate over all unique objects while resolving dependencies. + """ + iterable = itertools.chain(*self.graph.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 diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index 5a660755..e67bed4a 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -89,6 +89,13 @@ class EmulatorTestCase(test.CdistTestCase): emu.run() # if we get here all is fine + def test_requirement_pattern(self): + argv = ['__file', '/tmp/foobar'] + os.environ.update(self.env) + os.environ['require'] = '__file/etc/*' + emu = emulator.Emulator(argv) + # if we get here all is fine + import os.path as op my_dir = op.abspath(op.dirname(__file__)) diff --git a/lib/cdist/test/resolver/__init__.py b/lib/cdist/test/resolver/__init__.py new file mode 100644 index 00000000..cca058a4 --- /dev/null +++ b/lib/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.Object.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.graph['__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.graph + + 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.graph diff --git a/lib/cdist/test/resolver/fixtures/object/__first/.keep b/lib/cdist/test/resolver/fixtures/object/__first/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/resolver/fixtures/object/__first/child/.cdist/.keep b/lib/cdist/test/resolver/fixtures/object/__first/child/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/resolver/fixtures/object/__first/dog/.cdist/.keep b/lib/cdist/test/resolver/fixtures/object/__first/dog/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/resolver/fixtures/object/__first/man/.cdist/.keep b/lib/cdist/test/resolver/fixtures/object/__first/man/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/resolver/fixtures/object/__first/woman/.cdist/.keep b/lib/cdist/test/resolver/fixtures/object/__first/woman/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/resolver/fixtures/object/__second/.keep b/lib/cdist/test/resolver/fixtures/object/__second/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/resolver/fixtures/object/__second/on-the/.cdist/.keep b/lib/cdist/test/resolver/fixtures/object/__second/on-the/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/resolver/fixtures/object/__second/under-the/.cdist/.keep b/lib/cdist/test/resolver/fixtures/object/__second/under-the/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/resolver/fixtures/object/__third/.keep b/lib/cdist/test/resolver/fixtures/object/__third/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/.keep b/lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name b/lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name new file mode 100644 index 00000000..4129a761 --- /dev/null +++ b/lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name @@ -0,0 +1 @@ +Prometheus diff --git a/lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet b/lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet new file mode 100644 index 00000000..8e6ee422 --- /dev/null +++ b/lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet @@ -0,0 +1 @@ +Saturn diff --git a/lib/cdist/test/resolver/fixtures/type/__first/.keep b/lib/cdist/test/resolver/fixtures/type/__first/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/resolver/fixtures/type/__second/.keep b/lib/cdist/test/resolver/fixtures/type/__second/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/resolver/fixtures/type/__third/.keep b/lib/cdist/test/resolver/fixtures/type/__third/.keep new file mode 100644 index 00000000..e69de29b From a112b4f123d591096bede64ba96545e911204edd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 19 Jan 2012 09:12:54 +0100 Subject: [PATCH 1236/4212] documet debian/ubuntu problem Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/gencode-remote | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index ee2bdeb6..5e9c6343 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -40,6 +40,9 @@ case "$state_should" in present) case "$os" in debian|ubuntu) + # This does not work as expected: + # insserv: warning: current start runlevel(s) (3 4 5) of script `postfix' overwrites defaults (2 3 4 5). + #echo update-rc.d \"$name\" defaults echo update-rc.d \"$name\" defaults ;; From 3bfb1fbe8971538cf5c2370795344195bdbfa2a9 Mon Sep 17 00:00:00 2001 From: Tim Kersten Date: Thu, 19 Jan 2012 10:23:11 +0000 Subject: [PATCH 1237/4212] Add note about leading /'s in __object_id --- doc/man/cdist-reference.text.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 6b4e786f..898771c7 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -180,6 +180,7 @@ __object:: __object_id:: The type unique object id. Available for: type manifest, type explorer, type gencode + Note: The leading "/" will always be stripped. __self:: DEPRECATED: Same as __object_name, do not use anymore, use __object_name instead. Will be removed in cdist 3.x. From 4ed804a09455a235146c856bbd4de903b49cf52c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 19 Jan 2012 20:28:10 +0100 Subject: [PATCH 1238/4212] more changes for 2.0.6 Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 062db392..c31390ba 100644 --- a/doc/changelog +++ b/doc/changelog @@ -7,6 +7,7 @@ * New Type: __rvm_gem (Evax Software) * New Type: __rvm_gemset (Evax Software) * New Type: __rvm_ruby (Evax Software) + * Feature core: Added new dependency resolver (Steven Armstrong) 2.0.5: 2012-01-18 * Bugfix __key_value: Use correct delimiters From aae67652e9cdb79c019c7c405e2a97e0d8c32f90 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Jan 2012 12:57:40 +0100 Subject: [PATCH 1239/4212] explore state of init script on archlinux Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/explorer/state | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/conf/type/__start_on_boot/explorer/state b/conf/type/__start_on_boot/explorer/state index 9d63b84e..1de1fe57 100755 --- a/conf/type/__start_on_boot/explorer/state +++ b/conf/type/__start_on_boot/explorer/state @@ -29,6 +29,23 @@ name="$__object_id" state="present" case "$os" in + archlinux) + # convert bash array to shell + daemons=$(grep ^DAEMONS /etc/rc.conf | sed -e 's/^.*=(//' -e 's/)$//') + + # 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 + ;; + debian|ubuntu) [ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent" ;; From bd32bd0953d3075b21586df15abee23f22eb99c7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Jan 2012 12:58:50 +0100 Subject: [PATCH 1240/4212] setup state in os specific sections to get better overview Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/explorer/state | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/conf/type/__start_on_boot/explorer/state b/conf/type/__start_on_boot/explorer/state index 1de1fe57..ff092a65 100755 --- a/conf/type/__start_on_boot/explorer/state +++ b/conf/type/__start_on_boot/explorer/state @@ -25,8 +25,6 @@ os=$("$__explorer/os") runlevel=$("$__explorer/runlevel") name="$__object_id" -# default -state="present" case "$os" in archlinux) @@ -44,21 +42,23 @@ case "$os" in state="absent" fi done - ;; + ;; debian|ubuntu) + state="present" [ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent" - ;; + ;; centos|fedora|owl|redhat) + state="present" state=$(chkconfig --level "$runlevel" \"$name\" || echo absent) [ "$state" ] || state="present" - ;; + ;; *) echo "Unsupported os: $os" >&2 exit 1 - ;; + ;; esac echo $state From 4ea85fb40224da50eeb945fa0d1a366e846a0196 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Jan 2012 13:12:14 +0100 Subject: [PATCH 1241/4212] ++todo (absent/present) Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 948aa1a5..abcd5097 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -36,3 +36,5 @@ TYPES ------ - __user add option to include --create-home +- ensure that all types, which support --state support + present and absent (consistent look and feel) From e72c39b786eaee7e693a58cb579e311a3944ca71 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Jan 2012 13:12:14 +0100 Subject: [PATCH 1242/4212] ++todo (absent/present) Signed-off-by: Nico Schottelius Conflicts: doc/dev/todo/TAKEME Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 25d088b9..abcd5097 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -36,6 +36,5 @@ TYPES ------ - __user add option to include --create-home -- __init_script? - to enable/disable startup of init stuff - http://linuxhelp.blogspot.com/2006/04/enabling-and-disabling-services-during_01.html +- ensure that all types, which support --state support + present and absent (consistent look and feel) From 578fd664e44ecfbac7ab7a89fc27faa401528ca0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Jan 2012 13:14:24 +0100 Subject: [PATCH 1243/4212] __process: support present/absent Signed-off-by: Nico Schottelius --- conf/type/__process/gencode-remote | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/conf/type/__process/gencode-remote b/conf/type/__process/gencode-remote index f8da1795..be0e0cae 100755 --- a/conf/type/__process/gencode-remote +++ b/conf/type/__process/gencode-remote @@ -18,8 +18,6 @@ # along with cdist. If not, see . # # -# __file is a very basic type, which will probably be reused quite often -# if [ -f "$__object/parameter/name" ]; then name="$(cat "$__object/parameter/name")" @@ -28,10 +26,10 @@ else fi runs="$(cat "$__object/explorer/runs")" -state="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" -case "$state" in - running) +case "$state_should" in + running|present) # Does not run, start it! if [ -z "$runs" ]; then if [ -f "$__object/parameter/start" ]; then @@ -41,7 +39,7 @@ case "$state" in fi fi ;; - stopped) + stopped|absent) # Runs, kill it! if [ "$runs" ]; then if [ -f "$__object/parameter/stop" ]; then @@ -52,7 +50,7 @@ case "$state" in fi ;; *) - echo "Unknown state: $state" >&2 + echo "Unknown state: $state_should" >&2 exit 1 ;; From 6d5c69d5c423b2dcb049b11618b4f15216213161 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Jan 2012 14:16:49 +0100 Subject: [PATCH 1244/4212] remove runlevel parameter for now - seems to be too complex/unecessary for the moment Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/man.text | 4 ---- 1 file changed, 4 deletions(-) diff --git a/conf/type/__start_on_boot/man.text b/conf/type/__start_on_boot/man.text index 5614f16b..e9691401 100644 --- a/conf/type/__start_on_boot/man.text +++ b/conf/type/__start_on_boot/man.text @@ -23,10 +23,6 @@ OPTIONAL PARAMETERS state:: 'present' or 'absent', defaults to 'present' -runlevel:: - Specify runlevel(s) to affect. Defaults to default or current runlevel. - NOT YET SUPPORTED, ALWAYS USING CURRENT RUNLEVEL. - EXAMPLES -------- From a357d7d794990d3123a36c6690ccf5ac8ed979fb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Jan 2012 14:57:25 +0100 Subject: [PATCH 1245/4212] support adding start on boot on archlinux (no removal so far) Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/gencode-remote | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index 5e9c6343..c13013ad 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -33,12 +33,12 @@ state_is=$(cat "$__object/explorer/state") os=$(cat "$__global/explorer/os") name="$__object_id" -# Support runlevels later -#runlevel=$(cat $__global/explorer/runlevel) - case "$state_should" in present) case "$os" in + archlinux) + echo sed -i /etc/rc.conf \"s/^\\(DAEMONS=.*\\))/\\1 foo)/\" + ;; debian|ubuntu) # This does not work as expected: # insserv: warning: current start runlevel(s) (3 4 5) of script `postfix' overwrites defaults (2 3 4 5). From 6d14e32911c78130860718515115fe8a1ec248b1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Jan 2012 15:34:18 +0100 Subject: [PATCH 1246/4212] support removal and correct adding daemons on archlinux Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/gencode-remote | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index c13013ad..61a6b465 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -37,7 +37,7 @@ case "$state_should" in present) case "$os" in archlinux) - echo sed -i /etc/rc.conf \"s/^\\(DAEMONS=.*\\))/\\1 foo)/\" + echo sed -i /etc/rc.conf \"s/^\\(DAEMONS=.*\\))/\\1 $name)/\" ;; debian|ubuntu) # This does not work as expected: @@ -64,6 +64,9 @@ case "$state_should" in absent) case "$os" in + archlinux) + echo sed -i /etc/rc.conf -e \"s/ $name / /g\" -e \"s/($name/(/\" -e \"s/ $name)/)/\" + ;; debian|ubuntu) echo update-rc.d -f \"$name\" remove ;; From 1b263b57cfde719eb8a8134555317201d1e8e0aa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Jan 2012 16:30:44 +0100 Subject: [PATCH 1247/4212] prefer ' over " Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index 61a6b465..09c4912d 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -37,7 +37,7 @@ case "$state_should" in present) case "$os" in archlinux) - echo sed -i /etc/rc.conf \"s/^\\(DAEMONS=.*\\))/\\1 $name)/\" + echo sed -i /etc/rc.conf \'s/^\\(DAEMONS=.*\\))/\\1 $name)/\' ;; debian|ubuntu) # This does not work as expected: From a485ad6c3ee8df8f9d4345899bdd897f3d519a19 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Jan 2012 16:33:50 +0100 Subject: [PATCH 1248/4212] add homebrew to macosx Signed-off-by: Nico Schottelius --- README | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README b/README index 3ab11928..f8ee411b 100644 --- a/README +++ b/README @@ -135,7 +135,13 @@ If you want to ensure nothing breaks you must set back the python version to wha #### Max OS X -Ensure you have port installed and configured (http://www.macports.org/install.php). +You can choose between Homebrew and Macports, either way works: + +[Homebrew](http://mxcl.github.com/homebrew/) variant: + + brew install python3 + +[Macports](http://www.macports.org/install.php) variant: port install python32 ln -s /opt/local/bin/python3.2 /opt/local/bin/python3 From 287996c4a68726273e880de57276a95d2e75c313 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Jan 2012 17:25:33 +0100 Subject: [PATCH 1249/4212] link to latest and all versions Signed-off-by: Nico Schottelius --- README | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README b/README index f8ee411b..51fb323c 100644 --- a/README +++ b/README @@ -50,10 +50,11 @@ UNIX, simplicity, familar environment | cdist is configured in POSIX shell ### Documentation -The cdist documentation is included as manpages in the distribution. +The cdist documentation is included as manpages in the distribution. +You can browse the documentation online as well: - * You can [browse the documentation of the latest version online](man) as well. - * Have a look at the [given speeches](speeches) + * [latest version](man/latest) + * [all versions (>= 2.0.4)](man) ### OS support From d53accd57f7815733e08dddfb8202ce2b466c0dd Mon Sep 17 00:00:00 2001 From: Matt Coddington Date: Fri, 20 Jan 2012 18:02:28 +0100 Subject: [PATCH 1250/4212] Subject: [cdist] [BUG] fix for conf/type/__group/gencode-remote I noticed $current_value was not getting set correctly in __group/gencode-remote and tracked it down to this trivial fix (applies to current master). I'm unfortunately not comfortable enough with git yet to submit it that way... hopefully this is an appropriate way to submit: Signed-off-by: Nico Schottelius --- conf/type/__group/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__group/gencode-remote b/conf/type/__group/gencode-remote index 20e08738..cf26a437 100755 --- a/conf/type/__group/gencode-remote +++ b/conf/type/__group/gencode-remote @@ -29,7 +29,7 @@ if grep -q "^${name}:" "$__object/explorer/group"; then for property in $(ls .); do new_value="$(cat "$property")" - case "$key" in + case "$property" in password) current_value="$(awk -F: '{ print $2 }' < "$__object/explorer/gshadow")" ;; From ad51dcd8b546c09328ef9abcd6b67f6621fb75bb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Jan 2012 18:03:58 +0100 Subject: [PATCH 1251/4212] ++ changes for 2.0.6 Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index c31390ba..1136f742 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,6 +1,8 @@ 2.0.6: * Bugfix __apt_ppa: Also remove the [ppa-name].list file, if empty. (Tim Kersten) + * Bugfix __group: + Referenced wrong variable name (Matt Coddington) * Feature __package_apt: Initial support for virtual packages (Evax Software) * New Type: __rvm (Evax Software) From c5bd76ffbccaa54a80b23b45362a108dbb5a87d6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 23 Jan 2012 10:41:57 +0100 Subject: [PATCH 1252/4212] ++ changes: __rsyncer Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 1136f742..fdd9c16d 100644 --- a/doc/changelog +++ b/doc/changelog @@ -9,6 +9,7 @@ * New Type: __rvm_gem (Evax Software) * New Type: __rvm_gemset (Evax Software) * New Type: __rvm_ruby (Evax Software) + * New Type: __rsyncer (Daniel Maher) * Feature core: Added new dependency resolver (Steven Armstrong) 2.0.5: 2012-01-18 From f73709d467d6a624712be458e0036eab29a4abd8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 23 Jan 2012 10:45:52 +0100 Subject: [PATCH 1253/4212] document bug in __rsyncer (needs to be fixed) Signed-off-by: Nico Schottelius --- conf/type/__rsyncer/gencode-local | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/conf/type/__rsyncer/gencode-local b/conf/type/__rsyncer/gencode-local index 0d08e445..5d1f17b1 100755 --- a/conf/type/__rsyncer/gencode-local +++ b/conf/type/__rsyncer/gencode-local @@ -40,5 +40,9 @@ if [ -f "$__object/parameter/delete" ]; then args="$args --delete" fi +# FIXME: +# - using root@ may break - find a good way to avoid this +# - align with __remote_{exec,copy} variables? + # Run rsync (locally). echo "$rsyncbin $args $source root@$__target_host:$destination" From 88ea9bf245a20c4e835147121bc391eae8882ef4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 23 Jan 2012 10:46:22 +0100 Subject: [PATCH 1254/4212] remove --stats: if nothing changed, nothing should be printed on stdout Signed-off-by: Nico Schottelius --- conf/type/__rsyncer/gencode-local | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__rsyncer/gencode-local b/conf/type/__rsyncer/gencode-local index 5d1f17b1..9635707b 100755 --- a/conf/type/__rsyncer/gencode-local +++ b/conf/type/__rsyncer/gencode-local @@ -33,7 +33,7 @@ else rsyncbin=`which rsync` fi -args='-a --stats' +args='-a' # If the --delete argument should be passed to rsync. if [ -f "$__object/parameter/delete" ]; then From 8447702c5047f5e3f09e4507f6dec3c63926b303 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 26 Jan 2012 11:56:12 +0100 Subject: [PATCH 1255/4212] update changelog, move __rsyncer from types to other/ (see README.inclusion) Signed-off-by: Nico Schottelius --- doc/changelog | 7 +++++- .../__rsyncer/README.inclusion | 22 +++++++++++++++++++ .../__rsyncer/gencode-local | 0 .../__rsyncer/man.text | 0 .../__rsyncer/parameter/optional | 0 .../__rsyncer/parameter/required | 0 6 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 other/types_submitted_for_inclusion/__rsyncer/README.inclusion rename {conf/type => other/types_submitted_for_inclusion}/__rsyncer/gencode-local (100%) rename {conf/type => other/types_submitted_for_inclusion}/__rsyncer/man.text (100%) rename {conf/type => other/types_submitted_for_inclusion}/__rsyncer/parameter/optional (100%) rename {conf/type => other/types_submitted_for_inclusion}/__rsyncer/parameter/required (100%) diff --git a/doc/changelog b/doc/changelog index fdd9c16d..3679ae0f 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,3 +1,9 @@ +Changelog +--------- + + * Changes are always commented with their author in (braces) + * Exception: No braces means author == Nico Schottelius + 2.0.6: * Bugfix __apt_ppa: Also remove the [ppa-name].list file, if empty. (Tim Kersten) @@ -9,7 +15,6 @@ * New Type: __rvm_gem (Evax Software) * New Type: __rvm_gemset (Evax Software) * New Type: __rvm_ruby (Evax Software) - * New Type: __rsyncer (Daniel Maher) * Feature core: Added new dependency resolver (Steven Armstrong) 2.0.5: 2012-01-18 diff --git a/other/types_submitted_for_inclusion/__rsyncer/README.inclusion b/other/types_submitted_for_inclusion/__rsyncer/README.inclusion new file mode 100644 index 00000000..eff48995 --- /dev/null +++ b/other/types_submitted_for_inclusion/__rsyncer/README.inclusion @@ -0,0 +1,22 @@ +Description: + + Type that supports transfer of huge data, which is a general problem in + configuration management systems. + + Good solution using standardised rsync approach. + +Problem: + + Uses root@$__target_host:$destination notation for transfer. + This breaks the concept of being able to replace __remote_exec and + __remote_copy and then doing chroot or different stuff. + + This breaks for instance, if __remote_copy = cp and the destination is + a local chroot. + +Solutions: + + - Have cdist provide support for rsync syntax? + - Integrate __rsyncer more in line with philosohpy of other components + - Think about the general way of __rsyncer and what cdist would need + to provide for general solution. diff --git a/conf/type/__rsyncer/gencode-local b/other/types_submitted_for_inclusion/__rsyncer/gencode-local similarity index 100% rename from conf/type/__rsyncer/gencode-local rename to other/types_submitted_for_inclusion/__rsyncer/gencode-local diff --git a/conf/type/__rsyncer/man.text b/other/types_submitted_for_inclusion/__rsyncer/man.text similarity index 100% rename from conf/type/__rsyncer/man.text rename to other/types_submitted_for_inclusion/__rsyncer/man.text diff --git a/conf/type/__rsyncer/parameter/optional b/other/types_submitted_for_inclusion/__rsyncer/parameter/optional similarity index 100% rename from conf/type/__rsyncer/parameter/optional rename to other/types_submitted_for_inclusion/__rsyncer/parameter/optional diff --git a/conf/type/__rsyncer/parameter/required b/other/types_submitted_for_inclusion/__rsyncer/parameter/required similarity index 100% rename from conf/type/__rsyncer/parameter/required rename to other/types_submitted_for_inclusion/__rsyncer/parameter/required From 211ee5b043c167a111e591fc4d42c342646fe372 Mon Sep 17 00:00:00 2001 From: Matt Coddington Date: Wed, 25 Jan 2012 23:11:59 -0500 Subject: [PATCH 1256/4212] adding support for amazon linux --- conf/explorer/os | 5 +++++ conf/explorer/os_version | 3 +++ conf/type/__package/manifest | 2 +- conf/type/__package_yum/gencode-remote | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/conf/explorer/os b/conf/explorer/os index 1aafb468..a7eebb8a 100755 --- a/conf/explorer/os +++ b/conf/explorer/os @@ -75,6 +75,11 @@ if [ -f /etc/cdist-preos ]; then exit 0 fi +if grep -q ^Amazon /etc/system-release 2>/dev/null; then + echo amazon + exit 0 +fi + uname_s="$(uname -s)" # Assume there is no tr on the client -> do lower case ourselves diff --git a/conf/explorer/os_version b/conf/explorer/os_version index ef80e8fc..73d3ecd7 100755 --- a/conf/explorer/os_version +++ b/conf/explorer/os_version @@ -23,6 +23,9 @@ # case "$($__explorer/os)" in + amazon) + cat /etc/system-release + ;; archlinux) # empty, but well... cat /etc/arch-release diff --git a/conf/type/__package/manifest b/conf/type/__package/manifest index 48818dd8..f344cff7 100755 --- a/conf/type/__package/manifest +++ b/conf/type/__package/manifest @@ -33,7 +33,7 @@ else archlinux) type="pacman" ;; debian|ubuntu) type="apt" ;; gentoo) type="emerge" ;; - fedora|redhat|centos) type="yum" ;; + fedora|redhat|centos|amazon) type="yum" ;; *) echo "Don't know how to manage packages on: $os" >&2 exit 1 diff --git a/conf/type/__package_yum/gencode-remote b/conf/type/__package_yum/gencode-remote index e43712f8..b24ed220 100755 --- a/conf/type/__package_yum/gencode-remote +++ b/conf/type/__package_yum/gencode-remote @@ -29,7 +29,7 @@ fi state="$(cat "$__object/parameter/state")" -if grep -q -E "(centos|redhat)" "$__global/explorer/os"; then +if grep -q -E "(centos|redhat|amazon)" "$__global/explorer/os"; then opts="-y --quiet" else opts="--assumeyes --quiet" From e25eff23d090218c5c3d21e3a564674721aa93da Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 27 Jan 2012 08:38:36 +0100 Subject: [PATCH 1257/4212] document amazon linux support Signed-off-by: Nico Schottelius --- doc/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 3679ae0f..ac53ea40 100644 --- a/doc/changelog +++ b/doc/changelog @@ -11,11 +11,12 @@ Changelog Referenced wrong variable name (Matt Coddington) * Feature __package_apt: Initial support for virtual packages (Evax Software) + * Feature Core: Added new dependency resolver (Steven Armstrong) + * Feature Explorer, __package_yum: Support Amazon Linux (Matt Coddington) * New Type: __rvm (Evax Software) * New Type: __rvm_gem (Evax Software) * New Type: __rvm_gemset (Evax Software) * New Type: __rvm_ruby (Evax Software) - * Feature core: Added new dependency resolver (Steven Armstrong) 2.0.5: 2012-01-18 * Bugfix __key_value: Use correct delimiters From 84ca02d7cac9efb1f449d8e8bc20f5cee6293f68 Mon Sep 17 00:00:00 2001 From: Matt Coddington Date: Fri, 27 Jan 2012 04:35:50 -0500 Subject: [PATCH 1258/4212] alphabetize os explorer --- conf/explorer/os | 65 +++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/conf/explorer/os b/conf/explorer/os index a7eebb8a..3f3ce266 100755 --- a/conf/explorer/os +++ b/conf/explorer/os @@ -18,13 +18,14 @@ # along with cdist. If not, see . # # -# All os variables are lower case -# +# All os variables are lower case. Keep this file in alphabetical +# order by os variable except in cases where order otherwise matters, +# in which case keep the primary os and its derivatives together in +# a block (see Debian and Redhat examples below). # -# Ubuntu is also Debian, thus return if Ubuntu was found -if grep -q ^DISTRIB_ID=Ubuntu /etc/lsb-release 2>/dev/null; then - echo ubuntu +if grep -q ^Amazon /etc/system-release 2>/dev/null; then + echo amazon exit 0 fi @@ -33,50 +34,52 @@ if [ -f /etc/arch-release ]; then exit 0 fi +if [ -f /etc/cdist-preos ]; then + echo cdist-preos + exit 0 +fi + +### Debian and derivatives +if grep -q ^DISTRIB_ID=Ubuntu /etc/lsb-release 2>/dev/null; then + echo ubuntu + exit 0 +fi + if [ -f /etc/debian_version ]; then echo debian exit 0 fi +### if [ -f /etc/gentoo-release ]; then echo gentoo exit 0 fi -# Fedora is also Redhat, thus return before redhat! -if grep -q ^Fedora /etc/redhat-release 2>/dev/null; then - echo fedora - exit 0 -fi - -# CentOS is also based on Redhat, thus return before redhat! -if grep -q ^CentOS /etc/redhat-release 2>/dev/null; then - echo centos - exit 0 -fi - -if [ -f /etc/redhat-release ]; then - echo redhat - exit 0 -fi - -if [ -f /etc/SuSE-release ]; then - echo suse - exit 0 -fi - if [ -f /etc/owl-release ]; then echo owl exit 0 fi -if [ -f /etc/cdist-preos ]; then - echo cdist-preos +### Redhat and derivatives +if grep -q ^CentOS /etc/redhat-release 2>/dev/null; then + echo centos + exit 0 +fi + +if grep -q ^Fedora /etc/redhat-release 2>/dev/null; then + echo fedora exit 0 fi -if grep -q ^Amazon /etc/system-release 2>/dev/null; then - echo amazon +if [ -f /etc/redhat-release ]; then + echo redhat + exit 0 +fi +### + +if [ -f /etc/SuSE-release ]; then + echo suse exit 0 fi From bf8c5863d7ae742925efb217f628b9471c24209c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 28 Jan 2012 20:43:29 +0100 Subject: [PATCH 1259/4212] release date for 2.0.6 Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index ac53ea40..531e8de1 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.0.6: +2.0.6: 2012-01-28 * Bugfix __apt_ppa: Also remove the [ppa-name].list file, if empty. (Tim Kersten) * Bugfix __group: From 72fefef32050f2c686931dc66eb9babb8c3fd65b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 28 Jan 2012 20:49:47 +0100 Subject: [PATCH 1260/4212] increment version, update web release Signed-off-by: Nico Schottelius --- build | 7 ++++++- lib/cdist/__init__.py | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/build b/build index 5cc59b6d..ea4ca83c 100755 --- a/build +++ b/build @@ -99,7 +99,7 @@ case "$1" in webmain) cp README ${WEBPAGE} - cd ${WEBDIR} && git commit -m "cdist update" ${WEBPAGE} + cd ${WEBDIR} && git commit -m "cdist main update" ${WEBPAGE} cd ${WEBDIR} && make pub ;; @@ -119,6 +119,11 @@ case "$1" in cd ${WEBDIR} && git add ${WEBBASE} cd ${WEBDIR} && git commit -m "cdist update" ${WEBBASE} ${WEBPAGE} cd ${WEBDIR} && make 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 && + ln -sf "$version" latest" ;; p|pu|pub) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 09e4aacc..664b6456 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -19,6 +19,8 @@ # # +VERSION = "2.0.6" + BANNER = """ .. . .x+=:. s dF @88> z` ^% :8 @@ -34,7 +36,6 @@ BANNER = """ "P' "" "" """ DOT_CDIST = ".cdist" -VERSION = "2.0.5" import os From 78b44d4ddc4a2b20e8475c237769480fa0855214 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 28 Jan 2012 20:57:19 +0100 Subject: [PATCH 1261/4212] correctly grep for moved version string Signed-off-by: Nico Schottelius --- doc/dev/releasechecklist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index cb6d610d..19ab7b18 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -11,7 +11,7 @@ echo "Testing documentation..." ./build clean && ./build man || exit 1 # get version -changelog_version=$(head -n1 doc/changelog | sed 's/:.*//') +changelog_version=$(grep '^[[:digit:]]' doc/changelog | head -n1 | sed 's/:.*//') #git_version=$(git describe) lib_version=$(grep ^VERSION lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g') From 6fa8f1d051e2729b7f1c07949067b479e20a4798 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 30 Jan 2012 11:52:41 +0100 Subject: [PATCH 1262/4212] sort os by alphabet Signed-off-by: Nico Schottelius --- conf/type/__package/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__package/manifest b/conf/type/__package/manifest index f344cff7..181da077 100755 --- a/conf/type/__package/manifest +++ b/conf/type/__package/manifest @@ -33,7 +33,7 @@ else archlinux) type="pacman" ;; debian|ubuntu) type="apt" ;; gentoo) type="emerge" ;; - fedora|redhat|centos|amazon) type="yum" ;; + amazon|centos|fedora|redhat) type="yum" ;; *) echo "Don't know how to manage packages on: $os" >&2 exit 1 From 77545919fe07fa427c560bd63c394a9e78c8c81d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 30 Jan 2012 11:53:53 +0100 Subject: [PATCH 1263/4212] ++todo nico Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index abcd5097..42449f63 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -34,7 +34,3 @@ USER INTERFACE TYPES ------ -- __user - add option to include --create-home -- ensure that all types, which support --state support - present and absent (consistent look and feel) From aa79b05fb14d3fc059626de8b139242bb76aa292 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 30 Jan 2012 11:53:55 +0100 Subject: [PATCH 1264/4212] ++todo nico Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index ad859266..d7fb2e73 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,3 +1,8 @@ +- __user + add option to include --create-home +- ensure that all types, which support --state support + present and absent (consistent look and feel) + - update/create docs - cdist-cache:: How to get use information about the hosts we have been working on [advanced] From 23eba4c5e180d0e8c351b7ec0815426484e6e0ee Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 1 Feb 2012 11:55:58 +0100 Subject: [PATCH 1265/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 42449f63..95bda7fb 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -34,3 +34,4 @@ USER INTERFACE TYPES ------ +- Add testing framework (proposed by Evax Software) From 37c02dad45065fb2203b85071f9b71b3cf77a045 Mon Sep 17 00:00:00 2001 From: Matt Coddington Date: Thu, 2 Feb 2012 11:09:20 -0500 Subject: [PATCH 1266/4212] bugfix - do chmod last --- conf/type/__file/gencode-remote | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/conf/type/__file/gencode-remote b/conf/type/__file/gencode-remote index 9e700934..2b4c7e45 100755 --- a/conf/type/__file/gencode-remote +++ b/conf/type/__file/gencode-remote @@ -34,11 +34,6 @@ case "$state_should" in fi fi - # Mode settings - if [ -f "$__object/parameter/mode" ]; then - echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" - fi - # Group if [ -f "$__object/parameter/group" ]; then echo chgrp \"$(cat "$__object/parameter/group")\" \"$destination\" @@ -48,6 +43,12 @@ case "$state_should" in 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 ;; absent) From 63ba527bd8da1b420928bf375c5cbd6daaf169a1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 2 Feb 2012 22:07:53 +0100 Subject: [PATCH 1267/4212] first changes for 2.0.7 Signed-off-by: Nico Schottelius --- doc/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/changelog b/doc/changelog index 531e8de1..6e6b9ccb 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.0.7: + * Bugfix __file: Use chmod after chown/chgrp (Matt Coddington) + 2.0.6: 2012-01-28 * Bugfix __apt_ppa: Also remove the [ppa-name].list file, if empty. (Tim Kersten) From 85f7880c7ed4b86453e837bc781861ac0cd694e5 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 3 Feb 2012 20:50:17 +0100 Subject: [PATCH 1268/4212] add a hopefully more robust implementation for changing existing values Signed-off-by: Steven Armstrong --- conf/type/__key_value/gencode-remote | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/conf/type/__key_value/gencode-remote b/conf/type/__key_value/gencode-remote index eff0925c..08b3a0f3 100755 --- a/conf/type/__key_value/gencode-remote +++ b/conf/type/__key_value/gencode-remote @@ -40,10 +40,7 @@ DONE else # change value cat << DONE -awk -F "$delimiter" ' -/${key}${delimiter}*/{gsub("$value_is", "$value_should")};{print}' "$file" > "${file}+" \ -&& mv "${file}+" "$file" - +sed -i "s|^$key\($delimiter\+\).*|$key\1$value_should|" "$file" DONE fi ;; From 4628dad04576103945553609c9e46c71cee35de8 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 3 Feb 2012 20:55:24 +0100 Subject: [PATCH 1269/4212] cleaner way to set default values Signed-off-by: Steven Armstrong --- conf/type/__key_value/explorer/value | 8 +++----- conf/type/__key_value/manifest | 9 +++------ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/conf/type/__key_value/explorer/value b/conf/type/__key_value/explorer/value index 3afc7cc5..b4e1fafd 100755 --- a/conf/type/__key_value/explorer/value +++ b/conf/type/__key_value/explorer/value @@ -21,11 +21,9 @@ # Get the current value of key or __NOTSET__ if the key doesn't exist. # -if [ -f "$__object/parameter/key" ]; then - key="$(cat "$__object/parameter/key")" -else - key="$__object_id" -fi +key="$(cat "$__object/parameter/key" 2>/dev/null \ + || echo "$__object_id")" + file="$(cat "$__object/parameter/file")" delimiter="$(cat "$__object/parameter/delimiter")" diff --git a/conf/type/__key_value/manifest b/conf/type/__key_value/manifest index 706b0b0d..84c06352 100755 --- a/conf/type/__key_value/manifest +++ b/conf/type/__key_value/manifest @@ -18,9 +18,6 @@ # along with cdist. If not, see . # -if [ -f "$__object/parameter/key" ]; then - key="$(cat "$__object/parameter/key")" -else - echo "$__object_id" > "$__object/parameter/key" -fi - +# set defaults +[ -f "$__object/parameter/key" ] \ + || echo "$__object_id" > "$__object/parameter/key" From cad2097d0559861f66a988c88c4022721fa8c033 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 3 Feb 2012 22:43:34 +0100 Subject: [PATCH 1270/4212] complete rewrite: use state explorer to determine current state, more robust implementation for adding, changing, removing key/values Signed-off-by: Steven Armstrong --- .../__key_value/explorer/{value => state} | 35 ++++++++---- conf/type/__key_value/gencode-remote | 54 +++++++++++-------- conf/type/__key_value/man.text | 11 ++-- conf/type/__key_value/manifest | 11 +++- conf/type/__key_value/parameter/optional | 2 + conf/type/__key_value/parameter/required | 1 - 6 files changed, 75 insertions(+), 39 deletions(-) rename conf/type/__key_value/explorer/{value => state} (54%) diff --git a/conf/type/__key_value/explorer/value b/conf/type/__key_value/explorer/state similarity index 54% rename from conf/type/__key_value/explorer/value rename to conf/type/__key_value/explorer/state index b4e1fafd..7e66cb69 100755 --- a/conf/type/__key_value/explorer/value +++ b/conf/type/__key_value/explorer/state @@ -17,19 +17,34 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# -# Get the current value of key or __NOTSET__ if the key doesn't exist. -# key="$(cat "$__object/parameter/key" 2>/dev/null \ || echo "$__object_id")" - +state="$(cat "$__object/parameter/state" 2>/dev/null \ + || echo "present")" file="$(cat "$__object/parameter/file")" delimiter="$(cat "$__object/parameter/delimiter")" +value="$(cat "$__object/parameter/value" 2>/dev/null \ + || echo "__CDIST_NOTSET__")" -awk -F "$delimiter" ' -BEGIN { found=0 } -/^'$key'/ { print $2; found=1 } -END { if (found) exit 0; else exit 1 }' "$file" \ -|| echo "__NOTSET__" - +case "$state" in + absent) + # if the key exists, with whatever value, we will have to remove it + # so report it as present + if egrep -q "^$key$delimiter+" "$file"; then + echo present + fi + ;; + present) + if egrep -q "^$key$delimiter+$value$" "$file"; then + # key exists and value is same + echo present + elif egrep -q "^$key$delimiter+" "$file"; then + # key exists, but value is empty or different + echo wrongvalue + else + # key does not exist + echo absent + fi + ;; +esac diff --git a/conf/type/__key_value/gencode-remote b/conf/type/__key_value/gencode-remote index 08b3a0f3..0846dca1 100755 --- a/conf/type/__key_value/gencode-remote +++ b/conf/type/__key_value/gencode-remote @@ -18,32 +18,40 @@ # along with cdist. If not, see . # -value_is="$(cat "$__object/explorer/value")" -value_should="$(cat "$__object/parameter/value")" - key="$(cat "$__object/parameter/key")" file="$(cat "$__object/parameter/file")" delimiter="$(cat "$__object/parameter/delimiter")" +value="$(cat "$__object/parameter/value")" -if [ "$value_is" != "$value_should" ]; then - case "$value_is" in - __NOTSET__) - # add key and value - echo "echo \"${key}${delimiter}${value_should}\" >> \"$file\"" - ;; - *) - if [ "$value_should" = '__NOTSET__' ]; then - # remove key and value - cat << DONE -sed -i '/^${key}/d' "$file" -DONE - else - # change value - cat << DONE -sed -i "s|^$key\($delimiter\+\).*|$key\1$value_should|" "$file" -DONE - fi - ;; - esac +state_is="$(cat "$__object/explorer/state")" +state_should="$(cat "$__object/parameter/state")" + +if [ "$state_is" = "$state_should" ]; then + # nothing to do + exit 0 fi +case "$state_should" in + absent) + # remove lines starting with key + echo "sed -i '/^$key\($delimiter\+\)/d' \"$file\"" + ;; + present) + case "$state_is" in + absent) + # add new key and value + echo "echo \"${key}${delimiter}${value}\" >> \"$file\"" + ;; + wrongvalue) + # change exisiting value + echo "sed -i \"s|^$key\($delimiter\+\).*|$key\1$value|\" \"$file\"" + ;; + *) + echo "Unknown explorer state: $state_is" >&2 + exit 1 + esac + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 +esac diff --git a/conf/type/__key_value/man.text b/conf/type/__key_value/man.text index 3e4e8013..1423fc7d 100644 --- a/conf/type/__key_value/man.text +++ b/conf/type/__key_value/man.text @@ -16,9 +16,6 @@ file. REQUIRED PARAMETERS ------------------- -value:: - The value for the key. Setting the value to `__NOTSET__` will remove the key - from the file. file:: The file to operate on. delimiter:: @@ -27,8 +24,13 @@ delimiter:: OPTIONAL PARAMETERS ------------------- +state:: + present or absent, defaults to present. If present, sets the key to value, + if absent, removes the key from the file. key:: The key to change. Defaults to object_id. +value:: + The value for the key. Optional if state=absent, required otherwise. EXAMPLES @@ -45,6 +47,9 @@ __key_value my-fancy-id --file /etc/login.defs --key SYS_UID_MAX --value 666 \ # Enable packet forwarding __key_value net.ipv4.ip_forward --file /etc/sysctl.conf --value 1 \ --delimiter '=' + +# Remove existing key/value +__key_value LEGACY_KEY --file /etc/somefile --state absent --delimiter '=' -------------------------------------------------------------------------------- diff --git a/conf/type/__key_value/manifest b/conf/type/__key_value/manifest index 84c06352..2e75e175 100755 --- a/conf/type/__key_value/manifest +++ b/conf/type/__key_value/manifest @@ -19,5 +19,12 @@ # # set defaults -[ -f "$__object/parameter/key" ] \ - || echo "$__object_id" > "$__object/parameter/key" +key="$(cat "$__object/parameter/key" 2>/dev/null \ + || echo "$__object_id" | tee "$__object/parameter/key")" +state="$(cat "$__object/parameter/state" 2>/dev/null \ + || echo "present" | tee "$__object/parameter/state")" + +if [ "$state" = "present" -a ! -f "$__object/parameter/value" ]; then + echo "Missing required parameter 'value'" >&2 + exit 1 +fi diff --git a/conf/type/__key_value/parameter/optional b/conf/type/__key_value/parameter/optional index 06bfde49..483e3192 100644 --- a/conf/type/__key_value/parameter/optional +++ b/conf/type/__key_value/parameter/optional @@ -1 +1,3 @@ key +value +state diff --git a/conf/type/__key_value/parameter/required b/conf/type/__key_value/parameter/required index 8f4aa53c..3ae10da3 100644 --- a/conf/type/__key_value/parameter/required +++ b/conf/type/__key_value/parameter/required @@ -1,3 +1,2 @@ -value file delimiter From ef81f03e89a2b53498f52d2e6262ea0ec94afdd4 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 3 Feb 2012 22:49:10 +0100 Subject: [PATCH 1271/4212] have to report absent state no matter what the desired state is Signed-off-by: Steven Armstrong --- conf/type/__key_value/explorer/state | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/conf/type/__key_value/explorer/state b/conf/type/__key_value/explorer/state index 7e66cb69..ec760f71 100755 --- a/conf/type/__key_value/explorer/state +++ b/conf/type/__key_value/explorer/state @@ -29,10 +29,13 @@ value="$(cat "$__object/parameter/value" 2>/dev/null \ case "$state" in absent) - # if the key exists, with whatever value, we will have to remove it - # so report it as present if egrep -q "^$key$delimiter+" "$file"; then + # if the key exists, with whatever value, we will have to remove it + # so report it as present echo present + else + # key does not exist + echo absent fi ;; present) From 9d25dfdfa9c41a59fc67fce3e41e5b6292de6bdd Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 6 Feb 2012 21:08:59 +0100 Subject: [PATCH 1272/4212] properly handle existing links Signed-off-by: Steven Armstrong --- conf/type/__link/explorer/state | 62 +++++++++++++++++++++++++++++++++ conf/type/__link/gencode-remote | 7 ++++ 2 files changed, 69 insertions(+) create mode 100755 conf/type/__link/explorer/state diff --git a/conf/type/__link/explorer/state b/conf/type/__link/explorer/state new file mode 100755 index 00000000..a9220a3c --- /dev/null +++ b/conf/type/__link/explorer/state @@ -0,0 +1,62 @@ +#!/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 . +# + +destination="/$__object_id" +type="$(cat "$__object/parameter/type")" +source="$(cat "$__object/parameter/source")" + +# no destination? -> state is absent +if [ ! -e "$destination" ]; then + echo absent + exit 0 +fi + +destination_dir="${destination%/*}" + +case "$type" in + symbolic) + cd "$destination_dir" + source_is=$(ls -l "$destination" | sed 's/.*-> //g') + if [ -h "$destination" -a "$source_is" = "$source" ]; then + echo present + else + echo absent + fi + ;; + hard) + cd "$destination_dir" + # check source relative to destination_dir + if [ ! -e "$source" ]; then + echo sourcemissing + exit 0 + fi + destination_inode=$(ls -i "$destination" | awk '{print $1}') + source_inode=$(ls -i "$source" | awk '{print $1}') + if [ "$destination_inode" -eq "$source_inode" ]; then + echo present + else + echo absent + fi + ;; + *) + echo "Unknown type: $type" >&2 + exit 1 + ;; +esac diff --git a/conf/type/__link/gencode-remote b/conf/type/__link/gencode-remote index 0a367654..8d4cc3d5 100755 --- a/conf/type/__link/gencode-remote +++ b/conf/type/__link/gencode-remote @@ -39,7 +39,14 @@ case "$type" in ;; esac +state_is="$(cat "$__object/explorer/state")" state_should="$(cat "$__object/parameter/state")" + +if [ "$state_should" = "$state_is" ]; then + # nothing to do + exit 0 +fi + case "$state_should" in present) echo ln ${lnopt} -f \"$source\" \"$destination\" From bf1f6add5519a1661fabd3efa1818d9776db7869 Mon Sep 17 00:00:00 2001 From: Matt Coddington Date: Mon, 6 Feb 2012 15:23:38 -0500 Subject: [PATCH 1273/4212] bugfix for shadow field number --- conf/type/__user/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__user/gencode-remote b/conf/type/__user/gencode-remote index ce50359b..595c7f64 100755 --- a/conf/type/__user/gencode-remote +++ b/conf/type/__user/gencode-remote @@ -42,7 +42,7 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then fi ;; password) - field=3 + field=2 file="$__object/explorer/shadow" ;; comment) field=5 ;; From acb4644f1ed6941d81d98c0323c936c3c4ae6e16 Mon Sep 17 00:00:00 2001 From: Matt Coddington Date: Mon, 6 Feb 2012 16:21:51 -0500 Subject: [PATCH 1274/4212] redhat groupmod doesn't support --gid option redhat groupmod doesn't support password chages redhat doesn't support getent gshadow --- conf/type/__group/explorer/gshadow | 10 +++++++++- conf/type/__group/gencode-remote | 15 ++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/conf/type/__group/explorer/gshadow b/conf/type/__group/explorer/gshadow index 51d502a1..2c0c0e8c 100755 --- a/conf/type/__group/explorer/gshadow +++ b/conf/type/__group/explorer/gshadow @@ -22,6 +22,14 @@ # name=$__object_id +os="$($__explorer/os)" -getent gshadow "$name" || true +case "$os" in + centos|fedora|redhat) + grep "^${name}:" /etc/gshadow || true + ;; + *) + getent gshadow "$name" || true + ;; +esac diff --git a/conf/type/__group/gencode-remote b/conf/type/__group/gencode-remote index cf26a437..9a283207 100755 --- a/conf/type/__group/gencode-remote +++ b/conf/type/__group/gencode-remote @@ -23,23 +23,36 @@ # name="$__object_id" +os="$(cat "$__global/explorer/os")" cd "$__object/parameter" if grep -q "^${name}:" "$__object/explorer/group"; then for property in $(ls .); do new_value="$(cat "$property")" + # argument to pass the groupmod command for this property (os-specific + # exceptions are listed in the case statement below) + proparg="--$property" case "$property" in password) current_value="$(awk -F: '{ print $2 }' < "$__object/explorer/gshadow")" + case "$os" in + centos|fedora|redhat) + echo "group/$name: $os groupmod does not support password modification" >&2 + continue + ;; + esac ;; gid) current_value="$(awk -F: '{ print $3 }' < "$__object/explorer/group")" + case "$os" in + centos|fedora|redhat) proparg="-g" ;; + esac ;; esac if [ "$new_value" != "$current_value" ]; then - set -- "$@" "--$property" \"$new_value\" + set -- "$@" "$proparg" \"$new_value\" fi done From c55a4652c94d3ba26b798a756b8a741653ee17ea Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 7 Feb 2012 07:55:50 +0100 Subject: [PATCH 1275/4212] ++changes Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 6e6b9ccb..cd75d2a5 100644 --- a/doc/changelog +++ b/doc/changelog @@ -6,6 +6,7 @@ Changelog 2.0.7: * Bugfix __file: Use chmod after chown/chgrp (Matt Coddington) + * Bugfix __user: Correct shadow field in explorer (Matt Coddington) 2.0.6: 2012-01-28 * Bugfix __apt_ppa: From 92c35ddd980b6359cea384b27c2264b4e4c584c5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 7 Feb 2012 07:56:08 +0100 Subject: [PATCH 1276/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index d7fb2e73..4db98d58 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,3 +1,6 @@ +- __file/foo/bar//bar + - fails later + - __user add option to include --create-home - ensure that all types, which support --state support From 229c4f6c379f162859a85fe997b62397752496dd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 7 Feb 2012 08:57:10 +0100 Subject: [PATCH 1277/4212] ++changes for 2.0.7 Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index cd75d2a5..3d50fb3d 100644 --- a/doc/changelog +++ b/doc/changelog @@ -7,6 +7,7 @@ Changelog 2.0.7: * Bugfix __file: Use chmod after chown/chgrp (Matt Coddington) * Bugfix __user: Correct shadow field in explorer (Matt Coddington) + * Bugfix __link: Properly handle existing links (Steven Armstrong) 2.0.6: 2012-01-28 * Bugfix __apt_ppa: From 4d845b3feaf14f413e768256d20983491d9567f9 Mon Sep 17 00:00:00 2001 From: Matt Coddington Date: Tue, 7 Feb 2012 10:27:28 -0500 Subject: [PATCH 1278/4212] fix for changing a user's group by name --- conf/type/__user/gencode-remote | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/conf/type/__user/gencode-remote b/conf/type/__user/gencode-remote index 595c7f64..077562f4 100755 --- a/conf/type/__user/gencode-remote +++ b/conf/type/__user/gencode-remote @@ -28,6 +28,7 @@ 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" @@ -36,9 +37,15 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then if $(echo "$new_value" | grep -q '^[0-9][0-9]*$'); then field=4 else - # group name - file="$__object/explorer/group" - field=1 + # we were passed a group name. compare to current gid and + # set $current_value to $oldgid if it needs changing. + newgid=$(awk -F: '{ print $3 }' "$__object/explorer/group") + oldgid=$(awk -F: '{ print $4 }' "$file") + if [ "$newgid" != "$oldgid" ]; then + current_value="$oldgid" + else + current_value=$new_value + fi fi ;; password) @@ -51,8 +58,10 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then uid) field=3 ;; esac - export field - current_value="$(awk -F: '{ print $ENVIRON["field"] }' < "$file")" + if [ -z "$current_value" ]; then + export field + current_value="$(awk -F: '{ print $ENVIRON["field"] }' < "$file")" + fi if [ "$new_value" != "$current_value" ]; then set -- "$@" "--$property" \'$new_value\' From 908e74689c19c08534cc946949051a4ca11081e0 Mon Sep 17 00:00:00 2001 From: Matt Coddington Date: Tue, 7 Feb 2012 12:38:21 -0500 Subject: [PATCH 1279/4212] improve comments and use better variable names --- conf/type/__user/gencode-remote | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/conf/type/__user/gencode-remote b/conf/type/__user/gencode-remote index 077562f4..8979c56e 100755 --- a/conf/type/__user/gencode-remote +++ b/conf/type/__user/gencode-remote @@ -37,14 +37,15 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then if $(echo "$new_value" | grep -q '^[0-9][0-9]*$'); then field=4 else - # we were passed a group name. compare to current gid and - # set $current_value to $oldgid if it needs changing. - newgid=$(awk -F: '{ print $3 }' "$__object/explorer/group") - oldgid=$(awk -F: '{ print $4 }' "$file") - if [ "$newgid" != "$oldgid" ]; then - current_value="$oldgid" + # 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 + current_value="$new_value" fi fi ;; @@ -58,6 +59,8 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then uid) field=3 ;; 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")" From 1f8693a7226108b1d25bbee6cb6f08b154e8c269 Mon Sep 17 00:00:00 2001 From: Matt Coddington Date: Tue, 7 Feb 2012 17:29:55 -0500 Subject: [PATCH 1280/4212] case-based exceptions only on OS's where we know they are needed always use -g instead of --gid when passing arg to groupmod --- conf/type/__group/explorer/gshadow | 9 +++++---- conf/type/__group/gencode-remote | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/conf/type/__group/explorer/gshadow b/conf/type/__group/explorer/gshadow index 2c0c0e8c..e3c2dd6c 100755 --- a/conf/type/__group/explorer/gshadow +++ b/conf/type/__group/explorer/gshadow @@ -22,11 +22,12 @@ # name=$__object_id -os="$($__explorer/os)" +os_version="$($__explorer/os_version)" -case "$os" in - centos|fedora|redhat) - grep "^${name}:" /etc/gshadow || true +case "$os_version" in + "Red Hat Enterprise Linux Server release "[45]*|"CentOS release "[45]*) + # TODO: find a way to get this information + echo "$os_version does not have getent gshadow" ;; *) getent gshadow "$name" || true diff --git a/conf/type/__group/gencode-remote b/conf/type/__group/gencode-remote index 9a283207..2b4774ab 100755 --- a/conf/type/__group/gencode-remote +++ b/conf/type/__group/gencode-remote @@ -23,31 +23,31 @@ # name="$__object_id" -os="$(cat "$__global/explorer/os")" +os_version="$(cat "$__global/explorer/os_version")" cd "$__object/parameter" if grep -q "^${name}:" "$__object/explorer/group"; then for property in $(ls .); do new_value="$(cat "$property")" - # argument to pass the groupmod command for this property (os-specific - # exceptions are listed in the case statement below) + # argument to pass the groupmod command for this property (exceptions + # are made in the case statement below) proparg="--$property" case "$property" in password) current_value="$(awk -F: '{ print $2 }' < "$__object/explorer/gshadow")" - case "$os" in - centos|fedora|redhat) - echo "group/$name: $os groupmod does not support password modification" >&2 - continue + case "$os_version" in + "Red Hat Enterprise Linux Server release "[45]*|"CentOS release "[45]*) + # TODO: Use gpasswd? Need to fix gshadow explorer first. + echo "group/$name: '$os_version' groupmod does not support password modification" >&2 + exit 1 ;; esac ;; gid) + # set to -g to support older redhat/centos + proparg="-g" current_value="$(awk -F: '{ print $3 }' < "$__object/explorer/group")" - case "$os" in - centos|fedora|redhat) proparg="-g" ;; - esac ;; esac From 817ce9c2562cc24117702a3eac7c3717766d0a87 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 8 Feb 2012 08:31:59 +0100 Subject: [PATCH 1281/4212] /egrep/grep -E/ Signed-off-by: Steven Armstrong --- conf/type/__key_value/explorer/state | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conf/type/__key_value/explorer/state b/conf/type/__key_value/explorer/state index ec760f71..94a5ea7f 100755 --- a/conf/type/__key_value/explorer/state +++ b/conf/type/__key_value/explorer/state @@ -29,7 +29,7 @@ value="$(cat "$__object/parameter/value" 2>/dev/null \ case "$state" in absent) - if egrep -q "^$key$delimiter+" "$file"; then + if grep -q -E "^$key$delimiter+" "$file"; then # if the key exists, with whatever value, we will have to remove it # so report it as present echo present @@ -39,10 +39,10 @@ case "$state" in fi ;; present) - if egrep -q "^$key$delimiter+$value$" "$file"; then + if grep -q -E "^$key$delimiter+$value$" "$file"; then # key exists and value is same echo present - elif egrep -q "^$key$delimiter+" "$file"; then + elif grep -q -E "^$key$delimiter+" "$file"; then # key exists, but value is empty or different echo wrongvalue else From 28b69b8468cfdcf3a2a389cdf295833b35cef393 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 8 Feb 2012 22:03:19 +0100 Subject: [PATCH 1282/4212] document dependency problem Signed-off-by: Nico Schottelius --- ...012-02-08.explorer-depends-on-another-type | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 doc/dev/logs/2012-02-08.explorer-depends-on-another-type diff --git a/doc/dev/logs/2012-02-08.explorer-depends-on-another-type b/doc/dev/logs/2012-02-08.explorer-depends-on-another-type new file mode 100644 index 00000000..c76626d5 --- /dev/null +++ b/doc/dev/logs/2012-02-08.explorer-depends-on-another-type @@ -0,0 +1,36 @@ +If a type explorer depends on a command that will be generated by another type, +the operation fails, as can be seen below. + +This may be a corner case, but is hapenning with __package_pip and +__python_virtualenv. + +[19:10] brief:cdist% ./bin/cdist config -v loch +INFO: loch: Running global explorers +INFO: loch: Running initial manifest /home/users/nico/privat/firmen/local.ch/vcs/cdist/conf/manifest +INFO: loch: Running object manifests and type explorers +INFO: loch: Running manifest and explorers for __git/root/shinken +INFO: loch: Running manifest and explorers for __package_pip/pyro +/var/lib/cdist/conf/type/__package_pip/explorer/state: line 38: /root/shinken_virtualenv/bin/pip: No such file or directory +INFO: loch: Running manifest and explorers for __python_virtualenv/root/shinken_virtualenv +INFO: loch: Running manifest and explorers for __directory/pyro +INFO: loch: Running manifest and explorers for __directory/root/shinken +INFO: loch: Running manifest and explorers for __directory/root/shinken_virtualenv +INFO: loch: Running manifest and explorers for __package/git +INFO: loch: Running manifest and explorers for __package/python-virtualenv +INFO: loch: Running manifest and explorers for __package_pacman/git +INFO: loch: Running manifest and explorers for __package_pacman/python-virtualenv +INFO: loch: Generating and executing code +INFO: loch: Generating and executing code for __package_pacman/git +INFO: loch: Generating and executing code for __package/git +INFO: loch: Generating and executing code for __directory/root/shinken +INFO: loch: Generating and executing code for __git/root/shinken +fatal: write error: No space left on device +fatal: index-pack failed +ERROR: loch: Code that raised the error: +git clone --quiet "git://github.com/naparuba/shinken.git" "/root/shinken" + +ERROR: Remote script execution failed: ssh -o User=root -q loch /bin/sh -e /var/lib/cdist/object/__git/root/shinken/.cdist/code-remote +WARNING: Failed to deploy to the following hosts: loch +INFO: Total processing time for 1 host(s): 340.62370681762695 +[19:17] brief:cdist% ./bin/cdist config -v loch + From e42bf614130c81906c8ef237cdf042f08dca9245 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 8 Feb 2012 22:05:48 +0100 Subject: [PATCH 1283/4212] new type: __package_pip Signed-off-by: Nico Schottelius --- conf/type/__package_pip/explorer/state | 48 ++++++++++++++++++++ conf/type/__package_pip/gencode-remote | 50 ++++++++++++++++++++ conf/type/__package_pip/man.text | 53 ++++++++++++++++++++++ conf/type/__package_pip/parameter/optional | 1 + conf/type/__package_pip/parameter/required | 1 + 5 files changed, 153 insertions(+) create mode 100644 conf/type/__package_pip/explorer/state create mode 100644 conf/type/__package_pip/gencode-remote create mode 100644 conf/type/__package_pip/man.text create mode 100644 conf/type/__package_pip/parameter/optional create mode 100644 conf/type/__package_pip/parameter/required diff --git a/conf/type/__package_pip/explorer/state b/conf/type/__package_pip/explorer/state new file mode 100644 index 00000000..3a086e58 --- /dev/null +++ b/conf/type/__package_pip/explorer/state @@ -0,0 +1,48 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Development supported by Local AG (www.local.ch) +# + +nameparam="$__object/parameter/name" +if [ -f "$nameparam" ]; then + name=$(cat "$nameparam") +else + name="$__object_id" +fi + +pipparam="$__object/parameter/pip" +if [ -f "$pipparam" ]; then + pip=$(cat "$pipparam") +else + pip="pip" +fi + +# which is not posix, but command is :-) +if ! command -v "$pip" >/dev/null 2>&1; then + echo "No usable pip found at path \"$pip\"" >&2 + exit 1 +fi + +if "$pip" freeze | grep -i -q "^$name=="; then + echo present +else + echo absent +fi diff --git a/conf/type/__package_pip/gencode-remote b/conf/type/__package_pip/gencode-remote new file mode 100644 index 00000000..e60d74c5 --- /dev/null +++ b/conf/type/__package_pip/gencode-remote @@ -0,0 +1,50 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Development supported by Local AG (www.local.ch) +# + +state_is=$(cat "$__object/explorer/state") +state_should=$(cat "$__object/parameter/state") + +[ "$state_is" = "$state_should" ] && exit 0 + +nameparam="$__object/parameter/name" +if [ -f "$nameparam" ]; then + name=$(cat "$nameparam") +else + name="$__object_id" +fi + +pipparam="$__object/parameter/pip" +if [ -f "$pipparam" ]; then + pip=$(cat "$pipparam") +else + pip="pip" +fi + +case "$state_should" in + present) + echo $pip install -q pyro + ;; + absent) + echo $pip uninstall -q -y pyro + ;; +esac diff --git a/conf/type/__package_pip/man.text b/conf/type/__package_pip/man.text new file mode 100644 index 00000000..1822ffca --- /dev/null +++ b/conf/type/__package_pip/man.text @@ -0,0 +1,53 @@ +cdist-type__package_pip(7) +============================= +Nico Schottelius + + +NAME +---- +cdist-type__package_pip - Manage packages with pip + + +DESCRIPTION +----------- +Pip is used in Python environments to install packages. +It is also included in the python virtualenv environment. + + +REQUIRED PARAMETERS +------------------- +state:: + Either "present" or "absent". + + +OPTIONAL PARAMETERS +------------------- +name:: + If supplied, use the name and not the object id as the package name. + +pip:: + Instead of using pip from PATH, use the specific pip path. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Install a package +__package_pip pyro --state present + +# Use pip in a virtualenv located at /root/shinken_virtualenv +__package_pip pyro --state present --pip /root/shinken_virtualenv/bin/pip +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__package(7) + + +COPYING +------- +Copyright \(C) 2012 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__package_pip/parameter/optional b/conf/type/__package_pip/parameter/optional new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/conf/type/__package_pip/parameter/optional @@ -0,0 +1 @@ +pip diff --git a/conf/type/__package_pip/parameter/required b/conf/type/__package_pip/parameter/required new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/conf/type/__package_pip/parameter/required @@ -0,0 +1 @@ +state From 5a64c89c8e5fc06955064b396d0450f1d3ce2aeb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 8 Feb 2012 22:06:16 +0100 Subject: [PATCH 1284/4212] document new type Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 3d50fb3d..7e070cc5 100644 --- a/doc/changelog +++ b/doc/changelog @@ -8,6 +8,7 @@ Changelog * Bugfix __file: Use chmod after chown/chgrp (Matt Coddington) * Bugfix __user: Correct shadow field in explorer (Matt Coddington) * Bugfix __link: Properly handle existing links (Steven Armstrong) + * New Type: __package_pip 2.0.6: 2012-01-28 * Bugfix __apt_ppa: From 242ce6dfd2d9874ef1f8c092d6d209d2069bba24 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 8 Feb 2012 22:16:09 +0100 Subject: [PATCH 1285/4212] first round of absent/present changes Signed-off-by: Nico Schottelius --- conf/type/__package/man.text | 29 ++++++++++++------------ conf/type/__package_apt/man.text | 9 ++++---- conf/type/__package_luarocks/man.text | 7 +++--- conf/type/__package_pacman/man.text | 7 +++--- conf/type/__package_pip/man.text | 4 ++-- conf/type/__package_pkg_openbsd/man.text | 7 +++--- conf/type/__package_rubygem/man.text | 5 ++-- conf/type/__package_yum/man.text | 5 ++-- 8 files changed, 40 insertions(+), 33 deletions(-) diff --git a/conf/type/__package/man.text b/conf/type/__package/man.text index d0460a31..071a8bfb 100644 --- a/conf/type/__package/man.text +++ b/conf/type/__package/man.text @@ -1,5 +1,5 @@ -cdist-type__user(7) -=================== +cdist-type__package(7) +====================== Steven Armstrong @@ -17,22 +17,23 @@ It dispatches the actual work to the package system dependant types. REQUIRED PARAMETERS ------------------- state:: - The state the package should be in, either "installed" or "removed" + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS ------------------- name:: - The name of the package to install. Default is to use the object_id as the - package name. + The name of the package to install. Default is to use the object_id as the + package name. version:: - The version of the package to install. Default is to install the version - choosen by the local package manager. + The version of the package to install. Default is to install the version + choosen by the local package manager. type:: - The package type to use. Default is determined based on the $os explorer - variable. - e.g. __package_apt for Debian - __package_emerge for Gentoo + The package type to use. Default is determined based on the $os explorer + variable. + e.g. __package_apt for Debian + __package_emerge for Gentoo EXAMPLES @@ -40,13 +41,13 @@ EXAMPLES -------------------------------------------------------------------------------- # Install the package vim on the target -__package vim --state installed +__package vim --state present # Same but install specific version -__package vim --state installed --version 7.3.50 +__package vim --state present --version 7.3.50 # Force use of a specific package type -__package vim --state installed --type __package_apt +__package vim --state present --type __package_apt -------------------------------------------------------------------------------- diff --git a/conf/type/__package_apt/man.text b/conf/type/__package_apt/man.text index 905bfb5f..fd9c1a9c 100644 --- a/conf/type/__package_apt/man.text +++ b/conf/type/__package_apt/man.text @@ -17,7 +17,8 @@ manage packages. REQUIRED PARAMETERS ------------------- state:: - Either "installed" or "removed". + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS @@ -31,13 +32,13 @@ EXAMPLES -------------------------------------------------------------------------------- # Ensure zsh in installed -__package_apt zsh --state installed +__package_apt zsh --state present # In case you only want *a* webserver, but don't care which one -__package_apt webserver --state installed --name nginx +__package_apt webserver --state present --name nginx # Remove obsolete package -__package_apt puppet --state removed +__package_apt puppet --state absent -------------------------------------------------------------------------------- diff --git a/conf/type/__package_luarocks/man.text b/conf/type/__package_luarocks/man.text index 6c1e6734..4f68875a 100644 --- a/conf/type/__package_luarocks/man.text +++ b/conf/type/__package_luarocks/man.text @@ -1,5 +1,5 @@ cdist-type__package_luarocks(7) -============================== +=============================== Christian G. Warden @@ -16,13 +16,14 @@ LuaRocks is a deployment and management system for Lua modules. REQUIRED PARAMETERS ------------------- state:: - Either "installed" or "removed". + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS ------------------- name:: - If supplied, use the name and not the object id as the package name. + If supplied, use the name and not the object id as the package name. EXAMPLES diff --git a/conf/type/__package_pacman/man.text b/conf/type/__package_pacman/man.text index 28766581..52fa05c4 100644 --- a/conf/type/__package_pacman/man.text +++ b/conf/type/__package_pacman/man.text @@ -17,13 +17,14 @@ packages. REQUIRED PARAMETERS ------------------- state:: - Either "installed" or "removed". + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS ------------------- name:: - If supplied, use the name and not the object id as the package name. + If supplied, use the name and not the object id as the package name. EXAMPLES @@ -49,5 +50,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is +Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__package_pip/man.text b/conf/type/__package_pip/man.text index 1822ffca..bc773763 100644 --- a/conf/type/__package_pip/man.text +++ b/conf/type/__package_pip/man.text @@ -23,10 +23,10 @@ state:: OPTIONAL PARAMETERS ------------------- name:: - If supplied, use the name and not the object id as the package name. + If supplied, use the name and not the object id as the package name. pip:: - Instead of using pip from PATH, use the specific pip path. + Instead of using pip from PATH, use the specific pip path. EXAMPLES diff --git a/conf/type/__package_pkg_openbsd/man.text b/conf/type/__package_pkg_openbsd/man.text index 555bb0ac..0f594b96 100644 --- a/conf/type/__package_pkg_openbsd/man.text +++ b/conf/type/__package_pkg_openbsd/man.text @@ -16,16 +16,17 @@ This type is usually used on OpenBSD to manage packages. REQUIRED PARAMETERS ------------------- state:: - Either "installed" or "removed". + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS ------------------- name:: - If supplied, use the name and not the object id as the package name. + If supplied, use the name and not the object id as the package name. flavor:: - If supplied, use to avoid ambiguity. + If supplied, use to avoid ambiguity. EXAMPLES diff --git a/conf/type/__package_rubygem/man.text b/conf/type/__package_rubygem/man.text index c6248ee3..6db8f42b 100644 --- a/conf/type/__package_rubygem/man.text +++ b/conf/type/__package_rubygem/man.text @@ -16,13 +16,14 @@ Rubygems is the default package management system for the Ruby programming langu REQUIRED PARAMETERS ------------------- state:: - Either "installed" or "removed". + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS ------------------- name:: - If supplied, use the name and not the object id as the package name. + If supplied, use the name and not the object id as the package name. EXAMPLES diff --git a/conf/type/__package_yum/man.text b/conf/type/__package_yum/man.text index c9cad340..d90a2af7 100644 --- a/conf/type/__package_yum/man.text +++ b/conf/type/__package_yum/man.text @@ -18,13 +18,14 @@ slightly confusing error message "Error: Nothing to do". REQUIRED PARAMETERS ------------------- state:: - Either "installed" or "removed". + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS ------------------- name:: - If supplied, use the name and not the object id as the package name. + If supplied, use the name and not the object id as the package name. EXAMPLES From 2aed047f7565cc22512dbc61ab3d42c8ad15eb57 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 8 Feb 2012 22:23:31 +0100 Subject: [PATCH 1286/4212] 2nd correction round for manpages Signed-off-by: Nico Schottelius --- conf/type/__package_luarocks/man.text | 4 ++-- conf/type/__package_pacman/man.text | 6 +++--- conf/type/__package_pkg_openbsd/man.text | 8 ++++---- conf/type/__package_rubygem/man.text | 4 ++-- conf/type/__package_yum/man.text | 6 +++--- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/conf/type/__package_luarocks/man.text b/conf/type/__package_luarocks/man.text index 4f68875a..8b041b7c 100644 --- a/conf/type/__package_luarocks/man.text +++ b/conf/type/__package_luarocks/man.text @@ -31,10 +31,10 @@ EXAMPLES -------------------------------------------------------------------------------- # Ensure luasocket is installed -__package_luarocks luasocket --state installed +__package_luarocks luasocket --state present # Remove package -__package_luarocks luasocket --state removed +__package_luarocks luasocket --state absent -------------------------------------------------------------------------------- diff --git a/conf/type/__package_pacman/man.text b/conf/type/__package_pacman/man.text index 52fa05c4..fe2abac8 100644 --- a/conf/type/__package_pacman/man.text +++ b/conf/type/__package_pacman/man.text @@ -32,13 +32,13 @@ EXAMPLES -------------------------------------------------------------------------------- # Ensure zsh in installed -__package_pacman zsh --state installed +__package_pacman zsh --state present # If you don't want to follow pythonX packages, but always use python -__package_pacman python --state installed --name python2 +__package_pacman python --state present --name python2 # Remove obsolete package -__package_pacman puppet --state removed +__package_pacman puppet --state absent -------------------------------------------------------------------------------- diff --git a/conf/type/__package_pkg_openbsd/man.text b/conf/type/__package_pkg_openbsd/man.text index 0f594b96..71cf9d4e 100644 --- a/conf/type/__package_pkg_openbsd/man.text +++ b/conf/type/__package_pkg_openbsd/man.text @@ -34,16 +34,16 @@ EXAMPLES -------------------------------------------------------------------------------- # Ensure zsh is installed -__package_pkg_openbsd zsh --state installed +__package_pkg_openbsd zsh --state present # Ensure vim is installed, use flavor no_x11 -__package_pkg_openbsd vim --state installed --flavor no_x11 +__package_pkg_openbsd vim --state present --flavor no_x11 # If you don't want to follow pythonX packages, but always use python -__package_pkg_openbsd python --state installed --name python2 +__package_pkg_openbsd python --state present --name python2 # Remove obsolete package -__package_pkg_openbsd puppet --state removed +__package_pkg_openbsd puppet --state absent -------------------------------------------------------------------------------- diff --git a/conf/type/__package_rubygem/man.text b/conf/type/__package_rubygem/man.text index 6db8f42b..79bb8b52 100644 --- a/conf/type/__package_rubygem/man.text +++ b/conf/type/__package_rubygem/man.text @@ -31,10 +31,10 @@ EXAMPLES -------------------------------------------------------------------------------- # Ensure sinatra is installed -__package_rubygem sinatra --state installed +__package_rubygem sinatra --state present # Remove package -__package_rubygem rails --state removed +__package_rubygem rails --state absent -------------------------------------------------------------------------------- diff --git a/conf/type/__package_yum/man.text b/conf/type/__package_yum/man.text index d90a2af7..9dfb394e 100644 --- a/conf/type/__package_yum/man.text +++ b/conf/type/__package_yum/man.text @@ -33,13 +33,13 @@ EXAMPLES -------------------------------------------------------------------------------- # Ensure zsh in installed -__package_yum zsh --state installed +__package_yum zsh --state present # If you don't want to follow pythonX packages, but always use python -__package_yum python --state installed --name python2 +__package_yum python --state present --name python2 # Remove obsolete package -__package_yum puppet --state removed +__package_yum puppet --state absent -------------------------------------------------------------------------------- From 602e57455db6f09d48bc2f578d89fb13b7cb0d6b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 8 Feb 2012 22:23:49 +0100 Subject: [PATCH 1287/4212] support absent/present in __package_apt Signed-off-by: Nico Schottelius --- conf/type/__package_apt/explorer/pkg_status | 8 ++++---- conf/type/__package_apt/gencode-remote | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/conf/type/__package_apt/explorer/pkg_status b/conf/type/__package_apt/explorer/pkg_status index dbb3af3e..04926b60 100755 --- a/conf/type/__package_apt/explorer/pkg_status +++ b/conf/type/__package_apt/explorer/pkg_status @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -28,11 +28,11 @@ else fi # Except dpkg failing, if package is not known / installed -packages="$(apt-cache showpkg "$name" | sed -e "1,/Reverse Provides:/d" | cut -d ' ' -f 1) $name" +packages="$(apt-cache showpkg "$name" | sed -e "1,/Reverse Provides:/d" | cut -d ' ' -f 1) $name" for p in $packages; do if [ -n "$(dpkg -s "$p" 2>/dev/null | grep "^Status: install ok installed$")" ]; then - echo "installed $p" + echo "present $p" exit 0 fi done -echo "removed" +echo absent diff --git a/conf/type/__package_apt/gencode-remote b/conf/type/__package_apt/gencode-remote index 594ab8cb..da58ca1b 100755 --- a/conf/type/__package_apt/gencode-remote +++ b/conf/type/__package_apt/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -28,11 +28,18 @@ else fi state_should="$(cat "$__object/parameter/state")" + +# Correct pre 2.1 naming - FIXME in 2.1 +case "$state_should" in + installed) state_should="present" ;; + removed) state_should="absent" ;; +esac + state_is="$(cat "$__object/explorer/pkg_status")" case "$state_is" in - installed*) + present*) name="$(echo "$state_is" | cut -d ' ' -f 2)" - state_is="installed" + state_is="present" ;; esac @@ -40,10 +47,10 @@ aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes" if [ "$state_is" != "$state_should" ]; then case "$state_should" in - installed) + present) echo $aptget install \"$name\" ;; - removed) + absent) echo $aptget remove \"$name\" ;; *) @@ -52,4 +59,3 @@ if [ "$state_is" != "$state_should" ]; then ;; esac fi - From 8e5a0f83c5c7b5f42539fe44c0f02f503a409171 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 9 Feb 2012 10:10:13 +0100 Subject: [PATCH 1288/4212] rename explorer to state, being more consistent internally Signed-off-by: Nico Schottelius --- conf/type/__package_apt/explorer/{pkg_status => state} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename conf/type/__package_apt/explorer/{pkg_status => state} (100%) diff --git a/conf/type/__package_apt/explorer/pkg_status b/conf/type/__package_apt/explorer/state similarity index 100% rename from conf/type/__package_apt/explorer/pkg_status rename to conf/type/__package_apt/explorer/state From 52849b91c581ede9f57e9549fbda4bcfbe5fcea2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 9 Feb 2012 10:25:05 +0100 Subject: [PATCH 1289/4212] warn about deprecated usage Signed-off-by: Nico Schottelius --- conf/type/__package_apt/gencode-remote | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/conf/type/__package_apt/gencode-remote b/conf/type/__package_apt/gencode-remote index da58ca1b..32049a27 100755 --- a/conf/type/__package_apt/gencode-remote +++ b/conf/type/__package_apt/gencode-remote @@ -31,11 +31,19 @@ state_should="$(cat "$__object/parameter/state")" # Correct pre 2.1 naming - FIXME in 2.1 case "$state_should" in - installed) state_should="present" ;; - removed) state_should="absent" ;; + # FIXME: print warning to stderr! + installed) + echo "WARNING: $state_should is deprecated, please change to present/absent (will be removed in cdist 2.1)" >&2 + state_should="present" + ;; + removed) + echo "WARNING: $state_should is deprecated, please change to present/absent (will be removed in cdist 2.1)" >&2 + state_should="absent" + ;; esac -state_is="$(cat "$__object/explorer/pkg_status")" +# FIXME: use grep directly, state is a list, not a line! +state_is="$(cat "$__object/explorer/state")" case "$state_is" in present*) name="$(echo "$state_is" | cut -d ' ' -f 2)" From 3c19e7ab4c937bd6452d1f8a777288ab31163a47 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 9 Feb 2012 11:54:13 +0100 Subject: [PATCH 1290/4212] update __package_pacman for absent/present Signed-off-by: Nico Schottelius --- .../__package_pacman/explorer/pkg_version | 4 +-- conf/type/__package_pacman/gencode-remote | 33 +++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/conf/type/__package_pacman/explorer/pkg_version b/conf/type/__package_pacman/explorer/pkg_version index 4f612423..c33820f8 100755 --- a/conf/type/__package_pacman/explorer/pkg_version +++ b/conf/type/__package_pacman/explorer/pkg_version @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,7 +18,7 @@ # along with cdist. If not, see . # # -# Retrieve the status of a package - parsed dpkg output +# Retrieve the status of a package - parsed pacman output # if [ -f "$__object/parameter/name" ]; then diff --git a/conf/type/__package_pacman/gencode-remote b/conf/type/__package_pacman/gencode-remote index 3c4fdda7..1516370c 100755 --- a/conf/type/__package_pacman/gencode-remote +++ b/conf/type/__package_pacman/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -33,21 +33,34 @@ else name="$__object_id" fi -state="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" +case "$state_should" in + installed) + echo "WARNING: $state_should is deprecated, please change to present/absent (will be removed in cdist 2.1)" >&2 + state_should="present" + ;; + removed) + echo "WARNING: $state_should is deprecated, please change to present/absent (will be removed in cdist 2.1)" >&2 + state_should="absent" + ;; +esac + pkg_version="$(cat "$__object/explorer/pkg_version")" +if [ -z "$pkg_version" ]; then + state_is="absent" +else + state_is="present" +fi -case "$state" in - installed) +# Exit if nothing is needed to be done +[ "$state_is" = "$state_should ] && exit 0 - # Empty? Not installed. - if [ -z "$pkg_version" ]; then +case "$state_should" in + present) echo pacman "$pacopts" -S \"$name\" - fi ;; - removed) - if [ "$pkg_version" ]; then + absent) echo pacman "$pacopts" -R \"$name\" - fi ;; *) echo "Unknown state: $state" >&2 From 1713a70428427b8d33a7c223cfed8943f8332e78 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 9 Feb 2012 19:06:13 +0100 Subject: [PATCH 1291/4212] begin changes to __package_luarocks and __package_pkg_openbsd Signed-off-by: Nico Schottelius --- conf/type/__package_apt/gencode-remote | 1 - conf/type/__package_luarocks/gencode-remote | 2 +- .../type/__package_pkg_openbsd/gencode-remote | 73 ++++++++++++------- 3 files changed, 46 insertions(+), 30 deletions(-) diff --git a/conf/type/__package_apt/gencode-remote b/conf/type/__package_apt/gencode-remote index 32049a27..47e76ec8 100755 --- a/conf/type/__package_apt/gencode-remote +++ b/conf/type/__package_apt/gencode-remote @@ -31,7 +31,6 @@ state_should="$(cat "$__object/parameter/state")" # Correct pre 2.1 naming - FIXME in 2.1 case "$state_should" in - # FIXME: print warning to stderr! installed) echo "WARNING: $state_should is deprecated, please change to present/absent (will be removed in cdist 2.1)" >&2 state_should="present" diff --git a/conf/type/__package_luarocks/gencode-remote b/conf/type/__package_luarocks/gencode-remote index 179022b1..29fd7e38 100755 --- a/conf/type/__package_luarocks/gencode-remote +++ b/conf/type/__package_luarocks/gencode-remote @@ -29,7 +29,7 @@ else name="$__object_id" fi -state="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" is_installed="$(grep "(installed)" "$__object/explorer/pkg_status" || true)" case "$state" in diff --git a/conf/type/__package_pkg_openbsd/gencode-remote b/conf/type/__package_pkg_openbsd/gencode-remote index eee2a3d9..e8309f20 100755 --- a/conf/type/__package_pkg_openbsd/gencode-remote +++ b/conf/type/__package_pkg_openbsd/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2011 Andi Brönnimann (andi-cdist at v-net.ch) +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -42,44 +43,60 @@ else name="$__object_id" fi -state="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" +# Correct pre 2.1 naming - FIXME in 2.1 +case "$state_should" in + installed) + echo "WARNING: $state_should is deprecated, please change to present/absent (will be removed in cdist 2.1)" >&2 + state_should="present" + ;; + removed) + echo "WARNING: $state_should is deprecated, please change to present/absent (will be removed in cdist 2.1)" >&2 + state_should="absent" + ;; +esac + pkg_version="$(cat "$__object/explorer/pkg_version")" # TODO: Shouldn't be hardcoded echo export PKG_PATH=ftp://ftp.openbsd.org/pub/OpenBSD/$os_version/packages/$machine/ -case "$state" in - installed) - # Empty? Not installed. - if [ -z "$pkg_version" ]; then - # use this because pkg_add doesn't properly handle errors - cat << eof - status=\$(pkg_add "$pkgopts" "$name--$flavor") +if [ "$pkg_version" ]; then + state_is="present" +else + state_is="absent" +fi - # no error - if [ -n "\$status" ]; then - echo "Error: \$status" - exit 1 - fi -eof - fi - ;; - removed) - if [ "$pkg_version" ]; then - # use this because pkg_add doesn't properly handle errors - cat << eof - status=\$(pkg_delete "$pkgopts" "$name--$flavor") +[ "$state_is" = "$state_should" ] && exit 0 - # no error - if [ -n "\$status" ]; then - echo "Error: \$status" - exit 1 - fi +case "$state_should" in + present) + # use this because pkg_add doesn't properly handle errors + cat << eof +status=\$(pkg_add "$pkgopts" "$name--$flavor") + +# no error +if [ -n "\$status" ]; then + echo "Error: \$status" + exit 1 +fi +eof + ;; + + absent) + # use this because pkg_add doesn't properly handle errors + cat << eof +status=\$(pkg_delete "$pkgopts" "$name--$flavor") + +# no error +if [ -n "\$status" ]; then + echo "Error: \$status" + exit 1 +fi eof - fi ;; *) - echo "Unknown state: $state" >&2 + echo "Unknown state: $state_should" >&2 exit 1 ;; esac From d55c52601f970deec649f29418d66575be88db66 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 9 Feb 2012 19:08:32 +0100 Subject: [PATCH 1292/4212] move run_type_explorer near run_type_explorers Signed-off-by: Nico Schottelius --- lib/cdist/core/explorer.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 01c4c81d..43b0339c 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -130,6 +130,19 @@ class Explorer(object): self.log.debug("Running type explorer '%s' for object '%s'", explorer, cdist_object.name) cdist_object.explorers[explorer] = output + def run_type_explorer(self, explorer, cdist_object): + """Run the given type explorer for the given object and return it's output.""" + cdist_type = cdist_object.type + env = self.env.copy() + env.update({ + '__object': os.path.join(self.remote.object_path, cdist_object.path), + '__object_id': cdist_object.object_id, + '__object_fq': cdist_object.path, + '__type_explorer': os.path.join(self.remote.type_path, cdist_type.explorer_path) + }) + script = os.path.join(self.remote.type_path, cdist_type.explorer_path, explorer) + return self.remote.run_script(script, env=env, return_output=True) + def transfer_type_explorers(self, cdist_type): """Transfer the type explorers for the given type to the remote side.""" if cdist_type.explorers: @@ -149,16 +162,3 @@ class Explorer(object): destination = os.path.join(self.remote.object_path, cdist_object.parameter_path) self.remote.mkdir(destination) self.remote.transfer(source, destination) - - def run_type_explorer(self, explorer, cdist_object): - """Run the given type explorer for the given object and return it's output.""" - cdist_type = cdist_object.type - env = self.env.copy() - env.update({ - '__object': os.path.join(self.remote.object_path, cdist_object.path), - '__object_id': cdist_object.object_id, - '__object_fq': cdist_object.path, - '__type_explorer': os.path.join(self.remote.type_path, cdist_type.explorer_path) - }) - script = os.path.join(self.remote.type_path, cdist_type.explorer_path, explorer) - return self.remote.run_script(script, env=env, return_output=True) From 1dcc420a38d7fe394e8400704779d2fbb2363a65 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 9 Feb 2012 19:09:32 +0100 Subject: [PATCH 1293/4212] no, no common base class for local/remote Signed-off-by: Nico Schottelius --- lib/cdist/exec/remote.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 87db7273..b46235a8 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -20,8 +20,6 @@ # # -# FIXME: common base class with Local? - import io import os import sys From 53c61d42ad659fc6d0f156317c26a3ae34bde071 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 9 Feb 2012 19:12:49 +0100 Subject: [PATCH 1294/4212] remove useless if env: Signed-off-by: Nico Schottelius --- lib/cdist/exec/remote.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index b46235a8..69dc5dda 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -146,18 +146,17 @@ class Remote(object): os_environ = os.environ.copy() os_environ['__target_host'] = self.target_host + self.log.debug("Remote run script: %s", command) + # can't pass environment to remote side, so prepend command with # variable declarations if env: + self.log.debug("Remote run script env: %s", env) command.extend(["%s=%s" % item for item in env.items()]) command.extend(["/bin/sh", "-e"]) command.append(script) - self.log.debug("Remote run script: %s", command) - if env: - self.log.debug("Remote run script env: %s", env) - try: if return_output: return subprocess.check_output(command, env=os_environ).decode() From 45053c6d84d0d1693442b6c3f63342042ba4fe83 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 9 Feb 2012 19:31:30 +0100 Subject: [PATCH 1295/4212] allow pip to be non existent during explorer stage Signed-off-by: Nico Schottelius --- conf/type/__package_pip/explorer/state | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/conf/type/__package_pip/explorer/state b/conf/type/__package_pip/explorer/state index 3a086e58..7886a46b 100644 --- a/conf/type/__package_pip/explorer/state +++ b/conf/type/__package_pip/explorer/state @@ -35,14 +35,14 @@ else pip="pip" fi -# which is not posix, but command is :-) +# If there is no pip, it may get created from somebody else. +# If it will be created, there is probably no package installed. if ! command -v "$pip" >/dev/null 2>&1; then - echo "No usable pip found at path \"$pip\"" >&2 - exit 1 -fi - -if "$pip" freeze | grep -i -q "^$name=="; then - echo present -else echo absent +else + if "$pip" freeze | grep -i -q "^$name=="; then + echo present + else + echo absent + fi fi From 49917d29332558afa7411f1624971cc17c975648 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 10 Feb 2012 13:01:29 +0100 Subject: [PATCH 1296/4212] +object id issues/ideas Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-02-10.object_id-and-slashes | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 doc/dev/logs/2012-02-10.object_id-and-slashes diff --git a/doc/dev/logs/2012-02-10.object_id-and-slashes b/doc/dev/logs/2012-02-10.object_id-and-slashes new file mode 100644 index 00000000..de46a1f8 --- /dev/null +++ b/doc/dev/logs/2012-02-10.object_id-and-slashes @@ -0,0 +1,18 @@ +__typename /foo/bar # possible, usual use case +require="__a//b" __typename /foo/bar # possible and happens often for __a/$id in loops + +__typename /foo/bar/ # trailing slash will be stripped, can be documented + +__typename /foo//bar//baz # // will be converted to / implicitly through fs; error prone; disallow + +require="__a//b//c" __typename # // will be converted to / implicitly through fs; error prone; disallow + + +Solution: + + 1) allow require __a//b: type __a, object id /b + => strip first slash of object id, as we do in non-dep-mode + 2) allow _one_ trailing /: __type /foo/bar/ and require="__foo/abc/" + => strip one leading slash of object id + 3) disallow // within object id + 4) disallow starting or ending / after 1) and 2) From 947c9a4ccb3a96c2a825a97f40bea4eced22a8e3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 10 Feb 2012 16:17:53 +0100 Subject: [PATCH 1297/4212] ++changes for 2.0.7 Signed-off-by: Nico Schottelius --- conf/type/__package_pip/explorer/state | 1 + doc/changelog | 1 + 2 files changed, 2 insertions(+) diff --git a/conf/type/__package_pip/explorer/state b/conf/type/__package_pip/explorer/state index 7886a46b..5be07280 100644 --- a/conf/type/__package_pip/explorer/state +++ b/conf/type/__package_pip/explorer/state @@ -40,6 +40,7 @@ fi if ! command -v "$pip" >/dev/null 2>&1; then echo absent else + if "$pip" freeze | grep -i -q "^$name=="; then echo present else diff --git a/doc/changelog b/doc/changelog index 7e070cc5..dace28dd 100644 --- a/doc/changelog +++ b/doc/changelog @@ -8,6 +8,7 @@ Changelog * Bugfix __file: Use chmod after chown/chgrp (Matt Coddington) * Bugfix __user: Correct shadow field in explorer (Matt Coddington) * Bugfix __link: Properly handle existing links (Steven Armstrong) + * Bugfix __key_value: More robust implementation (Steven Armstrong) * New Type: __package_pip 2.0.6: 2012-01-28 From 2fc2df3a35aefc67ad39f0f0431529970d720049 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 11 Feb 2012 11:53:40 +0100 Subject: [PATCH 1298/4212] Preperation -> Preparation Signed-off-by: Nico Schottelius --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 51fb323c..965138c4 100644 --- a/README +++ b/README @@ -89,7 +89,7 @@ cdist was tested or is know to run on at least ## Installation -### Preperation +### Preparation Ensure you have Python 3.2 installed on the machine you use to **deploy to the targets** (the ***source host***). From 6dcbfc3b88bf7d075801003575f8aec66a943a02 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 12 Feb 2012 00:05:01 +0100 Subject: [PATCH 1299/4212] more todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 4db98d58..167f124a 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,5 +1,14 @@ -- __file/foo/bar//bar - - fails later +- cleanup object_id handling + - problems + - __file/foo/bar//bar + - fails later + - right strip __foo/bar/ last slash + - only emulator creates objects + - strip slashes in object creation? + + + +-------------------------------------------------------------------------------- - __user add option to include --create-home From 15fb097464f13f78009a6330c9578b45b102f03c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 12 Feb 2012 00:05:21 +0100 Subject: [PATCH 1300/4212] add function to sanitise object_id and verify no // Signed-off-by: Nico Schottelius --- lib/cdist/core/object.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index da2f21a6..23e2fba5 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -105,12 +105,17 @@ class Object(object): raise IllegalObjectIdError(object_id, 'object_id may not start with /') if OBJECT_MARKER in object_id.split(os.sep): raise IllegalObjectIdError(object_id, 'object_id may not contain \'%s\'' % OBJECT_MARKER) + if '//' in object_id: + raise IllegalObjectIdError(object_id, 'object_id may not contain //') def __init__(self, cdist_type, base_path, object_id=None): - self.validate_object_id(object_id) self.type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id + + self.sanitise_object_id() + self.validate_object_id(object_id) + self.name = self.join_name(self.type.name, self.object_id) self.path = os.path.join(self.type.path, self.object_id, OBJECT_MARKER) self.absolute_path = os.path.join(self.base_path, self.path) @@ -128,7 +133,6 @@ class Object(object): def __hash__(self): return hash(self.name) - def __lt__(self, other): return isinstance(other, self.__class__) and self.name < other.name @@ -146,6 +150,21 @@ class Object(object): type_name, object_id = self.split_name(object_name) return self.__class__(self.type.__class__(type_path, type_name), base_path, object_id=object_id) + def sanitise_object_id(self): + """ + Remove leading and trailing slash (one only) + """ + + print(self.__repr__()) + + # Remove leading slash + if self.object_id[0] == '/': + self.object_id = self.object_id[1:] + + # Remove trailing slash + if self.object_id[-1] == '/': + self.object_id = self.object_id[:-1] + # FIXME: still needed? @property def explorer_path(self): From 4be37f6e9372e0bc338a8c319bba782b84f23090 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 12 Feb 2012 00:08:18 +0100 Subject: [PATCH 1301/4212] begin rename Object => CdistObject Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 12 +++++----- lib/cdist/core/object.py | 8 +++---- lib/cdist/emulator.py | 6 ++--- lib/cdist/test/code/__init__.py | 2 +- lib/cdist/test/emulator/__init__.py | 4 ++-- lib/cdist/test/explorer/__init__.py | 6 ++--- lib/cdist/test/manifest/__init__.py | 2 +- lib/cdist/test/object/__init__.py | 34 ++++++++++++++--------------- lib/cdist/test/resolver/__init__.py | 2 +- 9 files changed, 37 insertions(+), 39 deletions(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 542f2024..f27fff77 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -89,9 +89,9 @@ class ConfigInstall(object): new_objects_created = True while new_objects_created: new_objects_created = False - for cdist_object in core.Object.list_objects(self.local.object_path, + for cdist_object in core.CdistObject.list_objects(self.local.object_path, self.local.type_path): - if cdist_object.state == core.Object.STATE_PREPARED: + if cdist_object.state == core.CdistObject.STATE_PREPARED: self.log.debug("Skipping re-prepare of object %s", cdist_object) continue else: @@ -103,12 +103,12 @@ class ConfigInstall(object): 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.Object.STATE_PREPARED + 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 " + cdist_object.name) - if cdist_object.state == core.Object.STATE_DONE: + if cdist_object.state == core.CdistObject.STATE_DONE: # TODO: remove once we are sure that this really never happens. raise cdist.Error("Attempting to run an already finished object: %s", cdist_object) @@ -130,13 +130,13 @@ class ConfigInstall(object): # Mark this object as done self.log.debug("Finishing run of " + cdist_object.name) - cdist_object.state = core.Object.STATE_DONE + 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") - objects = core.Object.list_objects( + objects = core.CdistObject.list_objects( self.local.object_path, self.local.type_path) diff --git a/lib/cdist/core/object.py b/lib/cdist/core/object.py index 23e2fba5..278cdc46 100644 --- a/lib/cdist/core/object.py +++ b/lib/cdist/core/object.py @@ -42,7 +42,7 @@ class IllegalObjectIdError(cdist.Error): return '%s: %s' % (self.message, self.object_id) -class Object(object): +class CdistObject(object): """Represents a cdist object. All interaction with objects in cdist should be done through this class. @@ -124,7 +124,7 @@ class Object(object): self.parameter_path = os.path.join(self.path, "parameter") def __repr__(self): - return '' % self.name + return '' % self.name def __eq__(self, other): """define equality as 'name is the same'""" @@ -142,7 +142,7 @@ class Object(object): Mainly intended to create objects when resolving requirements. e.g: - .object_from_name('__other/object') -> + .object_from_name('__other/object') -> """ type_path = self.type.base_path @@ -155,8 +155,6 @@ class Object(object): Remove leading and trailing slash (one only) """ - print(self.__repr__()) - # Remove leading slash if self.object_id[0] == '/': self.object_id = self.object_id[1:] diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 05202a39..77bc5ac8 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -126,7 +126,7 @@ class Emulator(object): self.object_id = self.object_id.lstrip('/') # Instantiate the cdist object we are defining - self.cdist_object = core.Object(self.cdist_type, self.object_base_path, self.object_id) + self.cdist_object = core.CdistObject(self.cdist_type, self.object_base_path, self.object_id) # Create object with given parameters self.parameters = {} @@ -154,13 +154,13 @@ class Emulator(object): if len(requirement) == 0: continue - requirement_type_name, requirement_object_id = core.Object.split_name(requirement) + requirement_type_name, requirement_object_id = core.CdistObject.split_name(requirement) # Instantiate type which fails if type does not exist requirement_type = core.Type(self.type_base_path, requirement_type_name) if requirement_object_id: # Validate object_id if any - core.Object.validate_object_id(requirement_object_id) + core.CdistObject.validate_object_id(requirement_object_id) elif not requirement_type.is_singleton: # Only singeltons have no object_id raise IllegalRequirementError(requirement, "Missing object_id and type is not a singleton.") diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index 2f061086..198d3e95 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -55,7 +55,7 @@ class CodeTestCase(test.CdistTestCase): self.code = code.Code(self.target_host, self.local, self.remote) self.cdist_type = core.Type(self.local.type_path, '__dump_environment') - self.cdist_object = core.Object(self.cdist_type, self.local.object_path, 'whatever') + self.cdist_object = core.CdistObject(self.cdist_type, self.local.object_path, 'whatever') self.cdist_object.create() self.log = logging.getLogger("cdist") diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index e67bed4a..4ea792cb 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -120,7 +120,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.Type(self.local.type_path, '__saturn') - cdist_object = core.Object(cdist_type, self.local.object_path, 'singleton') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'singleton') self.manifest.run_type_manifest(cdist_object) expected = ['__planet/Saturn', '__moon/Prometheus'] self.assertEqual(sorted(cdist_object.requirements), sorted(expected)) @@ -157,5 +157,5 @@ class ArgumentsWithDashesTestCase(test.CdistTestCase): emu.run() cdist_type = core.Type(self.local.type_path, '__arguments_with_dashes') - cdist_object = core.Object(cdist_type, self.local.object_path, 'some-id') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'some-id') self.assertTrue('with-dash' in cdist_object.parameters) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index cafe34fc..df5a76ab 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -110,7 +110,7 @@ class ExplorerClassTestCase(test.CdistTestCase): def test_transfer_object_parameters(self): cdist_type = core.Type(self.local.type_path, '__test_type') - cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever') cdist_object.create() cdist_object.parameters = {'first': 'first value', 'second': 'second value'} self.explorer.transfer_object_parameters(cdist_object) @@ -120,14 +120,14 @@ class ExplorerClassTestCase(test.CdistTestCase): def test_run_type_explorer(self): cdist_type = core.Type(self.local.type_path, '__test_type') - cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever') self.explorer.transfer_type_explorers(cdist_type) output = self.explorer.run_type_explorer('world', cdist_object) self.assertEqual(output, 'hello\n') def test_run_type_explorers(self): cdist_type = core.Type(self.local.type_path, '__test_type') - cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever') cdist_object.create() self.explorer.run_type_explorers(cdist_object) self.assertEqual(cdist_object.explorers, {'world': 'hello'}) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index 2383adf7..158cf6fd 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -80,7 +80,7 @@ class ManifestTestCase(test.CdistTestCase): def test_type_manifest_environment(self): cdist_type = core.Type(self.local.type_path, '__dump_environment') - cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever') handle, output_file = self.mkstemp(dir=self.temp_dir) os.close(handle) os.environ['__cdist_test_out'] = output_file diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index f199ffb5..9e6f1221 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -34,19 +34,19 @@ type_base_path = op.join(fixtures, 'type') class ObjectClassTestCase(test.CdistTestCase): def test_list_object_names(self): - object_names = list(core.Object.list_object_names(object_base_path)) + object_names = list(core.CdistObject.list_object_names(object_base_path)) self.assertEqual(object_names, ['__first/man', '__second/on-the', '__third/moon']) def test_list_type_names(self): - type_names = list(core.Object.list_type_names(object_base_path)) + type_names = list(core.CdistObject.list_type_names(object_base_path)) self.assertEqual(type_names, ['__first', '__second', '__third']) def test_list_objects(self): - objects = list(core.Object.list_objects(object_base_path, type_base_path)) + objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) objects_expected = [ - core.Object(core.Type(type_base_path, '__first'), object_base_path, 'man'), - core.Object(core.Type(type_base_path, '__second'), object_base_path, 'on-the'), - core.Object(core.Type(type_base_path, '__third'), object_base_path, 'moon'), + core.CdistObject(core.Type(type_base_path, '__first'), object_base_path, 'man'), + core.CdistObject(core.Type(type_base_path, '__second'), object_base_path, 'on-the'), + core.CdistObject(core.Type(type_base_path, '__third'), object_base_path, 'moon'), ] self.assertEqual(objects, objects_expected) @@ -56,18 +56,18 @@ class ObjectIdTestCase(test.CdistTestCase): cdist_type = core.Type(type_base_path, '__third') illegal_object_id = '/object_id/may/not/start/with/slash' with self.assertRaises(core.IllegalObjectIdError): - core.Object(cdist_type, object_base_path, illegal_object_id) + core.CdistObject(cdist_type, object_base_path, illegal_object_id) def test_object_id_contains_object_marker(self): cdist_type = core.Type(type_base_path, '__third') illegal_object_id = 'object_id/may/not/contain/%s/anywhere' % core.OBJECT_MARKER with self.assertRaises(core.IllegalObjectIdError): - core.Object(cdist_type, object_base_path, illegal_object_id) + core.CdistObject(cdist_type, object_base_path, illegal_object_id) def test_object_id_contains_object_marker_string(self): cdist_type = core.Type(type_base_path, '__third') illegal_object_id = 'object_id/may/contain_%s_in_filename' % core.OBJECT_MARKER - core.Object(cdist_type, object_base_path, illegal_object_id) + core.CdistObject(cdist_type, object_base_path, illegal_object_id) # if we get here, the test passed @@ -75,7 +75,7 @@ class ObjectTestCase(test.CdistTestCase): def setUp(self): self.cdist_type = core.Type(type_base_path, '__third') - self.cdist_object = core.Object(self.cdist_type, object_base_path, 'moon') + self.cdist_object = core.CdistObject(self.cdist_type, object_base_path, 'moon') def tearDown(self): self.cdist_object.changed = False @@ -159,16 +159,16 @@ class ObjectTestCase(test.CdistTestCase): self.assertEqual(self.cdist_object.state, '') def test_state_prepared(self): - self.cdist_object.state = core.Object.STATE_PREPARED - self.assertEqual(self.cdist_object.state, core.Object.STATE_PREPARED) + self.cdist_object.state = core.CdistObject.STATE_PREPARED + self.assertEqual(self.cdist_object.state, core.CdistObject.STATE_PREPARED) def test_state_running(self): - self.cdist_object.state = core.Object.STATE_RUNNING - self.assertEqual(self.cdist_object.state, core.Object.STATE_RUNNING) + self.cdist_object.state = core.CdistObject.STATE_RUNNING + self.assertEqual(self.cdist_object.state, core.CdistObject.STATE_RUNNING) def test_state_done(self): - self.cdist_object.state = core.Object.STATE_DONE - self.assertEqual(self.cdist_object.state, core.Object.STATE_DONE) + self.cdist_object.state = core.CdistObject.STATE_DONE + self.assertEqual(self.cdist_object.state, core.CdistObject.STATE_DONE) def test_source(self): self.assertEqual(list(self.cdist_object.source), []) @@ -195,6 +195,6 @@ class ObjectTestCase(test.CdistTestCase): self.cdist_object.code_remote = 'Hello World' other_name = '__first/man' other_object = self.cdist_object.object_from_name(other_name) - self.assertTrue(isinstance(other_object, core.Object)) + self.assertTrue(isinstance(other_object, core.CdistObject)) self.assertEqual(other_object.type.name, '__first') self.assertEqual(other_object.object_id, 'man') diff --git a/lib/cdist/test/resolver/__init__.py b/lib/cdist/test/resolver/__init__.py index cca058a4..ae8f6915 100644 --- a/lib/cdist/test/resolver/__init__.py +++ b/lib/cdist/test/resolver/__init__.py @@ -37,7 +37,7 @@ type_base_path = op.join(fixtures, 'type') class ResolverTestCase(test.CdistTestCase): def setUp(self): - self.objects = list(core.Object.list_objects(object_base_path, type_base_path)) + 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) From 1314567012d7394e9b87b7689ccc5080cb0cb981 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 12 Feb 2012 01:10:57 +0100 Subject: [PATCH 1302/4212] also begin to prefix type with cdist Signed-off-by: Nico Schottelius --- lib/cdist/core/__init__.py | 16 ++++++++-------- lib/cdist/core/{object.py => cdist_object.py} | 0 lib/cdist/core/{type.py => cdist_type.py} | 6 +++--- lib/cdist/test/object/__init__.py | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) rename lib/cdist/core/{object.py => cdist_object.py} (100%) rename lib/cdist/core/{type.py => cdist_type.py} (97%) diff --git a/lib/cdist/core/__init__.py b/lib/cdist/core/__init__.py index c61c659b..66ee00a5 100644 --- a/lib/cdist/core/__init__.py +++ b/lib/cdist/core/__init__.py @@ -19,11 +19,11 @@ # # -from cdist.core.type import Type -from cdist.core.type import NoSuchTypeError -from cdist.core.object import Object -from cdist.core.object import IllegalObjectIdError -from cdist.core.object import OBJECT_MARKER -from cdist.core.explorer import Explorer -from cdist.core.manifest import Manifest -from cdist.core.code import Code +from cdist.core.cdist_type import CdistType +from cdist.core.cdist_type import NoSuchTypeError +from cdist.core.cdist_object import CdistObject +from cdist.core.cdist_object import IllegalObjectIdError +from cdist.core.cdist_object import OBJECT_MARKER +from cdist.core.explorer import Explorer +from cdist.core.manifest import Manifest +from cdist.core.code import Code diff --git a/lib/cdist/core/object.py b/lib/cdist/core/cdist_object.py similarity index 100% rename from lib/cdist/core/object.py rename to lib/cdist/core/cdist_object.py diff --git a/lib/cdist/core/type.py b/lib/cdist/core/cdist_type.py similarity index 97% rename from lib/cdist/core/type.py rename to lib/cdist/core/cdist_type.py index 20365b8d..55609e7e 100644 --- a/lib/cdist/core/type.py +++ b/lib/cdist/core/cdist_type.py @@ -34,7 +34,7 @@ class NoSuchTypeError(cdist.Error): return "Type '%s' does not exist at %s" % (self.type_path, self.type_absolute_path) -class Type(object): +class CdistType(object): """Represents a cdist type. All interaction with types in cdist should be done through this class. @@ -61,7 +61,7 @@ class Type(object): # name is second argument name = args[1] if not name in cls._instances: - instance = super(Type, cls).__new__(cls) + instance = super(CdistType, cls).__new__(cls) cls._instances[name] = instance # return instance so __init__ is called return cls._instances[name] @@ -84,7 +84,7 @@ class Type(object): self.__optional_parameters = None def __repr__(self): - return '' % self.name + return '' % self.name def __eq__(self, other): return isinstance(other, self.__class__) and self.name == other.name diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 9e6f1221..a633955a 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -38,7 +38,7 @@ class ObjectClassTestCase(test.CdistTestCase): self.assertEqual(object_names, ['__first/man', '__second/on-the', '__third/moon']) def test_list_type_names(self): - type_names = list(core.CdistObject.list_type_names(object_base_path)) + type_names = list(cdist.core.CdistObject.list_type_names(object_base_path)) self.assertEqual(type_names, ['__first', '__second', '__third']) def test_list_objects(self): From fb4f8784b6cb0cdd83aa6fe109bcddcd884967f2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 12 Feb 2012 01:18:14 +0100 Subject: [PATCH 1303/4212] rename Type => CdistType Signed-off-by: Nico Schottelius --- lib/cdist/core/cdist_object.py | 2 +- lib/cdist/test/code/__init__.py | 6 ++-- lib/cdist/test/emulator/__init__.py | 4 +-- lib/cdist/test/explorer/__init__.py | 18 +++++----- lib/cdist/test/manifest/__init__.py | 2 +- lib/cdist/test/object/__init__.py | 14 ++++---- lib/cdist/test/type/__init__.py | 52 ++++++++++++++--------------- 7 files changed, 50 insertions(+), 48 deletions(-) diff --git a/lib/cdist/core/cdist_object.py b/lib/cdist/core/cdist_object.py index 278cdc46..43d07d6b 100644 --- a/lib/cdist/core/cdist_object.py +++ b/lib/cdist/core/cdist_object.py @@ -61,7 +61,7 @@ class CdistObject(object): """Return a list of object instances""" for object_name in cls.list_object_names(object_base_path): type_name, object_id = cls.split_name(object_name) - yield cls(cdist.core.Type(type_base_path, type_name), object_base_path, object_id=object_id) + yield cls(cdist.core.CdistType(type_base_path, type_name), object_base_path, object_id=object_id) @classmethod def list_type_names(cls, object_base_path): diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index 198d3e95..176f139c 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -48,13 +48,13 @@ class CodeTestCase(test.CdistTestCase): self.remote_base_path = self.mkdtemp() self.user = getpass.getuser() - remote_exec = "ssh -o User=%s -q" % self.user - remote_copy = "scp -o User=%s -q" % self.user + remote_exec = "ssh -o User=%s -q" % "root" # self.user + remote_copy = "scp -o User=%s -q" % "root" # self.user self.remote = remote.Remote(self.target_host, self.remote_base_path, remote_exec, remote_copy) self.code = code.Code(self.target_host, self.local, self.remote) - self.cdist_type = core.Type(self.local.type_path, '__dump_environment') + self.cdist_type = core.CdistType(self.local.type_path, '__dump_environment') self.cdist_object = core.CdistObject(self.cdist_type, self.local.object_path, 'whatever') self.cdist_object.create() diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index 4ea792cb..c0037b68 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -119,7 +119,7 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): def test_autorequire(self): initial_manifest = os.path.join(self.local.manifest_path, "init") self.manifest.run_initial_manifest(initial_manifest) - cdist_type = core.Type(self.local.type_path, '__saturn') + cdist_type = core.CdistType(self.local.type_path, '__saturn') cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'singleton') self.manifest.run_type_manifest(cdist_object) expected = ['__planet/Saturn', '__moon/Prometheus'] @@ -156,6 +156,6 @@ class ArgumentsWithDashesTestCase(test.CdistTestCase): emu = emulator.Emulator(argv) emu.run() - cdist_type = core.Type(self.local.type_path, '__arguments_with_dashes') + cdist_type = core.CdistType(self.local.type_path, '__arguments_with_dashes') cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'some-id') self.assertTrue('with-dash' in cdist_object.parameters) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index df5a76ab..716e56b7 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -49,8 +49,10 @@ class ExplorerClassTestCase(test.CdistTestCase): self.remote_base_path = self.mkdtemp() self.user = getpass.getuser() - remote_exec = "ssh -o User=%s -q" % self.user - remote_copy = "scp -o User=%s -q" % self.user + #remote_exec = "ssh -o User=%s -q" % self.user + #remote_copy = "scp -o User=%s -q" % self.user + remote_exec = "ssh -o User=%s -q" % "root" + remote_copy = "scp -o User=%s -q" % "root" self.remote = remote.Remote(self.target_host, self.remote_base_path, remote_exec, remote_copy) self.explorer = explorer.Explorer(self.target_host, self.local, self.remote) @@ -83,19 +85,19 @@ class ExplorerClassTestCase(test.CdistTestCase): shutil.rmtree(out_path) def test_list_type_explorer_names(self): - cdist_type = core.Type(self.local.type_path, '__test_type') + cdist_type = core.CdistType(self.local.type_path, '__test_type') expected = cdist_type.explorers self.assertEqual(self.explorer.list_type_explorer_names(cdist_type), expected) def test_transfer_type_explorers(self): - cdist_type = core.Type(self.local.type_path, '__test_type') + cdist_type = core.CdistType(self.local.type_path, '__test_type') self.explorer.transfer_type_explorers(cdist_type) source = os.path.join(self.local.type_path, cdist_type.explorer_path) destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) self.assertEqual(os.listdir(source), os.listdir(destination)) def test_transfer_type_explorers_only_once(self): - cdist_type = core.Type(self.local.type_path, '__test_type') + cdist_type = core.CdistType(self.local.type_path, '__test_type') # first transfer self.explorer.transfer_type_explorers(cdist_type) source = os.path.join(self.local.type_path, cdist_type.explorer_path) @@ -109,7 +111,7 @@ class ExplorerClassTestCase(test.CdistTestCase): self.assertFalse(os.listdir(destination)) def test_transfer_object_parameters(self): - cdist_type = core.Type(self.local.type_path, '__test_type') + cdist_type = core.CdistType(self.local.type_path, '__test_type') cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever') cdist_object.create() cdist_object.parameters = {'first': 'first value', 'second': 'second value'} @@ -119,14 +121,14 @@ class ExplorerClassTestCase(test.CdistTestCase): self.assertEqual(sorted(os.listdir(source)), sorted(os.listdir(destination))) def test_run_type_explorer(self): - cdist_type = core.Type(self.local.type_path, '__test_type') + cdist_type = core.CdistType(self.local.type_path, '__test_type') cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever') self.explorer.transfer_type_explorers(cdist_type) output = self.explorer.run_type_explorer('world', cdist_object) self.assertEqual(output, 'hello\n') def test_run_type_explorers(self): - cdist_type = core.Type(self.local.type_path, '__test_type') + cdist_type = core.CdistType(self.local.type_path, '__test_type') cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever') cdist_object.create() self.explorer.run_type_explorers(cdist_object) diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index 158cf6fd..a188c788 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -79,7 +79,7 @@ class ManifestTestCase(test.CdistTestCase): self.assertEqual(output_dict['__manifest'], self.local.manifest_path) def test_type_manifest_environment(self): - cdist_type = core.Type(self.local.type_path, '__dump_environment') + cdist_type = core.CdistType(self.local.type_path, '__dump_environment') cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever') handle, output_file = self.mkstemp(dir=self.temp_dir) os.close(handle) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index a633955a..00cc1e00 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -44,28 +44,28 @@ class ObjectClassTestCase(test.CdistTestCase): def test_list_objects(self): objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) objects_expected = [ - core.CdistObject(core.Type(type_base_path, '__first'), object_base_path, 'man'), - core.CdistObject(core.Type(type_base_path, '__second'), object_base_path, 'on-the'), - core.CdistObject(core.Type(type_base_path, '__third'), object_base_path, 'moon'), + core.CdistObject(core.CdistType(type_base_path, '__first'), object_base_path, 'man'), + core.CdistObject(core.CdistType(type_base_path, '__second'), object_base_path, 'on-the'), + core.CdistObject(core.CdistType(type_base_path, '__third'), object_base_path, 'moon'), ] self.assertEqual(objects, objects_expected) class ObjectIdTestCase(test.CdistTestCase): def test_object_id_starts_with_slash(self): - cdist_type = core.Type(type_base_path, '__third') + cdist_type = core.CdistType(type_base_path, '__third') illegal_object_id = '/object_id/may/not/start/with/slash' with self.assertRaises(core.IllegalObjectIdError): core.CdistObject(cdist_type, object_base_path, illegal_object_id) def test_object_id_contains_object_marker(self): - cdist_type = core.Type(type_base_path, '__third') + cdist_type = core.CdistType(type_base_path, '__third') illegal_object_id = 'object_id/may/not/contain/%s/anywhere' % core.OBJECT_MARKER with self.assertRaises(core.IllegalObjectIdError): core.CdistObject(cdist_type, object_base_path, illegal_object_id) def test_object_id_contains_object_marker_string(self): - cdist_type = core.Type(type_base_path, '__third') + cdist_type = core.CdistType(type_base_path, '__third') illegal_object_id = 'object_id/may/contain_%s_in_filename' % core.OBJECT_MARKER core.CdistObject(cdist_type, object_base_path, illegal_object_id) # if we get here, the test passed @@ -74,7 +74,7 @@ class ObjectIdTestCase(test.CdistTestCase): class ObjectTestCase(test.CdistTestCase): def setUp(self): - self.cdist_type = core.Type(type_base_path, '__third') + self.cdist_type = core.CdistType(type_base_path, '__third') self.cdist_object = core.CdistObject(self.cdist_type, object_base_path, 'moon') def tearDown(self): diff --git a/lib/cdist/test/type/__init__.py b/lib/cdist/test/type/__init__.py index 7bb8654c..2ef14a4c 100644 --- a/lib/cdist/test/type/__init__.py +++ b/lib/cdist/test/type/__init__.py @@ -33,115 +33,115 @@ class TypeTestCase(test.CdistTestCase): def test_list_type_names(self): base_path = op.join(fixtures, 'list_types') - type_names = core.Type.list_type_names(base_path) + type_names = core.CdistType.list_type_names(base_path) self.assertEqual(type_names, ['__first', '__second', '__third']) def test_list_types(self): base_path = op.join(fixtures, 'list_types') - types = list(core.Type.list_types(base_path)) + types = list(core.CdistType.list_types(base_path)) types_expected = [ - core.Type(base_path, '__first'), - core.Type(base_path, '__second'), - core.Type(base_path, '__third'), + core.CdistType(base_path, '__first'), + core.CdistType(base_path, '__second'), + core.CdistType(base_path, '__third'), ] self.assertEqual(types, types_expected) def test_only_one_instance(self): base_path = fixtures - cdist_type1 = core.Type(base_path, '__name_path') - cdist_type2 = core.Type(base_path, '__name_path') + cdist_type1 = core.CdistType(base_path, '__name_path') + cdist_type2 = core.CdistType(base_path, '__name_path') self.assertEqual(id(cdist_type1), id(cdist_type2)) def test_nonexistent_type(self): base_path = fixtures - self.assertRaises(core.NoSuchTypeError, core.Type, base_path, '__i-dont-exist') + self.assertRaises(core.NoSuchTypeError, core.CdistType, base_path, '__i-dont-exist') def test_name(self): base_path = fixtures - cdist_type = core.Type(base_path, '__name_path') + cdist_type = core.CdistType(base_path, '__name_path') self.assertEqual(cdist_type.name, '__name_path') def test_path(self): base_path = fixtures - cdist_type = core.Type(base_path, '__name_path') + cdist_type = core.CdistType(base_path, '__name_path') self.assertEqual(cdist_type.path, '__name_path') def test_base_path(self): base_path = fixtures - cdist_type = core.Type(base_path, '__name_path') + cdist_type = core.CdistType(base_path, '__name_path') self.assertEqual(cdist_type.base_path, base_path) def test_absolute_path(self): base_path = fixtures - cdist_type = core.Type(base_path, '__name_path') + cdist_type = core.CdistType(base_path, '__name_path') self.assertEqual(cdist_type.absolute_path, os.path.join(base_path, '__name_path')) def test_manifest_path(self): base_path = fixtures - cdist_type = core.Type(base_path, '__name_path') + cdist_type = core.CdistType(base_path, '__name_path') self.assertEqual(cdist_type.manifest_path, os.path.join('__name_path', 'manifest')) def test_explorer_path(self): base_path = fixtures - cdist_type = core.Type(base_path, '__name_path') + cdist_type = core.CdistType(base_path, '__name_path') self.assertEqual(cdist_type.explorer_path, os.path.join('__name_path', 'explorer')) def test_gencode_local_path(self): base_path = fixtures - cdist_type = core.Type(base_path, '__name_path') + cdist_type = core.CdistType(base_path, '__name_path') self.assertEqual(cdist_type.gencode_local_path, os.path.join('__name_path', 'gencode-local')) def test_gencode_remote_path(self): base_path = fixtures - cdist_type = core.Type(base_path, '__name_path') + cdist_type = core.CdistType(base_path, '__name_path') self.assertEqual(cdist_type.gencode_remote_path, os.path.join('__name_path', 'gencode-remote')) def test_singleton_is_singleton(self): base_path = fixtures - cdist_type = core.Type(base_path, '__singleton') + cdist_type = core.CdistType(base_path, '__singleton') self.assertTrue(cdist_type.is_singleton) def test_not_singleton_is_singleton(self): base_path = fixtures - cdist_type = core.Type(base_path, '__not_singleton') + 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.Type(base_path, '__install') + 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.Type(base_path, '__not_install') + 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.Type(base_path, '__with_explorers') + cdist_type = core.CdistType(base_path, '__with_explorers') self.assertEqual(cdist_type.explorers, ['whatever']) def test_without_explorers(self): base_path = fixtures - cdist_type = core.Type(base_path, '__without_explorers') + cdist_type = core.CdistType(base_path, '__without_explorers') self.assertEqual(cdist_type.explorers, []) def test_with_required_parameters(self): base_path = fixtures - cdist_type = core.Type(base_path, '__with_required_parameters') + cdist_type = core.CdistType(base_path, '__with_required_parameters') self.assertEqual(cdist_type.required_parameters, ['required1', 'required2']) def test_without_required_parameters(self): base_path = fixtures - cdist_type = core.Type(base_path, '__without_required_parameters') + cdist_type = core.CdistType(base_path, '__without_required_parameters') self.assertEqual(cdist_type.required_parameters, []) def test_with_optional_parameters(self): base_path = fixtures - cdist_type = core.Type(base_path, '__with_optional_parameters') + cdist_type = core.CdistType(base_path, '__with_optional_parameters') self.assertEqual(cdist_type.optional_parameters, ['optional1', 'optional2']) def test_without_optional_parameters(self): base_path = fixtures - cdist_type = core.Type(base_path, '__without_optional_parameters') + cdist_type = core.CdistType(base_path, '__without_optional_parameters') self.assertEqual(cdist_type.optional_parameters, []) From 91ecfa7d3f185e4baab2d5a3e903924d4170c026 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 12 Feb 2012 01:27:25 +0100 Subject: [PATCH 1304/4212] back to 100% tests working Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 8 +++++--- lib/cdist/exec/local.py | 2 +- lib/cdist/test/code/__init__.py | 4 ++-- lib/cdist/test/explorer/__init__.py | 6 ++---- lib/cdist/test/object/__init__.py | 2 ++ 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 77bc5ac8..72ed3b9b 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -41,14 +41,16 @@ class Emulator(object): self.object_id = False self.global_path = os.environ['__global'] - self.object_source = os.environ['__cdist_manifest'] self.target_host = os.environ['__target_host'] + + # Internally only + self.object_source = os.environ['__cdist_manifest'] self.type_base_path = os.environ['__cdist_type_base_path'] self.object_base_path = os.path.join(self.global_path, "object") self.type_name = os.path.basename(argv[0]) - self.cdist_type = core.Type(self.type_base_path, self.type_name) + self.cdist_type = core.CdistType(self.type_base_path, self.type_name) self.__init_log() @@ -156,7 +158,7 @@ class Emulator(object): requirement_type_name, requirement_object_id = core.CdistObject.split_name(requirement) # Instantiate type which fails if type does not exist - requirement_type = core.Type(self.type_base_path, requirement_type_name) + requirement_type = core.CdistType(self.type_base_path, requirement_type_name) if requirement_object_id: # Validate object_id if any diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index 613f5cf2..cdf06205 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -143,7 +143,7 @@ class Local(object): def link_emulator(self, exec_path): """Link emulator to types""" src = os.path.abspath(exec_path) - for cdist_type in core.Type.list_types(self.type_path): + for cdist_type in core.CdistType.list_types(self.type_path): dst = os.path.join(self.bin_path, cdist_type.name) self.log.debug("Linking emulator: %s to %s", src, dst) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index 176f139c..dc701cce 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -48,8 +48,8 @@ class CodeTestCase(test.CdistTestCase): self.remote_base_path = self.mkdtemp() self.user = getpass.getuser() - remote_exec = "ssh -o User=%s -q" % "root" # self.user - remote_copy = "scp -o User=%s -q" % "root" # self.user + remote_exec = "ssh -o User=%s -q" % self.user + remote_copy = "scp -o User=%s -q" % self.user self.remote = remote.Remote(self.target_host, self.remote_base_path, remote_exec, remote_copy) self.code = code.Code(self.target_host, self.local, self.remote) diff --git a/lib/cdist/test/explorer/__init__.py b/lib/cdist/test/explorer/__init__.py index 716e56b7..257ad8a9 100644 --- a/lib/cdist/test/explorer/__init__.py +++ b/lib/cdist/test/explorer/__init__.py @@ -49,10 +49,8 @@ class ExplorerClassTestCase(test.CdistTestCase): self.remote_base_path = self.mkdtemp() self.user = getpass.getuser() - #remote_exec = "ssh -o User=%s -q" % self.user - #remote_copy = "scp -o User=%s -q" % self.user - remote_exec = "ssh -o User=%s -q" % "root" - remote_copy = "scp -o User=%s -q" % "root" + remote_exec = "ssh -o User=%s -q" % self.user + remote_copy = "scp -o User=%s -q" % self.user self.remote = remote.Remote(self.target_host, self.remote_base_path, remote_exec, remote_copy) self.explorer = explorer.Explorer(self.target_host, self.local, self.remote) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 00cc1e00..0f8c0189 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -25,6 +25,8 @@ import shutil from cdist import test from cdist import core +import cdist + import os.path as op my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') From ad4aa19c3e54d16096dca9555e3398a9ce941522 Mon Sep 17 00:00:00 2001 From: Benedikt Koeppel Date: Sun, 12 Feb 2012 15:08:34 +0100 Subject: [PATCH 1305/4212] new type __run_command This cdist type allows you to run a specific command once at installation time. optional parameter: --command Command (with arguments) to run. --- conf/type/__run_command/gencode-remote | 26 ++++++++ conf/type/__run_command/man.text | 70 ++++++++++++++++++++++ conf/type/__run_command/parameter/optional | 1 + conf/type/__run_command/parameter/required | 0 4 files changed, 97 insertions(+) create mode 100755 conf/type/__run_command/gencode-remote create mode 100644 conf/type/__run_command/man.text create mode 100644 conf/type/__run_command/parameter/optional create mode 100644 conf/type/__run_command/parameter/required diff --git a/conf/type/__run_command/gencode-remote b/conf/type/__run_command/gencode-remote new file mode 100755 index 00000000..7ffd9a7b --- /dev/null +++ b/conf/type/__run_command/gencode-remote @@ -0,0 +1,26 @@ +#!/bin/sh +# +# 2012 Benedikt Koeppel (code at benediktkoeppel.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +if [ -f "$__object/parameter/command" ]; then + cat "$__object/parameter/command" +else + echo "$name" +fi diff --git a/conf/type/__run_command/man.text b/conf/type/__run_command/man.text new file mode 100644 index 00000000..5ea553c3 --- /dev/null +++ b/conf/type/__run_command/man.text @@ -0,0 +1,70 @@ +cdist-type__run_command(7) +========================== +Benedikt Koeppel + + +NAME +---- +cdist-type__run_command - Run a command + + +DESCRIPTION +----------- +This cdist type allows you to run a specific command once at installation time. + + +REQUIRED PARAMETERS +------------------- + + +OPTIONAL PARAMETERS +------------------- +command:: + Command (with arguments) to run. + + If no command is give, then the object_id is executed. + + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Run a command +__run_command "/etc/init.d/mysql restart" +# runs `/etc/init.d/mysql restart` (the "object_id") + +# Run the same command: +__run_command restart-mysql --command "/etc/init.d/mysql restart" +# runs `/etc/init.d/mysql restart` (the --command argument) +# additionally, it can easily be referenced (for example in a require="..." +#as __run_command/restart-mysql + +# Run a script: +__run_command install-pear --command "$(cat <<-EOF + /usr/bin/pear install --force Auth + /usr/bin/pear install --force HTML_Template_IT-1.2.1 + /usr/bin/pear install --force MDB2 + /usr/bin/pear install --force MDB2#mysql + /usr/bin/pear config-set preferred_state beta; + /usr/bin/pear install --force --alldeps Spreadsheet_Excel_Writer; + /usr/bin/pear config-set preferred_state stable + /usr/bin/pear install --force HTTP_Request + /usr/bin/pear install --force Mail + /usr/bin/pear install --force Auth_HTTP + /usr/bin/pear install --force XML_RPC +EOF +)" + +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2012 Benedikt Koeppel. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__run_command/parameter/optional b/conf/type/__run_command/parameter/optional new file mode 100644 index 00000000..aa56d324 --- /dev/null +++ b/conf/type/__run_command/parameter/optional @@ -0,0 +1 @@ +command diff --git a/conf/type/__run_command/parameter/required b/conf/type/__run_command/parameter/required new file mode 100644 index 00000000..e69de29b From 0c990e17566bc86fbcdade68fcbbcb3eff450a5f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 07:25:04 +0100 Subject: [PATCH 1306/4212] add singleton / no object_id test to CdistObject Signed-off-by: Nico Schottelius --- lib/cdist/core/cdist_object.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/cdist/core/cdist_object.py b/lib/cdist/core/cdist_object.py index 43d07d6b..6b1e02b0 100644 --- a/lib/cdist/core/cdist_object.py +++ b/lib/cdist/core/cdist_object.py @@ -96,25 +96,29 @@ class CdistObject(object): """ return os.path.join(type_name, object_id) - @staticmethod - def validate_object_id(object_id): + def validate_object_id(self): """Validate the given object_id and raise IllegalObjectIdError if it's not valid. """ if object_id: - if object_id.startswith('/'): + if self.object_id.startswith('/'): raise IllegalObjectIdError(object_id, 'object_id may not start with /') - if OBJECT_MARKER in object_id.split(os.sep): + if OBJECT_MARKER in self.object_id.split(os.sep): raise IllegalObjectIdError(object_id, 'object_id may not contain \'%s\'' % OBJECT_MARKER) - if '//' in object_id: + if '//' in self.object_id: raise IllegalObjectIdError(object_id, 'object_id may not contain //') + # If no object_id and type is not singleton => error out + if not object_id and not self.type.is_singleton: + raise IllegalObjectIdError(object_id, + "Missing object_id and type is not a singleton.") + def __init__(self, cdist_type, base_path, object_id=None): self.type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id self.sanitise_object_id() - self.validate_object_id(object_id) + self.validate_object_id() self.name = self.join_name(self.type.name, self.object_id) self.path = os.path.join(self.type.path, self.object_id, OBJECT_MARKER) From ab565dc3d90e8f2de14976e0e902bc52e3669af0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 07:45:10 +0100 Subject: [PATCH 1307/4212] cleanup / emulator Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 12 ++++-------- lib/cdist/emulator.py | 17 ++++------------- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 167f124a..34c2f7b0 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,12 +1,8 @@ - cleanup object_id handling - - problems - - __file/foo/bar//bar - - fails later - - right strip __foo/bar/ last slash - - only emulator creates objects - - strip slashes in object creation? - - + - have a look at singletons + - double check verification + - cleanup emulator to create object + - adjust tests -------------------------------------------------------------------------------- diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 72ed3b9b..67f6d373 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -115,18 +115,13 @@ class Emulator(object): def setup_object(self): - # FIXME: verify object id - - # Setup object_id + # Setup object_id - FIXME: unset / do not setup anymore! if self.cdist_type.is_singleton: self.object_id = "singleton" else: self.object_id = self.args.object_id[0] del self.args.object_id - # strip leading slash from object_id - self.object_id = self.object_id.lstrip('/') - # Instantiate the cdist object we are defining self.cdist_object = core.CdistObject(self.cdist_type, self.object_base_path, self.object_id) @@ -160,13 +155,9 @@ class Emulator(object): # Instantiate type which fails if type does not exist requirement_type = core.CdistType(self.type_base_path, requirement_type_name) - if requirement_object_id: - # Validate object_id if any - core.CdistObject.validate_object_id(requirement_object_id) - elif not requirement_type.is_singleton: - # Only singeltons have no object_id - raise IllegalRequirementError(requirement, "Missing object_id and type is not a singleton.") - + # FIXME: need try/catch here or pass exception from core.CdistObject? + # Instantiate object, which fails if object id is broken + requirement_object = core.CdistObject(requirement_type, self.object_base_path, requirement_object_id) self.log.debug("Recording requirement: " + requirement) self.cdist_object.requirements.append(requirement) From f27730e10b374a1952b825cb874b7089fb12acbf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 07:45:32 +0100 Subject: [PATCH 1308/4212] finish rewrite to instance method Signed-off-by: Nico Schottelius --- lib/cdist/core/cdist_object.py | 42 ++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/lib/cdist/core/cdist_object.py b/lib/cdist/core/cdist_object.py index 6b1e02b0..81b7e7e9 100644 --- a/lib/cdist/core/cdist_object.py +++ b/lib/cdist/core/cdist_object.py @@ -97,19 +97,21 @@ 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? + """Validate the given object_id and raise IllegalObjectIdError if it's not valid. """ - if object_id: + if self.object_id: if self.object_id.startswith('/'): - raise IllegalObjectIdError(object_id, 'object_id may not start with /') + raise IllegalObjectIdError(self.object_id, 'object_id may not start with /') if OBJECT_MARKER in self.object_id.split(os.sep): - raise IllegalObjectIdError(object_id, 'object_id may not contain \'%s\'' % OBJECT_MARKER) + raise IllegalObjectIdError(self.object_id, 'object_id may not contain \'%s\'' % OBJECT_MARKER) if '//' in self.object_id: - raise IllegalObjectIdError(object_id, 'object_id may not contain //') + raise IllegalObjectIdError(self.object_id, 'object_id may not contain //') # If no object_id and type is not singleton => error out - if not object_id and not self.type.is_singleton: - raise IllegalObjectIdError(object_id, + if not self.object_id and not self.type.is_singleton: + raise IllegalObjectIdError(self.object_id, "Missing object_id and type is not a singleton.") def __init__(self, cdist_type, base_path, object_id=None): @@ -127,19 +129,6 @@ class CdistObject(object): self.code_remote_path = os.path.join(self.path, "code-remote") self.parameter_path = os.path.join(self.path, "parameter") - def __repr__(self): - return '' % self.name - - def __eq__(self, other): - """define equality as 'name is the same'""" - return self.name == other.name - - def __hash__(self): - return hash(self.name) - - def __lt__(self, other): - return isinstance(other, self.__class__) and self.name < other.name - def object_from_name(self, object_name): """Convenience method for creating an object instance from an object name. @@ -154,7 +143,20 @@ class CdistObject(object): type_name, object_id = self.split_name(object_name) return self.__class__(self.type.__class__(type_path, type_name), base_path, object_id=object_id) - def sanitise_object_id(self): + def __repr__(self): + return '' % self.name + + def __eq__(self, other): + """define equality as 'name is the same'""" + return self.name == other.name + + def __hash__(self): + return hash(self.name) + + def __lt__(self, other): + return isinstance(other, self.__class__) and self.name < other.name + + def sanitise_object_id(self): """ Remove leading and trailing slash (one only) """ From 754aba1a15fcee312308fcd54d3757fdae195b59 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 07:47:33 +0100 Subject: [PATCH 1309/4212] record source in setup_object not in requirements Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 67f6d373..8174b38f 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -140,6 +140,9 @@ class Emulator(object): self.cdist_object.create() self.cdist_object.parameters = self.parameters + # Record / Append source + self.cdist_object.source.append(self.object_source) + def record_requirements(self): """record requirements""" @@ -153,17 +156,16 @@ class Emulator(object): requirement_type_name, requirement_object_id = core.CdistObject.split_name(requirement) # Instantiate type which fails if type does not exist - requirement_type = core.CdistType(self.type_base_path, requirement_type_name) + requirement_type = core.CdistType(self.type_base_path, + requirement_type_name) - # FIXME: need try/catch here or pass exception from core.CdistObject? # Instantiate object, which fails if object id is broken - requirement_object = core.CdistObject(requirement_type, self.object_base_path, requirement_object_id) + requirement_object = core.CdistObject(requirement_type, + self.object_base_path, requirement_object_id) + self.log.debug("Recording requirement: " + requirement) self.cdist_object.requirements.append(requirement) - # Record / Append source - self.cdist_object.source.append(self.object_source) - def record_auto_requirements(self): """An object shall automatically depend on all objects that it defined in it's type manifest. """ From 097b4ea6ada2bd55c0750429218a43871b80f413 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 07:50:11 +0100 Subject: [PATCH 1310/4212] :%s/self.type/self.cdist_type/g Signed-off-by: Nico Schottelius --- lib/cdist/core/cdist_object.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/cdist/core/cdist_object.py b/lib/cdist/core/cdist_object.py index 81b7e7e9..e7ea7a9f 100644 --- a/lib/cdist/core/cdist_object.py +++ b/lib/cdist/core/cdist_object.py @@ -110,20 +110,20 @@ class CdistObject(object): raise IllegalObjectIdError(self.object_id, 'object_id may not contain //') # If no object_id and type is not singleton => error out - if not self.object_id and not self.type.is_singleton: + 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.") def __init__(self, cdist_type, base_path, object_id=None): - self.type = cdist_type # instance of Type + self.cdist_type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id self.sanitise_object_id() self.validate_object_id() - self.name = self.join_name(self.type.name, self.object_id) - self.path = os.path.join(self.type.path, self.object_id, OBJECT_MARKER) + self.name = self.join_name(self.cdist_type.name, self.object_id) + self.path = os.path.join(self.cdist_type.path, self.object_id, OBJECT_MARKER) self.absolute_path = os.path.join(self.base_path, self.path) self.code_local_path = os.path.join(self.path, "code-local") self.code_remote_path = os.path.join(self.path, "code-remote") @@ -138,10 +138,10 @@ class CdistObject(object): .object_from_name('__other/object') -> """ - type_path = self.type.base_path + type_path = self.cdist_type.base_path base_path = self.base_path type_name, object_id = self.split_name(object_name) - return self.__class__(self.type.__class__(type_path, type_name), base_path, object_id=object_id) + return self.__class__(self.cdist_type.__class__(type_path, type_name), base_path, object_id=object_id) def __repr__(self): return '' % self.name From 2492d51f6f5d0741096344e13a3a2c54c782d36a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 07:56:37 +0100 Subject: [PATCH 1311/4212] make object_from_name() better readable Signed-off-by: Nico Schottelius --- lib/cdist/core/cdist_object.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/cdist_object.py b/lib/cdist/core/cdist_object.py index e7ea7a9f..b6bf0903 100644 --- a/lib/cdist/core/cdist_object.py +++ b/lib/cdist/core/cdist_object.py @@ -138,10 +138,15 @@ class CdistObject(object): .object_from_name('__other/object') -> """ - type_path = self.cdist_type.base_path + base_path = self.base_path + type_path = self.cdist_type.base_path + type_name, object_id = self.split_name(object_name) - return self.__class__(self.cdist_type.__class__(type_path, type_name), base_path, object_id=object_id) + + cdist_type = self.cdist_type.__class__(type_path, type_name) + + return self.__class__(cdist_type, base_path, object_id=object_id) def __repr__(self): return '' % self.name From dcd3bcee3258ef6f8bb55047db08151bf2e72770 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 07:57:51 +0100 Subject: [PATCH 1312/4212] use the great method object_from_name() in emulator Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 8174b38f..64773334 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -154,15 +154,7 @@ class Emulator(object): if len(requirement) == 0: continue - requirement_type_name, requirement_object_id = core.CdistObject.split_name(requirement) - # Instantiate type which fails if type does not exist - requirement_type = core.CdistType(self.type_base_path, - requirement_type_name) - - # Instantiate object, which fails if object id is broken - requirement_object = core.CdistObject(requirement_type, - self.object_base_path, requirement_object_id) - + self.cdist_object.object_from_name(requirement) self.log.debug("Recording requirement: " + requirement) self.cdist_object.requirements.append(requirement) From eadb62e67a9e4136e5321140d8160b01aa4fe931 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 08:44:09 +0100 Subject: [PATCH 1313/4212] minimal beaufity Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 1 - lib/cdist/emulator.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 34c2f7b0..77cbe986 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,7 +1,6 @@ - cleanup object_id handling - have a look at singletons - double check verification - - cleanup emulator to create object - adjust tests -------------------------------------------------------------------------------- diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 64773334..5e95e31c 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -151,9 +151,9 @@ class Emulator(object): self.log.debug("reqs = " + requirements) for requirement in requirements.split(" "): # Ignore empty fields - probably the only field anyway - if len(requirement) == 0: - continue + if len(requirement) == 0: continue + # Raises an error, if object cannot be created self.cdist_object.object_from_name(requirement) self.log.debug("Recording requirement: " + requirement) self.cdist_object.requirements.append(requirement) From 921b0c0dffb5d09b624cd384b3aa5bf2de90effc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 08:49:49 +0100 Subject: [PATCH 1314/4212] do not submit run/exec types containing echo only Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-hacker.text | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/man/man7/cdist-hacker.text b/doc/man/man7/cdist-hacker.text index 9bdf63d4..646439a3 100644 --- a/doc/man/man7/cdist-hacker.text +++ b/doc/man/man7/cdist-hacker.text @@ -61,12 +61,19 @@ including it. HOW TO SUBMIT A NEW TYPE ------------------------ +For detailled information about types, see cdist-type(7). + Submitting a type works as described above, with the additional requirement that a corresponding manpage named man.text in asciidoc format with the manpage-name "cdist-type__NAME" is included in the type directory AND asciidoc is able to compile it (i.e. do NOT have to many "=" in the second line). +Warning: Submitting "exec" or "run" types that simply echo their parameter in +gencode* will not be accepted, because they are of no use. Every type can output +code and thus such a type introduces redundant functionality that is given by +core cdist already. + SEE ALSO -------- From 1e5226e21c9007484982fe076c13087bea714c5f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 08:51:40 +0100 Subject: [PATCH 1315/4212] fix indention errors due to vim c&p Signed-off-by: Nico Schottelius --- lib/cdist/core/cdist_object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/cdist_object.py b/lib/cdist/core/cdist_object.py index b6bf0903..f425ca60 100644 --- a/lib/cdist/core/cdist_object.py +++ b/lib/cdist/core/cdist_object.py @@ -148,7 +148,7 @@ class CdistObject(object): return self.__class__(cdist_type, base_path, object_id=object_id) - def __repr__(self): + def __repr__(self): return '' % self.name def __eq__(self, other): @@ -161,7 +161,7 @@ class CdistObject(object): def __lt__(self, other): return isinstance(other, self.__class__) and self.name < other.name - def sanitise_object_id(self): + def sanitise_object_id(self): """ Remove leading and trailing slash (one only) """ From 2bc201614a77f99f554992f5b3260f0047c4c807 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 08:54:09 +0100 Subject: [PATCH 1316/4212] :%s/cdist_object.type/cdist_object.cdist_type/g Signed-off-by: Nico Schottelius --- lib/cdist/core/explorer.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index 43b0339c..bbd2108c 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -121,18 +121,18 @@ class Explorer(object): in the object. """ - self.log.debug("Transfering type explorers for type: %s", cdist_object.type) - self.transfer_type_explorers(cdist_object.type) + self.log.debug("Transfering type explorers for type: %s", cdist_object.cdist_type) + self.transfer_type_explorers(cdist_object.cdist_type) self.log.debug("Transfering object parameters for object: %s", cdist_object.name) self.transfer_object_parameters(cdist_object) - for explorer in self.list_type_explorer_names(cdist_object.type): + for explorer in self.list_type_explorer_names(cdist_object.cdist_type): output = self.run_type_explorer(explorer, cdist_object) self.log.debug("Running type explorer '%s' for object '%s'", explorer, cdist_object.name) cdist_object.explorers[explorer] = output def run_type_explorer(self, explorer, cdist_object): """Run the given type explorer for the given object and return it's output.""" - cdist_type = cdist_object.type + cdist_type = cdist_object.cdist_type env = self.env.copy() env.update({ '__object': os.path.join(self.remote.object_path, cdist_object.path), From a8e9b7feedb7485239f877ce1e5d2f2731930d7f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 08:55:42 +0100 Subject: [PATCH 1317/4212] :%s/cdist_object.type/cdist_object.cdist_type/g Signed-off-by: Nico Schottelius --- lib/cdist/core/manifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index 704a3978..8b784229 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -87,7 +87,7 @@ class Manifest(object): self.local.run_script(script, env=env) def run_type_manifest(self, cdist_object): - script = os.path.join(self.local.type_path, cdist_object.type.manifest_path) + script = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) if os.path.isfile(script): env = os.environ.copy() env.update(self.env) @@ -96,7 +96,7 @@ class Manifest(object): '__object_id': cdist_object.object_id, '__object_name': cdist_object.name, '__self': cdist_object.name, - '__type': cdist_object.type.absolute_path, + '__type': cdist_object.cdist_type.absolute_path, '__cdist_manifest': script, }) self.local.run_script(script, env=env) From 8f75a9133fae3a75f459aa5314934bb58db042e5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 10:38:36 +0100 Subject: [PATCH 1318/4212] do not fail validation on empty object_id Signed-off-by: Nico Schottelius --- lib/cdist/core/cdist_object.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/cdist/core/cdist_object.py b/lib/cdist/core/cdist_object.py index f425ca60..3c2de01b 100644 --- a/lib/cdist/core/cdist_object.py +++ b/lib/cdist/core/cdist_object.py @@ -166,13 +166,15 @@ class CdistObject(object): Remove leading and trailing slash (one only) """ - # Remove leading slash - if self.object_id[0] == '/': - self.object_id = self.object_id[1:] + # Allow empty object id for singletons + if self.object_id: + # Remove leading slash + if self.object_id[0] == '/': + self.object_id = self.object_id[1:] - # Remove trailing slash - if self.object_id[-1] == '/': - self.object_id = self.object_id[:-1] + # Remove trailing slash + if self.object_id[-1] == '/': + self.object_id = self.object_id[:-1] # FIXME: still needed? @property From 0851af7d52e98f30ad5454a000c6a7291b62539c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 10:39:04 +0100 Subject: [PATCH 1319/4212] allow object_id to start and end with one /, fail with any // Signed-off-by: Nico Schottelius --- lib/cdist/test/object/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 0f8c0189..72530910 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -54,9 +54,9 @@ class ObjectClassTestCase(test.CdistTestCase): class ObjectIdTestCase(test.CdistTestCase): - def test_object_id_starts_with_slash(self): + def test_object_id_contains_double_slash(self): cdist_type = core.CdistType(type_base_path, '__third') - illegal_object_id = '/object_id/may/not/start/with/slash' + illegal_object_id = '/object_id//may/not/contain/double/slash' with self.assertRaises(core.IllegalObjectIdError): core.CdistObject(cdist_type, object_base_path, illegal_object_id) From f12a83f3dddbe6481581b594ba8ee119f00181c7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 10:41:12 +0100 Subject: [PATCH 1320/4212] -migration to CdistType error Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 3 +++ lib/cdist/core/code.py | 4 ++-- lib/cdist/test/object/__init__.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 77cbe986..dd20026c 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -3,6 +3,9 @@ - double check verification - adjust tests +- remove useless + ERROR: monitoring02: Code that raised the error: + -------------------------------------------------------------------------------- - __user diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index 51912559..7e69f21c 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -96,13 +96,13 @@ class Code(object): self.env.update({'__debug': "yes" }) def _run_gencode(self, cdist_object, which): - cdist_type = cdist_object.type + cdist_type = cdist_object.cdist_type script = os.path.join(self.local.type_path, getattr(cdist_type, 'gencode_%s_path' % which)) if os.path.isfile(script): env = os.environ.copy() env.update(self.env) env.update({ - '__type': cdist_object.type.absolute_path, + '__type': cdist_object.cdist_type.absolute_path, '__object': cdist_object.absolute_path, '__object_id': cdist_object.object_id, '__object_name': cdist_object.name, diff --git a/lib/cdist/test/object/__init__.py b/lib/cdist/test/object/__init__.py index 72530910..3a91f709 100644 --- a/lib/cdist/test/object/__init__.py +++ b/lib/cdist/test/object/__init__.py @@ -198,5 +198,5 @@ class ObjectTestCase(test.CdistTestCase): other_name = '__first/man' other_object = self.cdist_object.object_from_name(other_name) self.assertTrue(isinstance(other_object, core.CdistObject)) - self.assertEqual(other_object.type.name, '__first') + self.assertEqual(other_object.cdist_type.name, '__first') self.assertEqual(other_object.object_id, 'man') From 2fce038423813a0d07c294ac1d08e5731ec77367 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 10:43:42 +0100 Subject: [PATCH 1321/4212] correct catching exception to IllegalObjectIdError Signed-off-by: Nico Schottelius --- lib/cdist/test/emulator/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index c0037b68..f1ea5832 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -79,7 +79,7 @@ class EmulatorTestCase(test.CdistTestCase): os.environ.update(self.env) os.environ['require'] = '__file' emu = emulator.Emulator(argv) - self.assertRaises(emulator.IllegalRequirementError, emu.run) + self.assertRaises(core.IllegalObjectIdError, emu.run) def test_singleton_object_requirement(self): argv = ['__file', '/tmp/foobar'] From 2d6107002357af985d7695082e98caea99ae4a31 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 10:47:40 +0100 Subject: [PATCH 1322/4212] remove old IllegalRequirementError exception Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 5e95e31c..8daa61fb 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -26,15 +26,6 @@ import os import cdist from cdist import core - -class IllegalRequirementError(cdist.Error): - def __init__(self, requirement, message=None): - self.requirement = requirement - self.message = message or 'Illegal requirement' - - def __str__(self): - return '%s: %s' % (self.message, self.requirement) - class Emulator(object): def __init__(self, argv): self.argv = argv @@ -155,6 +146,7 @@ class Emulator(object): # Raises an error, if object cannot be created self.cdist_object.object_from_name(requirement) + self.log.debug("Recording requirement: " + requirement) self.cdist_object.requirements.append(requirement) From 95cbdeba277b04535f60068e725b07b43138c2c5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 11:30:11 +0100 Subject: [PATCH 1323/4212] document /, // behaviour of object id Signed-off-by: Nico Schottelius --- doc/changelog | 3 + doc/dev/todo/niconext | 2 - doc/man/cdist-reference.text.sh | 138 ++++++++++++++++---------------- 3 files changed, 74 insertions(+), 69 deletions(-) diff --git a/doc/changelog b/doc/changelog index dace28dd..899b4b21 100644 --- a/doc/changelog +++ b/doc/changelog @@ -9,7 +9,10 @@ Changelog * Bugfix __user: Correct shadow field in explorer (Matt Coddington) * Bugfix __link: Properly handle existing links (Steven Armstrong) * Bugfix __key_value: More robust implementation (Steven Armstrong) + * Bugfix __user: Fix for changing a user's group by name (Matt Coddington) * New Type: __package_pip + * Bugfix/Cleanup: Correctly allow Object ID to start and end with /, but + not contain //. 2.0.6: 2012-01-28 * Bugfix __apt_ppa: diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index dd20026c..6dafda9a 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,7 +1,5 @@ - cleanup object_id handling - have a look at singletons - - double check verification - - adjust tests - remove useless ERROR: monitoring02: Code that raised the error: diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 898771c7..bf8d250e 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -49,10 +49,10 @@ The following global explorers are available: eof ( - cd ../../conf/explorer - for explorer in *; do - echo "- $explorer" - done + cd ../../conf/explorer + for explorer in *; do + echo "- $explorer" + done ) cat << eof @@ -62,77 +62,77 @@ PATHS If not specified otherwise, all paths are relative to the checkout directory. conf/:: - Contains the (static) configuration like manifests, types and explorers. + Contains the (static) configuration like manifests, types and explorers. conf/manifest/init:: - This is the central entry point used by cdist-manifest-init(1). - It is an executable (+x bit set) shell script that can use - values from the explorers to decide which configuration to create - for the specified target host. - It should be primary used to define mapping from configurations to hosts. + This is the central entry point used by cdist-manifest-init(1). + It is an executable (+x bit set) shell script that can use + values from the explorers to decide which configuration to create + for the specified target host. + It should be primary used to define mapping from configurations to hosts. conf/manifest/*:: - All other files in this directory are not directly used by cdist, but you - can seperate configuration mappings, if you have a lot of code in the - manifest/init file. This may also be helpful to have different admins - maintain different groups of hosts. + All other files in this directory are not directly used by cdist, but you + can seperate configuration mappings, if you have a lot of code in the + manifest/init file. This may also be helpful to have different admins + maintain different groups of hosts. conf/explorer/:: - Contains explorers to be run on the target hosts, see cdist-explorer(7). + Contains explorers to be run on the target hosts, see cdist-explorer(7). conf/type/:: - Contains all available types, which are used to provide - some kind of functionality. See cdist-type(7). + Contains all available types, which are used to provide + some kind of functionality. See cdist-type(7). conf/type//:: - Home of the type . + Home of the type . - This directory is referenced by the variable __type (see below). + This directory is referenced by the variable __type (see below). conf/type//man.text:: - Manpage in Asciidoc format (required for inclusion into upstream) + Manpage in Asciidoc format (required for inclusion into upstream) conf/type//manifest:: - Used to generate additional objects from a type. + Used to generate additional objects from a type. conf/type//gencode-local:: - Used to generate code to be executed on the server. + Used to generate code to be executed on the server. conf/type//gencode-remote:: - Used to generate code to be executed on the client. + Used to generate code to be executed on the client. conf/type//parameters/required:: - Parameters required by type, \n seperated list. + Parameters required by type, \n seperated list. conf/type//parameters/optional:: - Parameters optionally accepted by type, \n seperated list. + Parameters optionally accepted by type, \n seperated list. conf/type//explorer:: - Location of the type specific explorers. - This directory is referenced by the variable __type_explorer (see below). - See cdist-explorer(7). + Location of the type specific explorers. + This directory is referenced by the variable __type_explorer (see below). + See cdist-explorer(7). out/:: - This directory contains output of cdist and is usually located - in a temporary directory and thus will be removed after the run. - This directory is referenced by the variable __global (see below). + This directory contains output of cdist and is usually located + in a temporary directory and thus will be removed after the run. + This directory is referenced by the variable __global (see below). out/explorer:: - Output of general explorers. + Output of general explorers. out/object:: - Objects created for the host. + Objects created for the host. out/object/:: - Contains all object specific information. - This directory is referenced by the variable __object (see below). + Contains all object specific information. + This directory is referenced by the variable __object (see below). out/object//explorers:: - Output of type specific explorers, per object. + Output of type specific explorers, per object. tmp_dir:: - A tempdir and a tempfile is used by cdist internally, - which will be removed when the scripts end automatically. + A tempdir and a tempfile is used by cdist internally, + which will be removed when the scripts end automatically. TYPES ----- @@ -141,13 +141,13 @@ The following types are available: eof for type in man7/cdist-type__*.text; do - no_dir="${type#man7/}"; - no_type="${no_dir#cdist-type}"; - name="${no_type%.text}"; - name_no_underline="$(echo $name | sed 's/^__/\\__/g')" - man="${no_dir%.text}(7)" + no_dir="${type#man7/}"; + no_type="${no_dir#cdist-type}"; + name="${no_type%.text}"; + name_no_underline="$(echo $name | sed 's/^__/\\__/g')" + man="${no_dir%.text}(7)" - echo "- $name_no_underline" "($man)" + echo "- $name_no_underline" "($man)" done cat << eof @@ -159,43 +159,47 @@ For object to object communication and tests, the following paths are usable within a object directory: changed:: - This empty file exists in an object directory, if the object has - code to be excuted (either remote or local) + This empty file exists in an object directory, if the object has + code to be excuted (either remote or local) ENVIRONMENT VARIABLES --------------------- __explorer:: - Directory that contains all global explorers. - Available for: explorer + Directory that contains all global explorers. + Available for: explorer __manifest:: - Directory that contains the initial manifest. - Available for: initial manifest + Directory that contains the initial manifest. + Available for: initial manifest __global:: - Directory that contains generic output like explorer. - Available for: initial manifest, type manifest, type gencode + Directory that contains generic output like explorer. + Available for: initial manifest, type manifest, type gencode __object:: - Directory that contains the current object. - Available for: type manifest, type explorer, type gencode + Directory that contains the current object. + Available for: type manifest, type explorer, type gencode __object_id:: - The type unique object id. - Available for: type manifest, type explorer, type gencode - Note: The leading "/" will always be stripped. + The type unique object id. + Available for: type manifest, type explorer, type gencode + + Note: The leading and the trailing "/" will always be stripped (caused by + the filesystem database and ensured by the core). + + Note: Double slashes ("//") will not be fixed and result in an error. __self:: - DEPRECATED: Same as __object_name, do not use anymore, use __object_name instead. - Will be removed in cdist 3.x. + DEPRECATED: Same as __object_name, do not use anymore, use __object_name instead. + Will be removed in cdist 3.x. __object_name:: - The full qualified name of the current object. - Available for: type manifest, type explorer, type gencode + The full qualified name of the current object. + Available for: type manifest, type explorer, type gencode __target_host:: - The host we are deploying to. - Available for: initial manifest, type manifest, type gencode + The host we are deploying to. + Available for: initial manifest, type manifest, type gencode __type:: - Path to the current type. - Available for: type manifest, type gencode + Path to the current type. + Available for: type manifest, type gencode __type_explorer:: - Directory that contains the type explorers. - Available for: type explorer + Directory that contains the type explorers. + Available for: type explorer SEE ALSO From e3ab8ef77ba80301e08ac65d16bc668e22ed2e7c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 14:25:11 +0100 Subject: [PATCH 1324/4212] version increment Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 664b6456..800bdaa2 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -19,7 +19,7 @@ # # -VERSION = "2.0.6" +VERSION = "2.0.7" BANNER = """ .. . .x+=:. s From c8ec4c200aa9b369f9fd3926b18f641598a3cd59 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 14:28:30 +0100 Subject: [PATCH 1325/4212] repair manpage for __package_pip Signed-off-by: Nico Schottelius --- conf/type/__package_pip/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__package_pip/man.text b/conf/type/__package_pip/man.text index 1822ffca..5ce45c50 100644 --- a/conf/type/__package_pip/man.text +++ b/conf/type/__package_pip/man.text @@ -1,5 +1,5 @@ cdist-type__package_pip(7) -============================= +========================== Nico Schottelius From f9ab756ee5c6528de17e0c54bc1ddab6b7b03eec Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 14:29:04 +0100 Subject: [PATCH 1326/4212] cleanup todo Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 6dafda9a..f81c7570 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,16 +1,16 @@ +2.0.8 features / cleanups: + - cleanup object_id handling - have a look at singletons - remove useless ERROR: monitoring02: Code that raised the error: --------------------------------------------------------------------------------- - -- __user - add option to include --create-home - ensure that all types, which support --state support present and absent (consistent look and feel) +-------------------------------------------------------------------------------- + - update/create docs - cdist-cache:: How to get use information about the hosts we have been working on [advanced] From 84b6df2e815d8c69d5c004883b62995c354cd24e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 14:29:44 +0100 Subject: [PATCH 1327/4212] ++todo for anyone Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 95bda7fb..b40936f6 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -35,3 +35,5 @@ USER INTERFACE TYPES ------ - Add testing framework (proposed by Evax Software) +- __user + add option to include --create-home From 632146114ca07254b0119510758316ffc68ffc37 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 14:30:27 +0100 Subject: [PATCH 1328/4212] update copyright Signed-off-by: Nico Schottelius --- lib/cdist/core/cdist_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/core/cdist_object.py b/lib/cdist/core/cdist_object.py index 3c2de01b..9937c823 100644 --- a/lib/cdist/core/cdist_object.py +++ b/lib/cdist/core/cdist_object.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-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # From 06cf5ec3c94435e1cc82cd349302cb09d2200135 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 14:37:10 +0100 Subject: [PATCH 1329/4212] check release before releasing... Signed-off-by: Nico Schottelius --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index ea4ca83c..7da51ded 100755 --- a/build +++ b/build @@ -85,7 +85,7 @@ case "$1" in ;; release) - "$0" clean && "$0" man && "$0" web + ./doc/dev/releasechecklist && "$0" clean && "$0" man && "$0" web ;; speeches) From f8de3afb5f3712eda304b5592682a51a5c1c1645 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 14:37:30 +0100 Subject: [PATCH 1330/4212] +releasedate Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 899b4b21..00823886 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.0.7: +2.0.7: 2012-02-13 * Bugfix __file: Use chmod after chown/chgrp (Matt Coddington) * Bugfix __user: Correct shadow field in explorer (Matt Coddington) * Bugfix __link: Properly handle existing links (Steven Armstrong) From 762b8e0a3ad9d414281f8b7443254c98a878767e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 14:48:22 +0100 Subject: [PATCH 1331/4212] also check date on release Signed-off-by: Nico Schottelius --- doc/dev/releasechecklist | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index 19ab7b18..3473ae0f 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -15,11 +15,21 @@ changelog_version=$(grep '^[[:digit:]]' doc/changelog | head -n1 | sed 's/:.*//' #git_version=$(git describe) lib_version=$(grep ^VERSION lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g') +# get date +date_today="$(date +%Y-%m-%d)" +date_changelogn=$(grep '^[[:digit:]]' doc/changelog | head -n1 | sed 's/.*: //') + echo "Ensure you fixed/prepared version files: $files" echo "changelog: $changelog_version" #echo "git: $git_version" echo "lib: $lib_version" +if [ "$date_today" != "$date_changelog" ]; then + echo "Messed up date, not releasing:" + echo "Changelog: $date_changelog" + exit 1 +fi + if [ "$lib_version" != "$changelog_version" ]; then echo "Messed up versions, not releasing" exit 1 From 992584582853f41b1491f80a31384fc19555f55b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 14:49:36 +0100 Subject: [PATCH 1332/4212] only need release script for release Signed-off-by: Nico Schottelius --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index 7da51ded..6b415391 100755 --- a/build +++ b/build @@ -85,7 +85,7 @@ case "$1" in ;; release) - ./doc/dev/releasechecklist && "$0" clean && "$0" man && "$0" web + ./doc/dev/releasechecklist ;; speeches) From edd93aa1f899ca05dd9bf7487bbbf3b67336115a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 14:55:41 +0100 Subject: [PATCH 1333/4212] -typo Signed-off-by: Nico Schottelius --- doc/dev/releasechecklist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index 3473ae0f..eba81dc0 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -17,7 +17,7 @@ lib_version=$(grep ^VERSION lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g # get date date_today="$(date +%Y-%m-%d)" -date_changelogn=$(grep '^[[:digit:]]' doc/changelog | head -n1 | sed 's/.*: //') +date_changelog=$(grep '^[[:digit:]]' doc/changelog | head -n1 | sed 's/.*: //') echo "Ensure you fixed/prepared version files: $files" echo "changelog: $changelog_version" From f8868349e6f1fa7694a5aef3220990ec6b8039f6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 15:01:45 +0100 Subject: [PATCH 1334/4212] cdist_object.type => cdist_object.cdist_type Signed-off-by: Nico Schottelius --- lib/cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index f27fff77..7cce240e 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -112,7 +112,7 @@ class ConfigInstall(object): # TODO: remove once we are sure that this really never happens. raise cdist.Error("Attempting to run an already finished object: %s", cdist_object) - cdist_type = cdist_object.type + cdist_type = cdist_object.cdist_type # Generate self.log.info("Generating and executing code for " + cdist_object.name) From ba0130594cb51d826f311116dc73caacf2ca518e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 15:20:33 +0100 Subject: [PATCH 1335/4212] remove latest before linking to prevent symlink below latest/ Signed-off-by: Nico Schottelius --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index 6b415391..b994ce00 100755 --- a/build +++ b/build @@ -123,7 +123,7 @@ case "$1" in # 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 && - ln -sf "$version" latest" + rm -f latest && ln -sf "$version" latest" ;; p|pu|pub) From 08612764362c629b9b144db64277abbe7f200b9c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 16:14:48 +0100 Subject: [PATCH 1336/4212] remove obsolete MissingEnvironmentVariableError() Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 10 ---------- lib/cdist/emulator.py | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 800bdaa2..973b61f8 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -44,16 +44,6 @@ class Error(Exception): """Base exception class for this project""" pass - -class MissingEnvironmentVariableError(Error): - """Raised when a required environment variable is not set.""" - - def __init__(self, name): - self.name = name - - def __str__(self): - return 'Missing required environment variable: ' + str(self.name) - def file_to_list(filename): """Return list from \n seperated file""" if os.path.isfile(filename): diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 8daa61fb..687aee93 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # From d51a177a9545f9d534c24c25239144a6f8bd4b3d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 16:22:14 +0100 Subject: [PATCH 1337/4212] invent a generic CdistObjectError and point to definition source (easier debugging) Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 12 ++++++++++++ lib/cdist/resolver.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 973b61f8..4742a937 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -44,6 +44,18 @@ class Error(Exception): """Base exception class for this project""" pass +class CdistObjectError(Error): + """Something went wrong with an object""" + + def __init__(self, cdist_object, message): + self.name = cdist_object.name + self.source = " ".join(cdist_object.source) + self.message = message + + + def __str__(self): + return '%s: %s (defined at %s)' % (self.name, self.message, self.source) + def file_to_list(filename): """Return list from \n seperated file""" if os.path.isfile(filename): diff --git a/lib/cdist/resolver.py b/lib/cdist/resolver.py index 24a5e496..368c9eb8 100644 --- a/lib/cdist/resolver.py +++ b/lib/cdist/resolver.py @@ -125,7 +125,7 @@ class DependencyResolver(object): resolved.append(cdist_object) unresolved.remove(cdist_object) except RequirementNotFoundError as e: - raise cdist.Error(cdist_object.name + " requires non-existing " + e.requirement) + raise cdist.CdistObjectError(cdist_object, "requires non-existing " + e.requirement) def __iter__(self): """Iterate over all unique objects while resolving dependencies. From 8f1735fab2b69e4b5c21cacb97230626e08d0cde Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 16:22:46 +0100 Subject: [PATCH 1338/4212] ++changes(2.0.8) Signed-off-by: Nico Schottelius --- doc/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/changelog b/doc/changelog index 00823886..c241624a 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.0.8: + * Cleanup: Better hint to source of error + 2.0.7: 2012-02-13 * Bugfix __file: Use chmod after chown/chgrp (Matt Coddington) * Bugfix __user: Correct shadow field in explorer (Matt Coddington) From c9ae06db6428855a3d9d849efd1019346b203c06 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 13 Feb 2012 16:27:41 +0100 Subject: [PATCH 1339/4212] do not setup __debug - let the user do if required - do not interfere type with core Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ lib/cdist/core/code.py | 3 --- lib/cdist/core/explorer.py | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/doc/changelog b/doc/changelog index c241624a..2d2d7a48 100644 --- a/doc/changelog +++ b/doc/changelog @@ -6,6 +6,8 @@ Changelog 2.0.8: * Cleanup: Better hint to source of error + * Cleanup: Remove support for __debug variable in manifests (Type != Core + debugging) 2.0.7: 2012-02-13 * Bugfix __file: Use chmod after chown/chgrp (Matt Coddington) diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index 7e69f21c..2ffef9cf 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -92,9 +92,6 @@ class Code(object): '__global': self.local.out_path, } - if log.getEffectiveLevel() == logging.DEBUG: - self.env.update({'__debug': "yes" }) - def _run_gencode(self, cdist_object, which): cdist_type = cdist_object.cdist_type script = os.path.join(self.local.type_path, getattr(cdist_type, 'gencode_%s_path' % which)) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index bbd2108c..d49b7ac4 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -73,8 +73,6 @@ class Explorer(object): '__target_host': self.target_host, '__explorer': self.remote.global_explorer_path, } - if self.log.getEffectiveLevel() == logging.DEBUG: - self.env.update({'__debug': "yes" }) self._type_explorers_transferred = [] ### global From 861b13ffe48ae5ed5867ec9efd9f0fa92145fc71 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Feb 2012 11:12:17 +0100 Subject: [PATCH 1340/4212] record sanitised object, not the user supplied one, as requirement Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 687aee93..0979182a 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -145,10 +145,14 @@ class Emulator(object): if len(requirement) == 0: continue # Raises an error, if object cannot be created - self.cdist_object.object_from_name(requirement) + cdist_object = self.cdist_object.object_from_name(requirement) self.log.debug("Recording requirement: " + requirement) - self.cdist_object.requirements.append(requirement) + + # Save the sanitised version, not the user supplied one + # (__file//bar => __file/bar) + # This ensures pattern matching is done against sanitised list + self.cdist_object.requirements.append(cdist_object.name) def record_auto_requirements(self): """An object shall automatically depend on all objects that it defined in it's type manifest. From df54ab328435781f0e098c60894f95382c8e3cc4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Feb 2012 11:15:02 +0100 Subject: [PATCH 1341/4212] mark same algorithmus for deps in logs Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-02-13.dependencies | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 doc/dev/logs/2012-02-13.dependencies diff --git a/doc/dev/logs/2012-02-13.dependencies b/doc/dev/logs/2012-02-13.dependencies new file mode 100644 index 00000000..3b0f3f21 --- /dev/null +++ b/doc/dev/logs/2012-02-13.dependencies @@ -0,0 +1,23 @@ +possible dependencies: + + - unix pattern __foo/* + - object: __foo//bar, __foo/bar + - singleton with object_id: __foo/singleton + - singleton without object_id: __foo/ + +solving dependencies: + + solve_dep(object, run_list): + - list = [me] + - if status == IN_DEPENDENCY: + fail: circular dependency + - status = IN_DEPENDENCY + - create_list_of_deps(object) + - try pattern expansion + - for each dependency: + if object does not exist: + fail + else: + list.append(solve_dep(object, run_list)): + - status == IN_LIST + - return [me, dependencies [, dependencies of dependencies]] From 0082b7f07cd821b80f24fb8d23524706bba531d9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Feb 2012 12:41:13 +0100 Subject: [PATCH 1342/4212] allow objects to start with /, but not to contain //; sanitise after validation Signed-off-by: Nico Schottelius --- lib/cdist/core/cdist_object.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/cdist/core/cdist_object.py b/lib/cdist/core/cdist_object.py index 9937c823..e12bcfbd 100644 --- a/lib/cdist/core/cdist_object.py +++ b/lib/cdist/core/cdist_object.py @@ -102,8 +102,6 @@ class CdistObject(object): """Validate the given object_id and raise IllegalObjectIdError if it's not valid. """ if self.object_id: - if self.object_id.startswith('/'): - raise IllegalObjectIdError(self.object_id, 'object_id may not start with /') if OBJECT_MARKER in self.object_id.split(os.sep): raise IllegalObjectIdError(self.object_id, 'object_id may not contain \'%s\'' % OBJECT_MARKER) if '//' in self.object_id: @@ -119,8 +117,8 @@ class CdistObject(object): self.base_path = base_path self.object_id = object_id - self.sanitise_object_id() self.validate_object_id() + self.sanitise_object_id() self.name = self.join_name(self.cdist_type.name, self.object_id) self.path = os.path.join(self.cdist_type.path, self.object_id, OBJECT_MARKER) From 365c629db9578790725e8dd981894f62abc1b97e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Feb 2012 13:55:50 +0100 Subject: [PATCH 1343/4212] update variable availbility list in reference Signed-off-by: Nico Schottelius --- doc/man/cdist-reference.text.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index bf8d250e..81e58ab2 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -167,7 +167,7 @@ ENVIRONMENT VARIABLES --------------------- __explorer:: Directory that contains all global explorers. - Available for: explorer + Available for: explorer, type explorer __manifest:: Directory that contains the initial manifest. Available for: initial manifest @@ -193,7 +193,7 @@ __object_name:: Available for: type manifest, type explorer, type gencode __target_host:: The host we are deploying to. - Available for: initial manifest, type manifest, type gencode + Available for: explorer, initial manifest, type explorer, type manifest, type gencode __type:: Path to the current type. Available for: type manifest, type gencode From 2b0c2737151b52d38aa449b9cefc42fa19957cbb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Feb 2012 18:04:00 +0100 Subject: [PATCH 1344/4212] state_should is being populated in manifest, if not given Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/gencode-remote | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index 09c4912d..6618b9b0 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -19,12 +19,7 @@ # # -if [ -f "$__object/parameter/state" ]; then - state_should="$(cat "$__object/parameter/state")" -else - state_should="present" -fi - +state_should="$(cat "$__object/parameter/state")" state_is=$(cat "$__object/explorer/state") # Nothing todo, go away From 2f16b08bb0247e7ba5454f43b2dea6bf33691636 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Feb 2012 20:31:02 +0100 Subject: [PATCH 1345/4212] also copy over the .css for manpages Signed-off-by: Nico Schottelius --- build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build b/build index b994ce00..2d98e862 100755 --- a/build +++ b/build @@ -113,8 +113,8 @@ case "$1" in # cp ${SPEECHESDIR}/*.pdf ${WEBDIR}/${WEBBASE}/speeches # git describe > ${WEBDIR}/${WEBBASE}/man/VERSION - cp ${MAN1DSTDIR}/*.html ${WEBMAN}/man1 - cp ${MAN7DSTDIR}/*.html ${WEBMAN}/man7 + cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${WEBMAN}/man1 + cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${WEBMAN}/man7 cd ${WEBDIR} && git add ${WEBBASE} cd ${WEBDIR} && git commit -m "cdist update" ${WEBBASE} ${WEBPAGE} From 5d47eb849f5f8f78a8a63932316e14da894323f9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Feb 2012 20:31:16 +0100 Subject: [PATCH 1346/4212] some stuff to be fixed Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/gencode-remote | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index 6618b9b0..3db7293f 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -35,13 +35,13 @@ case "$state_should" in echo sed -i /etc/rc.conf \'s/^\\(DAEMONS=.*\\))/\\1 $name)/\' ;; debian|ubuntu) - # This does not work as expected: + # FIXME: This does not work as expected: # insserv: warning: current start runlevel(s) (3 4 5) of script `postfix' overwrites defaults (2 3 4 5). #echo update-rc.d \"$name\" defaults echo update-rc.d \"$name\" defaults ;; -# Disabled until the explorer is checked +# FIXME: Disabled until the explorer is checked # gentoo) # echo rc-update add \"$name\" default # ;; @@ -60,13 +60,14 @@ case "$state_should" in absent) case "$os" in archlinux) - echo sed -i /etc/rc.conf -e \"s/ $name / /g\" -e \"s/($name/(/\" -e \"s/ $name)/)/\" + # Replace a) at the beginning b) in the middle c) end d) only + echo "sed -i /etc/rc.conf -e 's/^\(DAEMONS=(\)$name /\1/' -e 's/^\(DAEMONS=(.* \)$name \(.*\)/\1\2/' -e 's/^\(DAEMONS=(.*\) $name)/\1)/' -e 's/^\(DAEMONS=(\)$name)/\1)/'" ;; debian|ubuntu) echo update-rc.d -f \"$name\" remove ;; -# Disabled until the explorer is checked +# FIXME: Disabled until the explorer is checked # gentoo) # echo rc-update del \"$name\" # ;; From d427af2ee33875f271c413ecde5421640448ae72 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Feb 2012 08:50:03 +0100 Subject: [PATCH 1347/4212] add hint on incomplete type Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/man.text | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conf/type/__start_on_boot/man.text b/conf/type/__start_on_boot/man.text index e9691401..0e75c9ab 100644 --- a/conf/type/__start_on_boot/man.text +++ b/conf/type/__start_on_boot/man.text @@ -13,6 +13,9 @@ DESCRIPTION This cdist type allows you to enable or disable stuff to be started at boot of your operating system. +Warning: This type has not been tested intensively and is not fully +supported (i.e. gentoo and *bsd are not implemented). + REQUIRED PARAMETERS ------------------- From 824ec459ea3ce1dbc2c2751071a42eb235eae66e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Feb 2012 08:50:26 +0100 Subject: [PATCH 1348/4212] cleanups in gencode Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/gencode-remote | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index 3db7293f..f1788d4b 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -32,13 +32,10 @@ case "$state_should" in present) case "$os" in archlinux) - echo sed -i /etc/rc.conf \'s/^\\(DAEMONS=.*\\))/\\1 $name)/\' + echo "sed -i /etc/rc.conf \'s/^\\(DAEMONS=.*\\))/\\1 $name)/\'" ;; debian|ubuntu) - # FIXME: This does not work as expected: - # insserv: warning: current start runlevel(s) (3 4 5) of script `postfix' overwrites defaults (2 3 4 5). - #echo update-rc.d \"$name\" defaults - echo update-rc.d \"$name\" defaults + echo "update-rc.d \"$name\" defaults >/dev/null" ;; # FIXME: Disabled until the explorer is checked @@ -61,7 +58,7 @@ case "$state_should" in case "$os" in archlinux) # Replace a) at the beginning b) in the middle c) end d) only - echo "sed -i /etc/rc.conf -e 's/^\(DAEMONS=(\)$name /\1/' -e 's/^\(DAEMONS=(.* \)$name \(.*\)/\1\2/' -e 's/^\(DAEMONS=(.*\) $name)/\1)/' -e 's/^\(DAEMONS=(\)$name)/\1)/'" + echo "sed -i /etc/rc.conf -e 's/^\\(DAEMONS=(\\)$name /\\1/' -e 's/^\\(DAEMONS=(.* \\)$name \\(.*\\)/\\1\\2/' -e 's/^\\(DAEMONS=(.*\\) $name)/\\1)/' -e 's/^\\(DAEMONS=(\\)$name)/\\1)/'" ;; debian|ubuntu) echo update-rc.d -f \"$name\" remove From be670597253d1e713ba79416b2392f51108e4ae7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Feb 2012 09:27:11 +0100 Subject: [PATCH 1349/4212] print name, not object (user does not need to see python way of things) Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 0979182a..6d6050e8 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -125,7 +125,7 @@ class Emulator(object): if self.cdist_object.exists: 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, " ".join(self.cdist_object.source), self.cdist_object.parameters, self.object_source, self.parameters) + % (self.cdist_object.name, " ".join(self.cdist_object.source), self.cdist_object.parameters, self.object_source, self.parameters) ) else: self.cdist_object.create() From 46e6ea4308dd95462e74e3292a5754c4e21cdcc0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Feb 2012 09:27:11 +0100 Subject: [PATCH 1350/4212] print name, not object (user does not need to see python way of things) Signed-off-by: Nico Schottelius --- lib/cdist/emulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 0979182a..6d6050e8 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -125,7 +125,7 @@ class Emulator(object): if self.cdist_object.exists: 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, " ".join(self.cdist_object.source), self.cdist_object.parameters, self.object_source, self.parameters) + % (self.cdist_object.name, " ".join(self.cdist_object.source), self.cdist_object.parameters, self.object_source, self.parameters) ) else: self.cdist_object.create() From 67abdb339978f231ce64cf0940ee9e85ba9f59c8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Feb 2012 12:46:36 +0100 Subject: [PATCH 1351/4212] +lunchlogfile Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-02-15.steven | 120 +++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 doc/dev/logs/2012-02-15.steven diff --git a/doc/dev/logs/2012-02-15.steven b/doc/dev/logs/2012-02-15.steven new file mode 100644 index 00000000..96bccb9f --- /dev/null +++ b/doc/dev/logs/2012-02-15.steven @@ -0,0 +1,120 @@ +- parameter/setting default from manifest + - current bug + - proposal 1: parameter/default/$name (for optional ones) + - new way + - catches --state absent|present + - needs changes of types + - also possible for explorer + - support for it in core? + - handling of ${o} $o "$o" ? + - handling which variables? + - introduction of "templating language" + - aka macros + - possible problems: + - inconsistency + - redoing shell functionality + - raising expectations for more templating from users + - possible benefit + - no need for eval + - once in core, not everytime in type + - OTOH: one extra word. + - a=$(cat $__object/parameter/name) vs. $(eval $(cat $__object/parameter/name)) + - only possible for static defaults + - --name overrides name not possible vs. object_id + - Is this the only case???? + - if yes: don't care. + - possible solution: + - echo '/$__object_id' > typename/parameter/default/name + - eval $(cat $__object/parameter/name) + - probably allows code injection + - is possible anyway??? + - $(cat /etc/shadow) + - other eval side effects??? + - none: go for it + - some: have headache + - many: don't do + - proposal 2: 2 dbs (user input vs. stuff changable by type) + - explicit 2nd db [parameter_user and parameter/] + - not very clean (both agreed) + - proposal 3: parameter are read-only + - breaks current types (in core probably elsewhere) + - can't enforce, but user is on his own => breaks, her problem + + clean seperation between core and type (nico) + - parameter belongs to type not core (steven) + - proposal 4: core ignores changes in parameter/* of object + - implicit 2nd db [see automagic below] + - steven+++ + - does not work with divergent emulator not being in core + - because emulators primary db __is__ fs. + +1 manifest: + +__foo bar == emulator +echo present > $__global/object/__foo/bar/parameter/state + +# fails +__foo bar == emulator + +! automagic / filesystem + ! fsproperty: + - kill, write explicitly to disk + + - implicit/automatic writes/read to fs + - explicit interfaces are better then implicit + - same problems as in cdist 1.x to 2.x move! (environment!) + - format on disk should not change/dictate code flow + - degrade python to shell (nico++! steven--) + - user should not care about python, ruby, .net or ASM implementation (steven++ nico++) + + ? proposal 1: diverge emulator / core + - emulator verifies input + - emulator writes to fs + - core reads/syncs from/to fs before passing control to user + + ? proposal 2: emulator is dumb and passes data to core + - core creates objects + - no fs involved + - core reads/syncs from/to fs before passing control to user + - passing: + - full objects via pickle + - parameters only + - how??? + - unix socket? + - not everywhere possible? + - tcp / ip + - not everywhere possible + - chroot / local only + - rfc 1149 + - not everywhere possible + - missing avian carriers + - 0mq + - not everywhere possible + - not installed + - shm (ipcs and friends) + - not everywhere possible + - no /dev/shm, different libraries? cleanups needed... + - what speaks against FS? + - emulator_input/.../ + + - nico: to fancy probably + +! boolean implementation + - nico: + - parameters/boolean: document + - argparse changes (consider parameters/boolean) + - create + - can be implemented with changes in emulator + - use store_true, del if false => never seen by core + - INDEPENDENT INDEPENDT OF FS.PROPERTIES!!111111! + +- emulator: + - how much integrated into core + - also: using CdistObject???? + - dependency on filesystem: good (nico) | bad (steven) + +- singleton / support without object_id + + +- logging divergent between emulator / core + - no problem (nico) + - may be helpful (steven) From 6ec57acce6fbd52211c95cbb9f4124f8288d741f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Feb 2012 13:08:29 +0100 Subject: [PATCH 1352/4212] ++logchanges Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-02-15.steven | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/dev/logs/2012-02-15.steven b/doc/dev/logs/2012-02-15.steven index 96bccb9f..2d513728 100644 --- a/doc/dev/logs/2012-02-15.steven +++ b/doc/dev/logs/2012-02-15.steven @@ -1,4 +1,7 @@ - parameter/setting default from manifest + ==> BRANCH[feature_default_parameters], + ==> PERSON[Steven or Nico] + ==> PROPOSAL(1) - current bug - proposal 1: parameter/default/$name (for optional ones) - new way @@ -58,6 +61,9 @@ __foo bar == emulator ! automagic / filesystem ! fsproperty: - kill, write explicitly to disk + ==> BRANCH[cleanup_fsproperty] + ==> PERSON[Steven] + ==> PROPOSAL(just cleanup) - implicit/automatic writes/read to fs - explicit interfaces are better then implicit @@ -99,6 +105,8 @@ __foo bar == emulator - nico: to fancy probably ! boolean implementation + ==> BRANCH[feature_boolean_parameter] + ==> PERSON[Steven] - nico: - parameters/boolean: document - argparse changes (consider parameters/boolean) @@ -113,7 +121,11 @@ __foo bar == emulator - dependency on filesystem: good (nico) | bad (steven) - singleton / support without object_id + - not discussed +- __apt_ppa: + ==> BRANCH[bugfix_do_not_change_state_in_manifest] + ==> PERSON[Nico] - logging divergent between emulator / core - no problem (nico) From ddb5bd16c923c5aabe465115ca1cb0819dde2cc3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Feb 2012 13:36:05 +0100 Subject: [PATCH 1353/4212] also support @daemon syntax from rc.conf Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/gencode-remote | 3 ++- doc/dev/todo/niconext | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index f1788d4b..be2bd98b 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -58,7 +58,8 @@ case "$state_should" in case "$os" in archlinux) # Replace a) at the beginning b) in the middle c) end d) only - echo "sed -i /etc/rc.conf -e 's/^\\(DAEMONS=(\\)$name /\\1/' -e 's/^\\(DAEMONS=(.* \\)$name \\(.*\\)/\\1\\2/' -e 's/^\\(DAEMONS=(.*\\) $name)/\\1)/' -e 's/^\\(DAEMONS=(\\)$name)/\\1)/'" + # Support @name as well...makes it more ugly, but well... + echo "sed -i /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)/'" ;; debian|ubuntu) echo update-rc.d -f \"$name\" remove diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index f81c7570..828ff917 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,4 +1,4 @@ -2.0.8 features / cleanups: +- introduce default parameters - cleanup object_id handling - have a look at singletons From 362bdcdbdddcc013e66d79877c38549f5dc1b8de Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 15 Feb 2012 13:57:45 +0100 Subject: [PATCH 1354/4212] implement boolean parameters Signed-off-by: Steven Armstrong --- .../fixtures/conf/type/__arguments_boolean/parameter/boolean | 2 ++ .../fixtures/conf/type/__arguments_optional/parameter/optional | 1 + .../fixtures/conf/type/__arguments_required/parameter/required | 2 ++ .../type/fixtures/__with_boolean_parameters/parameter/boolean | 2 ++ lib/cdist/test/type/fixtures/__without_boolean_parameters/.keep | 0 5 files changed, 7 insertions(+) create mode 100644 lib/cdist/test/emulator/fixtures/conf/type/__arguments_boolean/parameter/boolean create mode 100644 lib/cdist/test/emulator/fixtures/conf/type/__arguments_optional/parameter/optional create mode 100644 lib/cdist/test/emulator/fixtures/conf/type/__arguments_required/parameter/required create mode 100644 lib/cdist/test/type/fixtures/__with_boolean_parameters/parameter/boolean create mode 100644 lib/cdist/test/type/fixtures/__without_boolean_parameters/.keep diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__arguments_boolean/parameter/boolean b/lib/cdist/test/emulator/fixtures/conf/type/__arguments_boolean/parameter/boolean new file mode 100644 index 00000000..3215c409 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__arguments_boolean/parameter/boolean @@ -0,0 +1,2 @@ +boolean1 +boolean2 diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__arguments_optional/parameter/optional b/lib/cdist/test/emulator/fixtures/conf/type/__arguments_optional/parameter/optional new file mode 100644 index 00000000..31647628 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__arguments_optional/parameter/optional @@ -0,0 +1 @@ +optional1 diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__arguments_required/parameter/required b/lib/cdist/test/emulator/fixtures/conf/type/__arguments_required/parameter/required new file mode 100644 index 00000000..e0fba2c9 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__arguments_required/parameter/required @@ -0,0 +1,2 @@ +required1 +required2 diff --git a/lib/cdist/test/type/fixtures/__with_boolean_parameters/parameter/boolean b/lib/cdist/test/type/fixtures/__with_boolean_parameters/parameter/boolean new file mode 100644 index 00000000..3215c409 --- /dev/null +++ b/lib/cdist/test/type/fixtures/__with_boolean_parameters/parameter/boolean @@ -0,0 +1,2 @@ +boolean1 +boolean2 diff --git a/lib/cdist/test/type/fixtures/__without_boolean_parameters/.keep b/lib/cdist/test/type/fixtures/__without_boolean_parameters/.keep new file mode 100644 index 00000000..e69de29b From 0760ff3c94edefc815697caae1807ae7894771c0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 15 Feb 2012 14:44:16 +0100 Subject: [PATCH 1355/4212] implement boolean parameters, forgotten files ;-) Signed-off-by: Steven Armstrong --- lib/cdist/core/cdist_type.py | 17 +++++++++ lib/cdist/emulator.py | 5 ++- lib/cdist/test/emulator/__init__.py | 58 ++++++++++++++++++++++++++++- lib/cdist/test/type/__init__.py | 11 ++++++ 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/lib/cdist/core/cdist_type.py b/lib/cdist/core/cdist_type.py index 55609e7e..1d2472c4 100644 --- a/lib/cdist/core/cdist_type.py +++ b/lib/cdist/core/cdist_type.py @@ -82,6 +82,7 @@ class CdistType(object): self.__explorers = None self.__required_parameters = None self.__optional_parameters = None + self.__boolean_parameters = None def __repr__(self): return '' % self.name @@ -144,3 +145,19 @@ class CdistType(object): finally: self.__optional_parameters = parameters return self.__optional_parameters + + @property + def boolean_parameters(self): + """Return a list of boolean parameters""" + if not self.__boolean_parameters: + parameters = [] + try: + with open(os.path.join(self.absolute_path, "parameter", "boolean")) as fd: + for line in fd: + parameters.append(line.strip()) + except EnvironmentError: + # error ignored + pass + finally: + self.__boolean_parameters = parameters + return self.__boolean_parameters diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 6d6050e8..c4b84feb 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -87,7 +87,7 @@ class Emulator(object): def commandline(self): """Parse command line""" - parser = argparse.ArgumentParser(add_help=False) + parser = argparse.ArgumentParser(add_help=False, argument_default=argparse.SUPPRESS) for parameter in self.cdist_type.optional_parameters: argument = "--" + parameter @@ -95,6 +95,9 @@ class Emulator(object): for parameter in self.cdist_type.required_parameters: argument = "--" + parameter parser.add_argument(argument, dest=parameter, action='store', required=True) + for parameter in self.cdist_type.boolean_parameters: + argument = "--" + parameter + parser.add_argument(argument, dest=parameter, action='store_const', const='') # If not singleton support one positional parameter if not self.cdist_type.is_singleton: diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index f1ea5832..370d3d82 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -126,7 +126,7 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): self.assertEqual(sorted(cdist_object.requirements), sorted(expected)) -class ArgumentsWithDashesTestCase(test.CdistTestCase): +class ArgumentsTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() @@ -159,3 +159,59 @@ class ArgumentsWithDashesTestCase(test.CdistTestCase): cdist_type = core.CdistType(self.local.type_path, '__arguments_with_dashes') cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'some-id') self.assertTrue('with-dash' in cdist_object.parameters) + + def test_boolean(self): + type_name = '__arguments_boolean' + object_id = 'some-id' + argv = [type_name, object_id, '--boolean1'] + 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('boolean1' in cdist_object.parameters) + self.assertFalse('boolean2' in cdist_object.parameters) + # empty file -> True + self.assertTrue(cdist_object.parameters['boolean1'] == '') + + def test_required(self): + type_name = '__arguments_required' + object_id = 'some-id' + value = 'some value' + argv = [type_name, object_id, '--required1', value, '--required2', value] + os.environ.update(self.env) + emu = emulator.Emulator(argv) + emu.run() + + cdist_type = core.CdistType(self.local.type_path, type_name) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, object_id) + self.assertTrue('required1' in cdist_object.parameters) + self.assertTrue('required2' in cdist_object.parameters) + self.assertEqual(cdist_object.parameters['required1'], value) + self.assertEqual(cdist_object.parameters['required2'], value) + +# def test_required_missing(self): +# type_name = '__arguments_required' +# object_id = 'some-id' +# value = 'some value' +# argv = [type_name, object_id, '--required1', value] +# os.environ.update(self.env) +# emu = emulator.Emulator(argv) +# +# self.assertRaises(SystemExit, emu.run) + + def test_optional(self): + type_name = '__arguments_optional' + object_id = 'some-id' + value = 'some value' + argv = [type_name, object_id, '--optional1', value] + os.environ.update(self.env) + emu = emulator.Emulator(argv) + emu.run() + + cdist_type = core.CdistType(self.local.type_path, type_name) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, object_id) + self.assertTrue('optional1' in cdist_object.parameters) + self.assertFalse('optional2' in cdist_object.parameters) + self.assertEqual(cdist_object.parameters['optional1'], value) diff --git a/lib/cdist/test/type/__init__.py b/lib/cdist/test/type/__init__.py index 2ef14a4c..5e774aa9 100644 --- a/lib/cdist/test/type/__init__.py +++ b/lib/cdist/test/type/__init__.py @@ -145,3 +145,14 @@ class TypeTestCase(test.CdistTestCase): base_path = fixtures cdist_type = core.CdistType(base_path, '__without_optional_parameters') self.assertEqual(cdist_type.optional_parameters, []) + + def test_with_boolean_parameters(self): + base_path = fixtures + cdist_type = core.CdistType(base_path, '__with_boolean_parameters') + self.assertEqual(cdist_type.boolean_parameters, ['boolean1', 'boolean2']) + + def test_without_boolean_parameters(self): + base_path = fixtures + cdist_type = core.CdistType(base_path, '__without_boolean_parameters') + self.assertEqual(cdist_type.boolean_parameters, []) + From a4882e7e30a40c453735f4e727f267a9e759dcd8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Feb 2012 16:17:49 +0100 Subject: [PATCH 1356/4212] remove useless script printing and reuse run() method Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 3 --- lib/cdist/exec/local.py | 21 +-------------------- lib/cdist/exec/remote.py | 28 ++-------------------------- 3 files changed, 3 insertions(+), 49 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 828ff917..bead6d72 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -3,9 +3,6 @@ - cleanup object_id handling - have a look at singletons -- remove useless - ERROR: monitoring02: Code that raised the error: - - ensure that all types, which support --state support present and absent (consistent look and feel) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index cdf06205..e24ae484 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -119,26 +119,7 @@ class Local(object): command = ["/bin/sh", "-e"] command.append(script) - self.log.debug("Local run script: %s", command) - - if env is None: - env = os.environ.copy() - # Export __target_host for use in __remote_{copy,exec} scripts - env['__target_host'] = self.target_host - - self.log.debug("Local run script env: %s", env) - - try: - if return_output: - return subprocess.check_output(command, env=env).decode() - else: - subprocess.check_call(command, env=env) - except subprocess.CalledProcessError as error: - script_content = self.run(["cat", script], return_output=True) - self.log.error("Code that raised the error:\n%s", script_content) - raise LocalScriptError(script, command, script_content) - except EnvironmentError as error: - raise cdist.Error(" ".join(command) + ": " + error.args[1]) + self.run(command, env, return_output) def link_emulator(self, exec_path): """Link emulator to types""" diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 69dc5dda..0fb93e10 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -139,32 +139,8 @@ class Remote(object): Return the output as a string. """ - command = self._exec.split() - command.append(self.target_host) - # export target_host for use in __remote_{exec,copy} scripts - os_environ = os.environ.copy() - os_environ['__target_host'] = self.target_host - - self.log.debug("Remote run script: %s", command) - - # can't pass environment to remote side, so prepend command with - # variable declarations - if env: - self.log.debug("Remote run script env: %s", env) - command.extend(["%s=%s" % item for item in env.items()]) - - command.extend(["/bin/sh", "-e"]) + command = ["/bin/sh", "-e"] command.append(script) - try: - if return_output: - return subprocess.check_output(command, env=os_environ).decode() - else: - subprocess.check_call(command, env=os_environ) - except subprocess.CalledProcessError as error: - script_content = self.run(["cat", script], return_output=True) - self.log.error("Code that raised the error:\n%s", script_content) - raise RemoteScriptError(script, command, script_content) - except EnvironmentError as error: - raise cdist.Error(" ".join(command) + ": " + error.args[1]) + self.run(command, env, return_output) From ab48a72ce135df073b3be572e8fe24bcc6296421 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Feb 2012 16:25:18 +0100 Subject: [PATCH 1357/4212] return results from run() Signed-off-by: Nico Schottelius --- lib/cdist/exec/local.py | 2 +- lib/cdist/exec/remote.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index e24ae484..7fb63429 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -119,7 +119,7 @@ class Local(object): command = ["/bin/sh", "-e"] command.append(script) - self.run(command, env, return_output) + return self.run(command, env, return_output) def link_emulator(self, exec_path): """Link emulator to types""" diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 0fb93e10..47b670b0 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -143,4 +143,4 @@ class Remote(object): command = ["/bin/sh", "-e"] command.append(script) - self.run(command, env, return_output) + return self.run(command, env, return_output) From f031a40746c30beec6ccdc4d282a475ff9bb9eb6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Feb 2012 17:01:03 +0100 Subject: [PATCH 1358/4212] rebuild the command string Signed-off-by: Nico Schottelius --- lib/cdist/exec/remote.py | 49 ++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 47b670b0..7cd9052d 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -28,17 +28,6 @@ import logging import cdist - -class RemoteScriptError(cdist.Error): - def __init__(self, script, command, script_content): - self.script = script - self.command = command - self.script_content = script_content - - def __str__(self): - plain_command = " ".join(self.command) - return "Remote script execution failed: %s" % plain_command - class DecodeError(cdist.Error): def __init__(self, command): self.command = command @@ -91,6 +80,17 @@ class Remote(object): command.extend(["-r", source, 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. + Return the output as a string. + + """ + + command = ["/bin/sh", "-e"] + command.append(script) + + return self.run(command, env, return_output) + def run(self, command, env=None, return_output=False): """Run the given command with the given environment on the remote side. Return the output as a string. @@ -99,7 +99,15 @@ class Remote(object): # prefix given command with remote_exec cmd = self._exec.split() cmd.append(self.target_host) + + # can't pass environment to remote side, so prepend command with + # variable declarations + if env: + remote_env = ["%s=%s" % item for item in env.items()] + cmd.append(remote_env) + cmd.extend(command) + return self._run_command(cmd, env=env, return_output=return_output) def _run_command(self, command, env=None, return_output=False): @@ -113,14 +121,6 @@ class Remote(object): os_environ = os.environ.copy() os_environ['__target_host'] = self.target_host - # can't pass environment to remote side, so prepend command with - # variable declarations - if env: - cmd = ["%s=%s" % item for item in env.items()] - cmd.extend(command) - else: - cmd = command - self.log.debug("Remote run: %s", command) try: if return_output: @@ -133,14 +133,3 @@ class Remote(object): raise cdist.Error(" ".join(*args) + ": " + error.args[1]) except UnicodeDecodeError: raise DecodeError(command) - - def run_script(self, script, env=None, return_output=False): - """Run the given script with the given environment on the remote side. - Return the output as a string. - - """ - - command = ["/bin/sh", "-e"] - command.append(script) - - return self.run(command, env, return_output) From 72fb77f13552bc5fbc240e8c584c94cc4b3ce16c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Feb 2012 17:02:21 +0100 Subject: [PATCH 1359/4212] extend not append Signed-off-by: Nico Schottelius --- lib/cdist/exec/remote.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 7cd9052d..124c1b4f 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -104,7 +104,7 @@ class Remote(object): # variable declarations if env: remote_env = ["%s=%s" % item for item in env.items()] - cmd.append(remote_env) + cmd.extend(remote_env) cmd.extend(command) From 64bb1741aa0fb201b5e0f683f607f05c534a7038 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Feb 2012 17:05:22 +0100 Subject: [PATCH 1360/4212] cleanup local Signed-off-by: Nico Schottelius --- lib/cdist/exec/local.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index 7fb63429..d3c6a0ce 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -32,18 +32,6 @@ import logging import cdist from cdist import core - -class LocalScriptError(cdist.Error): - def __init__(self, script, command, script_content): - self.script = script - self.command = command - self.script_content = script_content - - def __str__(self): - plain_command = " ".join(self.command) - return "Local script execution failed: %s" % plain_command - - class Local(object): """Execute commands locally. @@ -131,4 +119,4 @@ class Local(object): try: os.symlink(src, dst) except OSError as e: - raise cdist.Error("Linking emulator from " + src + " to " + dst + " failed: " + e.__str__()) + raise cdist.Error("Linking emulator from %s to %s failed: %s" % (src, dst, e.__str__())) From 4a844ef2650314ed995608c5150e9cdf5121afb6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Feb 2012 17:06:58 +0100 Subject: [PATCH 1361/4212] ++changes(2.0.8) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 2d2d7a48..507726bc 100644 --- a/doc/changelog +++ b/doc/changelog @@ -6,6 +6,7 @@ Changelog 2.0.8: * Cleanup: Better hint to source of error + * Cleanup: Do not output failing script, but path to script only * Cleanup: Remove support for __debug variable in manifests (Type != Core debugging) From 6a97cf8f26214424d877a474a4ffe85a41233179 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 15 Feb 2012 14:27:30 -0500 Subject: [PATCH 1362/4212] Initial commit. Includes a few types in development and __package_pkg_freebsd. --- conf/type/__build/man.text | 56 ++++++++ conf/type/__build/manifest | 46 ++++++ conf/type/__build/parameter/optional | 2 + conf/type/__build_port_freebsd/gencode-remote | 69 +++++++++ conf/type/__build_port_freebsd/man.text | 61 ++++++++ .../__build_port_freebsd/parameter/optional | 1 + conf/type/__package/manifest | 1 + .../explorer/pkg_version | 35 +++++ .../type/__package_pkg_freebsd/gencode-remote | 135 ++++++++++++++++++ conf/type/__package_pkg_freebsd/man.text | 64 +++++++++ .../__package_pkg_freebsd/parameter/optional | 4 + .../__package_pkg_freebsd/parameter/required | 1 + conf/type/__rsyncer/gencode-local | 71 +++++++++ conf/type/__rsyncer/man.text | 72 ++++++++++ conf/type/__rsyncer/manifest | 31 ++++ conf/type/__rsyncer/parameter/optional | 3 + conf/type/__rsyncer/parameter/required | 1 + conf/type/__service/gencode-remote | 98 +++++++++++++ conf/type/__service/man.text | 48 +++++++ conf/type/__service/parameter/required | 1 + 20 files changed, 800 insertions(+) create mode 100644 conf/type/__build/man.text create mode 100755 conf/type/__build/manifest create mode 100644 conf/type/__build/parameter/optional create mode 100755 conf/type/__build_port_freebsd/gencode-remote create mode 100644 conf/type/__build_port_freebsd/man.text create mode 100644 conf/type/__build_port_freebsd/parameter/optional create mode 100755 conf/type/__package_pkg_freebsd/explorer/pkg_version create mode 100755 conf/type/__package_pkg_freebsd/gencode-remote create mode 100644 conf/type/__package_pkg_freebsd/man.text create mode 100644 conf/type/__package_pkg_freebsd/parameter/optional create mode 100644 conf/type/__package_pkg_freebsd/parameter/required create mode 100755 conf/type/__rsyncer/gencode-local create mode 100644 conf/type/__rsyncer/man.text create mode 100755 conf/type/__rsyncer/manifest create mode 100644 conf/type/__rsyncer/parameter/optional create mode 100644 conf/type/__rsyncer/parameter/required create mode 100755 conf/type/__service/gencode-remote create mode 100644 conf/type/__service/man.text create mode 100644 conf/type/__service/parameter/required diff --git a/conf/type/__build/man.text b/conf/type/__build/man.text new file mode 100644 index 00000000..1a297ec2 --- /dev/null +++ b/conf/type/__build/man.text @@ -0,0 +1,56 @@ +cdist-type__build(7) +=================== +Jake Guffey + + +NAME +---- +cdist-type__build - Manage software build operations + + +DESCRIPTION +----------- +This cdist type allows you to build software on the target. +It dispatches the actual work to the build-dependant types. + + +REQUIRED PARAMETERS +------------------- +None. + +OPTIONAL PARAMETERS +------------------- +name:: + The name of the software to build. Default is to use the object_id. +type:: + The build type to use. Default is to build a port for direct installation + on the target host. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Build and install a port +__build vim + +# Build and install a port explicitly defining to use ports +__build vim --type port_freebsd + +# Build a package to install via __package on another machine +__build vim --type pkg_freebsd + +# Force use of a specific package type +__build nanobsd --name nanobsd-internaluse-9.0 --type nanobsd +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2012 Jake Guffey. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__build/manifest b/conf/type/__build/manifest new file mode 100755 index 00000000..c8392d35 --- /dev/null +++ b/conf/type/__build/manifest @@ -0,0 +1,46 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# __build is an abstract type which dispatches to the lower level +# __build_$name types which do the actual interaction with the software +# build system. +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +if [ -f "$__object/parameter/type" ]; then + type="$(cat "$__object/parameter/type")" +else + type="port_freebsd" +fi + +set -- "$@" "$__object_id" +cd "$__object/parameter" +for property in $(ls .); do + if [ "$property" != "type" ]; then + set -- "$@" "--$property" "$(cat "$property")" + fi +done + +__build_$type "$@" diff --git a/conf/type/__build/parameter/optional b/conf/type/__build/parameter/optional new file mode 100644 index 00000000..d3598a51 --- /dev/null +++ b/conf/type/__build/parameter/optional @@ -0,0 +1,2 @@ +name +type diff --git a/conf/type/__build_port_freebsd/gencode-remote b/conf/type/__build_port_freebsd/gencode-remote new file mode 100755 index 00000000..ff0432ba --- /dev/null +++ b/conf/type/__build_port_freebsd/gencode-remote @@ -0,0 +1,69 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Build ports on FreeBSD +# + +assert () # If condition false, +{ #+ exit from script with error message. + E_PARAM_ERR=98 + E_ASSERT_FAILED=99 + + if [ -z "$2" ] # Not enough parameters passed. + then + return $E_PARAM_ERR # No damage done. + fi + + lineno=$2 + + if [ ! $1 ] + then + echo "Assertion failed: \"$1\"" + echo "File \"$0\", line $lineno, called by $(caller 0)" + exit $E_ASSERT_FAILED + fi +} + +# Debug +#exec >&2 +#set -x + +if [ -f "$__object/parameter/name" ]; then + name="$__object/parameter/name" +else + name="$__object_id" +fi + +# Get list of installed ports +installed="$(cat "$__object/explorer/installed")" + +# Is port already built/installed? Check /var/db/ports +for PORT in $installed; do + if [ "$(eval "$PORT" : "$name")" != 0 ]; then # already installed + exit 0; + fi +done + +# If not, build +echo "cd /usr/ports && " + +# Debug +#set +x + diff --git a/conf/type/__build_port_freebsd/man.text b/conf/type/__build_port_freebsd/man.text new file mode 100644 index 00000000..7ce6042b --- /dev/null +++ b/conf/type/__build_port_freebsd/man.text @@ -0,0 +1,61 @@ +cdist-type__package_pkg_freebsd(7) +================================== +Jake Guffey + + +NAME +---- +cdist-type__package_pkg_freebsd - Manage FreeBSD packages + + +DESCRIPTION +----------- +This type is usually used on FreeBSD to manage packages. + + +REQUIRED PARAMETERS +------------------- +state:: + Either "installed" or "removed". + + +OPTIONAL PARAMETERS +------------------- +name:: + If supplied, use the name and not the object id as the package name. + +flavor:: + If supplied, use to avoid ambiguity. + +version:: + If supplied, use to install a specific version of the package named. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure zsh is installed +__package_pkg_freebsd zsh --state installed + +# Ensure vim is installed, use flavor no_x11 +__package_pkg_freebsd vim --state installed --flavor no_x11 + +# If you don't want to follow pythonX packages, but always use python +__package_pkg_freebsd python --state installed --name python2 + +# Remove obsolete package +__package_pkg_freebsd puppet --state removed +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__package(7) + + +COPYING +------- +Copyright \(C) 2012 Jake Guffey. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__build_port_freebsd/parameter/optional b/conf/type/__build_port_freebsd/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/conf/type/__build_port_freebsd/parameter/optional @@ -0,0 +1 @@ +name diff --git a/conf/type/__package/manifest b/conf/type/__package/manifest index 181da077..7e0d7080 100755 --- a/conf/type/__package/manifest +++ b/conf/type/__package/manifest @@ -34,6 +34,7 @@ else debian|ubuntu) type="apt" ;; gentoo) type="emerge" ;; amazon|centos|fedora|redhat) type="yum" ;; + freebsd) type="pkg_freebsd" ;; *) echo "Don't know how to manage packages on: $os" >&2 exit 1 diff --git a/conf/type/__package_pkg_freebsd/explorer/pkg_version b/conf/type/__package_pkg_freebsd/explorer/pkg_version new file mode 100755 index 00000000..4bca24b6 --- /dev/null +++ b/conf/type/__package_pkg_freebsd/explorer/pkg_version @@ -0,0 +1,35 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Retrieve the status of a package - parsed dpkg output +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +# Don't produce "no pkgs installed" output -- breaks things +PKG_OUTPUT=$(pkg_info 2>&1) +if [ ! "$PKG_OUTPUT" = "pkg_info: no packages installed" ]; then + echo "$(echo "$PKG_OUTPUT" | grep "^$name-" | cut '-d ' -f1 | sed "s/$name-//g")" +fi + diff --git a/conf/type/__package_pkg_freebsd/gencode-remote b/conf/type/__package_pkg_freebsd/gencode-remote new file mode 100755 index 00000000..4d3c9844 --- /dev/null +++ b/conf/type/__package_pkg_freebsd/gencode-remote @@ -0,0 +1,135 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Manage packages with pkg on FreeBSD +# + +assert () # If condition false, +{ #+ exit from script with error message. + E_PARAM_ERR=98 + E_ASSERT_FAILED=99 + + if [ -z "$2" ] # Not enough parameters passed. + then + return $E_PARAM_ERR # No damage done. + fi + + lineno=$2 + + if [ ! $1 ] + then + echo "Assertion failed: \"$1\"" + echo "File \"$0\", line $lineno, called by $(caller 0)" + exit $E_ASSERT_FAILED + fi +} + +# Debug +#exec >&2 +#set -x + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +if [ -f "$__object/parameter/flavor" ]; then + flavor="$(cat "$__object/parameter/flavor")" +fi + +if [ -f "$__object/parameter/version" ]; then + version="$(cat "$__object/parameter/version")" +fi + +if [ -f "$__object/parameter/pkgsite" ]; then + pkgsite="$(cat "$__object/parameter/pkgsite")" +fi + +state="$(cat "$__object/parameter/state")" +curr_version="$(cat "$__object/explorer/pkg_version")" +add_cmd="pkg_add" +rm_cmd="pkg_delete" +cmd="" + +# Print the command to be executed +# Parms: $1 -- mode, "remove" or "add" +# $2 -- the command to be echoed +# FIXME: This is ugly. +execcmd(){ + # Set the PACKAGESITE if we're ADDing a new package + if [ "$1" = "add" -a -n "$pkgsite" ]; then + # Use http.../All/ if we know the exact version we want, use .../Latest/ otherwise + [ -n "$version" ] && pkgsite="${pkgsite}/All/" || pkgsite="${pkgsite}/Latest/" + echo "${pkgsite}" + fi + echo "${2} 2>&- >&-" # Silence the output of the command + echo "status=\$?" + echo "if [ \"\$status\" -ne \"0\" ]; then" + echo " echo \"Error: ${cmd} exited nonzero with \$status\"'!' >&2" + echo " exit 1" + echo "fi" +} + +if [ -n "$curr_version" ]; then # PKG *is* installed + if [ "$state" = "removed" ]; then # Shouldn't be installed + if [ -n "$flavor" ]; then + cmd="${rm_cmd} ${name}-${flavor}-${curr_version}" + else + cmd="${rm_cmd} ${name}-${curr_version}" + fi + execcmd "remove" "${cmd}" + exit 0 + else # Should be installed + if [ -n "$version" ]; then # Want a specific version + if [ "$version" = "$curr_version" ]; then # Current version is correct + exit 0 + else # Current version is wrong, fix + #updatepkg "$name" "$version" + assert "! ${version} = ${curr_version}" $LINENO + cmd="${rm_cmd} ${name}-${curr_version}" + execcmd "remove" "${cmd}" + cmd="${add_cmd} ${name}-${version}" + execcmd "add" "${cmd}" + fi + else # Don't care what version to use + exit 0 + fi + fi +else # PKG *isn't* installed + if [ "$state" = "removed" ]; then # Shouldn't be installed + exit 0 + elif [ "$state" = "installed" ]; then # Is not currently installed, should be + if [ -n "$flavor" ]; then + cmd="${add_cmd} -r ${name}-${flavor}" + else + cmd="${add_cmd} -r ${name}" + fi + if [ -n "$version" ]; then + cmd="${cmd}-${version}" + fi + execcmd "add" "${cmd}" + exit 0 + fi +fi + +# Debug +#set +x + diff --git a/conf/type/__package_pkg_freebsd/man.text b/conf/type/__package_pkg_freebsd/man.text new file mode 100644 index 00000000..882bece9 --- /dev/null +++ b/conf/type/__package_pkg_freebsd/man.text @@ -0,0 +1,64 @@ +cdist-type__package_pkg_freebsd(7) +================================== +Jake Guffey + + +NAME +---- +cdist-type__package_pkg_freebsd - Manage FreeBSD packages + + +DESCRIPTION +----------- +This type is usually used on FreeBSD to manage packages. + + +REQUIRED PARAMETERS +------------------- +state:: + Either "installed" or "removed". + + +OPTIONAL PARAMETERS +------------------- +name:: + If supplied, use the name and not the object id as the package name. + +flavor:: + If supplied, use to avoid ambiguity. + +version:: + If supplied, use to install a specific version of the package named. + +pkgsite:: + If supplied, use to install from a specific package repository. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure zsh is installed +__package_pkg_freebsd zsh --state installed + +# Ensure vim is installed, use flavor no_x11 +__package_pkg_freebsd vim --state installed --flavor no_x11 + +# If you don't want to follow pythonX packages, but always use python +__package_pkg_freebsd python --state installed --name python2 + +# Remove obsolete package +__package_pkg_freebsd puppet --state removed +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__package(7) + + +COPYING +------- +Copyright \(C) 2012 Jake Guffey. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__package_pkg_freebsd/parameter/optional b/conf/type/__package_pkg_freebsd/parameter/optional new file mode 100644 index 00000000..3fb2f29e --- /dev/null +++ b/conf/type/__package_pkg_freebsd/parameter/optional @@ -0,0 +1,4 @@ +name +flavor +version +pkgsite diff --git a/conf/type/__package_pkg_freebsd/parameter/required b/conf/type/__package_pkg_freebsd/parameter/required new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/conf/type/__package_pkg_freebsd/parameter/required @@ -0,0 +1 @@ +state diff --git a/conf/type/__rsyncer/gencode-local b/conf/type/__rsyncer/gencode-local new file mode 100755 index 00000000..515ab71b --- /dev/null +++ b/conf/type/__rsyncer/gencode-local @@ -0,0 +1,71 @@ +#!/bin/sh +# +# Copyright (C) 2011 Daniel Maher (phrawzty+cdist at gmail.com) +# Parts copyright (C) 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist (https://github.com/telmich/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 . +# + +# Debug +#exec >&2 +#set -x + +source="$(cat "$__object/parameter/source")" + +if [ -f "$__object/parameter/destination" ]; then + destination="$(cat "$__object/parameter/destination")" +else + destination="/$__object_id" +fi + +# The system binary is probably ok, but if not... +if [ -f "$__object/parameter/rsyncbin" ]; then + rsyncbin="$(cat "$__object/parameter/rsyncbin")" +else + rsyncbin=`which rsync` +fi + +# Turned this into an array so that we can use the "-e" argument to get the +# "root@" stuff fixed and so that "ssh -l root" is a single arg (as rsync +# wants it to be). +args=('-a' '-e' '"ssh -l root"') + +# If the --delete argument should be passed to rsync. +if [ -f "$__object/parameter/delete" ]; then +# This is from having args defined as an array previously. ${#args[@]} +# is the number of indices in args, and args[${#args[@]}]=... creates a +# new index of args, which is then filled with "--delete." + args[${#args[@]}]="--delete" +fi + +cmd="${rsyncbin} ${args[@]} \"${source}\"" + +# If the --chroot argument was given +if [ -f "$__object/parameter/chroot" ]; then + chroot=$(cat $__object/parameter/chroot) + cmd="${cmd} \"$chroot/$destination\"" +else + cmd="${cmd} \"$__target_host:$destination\"" +fi + +# FIXME: +# - align with __remote_{exec,copy} variables? -- done + +# Run rsync (locally). +echo "${cmd}" + +#set +x + diff --git a/conf/type/__rsyncer/man.text b/conf/type/__rsyncer/man.text new file mode 100644 index 00000000..18218181 --- /dev/null +++ b/conf/type/__rsyncer/man.text @@ -0,0 +1,72 @@ +cdist-type__rsyncer(7) +====================== +Daniel Maher +Jake Guffey + + +NAME +---- +cdist-type__rsyncer - Use rsync to copy files. + + +DESCRIPTION +----------- +This type is used to trigger rsync to copy files from the machine running cdist +(source) to the target machine in question (destination). The likely usage is +the rapid deployment of full directory trees, the cohorency of which can be +guarunteed with the optional --delete argument, which will remove any files +from the destination which are not present on the source. + + +REQUIRED PARAMETERS +------------------- +source:: + The full path of the source from which to copy. This is passed directly + to rsync. + + +OPTIONAL PARAMETERS +------------------- +destination:: + The full path of the destination. This is passed directly to rsync. + Default: object_id + +delete:: + If true, remove files from destination which are not in source. This is + effectively the --delete argument of rsync. + Default: false + +rsyncbin:: + Specify the full path to the rsync binary. + Default: `which rsync` + +chroot:: + Specify the use of a chroot environment. If given, rsync copies the source + to $chroot/$destination. + Default: none + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Basic example +__rsyncer '/home/foo' --source '/opt/dist/foo' + +# Fancier example +__rsyncer FOO --source '/opt/dist/foo' --destination '/home/foo/' --delete true + +# Chroot example +__rsyncer '/home/foo' --source '/opt/dist/foo' --chroot '/usr/chroot/home' +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011-2012 Daniel Maher, Jake Guffey. Free use of this software +is granted under the terms of the GNU General Public License version 3 (GPLv3). + diff --git a/conf/type/__rsyncer/manifest b/conf/type/__rsyncer/manifest new file mode 100755 index 00000000..fb884bc1 --- /dev/null +++ b/conf/type/__rsyncer/manifest @@ -0,0 +1,31 @@ +#!/bin/sh +# +# Copyright (C) 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist (https://github.com/telmich/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 . +# + +# Debug +#exec >&2 +#set -x + +# This type has a dependency of the rsync package on the "other" side. +# Ensure that it's installed. +__package rsync --state installed + +# Debug +#set +x + diff --git a/conf/type/__rsyncer/parameter/optional b/conf/type/__rsyncer/parameter/optional new file mode 100644 index 00000000..3bcb4dc7 --- /dev/null +++ b/conf/type/__rsyncer/parameter/optional @@ -0,0 +1,3 @@ +destination +delete +rsyncbin diff --git a/conf/type/__rsyncer/parameter/required b/conf/type/__rsyncer/parameter/required new file mode 100644 index 00000000..5a18cd2f --- /dev/null +++ b/conf/type/__rsyncer/parameter/required @@ -0,0 +1 @@ +source diff --git a/conf/type/__service/gencode-remote b/conf/type/__service/gencode-remote new file mode 100755 index 00000000..85bd981c --- /dev/null +++ b/conf/type/__service/gencode-remote @@ -0,0 +1,98 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +# Debug +#exec >&2 +#set -x + +state="$(cat "$__object/parameter/status")" + +### Begin forming $cmd +cmd="" +cmd="$(cat <&2 + exit -1 +fi + +status="\$("\$exists" status || true)" +if [ "\$(expr "\$status" : "Cannot 'status' \$name. Set \${name}_enable to YES")" != "0" ]; then + echo "Can't status \$name. Set \${name}_enable to YES first in rc.conf on \$__target_host." >&2 + exit -1 +fi + +EOF)" +### End forming $cmd + +### Begin forming $running +running="$(cat <&- >&- +elif [ \$(expr "\$status" : ".*not running.*") != "0" ]; then + "\$exists" start 2>&- >&- +elif [ \$(expr "\$status" : ".*dead.*") != "0" ]; then + "\$exists" restart 2>&- >&- +fi +EOF)" +### End forming $running + +### Begin forming $stopped +stopped="$(cat <&- >&- + fi +EOF)" +### End forming $stopped + +case "$state" in + running) + cmd="$(echo "${cmd}\n${running}")" + ;; + stopped) + cmd="$(echo "${cmd}\n${stopped}")" + ;; + *) + echo "Unknown state: ${state}" >&2 + exit 1 + ;; +esac + +echo "${cmd}" + +# Debug +#set +x + diff --git a/conf/type/__service/man.text b/conf/type/__service/man.text new file mode 100644 index 00000000..9b55a18f --- /dev/null +++ b/conf/type/__service/man.text @@ -0,0 +1,48 @@ +cdist-type__service(7) +====================== +Jake Guffey + + +NAME +---- +cdist-type__service - Control a system service (daemon) state + + +DESCRIPTION +----------- +This cdist type allows you to control the state of a service (daemon). + + +REQUIRED PARAMETERS +------------------- +state:: + State of the service: Either stopped or running. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Start if not running +__service syslog-ng --state running + +# Stop the process if it is running +__service sshd --state stopped + +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2012 Jake Guffey. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__service/parameter/required b/conf/type/__service/parameter/required new file mode 100644 index 00000000..8be5547d --- /dev/null +++ b/conf/type/__service/parameter/required @@ -0,0 +1 @@ +status From 79dedb5bb52cd856ecef5e12340e2c38a42bf0a0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 16 Feb 2012 10:17:09 +0100 Subject: [PATCH 1363/4212] document boolean parameters Signed-off-by: Steven Armstrong --- doc/man/cdist-reference.text.sh | 7 ++++-- doc/man/man7/cdist-type.text | 41 +++++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 81e58ab2..a76e7941 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -101,12 +101,15 @@ conf/type//gencode-local:: conf/type//gencode-remote:: Used to generate code to be executed on the client. -conf/type//parameters/required:: +conf/type//parameter/required:: Parameters required by type, \n seperated list. -conf/type//parameters/optional:: +conf/type//parameter/optional:: Parameters optionally accepted by type, \n seperated list. +conf/type//parameter/boolean:: + Boolean parameters accepted by type, \n seperated list. + conf/type//explorer:: Location of the type specific explorers. This directory is referenced by the variable __type_explorer (see below). diff --git a/doc/man/man7/cdist-type.text b/doc/man/man7/cdist-type.text index 48d412f1..1147511e 100644 --- a/doc/man/man7/cdist-type.text +++ b/doc/man/man7/cdist-type.text @@ -40,7 +40,7 @@ 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 +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. @@ -72,15 +72,42 @@ To begin a new type, just create the directory **conf/type/__NAME**. DEFINING PARAMETERS ------------------- -Every type consists of optional and required parameters, which must -be created in a newline seperated file in ***parameters/required*** and -***parameters/optional***. If either or both missing, the type will have -no required, no optional or no parameters at all. +Every type consists of required, optional and boolean parameters, which must +be created in a newline seperated file in ***parameter/required***, +***parameter/optional*** and ***parameter/boolean***. If either is missing, +the type will have no required, no optional, no boolean or no parameters at +all. Example: -------------------------------------------------------------------------------- echo servername >> conf/type/__nginx_vhost/parameter/required echo logdirectory >> conf/type/__nginx_vhost/parameter/optional +echo use_ssl >> 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 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 -------------------------------------------------------------------------------- @@ -116,7 +143,7 @@ SINGLETON - ONLY 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: +directory: -------------------------------------------------------------------------------- touch conf/type/__NAME/singleton @@ -128,7 +155,7 @@ 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, +As you can see, the object ID is omitted, because it does not make any sense, if your type can be used only once. From baf8614e6cfab4467a62c57c66f82cd4940939ee Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 16 Feb 2012 11:13:50 +0100 Subject: [PATCH 1364/4212] ++changes(2.0.8) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 507726bc..ab006435 100644 --- a/doc/changelog +++ b/doc/changelog @@ -9,6 +9,7 @@ Changelog * Cleanup: Do not output failing script, but path to script only * Cleanup: Remove support for __debug variable in manifests (Type != Core debugging) + * Feature Core: Support boolean parameters (Steven Armstrong) 2.0.7: 2012-02-13 * Bugfix __file: Use chmod after chown/chgrp (Matt Coddington) From 8f46b2ca05e3bd12d78f37e112a03627c6c4b87e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 16 Feb 2012 23:08:02 +0100 Subject: [PATCH 1365/4212] reorder Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index bead6d72..fc815bc2 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,11 +1,11 @@ - introduce default parameters -- cleanup object_id handling - - have a look at singletons - - ensure that all types, which support --state support present and absent (consistent look and feel) +- cleanup object_id handling + - have a look at singletons + -------------------------------------------------------------------------------- - update/create docs From aa53a3f221e6a631482a7b68c7a3cb9afc385333 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 16 Feb 2012 23:12:49 +0100 Subject: [PATCH 1366/4212] better warning Signed-off-by: Nico Schottelius --- conf/type/__package_apt/gencode-remote | 4 ++-- conf/type/__package_pacman/gencode-remote | 4 ++-- conf/type/__package_pkg_openbsd/gencode-remote | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/conf/type/__package_apt/gencode-remote b/conf/type/__package_apt/gencode-remote index 47e76ec8..406708c2 100755 --- a/conf/type/__package_apt/gencode-remote +++ b/conf/type/__package_apt/gencode-remote @@ -32,11 +32,11 @@ state_should="$(cat "$__object/parameter/state")" # Correct pre 2.1 naming - FIXME in 2.1 case "$state_should" in installed) - echo "WARNING: $state_should is deprecated, please change to present/absent (will be removed in cdist 2.1)" >&2 + echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="present" ;; removed) - echo "WARNING: $state_should is deprecated, please change to present/absent (will be removed in cdist 2.1)" >&2 + echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="absent" ;; esac diff --git a/conf/type/__package_pacman/gencode-remote b/conf/type/__package_pacman/gencode-remote index 1516370c..6d445ddc 100755 --- a/conf/type/__package_pacman/gencode-remote +++ b/conf/type/__package_pacman/gencode-remote @@ -36,11 +36,11 @@ fi state_should="$(cat "$__object/parameter/state")" case "$state_should" in installed) - echo "WARNING: $state_should is deprecated, please change to present/absent (will be removed in cdist 2.1)" >&2 + echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="present" ;; removed) - echo "WARNING: $state_should is deprecated, please change to present/absent (will be removed in cdist 2.1)" >&2 + echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="absent" ;; esac diff --git a/conf/type/__package_pkg_openbsd/gencode-remote b/conf/type/__package_pkg_openbsd/gencode-remote index e8309f20..0cf27a93 100755 --- a/conf/type/__package_pkg_openbsd/gencode-remote +++ b/conf/type/__package_pkg_openbsd/gencode-remote @@ -47,11 +47,11 @@ state_should="$(cat "$__object/parameter/state")" # Correct pre 2.1 naming - FIXME in 2.1 case "$state_should" in installed) - echo "WARNING: $state_should is deprecated, please change to present/absent (will be removed in cdist 2.1)" >&2 + echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="present" ;; removed) - echo "WARNING: $state_should is deprecated, please change to present/absent (will be removed in cdist 2.1)" >&2 + echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="absent" ;; esac From 272c12e3f7c8996a8ae4f8085d1fd1417367a24a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 16 Feb 2012 23:15:31 +0100 Subject: [PATCH 1367/4212] correct parameters in __package_luarocks Signed-off-by: Nico Schottelius --- conf/type/__package_luarocks/gencode-remote | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/conf/type/__package_luarocks/gencode-remote b/conf/type/__package_luarocks/gencode-remote index 29fd7e38..17599bd3 100755 --- a/conf/type/__package_luarocks/gencode-remote +++ b/conf/type/__package_luarocks/gencode-remote @@ -30,6 +30,18 @@ else fi state_should="$(cat "$__object/parameter/state")" +# Correct pre 2.1 naming - FIXME in 2.1 +case "$state_should" in + installed) + echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + state_should="present" + ;; + removed) + echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + state_should="absent" + ;; +esac + is_installed="$(grep "(installed)" "$__object/explorer/pkg_status" || true)" case "$state" in From 76a3c2066905a9b27b33b2487cab6c0997050a2a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 16 Feb 2012 23:16:26 +0100 Subject: [PATCH 1368/4212] setup state_is Signed-off-by: Nico Schottelius --- conf/type/__package_luarocks/gencode-remote | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/conf/type/__package_luarocks/gencode-remote b/conf/type/__package_luarocks/gencode-remote index 17599bd3..2c1aa763 100755 --- a/conf/type/__package_luarocks/gencode-remote +++ b/conf/type/__package_luarocks/gencode-remote @@ -42,7 +42,12 @@ case "$state_should" in ;; esac -is_installed="$(grep "(installed)" "$__object/explorer/pkg_status" || true)" + +if grep -q "(installed)" "$__object/explorer/pkg_status"; then + state_is="present" +else + state_is="absent" +fi case "$state" in installed) From 9fab782a0cbb1f9dd6af6a1e348b76a95aa7897b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 16 Feb 2012 23:18:26 +0100 Subject: [PATCH 1369/4212] update __package_luarocks to new style state checking Signed-off-by: Nico Schottelius --- conf/type/__package_luarocks/gencode-remote | 35 ++++++++++----------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/conf/type/__package_luarocks/gencode-remote b/conf/type/__package_luarocks/gencode-remote index 2c1aa763..bfde7792 100755 --- a/conf/type/__package_luarocks/gencode-remote +++ b/conf/type/__package_luarocks/gencode-remote @@ -24,9 +24,9 @@ if [ -f "$__object/parameter/name" ]; then - name="$(cat "$__object/parameter/name")" + name="$(cat "$__object/parameter/name")" else - name="$__object_id" + name="$__object_id" fi state_should="$(cat "$__object/parameter/state")" @@ -49,21 +49,18 @@ else state_is="absent" fi -case "$state" in - installed) - # Install only if non-existent - if [ -z "$is_installed" ]; then - echo luarocks install \"$name\" - fi - ;; - removed) - # Remove only if existent - if [ -n "$is_installed" ]; then - echo luarocks remove \"$name\" - fi - ;; - *) - echo "Unknown state: $state" >&2 - exit 1 - ;; +# Leave if nothing is to be done +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + echo luarocks install \"$name\" + ;; + absent) + echo luarocks remove \"$name\" + ;; + *) + echo "Unknown state: $state" >&2 + exit 1 + ;; esac From e4aafe0af96ac6fc79faf99580defe8964a38a04 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 16 Feb 2012 23:23:19 +0100 Subject: [PATCH 1370/4212] support absent/present in __package_rubygem Signed-off-by: Nico Schottelius --- .../type/__package_pkg_openbsd/gencode-remote | 1 - conf/type/__package_rubygem/gencode-remote | 57 +++++++++++-------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/conf/type/__package_pkg_openbsd/gencode-remote b/conf/type/__package_pkg_openbsd/gencode-remote index 0cf27a93..97f3f101 100755 --- a/conf/type/__package_pkg_openbsd/gencode-remote +++ b/conf/type/__package_pkg_openbsd/gencode-remote @@ -29,7 +29,6 @@ os_version="$(cat "$__global/explorer/os_version")" machine="$(cat "$__global/explorer/machine")" - if [ -f "$__object/parameter/flavor" ]; then flavor="$(cat "$__object/parameter/flavor")" fi diff --git a/conf/type/__package_rubygem/gencode-remote b/conf/type/__package_rubygem/gencode-remote index daaba524..b48874c7 100755 --- a/conf/type/__package_rubygem/gencode-remote +++ b/conf/type/__package_rubygem/gencode-remote @@ -21,31 +21,42 @@ # Manage Rubygem packages # - if [ -f "$__object/parameter/name" ]; then - name="$(cat "$__object/parameter/name")" + name="$(cat "$__object/parameter/name")" else - name="$__object_id" + name="$__object_id" fi -state="$(cat "$__object/parameter/state")" -is_installed="$(grep "true" "$__object/explorer/pkg_status" || true)" - -case "$state" in - installed) - # Install only if non-existent - if [ -z "$is_installed" ]; then - echo gem install \"$name\" --no-ri --no-rdoc - fi - ;; - removed) - # Remove only if existent - if [ -n "$is_installed" ]; then - echo gem uninstall \"$name\" - fi - ;; - *) - echo "Unknown state: $state" >&2 - exit 1 - ;; +state_should="$(cat "$__object/parameter/state")" +# Correct pre 2.1 naming - FIXME in 2.1 +case "$state_should" in + installed) + echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + state_should="present" + ;; + removed) + echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + state_should="absent" + ;; +esac + +if grep -q true "$__object/explorer/pkg_status"; then + state_is="present" +else + state_is="absent" +fi + +[ "$state_is" = "$state_should ] && exit 0 + +case "$state_should" in + present) + echo gem install \"$name\" --no-ri --no-rdoc + ;; + absent) + echo gem uninstall \"$name\" + ;; + *) + echo "Unknown state: $state" >&2 + exit 1 + ;; esac From 2f01fd6ce05072faf76c4ee74c25f8b579719585 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 16 Feb 2012 23:26:23 +0100 Subject: [PATCH 1371/4212] support absent/present in __package_yum Signed-off-by: Nico Schottelius --- conf/type/__package_yum/gencode-remote | 46 +++++++++++++++++--------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/conf/type/__package_yum/gencode-remote b/conf/type/__package_yum/gencode-remote index b24ed220..35e8bd6b 100755 --- a/conf/type/__package_yum/gencode-remote +++ b/conf/type/__package_yum/gencode-remote @@ -27,7 +27,17 @@ else name="$__object_id" fi -state="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" +case "$state_should" in + installed) + echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + state_should="present" + ;; + removed) + echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + state_should="absent" + ;; +esac if grep -q -E "(centos|redhat|amazon)" "$__global/explorer/os"; then opts="-y --quiet" @@ -37,19 +47,23 @@ fi not_installed="^no package provides" -case "$state" in - installed) - if grep -q "$not_installed" "$__object/explorer/pkg_version"; then - echo yum $opts install \"$name\" - fi - ;; - removed) - if ! grep -q "$not_installed" "$__object/explorer/pkg_version"; then - echo yum $opts remove \"$name\" - fi - ;; - *) - echo "Unknown state: $state" >&2 - exit 1 - ;; +if grep -q "$not_installed" "$__object/explorer/pkg_version"; then + state_is="absent" +else + state_is="present" +fi + +[ "$state_is" = "$state_should ] && exit 0 + +case "$state_should" in + present) + echo yum $opts install \"$name\" + ;; + absent) + echo yum $opts remove \"$name\" + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; esac From 48f3252de58ec1504efc270fc338e1f72d20763c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 16 Feb 2012 23:29:51 +0100 Subject: [PATCH 1372/4212] correct state error message to use new variable Signed-off-by: Nico Schottelius --- conf/type/__package_apt/gencode-remote | 2 +- conf/type/__package_luarocks/gencode-remote | 2 +- conf/type/__package_pacman/gencode-remote | 2 +- conf/type/__package_pip/gencode-remote | 4 ++++ conf/type/__package_rubygem/gencode-remote | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/conf/type/__package_apt/gencode-remote b/conf/type/__package_apt/gencode-remote index 406708c2..ed5ca5bb 100755 --- a/conf/type/__package_apt/gencode-remote +++ b/conf/type/__package_apt/gencode-remote @@ -61,7 +61,7 @@ if [ "$state_is" != "$state_should" ]; then echo $aptget remove \"$name\" ;; *) - echo "Unknown state: $state" >&2 + echo "Unknown state: $state_should" >&2 exit 1 ;; esac diff --git a/conf/type/__package_luarocks/gencode-remote b/conf/type/__package_luarocks/gencode-remote index bfde7792..b4970daa 100755 --- a/conf/type/__package_luarocks/gencode-remote +++ b/conf/type/__package_luarocks/gencode-remote @@ -60,7 +60,7 @@ case "$state_should" in echo luarocks remove \"$name\" ;; *) - echo "Unknown state: $state" >&2 + echo "Unknown state: $state_should" >&2 exit 1 ;; esac diff --git a/conf/type/__package_pacman/gencode-remote b/conf/type/__package_pacman/gencode-remote index 6d445ddc..5c45fbce 100755 --- a/conf/type/__package_pacman/gencode-remote +++ b/conf/type/__package_pacman/gencode-remote @@ -63,7 +63,7 @@ case "$state_should" in echo pacman "$pacopts" -R \"$name\" ;; *) - echo "Unknown state: $state" >&2 + echo "Unknown state: $state_should" >&2 exit 1 ;; esac diff --git a/conf/type/__package_pip/gencode-remote b/conf/type/__package_pip/gencode-remote index e60d74c5..0f15abdc 100644 --- a/conf/type/__package_pip/gencode-remote +++ b/conf/type/__package_pip/gencode-remote @@ -47,4 +47,8 @@ case "$state_should" in absent) echo $pip uninstall -q -y pyro ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; esac diff --git a/conf/type/__package_rubygem/gencode-remote b/conf/type/__package_rubygem/gencode-remote index b48874c7..cca016cf 100755 --- a/conf/type/__package_rubygem/gencode-remote +++ b/conf/type/__package_rubygem/gencode-remote @@ -56,7 +56,7 @@ case "$state_should" in echo gem uninstall \"$name\" ;; *) - echo "Unknown state: $state" >&2 + echo "Unknown state: $state_should" >&2 exit 1 ;; esac From 6afcb0e9ee32794719cb0bc0f406eebdf3e62d1f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 16 Feb 2012 23:34:22 +0100 Subject: [PATCH 1373/4212] indent + simplify Signed-off-by: Nico Schottelius --- conf/type/__package_apt/gencode-remote | 28 +++++++++++------------ conf/type/__package_pacman/gencode-remote | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/conf/type/__package_apt/gencode-remote b/conf/type/__package_apt/gencode-remote index ed5ca5bb..f0c6090b 100755 --- a/conf/type/__package_apt/gencode-remote +++ b/conf/type/__package_apt/gencode-remote @@ -52,17 +52,17 @@ esac aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes" -if [ "$state_is" != "$state_should" ]; then - case "$state_should" in - present) - echo $aptget install \"$name\" - ;; - absent) - echo $aptget remove \"$name\" - ;; - *) - echo "Unknown state: $state_should" >&2 - exit 1 - ;; - esac -fi +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + echo $aptget install \"$name\" + ;; + absent) + echo $aptget remove \"$name\" + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/conf/type/__package_pacman/gencode-remote b/conf/type/__package_pacman/gencode-remote index 5c45fbce..73ed0997 100755 --- a/conf/type/__package_pacman/gencode-remote +++ b/conf/type/__package_pacman/gencode-remote @@ -53,7 +53,7 @@ else fi # Exit if nothing is needed to be done -[ "$state_is" = "$state_should ] && exit 0 +[ "$state_is" = "$state_should" ] && exit 0 case "$state_should" in present) From 31aa102b209e066b4abacd4b5b13fa6e5d1cd655 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 16 Feb 2012 23:37:08 +0100 Subject: [PATCH 1374/4212] ++changes(2.0.8) Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index ab006435..0bdbeb32 100644 --- a/doc/changelog +++ b/doc/changelog @@ -9,6 +9,8 @@ Changelog * Cleanup: Do not output failing script, but path to script only * Cleanup: Remove support for __debug variable in manifests (Type != Core debugging) + * Cleanup: Change __package_* to support absent/present (default state + name now). The values removed/installed will be removed in cdist 2.1. * Feature Core: Support boolean parameters (Steven Armstrong) 2.0.7: 2012-02-13 From 78bdbce7004bc46ab8b1203df93dcda122981710 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 16 Feb 2012 23:38:09 +0100 Subject: [PATCH 1375/4212] absent/present implemented in __package_absent_present branch Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index fc815bc2..d37a0f9f 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,8 +1,5 @@ - introduce default parameters -- ensure that all types, which support --state support - present and absent (consistent look and feel) - - cleanup object_id handling - have a look at singletons From 9e4b3d23256563319e7113280639ae61e5095d2b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Feb 2012 10:27:23 +0100 Subject: [PATCH 1376/4212] +mirror Signed-off-by: Nico Schottelius --- build | 1 + 1 file changed, 1 insertion(+) diff --git a/build b/build index 2d98e862..b209e1c2 100755 --- a/build +++ b/build @@ -130,6 +130,7 @@ case "$1" in git push --mirror git push --mirror github git push --mirror sf + git push --mirror ethz ;; clean) From 9eeac41bea71b836331da32a53d48405eb978f62 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Feb 2012 11:20:47 +0100 Subject: [PATCH 1377/4212] ++ideas Signed-off-by: Nico Schottelius --- doc/dev/todo/niconext | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index d37a0f9f..aa5f6001 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,10 +1,13 @@ - introduce default parameters + - valid for optional parameters only + - stored in parameter/default/$name + + - when/where to save? in emulator? + - read vi fsproperty? - cleanup object_id handling - have a look at singletons --------------------------------------------------------------------------------- - - update/create docs - cdist-cache:: How to get use information about the hosts we have been working on [advanced] From 241f66a537c32c346011d64c0cc7b7816df97b21 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Feb 2012 11:24:29 +0100 Subject: [PATCH 1378/4212] +quotes Signed-off-by: Nico Schottelius --- conf/type/__package_rubygem/gencode-remote | 2 +- conf/type/__package_yum/gencode-remote | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/type/__package_rubygem/gencode-remote b/conf/type/__package_rubygem/gencode-remote index cca016cf..4a8f21ee 100755 --- a/conf/type/__package_rubygem/gencode-remote +++ b/conf/type/__package_rubygem/gencode-remote @@ -46,7 +46,7 @@ else state_is="absent" fi -[ "$state_is" = "$state_should ] && exit 0 +[ "$state_is" = "$state_should" ] && exit 0 case "$state_should" in present) diff --git a/conf/type/__package_yum/gencode-remote b/conf/type/__package_yum/gencode-remote index 35e8bd6b..7f294a46 100755 --- a/conf/type/__package_yum/gencode-remote +++ b/conf/type/__package_yum/gencode-remote @@ -53,7 +53,7 @@ else state_is="present" fi -[ "$state_is" = "$state_should ] && exit 0 +[ "$state_is" = "$state_should" ] && exit 0 case "$state_should" in present) From e0f80f01030f0a46275be01eb4ff2bde6c89bd98 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Feb 2012 11:54:34 +0100 Subject: [PATCH 1379/4212] include object_name in warning Signed-off-by: Nico Schottelius --- conf/type/__package_apt/gencode-remote | 4 ++-- conf/type/__package_luarocks/gencode-remote | 4 ++-- conf/type/__package_pacman/gencode-remote | 4 ++-- conf/type/__package_pkg_openbsd/gencode-remote | 4 ++-- conf/type/__package_rubygem/gencode-remote | 4 ++-- conf/type/__package_yum/gencode-remote | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/conf/type/__package_apt/gencode-remote b/conf/type/__package_apt/gencode-remote index f0c6090b..0bcdb946 100755 --- a/conf/type/__package_apt/gencode-remote +++ b/conf/type/__package_apt/gencode-remote @@ -32,11 +32,11 @@ state_should="$(cat "$__object/parameter/state")" # Correct pre 2.1 naming - FIXME in 2.1 case "$state_should" in installed) - echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="present" ;; removed) - echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="absent" ;; esac diff --git a/conf/type/__package_luarocks/gencode-remote b/conf/type/__package_luarocks/gencode-remote index b4970daa..327f812c 100755 --- a/conf/type/__package_luarocks/gencode-remote +++ b/conf/type/__package_luarocks/gencode-remote @@ -33,11 +33,11 @@ state_should="$(cat "$__object/parameter/state")" # Correct pre 2.1 naming - FIXME in 2.1 case "$state_should" in installed) - echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="present" ;; removed) - echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="absent" ;; esac diff --git a/conf/type/__package_pacman/gencode-remote b/conf/type/__package_pacman/gencode-remote index 73ed0997..9defabe8 100755 --- a/conf/type/__package_pacman/gencode-remote +++ b/conf/type/__package_pacman/gencode-remote @@ -36,11 +36,11 @@ fi state_should="$(cat "$__object/parameter/state")" case "$state_should" in installed) - echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="present" ;; removed) - echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="absent" ;; esac diff --git a/conf/type/__package_pkg_openbsd/gencode-remote b/conf/type/__package_pkg_openbsd/gencode-remote index 97f3f101..26dd4689 100755 --- a/conf/type/__package_pkg_openbsd/gencode-remote +++ b/conf/type/__package_pkg_openbsd/gencode-remote @@ -46,11 +46,11 @@ state_should="$(cat "$__object/parameter/state")" # Correct pre 2.1 naming - FIXME in 2.1 case "$state_should" in installed) - echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="present" ;; removed) - echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="absent" ;; esac diff --git a/conf/type/__package_rubygem/gencode-remote b/conf/type/__package_rubygem/gencode-remote index 4a8f21ee..638c4252 100755 --- a/conf/type/__package_rubygem/gencode-remote +++ b/conf/type/__package_rubygem/gencode-remote @@ -31,11 +31,11 @@ state_should="$(cat "$__object/parameter/state")" # Correct pre 2.1 naming - FIXME in 2.1 case "$state_should" in installed) - echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="present" ;; removed) - echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="absent" ;; esac diff --git a/conf/type/__package_yum/gencode-remote b/conf/type/__package_yum/gencode-remote index 7f294a46..a10e60dd 100755 --- a/conf/type/__package_yum/gencode-remote +++ b/conf/type/__package_yum/gencode-remote @@ -30,11 +30,11 @@ fi state_should="$(cat "$__object/parameter/state")" case "$state_should" in installed) - echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="present" ;; removed) - echo "WARNING: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 state_should="absent" ;; esac From 0f649577ad82bc894265ad07a111f4c8b0f9cd94 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Feb 2012 12:10:42 +0100 Subject: [PATCH 1380/4212] update __process to new style, warn if not present/absent Signed-off-by: Nico Schottelius --- conf/type/__process/gencode-remote | 51 ++++++++++++++++++------------ conf/type/__process/man.text | 18 ++++++----- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/conf/type/__process/gencode-remote b/conf/type/__process/gencode-remote index be0e0cae..3411734e 100755 --- a/conf/type/__process/gencode-remote +++ b/conf/type/__process/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -25,33 +25,44 @@ else name="$__object_id" fi -runs="$(cat "$__object/explorer/runs")" state_should="$(cat "$__object/parameter/state")" +case "$state_should" in + running) + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + state_should="present" + ;; + stopped) + echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 + state_should="absent" + ;; +esac + +runs="$(cat "$__object/explorer/runs")" +if [ "$runs" ]; then + state_is="present" +else + state_is="absent" +fi + +[ "$state_is" = "$state_should" ] && exit 0 case "$state_should" in - running|present) - # Does not run, start it! - if [ -z "$runs" ]; then - if [ -f "$__object/parameter/start" ]; then + present) + if [ -f "$__object/parameter/start" ]; then cat "$__object/parameter/start" - else + else echo "$name" - fi - fi - ;; - stopped|absent) - # Runs, kill it! - if [ "$runs" ]; then + fi + ;; + absent) if [ -f "$__object/parameter/stop" ]; then cat "$__object/parameter/stop" else echo kill "${runs}" fi - fi - ;; - *) - echo "Unknown state: $state_should" >&2 - exit 1 - ;; - + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; esac diff --git a/conf/type/__process/man.text b/conf/type/__process/man.text index fbd54847..961a7f9a 100644 --- a/conf/type/__process/man.text +++ b/conf/type/__process/man.text @@ -16,7 +16,9 @@ This cdist type allows you to define the state of a process. REQUIRED PARAMETERS ------------------- state:: - State of the process: Either stopped or running. + State of the process: Either present or absent + (old values "stopped" and "running" are deprecated and will be removed in + cdist 2.1). OPTIONAL PARAMETERS @@ -40,23 +42,23 @@ EXAMPLES -------------------------------------------------------------------------------- # Start if not running -__process /usr/sbin/syslog-ng --state running +__process /usr/sbin/syslog-ng --state present # Start if not running with a different binary -__process /usr/sbin/nginx --state running --start "/etc/rc.d/nginx start" +__process /usr/sbin/nginx --state present --start "/etc/rc.d/nginx start" # Stop the process using kill (the type default) - DO NOT USE THIS -__process /usr/sbin/sshd --state stopped +__process /usr/sbin/sshd --state absent # Stop the process using /etc/rc.d/sshd stop - THIS ONE NOT AS WELL -__process /usr/sbin/sshd --state stopped --stop "/etc/rc.d/sshd stop" +__process /usr/sbin/sshd --state absent --stop "/etc/rc.d/sshd stop" # Ensure cups is running, which runs with -C ...: -__process cups --start "/etc/rc.d/cups start" --state running \ +__process cups --start "/etc/rc.d/cups start" --state present \ --name "/usr/sbin/cupsd -C /etc/cups/cupsd.conf" # Ensure rpc.statd is running (which usually runs with -L) using a regexp -__process rpcstatd --state running --start "/etc/init.d/statd start" \ +__process rpcstatd --state present --start "/etc/init.d/statd start" \ --name "rpc.statd.*" -------------------------------------------------------------------------------- @@ -68,5 +70,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is +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 ae898ac870ecd9035acc585948a0ab0faac1c84b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Feb 2012 12:21:03 +0100 Subject: [PATCH 1381/4212] +kbdirq Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-02-17.keyboardirq | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 doc/dev/logs/2012-02-17.keyboardirq diff --git a/doc/dev/logs/2012-02-17.keyboardirq b/doc/dev/logs/2012-02-17.keyboardirq new file mode 100644 index 00000000..93e62fbf --- /dev/null +++ b/doc/dev/logs/2012-02-17.keyboardirq @@ -0,0 +1,26 @@ +Somewhere there is still a race condition: + +INFO: monitoring03: Running manifest and explorers for __file/etc/yum.repos.d/epel.repo +^C^CTraceback (most recent call last): + File "./bin/cdist", line 204, in + import logging + File "/usr/lib/python3.2/logging/__init__.py", line 27, in + from string import Template + File "/usr/lib/python3.2/string.py", line 178, in + class Formatter: + File "/usr/lib/python3.2/string.py", line 179, in Formatter + def format(self, format_string, *args, **kwargs): +KeyboardInterrupt + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "./bin/cdist", line 232, in + sys.exit(0) +NameError: name 'sys' is not defined +^C^CFatal Python error: Py_Initialize: can't initialize sys standard streams +Traceback (most recent call last): + File "/usr/lib/python3.2/encodings/latin_1.py", line 8, in + """ +KeyboardInterrupt +^C% [12:19] brief:cdist% From 61666664c160dd78e179d39bf5f795785ada19c8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Feb 2012 12:51:14 +0100 Subject: [PATCH 1382/4212] ++changes(2.0.8) Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index 0bdbeb32..06a8ded4 100644 --- a/doc/changelog +++ b/doc/changelog @@ -11,6 +11,8 @@ Changelog debugging) * Cleanup: Change __package_* to support absent/present (default state name now). The values removed/installed will be removed in cdist 2.1. + * Cleanup: Change __process to support absent/present (default state + name now). The values running/stopped will be removed in cdist 2.1. * Feature Core: Support boolean parameters (Steven Armstrong) 2.0.7: 2012-02-13 From aa81486fe9caf6034560fdc8e24b2610e945a8bd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Feb 2012 13:47:00 +0100 Subject: [PATCH 1383/4212] sys.exit() in try Signed-off-by: Nico Schottelius --- bin/cdist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index 06e82cc9..971288fd 100755 --- a/bin/cdist +++ b/bin/cdist @@ -228,7 +228,7 @@ if __name__ == "__main__": else: commandline() - except KeyboardInterrupt: sys.exit(0) - sys.exit(0) + except KeyboardInterrupt: + sys.exit(0) From 5e20ba5a1354e0a530ca92f1c165322391bff320 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Feb 2012 13:59:16 +0100 Subject: [PATCH 1384/4212] ++logs, +import sys at top level Signed-off-by: Nico Schottelius --- bin/cdist | 4 +++- doc/dev/logs/2012-02-17.keyboardirq | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 971288fd..5456b134 100755 --- a/bin/cdist +++ b/bin/cdist @@ -200,11 +200,13 @@ def emulator(): sys.exit(1) if __name__ == "__main__": + # Sys is needed for sys.exit() + import sys + try: import logging import os import re - import sys cdistpythonversion = '3.2' if sys.version < cdistpythonversion: diff --git a/doc/dev/logs/2012-02-17.keyboardirq b/doc/dev/logs/2012-02-17.keyboardirq index 93e62fbf..8ce59681 100644 --- a/doc/dev/logs/2012-02-17.keyboardirq +++ b/doc/dev/logs/2012-02-17.keyboardirq @@ -24,3 +24,25 @@ Traceback (most recent call last): """ KeyboardInterrupt ^C% [12:19] brief:cdist% + + +-------------------------------------------------------------------------------- +[13:50] brief:cdist% ./bin/cdist config -vp monitoring02 +INFO: monitoring02: Running global explorers +INFO: monitoring02: Running initial manifest /home/users/nico/privat/firmen/local.ch/vcs/cdist/conf/manifest +INFO: monitoring02: Running object manifests and type explorers +INFO: monitoring02: Running manifest and explorers for __localch_shinken/singleton +^CTraceback (most recent call last): + File "/usr/lib/python3.2/site.py", line 58, in + import traceback + File "/usr/lib/python3.2/traceback.py", line 3, in + import linecache + File "/usr/lib/python3.2/linecache.py", line 10, in + import tokenize + File "/usr/lib/python3.2/tokenize.py", line 49, in + class TokenInfo(collections.namedtuple('TokenInfo', 'type string start end line')): + File "/usr/lib/python3.2/collections.py", line 363, in namedtuple + exec(class_definition, namespace) + File "", line 1, in +KeyboardInterrupt + From 1dfb5872644d5dcc1ae207586b970419a4ba4047 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Feb 2012 14:07:00 +0100 Subject: [PATCH 1385/4212] ++changes(2.0.8) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 06a8ded4..cb72068e 100644 --- a/doc/changelog +++ b/doc/changelog @@ -5,6 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius 2.0.8: + * Bugfix core: Remove another nasty traceback when sending SIGINT (aka Ctrl-C) * Cleanup: Better hint to source of error * Cleanup: Do not output failing script, but path to script only * Cleanup: Remove support for __debug variable in manifests (Type != Core From 39417fee8f9487565f94bdba81dbec001e774eae Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Feb 2012 14:15:38 +0100 Subject: [PATCH 1386/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index b40936f6..3007cedb 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -37,3 +37,4 @@ TYPES - Add testing framework (proposed by Evax Software) - __user add option to include --create-home +- Merge __addifnosuchline and __removeline into __line + --state present|absent From ff5d0fd7fc621e9f2478aec1648808df118554e2 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Fri, 17 Feb 2012 11:29:12 -0500 Subject: [PATCH 1387/4212] Removed newly-developed types for inclusion in separate branches. --- conf/type/__build/man.text | 56 -------- conf/type/__build/manifest | 46 ------ conf/type/__build/parameter/optional | 2 - conf/type/__build_port_freebsd/gencode-remote | 69 --------- conf/type/__build_port_freebsd/man.text | 61 -------- .../__build_port_freebsd/parameter/optional | 1 - .../explorer/pkg_version | 35 ----- .../type/__package_pkg_freebsd/gencode-remote | 135 ------------------ conf/type/__package_pkg_freebsd/man.text | 64 --------- .../__package_pkg_freebsd/parameter/optional | 4 - .../__package_pkg_freebsd/parameter/required | 1 - conf/type/__rsyncer/gencode-local | 71 --------- conf/type/__rsyncer/man.text | 72 ---------- conf/type/__rsyncer/manifest | 31 ---- conf/type/__rsyncer/parameter/optional | 3 - conf/type/__rsyncer/parameter/required | 1 - conf/type/__service/gencode-remote | 98 ------------- conf/type/__service/man.text | 48 ------- conf/type/__service/parameter/required | 1 - 19 files changed, 799 deletions(-) delete mode 100644 conf/type/__build/man.text delete mode 100755 conf/type/__build/manifest delete mode 100644 conf/type/__build/parameter/optional delete mode 100755 conf/type/__build_port_freebsd/gencode-remote delete mode 100644 conf/type/__build_port_freebsd/man.text delete mode 100644 conf/type/__build_port_freebsd/parameter/optional delete mode 100755 conf/type/__package_pkg_freebsd/explorer/pkg_version delete mode 100755 conf/type/__package_pkg_freebsd/gencode-remote delete mode 100644 conf/type/__package_pkg_freebsd/man.text delete mode 100644 conf/type/__package_pkg_freebsd/parameter/optional delete mode 100644 conf/type/__package_pkg_freebsd/parameter/required delete mode 100755 conf/type/__rsyncer/gencode-local delete mode 100644 conf/type/__rsyncer/man.text delete mode 100755 conf/type/__rsyncer/manifest delete mode 100644 conf/type/__rsyncer/parameter/optional delete mode 100644 conf/type/__rsyncer/parameter/required delete mode 100755 conf/type/__service/gencode-remote delete mode 100644 conf/type/__service/man.text delete mode 100644 conf/type/__service/parameter/required diff --git a/conf/type/__build/man.text b/conf/type/__build/man.text deleted file mode 100644 index 1a297ec2..00000000 --- a/conf/type/__build/man.text +++ /dev/null @@ -1,56 +0,0 @@ -cdist-type__build(7) -=================== -Jake Guffey - - -NAME ----- -cdist-type__build - Manage software build operations - - -DESCRIPTION ------------ -This cdist type allows you to build software on the target. -It dispatches the actual work to the build-dependant types. - - -REQUIRED PARAMETERS -------------------- -None. - -OPTIONAL PARAMETERS -------------------- -name:: - The name of the software to build. Default is to use the object_id. -type:: - The build type to use. Default is to build a port for direct installation - on the target host. - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Build and install a port -__build vim - -# Build and install a port explicitly defining to use ports -__build vim --type port_freebsd - -# Build a package to install via __package on another machine -__build vim --type pkg_freebsd - -# Force use of a specific package type -__build nanobsd --name nanobsd-internaluse-9.0 --type nanobsd --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2012 Jake Guffey. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__build/manifest b/conf/type/__build/manifest deleted file mode 100755 index c8392d35..00000000 --- a/conf/type/__build/manifest +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh -# -# 2012 Jake Guffey (jake.guffey at eprotex.com) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# __build is an abstract type which dispatches to the lower level -# __build_$name types which do the actual interaction with the software -# build system. -# - -if [ -f "$__object/parameter/name" ]; then - name="$(cat "$__object/parameter/name")" -else - name="$__object_id" -fi - -if [ -f "$__object/parameter/type" ]; then - type="$(cat "$__object/parameter/type")" -else - type="port_freebsd" -fi - -set -- "$@" "$__object_id" -cd "$__object/parameter" -for property in $(ls .); do - if [ "$property" != "type" ]; then - set -- "$@" "--$property" "$(cat "$property")" - fi -done - -__build_$type "$@" diff --git a/conf/type/__build/parameter/optional b/conf/type/__build/parameter/optional deleted file mode 100644 index d3598a51..00000000 --- a/conf/type/__build/parameter/optional +++ /dev/null @@ -1,2 +0,0 @@ -name -type diff --git a/conf/type/__build_port_freebsd/gencode-remote b/conf/type/__build_port_freebsd/gencode-remote deleted file mode 100755 index ff0432ba..00000000 --- a/conf/type/__build_port_freebsd/gencode-remote +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/sh -# -# 2012 Jake Guffey (jake.guffey at eprotex.com) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Build ports on FreeBSD -# - -assert () # If condition false, -{ #+ exit from script with error message. - E_PARAM_ERR=98 - E_ASSERT_FAILED=99 - - if [ -z "$2" ] # Not enough parameters passed. - then - return $E_PARAM_ERR # No damage done. - fi - - lineno=$2 - - if [ ! $1 ] - then - echo "Assertion failed: \"$1\"" - echo "File \"$0\", line $lineno, called by $(caller 0)" - exit $E_ASSERT_FAILED - fi -} - -# Debug -#exec >&2 -#set -x - -if [ -f "$__object/parameter/name" ]; then - name="$__object/parameter/name" -else - name="$__object_id" -fi - -# Get list of installed ports -installed="$(cat "$__object/explorer/installed")" - -# Is port already built/installed? Check /var/db/ports -for PORT in $installed; do - if [ "$(eval "$PORT" : "$name")" != 0 ]; then # already installed - exit 0; - fi -done - -# If not, build -echo "cd /usr/ports && " - -# Debug -#set +x - diff --git a/conf/type/__build_port_freebsd/man.text b/conf/type/__build_port_freebsd/man.text deleted file mode 100644 index 7ce6042b..00000000 --- a/conf/type/__build_port_freebsd/man.text +++ /dev/null @@ -1,61 +0,0 @@ -cdist-type__package_pkg_freebsd(7) -================================== -Jake Guffey - - -NAME ----- -cdist-type__package_pkg_freebsd - Manage FreeBSD packages - - -DESCRIPTION ------------ -This type is usually used on FreeBSD to manage packages. - - -REQUIRED PARAMETERS -------------------- -state:: - Either "installed" or "removed". - - -OPTIONAL PARAMETERS -------------------- -name:: - If supplied, use the name and not the object id as the package name. - -flavor:: - If supplied, use to avoid ambiguity. - -version:: - If supplied, use to install a specific version of the package named. - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Ensure zsh is installed -__package_pkg_freebsd zsh --state installed - -# Ensure vim is installed, use flavor no_x11 -__package_pkg_freebsd vim --state installed --flavor no_x11 - -# If you don't want to follow pythonX packages, but always use python -__package_pkg_freebsd python --state installed --name python2 - -# Remove obsolete package -__package_pkg_freebsd puppet --state removed --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- cdist-type__package(7) - - -COPYING -------- -Copyright \(C) 2012 Jake Guffey. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__build_port_freebsd/parameter/optional b/conf/type/__build_port_freebsd/parameter/optional deleted file mode 100644 index f121bdbf..00000000 --- a/conf/type/__build_port_freebsd/parameter/optional +++ /dev/null @@ -1 +0,0 @@ -name diff --git a/conf/type/__package_pkg_freebsd/explorer/pkg_version b/conf/type/__package_pkg_freebsd/explorer/pkg_version deleted file mode 100755 index 4bca24b6..00000000 --- a/conf/type/__package_pkg_freebsd/explorer/pkg_version +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh -# -# 2012 Jake Guffey (jake.guffey at eprotex.com) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Retrieve the status of a package - parsed dpkg output -# - -if [ -f "$__object/parameter/name" ]; then - name="$(cat "$__object/parameter/name")" -else - name="$__object_id" -fi - -# Don't produce "no pkgs installed" output -- breaks things -PKG_OUTPUT=$(pkg_info 2>&1) -if [ ! "$PKG_OUTPUT" = "pkg_info: no packages installed" ]; then - echo "$(echo "$PKG_OUTPUT" | grep "^$name-" | cut '-d ' -f1 | sed "s/$name-//g")" -fi - diff --git a/conf/type/__package_pkg_freebsd/gencode-remote b/conf/type/__package_pkg_freebsd/gencode-remote deleted file mode 100755 index 4d3c9844..00000000 --- a/conf/type/__package_pkg_freebsd/gencode-remote +++ /dev/null @@ -1,135 +0,0 @@ -#!/bin/sh -# -# 2012 Jake Guffey (jake.guffey at eprotex.com) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Manage packages with pkg on FreeBSD -# - -assert () # If condition false, -{ #+ exit from script with error message. - E_PARAM_ERR=98 - E_ASSERT_FAILED=99 - - if [ -z "$2" ] # Not enough parameters passed. - then - return $E_PARAM_ERR # No damage done. - fi - - lineno=$2 - - if [ ! $1 ] - then - echo "Assertion failed: \"$1\"" - echo "File \"$0\", line $lineno, called by $(caller 0)" - exit $E_ASSERT_FAILED - fi -} - -# Debug -#exec >&2 -#set -x - -if [ -f "$__object/parameter/name" ]; then - name="$(cat "$__object/parameter/name")" -else - name="$__object_id" -fi - -if [ -f "$__object/parameter/flavor" ]; then - flavor="$(cat "$__object/parameter/flavor")" -fi - -if [ -f "$__object/parameter/version" ]; then - version="$(cat "$__object/parameter/version")" -fi - -if [ -f "$__object/parameter/pkgsite" ]; then - pkgsite="$(cat "$__object/parameter/pkgsite")" -fi - -state="$(cat "$__object/parameter/state")" -curr_version="$(cat "$__object/explorer/pkg_version")" -add_cmd="pkg_add" -rm_cmd="pkg_delete" -cmd="" - -# Print the command to be executed -# Parms: $1 -- mode, "remove" or "add" -# $2 -- the command to be echoed -# FIXME: This is ugly. -execcmd(){ - # Set the PACKAGESITE if we're ADDing a new package - if [ "$1" = "add" -a -n "$pkgsite" ]; then - # Use http.../All/ if we know the exact version we want, use .../Latest/ otherwise - [ -n "$version" ] && pkgsite="${pkgsite}/All/" || pkgsite="${pkgsite}/Latest/" - echo "${pkgsite}" - fi - echo "${2} 2>&- >&-" # Silence the output of the command - echo "status=\$?" - echo "if [ \"\$status\" -ne \"0\" ]; then" - echo " echo \"Error: ${cmd} exited nonzero with \$status\"'!' >&2" - echo " exit 1" - echo "fi" -} - -if [ -n "$curr_version" ]; then # PKG *is* installed - if [ "$state" = "removed" ]; then # Shouldn't be installed - if [ -n "$flavor" ]; then - cmd="${rm_cmd} ${name}-${flavor}-${curr_version}" - else - cmd="${rm_cmd} ${name}-${curr_version}" - fi - execcmd "remove" "${cmd}" - exit 0 - else # Should be installed - if [ -n "$version" ]; then # Want a specific version - if [ "$version" = "$curr_version" ]; then # Current version is correct - exit 0 - else # Current version is wrong, fix - #updatepkg "$name" "$version" - assert "! ${version} = ${curr_version}" $LINENO - cmd="${rm_cmd} ${name}-${curr_version}" - execcmd "remove" "${cmd}" - cmd="${add_cmd} ${name}-${version}" - execcmd "add" "${cmd}" - fi - else # Don't care what version to use - exit 0 - fi - fi -else # PKG *isn't* installed - if [ "$state" = "removed" ]; then # Shouldn't be installed - exit 0 - elif [ "$state" = "installed" ]; then # Is not currently installed, should be - if [ -n "$flavor" ]; then - cmd="${add_cmd} -r ${name}-${flavor}" - else - cmd="${add_cmd} -r ${name}" - fi - if [ -n "$version" ]; then - cmd="${cmd}-${version}" - fi - execcmd "add" "${cmd}" - exit 0 - fi -fi - -# Debug -#set +x - diff --git a/conf/type/__package_pkg_freebsd/man.text b/conf/type/__package_pkg_freebsd/man.text deleted file mode 100644 index 882bece9..00000000 --- a/conf/type/__package_pkg_freebsd/man.text +++ /dev/null @@ -1,64 +0,0 @@ -cdist-type__package_pkg_freebsd(7) -================================== -Jake Guffey - - -NAME ----- -cdist-type__package_pkg_freebsd - Manage FreeBSD packages - - -DESCRIPTION ------------ -This type is usually used on FreeBSD to manage packages. - - -REQUIRED PARAMETERS -------------------- -state:: - Either "installed" or "removed". - - -OPTIONAL PARAMETERS -------------------- -name:: - If supplied, use the name and not the object id as the package name. - -flavor:: - If supplied, use to avoid ambiguity. - -version:: - If supplied, use to install a specific version of the package named. - -pkgsite:: - If supplied, use to install from a specific package repository. - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Ensure zsh is installed -__package_pkg_freebsd zsh --state installed - -# Ensure vim is installed, use flavor no_x11 -__package_pkg_freebsd vim --state installed --flavor no_x11 - -# If you don't want to follow pythonX packages, but always use python -__package_pkg_freebsd python --state installed --name python2 - -# Remove obsolete package -__package_pkg_freebsd puppet --state removed --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- cdist-type__package(7) - - -COPYING -------- -Copyright \(C) 2012 Jake Guffey. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__package_pkg_freebsd/parameter/optional b/conf/type/__package_pkg_freebsd/parameter/optional deleted file mode 100644 index 3fb2f29e..00000000 --- a/conf/type/__package_pkg_freebsd/parameter/optional +++ /dev/null @@ -1,4 +0,0 @@ -name -flavor -version -pkgsite diff --git a/conf/type/__package_pkg_freebsd/parameter/required b/conf/type/__package_pkg_freebsd/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/conf/type/__package_pkg_freebsd/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state diff --git a/conf/type/__rsyncer/gencode-local b/conf/type/__rsyncer/gencode-local deleted file mode 100755 index 515ab71b..00000000 --- a/conf/type/__rsyncer/gencode-local +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/sh -# -# Copyright (C) 2011 Daniel Maher (phrawzty+cdist at gmail.com) -# Parts copyright (C) 2012 Jake Guffey (jake.guffey at eprotex.com) -# -# This file is part of cdist (https://github.com/telmich/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 . -# - -# Debug -#exec >&2 -#set -x - -source="$(cat "$__object/parameter/source")" - -if [ -f "$__object/parameter/destination" ]; then - destination="$(cat "$__object/parameter/destination")" -else - destination="/$__object_id" -fi - -# The system binary is probably ok, but if not... -if [ -f "$__object/parameter/rsyncbin" ]; then - rsyncbin="$(cat "$__object/parameter/rsyncbin")" -else - rsyncbin=`which rsync` -fi - -# Turned this into an array so that we can use the "-e" argument to get the -# "root@" stuff fixed and so that "ssh -l root" is a single arg (as rsync -# wants it to be). -args=('-a' '-e' '"ssh -l root"') - -# If the --delete argument should be passed to rsync. -if [ -f "$__object/parameter/delete" ]; then -# This is from having args defined as an array previously. ${#args[@]} -# is the number of indices in args, and args[${#args[@]}]=... creates a -# new index of args, which is then filled with "--delete." - args[${#args[@]}]="--delete" -fi - -cmd="${rsyncbin} ${args[@]} \"${source}\"" - -# If the --chroot argument was given -if [ -f "$__object/parameter/chroot" ]; then - chroot=$(cat $__object/parameter/chroot) - cmd="${cmd} \"$chroot/$destination\"" -else - cmd="${cmd} \"$__target_host:$destination\"" -fi - -# FIXME: -# - align with __remote_{exec,copy} variables? -- done - -# Run rsync (locally). -echo "${cmd}" - -#set +x - diff --git a/conf/type/__rsyncer/man.text b/conf/type/__rsyncer/man.text deleted file mode 100644 index 18218181..00000000 --- a/conf/type/__rsyncer/man.text +++ /dev/null @@ -1,72 +0,0 @@ -cdist-type__rsyncer(7) -====================== -Daniel Maher -Jake Guffey - - -NAME ----- -cdist-type__rsyncer - Use rsync to copy files. - - -DESCRIPTION ------------ -This type is used to trigger rsync to copy files from the machine running cdist -(source) to the target machine in question (destination). The likely usage is -the rapid deployment of full directory trees, the cohorency of which can be -guarunteed with the optional --delete argument, which will remove any files -from the destination which are not present on the source. - - -REQUIRED PARAMETERS -------------------- -source:: - The full path of the source from which to copy. This is passed directly - to rsync. - - -OPTIONAL PARAMETERS -------------------- -destination:: - The full path of the destination. This is passed directly to rsync. - Default: object_id - -delete:: - If true, remove files from destination which are not in source. This is - effectively the --delete argument of rsync. - Default: false - -rsyncbin:: - Specify the full path to the rsync binary. - Default: `which rsync` - -chroot:: - Specify the use of a chroot environment. If given, rsync copies the source - to $chroot/$destination. - Default: none - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Basic example -__rsyncer '/home/foo' --source '/opt/dist/foo' - -# Fancier example -__rsyncer FOO --source '/opt/dist/foo' --destination '/home/foo/' --delete true - -# Chroot example -__rsyncer '/home/foo' --source '/opt/dist/foo' --chroot '/usr/chroot/home' --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2011-2012 Daniel Maher, Jake Guffey. Free use of this software -is granted under the terms of the GNU General Public License version 3 (GPLv3). - diff --git a/conf/type/__rsyncer/manifest b/conf/type/__rsyncer/manifest deleted file mode 100755 index fb884bc1..00000000 --- a/conf/type/__rsyncer/manifest +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -# -# Copyright (C) 2012 Jake Guffey (jake.guffey at eprotex.com) -# -# This file is part of cdist (https://github.com/telmich/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 . -# - -# Debug -#exec >&2 -#set -x - -# This type has a dependency of the rsync package on the "other" side. -# Ensure that it's installed. -__package rsync --state installed - -# Debug -#set +x - diff --git a/conf/type/__rsyncer/parameter/optional b/conf/type/__rsyncer/parameter/optional deleted file mode 100644 index 3bcb4dc7..00000000 --- a/conf/type/__rsyncer/parameter/optional +++ /dev/null @@ -1,3 +0,0 @@ -destination -delete -rsyncbin diff --git a/conf/type/__rsyncer/parameter/required b/conf/type/__rsyncer/parameter/required deleted file mode 100644 index 5a18cd2f..00000000 --- a/conf/type/__rsyncer/parameter/required +++ /dev/null @@ -1 +0,0 @@ -source diff --git a/conf/type/__service/gencode-remote b/conf/type/__service/gencode-remote deleted file mode 100755 index 85bd981c..00000000 --- a/conf/type/__service/gencode-remote +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/sh -# -# 2012 Jake Guffey (jake.guffey at eprotex.com) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# - -# Debug -#exec >&2 -#set -x - -state="$(cat "$__object/parameter/status")" - -### Begin forming $cmd -cmd="" -cmd="$(cat <&2 - exit -1 -fi - -status="\$("\$exists" status || true)" -if [ "\$(expr "\$status" : "Cannot 'status' \$name. Set \${name}_enable to YES")" != "0" ]; then - echo "Can't status \$name. Set \${name}_enable to YES first in rc.conf on \$__target_host." >&2 - exit -1 -fi - -EOF)" -### End forming $cmd - -### Begin forming $running -running="$(cat <&- >&- -elif [ \$(expr "\$status" : ".*not running.*") != "0" ]; then - "\$exists" start 2>&- >&- -elif [ \$(expr "\$status" : ".*dead.*") != "0" ]; then - "\$exists" restart 2>&- >&- -fi -EOF)" -### End forming $running - -### Begin forming $stopped -stopped="$(cat <&- >&- - fi -EOF)" -### End forming $stopped - -case "$state" in - running) - cmd="$(echo "${cmd}\n${running}")" - ;; - stopped) - cmd="$(echo "${cmd}\n${stopped}")" - ;; - *) - echo "Unknown state: ${state}" >&2 - exit 1 - ;; -esac - -echo "${cmd}" - -# Debug -#set +x - diff --git a/conf/type/__service/man.text b/conf/type/__service/man.text deleted file mode 100644 index 9b55a18f..00000000 --- a/conf/type/__service/man.text +++ /dev/null @@ -1,48 +0,0 @@ -cdist-type__service(7) -====================== -Jake Guffey - - -NAME ----- -cdist-type__service - Control a system service (daemon) state - - -DESCRIPTION ------------ -This cdist type allows you to control the state of a service (daemon). - - -REQUIRED PARAMETERS -------------------- -state:: - State of the service: Either stopped or running. - - -OPTIONAL PARAMETERS -------------------- -None. - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Start if not running -__service syslog-ng --state running - -# Stop the process if it is running -__service sshd --state stopped - --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2012 Jake Guffey. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__service/parameter/required b/conf/type/__service/parameter/required deleted file mode 100644 index 8be5547d..00000000 --- a/conf/type/__service/parameter/required +++ /dev/null @@ -1 +0,0 @@ -status From ffec26d462ac4f3acb3ebcf449b48396978d81a9 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Fri, 17 Feb 2012 11:30:21 -0500 Subject: [PATCH 1388/4212] Removed __package_pkg_freebsd customization from __package type for inclusion in a separate branch. --- conf/type/__package/manifest | 1 - 1 file changed, 1 deletion(-) diff --git a/conf/type/__package/manifest b/conf/type/__package/manifest index 7e0d7080..181da077 100755 --- a/conf/type/__package/manifest +++ b/conf/type/__package/manifest @@ -34,7 +34,6 @@ else debian|ubuntu) type="apt" ;; gentoo) type="emerge" ;; amazon|centos|fedora|redhat) type="yum" ;; - freebsd) type="pkg_freebsd" ;; *) echo "Don't know how to manage packages on: $os" >&2 exit 1 From 1d5b7cef9c5ec0179bae5b52268ddd3f8b1fcf02 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Fri, 17 Feb 2012 11:35:31 -0500 Subject: [PATCH 1389/4212] Moved __package_pkg_freebsd to separate branch --- .../explorer/pkg_version | 35 +++++ .../type/__package_pkg_freebsd/gencode-remote | 135 ++++++++++++++++++ conf/type/__package_pkg_freebsd/man.text | 64 +++++++++ .../__package_pkg_freebsd/parameter/optional | 4 + .../__package_pkg_freebsd/parameter/required | 1 + 5 files changed, 239 insertions(+) create mode 100755 conf/type/__package_pkg_freebsd/explorer/pkg_version create mode 100755 conf/type/__package_pkg_freebsd/gencode-remote create mode 100644 conf/type/__package_pkg_freebsd/man.text create mode 100644 conf/type/__package_pkg_freebsd/parameter/optional create mode 100644 conf/type/__package_pkg_freebsd/parameter/required diff --git a/conf/type/__package_pkg_freebsd/explorer/pkg_version b/conf/type/__package_pkg_freebsd/explorer/pkg_version new file mode 100755 index 00000000..4bca24b6 --- /dev/null +++ b/conf/type/__package_pkg_freebsd/explorer/pkg_version @@ -0,0 +1,35 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Retrieve the status of a package - parsed dpkg output +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +# Don't produce "no pkgs installed" output -- breaks things +PKG_OUTPUT=$(pkg_info 2>&1) +if [ ! "$PKG_OUTPUT" = "pkg_info: no packages installed" ]; then + echo "$(echo "$PKG_OUTPUT" | grep "^$name-" | cut '-d ' -f1 | sed "s/$name-//g")" +fi + diff --git a/conf/type/__package_pkg_freebsd/gencode-remote b/conf/type/__package_pkg_freebsd/gencode-remote new file mode 100755 index 00000000..4d3c9844 --- /dev/null +++ b/conf/type/__package_pkg_freebsd/gencode-remote @@ -0,0 +1,135 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Manage packages with pkg on FreeBSD +# + +assert () # If condition false, +{ #+ exit from script with error message. + E_PARAM_ERR=98 + E_ASSERT_FAILED=99 + + if [ -z "$2" ] # Not enough parameters passed. + then + return $E_PARAM_ERR # No damage done. + fi + + lineno=$2 + + if [ ! $1 ] + then + echo "Assertion failed: \"$1\"" + echo "File \"$0\", line $lineno, called by $(caller 0)" + exit $E_ASSERT_FAILED + fi +} + +# Debug +#exec >&2 +#set -x + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +if [ -f "$__object/parameter/flavor" ]; then + flavor="$(cat "$__object/parameter/flavor")" +fi + +if [ -f "$__object/parameter/version" ]; then + version="$(cat "$__object/parameter/version")" +fi + +if [ -f "$__object/parameter/pkgsite" ]; then + pkgsite="$(cat "$__object/parameter/pkgsite")" +fi + +state="$(cat "$__object/parameter/state")" +curr_version="$(cat "$__object/explorer/pkg_version")" +add_cmd="pkg_add" +rm_cmd="pkg_delete" +cmd="" + +# Print the command to be executed +# Parms: $1 -- mode, "remove" or "add" +# $2 -- the command to be echoed +# FIXME: This is ugly. +execcmd(){ + # Set the PACKAGESITE if we're ADDing a new package + if [ "$1" = "add" -a -n "$pkgsite" ]; then + # Use http.../All/ if we know the exact version we want, use .../Latest/ otherwise + [ -n "$version" ] && pkgsite="${pkgsite}/All/" || pkgsite="${pkgsite}/Latest/" + echo "${pkgsite}" + fi + echo "${2} 2>&- >&-" # Silence the output of the command + echo "status=\$?" + echo "if [ \"\$status\" -ne \"0\" ]; then" + echo " echo \"Error: ${cmd} exited nonzero with \$status\"'!' >&2" + echo " exit 1" + echo "fi" +} + +if [ -n "$curr_version" ]; then # PKG *is* installed + if [ "$state" = "removed" ]; then # Shouldn't be installed + if [ -n "$flavor" ]; then + cmd="${rm_cmd} ${name}-${flavor}-${curr_version}" + else + cmd="${rm_cmd} ${name}-${curr_version}" + fi + execcmd "remove" "${cmd}" + exit 0 + else # Should be installed + if [ -n "$version" ]; then # Want a specific version + if [ "$version" = "$curr_version" ]; then # Current version is correct + exit 0 + else # Current version is wrong, fix + #updatepkg "$name" "$version" + assert "! ${version} = ${curr_version}" $LINENO + cmd="${rm_cmd} ${name}-${curr_version}" + execcmd "remove" "${cmd}" + cmd="${add_cmd} ${name}-${version}" + execcmd "add" "${cmd}" + fi + else # Don't care what version to use + exit 0 + fi + fi +else # PKG *isn't* installed + if [ "$state" = "removed" ]; then # Shouldn't be installed + exit 0 + elif [ "$state" = "installed" ]; then # Is not currently installed, should be + if [ -n "$flavor" ]; then + cmd="${add_cmd} -r ${name}-${flavor}" + else + cmd="${add_cmd} -r ${name}" + fi + if [ -n "$version" ]; then + cmd="${cmd}-${version}" + fi + execcmd "add" "${cmd}" + exit 0 + fi +fi + +# Debug +#set +x + diff --git a/conf/type/__package_pkg_freebsd/man.text b/conf/type/__package_pkg_freebsd/man.text new file mode 100644 index 00000000..882bece9 --- /dev/null +++ b/conf/type/__package_pkg_freebsd/man.text @@ -0,0 +1,64 @@ +cdist-type__package_pkg_freebsd(7) +================================== +Jake Guffey + + +NAME +---- +cdist-type__package_pkg_freebsd - Manage FreeBSD packages + + +DESCRIPTION +----------- +This type is usually used on FreeBSD to manage packages. + + +REQUIRED PARAMETERS +------------------- +state:: + Either "installed" or "removed". + + +OPTIONAL PARAMETERS +------------------- +name:: + If supplied, use the name and not the object id as the package name. + +flavor:: + If supplied, use to avoid ambiguity. + +version:: + If supplied, use to install a specific version of the package named. + +pkgsite:: + If supplied, use to install from a specific package repository. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure zsh is installed +__package_pkg_freebsd zsh --state installed + +# Ensure vim is installed, use flavor no_x11 +__package_pkg_freebsd vim --state installed --flavor no_x11 + +# If you don't want to follow pythonX packages, but always use python +__package_pkg_freebsd python --state installed --name python2 + +# Remove obsolete package +__package_pkg_freebsd puppet --state removed +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__package(7) + + +COPYING +------- +Copyright \(C) 2012 Jake Guffey. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__package_pkg_freebsd/parameter/optional b/conf/type/__package_pkg_freebsd/parameter/optional new file mode 100644 index 00000000..3fb2f29e --- /dev/null +++ b/conf/type/__package_pkg_freebsd/parameter/optional @@ -0,0 +1,4 @@ +name +flavor +version +pkgsite diff --git a/conf/type/__package_pkg_freebsd/parameter/required b/conf/type/__package_pkg_freebsd/parameter/required new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/conf/type/__package_pkg_freebsd/parameter/required @@ -0,0 +1 @@ +state From 5443d1a64a6cf75e76c69ed3293c7f7c3fae9859 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Fri, 17 Feb 2012 11:35:59 -0500 Subject: [PATCH 1390/4212] Modified __package to utilize __package_pkg_freebsd --- conf/type/__package/manifest | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/type/__package/manifest b/conf/type/__package/manifest index 181da077..7e0d7080 100755 --- a/conf/type/__package/manifest +++ b/conf/type/__package/manifest @@ -34,6 +34,7 @@ else debian|ubuntu) type="apt" ;; gentoo) type="emerge" ;; amazon|centos|fedora|redhat) type="yum" ;; + freebsd) type="pkg_freebsd" ;; *) echo "Don't know how to manage packages on: $os" >&2 exit 1 From b7e33782623f68a3cd83b6c5d96a79f09fab28d6 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Fri, 17 Feb 2012 12:18:06 -0500 Subject: [PATCH 1391/4212] Modified __package to allow pkgsite param, bugfix in __package_pkg_freebsd where it wasn't setting the PACKAGESITE variable on remote side. --- conf/type/__package/parameter/optional | 1 + conf/type/__package_pkg_freebsd/gencode-remote | 1 + 2 files changed, 2 insertions(+) diff --git a/conf/type/__package/parameter/optional b/conf/type/__package/parameter/optional index 712ea892..6f793411 100644 --- a/conf/type/__package/parameter/optional +++ b/conf/type/__package/parameter/optional @@ -1,3 +1,4 @@ name version type +pkgsite diff --git a/conf/type/__package_pkg_freebsd/gencode-remote b/conf/type/__package_pkg_freebsd/gencode-remote index 4d3c9844..022c727a 100755 --- a/conf/type/__package_pkg_freebsd/gencode-remote +++ b/conf/type/__package_pkg_freebsd/gencode-remote @@ -77,6 +77,7 @@ execcmd(){ # Set the PACKAGESITE if we're ADDing a new package if [ "$1" = "add" -a -n "$pkgsite" ]; then # Use http.../All/ if we know the exact version we want, use .../Latest/ otherwise + pkgsite="export PACKAGESITE=${pkgsite}" [ -n "$version" ] && pkgsite="${pkgsite}/All/" || pkgsite="${pkgsite}/Latest/" echo "${pkgsite}" fi From d5b015b268280470602d70dd8814a7ae4bc5a26b Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Fri, 17 Feb 2012 14:13:55 -0500 Subject: [PATCH 1392/4212] Initial commit. Placeholder files. --- conf/type/__jail/gencode-remote | 0 conf/type/__jail/man.text | 0 conf/type/__jail/parameter/optional | 0 conf/type/__jail/parameter/required | 0 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 conf/type/__jail/gencode-remote create mode 100644 conf/type/__jail/man.text create mode 100644 conf/type/__jail/parameter/optional create mode 100644 conf/type/__jail/parameter/required diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote new file mode 100644 index 00000000..e69de29b diff --git a/conf/type/__jail/man.text b/conf/type/__jail/man.text new file mode 100644 index 00000000..e69de29b diff --git a/conf/type/__jail/parameter/optional b/conf/type/__jail/parameter/optional new file mode 100644 index 00000000..e69de29b diff --git a/conf/type/__jail/parameter/required b/conf/type/__jail/parameter/required new file mode 100644 index 00000000..e69de29b From ff5c97342b37069d88bfd64f539ec9e150567333 Mon Sep 17 00:00:00 2001 From: Benedikt Koeppel Date: Sat, 18 Feb 2012 20:40:03 +0100 Subject: [PATCH 1393/4212] new type "__mysql_server" installs a MySQL server and performs some basic security changes. --- conf/type/__mysql_server/files/my.cnf | 1 + conf/type/__mysql_server/man.text | 43 ++++++++++++++++ conf/type/__mysql_server/manifest | 57 +++++++++++++++++++++ conf/type/__mysql_server/parameter/required | 1 + conf/type/__mysql_server/singleton | 0 5 files changed, 102 insertions(+) create mode 100644 conf/type/__mysql_server/files/my.cnf create mode 100644 conf/type/__mysql_server/man.text create mode 100755 conf/type/__mysql_server/manifest create mode 100644 conf/type/__mysql_server/parameter/required create mode 100644 conf/type/__mysql_server/singleton diff --git a/conf/type/__mysql_server/files/my.cnf b/conf/type/__mysql_server/files/my.cnf new file mode 100644 index 00000000..bd651c46 --- /dev/null +++ b/conf/type/__mysql_server/files/my.cnf @@ -0,0 +1 @@ +[client] diff --git a/conf/type/__mysql_server/man.text b/conf/type/__mysql_server/man.text new file mode 100644 index 00000000..e1bcc5a5 --- /dev/null +++ b/conf/type/__mysql_server/man.text @@ -0,0 +1,43 @@ +cdist-type__issue(7) +==================== +Benedikt Koeppel + + +NAME +---- +cdist-type__mysql_server - Manage a MySQL server + + +DESCRIPTION +----------- +This cdist type allows you to install a MySQL database server. + + +REQUIRED PARAMETERS +------------------- +password:: + The root password to set. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__mysql_server "mysql-server" --password "Uu9jooKe" +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2012 Benedikt Koeppel. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__mysql_server/manifest b/conf/type/__mysql_server/manifest new file mode 100755 index 00000000..88a585da --- /dev/null +++ b/conf/type/__mysql_server/manifest @@ -0,0 +1,57 @@ +#!/bin/sh +# +# 2012 Benedikt Koeppel (code@benediktkoeppel.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +# install mysql-server +__package mysql-server --state installed + +# store the root password in /root/.my.cnf so that processes can connect +# to the database without requiring a passwort input +rootpassword="$(cat "$__object/parameter/password")" +__file "/root/.my.cnf" --group root --user root --mode 600 --source "$__type/files/my.cnf" +require="__file/root/.my.cnf" \ + __addifnosuchline "/root/.my.cnf" --line "password=$rootpassword" + +# set root password +mysqladmin -u root password $rootpassword + +# remove anonymous users +mysql -u root -p <<-EOF + DELETE FROM mysql.user WHERE User=''; +EOF + +# remove remote-access for root +mysql -u root -p <<-EOF + DELETE FROM mysql.user WHERE User='root' AND Host!='localhost'; +EOF + +# remove test database +mysql -u root -p <<-EOF + DROP DATABASE test; +EOF +mysql -u root -p <<-EOF + DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%' +EOF + +# flush privileges +mysql -u root -p <<-EOF + FLUSH PRIVILEGES; +EOF + diff --git a/conf/type/__mysql_server/parameter/required b/conf/type/__mysql_server/parameter/required new file mode 100644 index 00000000..f3097ab1 --- /dev/null +++ b/conf/type/__mysql_server/parameter/required @@ -0,0 +1 @@ +password diff --git a/conf/type/__mysql_server/singleton b/conf/type/__mysql_server/singleton new file mode 100644 index 00000000..e69de29b From b6a0d55c0b7d7c55d0b1d561de88298d9db92dbd Mon Sep 17 00:00:00 2001 From: Benedikt Koeppel Date: Sat, 18 Feb 2012 20:47:04 +0100 Subject: [PATCH 1394/4212] fixed title in mysql_server man page --- conf/type/__mysql_server/man.text | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/type/__mysql_server/man.text b/conf/type/__mysql_server/man.text index e1bcc5a5..92163fa3 100644 --- a/conf/type/__mysql_server/man.text +++ b/conf/type/__mysql_server/man.text @@ -1,5 +1,5 @@ -cdist-type__issue(7) -==================== +cdist-type__mysql_server(7) +=========================== Benedikt Koeppel From 01619614d4b16425deeb107aa41f783f0e118d12 Mon Sep 17 00:00:00 2001 From: Benedikt Koeppel Date: Sat, 18 Feb 2012 21:04:25 +0100 Subject: [PATCH 1395/4212] splitted manifest up in manifest and gencode-remote --- conf/type/__mysql_server/gencode-remote | 51 +++++++++++++++++++++++++ conf/type/__mysql_server/manifest | 27 ------------- 2 files changed, 51 insertions(+), 27 deletions(-) create mode 100755 conf/type/__mysql_server/gencode-remote diff --git a/conf/type/__mysql_server/gencode-remote b/conf/type/__mysql_server/gencode-remote new file mode 100755 index 00000000..782a4cb6 --- /dev/null +++ b/conf/type/__mysql_server/gencode-remote @@ -0,0 +1,51 @@ +#!/bin/sh +# +# 2012 Benedikt Koeppel (code@benediktkoeppel.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +# store the root password in /root/.my.cnf so that processes can connect +# to the database without requiring a passwort input +rootpassword="$(cat "$__object/parameter/password")" + +# set root password +mysqladmin -u root password $rootpassword + +# remove anonymous users +mysql -u root -p <<-EOF + DELETE FROM mysql.user WHERE User=''; +EOF + +# remove remote-access for root +mysql -u root -p <<-EOF + DELETE FROM mysql.user WHERE User='root' AND Host!='localhost'; +EOF + +# remove test database +mysql -u root -p <<-EOF + DROP DATABASE test; +EOF +mysql -u root -p <<-EOF + DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%' +EOF + +# flush privileges +mysql -u root -p <<-EOF + FLUSH PRIVILEGES; +EOF + diff --git a/conf/type/__mysql_server/manifest b/conf/type/__mysql_server/manifest index 88a585da..a9d5127c 100755 --- a/conf/type/__mysql_server/manifest +++ b/conf/type/__mysql_server/manifest @@ -28,30 +28,3 @@ rootpassword="$(cat "$__object/parameter/password")" __file "/root/.my.cnf" --group root --user root --mode 600 --source "$__type/files/my.cnf" require="__file/root/.my.cnf" \ __addifnosuchline "/root/.my.cnf" --line "password=$rootpassword" - -# set root password -mysqladmin -u root password $rootpassword - -# remove anonymous users -mysql -u root -p <<-EOF - DELETE FROM mysql.user WHERE User=''; -EOF - -# remove remote-access for root -mysql -u root -p <<-EOF - DELETE FROM mysql.user WHERE User='root' AND Host!='localhost'; -EOF - -# remove test database -mysql -u root -p <<-EOF - DROP DATABASE test; -EOF -mysql -u root -p <<-EOF - DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%' -EOF - -# flush privileges -mysql -u root -p <<-EOF - FLUSH PRIVILEGES; -EOF - From dc5fb8b769256dcbd84b5419f2c83116f0c03aee Mon Sep 17 00:00:00 2001 From: Benedikt Koeppel Date: Sat, 18 Feb 2012 21:17:24 +0100 Subject: [PATCH 1396/4212] fixed usage of __file --- conf/type/__mysql_server/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__mysql_server/manifest b/conf/type/__mysql_server/manifest index a9d5127c..da7e0165 100755 --- a/conf/type/__mysql_server/manifest +++ b/conf/type/__mysql_server/manifest @@ -25,6 +25,6 @@ __package mysql-server --state installed # store the root password in /root/.my.cnf so that processes can connect # to the database without requiring a passwort input rootpassword="$(cat "$__object/parameter/password")" -__file "/root/.my.cnf" --group root --user root --mode 600 --source "$__type/files/my.cnf" +__file "/root/.my.cnf" --group root --owner root --mode 600 --source "$__type/files/my.cnf" require="__file/root/.my.cnf" \ __addifnosuchline "/root/.my.cnf" --line "password=$rootpassword" From 3ceb643487d43e27977a11b12be36f1165a69a31 Mon Sep 17 00:00:00 2001 From: Benedikt Koeppel Date: Sat, 18 Feb 2012 21:50:26 +0100 Subject: [PATCH 1397/4212] fixed the generating of .my.cnf --- conf/type/__mysql_server/gencode-remote | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/conf/type/__mysql_server/gencode-remote b/conf/type/__mysql_server/gencode-remote index 782a4cb6..07826d27 100755 --- a/conf/type/__mysql_server/gencode-remote +++ b/conf/type/__mysql_server/gencode-remote @@ -19,13 +19,18 @@ # # -# store the root password in /root/.my.cnf so that processes can connect # to the database without requiring a passwort input rootpassword="$(cat "$__object/parameter/password")" # set root password mysqladmin -u root password $rootpassword +# store the root password in /root/.my.cnf so that processes can connect +cat <<-EOF > /root/.my.cnf + [client] + password=$rootpassword +EOF + # remove anonymous users mysql -u root -p <<-EOF DELETE FROM mysql.user WHERE User=''; From 3a810fa5ea1e19c24ea8d51b257ce725ec402e23 Mon Sep 17 00:00:00 2001 From: Benedikt Koeppel Date: Sat, 18 Feb 2012 21:59:42 +0100 Subject: [PATCH 1398/4212] fix manifest --- conf/type/__mysql_server/manifest | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/conf/type/__mysql_server/manifest b/conf/type/__mysql_server/manifest index da7e0165..a6840964 100755 --- a/conf/type/__mysql_server/manifest +++ b/conf/type/__mysql_server/manifest @@ -24,7 +24,4 @@ __package mysql-server --state installed # store the root password in /root/.my.cnf so that processes can connect # to the database without requiring a passwort input -rootpassword="$(cat "$__object/parameter/password")" -__file "/root/.my.cnf" --group root --owner root --mode 600 --source "$__type/files/my.cnf" -require="__file/root/.my.cnf" \ - __addifnosuchline "/root/.my.cnf" --line "password=$rootpassword" +__file "/root/.my.cnf" --group root --owner root --mode 600 From 7715ba395c77fb7ade861b7cd0e708f9a5d22e7a Mon Sep 17 00:00:00 2001 From: Benedikt Koeppel Date: Sat, 18 Feb 2012 23:08:34 +0100 Subject: [PATCH 1399/4212] fixed mysql_server type can install now successfully removes test database and all grants sets a root password --- conf/type/__mysql_server/gencode-remote | 26 ++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/conf/type/__mysql_server/gencode-remote b/conf/type/__mysql_server/gencode-remote index 07826d27..30803a91 100755 --- a/conf/type/__mysql_server/gencode-remote +++ b/conf/type/__mysql_server/gencode-remote @@ -23,34 +23,46 @@ rootpassword="$(cat "$__object/parameter/password")" # set root password -mysqladmin -u root password $rootpassword +echo "mysqladmin -u root password $rootpassword" # store the root password in /root/.my.cnf so that processes can connect +cat <<-EOFF cat <<-EOF > /root/.my.cnf [client] password=$rootpassword EOF +EOFF # remove anonymous users -mysql -u root -p <<-EOF +cat <<-EOFF +mysql -u root <<-EOF DELETE FROM mysql.user WHERE User=''; EOF +EOFF # remove remote-access for root -mysql -u root -p <<-EOF +cat <<-EOFF +mysql -u root <<-EOF DELETE FROM mysql.user WHERE User='root' AND Host!='localhost'; EOF +EOFF # remove test database -mysql -u root -p <<-EOF - DROP DATABASE test; +cat <<-EOFF +mysql -u root <<-EOF + DROP DATABASE IF EXISTS test; EOF -mysql -u root -p <<-EOF +EOFF +cat <<-EOFF +mysql -u root <<-EOF DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%' EOF +EOFF # flush privileges -mysql -u root -p <<-EOF +cat <<-EOFF +mysql -u root <<-EOF FLUSH PRIVILEGES; EOF +EOFF From 6a491080f8529dbaeda0436667d8d18bf12c2b2f Mon Sep 17 00:00:00 2001 From: Benedikt Koeppel Date: Sat, 18 Feb 2012 23:09:26 +0100 Subject: [PATCH 1400/4212] fixed man page for mysql_server it is a singleton and thus can't have a name --- conf/type/__mysql_server/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__mysql_server/man.text b/conf/type/__mysql_server/man.text index 92163fa3..25ce3e0e 100644 --- a/conf/type/__mysql_server/man.text +++ b/conf/type/__mysql_server/man.text @@ -28,7 +28,7 @@ EXAMPLES -------- -------------------------------------------------------------------------------- -__mysql_server "mysql-server" --password "Uu9jooKe" +__mysql_server --password "Uu9jooKe" -------------------------------------------------------------------------------- From cfaee39e706e2998f023d4693aa49ed29ae7fd27 Mon Sep 17 00:00:00 2001 From: Benedikt Koeppel Date: Sat, 18 Feb 2012 21:02:26 +0100 Subject: [PATCH 1401/4212] new type 'mysql_database' installs a database on an existing mysql_server remotely --- conf/type/__mysql_database/gencode-remote | 48 ++++++++++++++++++ conf/type/__mysql_database/man.text | 49 +++++++++++++++++++ conf/type/__mysql_database/parameter/optional | 3 ++ 3 files changed, 100 insertions(+) create mode 100755 conf/type/__mysql_database/gencode-remote create mode 100644 conf/type/__mysql_database/man.text create mode 100644 conf/type/__mysql_database/parameter/optional diff --git a/conf/type/__mysql_database/gencode-remote b/conf/type/__mysql_database/gencode-remote new file mode 100755 index 00000000..fdfb1501 --- /dev/null +++ b/conf/type/__mysql_database/gencode-remote @@ -0,0 +1,48 @@ +#!/bin/sh +# +# 2012 Benedikt Koeppel (code@benediktkoeppel.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +# if --database was specified +if [ -f "$__object/parameter/database" ]; then + database="$(cat "$__object/parameter/database")" +else # otherwise use the object id as database name + database="$__object_id" +fi + +mysql -u root -p <<-EOF + CREATE DATABASE IF NOT EXISTS $database +EOF + +# if --user was specified +if [ -f "$__object/parameter/user" ]; then + user="$(cat "$__object/parameter/user")" + + # if --password was specified + if [ -f "$__object/parameter/password" ]; then + password="$(cat "$__object/parameter/password")" + mysql -u root -p <<-EOF + GRANT ALL PRIVILEGES ON $database.* to '$user'@'localhost' IDENTIFIED BY '$password'; + EOF + else + mysql -u root -p <<-EOF + GRANT ALL PRIVILEGES ON $database.* to '$user'@'localhost'; + EOF + fi +fi diff --git a/conf/type/__mysql_database/man.text b/conf/type/__mysql_database/man.text new file mode 100644 index 00000000..3c66eeab --- /dev/null +++ b/conf/type/__mysql_database/man.text @@ -0,0 +1,49 @@ +cdist-type__mysql_database(7) +============================= +Benedikt Koeppel + + +NAME +---- +cdist-type__mysql_database - Manage a MySQL database + + +DESCRIPTION +----------- +This cdist type allows you to install a MySQL database. + + +REQUIRED PARAMETERS +------------------- +None. + +OPTIONAL PARAMETERS +------------------- +database:: + The name of the database to install + defaults to the object id + +user:: + A user that should have access to the database + +password:: + The password for the user who manages the database + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__mysql_database "cdist" --database "cdist" --user "myuser" --password "mypwd" +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2012 Benedikt Koeppel. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__mysql_database/parameter/optional b/conf/type/__mysql_database/parameter/optional new file mode 100644 index 00000000..ac60a873 --- /dev/null +++ b/conf/type/__mysql_database/parameter/optional @@ -0,0 +1,3 @@ +database +user +password From c67c0cf12dd76a87de17e8812f8948f2b7ac094d Mon Sep 17 00:00:00 2001 From: Benedikt Koeppel Date: Sat, 18 Feb 2012 23:10:56 +0100 Subject: [PATCH 1402/4212] fixed mysql_database type can now install a database, and create a user who manages that database --- conf/type/__mysql_database/gencode-remote | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/conf/type/__mysql_database/gencode-remote b/conf/type/__mysql_database/gencode-remote index fdfb1501..9001ac99 100755 --- a/conf/type/__mysql_database/gencode-remote +++ b/conf/type/__mysql_database/gencode-remote @@ -26,9 +26,11 @@ else # otherwise use the object id as database name database="$__object_id" fi -mysql -u root -p <<-EOF +cat <<-EOFF +mysql -u root <<-EOF CREATE DATABASE IF NOT EXISTS $database EOF +EOFF # if --user was specified if [ -f "$__object/parameter/user" ]; then @@ -37,12 +39,17 @@ if [ -f "$__object/parameter/user" ]; then # if --password was specified if [ -f "$__object/parameter/password" ]; then password="$(cat "$__object/parameter/password")" - mysql -u root -p <<-EOF + cat <<-EOFF + mysql -u root <<-EOF GRANT ALL PRIVILEGES ON $database.* to '$user'@'localhost' IDENTIFIED BY '$password'; - EOF +EOF +EOFF else - mysql -u root -p <<-EOF + password="" + cat <<-EOFF + mysql -u root <<-EOF GRANT ALL PRIVILEGES ON $database.* to '$user'@'localhost'; - EOF +EOF +EOFF fi fi From d082815c811ba53cb096198d1199f5c35e11f269 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Sun, 19 Feb 2012 14:09:36 -0500 Subject: [PATCH 1403/4212] Created explorers, man page, jailbase placeholder. Began initial development of gencode-remote. --- conf/type/__jail/explorer/present | 27 +++++++++++++++ conf/type/__jail/explorer/status | 28 +++++++++++++++ conf/type/__jail/files/jailbase | 1 + conf/type/__jail/gencode-remote | 44 +++++++++++++++++++++++ conf/type/__jail/man.text | 54 +++++++++++++++++++++++++++++ conf/type/__jail/manifest | 31 +++++++++++++++++ conf/type/__jail/parameter/optional | 1 + conf/type/__jail/parameter/required | 1 + 8 files changed, 187 insertions(+) create mode 100755 conf/type/__jail/explorer/present create mode 100755 conf/type/__jail/explorer/status create mode 100644 conf/type/__jail/files/jailbase mode change 100644 => 100755 conf/type/__jail/gencode-remote create mode 100755 conf/type/__jail/manifest diff --git a/conf/type/__jail/explorer/present b/conf/type/__jail/explorer/present new file mode 100755 index 00000000..c559cf65 --- /dev/null +++ b/conf/type/__jail/explorer/present @@ -0,0 +1,27 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# See if the requested jail exists +# + +name=$__object_id + +[ -d "/usr/jail/$name" ] && echo "EXISTS" + diff --git a/conf/type/__jail/explorer/status b/conf/type/__jail/explorer/status new file mode 100755 index 00000000..19b57672 --- /dev/null +++ b/conf/type/__jail/explorer/status @@ -0,0 +1,28 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# See if the requested jail is started +# + +name=$__object_id + +jls_output=$(jls | grep "[ ]\/usr\/jail\/$name\$") +[ -n "$jls_output" ] && echo "STARTED" + diff --git a/conf/type/__jail/files/jailbase b/conf/type/__jail/files/jailbase new file mode 100644 index 00000000..defb739a --- /dev/null +++ b/conf/type/__jail/files/jailbase @@ -0,0 +1 @@ +Create a tarball jailbase.tgz in this directory containing the base filesystem for a jail. diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote old mode 100644 new mode 100755 index e69de29b..264ce111 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -0,0 +1,44 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# The __jail type creates, configures, and deletes FreeBSD jails for use as +# virtual machines. +# + +jaildir="/usr/jail" +present="$(cat "$__object/explorer/present")" +status="$(cat "$__object/explorer/status")" +state="$(cat "$__object/parameter/state")" +name="$__object_id" + +if [ -f "$__object/parameter/started" ]; then + started="$(cat "$__object/parameter/started")" +fi + +# + +if [ "$present" = "EXISTS" ]; then +# blah +fi + +if [ "$status" = "STARTED" ]; then +# blah +fi + diff --git a/conf/type/__jail/man.text b/conf/type/__jail/man.text index e69de29b..b2e49468 100644 --- a/conf/type/__jail/man.text +++ b/conf/type/__jail/man.text @@ -0,0 +1,54 @@ +cdist-type__jail(7) +========================== +Jake Guffey + + +NAME +---- +cdist-type__jail - Manage FreeBSD jails + + +DESCRIPTION +----------- +This type is used on FreeBSD to manage jails. + + +REQUIRED PARAMETERS +------------------- +state:: + Either "present" or "absent." + + +OPTIONAL PARAMETERS +------------------- +started:: + Either "true" or "false." + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Create a jail called www +__jail www --state present + +# Remove the jail called www +__jail www --state absent + +# Ensure that the jail called www is started +__jail www --state present --started true + +# Use the name variable explicitly +__jail thisjail --state present --name www +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2012 Jake Guffey. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__jail/manifest b/conf/type/__jail/manifest new file mode 100755 index 00000000..81fcd65b --- /dev/null +++ b/conf/type/__jail/manifest @@ -0,0 +1,31 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# The __jail type creates, configures, and deletes FreeBSD jails for use as +# virtual machines. +# + +#FIXME: /usr/jail should never be hardcoded in this type +#FIXME: jailbase.tgz should not be hardcoded in this file + +jailbase="/usr/jail/jailbase.tgz" + +__rsyncer "$jailbase" --source "$__object/files/jailbase.tgz" + diff --git a/conf/type/__jail/parameter/optional b/conf/type/__jail/parameter/optional index e69de29b..c06c82c7 100644 --- a/conf/type/__jail/parameter/optional +++ b/conf/type/__jail/parameter/optional @@ -0,0 +1 @@ +started diff --git a/conf/type/__jail/parameter/required b/conf/type/__jail/parameter/required index e69de29b..ff72b5c7 100644 --- a/conf/type/__jail/parameter/required +++ b/conf/type/__jail/parameter/required @@ -0,0 +1 @@ +state From cfb8e7d37237e54a7bfd8b430e9ce4e4e5387397 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Feb 2012 10:22:52 +0100 Subject: [PATCH 1404/4212] move __run_command to types_submitted_for_inclusion directory Signed-off-by: Nico Schottelius --- .../__run_command/README.inclusion | 6 ++++++ .../__run_command/gencode-remote | 0 .../types_submitted_for_inclusion}/__run_command/man.text | 0 .../__run_command/parameter/optional | 0 .../__run_command/parameter/required | 0 5 files changed, 6 insertions(+) create mode 100644 other/types_submitted_for_inclusion/__run_command/README.inclusion rename {conf/type => other/types_submitted_for_inclusion}/__run_command/gencode-remote (100%) rename {conf/type => other/types_submitted_for_inclusion}/__run_command/man.text (100%) rename {conf/type => other/types_submitted_for_inclusion}/__run_command/parameter/optional (100%) rename {conf/type => other/types_submitted_for_inclusion}/__run_command/parameter/required (100%) diff --git a/other/types_submitted_for_inclusion/__run_command/README.inclusion b/other/types_submitted_for_inclusion/__run_command/README.inclusion new file mode 100644 index 00000000..f7c95da7 --- /dev/null +++ b/other/types_submitted_for_inclusion/__run_command/README.inclusion @@ -0,0 +1,6 @@ +This type is not much of use, as any type can issue code to be executed. +Thus you can implement the code directly in the calling type. + Or if you need to reuse it, create a type on its own. + +Because this seems to be a common misunderstanding when people come from "non managed areas", + where script iexecution is the main focus, I documented this in cdist-hacker to clearify. diff --git a/conf/type/__run_command/gencode-remote b/other/types_submitted_for_inclusion/__run_command/gencode-remote similarity index 100% rename from conf/type/__run_command/gencode-remote rename to other/types_submitted_for_inclusion/__run_command/gencode-remote diff --git a/conf/type/__run_command/man.text b/other/types_submitted_for_inclusion/__run_command/man.text similarity index 100% rename from conf/type/__run_command/man.text rename to other/types_submitted_for_inclusion/__run_command/man.text diff --git a/conf/type/__run_command/parameter/optional b/other/types_submitted_for_inclusion/__run_command/parameter/optional similarity index 100% rename from conf/type/__run_command/parameter/optional rename to other/types_submitted_for_inclusion/__run_command/parameter/optional diff --git a/conf/type/__run_command/parameter/required b/other/types_submitted_for_inclusion/__run_command/parameter/required similarity index 100% rename from conf/type/__run_command/parameter/required rename to other/types_submitted_for_inclusion/__run_command/parameter/required From edcb2363e9cae80b368e12cd895d30ab52b8f06d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Feb 2012 11:18:37 +0100 Subject: [PATCH 1405/4212] ++version(2.0.8) Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- lib/cdist/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/changelog b/doc/changelog index cb72068e..96681617 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.0.8: +2.0.8: 2012-02-20 * Bugfix core: Remove another nasty traceback when sending SIGINT (aka Ctrl-C) * Cleanup: Better hint to source of error * Cleanup: Do not output failing script, but path to script only diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 4742a937..c1e16ffb 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -19,7 +19,7 @@ # # -VERSION = "2.0.7" +VERSION = "2.0.8" BANNER = """ .. . .x+=:. s From 377afe8b1c2e19b820f499e7c84951b9450c2c26 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Mon, 20 Feb 2012 10:51:18 -0500 Subject: [PATCH 1406/4212] Migrated to using present/absent for --state param. --- conf/type/__package_pkg_freebsd/gencode-remote | 6 +++--- conf/type/__package_pkg_freebsd/man.text | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/conf/type/__package_pkg_freebsd/gencode-remote b/conf/type/__package_pkg_freebsd/gencode-remote index 022c727a..fa962970 100755 --- a/conf/type/__package_pkg_freebsd/gencode-remote +++ b/conf/type/__package_pkg_freebsd/gencode-remote @@ -90,7 +90,7 @@ execcmd(){ } if [ -n "$curr_version" ]; then # PKG *is* installed - if [ "$state" = "removed" ]; then # Shouldn't be installed + if [ "$state" = "absent" ]; then # Shouldn't be installed if [ -n "$flavor" ]; then cmd="${rm_cmd} ${name}-${flavor}-${curr_version}" else @@ -115,9 +115,9 @@ if [ -n "$curr_version" ]; then # PKG *is* installed fi fi else # PKG *isn't* installed - if [ "$state" = "removed" ]; then # Shouldn't be installed + if [ "$state" = "absent" ]; then # Shouldn't be installed exit 0 - elif [ "$state" = "installed" ]; then # Is not currently installed, should be + elif [ "$state" = "present" ]; then # Is not currently installed, should be if [ -n "$flavor" ]; then cmd="${add_cmd} -r ${name}-${flavor}" else diff --git a/conf/type/__package_pkg_freebsd/man.text b/conf/type/__package_pkg_freebsd/man.text index 882bece9..f41ac47a 100644 --- a/conf/type/__package_pkg_freebsd/man.text +++ b/conf/type/__package_pkg_freebsd/man.text @@ -16,7 +16,7 @@ This type is usually used on FreeBSD to manage packages. REQUIRED PARAMETERS ------------------- state:: - Either "installed" or "removed". + Either "present" or "absent". OPTIONAL PARAMETERS From a2a0fd6b975a0fe962c2fd0e57d73cbd928f01a3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Feb 2012 17:07:06 +0100 Subject: [PATCH 1407/4212] +error log (2 missing bits) Signed-off-by: Nico Schottelius --- .../2012-02-20.error-does-not-contain-host | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 doc/dev/logs/2012-02-20.error-does-not-contain-host diff --git a/doc/dev/logs/2012-02-20.error-does-not-contain-host b/doc/dev/logs/2012-02-20.error-does-not-contain-host new file mode 100644 index 00000000..5838c011 --- /dev/null +++ b/doc/dev/logs/2012-02-20.error-does-not-contain-host @@ -0,0 +1,26 @@ +- errors do not contain host +- it's not logged which hosts failed! + +INFO: monitoring02: Running manifest and explorers for __directory/opt/local.ch/sys/shinken/host.d +INFO: monitoring03: Running manifest and explorers for __file/usr/sbin/iptables-rebuild +INFO: monitoring03: Running manifest and explorers for __git/opt/local.ch/sys/shinken/shinken +INFO: monitoring02: Running manifest and explorers for __file/etc/iptables.d/005_start +INFO: monitoring03: Running manifest and explorers for __localch_rsyncd/singleton +ERROR: Object __localch_iptables/xensnmp already exists with conflicting parameters: +/home/users/nico/privat/firmen/local.ch/vcs/cdist/conf/manifest/init: {'rule': '-A RH-Firewall-1-INPUT -p tcp --dport 161 -j ACCEPT'} +/home/users/nico/privat/firmen/local.ch/vcs/cdist/conf/type/__localch_rsyncd/manifest: {'rule': '-A RH-Firewall-1-INPUT -p tcp --dport 873 -j ACCEPT'} +ERROR: Command failed: /bin/sh -e /home/users/nico/privat/firmen/local.ch/vcs/cdist/conf/type/__localch_rsyncd/manifest +INFO: monitoring02: Running manifest and explorers for __file/etc/iptables.d/500_xensnmp +INFO: monitoring02: Running manifest and explorers for __file/etc/iptables.d/995_end +INFO: monitoring02: Running manifest and explorers for __file/etc/rsyncd.conf +INFO: monitoring02: Running manifest and explorers for __file/etc/yum.repos.d/epel.repo +INFO: monitoring02: Running manifest and explorers for __file/etc/yum.repos.d/rpmforge.repo +INFO: monitoring02: Running manifest and explorers for __file/usr/sbin/iptables-rebuild +INFO: monitoring02: Running manifest and explorers for __git/opt/local.ch/sys/shinken/shinken +INFO: monitoring02: Running manifest and explorers for __localch_rsyncd/singleton +ERROR: Object __localch_iptables/xensnmp already exists with conflicting parameters: +/home/users/nico/privat/firmen/local.ch/vcs/cdist/conf/manifest/init: {'rule': '-A RH-Firewall-1-INPUT -p tcp --dport 161 -j ACCEPT'} +/home/users/nico/privat/firmen/local.ch/vcs/cdist/conf/type/__localch_rsyncd/manifest: {'rule': '-A RH-Firewall-1-INPUT -p tcp --dport 873 -j ACCEPT'} +ERROR: Command failed: /bin/sh -e /home/users/nico/privat/firmen/local.ch/vcs/cdist/conf/type/__localch_rsyncd/manifest +INFO: Total processing time for 2 host(s): 14.245397090911865 +[16:53] brief:cdist% From 9538ef6462981c62a703a87c218f0d9e0c76b184 Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Sun, 19 Feb 2012 19:48:05 +0100 Subject: [PATCH 1408/4212] Properly detect OpenWRT in global explorers Signed-off-by: Giel van Schijndel --- conf/explorer/lsb_codename | 15 +++++++++++---- conf/explorer/lsb_description | 15 +++++++++++---- conf/explorer/lsb_id | 15 +++++++++++---- conf/explorer/lsb_release | 15 +++++++++++---- conf/explorer/os | 5 +++++ conf/explorer/os_version | 3 +++ 6 files changed, 52 insertions(+), 16 deletions(-) diff --git a/conf/explorer/lsb_codename b/conf/explorer/lsb_codename index bc742cf7..22b6d51e 100755 --- a/conf/explorer/lsb_codename +++ b/conf/explorer/lsb_codename @@ -20,7 +20,14 @@ # set +e -lsb_release=$(which lsb_release 2>/dev/null) -if [ -x "$lsb_release" ]; then - $lsb_release --short --codename -fi +case "$($__explorer/os)" in + openwrt) + (. /etc/openwrt_release && echo "$DISTRIB_CODENAME") + ;; + *) + lsb_release=$(which lsb_release 2>/dev/null) + if [ -x "$lsb_release" ]; then + $lsb_release --short --codename + fi + ;; +esac diff --git a/conf/explorer/lsb_description b/conf/explorer/lsb_description index f6c30322..48aff30d 100755 --- a/conf/explorer/lsb_description +++ b/conf/explorer/lsb_description @@ -20,7 +20,14 @@ # set +e -lsb_release=$(which lsb_release 2>/dev/null) -if [ -x "$lsb_release" ]; then - $lsb_release --short --description -fi +case "$($__explorer/os)" in + openwrt) + (. /etc/openwrt_release && echo "$DISTRIB_DESCRIPTION") + ;; + *) + lsb_release=$(which lsb_release 2>/dev/null) + if [ -x "$lsb_release" ]; then + $lsb_release --short --description + fi + ;; +esac diff --git a/conf/explorer/lsb_id b/conf/explorer/lsb_id index 6cb2359b..0dd0f9f4 100755 --- a/conf/explorer/lsb_id +++ b/conf/explorer/lsb_id @@ -20,7 +20,14 @@ # set +e -lsb_release=$(which lsb_release 2>/dev/null) -if [ -x "$lsb_release" ]; then - $lsb_release --short --id -fi +case "$($__explorer/os)" in + openwrt) + (. /etc/openwrt_release && echo "$DISTRIB_ID") + ;; + *) + lsb_release=$(which lsb_release 2>/dev/null) + if [ -x "$lsb_release" ]; then + $lsb_release --short --id + fi + ;; +esac diff --git a/conf/explorer/lsb_release b/conf/explorer/lsb_release index a96ac50b..8266171a 100755 --- a/conf/explorer/lsb_release +++ b/conf/explorer/lsb_release @@ -20,7 +20,14 @@ # set +e -lsb_release=$(which lsb_release 2>/dev/null) -if [ -x "$lsb_release" ]; then - $lsb_release --short --release -fi +case "$($__explorer/os)" in + openwrt) + (. /etc/openwrt_release && echo "$DISTRIB_RELEASE") + ;; + *) + lsb_release=$(which lsb_release 2>/dev/null) + if [ -x "$lsb_release" ]; then + $lsb_release --short --release + fi + ;; +esac diff --git a/conf/explorer/os b/conf/explorer/os index 3f3ce266..e67d87ab 100755 --- a/conf/explorer/os +++ b/conf/explorer/os @@ -56,6 +56,11 @@ if [ -f /etc/gentoo-release ]; then exit 0 fi +if [ -f /etc/openwrt_version ]; then + echo openwrt + exit 0 +fi + if [ -f /etc/owl-release ]; then echo owl exit 0 diff --git a/conf/explorer/os_version b/conf/explorer/os_version index 73d3ecd7..8e6d37d3 100755 --- a/conf/explorer/os_version +++ b/conf/explorer/os_version @@ -45,6 +45,9 @@ case "$($__explorer/os)" in *bsd|solaris) uname -r ;; + openwrt) + cat /etc/openwrt_version + ;; owl) cat /etc/owl-release ;; From 2e4e291449af87d1aafaed9e604766ff28e35aa0 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Mon, 20 Feb 2012 14:20:55 -0500 Subject: [PATCH 1409/4212] Added gencode-local to sync jailbase with remote side, added .gitignore to keep from syncing jailbase.tgz with github, new explorer basepresent to look for /usr/jail/{base,jailbase.tgz} --- conf/type/__jail/.gitignore | 1 + conf/type/__jail/explorer/basepresent | 42 +++++++++++++++++++++++++++ conf/type/__jail/gencode-local | 34 ++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 conf/type/__jail/.gitignore create mode 100755 conf/type/__jail/explorer/basepresent create mode 100755 conf/type/__jail/gencode-local diff --git a/conf/type/__jail/.gitignore b/conf/type/__jail/.gitignore new file mode 100644 index 00000000..e0471be4 --- /dev/null +++ b/conf/type/__jail/.gitignore @@ -0,0 +1 @@ +files/jailbase.tgz diff --git a/conf/type/__jail/explorer/basepresent b/conf/type/__jail/explorer/basepresent new file mode 100755 index 00000000..7c21fc08 --- /dev/null +++ b/conf/type/__jail/explorer/basepresent @@ -0,0 +1,42 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# See if the jailbase.tgz or /usr/jail/base dir exists +# + +name="base:jailbase.tgz" +exists=0 + +save_IFS="$IFS" +IFS=":" +for cur in $name; do + if [ -e "/usr/jail/$cur" ]; then + echo -n "$cur:" + let exists="$exists+1" 2>&1 >&- + fi +done +IFS="$save_IFS" + +if [ "$exists" -eq "0" ]; then + echo "NONE" +else + echo "$exists" +fi + diff --git a/conf/type/__jail/gencode-local b/conf/type/__jail/gencode-local new file mode 100755 index 00000000..6ad476e6 --- /dev/null +++ b/conf/type/__jail/gencode-local @@ -0,0 +1,34 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# The __jail type creates, configures, and deletes FreeBSD jails for use as +# virtual machines. +# + +#FIXME: /usr/jail should never be hardcoded in this type +#FIXME: jailbase.tgz should not be hardcoded in this file + +jailbase="/usr/jail/jailbase.tgz" +basepresent="$(cat "$__object/explorer/basepresent")" + +if [ "$basepresent" = "NONE" ]; then + __file "$jailbase" --source "$__object/files/jailbase.tgz" +fi + From afdfb660c7cc6003b67ee89ecb8c8bda4a61d731 Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Sun, 19 Feb 2012 19:51:04 +0100 Subject: [PATCH 1410/4212] Add support for OpenWRT packages Signed-off-by: Giel van Schijndel --- conf/type/__package/manifest | 1 + conf/type/__package_opkg/explorer/pkg_status | 39 ++++++++++++++ conf/type/__package_opkg/gencode-remote | 57 ++++++++++++++++++++ conf/type/__package_opkg/man.text | 49 +++++++++++++++++ conf/type/__package_opkg/parameter/optional | 1 + conf/type/__package_opkg/parameter/required | 1 + 6 files changed, 148 insertions(+) create mode 100755 conf/type/__package_opkg/explorer/pkg_status create mode 100755 conf/type/__package_opkg/gencode-remote create mode 100644 conf/type/__package_opkg/man.text create mode 100644 conf/type/__package_opkg/parameter/optional create mode 100644 conf/type/__package_opkg/parameter/required diff --git a/conf/type/__package/manifest b/conf/type/__package/manifest index 181da077..26c2cd39 100755 --- a/conf/type/__package/manifest +++ b/conf/type/__package/manifest @@ -34,6 +34,7 @@ else debian|ubuntu) type="apt" ;; gentoo) type="emerge" ;; amazon|centos|fedora|redhat) type="yum" ;; + openwrt) type="opkg" ;; *) echo "Don't know how to manage packages on: $os" >&2 exit 1 diff --git a/conf/type/__package_opkg/explorer/pkg_status b/conf/type/__package_opkg/explorer/pkg_status new file mode 100755 index 00000000..5da4f742 --- /dev/null +++ b/conf/type/__package_opkg/explorer/pkg_status @@ -0,0 +1,39 @@ +#!/bin/sh +# +# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2012 Giel van Schijndel (giel plus cdist at mortis dot eu) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Retrieve the status of a package - parsed opkg output +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +# Except dpkg failing, if package is not known / installed +if opkg status "$name" 2>/dev/null | grep -q "^Status: install user installed$"; then + echo "present" + exit 0 +elif [ "$(opkg info "$name" 2> /dev/null | wc -l)" -eq 0 ]; then + echo "absent notpresent" + exit 0 +fi +echo "absent" diff --git a/conf/type/__package_opkg/gencode-remote b/conf/type/__package_opkg/gencode-remote new file mode 100755 index 00000000..bd9a599b --- /dev/null +++ b/conf/type/__package_opkg/gencode-remote @@ -0,0 +1,57 @@ +#!/bin/sh +# +# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2012 Giel van Schijndel (giel plus cdist at mortis dot eu) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Manage packages on OpenWRT and co. +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +state_should="$(cat "$__object/parameter/state")" +state_is="$(cat "$__object/explorer/pkg_status")" +case "$state_is" in + absent*) + present="$(echo "$state_is" | cut -d ' ' -f 2)" + state_is="absent" + ;; +esac + +if [ "$state_is" != "$state_should" ]; then + 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 + diff --git a/conf/type/__package_opkg/man.text b/conf/type/__package_opkg/man.text new file mode 100644 index 00000000..19d26af6 --- /dev/null +++ b/conf/type/__package_opkg/man.text @@ -0,0 +1,49 @@ +cdist-type__package_opkg(7) +========================== +Giel van Schijndel + + +NAME +---- +cdist-type__package_opkg - Manage packages with opkg + + +DESCRIPTION +----------- +opkg is usually used on OpenWRT to manage packages. + + +REQUIRED PARAMETERS +------------------- +state:: + The state the package should be in, either "present" or "absent" + + +OPTIONAL PARAMETERS +------------------- +name:: + If supplied, use the name and not the object id as the package name. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure lsof is installed +__package_opkg lsof --state present + +# Remove obsolete package +__package_opkg dnsmasq --state absent +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__package(7) + + +COPYING +------- +Copyright \(C) 2012 Giel van Schijndel. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__package_opkg/parameter/optional b/conf/type/__package_opkg/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/conf/type/__package_opkg/parameter/optional @@ -0,0 +1 @@ +name diff --git a/conf/type/__package_opkg/parameter/required b/conf/type/__package_opkg/parameter/required new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/conf/type/__package_opkg/parameter/required @@ -0,0 +1 @@ +state From df512162cba34bde910df33bd5338f7b636ed1c8 Mon Sep 17 00:00:00 2001 From: Benedikt Koeppel Date: Tue, 21 Feb 2012 06:49:47 +0100 Subject: [PATCH 1411/4212] --password is optional now, and added --no_my_cnf option if no password is specified, then __mysql_server simply installs the mysql-server package and doesn't perform any additional tasks. if --password is specified, it writes its own .my.cnf configuration file with the root password. This behaviour can be turned of by setting --no_my_cnf "true" --- conf/type/__mysql_server/gencode-remote | 101 ++++++++++++-------- conf/type/__mysql_server/man.text | 21 +++- conf/type/__mysql_server/manifest | 20 +++- conf/type/__mysql_server/parameter/optional | 2 + conf/type/__mysql_server/parameter/required | 1 - 5 files changed, 101 insertions(+), 44 deletions(-) create mode 100644 conf/type/__mysql_server/parameter/optional diff --git a/conf/type/__mysql_server/gencode-remote b/conf/type/__mysql_server/gencode-remote index 30803a91..4c160671 100755 --- a/conf/type/__mysql_server/gencode-remote +++ b/conf/type/__mysql_server/gencode-remote @@ -19,50 +19,75 @@ # # -# to the database without requiring a passwort input -rootpassword="$(cat "$__object/parameter/password")" +if [ -f "$__object/parameter/no_my_cnf" ]; then + no_my_cnf="$(cat "$__object/parameter/no_my_cnf")" +else + no_my_cnf="false" +fi -# set root password -echo "mysqladmin -u root password $rootpassword" +if [ -f "$__object/parameter/password" ]; then + rootpassword="$(cat "$__object/parameter/password")" +else + rootpassword="" +fi -# store the root password in /root/.my.cnf so that processes can connect -cat <<-EOFF -cat <<-EOF > /root/.my.cnf - [client] - password=$rootpassword + +if [ "$rootpassword" != "" ]; then + # to the database without requiring a passwort input + # set root password + echo "mysqladmin -u root password $rootpassword" + + # if we don't want to overwrite the .my.cnf, then take a backup now + if [ "$no_my_cnf" == "true" ]; then + mv /root/.my.cnf /root/.my.cnf.cdist.bkp + fi + + # store the root password in /root/.my.cnf so that processes can connect + cat <<-EOFF + cat <<-EOF > /root/.my.cnf + [client] + password=$rootpassword EOF EOFF -# remove anonymous users -cat <<-EOFF -mysql -u root <<-EOF - DELETE FROM mysql.user WHERE User=''; + + + # remove anonymous users + cat <<-EOFF + mysql -u root <<-EOF + DELETE FROM mysql.user WHERE User=''; +EOF +EOFF + + # remove remote-access for root + cat <<-EOFF + mysql -u root <<-EOF + DELETE FROM mysql.user WHERE User='root' AND Host!='localhost'; +EOF +EOFF + + # remove test database + cat <<-EOFF + mysql -u root <<-EOF + DROP DATABASE IF EXISTS test; +EOF +EOFF + cat <<-EOFF + mysql -u root <<-EOF + DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%' +EOF +EOFF + + # flush privileges + cat <<-EOFF + mysql -u root <<-EOF + FLUSH PRIVILEGES; EOF EOFF -# remove remote-access for root -cat <<-EOFF -mysql -u root <<-EOF - DELETE FROM mysql.user WHERE User='root' AND Host!='localhost'; -EOF -EOFF - -# remove test database -cat <<-EOFF -mysql -u root <<-EOF - DROP DATABASE IF EXISTS test; -EOF -EOFF -cat <<-EOFF -mysql -u root <<-EOF - DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%' -EOF -EOFF - -# flush privileges -cat <<-EOFF -mysql -u root <<-EOF - FLUSH PRIVILEGES; -EOF -EOFF + # if we don't want to overwrite the .my.cnf, then restore the backup now + if [ "$no_my_cnf" == "true" ]; then + mv /root/.my.cnf.cdist.bkp /root/.my.cnf + fi +fi diff --git a/conf/type/__mysql_server/man.text b/conf/type/__mysql_server/man.text index 25ce3e0e..f8573051 100644 --- a/conf/type/__mysql_server/man.text +++ b/conf/type/__mysql_server/man.text @@ -10,7 +10,10 @@ cdist-type__mysql_server - Manage a MySQL server DESCRIPTION ----------- -This cdist type allows you to install a MySQL database server. +This cdist type allows you to install a MySQL database server. The +__mysql_server type also takes care of a few basic security tweaks that are +normally done by running the mysql_secure_installation script that is provided +with MySQL. REQUIRED PARAMETERS @@ -21,14 +24,28 @@ password:: OPTIONAL PARAMETERS ------------------- -None. +no_my_cnf:: + The /root/.my.cnf file is used to temporary store the root password when doing + the mysql_secure_installation. If you want to have your own .my.cnf file, then + specify --no_my_cnf "true". + Cdist will then place your original /root/.my.cnf back once cdist has run. EXAMPLES -------- -------------------------------------------------------------------------------- +# to install a MySQL server +__mysql_server + +# to install a MySQL server, remove remote access, remove test databases +# similar to mysql_secure_installation, specify the root password __mysql_server --password "Uu9jooKe" +# this will also write a /root/.my.cnf file + +# if you don't want cdist to write a /root/.my.cnf file permanently, specify +# the --no_my_cnf option +__mysql_server --password "Uu9jooKe" --no_my_cnf -------------------------------------------------------------------------------- diff --git a/conf/type/__mysql_server/manifest b/conf/type/__mysql_server/manifest index a6840964..ce331998 100755 --- a/conf/type/__mysql_server/manifest +++ b/conf/type/__mysql_server/manifest @@ -22,6 +22,20 @@ # install mysql-server __package mysql-server --state installed -# store the root password in /root/.my.cnf so that processes can connect -# to the database without requiring a passwort input -__file "/root/.my.cnf" --group root --owner root --mode 600 +if [ -f "$__object/parameter/no_my_cnf" ]; then + no_my_cnf="$(cat "$__object/parameter/no_my_cnf")" +else + no_my_cnf="false" +fi + +if [ -f "$__object/parameter/password" ]; then + rootpassword="$(cat "$__object/parameter/password")" +else + rootpassword="" +fi + +if [ "$no_my_cnf" != "true" -a "$rootpassword" != "" ]; then + # store the root password in /root/.my.cnf so that processes can connect + # to the database without requiring a passwort input + __file "/root/.my.cnf" --group root --owner root --mode 600 +fi diff --git a/conf/type/__mysql_server/parameter/optional b/conf/type/__mysql_server/parameter/optional new file mode 100644 index 00000000..4c40596c --- /dev/null +++ b/conf/type/__mysql_server/parameter/optional @@ -0,0 +1,2 @@ +no_my_cnf +password diff --git a/conf/type/__mysql_server/parameter/required b/conf/type/__mysql_server/parameter/required index f3097ab1..e69de29b 100644 --- a/conf/type/__mysql_server/parameter/required +++ b/conf/type/__mysql_server/parameter/required @@ -1 +0,0 @@ -password From cd8e2869883efd3eedd1b78a78227259565c6731 Mon Sep 17 00:00:00 2001 From: Benedikt Koeppel Date: Tue, 21 Feb 2012 07:03:03 +0100 Subject: [PATCH 1412/4212] renamed --database to --name --- conf/type/__mysql_database/gencode-remote | 4 ++-- conf/type/__mysql_database/man.text | 4 ++-- conf/type/__mysql_database/parameter/optional | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/conf/type/__mysql_database/gencode-remote b/conf/type/__mysql_database/gencode-remote index 9001ac99..c0e862f3 100755 --- a/conf/type/__mysql_database/gencode-remote +++ b/conf/type/__mysql_database/gencode-remote @@ -20,8 +20,8 @@ # # if --database was specified -if [ -f "$__object/parameter/database" ]; then - database="$(cat "$__object/parameter/database")" +if [ -f "$__object/parameter/name" ]; then + database="$(cat "$__object/parameter/name")" else # otherwise use the object id as database name database="$__object_id" fi diff --git a/conf/type/__mysql_database/man.text b/conf/type/__mysql_database/man.text index 3c66eeab..f184a30e 100644 --- a/conf/type/__mysql_database/man.text +++ b/conf/type/__mysql_database/man.text @@ -19,7 +19,7 @@ None. OPTIONAL PARAMETERS ------------------- -database:: +name:: The name of the database to install defaults to the object id @@ -34,7 +34,7 @@ EXAMPLES -------- -------------------------------------------------------------------------------- -__mysql_database "cdist" --database "cdist" --user "myuser" --password "mypwd" +__mysql_database "cdist" --name "cdist" --user "myuser" --password "mypwd" -------------------------------------------------------------------------------- diff --git a/conf/type/__mysql_database/parameter/optional b/conf/type/__mysql_database/parameter/optional index ac60a873..756afee7 100644 --- a/conf/type/__mysql_database/parameter/optional +++ b/conf/type/__mysql_database/parameter/optional @@ -1,3 +1,3 @@ -database +name user password From 63df800b56dfc655eef4664008c08803072e7c49 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 21 Feb 2012 09:41:37 +0100 Subject: [PATCH 1413/4212] ++changes(2.0.9) Signed-off-by: Nico Schottelius --- doc/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/changelog b/doc/changelog index 96681617..dc97ea14 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,6 +4,10 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.0.9: + * New Type: __package_opkg (Giel van Schijndel) + * Feature __package: Support OpenWRT (Giel van Schijndel) + 2.0.8: 2012-02-20 * Bugfix core: Remove another nasty traceback when sending SIGINT (aka Ctrl-C) * Cleanup: Better hint to source of error From db86d7316a95dd4c666be449cb0eb699ff7d6524 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 21 Feb 2012 09:59:13 +0100 Subject: [PATCH 1414/4212] ++changes(2.0.9) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index dc97ea14..0f0df0f2 100644 --- a/doc/changelog +++ b/doc/changelog @@ -6,6 +6,7 @@ Changelog 2.0.9: * New Type: __package_opkg (Giel van Schijndel) + * New Type: __package_pkg_freebsd (Jake Guffey) * Feature __package: Support OpenWRT (Giel van Schijndel) 2.0.8: 2012-02-20 From 68834984382e816fd6c78b6aae023e1e1bd0e94a Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Tue, 21 Feb 2012 11:02:24 +0100 Subject: [PATCH 1415/4212] reference doc: fix environment variable list to be properly displayed Prevent nesting of blockquotes below __object_id, preventing the following environment variables from being displayed as list items. Signed-off-by: Giel van Schijndel --- doc/man/cdist-reference.text.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index a76e7941..6bd5f1b8 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -188,6 +188,7 @@ __object_id:: the filesystem database and ensured by the core). Note: Double slashes ("//") will not be fixed and result in an error. + __self:: DEPRECATED: Same as __object_name, do not use anymore, use __object_name instead. Will be removed in cdist 3.x. From 566bfda6d2c2d1e5550553d02cbcc33bb9343fc1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 21 Feb 2012 15:11:46 +0100 Subject: [PATCH 1416/4212] ++changes(2.0.9) Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index 0f0df0f2..dc498b9e 100644 --- a/doc/changelog +++ b/doc/changelog @@ -5,6 +5,8 @@ Changelog * Exception: No braces means author == Nico Schottelius 2.0.9: + * Cleanup documentation: Fix environment variable list to be properly + displayed (Giel van Schijndel) * New Type: __package_opkg (Giel van Schijndel) * New Type: __package_pkg_freebsd (Jake Guffey) * Feature __package: Support OpenWRT (Giel van Schijndel) From b9c757b78a095fb344c2043cea843333f2447fe8 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Tue, 21 Feb 2012 15:59:19 -0500 Subject: [PATCH 1417/4212] Filled out man page, created gencode-local to copy jailbase to __target_host, filled out parameter list, made explorers useful, created basic layout within gencode-remote. --- conf/type/__jail/explorer/present | 6 +- conf/type/__jail/explorer/status | 6 +- conf/type/__jail/gencode-local | 2 +- conf/type/__jail/gencode-remote | 118 +++++++++++++++++++++++++--- conf/type/__jail/man.text | 52 ++++++++++-- conf/type/__jail/manifest | 31 -------- conf/type/__jail/parameter/optional | 7 ++ 7 files changed, 173 insertions(+), 49 deletions(-) delete mode 100755 conf/type/__jail/manifest diff --git a/conf/type/__jail/explorer/present b/conf/type/__jail/explorer/present index c559cf65..9338fd56 100755 --- a/conf/type/__jail/explorer/present +++ b/conf/type/__jail/explorer/present @@ -21,7 +21,11 @@ # See if the requested jail exists # -name=$__object_id +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name=$__object_id +fi [ -d "/usr/jail/$name" ] && echo "EXISTS" diff --git a/conf/type/__jail/explorer/status b/conf/type/__jail/explorer/status index 19b57672..3fe22adc 100755 --- a/conf/type/__jail/explorer/status +++ b/conf/type/__jail/explorer/status @@ -21,7 +21,11 @@ # See if the requested jail is started # -name=$__object_id +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name=$__object_id +fi jls_output=$(jls | grep "[ ]\/usr\/jail\/$name\$") [ -n "$jls_output" ] && echo "STARTED" diff --git a/conf/type/__jail/gencode-local b/conf/type/__jail/gencode-local index 6ad476e6..2d4415e3 100755 --- a/conf/type/__jail/gencode-local +++ b/conf/type/__jail/gencode-local @@ -29,6 +29,6 @@ jailbase="/usr/jail/jailbase.tgz" basepresent="$(cat "$__object/explorer/basepresent")" if [ "$basepresent" = "NONE" ]; then - __file "$jailbase" --source "$__object/files/jailbase.tgz" + echo "$__remote_copy" "$__object/files/jailbase.tgz" "${target_host}:${jailbase}" fi diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index 264ce111..038daa14 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -22,23 +22,121 @@ # virtual machines. # +# Debug +#exec >&2 +#set -x + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +state="$(cat "$__object/parameter/state")" + +if [ -f "$__object/parameter/started" ]; then + started="$(cat "$__object/parameter/started")" +else + started="true" +fi + +if [ -f "$__object/parameter/ip" ]; then + ip="$(cat "$__object/parameter/ip")" +else +# IP is an optional param when $state=absent, but +# when $state=present, it's required. Enforce this. + if [ "$state" = "present" ]; then + exec >&2 + echo "If --state is 'present,' --ip must be given\!" + exit 1 + fi +fi + +if [ -f "$__object/parameter/hostname" ]; then + hostname="$(cat "$__object/parameter/hostname")" +else + hostname="$name" +fi + +if [ -f "$__object/parameter/interface" ]; then + interface="$(cat "$__object/parameter/interface")" +fi + +if [ -f "$__object/parameter/devfs-enable" ]; then + devfsenable="$(cat "$__object/parameter/devfs-enable")" +else + devfsenable="true" +fi + +if [ -f "$__object/parameter/devfs-ruleset" ]; then + devfsruleset="$(cat "$__object/parameter/devfs-ruleset")" +else + devfsruleset="jailrules" +fi + +# devfs_ruleset being defined without devfs_enable being true +# is pointless. Treat this as an error. +if [ -n "$devfsrules" -a "$devfsenable" = "false" ]; then + exec >&2 + echo "Can't have --devfs-ruleset defined without --devfs-enable true." + exit 1 +fi + +if [ -f "$__object/parameter/onboot" ]; then + onboot="$(cat "$__object/parameter/onboot")" +fi + jaildir="/usr/jail" present="$(cat "$__object/explorer/present")" status="$(cat "$__object/explorer/status")" -state="$(cat "$__object/parameter/state")" -name="$__object_id" -if [ -f "$__object/parameter/started" ]; then - started="$(cat "$__object/parameter/started")" +# Defining a jail as absent and started at the same time +# makes no sense. Treat this as an error. +if [ "$started" = "true" -a "$state" = "absent" ]; then + exec >&2 + echo "Can't have --state absent and --started true together\!" + exit 1 fi -# +stopJail() { +# Check $status before issuing command + [ "$status" = "STARTED" ] && echo "/etc/rc.d/jail stop ${name}" +} -if [ "$present" = "EXISTS" ]; then -# blah +startJail() { +# Check $status before issuing command + [ ! "$status" = "STARTED" ] && echo "/etc/rc.d/jail start ${name}" +} + +deleteJail() { +} + +createJail() { +} + +if [ "$present" = "EXISTS" ]; then # The jail currently exists + if [ "$state" = "present" ]; then # The jail is supposed to exist + if [ "$started" = "true" ]; then # The jail is supposed to be started + startJail + else # The jail is not supposed to be started + stopJail + fi + exit 0 + else # The jail is not supposed to exist + stopJail + deleteJail + exit 0 + fi +else # The jail does not currently exist + if [ "$state" = "absent" ]; then # The jail is not supposed to be present + exit 0 + else # The jail is supposed to exist + createJail + [ "$started" = "true" ] && startJail + exit 0 + fi fi -if [ "$status" = "STARTED" ]; then -# blah -fi +# Debug +#set +x diff --git a/conf/type/__jail/man.text b/conf/type/__jail/man.text index b2e49468..e6256975 100644 --- a/conf/type/__jail/man.text +++ b/conf/type/__jail/man.text @@ -21,25 +21,67 @@ state:: OPTIONAL PARAMETERS ------------------- -started:: - Either "true" or "false." +name:: + The name of the jail. Default is to use the object_id as the jail name. +started:: + Either "true" or "false." Defaults to true. + +ip:: + The ifconfig style IP/netmask combination to use for the jail guest. If + the state parameter is "present," this parameter is required. + +hostname:: + The FQDN to use for the jail guest. Defaults to the name parameter. + +interface:: + The name of the physical interface on the jail server to bind the jail to. + +devfs-enable:: + Whether to allow devfs mounting within the jail. Must be "true" or "false." + Defaults to true. + +devfs-ruleset:: + The name of the devfs ruleset to associate with the jail. Defaults to + "jailrules." This ruleset must be copied to the server via another type. + To use this option, devfs-enable must be "true." + +onboot:: + Whether to add the jail to rc.conf's jail_list variable. Must be either + "true" or "false." Defaults to false. + + +CAVEATS +------- +This type does not currently support modification of jail options. If, for +example a jail needs to have its IP address or netmask changed, the jail must +be removed then re-added with the correct IP address/netmask or the appropriate +line (jail__ip="...") modified within rc.conf through some alternate +means. EXAMPLES -------- -------------------------------------------------------------------------------- # Create a jail called www -__jail www --state present +__jail www --state present --ip "192.168.1.2 netmask 255.255.255.0" # Remove the jail called www __jail www --state absent # Ensure that the jail called www is started -__jail www --state present --started true +__jail www --state present --started true \ + --ip "192.168.1.2 netmask 255.255.255.0" # Use the name variable explicitly -__jail thisjail --state present --name www +__jail thisjail --state present --name www \ + --ip "192.168.1.2 netmask 255.255.255.0" + +# Go nuts +__jail lotsofoptions --state present --name testjail --started true \ + --ip "192.168.1.100 netmask 255.255.255.0" \ + --hostname "testjail.example.com" --interface "em0" \ + --onboot yes -------------------------------------------------------------------------------- diff --git a/conf/type/__jail/manifest b/conf/type/__jail/manifest deleted file mode 100755 index 81fcd65b..00000000 --- a/conf/type/__jail/manifest +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -# -# 2012 Jake Guffey (jake.guffey at eprotex.com) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# The __jail type creates, configures, and deletes FreeBSD jails for use as -# virtual machines. -# - -#FIXME: /usr/jail should never be hardcoded in this type -#FIXME: jailbase.tgz should not be hardcoded in this file - -jailbase="/usr/jail/jailbase.tgz" - -__rsyncer "$jailbase" --source "$__object/files/jailbase.tgz" - diff --git a/conf/type/__jail/parameter/optional b/conf/type/__jail/parameter/optional index c06c82c7..85b94270 100644 --- a/conf/type/__jail/parameter/optional +++ b/conf/type/__jail/parameter/optional @@ -1 +1,8 @@ +name started +ip +hostname +interface +devfs-enable +devfs-ruleset +onboot From 12d2c6c19960fa33d4750fe8807f9381219a52d2 Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Tue, 21 Feb 2012 15:48:39 +0100 Subject: [PATCH 1418/4212] __start_on_boot type: add support for OpenWRT Signed-off-by: Giel van Schijndel --- conf/type/__start_on_boot/explorer/state | 2 +- conf/type/__start_on_boot/gencode-remote | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/conf/type/__start_on_boot/explorer/state b/conf/type/__start_on_boot/explorer/state index ff092a65..d1998e22 100755 --- a/conf/type/__start_on_boot/explorer/state +++ b/conf/type/__start_on_boot/explorer/state @@ -44,7 +44,7 @@ case "$os" in done ;; - debian|ubuntu) + debian|ubuntu|openwrt) state="present" [ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent" ;; diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index be2bd98b..cefdc385 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -47,6 +47,13 @@ case "$state_should" in echo chkconfig \"$name\" on ;; + openwrt) + # 'enable' can be successful and still return a non-zero exit + # code, deal with it by checking for success ourselves in that + # case (the || ... part). + echo "/etc/init.d/\"$name\" enable || [ -f /etc/rc.d/S??\"$name\" ]" + ;; + *) echo "Unsupported os: $os" >&2 exit 1 @@ -74,6 +81,10 @@ case "$state_should" in echo chkconfig \"$name\" off ;; + openwrt) + echo "\"/etc/init.d/$name\" disable" + ;; + *) echo "Unsupported os: $os" >&2 exit 1 From 18c0e947aa6cf57f0dbe01e61b860298b20fcb17 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Tue, 21 Feb 2012 18:34:21 -0500 Subject: [PATCH 1419/4212] Created initial createJail function. Script still can't delete jails yet. --- conf/type/__jail/gencode-remote | 95 ++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index 038daa14..5e1bdc02 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -76,7 +76,7 @@ fi # devfs_ruleset being defined without devfs_enable being true # is pointless. Treat this as an error. -if [ -n "$devfsrules" -a "$devfsenable" = "false" ]; then +if [ -n "$devfsruleset" -a "$devfsenable" = "false" ]; then exec >&2 echo "Can't have --devfs-ruleset defined without --devfs-enable true." exit 1 @@ -109,9 +109,102 @@ startJail() { } deleteJail() { +# If the jail's mountpoints are mounted, unmount them +# Remove the jail's rw mountpoints +# Remove the jail's ro mountpoint +# Remove the jail directory +# If the jail's devfs rules are custom (!="jailrules"), remove them +# Remove jail_$name_* lines from rc.conf +# Remove " $name " from jail_list if it's there } createJail() { +# Create the jail directory +echo <<-EOF + mkdir -p ${jaildir}/${name} + if [ ! -d "${jaildir}/base" ]; then + mkdir "${jaildir}/base" + tar -xzf "${jaildir}/jailbase.tgz" -C "${jaildir}/base" + if [ ! -d "${jaildir}/base/usr/local" ]; then + mkdir -p "${jaildir}/base/usr/local" + fi + if [ ! -d "${jaildir}/base/usr/home" ]; then + mkdir -p "${jaildir}/base/usr/home" + fi + fi + if [ ! -d "${jaildir}/rw" ]; then + mkdir "${jaildir}/rw" + fi + mkdir -p "${jaildir}/rw/${name}/etc" + cp -r ${jaildir}/base/etc/* "${jaildir}/rw/${name}/etc/" + mkdir "${jaildir}/rw/${name}/local" + mkdir "${jaildir}/rw/${name}/db" + if [ -d "${jaildir}/base/var/db" ]; then + cp -r ${jaildir}/base/var/db/* "${jaildir}/rw/${name}/db/" + fi + mkdir "${jaildir}/rw/${name}/home" + if [ -d "${jaildir}/base/usr/home" ]; then + cp -r ${jaildir}/base/usr/home/* "${jaildir}/rw/${name}/home/" + fi + mkdir "${jaildir}/rw/${name}/tmp" +EOF + +# Create the ro+rw mountpoint entries in fstab +echo <<-EOF + echo >/etc/fstab.${name} <<-END + /usr/jail/base /usr/jail/${name} nullfs ro 0 0 + /usr/jail/rw/${name}/etc /usr/jail/${name}/etc nullfs rw 0 0 + /usr/jail/rw/${name}/local /usr/jail/${name}/usr/local nullfs rw 0 0 + /usr/jail/rw/${name}/db /usr/jail/${name}/var/db nullfs rw 0 0 + /usr/jail/rw/${name}/home /usr/jail/${name}/usr/home nullfs rw 0 0 + /usr/jail/rw/${name}/tmp /usr/jail/${name}/var/tmp nullfs rw 0 0 + END +EOF + +# Add the jail_$name_* lines to rc.conf +echo <<-EOF + echo >>/etc/rc.conf <<-END + jail_${name}_rootdir="${jaildir}/${name}" + jail_${name}_hostname="${hostname}" + jail_${name}_ip="${ip}" + jail_${name}_devfs_enable="${devfsenable}" + jail_${name}_mount_enable="YES" + jail_${name}_fstab="/etc/fstab.$name" + END +EOF + +if [ -n "$interface" ]; then + echo <<-EOF + echo >>/etc/rc.conf <<-END + jail_${name}_interface="${interface}" + END +EOF +fi + +if [ "$devfsenable" = "true" ]; then + echo <<-EOF + echo >>/etc/rc.conf <<-END + jail_${name}_devfs_ruleset="$devfsruleset" + END +EOF +fi + +# Add $name to jail_list if $onboot=true +if [ "$onboot" = "true" ]; then + echo <<-EOF + eval $(grep '^jail_list=' /etc/rc.conf) + jail_list="${jail_list} ${name}" + sed -i "s/^jail_list=\".*\"/jail_list=\"${jail_list}\"/" /etc/rc.conf + unset jail_list +EOF +fi + +# Add the normal entries into the jail's rc.conf +echo "echo hostname=\"${hostname}\"" >>"${jaildir}/rw/${name}/etc/rc.conf" +echo 'echo sendmail_enable=\"NONE\"' >>"${jaildir}/rw/${name}/etc/rc.conf" +echo 'echo syslogd_enable=\"YES\"' >>"${jaildir}/rw/${name}/etc/rc.conf" +echo 'echo syslogd_flags=\"-ss\"' >>"${jaildir}/rw/${name}/etc/rc.conf" + } if [ "$present" = "EXISTS" ]; then # The jail currently exists From 1016161bfbe0875f7216b7b22066d14e6aa01cb5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 22 Feb 2012 09:11:00 +0100 Subject: [PATCH 1420/4212] ++changes(2.0.9) Signed-off-by: Nico Schottelius --- doc/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index dc498b9e..c4d02aed 100644 --- a/doc/changelog +++ b/doc/changelog @@ -9,7 +9,8 @@ Changelog displayed (Giel van Schijndel) * New Type: __package_opkg (Giel van Schijndel) * New Type: __package_pkg_freebsd (Jake Guffey) - * Feature __package: Support OpenWRT (Giel van Schijndel) + * Feature __package: Support for OpenWRT (Giel van Schijndel) + * Feature __start_on_boot: Support for OpenWRT (Giel van Schijndel) 2.0.8: 2012-02-20 * Bugfix core: Remove another nasty traceback when sending SIGINT (aka Ctrl-C) From 446f497c4c911929ecb6a54d531bb06a82142926 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 22 Feb 2012 12:13:20 -0500 Subject: [PATCH 1421/4212] Created deleteJail function. Ready to begin debugging. --- conf/type/__jail/gencode-remote | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index 5e1bdc02..37aa8d56 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -109,13 +109,31 @@ startJail() { } deleteJail() { -# If the jail's mountpoints are mounted, unmount them # Remove the jail's rw mountpoints -# Remove the jail's ro mountpoint + echo "rm -rf /usr/jail/rw/${name}" +# Remove the jail's fstab + echo "rm -f /etc/fstab.${name}" # Remove the jail directory -# If the jail's devfs rules are custom (!="jailrules"), remove them + echo "rm -rf /usr/jail/${name}" # Remove jail_$name_* lines from rc.conf + echo <<-EOF + sed -i '.bak' "/^jail_${name}_/d" /etc/rc.conf +EOF # Remove " $name " from jail_list if it's there + echo <<-EOF + eval $(grep '^jail_list=' /etc/rc.conf) + + for JAIL in ${jail_list}; do + if [ ! "${JAIL}" = "${name}" ]; then + new_list="${new_list} ${JAIL}" + fi + done + jail_list="${new_list}" + + sed -i '.bak' "s/^jail_list=\".*\"/jail_list=\"${jail_list}\"/" /etc/rc.conf + unset jail_list + rm -f /etc/rc.conf.bak +EOF } createJail() { @@ -194,8 +212,9 @@ if [ "$onboot" = "true" ]; then echo <<-EOF eval $(grep '^jail_list=' /etc/rc.conf) jail_list="${jail_list} ${name}" - sed -i "s/^jail_list=\".*\"/jail_list=\"${jail_list}\"/" /etc/rc.conf + sed -i '.bak' "s/^jail_list=\".*\"/jail_list=\"${jail_list}\"/" /etc/rc.conf unset jail_list + rm -f /etc/rc.conf.bak EOF fi From 3ebda62f04342ea362d05d88c13500d4a3f6f040 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 22 Feb 2012 12:41:45 -0500 Subject: [PATCH 1422/4212] bugfix -- needed to pass '-r' to ${add_cmd} to retreive package from remote repository. --- conf/type/__package_pkg_freebsd/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__package_pkg_freebsd/gencode-remote b/conf/type/__package_pkg_freebsd/gencode-remote index fa962970..ef6632c0 100755 --- a/conf/type/__package_pkg_freebsd/gencode-remote +++ b/conf/type/__package_pkg_freebsd/gencode-remote @@ -107,7 +107,7 @@ if [ -n "$curr_version" ]; then # PKG *is* installed assert "! ${version} = ${curr_version}" $LINENO cmd="${rm_cmd} ${name}-${curr_version}" execcmd "remove" "${cmd}" - cmd="${add_cmd} ${name}-${version}" + cmd="${add_cmd} -r ${name}-${version}" execcmd "add" "${cmd}" fi else # Don't care what version to use From 0515fd84831f76d31a7689e38931d4d76b55deae Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Thu, 23 Feb 2012 17:17:30 -0500 Subject: [PATCH 1423/4212] Various bugfixes. Needed to use '|| true' on subshell variable assignments in case of empty return Added default status (started=true or false) Added default devfs rules Replaced <<- HEREDOC usage with << Added escapes where necessary within quoted strings or HEREDOCs --- conf/type/__jail/explorer/basepresent | 16 ++- conf/type/__jail/explorer/present | 8 +- conf/type/__jail/explorer/status | 18 ++- conf/type/__jail/gencode-remote | 153 +++++++++++++++++--------- 4 files changed, 132 insertions(+), 63 deletions(-) diff --git a/conf/type/__jail/explorer/basepresent b/conf/type/__jail/explorer/basepresent index 7c21fc08..aa155b03 100755 --- a/conf/type/__jail/explorer/basepresent +++ b/conf/type/__jail/explorer/basepresent @@ -21,22 +21,28 @@ # See if the jailbase.tgz or /usr/jail/base dir exists # +# Debug +#exec >&2 +#set -x + name="base:jailbase.tgz" -exists=0 +out="" save_IFS="$IFS" IFS=":" for cur in $name; do if [ -e "/usr/jail/$cur" ]; then - echo -n "$cur:" - let exists="$exists+1" 2>&1 >&- + out="${out}:${cur}" fi done IFS="$save_IFS" -if [ "$exists" -eq "0" ]; then +if [ -z "$out" ]; then echo "NONE" else - echo "$exists" + echo "${out}" fi +# Debug +#set +x + diff --git a/conf/type/__jail/explorer/present b/conf/type/__jail/explorer/present index 9338fd56..a1f44302 100755 --- a/conf/type/__jail/explorer/present +++ b/conf/type/__jail/explorer/present @@ -21,11 +21,17 @@ # See if the requested jail exists # +# Debug +#exec >&2 +#set -x + if [ -f "$__object/parameter/name" ]; then name="$(cat "$__object/parameter/name")" else name=$__object_id fi -[ -d "/usr/jail/$name" ] && echo "EXISTS" +[ -d "/usr/jail/$name" ] && echo "EXISTS" || echo "NOTEXIST" + +#set +x diff --git a/conf/type/__jail/explorer/status b/conf/type/__jail/explorer/status index 3fe22adc..5f95f406 100755 --- a/conf/type/__jail/explorer/status +++ b/conf/type/__jail/explorer/status @@ -21,12 +21,24 @@ # See if the requested jail is started # +# Debug +#exec >&2 +#set -x + if [ -f "$__object/parameter/name" ]; then name="$(cat "$__object/parameter/name")" else - name=$__object_id + name="$__object_id" fi -jls_output=$(jls | grep "[ ]\/usr\/jail\/$name\$") -[ -n "$jls_output" ] && echo "STARTED" +jls_output="$(jls | grep "[ ^I]\/usr\/jail\/${name}\$")" || true + +if [ -n "${jls_output}" ]; then + echo "STARTED" +else + echo "NOTSTART" +fi + +# Debug +#set +x diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index 37aa8d56..3dfec9ad 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -37,7 +37,11 @@ state="$(cat "$__object/parameter/state")" if [ -f "$__object/parameter/started" ]; then started="$(cat "$__object/parameter/started")" else - started="true" + if [ ! "$state" = "present" ]; then + started="false" + else + started="true" + fi fi if [ -f "$__object/parameter/ip" ]; then @@ -100,45 +104,71 @@ fi stopJail() { # Check $status before issuing command - [ "$status" = "STARTED" ] && echo "/etc/rc.d/jail stop ${name}" + if [ "$status" = "STARTED" ]; then + echo "/etc/rc.d/jail stop ${name}" + fi } startJail() { # Check $status before issuing command - [ ! "$status" = "STARTED" ] && echo "/etc/rc.d/jail start ${name}" + if [ "$status" = "NOTSTART" ]; then + echo "/etc/rc.d/jail start ${name}" + fi } deleteJail() { +# Unmount the jail's mountpoints if necessary + cat <=1 rw mount is mounted still + for DIR in "${output}"; do + umount -F "/etc/fstab.${name}" "\$(echo "${DIR}" | awk '{print $3}')" + done + fi + output="\$(mount | grep "\/${name} (")" || true + if [ -n "\${output}" ]; then # ro mount is mounted still + umount -F "/etc/fstab.${name}" "\$(echo "${output}" | awk '{print $3}')" + fi +EOF # Remove the jail's rw mountpoints - echo "rm -rf /usr/jail/rw/${name}" -# Remove the jail's fstab - echo "rm -f /etc/fstab.${name}" + echo "rm -rf \"/usr/jail/rw/${name}\"" # Remove the jail directory - echo "rm -rf /usr/jail/${name}" + echo "rm -rf \"/usr/jail/${name}\"" +# Remove the jail's fstab + echo "rm -f \"/etc/fstab.${name}\"" # Remove jail_$name_* lines from rc.conf - echo <<-EOF + cat </etc/fstab.${name} <<-END - /usr/jail/base /usr/jail/${name} nullfs ro 0 0 - /usr/jail/rw/${name}/etc /usr/jail/${name}/etc nullfs rw 0 0 - /usr/jail/rw/${name}/local /usr/jail/${name}/usr/local nullfs rw 0 0 - /usr/jail/rw/${name}/db /usr/jail/${name}/var/db nullfs rw 0 0 - /usr/jail/rw/${name}/home /usr/jail/${name}/usr/home nullfs rw 0 0 - /usr/jail/rw/${name}/tmp /usr/jail/${name}/var/tmp nullfs rw 0 0 - END +cat </etc/fstab.${name} <>/etc/rc.conf <<-END - jail_${name}_rootdir="${jaildir}/${name}" - jail_${name}_hostname="${hostname}" - jail_${name}_ip="${ip}" - jail_${name}_devfs_enable="${devfsenable}" - jail_${name}_mount_enable="YES" - jail_${name}_fstab="/etc/fstab.$name" - END +cat <>/etc/rc.conf <>/etc/rc.conf <<-END - jail_${name}_interface="${interface}" - END + cat <>/etc/rc.conf <>/etc/rc.conf <<-END - jail_${name}_devfs_ruleset="$devfsruleset" - END + cat <>/etc/rc.conf <&- >&- + # add default ruleset + cat >>/etc/devfs.rules <>"${jaildir}/rw/${name}/etc/rc.conf" -echo 'echo sendmail_enable=\"NONE\"' >>"${jaildir}/rw/${name}/etc/rc.conf" -echo 'echo syslogd_enable=\"YES\"' >>"${jaildir}/rw/${name}/etc/rc.conf" -echo 'echo syslogd_flags=\"-ss\"' >>"${jaildir}/rw/${name}/etc/rc.conf" - +echo "echo hostname=\"${hostname}\" >>\"${jaildir}/rw/${name}/etc/rc.conf\"" +echo "echo sendmail_enable=\"NONE\" >>\"${jaildir}/rw/${name}/etc/rc.conf\"" +echo "echo syslogd_enable=\"YES\" >>\"${jaildir}/rw/${name}/etc/rc.conf\"" +echo "echo syslogd_flags=\"-ss\" >>\"${jaildir}/rw/${name}/etc/rc.conf\"" } if [ "$present" = "EXISTS" ]; then # The jail currently exists From 20a3538e72ee6182edc7f12abe6e5bcd5dcf2df4 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Tue, 28 Feb 2012 11:21:23 -0500 Subject: [PATCH 1424/4212] Fixed echoing entries Entries weren't being properly echoed into /usr/jail/rw/${name}/etc/rc.conf --- conf/type/__jail/gencode-remote | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index 3dfec9ad..dc18312b 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -265,10 +265,11 @@ EOF fi # Add the normal entries into the jail's rc.conf -echo "echo hostname=\"${hostname}\" >>\"${jaildir}/rw/${name}/etc/rc.conf\"" -echo "echo sendmail_enable=\"NONE\" >>\"${jaildir}/rw/${name}/etc/rc.conf\"" -echo "echo syslogd_enable=\"YES\" >>\"${jaildir}/rw/${name}/etc/rc.conf\"" -echo "echo syslogd_flags=\"-ss\" >>\"${jaildir}/rw/${name}/etc/rc.conf\"" +echo "echo hostname=\\\"${hostname}\\\" >\\\"${jaildir}/rw/${name}/etc/rc.conf\\\"" +echo "echo sshd_enable=\\\"YES\\\" >>\\\"${jaildir}/rw/${name}/etc/rc.conf\\\"" +echo "echo sendmail_enable=\\\"NONE\\\" >>\\\"${jaildir}/rw/${name}/etc/rc.conf\\\"" +echo "echo syslogd_enable=\\\"YES\\\" >>\\\"${jaildir}/rw/${name}/etc/rc.conf\\\"" +echo "echo syslogd_flags=\\\"-ss\\\" >>\\\"${jaildir}/rw/${name}/etc/rc.conf\\\"" } if [ "$present" = "EXISTS" ]; then # The jail currently exists From 46b916c0e18f145a5229e5c8cdf4fe655c433346 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Tue, 28 Feb 2012 16:39:08 -0500 Subject: [PATCH 1425/4212] Various bugfixes Added logic to ensure that /etc/resolv.conf exists within a jail Replaced /var/db, /var/tmp mountpoints with /var mountpoint in jail Added logic to ensure that every jail is bound to an interface Modified how information is inserted into the jail's rc.conf Added ListenAddress directive for SSHd Updated manpage to reflect these changes --- conf/type/__jail/gencode-remote | 38 +++++++++++++++++++++++---------- conf/type/__jail/man.text | 5 +++-- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index dc18312b..c0a35784 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -185,16 +185,18 @@ cat <>/etc/rc.conf <\\\"${jaildir}/rw/${name}/etc/rc.conf\\\"" -echo "echo sshd_enable=\\\"YES\\\" >>\\\"${jaildir}/rw/${name}/etc/rc.conf\\\"" -echo "echo sendmail_enable=\\\"NONE\\\" >>\\\"${jaildir}/rw/${name}/etc/rc.conf\\\"" -echo "echo syslogd_enable=\\\"YES\\\" >>\\\"${jaildir}/rw/${name}/etc/rc.conf\\\"" -echo "echo syslogd_flags=\\\"-ss\\\" >>\\\"${jaildir}/rw/${name}/etc/rc.conf\\\"" +cat <"${jaildir}/rw/${name}/etc/rc.conf" +echo sshd_enable=\"YES\" >>"${jaildir}/rw/${name}/etc/rc.conf" +echo sendmail_enable=\"NONE\" >>"${jaildir}/rw/${name}/etc/rc.conf" +echo syslogd_enable=\"YES\" >>"${jaildir}/rw/${name}/etc/rc.conf" +echo syslogd_flags=\"-ss\" >>"${jaildir}/rw/${name}/etc/rc.conf" + +EOF +# Configure SSHd's listening address +cat < Date: Thu, 1 Mar 2012 08:44:37 +0100 Subject: [PATCH 1426/4212] tiny fix for __start_on_boot/explorer/state Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/explorer/state | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/conf/type/__start_on_boot/explorer/state b/conf/type/__start_on_boot/explorer/state index d1998e22..bf24738a 100755 --- a/conf/type/__start_on_boot/explorer/state +++ b/conf/type/__start_on_boot/explorer/state @@ -49,9 +49,8 @@ case "$os" in [ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent" ;; - centos|fedora|owl|redhat) - state="present" - state=$(chkconfig --level "$runlevel" \"$name\" || echo absent) + amazon|centos|fedora|owl|redhat) + state=$(chkconfig --level "$runlevel" "$name" || echo absent) [ "$state" ] || state="present" ;; From 53ca7e7acad8cf42ba9206c9880c2a9b938e455a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Mar 2012 09:28:23 +0100 Subject: [PATCH 1427/4212] ++changes(2.0.9) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index c4d02aed..7533133a 100644 --- a/doc/changelog +++ b/doc/changelog @@ -11,6 +11,7 @@ Changelog * New Type: __package_pkg_freebsd (Jake Guffey) * Feature __package: Support for OpenWRT (Giel van Schijndel) * Feature __start_on_boot: Support for OpenWRT (Giel van Schijndel) + * Feature __start_on_boot: Support for Amazon Linux (Matt Coddington) 2.0.8: 2012-02-20 * Bugfix core: Remove another nasty traceback when sending SIGINT (aka Ctrl-C) From 5dc8d305e53f8f34023c439cea19ead9704ab02b Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Mon, 5 Mar 2012 14:57:37 -0500 Subject: [PATCH 1428/4212] Bugfix Modified pipeline to determine ${name}'s version if it's installed. --- conf/type/__package_pkg_freebsd/explorer/pkg_version | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/conf/type/__package_pkg_freebsd/explorer/pkg_version b/conf/type/__package_pkg_freebsd/explorer/pkg_version index 4bca24b6..1335ba79 100755 --- a/conf/type/__package_pkg_freebsd/explorer/pkg_version +++ b/conf/type/__package_pkg_freebsd/explorer/pkg_version @@ -30,6 +30,10 @@ fi # Don't produce "no pkgs installed" output -- breaks things PKG_OUTPUT=$(pkg_info 2>&1) if [ ! "$PKG_OUTPUT" = "pkg_info: no packages installed" ]; then - echo "$(echo "$PKG_OUTPUT" | grep "^$name-" | cut '-d ' -f1 | sed "s/$name-//g")" + echo -n "$(echo "$PKG_OUTPUT" \ + | awk '{print $1}' \ + | sed 's/^\(.*\)-\([^-]*\)$/name:\1 ver:\2/g' \ + | grep "name:$name ver:" \ + | sed 's/^.*ver:\(.*\)/\1/g')" fi From d3b9aa6769ca1e8ffad410c2e5d5c3babfa3ed7e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Mar 2012 11:19:26 +0100 Subject: [PATCH 1429/4212] begin support for sensible exit codes of cdist Signed-off-by: Nico Schottelius --- bin/cdist | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/bin/cdist b/bin/cdist index 5456b134..edd610a5 100755 --- a/bin/cdist +++ b/bin/cdist @@ -91,13 +91,13 @@ def commandline(): logging.root.setLevel(logging.DEBUG) log.debug(args) - args.func(args) + return args.func(args) def config(args): - configinstall(args, mode=cdist.config.Config) + return configinstall(args, mode=cdist.config.Config) def install(args): - configinstall(args, mode=cdist.install.Install) + return configinstall(args, mode=cdist.install.Install) def configinstall(args, mode): """Configure or install remote system""" @@ -140,6 +140,7 @@ def configinstall(args, mode): if len(failed_hosts) > 0: log.warn("Failed to deploy to the following hosts: " + " ".join(failed_hosts)) + exit_code = 1 time_end = time.time() log.info("Total processing time for %s host(s): %s", len(args.host), @@ -203,6 +204,8 @@ if __name__ == "__main__": # Sys is needed for sys.exit() import sys + exit_code = 0 + try: import logging import os @@ -226,11 +229,15 @@ if __name__ == "__main__": logging.basicConfig(format='%(levelname)s: %(message)s') if re.match("__", os.path.basename(sys.argv[0])): - emulator() + run = emulator() else: - commandline() - - sys.exit(0) + run = commandline() except KeyboardInterrupt: - sys.exit(0) + pass + + # Determine exit code by return value of function + if not run: + exit_code = 1 + + sys.exit(exit_code) From 531ad2966fe1580880fc4c1192192eb98f1f0b26 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Mar 2012 11:48:41 +0100 Subject: [PATCH 1430/4212] in fork() do sys.exit() so parent knows about failures Signed-off-by: Nico Schottelius --- bin/cdist | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/bin/cdist b/bin/cdist index edd610a5..9c15a8cf 100755 --- a/bin/cdist +++ b/bin/cdist @@ -177,28 +177,25 @@ def configinstall_onehost(host, args, mode, parallel): context.cleanup() except cdist.Error as e: - log.error(e) - return False - except KeyboardInterrupt: - # Do not care in sequential mode, catch in parallel mode - if not parallel: - raise + if parallel: + log.error(e) + sys.exit(1) else: - # Catch here, above does not need to know about our errors - return False + raise - return True + 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 emulator(): """Prepare and run emulator""" - try: - import cdist.emulator - emulator = cdist.emulator.Emulator(sys.argv) - emulator.run() - - except cdist.Error as e: - log.error(e) - sys.exit(1) + import cdist.emulator + emulator = cdist.emulator.Emulator(sys.argv) + return emulator.run() if __name__ == "__main__": # Sys is needed for sys.exit() @@ -213,9 +210,8 @@ if __name__ == "__main__": cdistpythonversion = '3.2' if sys.version < cdistpythonversion: - print('Cdist requires Python >= ' + cdistpythonversion + + raise cdist.Error('Cdist requires Python >= ' + cdistpythonversion + ' on the source host.') - sys.exit(1) # Ensure our /lib/ is included into PYTHON_PATH sys.path.insert(0, os.path.abspath( @@ -236,6 +232,10 @@ if __name__ == "__main__": except KeyboardInterrupt: pass + except cdist.Error as e: + log.error(e) + exit_code = 1 + # Determine exit code by return value of function if not run: exit_code = 1 From 58a88ca5bd5dacad2860abeeca60ea24555e1e0b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Mar 2012 11:50:16 +0100 Subject: [PATCH 1431/4212] remove useless try: block that was needed to find out how multiprocess /sigint behaviour works NOT needed: KeyBoardInterrupet (aka SIGINT) is forwarded to processes spawned by multiprocess! Signed-off-by: Nico Schottelius --- bin/cdist | 59 ++++++++++++++++++++++--------------------------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/bin/cdist b/bin/cdist index 9c15a8cf..97dd4107 100755 --- a/bin/cdist +++ b/bin/cdist @@ -115,48 +115,35 @@ def configinstall(args, mode): import atexit atexit.register(lambda: os.remove(initial_manifest_temp_path)) - try: - 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: - if not configinstall_onehost(host, args, mode, parallel=False): - failed_hosts.append(host) + process = {} + failed_hosts = [] + time_start = time.time() + for host in args.host: if args.parallel: - for p in process.keys(): - log.debug("Joining process %s", p) - process[p].join() + log.debug("Creating child process for %s", host) + process[host] = multiprocessing.Process(target=configinstall_onehost, args=(host, args, mode, True)) + process[host].start() + else: + if not configinstall_onehost(host, args, mode, parallel=False): + failed_hosts.append(host) - if not process[p].exitcode == 0: - failed_hosts.append(p) + if args.parallel: + for p in process.keys(): + log.debug("Joining process %s", p) + process[p].join() - if len(failed_hosts) > 0: - log.warn("Failed to deploy to the following hosts: " + - " ".join(failed_hosts)) - exit_code = 1 + if not process[p].exitcode == 0: + failed_hosts.append(p) - 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: + log.warn("Failed to deploy to the following hosts: " + + " ".join(failed_hosts)) + exit_code = 1 - except KeyboardInterrupt: - if args.parallel: - for p in process.keys(): - # NOT needed: KeyBoardInterrupet (aka SIGINT) - # is forwarded to processes spawned by multiprocess! - # pid = process[p].pid.__str__() - #log.warn("Terminating deploy " + p + " (" + pid + ")") - # process[p].terminate() - pass - - sys.exit(0) + time_end = time.time() + log.info("Total processing time for %s host(s): %s", len(args.host), + (time_end - time_start)) def configinstall_onehost(host, args, mode, parallel): From 5001e9cbe739a55d516c3912832b21372d181186 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Mar 2012 13:01:11 +0100 Subject: [PATCH 1432/4212] prevent tracebacks in tempfile code/initial manifest from stdin Signed-off-by: Nico Schottelius --- bin/cdist | 29 +++++++++++++++++------------ lib/cdist/banner.py | 2 +- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/bin/cdist b/bin/cdist index 97dd4107..79b8cae3 100755 --- a/bin/cdist +++ b/bin/cdist @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -91,13 +91,13 @@ def commandline(): logging.root.setLevel(logging.DEBUG) log.debug(args) - return args.func(args) + args.func(args) def config(args): - return configinstall(args, mode=cdist.config.Config) + configinstall(args, mode=cdist.config.Config) def install(args): - return configinstall(args, mode=cdist.install.Install) + configinstall(args, mode=cdist.install.Install) def configinstall(args, mode): """Configure or install remote system""" @@ -108,9 +108,13 @@ def configinstall(args, mode): if args.manifest == '-': # read initial manifest from stdin import tempfile - handle, initial_manifest_temp_path = tempfile.mkstemp(prefix='cdist.stdin.') - with os.fdopen(handle, 'w') as fd: - fd.write(sys.stdin.read()) + 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)) @@ -139,12 +143,15 @@ def configinstall(args, mode): if len(failed_hosts) > 0: log.warn("Failed to deploy to the following hosts: " + " ".join(failed_hosts)) - exit_code = 1 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: + return False + else: + return True def configinstall_onehost(host, args, mode, parallel): """Configure or install ONE remote system""" @@ -212,9 +219,9 @@ if __name__ == "__main__": logging.basicConfig(format='%(levelname)s: %(message)s') if re.match("__", os.path.basename(sys.argv[0])): - run = emulator() + emulator() else: - run = commandline() + commandline() except KeyboardInterrupt: pass @@ -224,7 +231,5 @@ if __name__ == "__main__": exit_code = 1 # Determine exit code by return value of function - if not run: - exit_code = 1 sys.exit(exit_code) diff --git a/lib/cdist/banner.py b/lib/cdist/banner.py index 4148fa72..edfa72e8 100644 --- a/lib/cdist/banner.py +++ b/lib/cdist/banner.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # From eef408c1b304d43b4f9826cbc5b7c346a360fb21 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Mar 2012 14:26:28 +0100 Subject: [PATCH 1433/4212] record failing host and continue Signed-off-by: Nico Schottelius --- bin/cdist | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/bin/cdist b/bin/cdist index 79b8cae3..d291beb0 100755 --- a/bin/cdist +++ b/bin/cdist @@ -129,29 +129,29 @@ def configinstall(args, mode): process[host] = multiprocessing.Process(target=configinstall_onehost, args=(host, args, mode, True)) process[host].start() else: - if not configinstall_onehost(host, args, mode, parallel=False): + try: + configinstall_onehost(host, args, mode, parallel=False) + except cdist.Error as e: + # FIXME: save the error and display at the end? + # Would be non-consistent to parallel mode failed_hosts.append(host) + # Catch errors in parallel mode when joining if args.parallel: - for p in process.keys(): - log.debug("Joining process %s", p) - process[p].join() + for host in process.keys(): + log.debug("Joining process %s", host) + process[host].join() - if not process[p].exitcode == 0: - failed_hosts.append(p) - - if len(failed_hosts) > 0: - log.warn("Failed to deploy to the following hosts: " + - " ".join(failed_hosts)) + 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: - return False - else: - return True + raise cdist.Error("Failed to deploy to the following hosts: " + + " ".join(failed_hosts)) def configinstall_onehost(host, args, mode, parallel): """Configure or install ONE remote system""" From 1ea0ea0b1b2c4cd5caefaa1dcc79c672f5765ac6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 9 Mar 2012 20:05:50 +0100 Subject: [PATCH 1434/4212] add support for crontab EXTENSIONS, e.g. @reboot Signed-off-by: Steven Armstrong --- conf/type/__cron/man.text | 12 ++++++-- conf/type/__cron/manifest | 45 ++++++++--------------------- conf/type/__cron/parameter/optional | 1 + 3 files changed, 23 insertions(+), 35 deletions(-) diff --git a/conf/type/__cron/man.text b/conf/type/__cron/man.text index c4852b7f..2e3ae925 100644 --- a/conf/type/__cron/man.text +++ b/conf/type/__cron/man.text @@ -35,14 +35,22 @@ month:: See crontab(5). Defaults to * day_of_week:: See crontab(5). Defaults to * +special:: + See EXTENSIONS in crontab(5). e.g. reboot, yearly, monthly + If given all other time and date fields are ignored. EXAMPLES -------- -------------------------------------------------------------------------------- -# add cronjob -__cron some-id --user root --command "/path/to/script" +# run Monday to Saturday at 23:15 +__cron some-id --user root --command "/path/to/script" \ + --hour 23 --minute 15 --day_of_week 1-6 + +# run on reboot +__cron some-id --user root --command "/path/to/script" \ + --special reboot # remove cronjob __cron some-id --user root --command "/path/to/script" --state absent diff --git a/conf/type/__cron/manifest b/conf/type/__cron/manifest index 01c4358c..e8a77229 100755 --- a/conf/type/__cron/manifest +++ b/conf/type/__cron/manifest @@ -23,44 +23,23 @@ user="$(cat "$__object/parameter/user")" command="$(cat "$__object/parameter/command")" # set defaults -if [ ! -f "$__object/parameter/state" ]; then - echo "present" > "$__object/parameter/state" -fi -if [ -f "$__object/parameter/minute" ]; then - minute="$(cat "$__object/parameter/minute")" +test -f "$__object/parameter/state" || echo "present" > "$__object/parameter/state" + +if [ -f "$__object/parameter/special" ]; then + special="$(cat "$__object/parameter/special")" + entry="@$special $command" else - minute="*" - echo "$minute" > "$__object/parameter/minute" -fi -if [ -f "$__object/parameter/hour" ]; then - hour="$(cat "$__object/parameter/hour")" -else - hour="*" - echo "$hour" > "$__object/parameter/hour" -fi -if [ -f "$__object/parameter/day_of_month" ]; then - day_of_month="$(cat "$__object/parameter/day_of_month")" -else - day_of_month="*" - echo "$day_of_month" > "$__object/parameter/day_of_month" -fi -if [ -f "$__object/parameter/month" ]; then - month="$(cat "$__object/parameter/month")" -else - month="*" - echo "$month" > "$__object/parameter/month" -fi -if [ -f "$__object/parameter/day_of_week" ]; then - day_of_week="$(cat "$__object/parameter/day_of_week")" -else - day_of_week="*" - echo "$day_of_week" > "$__object/parameter/day_of_week" + 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: if changed, also change in explorers prefix="#cdist:__cron/$name" suffix="#/cdist:__cron/$name" echo "$prefix" | tee "$__object/parameter/prefix" > "$__object/parameter/entry" -echo "$minute $hour $day_of_month $month $day_of_week $command" >> "$__object/parameter/entry" +echo "$entry" >> "$__object/parameter/entry" echo "$suffix" | tee "$__object/parameter/suffix" >> "$__object/parameter/entry" - diff --git a/conf/type/__cron/parameter/optional b/conf/type/__cron/parameter/optional index 1a4aae3d..e81b64c3 100644 --- a/conf/type/__cron/parameter/optional +++ b/conf/type/__cron/parameter/optional @@ -4,3 +4,4 @@ hour day_of_month month day_of_week +special From 3e6b866cae62707d0fb8ab2b58e9487c01388f09 Mon Sep 17 00:00:00 2001 From: Matt Coddington Date: Fri, 9 Mar 2012 15:43:49 -0500 Subject: [PATCH 1435/4212] support rsync for remote copy --- lib/cdist/exec/remote.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 124c1b4f..2e7d9d10 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -77,7 +77,12 @@ class Remote(object): self.log.debug("Remote transfer: %s -> %s", source, destination) self.rmdir(destination) command = self._copy.split() - command.extend(["-r", source, self.target_host + ":" + destination]) + # support rsync by appending a "/" to the source if it's a directory + if os.path.isdir(source) == True: + command.extend(["-r", source + "/", self.target_host + ":" + destination]) + else: + command.extend(["-r", source, self.target_host + ":" + destination]) + self._run_command(command) def run_script(self, script, env=None, return_output=False): From 534ccc86ab46268ffffb7e1a88cd2d672a2843f2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Mar 2012 23:14:06 +0100 Subject: [PATCH 1436/4212] clearify same object and use example.org in doc Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-stages.text | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/man/man7/cdist-stages.text b/doc/man/man7/cdist-stages.text index c1b73a8d..fa5e28d1 100644 --- a/doc/man/man7/cdist-stages.text +++ b/doc/man/man7/cdist-stages.text @@ -27,7 +27,7 @@ The initial manifest, which should be used for mappings of hosts to types, is executed. This stage creates objects in a cconfig database that contains the objects as defined in the manifest for the specific host. In this stage, no conflicts may occur, i.e. no object of the same type with the same id may -be created. +be created, if it has different parameters. STAGE 3: OBJECT INFORMATION RETRIEVAL @@ -44,7 +44,7 @@ Every object is checked whether its type has a executable manifest. The manifest script may generate and change the created objects. In other words, one type can reuse other types. -For instance the object __apache/www.test.ch is of type __apache, which may +For instance the object __apache/www.example.org is of type __apache, which may contain a manifest script, which creates new objects of type __file. The newly created objects are merged back into the existing tree. No conflicts From 5f2f8e2bd2efd404d17004590a5ba3030bd9c86d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Mar 2012 23:14:15 +0100 Subject: [PATCH 1437/4212] no == true needed Signed-off-by: Nico Schottelius --- lib/cdist/exec/remote.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 2e7d9d10..11b8c78e 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -78,7 +78,7 @@ class Remote(object): self.rmdir(destination) command = self._copy.split() # support rsync by appending a "/" to the source if it's a directory - if os.path.isdir(source) == True: + if os.path.isdir(source): command.extend(["-r", source + "/", self.target_host + ":" + destination]) else: command.extend(["-r", source, self.target_host + ":" + destination]) From 79e8eff032cd24fcd6c178d6881c6a11dcca0d42 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Mar 2012 23:23:22 +0100 Subject: [PATCH 1438/4212] ONE != ONLY Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-type.text | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/man/man7/cdist-type.text b/doc/man/man7/cdist-type.text index 1147511e..22e72a01 100644 --- a/doc/man/man7/cdist-type.text +++ b/doc/man/man7/cdist-type.text @@ -139,8 +139,8 @@ 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 - ONLY INSTANCE ONLY ------------------------------- +SINGLETON - ONE INSTANCE ONLY +----------------------------- If you want to ensure that a type can only be used once per target, you can mark it as a singleton: Just create the (empty) file "singleton" in your type directory: From cec0418794d6f04f07cbd8b82d4c104f66d93b6a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Mar 2012 23:27:52 +0100 Subject: [PATCH 1439/4212] ++changes(2.0.9) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 7533133a..cdc0c956 100644 --- a/doc/changelog +++ b/doc/changelog @@ -7,6 +7,7 @@ Changelog 2.0.9: * Cleanup documentation: Fix environment variable list to be properly displayed (Giel van Schijndel) + * Cleanup documentation: Some minor corrections * New Type: __package_opkg (Giel van Schijndel) * New Type: __package_pkg_freebsd (Jake Guffey) * Feature __package: Support for OpenWRT (Giel van Schijndel) From c12501b63df9b57e74a16445116560ae083fb13e Mon Sep 17 00:00:00 2001 From: Matt Coddington Date: Fri, 9 Mar 2012 17:32:45 -0500 Subject: [PATCH 1440/4212] added rsync copy example --- other/examples/remote/rsync/copy | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100755 other/examples/remote/rsync/copy diff --git a/other/examples/remote/rsync/copy b/other/examples/remote/rsync/copy new file mode 100755 index 00000000..ca1f1959 --- /dev/null +++ b/other/examples/remote/rsync/copy @@ -0,0 +1,30 @@ +#!/bin/sh +# +# 2012 Matt Coddington (mcoddington at gmail.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Use rsync to copy files. This particular invocation of rsync makes +# a backup of the file before overwriting it. For example, if cdist +# overwrites /etc/passwd then you'll end up with the old copy at +# /etc/passwd~cdist +# +# Usage: +# __remote_copy="/path/to/this/script" cdist config target_host +# + +rsync --backup --suffix=~cdist -e 'ssh -i /root/.ssh/cdist -o User=root' $@ From 9c98f387b2d154219072bfa70f5a739e061a87c1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Mar 2012 23:34:46 +0100 Subject: [PATCH 1441/4212] remove redundant redundant sentence Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-type.text | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/man/man7/cdist-type.text b/doc/man/man7/cdist-type.text index 22e72a01..7e3198f3 100644 --- a/doc/man/man7/cdist-type.text +++ b/doc/man/man7/cdist-type.text @@ -186,10 +186,8 @@ 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. The output (stdout) of these script is -saved by cdist and will be executed on the target. +and the type specific explorers. If the gencode scripts encounter an error, it should print diagnostic messages to stderr and exit non-zero. If you need to debug the gencode From 115f0549555c66c59c50915d99bdde8326297a25 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Mar 2012 23:39:47 +0100 Subject: [PATCH 1442/4212] move submit stuff into cdist-hacker Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-hacker.text | 8 +++++--- doc/man/man7/cdist-type.text | 10 +++------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/doc/man/man7/cdist-hacker.text b/doc/man/man7/cdist-hacker.text index 646439a3..ee88ca29 100644 --- a/doc/man/man7/cdist-hacker.text +++ b/doc/man/man7/cdist-hacker.text @@ -54,9 +54,9 @@ work nor kill the authors brain: seperate 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, you can contact me -(IRC, Mailinglist, Phone, RFC 1149) and I'll check your code before -including it. +As soon as your work meets these requirements, write a mail +for inclusion to the mailinglist **cdist at cdist -- at -- l.schottelius.org** +or open a pull request at http://github.com/telmich/cdist. HOW TO SUBMIT A NEW TYPE @@ -75,6 +75,8 @@ code and thus such a type introduces redundant functionality that is given by core cdist already. + + SEE ALSO -------- - cdist(7) diff --git a/doc/man/man7/cdist-type.text b/doc/man/man7/cdist-type.text index 7e3198f3..92a2b36d 100644 --- a/doc/man/man7/cdist-type.text +++ b/doc/man/man7/cdist-type.text @@ -222,17 +222,13 @@ 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 submit the git url containing the type for -inclusion to the mailinglist **cdist at cdist -- at -- l.schottelius.org** -or open a pull request at http://github.com/telmich/cdist. - -Ensure a corresponding manpage named man.text in asciidoc format with -the manpage-name "cdist-type__NAME" is included in the type directory. - +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) From 9ef7482ec1669f78c174d8042768b37ad4c90b72 Mon Sep 17 00:00:00 2001 From: Matt Coddington Date: Fri, 9 Mar 2012 17:39:54 -0500 Subject: [PATCH 1443/4212] remove ssh key location to simplify and match other examples --- other/examples/remote/rsync/copy | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/other/examples/remote/rsync/copy b/other/examples/remote/rsync/copy index ca1f1959..f6b93c5c 100755 --- a/other/examples/remote/rsync/copy +++ b/other/examples/remote/rsync/copy @@ -18,13 +18,13 @@ # along with cdist. If not, see . # # -# Use rsync to copy files. This particular invocation of rsync makes -# a backup of the file before overwriting it. For example, if cdist -# overwrites /etc/passwd then you'll end up with the old copy at -# /etc/passwd~cdist +# Use rsync over ssh to copy files. This particular invocation of +# rsync makes a backup of the file before overwriting it. For example, +# if cdist overwrites /etc/passwd then you'll end up with the old copy +# at /etc/passwd~cdist. # # Usage: # __remote_copy="/path/to/this/script" cdist config target_host # -rsync --backup --suffix=~cdist -e 'ssh -i /root/.ssh/cdist -o User=root' $@ +rsync --backup --suffix=~cdist -e 'ssh -o User=root' $@ From a35c81d2e1d750b9cc24994d5bbba0320d8bae39 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 Mar 2012 23:48:04 +0100 Subject: [PATCH 1444/4212] ++changes(2.0.9) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index cdc0c956..8164228d 100644 --- a/doc/changelog +++ b/doc/changelog @@ -13,6 +13,7 @@ Changelog * Feature __package: Support for OpenWRT (Giel van Schijndel) * Feature __start_on_boot: Support for OpenWRT (Giel van Schijndel) * Feature __start_on_boot: Support for Amazon Linux (Matt Coddington) + * New Example: Use rsync to backup files (Matt Coddington) 2.0.8: 2012-02-20 * Bugfix core: Remove another nasty traceback when sending SIGINT (aka Ctrl-C) From dc355e7aa22cb937ddabef9c0300301e2702422a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 10 Mar 2012 00:25:13 +0100 Subject: [PATCH 1445/4212] be consistent - log parsing is easy Signed-off-by: Nico Schottelius --- bin/cdist | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/cdist b/bin/cdist index d291beb0..c6467477 100755 --- a/bin/cdist +++ b/bin/cdist @@ -132,8 +132,6 @@ def configinstall(args, mode): try: configinstall_onehost(host, args, mode, parallel=False) except cdist.Error as e: - # FIXME: save the error and display at the end? - # Would be non-consistent to parallel mode failed_hosts.append(host) # Catch errors in parallel mode when joining @@ -171,6 +169,7 @@ def configinstall_onehost(host, args, mode, parallel): context.cleanup() except cdist.Error as e: + # We are running in our own process here, need to sys.exit! if parallel: log.error(e) sys.exit(1) From 10d0cf00d66a66be937b5234f5073de12d34fa7c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 10 Mar 2012 14:07:13 +0100 Subject: [PATCH 1446/4212] /special/raw/ Signed-off-by: Steven Armstrong --- conf/type/__cron/man.text | 9 +++++---- conf/type/__cron/manifest | 6 +++--- conf/type/__cron/parameter/optional | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/conf/type/__cron/man.text b/conf/type/__cron/man.text index 2e3ae925..039be04c 100644 --- a/conf/type/__cron/man.text +++ b/conf/type/__cron/man.text @@ -35,9 +35,10 @@ month:: See crontab(5). Defaults to * day_of_week:: See crontab(5). Defaults to * -special:: - See EXTENSIONS in crontab(5). e.g. reboot, yearly, monthly - If given all other time and date fields are ignored. +raw:: + Take whatever the user has given instead of time and date fields. + If given, all other time and date fields are ignored. + Can for example be used to specify cron EXTENSIONS like reboot, yearly etc. EXAMPLES @@ -50,7 +51,7 @@ __cron some-id --user root --command "/path/to/script" \ # run on reboot __cron some-id --user root --command "/path/to/script" \ - --special reboot + --raw @reboot # remove cronjob __cron some-id --user root --command "/path/to/script" --state absent diff --git a/conf/type/__cron/manifest b/conf/type/__cron/manifest index e8a77229..7aca41ff 100755 --- a/conf/type/__cron/manifest +++ b/conf/type/__cron/manifest @@ -25,9 +25,9 @@ command="$(cat "$__object/parameter/command")" # set defaults test -f "$__object/parameter/state" || echo "present" > "$__object/parameter/state" -if [ -f "$__object/parameter/special" ]; then - special="$(cat "$__object/parameter/special")" - entry="@$special $command" +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 "*")" diff --git a/conf/type/__cron/parameter/optional b/conf/type/__cron/parameter/optional index e81b64c3..517d821e 100644 --- a/conf/type/__cron/parameter/optional +++ b/conf/type/__cron/parameter/optional @@ -4,4 +4,4 @@ hour day_of_month month day_of_week -special +raw From f3545a51fe88edf0ce8bf92d794f6f39b0500091 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 10 Mar 2012 14:08:57 +0100 Subject: [PATCH 1447/4212] be nice with them users Signed-off-by: Steven Armstrong --- conf/type/__cron/man.text | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/type/__cron/man.text b/conf/type/__cron/man.text index 039be04c..47f47456 100644 --- a/conf/type/__cron/man.text +++ b/conf/type/__cron/man.text @@ -39,6 +39,8 @@ raw:: Take whatever the user has given instead of time and date fields. If given, all other time and date fields are ignored. Can for example be used to specify cron EXTENSIONS like reboot, yearly etc. + See crontab(5) for the extensions if any that your cron implementation + implements. EXAMPLES From 2b22e5de242a23797b064b05d24385a6c0adfdeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Bondis?= Date: Mon, 12 Mar 2012 14:13:02 -0400 Subject: [PATCH 1448/4212] added informations for templating --- doc/man/man7/cdist-best-practice.text | 34 +++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/doc/man/man7/cdist-best-practice.text b/doc/man/man7/cdist-best-practice.text index bbfd084a..2674bc06 100644 --- a/doc/man/man7/cdist-best-practice.text +++ b/doc/man/man7/cdist-best-practice.text @@ -153,6 +153,40 @@ implement this scenario with a gateway host and sudo: 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 + +-------------------------------------------------------------------------------------- +#!/bin/bash +# in the template, use cat << eof (here document) to output the text +# and use standard shell variables in the template +# output everything in the template script to stdout +cat << EOF +server { + listen 80; + server_name $SERVERNAME; + root $ROOT; + + access_log /var/log/nginx/$SERVERNAME_access.log + error_log /var/log/nginx/$SERVERNAME_error.log +} +EOF +-------------------------------------------------------------------------------------- + +* in the manifest, export the relevant variables and add the following lines in your manifest: +-------------------------------------------------------------------------------------- +# export variables needed for the template + export SERVERNAME='test" + export ROOT='/var/www/test' +# render the template + mkdir -p "$__object/files" + "$__type/templates/collectd.conf" > "$__object/files/collectd.conf" +# send the rendered template + __file /etc/collectd.conf --state present --source "$__object/files/collectd.conf" +-------------------------------------------------------------------------------------- + SEE ALSO -------- - cdist(1) From 1878c35ac4f30822e68f55e0573f8c1c8a00977b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Bondis?= Date: Mon, 12 Mar 2012 14:16:37 -0400 Subject: [PATCH 1449/4212] modify template name in example --- doc/man/man7/cdist-best-practice.text | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/man/man7/cdist-best-practice.text b/doc/man/man7/cdist-best-practice.text index 2674bc06..9e18bd2f 100644 --- a/doc/man/man7/cdist-best-practice.text +++ b/doc/man/man7/cdist-best-practice.text @@ -182,9 +182,9 @@ EOF export ROOT='/var/www/test' # render the template mkdir -p "$__object/files" - "$__type/templates/collectd.conf" > "$__object/files/collectd.conf" + "$__type/templates/basic.conf.sh" > "$__object/files/basic.conf" # send the rendered template - __file /etc/collectd.conf --state present --source "$__object/files/collectd.conf" + __file /etc/nginx/sites-available/test.conf --state present --source "$__object/files/basic.conf" -------------------------------------------------------------------------------------- SEE ALSO From 6b125d26ecd856ab4827c6ce89c2836176ff9623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Bondis?= Date: Mon, 12 Mar 2012 14:19:41 -0400 Subject: [PATCH 1450/4212] doc: template changed to /bin/sh --- doc/man/man7/cdist-best-practice.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man/man7/cdist-best-practice.text b/doc/man/man7/cdist-best-practice.text index 9e18bd2f..a8851f7f 100644 --- a/doc/man/man7/cdist-best-practice.text +++ b/doc/man/man7/cdist-best-practice.text @@ -159,7 +159,7 @@ TEMPLATING * create the template as an executable file like templates/basic.conf.sh, it will output text using shell variables for the values -------------------------------------------------------------------------------------- -#!/bin/bash +#!/bin/sh # in the template, use cat << eof (here document) to output the text # and use standard shell variables in the template # output everything in the template script to stdout From bb926f88bd6b2dc1d82344de49dd92916d78d259 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Mar 2012 19:24:30 +0100 Subject: [PATCH 1451/4212] ++changes(2.0.9) Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index 8164228d..29e0cbdf 100644 --- a/doc/changelog +++ b/doc/changelog @@ -14,6 +14,8 @@ Changelog * Feature __start_on_boot: Support for OpenWRT (Giel van Schijndel) * Feature __start_on_boot: Support for Amazon Linux (Matt Coddington) * New Example: Use rsync to backup files (Matt Coddington) + * Feature core: Exit non-zero, if configuration failed + * Documentation: Describe how to do templating (Aurélien Bondis) 2.0.8: 2012-02-20 * Bugfix core: Remove another nasty traceback when sending SIGINT (aka Ctrl-C) From 73113a2fe97a250f5ce13eee390c61699445bfe5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Mar 2012 20:17:59 +0100 Subject: [PATCH 1452/4212] --whitespace Signed-off-by: Nico Schottelius --- conf/type/__mysql_database/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__mysql_database/gencode-remote b/conf/type/__mysql_database/gencode-remote index c0e862f3..7cd32242 100755 --- a/conf/type/__mysql_database/gencode-remote +++ b/conf/type/__mysql_database/gencode-remote @@ -35,7 +35,7 @@ EOFF # if --user was specified if [ -f "$__object/parameter/user" ]; then user="$(cat "$__object/parameter/user")" - + # if --password was specified if [ -f "$__object/parameter/password" ]; then password="$(cat "$__object/parameter/password")" From 48f169f11fb97ac66f3c85f63cd3c650b248d680 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Mar 2012 20:18:49 +0100 Subject: [PATCH 1453/4212] ++changes(2.0.9) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 29e0cbdf..4899e915 100644 --- a/doc/changelog +++ b/doc/changelog @@ -10,6 +10,7 @@ Changelog * Cleanup documentation: Some minor corrections * New Type: __package_opkg (Giel van Schijndel) * New Type: __package_pkg_freebsd (Jake Guffey) + * New Type: __mysql_database (Benedikt Koeppel) * Feature __package: Support for OpenWRT (Giel van Schijndel) * Feature __start_on_boot: Support for OpenWRT (Giel van Schijndel) * Feature __start_on_boot: Support for Amazon Linux (Matt Coddington) From ff42f7dd4c7ec47457e2297787d329f59dea4bff Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Mar 2012 20:20:18 +0100 Subject: [PATCH 1454/4212] document return code Signed-off-by: Nico Schottelius --- doc/man/man1/cdist.text | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/man/man1/cdist.text b/doc/man/man1/cdist.text index 99c28f8b..e46e84a3 100644 --- a/doc/man/man1/cdist.text +++ b/doc/man/man1/cdist.text @@ -90,10 +90,20 @@ TMPDIR, TEMP, TMP:: more information. This is rather useful, if the standard directory used does not allow executables. + +EXIT STATUS +----------- +The following exit values shall be returned: + +0:: + Successful completion +1:: + One or more host configuration failed. + + SEE ALSO -------- - cdist(7) -- cdist-type-emulator(1) - cdist-reference(7) From 04c768d51d1a6333c4b8399219a5921bdcd70aed Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Mar 2012 20:20:56 +0100 Subject: [PATCH 1455/4212] lib: 2.0.9 Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index c1e16ffb..bd8e6483 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -19,7 +19,7 @@ # # -VERSION = "2.0.8" +VERSION = "2.0.9" BANNER = """ .. . .x+=:. s From 0e99dbc30acf0954c343866ea49dc4f56a0566e2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Mar 2012 20:23:58 +0100 Subject: [PATCH 1456/4212] ++releasedate Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 4899e915..dead9aa8 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.0.9: +2.0.9: 2012-03-12 * Cleanup documentation: Fix environment variable list to be properly displayed (Giel van Schijndel) * Cleanup documentation: Some minor corrections From db14277b411bd05d3a651a749addc075da04f2a0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Mar 2012 20:54:41 +0100 Subject: [PATCH 1457/4212] move __mysql_server to types_submitted_for_inclusion Signed-off-by: Nico Schottelius --- .../.readmes/README.inclusion.specific | 1 + .../__mysql_server/README.inclusion | 1 + .../types_submitted_for_inclusion}/__mysql_server/files/my.cnf | 0 .../types_submitted_for_inclusion}/__mysql_server/gencode-remote | 0 .../types_submitted_for_inclusion}/__mysql_server/man.text | 0 .../types_submitted_for_inclusion}/__mysql_server/manifest | 0 .../__mysql_server/parameter/optional | 0 .../__mysql_server/parameter/required | 0 .../types_submitted_for_inclusion}/__mysql_server/singleton | 0 9 files changed, 2 insertions(+) create mode 120000 other/types_submitted_for_inclusion/__mysql_server/README.inclusion rename {conf/type => other/types_submitted_for_inclusion}/__mysql_server/files/my.cnf (100%) rename {conf/type => other/types_submitted_for_inclusion}/__mysql_server/gencode-remote (100%) rename {conf/type => other/types_submitted_for_inclusion}/__mysql_server/man.text (100%) rename {conf/type => other/types_submitted_for_inclusion}/__mysql_server/manifest (100%) rename {conf/type => other/types_submitted_for_inclusion}/__mysql_server/parameter/optional (100%) rename {conf/type => other/types_submitted_for_inclusion}/__mysql_server/parameter/required (100%) rename {conf/type => other/types_submitted_for_inclusion}/__mysql_server/singleton (100%) diff --git a/other/types_submitted_for_inclusion/.readmes/README.inclusion.specific b/other/types_submitted_for_inclusion/.readmes/README.inclusion.specific index 0a1eb22e..3afdb7b4 100644 --- a/other/types_submitted_for_inclusion/.readmes/README.inclusion.specific +++ b/other/types_submitted_for_inclusion/.readmes/README.inclusion.specific @@ -2,6 +2,7 @@ Description: Type that will probably only work in a very specific environnment (like a specific distribution only). + or has custom code that may not satisfy the "usual" or generic use case. Problem: diff --git a/other/types_submitted_for_inclusion/__mysql_server/README.inclusion b/other/types_submitted_for_inclusion/__mysql_server/README.inclusion new file mode 120000 index 00000000..573e1f5f --- /dev/null +++ b/other/types_submitted_for_inclusion/__mysql_server/README.inclusion @@ -0,0 +1 @@ +../.readmes/README.inclusion.specific \ No newline at end of file diff --git a/conf/type/__mysql_server/files/my.cnf b/other/types_submitted_for_inclusion/__mysql_server/files/my.cnf similarity index 100% rename from conf/type/__mysql_server/files/my.cnf rename to other/types_submitted_for_inclusion/__mysql_server/files/my.cnf diff --git a/conf/type/__mysql_server/gencode-remote b/other/types_submitted_for_inclusion/__mysql_server/gencode-remote similarity index 100% rename from conf/type/__mysql_server/gencode-remote rename to other/types_submitted_for_inclusion/__mysql_server/gencode-remote diff --git a/conf/type/__mysql_server/man.text b/other/types_submitted_for_inclusion/__mysql_server/man.text similarity index 100% rename from conf/type/__mysql_server/man.text rename to other/types_submitted_for_inclusion/__mysql_server/man.text diff --git a/conf/type/__mysql_server/manifest b/other/types_submitted_for_inclusion/__mysql_server/manifest similarity index 100% rename from conf/type/__mysql_server/manifest rename to other/types_submitted_for_inclusion/__mysql_server/manifest diff --git a/conf/type/__mysql_server/parameter/optional b/other/types_submitted_for_inclusion/__mysql_server/parameter/optional similarity index 100% rename from conf/type/__mysql_server/parameter/optional rename to other/types_submitted_for_inclusion/__mysql_server/parameter/optional diff --git a/conf/type/__mysql_server/parameter/required b/other/types_submitted_for_inclusion/__mysql_server/parameter/required similarity index 100% rename from conf/type/__mysql_server/parameter/required rename to other/types_submitted_for_inclusion/__mysql_server/parameter/required diff --git a/conf/type/__mysql_server/singleton b/other/types_submitted_for_inclusion/__mysql_server/singleton similarity index 100% rename from conf/type/__mysql_server/singleton rename to other/types_submitted_for_inclusion/__mysql_server/singleton From a013fa6b10b52d93ddd39a53f6392f3fd28b3546 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Mar 2012 20:58:53 +0100 Subject: [PATCH 1458/4212] ++changes(2.0.10) Signed-off-by: Nico Schottelius --- doc/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/changelog b/doc/changelog index dead9aa8..ce9f798b 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,6 +4,10 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.0.10: + * Cleanup __group: No getent gshadow in old Redhat, use groupmod -g + (Matt Coddington) + 2.0.9: 2012-03-12 * Cleanup documentation: Fix environment variable list to be properly displayed (Giel van Schijndel) From 2de7c92bbdbb7c2b5a743f4ecd22d64cdb6ce88c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Mar 2012 21:01:03 +0100 Subject: [PATCH 1459/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 3007cedb..502810f7 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -38,3 +38,5 @@ TYPES - __user add option to include --create-home - Merge __addifnosuchline and __removeline into __line + --state present|absent +- __cron: Support --file to be used instead of user cron (probably direct support + of /etc/cron.d) From 3cee298bcbf4d56a3b6a4d8c8765f6ecdf1398cb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 13 Mar 2012 20:49:46 +0100 Subject: [PATCH 1460/4212] incude __git type from private branch Signed-off-by: Nico Schottelius --- conf/type/__git/gencode-remote | 1 + conf/type/__git/manifest | 1 + conf/type/__git/parameter/required | 1 + 3 files changed, 3 insertions(+) create mode 100644 conf/type/__git/gencode-remote create mode 100644 conf/type/__git/manifest create mode 100644 conf/type/__git/parameter/required diff --git a/conf/type/__git/gencode-remote b/conf/type/__git/gencode-remote new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/conf/type/__git/gencode-remote @@ -0,0 +1 @@ + diff --git a/conf/type/__git/manifest b/conf/type/__git/manifest new file mode 100644 index 00000000..c0eb2c23 --- /dev/null +++ b/conf/type/__git/manifest @@ -0,0 +1 @@ +__package git diff --git a/conf/type/__git/parameter/required b/conf/type/__git/parameter/required new file mode 100644 index 00000000..5a18cd2f --- /dev/null +++ b/conf/type/__git/parameter/required @@ -0,0 +1 @@ +source From 9682ce7ebba04cabca5bbc69a8d8a55df88ecd4b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 18 Mar 2012 09:44:44 +0100 Subject: [PATCH 1461/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 502810f7..9626a608 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -3,6 +3,10 @@ UNASSIGNED TODOS The following list of todos has not been assigned to any developer. Feel free to pick one! +CORE +---- +- support default parameter + TESTS ----- - multiple defines of object: From 59f05ca4add14bfbe445a98cc00b3c357bc419b6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 21 Mar 2012 10:39:47 +0100 Subject: [PATCH 1462/4212] add old logfile Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-02-20.debug-jake-deps | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 doc/dev/logs/2012-02-20.debug-jake-deps diff --git a/doc/dev/logs/2012-02-20.debug-jake-deps b/doc/dev/logs/2012-02-20.debug-jake-deps new file mode 100644 index 00000000..2ae39f50 --- /dev/null +++ b/doc/dev/logs/2012-02-20.debug-jake-deps @@ -0,0 +1,8 @@ +require="__package/pkg-config" \ + __package libxml2 --version "2.7.8_1" --state installed --pkgsite http://192.168.196.70 + +Kein + INFO: www: Generating and executing code for __package_pkg_freebsd/libxml2 + +für + __package/libxml2 From fe4074b27052dbc76b22615c391a36afb9bfc82a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 21 Mar 2012 10:42:43 +0100 Subject: [PATCH 1463/4212] +update README Signed-off-by: Nico Schottelius --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index 965138c4..e514df91 100644 --- a/README +++ b/README @@ -38,6 +38,7 @@ Design | Define target state, do not focus on methods or scripts Design | Push architecture: Instantly apply your changes Small core | cdist's core is very small - less code, less bugs Fast development | Focus on straightforwardness of type creation is a main development objective +Fast development | Batteries included: A lot of requirements can be solved using standard types Modern Programming Language | cdist is written in Python Requirements, Scalability | No central server needed, cdist operates in push mode and can be run from any computer Requirements, Scalability, Upgrade | cdist only needs to be updated on the master, not on the target hosts From 9832512bfd2936ea1ec25df106a664f5abdef1a5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 26 Mar 2012 18:12:06 +0200 Subject: [PATCH 1464/4212] ++todos :-) Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 9626a608..1dd73d87 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -44,3 +44,6 @@ TYPES - Merge __addifnosuchline and __removeline into __line + --state present|absent - __cron: Support --file to be used instead of user cron (probably direct support of /etc/cron.d) + +- Support uci from openwrt? + - http://wiki.openwrt.org/doc/uci From f3efa1e74db49b0701ca4b761ae85f04aea5c095 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 30 Mar 2012 09:14:25 +0200 Subject: [PATCH 1465/4212] enable __start_on_boot on amazon linux Signed-off-by: Nico Schottelius --- conf/type/__start_on_boot/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index cefdc385..974abb30 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -43,7 +43,7 @@ case "$state_should" in # echo rc-update add \"$name\" default # ;; - centos|fedora|owl|redhat) + amazon|centos|fedora|owl|redhat) echo chkconfig \"$name\" on ;; From e540502830e7ce54c081e97504347e22c5ae6ac8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 3 Apr 2012 05:59:24 +0200 Subject: [PATCH 1466/4212] Missing cat in __package_yum Signed-off-by: Nico Schottelius --- conf/type/__package_yum/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__package_yum/gencode-remote b/conf/type/__package_yum/gencode-remote index a10e60dd..df2bf405 100755 --- a/conf/type/__package_yum/gencode-remote +++ b/conf/type/__package_yum/gencode-remote @@ -22,7 +22,7 @@ # if [ -f "$__object/parameter/name" ]; then - name="$__object/parameter/name" + name="$(cat "$__object/parameter/name")" else name="$__object_id" fi From 941e89f950d0c121cfbd06cbd2cfec24bd80f0ab Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 3 Apr 2012 06:00:00 +0200 Subject: [PATCH 1467/4212] ++changes(2.0.10) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index ce9f798b..127b33ee 100644 --- a/doc/changelog +++ b/doc/changelog @@ -7,6 +7,7 @@ Changelog 2.0.10: * Cleanup __group: No getent gshadow in old Redhat, use groupmod -g (Matt Coddington) + * Bugfix __package_yum: Missing cat 2.0.9: 2012-03-12 * Cleanup documentation: Fix environment variable list to be properly From 386c12f2512b45a197450fd7ece6bb8a634004ab Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 3 Apr 2012 17:52:58 +0200 Subject: [PATCH 1468/4212] nested quotes should not be escaped Signed-off-by: Steven Armstrong --- conf/type/__start_on_boot/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index 974abb30..b9e26815 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -32,7 +32,7 @@ case "$state_should" in present) case "$os" in archlinux) - echo "sed -i /etc/rc.conf \'s/^\\(DAEMONS=.*\\))/\\1 $name)/\'" + echo "sed -i /etc/rc.conf 's/^\\(DAEMONS=.*\\))/\\1 $name)/'" ;; debian|ubuntu) echo "update-rc.d \"$name\" defaults >/dev/null" From 18a25dc65bf8b00a41ad805efcc2941aa2e61829 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 3 Apr 2012 17:53:28 +0200 Subject: [PATCH 1469/4212] file must be last argument Signed-off-by: Steven Armstrong --- conf/type/__start_on_boot/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index b9e26815..a64c1096 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -32,7 +32,7 @@ case "$state_should" in present) case "$os" in archlinux) - echo "sed -i /etc/rc.conf 's/^\\(DAEMONS=.*\\))/\\1 $name)/'" + echo "sed -i 's/^\\(DAEMONS=.*\\))/\\1 $name)/' /etc/rc.conf" ;; debian|ubuntu) echo "update-rc.d \"$name\" defaults >/dev/null" From ffcf57ee45783145451484ae94f8edc25e6a9195 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 4 Apr 2012 00:08:23 +0200 Subject: [PATCH 1470/4212] implement --state exists Signed-off-by: Steven Armstrong --- conf/type/__file/gencode-local | 3 +++ conf/type/__file/man.text | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/conf/type/__file/gencode-local b/conf/type/__file/gencode-local index d9839a19..a55cfc2b 100755 --- a/conf/type/__file/gencode-local +++ b/conf/type/__file/gencode-local @@ -23,6 +23,9 @@ destination="/$__object_id" state_should="$(cat "$__object/parameter/state")" +exists="$(cat "$__object/explorer/exists")" + +[ "$state_should" = "exists" -a "$exists" = "yes" ] && exit 0 # nothing to do if [ "$state_should" = "present" ]; then if [ -f "$__object/parameter/source" ]; then diff --git a/conf/type/__file/man.text b/conf/type/__file/man.text index 5e91599f..db20d857 100644 --- a/conf/type/__file/man.text +++ b/conf/type/__file/man.text @@ -21,7 +21,11 @@ None. OPTIONAL PARAMETERS ------------------- state:: - 'present' or 'absent', defaults to 'present' + 'present', 'absent' or 'exists', defaults to 'present' + where: + present: the file is exactly the one from source + absent: the file does not exist + exists: the file from source but only if it doesn't already exist group:: Group to chgrp to. From e3f767f5a1cfba53cf8ba5dc6a7490de02bf1eb4 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 4 Apr 2012 09:37:18 +0200 Subject: [PATCH 1471/4212] += example Signed-off-by: Steven Armstrong --- conf/type/__file/man.text | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/conf/type/__file/man.text b/conf/type/__file/man.text index db20d857..0215027a 100644 --- a/conf/type/__file/man.text +++ b/conf/type/__file/man.text @@ -59,6 +59,11 @@ __file /etc/issue --source "$__type/files/archlinux" --state present __file /etc/shadow --source "$__type/files/shadow" \ --owner root --group shadow --mode 0640 \ --state present + +# Provide a default file, but let the user change it +__file /home/frodo/.bashrc --source "/etc/skel/.bashrc" \ + --state exists \ + --owner frodo --mode 0600 -------------------------------------------------------------------------------- From 9da25ca4eaa7ca2a5be27d4f871d90ecc08b904d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Apr 2012 09:44:57 +0200 Subject: [PATCH 1472/4212] ++changes(2.0.10) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 127b33ee..08232af6 100644 --- a/doc/changelog +++ b/doc/changelog @@ -8,6 +8,7 @@ Changelog * Cleanup __group: No getent gshadow in old Redhat, use groupmod -g (Matt Coddington) * Bugfix __package_yum: Missing cat + * Feature __file: Support for --state exists (Steven Armstrong) 2.0.9: 2012-03-12 * Cleanup documentation: Fix environment variable list to be properly From 689acb4c2167a42574645b4d03bfae16f0b5c784 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Apr 2012 09:47:52 +0200 Subject: [PATCH 1473/4212] ++changes(2.0.10) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 08232af6..0bd00135 100644 --- a/doc/changelog +++ b/doc/changelog @@ -8,6 +8,7 @@ Changelog * Cleanup __group: No getent gshadow in old Redhat, use groupmod -g (Matt Coddington) * Bugfix __package_yum: Missing cat + * Bugfix __start_on_boot: Correctly use sed and quotes (Steven Armstrong) * Feature __file: Support for --state exists (Steven Armstrong) 2.0.9: 2012-03-12 From 7d2799d958ce90769f19d54f74359f4b4db7fba6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Apr 2012 17:21:54 +0200 Subject: [PATCH 1474/4212] Make __manifest usable in type manifests Signed-off-by: Nico Schottelius --- doc/changelog | 1 + doc/man/cdist-reference.text.sh | 2 +- lib/cdist/core/manifest.py | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 0bd00135..e3f7d1a5 100644 --- a/doc/changelog +++ b/doc/changelog @@ -10,6 +10,7 @@ Changelog * Bugfix __package_yum: Missing cat * Bugfix __start_on_boot: Correctly use sed and quotes (Steven Armstrong) * Feature __file: Support for --state exists (Steven Armstrong) + * Feature core: Make variable __manifest available to type manifests 2.0.9: 2012-03-12 * Cleanup documentation: Fix environment variable list to be properly diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 6bd5f1b8..2aa87aa1 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -173,7 +173,7 @@ __explorer:: Available for: explorer, type explorer __manifest:: Directory that contains the initial manifest. - Available for: initial manifest + Available for: initial manifest, type manifest __global:: Directory that contains generic output like explorer. Available for: initial manifest, type manifest, type gencode diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index 8b784229..4b798883 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -92,6 +92,7 @@ class Manifest(object): env = os.environ.copy() env.update(self.env) env.update({ + '__manifest': self.local.manifest_path, '__object': cdist_object.absolute_path, '__object_id': cdist_object.object_id, '__object_name': cdist_object.name, From 0e11583b1e563a8afa53fae185942efaaf14d2af Mon Sep 17 00:00:00 2001 From: pestaa Date: Thu, 5 Apr 2012 23:21:11 +0200 Subject: [PATCH 1475/4212] Fix sed argumenting on FreeBSD. While specifying -i flag is optional on GNU sed, it is mandatory on non-GNU variants. In order to keep behavior backward-compatible, the backup file is always removed. --- conf/type/__key_value/gencode-remote | 6 ++++-- conf/type/__rvm/gencode-remote | 3 ++- conf/type/__start_on_boot/gencode-remote | 6 ++++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/conf/type/__key_value/gencode-remote b/conf/type/__key_value/gencode-remote index 0846dca1..0b02adf2 100755 --- a/conf/type/__key_value/gencode-remote +++ b/conf/type/__key_value/gencode-remote @@ -34,7 +34,8 @@ fi case "$state_should" in absent) # remove lines starting with key - echo "sed -i '/^$key\($delimiter\+\)/d' \"$file\"" + echo "sed -i cdist-backup '/^$key\($delimiter\+\)/d' \"$file\"" + echo "rm -f \"$file.cdist-backup\"" ;; present) case "$state_is" in @@ -44,7 +45,8 @@ case "$state_should" in ;; wrongvalue) # change exisiting value - echo "sed -i \"s|^$key\($delimiter\+\).*|$key\1$value|\" \"$file\"" + echo "sed -i cdist-backup \"s|^$key\($delimiter\+\).*|$key\1$value|\" \"$file\"" + echo "rm -f \"$file.cdist-backup\"" ;; *) echo "Unknown explorer state: $state_is" >&2 diff --git a/conf/type/__rvm/gencode-remote b/conf/type/__rvm/gencode-remote index f306979a..ec39acac 100755 --- a/conf/type/__rvm/gencode-remote +++ b/conf/type/__rvm/gencode-remote @@ -32,7 +32,8 @@ DONE removed) cat << DONE su - $user -c "rm -Rf \"\\\$HOME/.rvm\"; -sed -i '/rvm\/scripts\/rvm/d' \"\\\$HOME/.bashrc\"" +sed -i cdist-backup '/rvm\/scripts\/rvm/d' \"\\\$HOME/.bashrc\"" +rm -f \"\\\$HOME/.bashrc.cdist-backup\"" DONE ;; esac diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index a64c1096..a6ecf032 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -32,7 +32,8 @@ case "$state_should" in present) case "$os" in archlinux) - echo "sed -i 's/^\\(DAEMONS=.*\\))/\\1 $name)/' /etc/rc.conf" + echo "sed -i cdist-backup 's/^\\(DAEMONS=.*\\))/\\1 $name)/' /etc/rc.conf" + echo "rm -f /etc/rc.conf.cdist-backup" ;; debian|ubuntu) echo "update-rc.d \"$name\" defaults >/dev/null" @@ -66,7 +67,8 @@ case "$state_should" 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 -i /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)/'" + echo "sed -i cdist-backup /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)/'" + echo "rm -f /etc/rc.conf.cdist-backup" ;; debian|ubuntu) echo update-rc.d -f \"$name\" remove From cb47a7d56f2e89e5433ea3f4b1ad1009445fed88 Mon Sep 17 00:00:00 2001 From: Istvan Beregszaszi Date: Fri, 6 Apr 2012 00:29:14 +0300 Subject: [PATCH 1476/4212] Fix indenting. --- conf/type/__start_on_boot/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index a6ecf032..ffd30f7f 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -33,7 +33,7 @@ case "$state_should" in case "$os" in archlinux) echo "sed -i cdist-backup 's/^\\(DAEMONS=.*\\))/\\1 $name)/' /etc/rc.conf" - echo "rm -f /etc/rc.conf.cdist-backup" + echo "rm -f /etc/rc.conf.cdist-backup" ;; debian|ubuntu) echo "update-rc.d \"$name\" defaults >/dev/null" @@ -68,7 +68,7 @@ case "$state_should" in # 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 -i cdist-backup /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)/'" - echo "rm -f /etc/rc.conf.cdist-backup" + echo "rm -f /etc/rc.conf.cdist-backup" ;; debian|ubuntu) echo update-rc.d -f \"$name\" remove From f9c945cc86fcf96b048313f8ea239f36f2629d16 Mon Sep 17 00:00:00 2001 From: pestaa Date: Fri, 6 Apr 2012 11:15:06 +0200 Subject: [PATCH 1477/4212] Changed tactics. Sed's -i flag is not cross-platform. --- conf/type/__key_value/gencode-remote | 6 ++---- conf/type/__rvm/gencode-remote | 3 +-- conf/type/__start_on_boot/gencode-remote | 6 ++---- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/conf/type/__key_value/gencode-remote b/conf/type/__key_value/gencode-remote index 0b02adf2..84ea6430 100755 --- a/conf/type/__key_value/gencode-remote +++ b/conf/type/__key_value/gencode-remote @@ -34,8 +34,7 @@ fi case "$state_should" in absent) # remove lines starting with key - echo "sed -i cdist-backup '/^$key\($delimiter\+\)/d' \"$file\"" - echo "rm -f \"$file.cdist-backup\"" + echo "sed '/^$key\($delimiter\+\)/d' \"$file\" | tee \"$file\" > /dev/null" ;; present) case "$state_is" in @@ -45,8 +44,7 @@ case "$state_should" in ;; wrongvalue) # change exisiting value - echo "sed -i cdist-backup \"s|^$key\($delimiter\+\).*|$key\1$value|\" \"$file\"" - echo "rm -f \"$file.cdist-backup\"" + echo "sed \"s|^$key\($delimiter\+\).*|$key\1$value|\" \"$file\" | tee \"$file\" > /dev/null" ;; *) echo "Unknown explorer state: $state_is" >&2 diff --git a/conf/type/__rvm/gencode-remote b/conf/type/__rvm/gencode-remote index ec39acac..cc527678 100755 --- a/conf/type/__rvm/gencode-remote +++ b/conf/type/__rvm/gencode-remote @@ -32,8 +32,7 @@ DONE removed) cat << DONE su - $user -c "rm -Rf \"\\\$HOME/.rvm\"; -sed -i cdist-backup '/rvm\/scripts\/rvm/d' \"\\\$HOME/.bashrc\"" -rm -f \"\\\$HOME/.bashrc.cdist-backup\"" +sed '/rvm\/scripts\/rvm/d' \"\\\$HOME/.bashrc\" | tee \"\\\$HOME/.bashrc\" > /dev/null" DONE ;; esac diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index a6ecf032..f6036dc1 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -32,8 +32,7 @@ case "$state_should" in present) case "$os" in archlinux) - echo "sed -i cdist-backup 's/^\\(DAEMONS=.*\\))/\\1 $name)/' /etc/rc.conf" - echo "rm -f /etc/rc.conf.cdist-backup" + echo "sed 's/^\\(DAEMONS=.*\\))/\\1 $name)/' /etc/rc.conf | tee /etc/rc.conf > /dev/null" ;; debian|ubuntu) echo "update-rc.d \"$name\" defaults >/dev/null" @@ -67,8 +66,7 @@ case "$state_should" 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 -i cdist-backup /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)/'" - echo "rm -f /etc/rc.conf.cdist-backup" + 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)/' | tee /etc/rc.conf > /dev/null" ;; debian|ubuntu) echo update-rc.d -f \"$name\" remove From deafcc60e8ffaec0338e306062c24749a3d72049 Mon Sep 17 00:00:00 2001 From: pestaa Date: Fri, 6 Apr 2012 18:55:35 +0200 Subject: [PATCH 1478/4212] Workound lack of pipeline's integrity guarantee. --- conf/type/__key_value/gencode-remote | 6 ++++-- conf/type/__rvm/gencode-remote | 4 +++- conf/type/__start_on_boot/gencode-remote | 6 ++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/conf/type/__key_value/gencode-remote b/conf/type/__key_value/gencode-remote index 84ea6430..b3ffeb46 100755 --- a/conf/type/__key_value/gencode-remote +++ b/conf/type/__key_value/gencode-remote @@ -34,7 +34,8 @@ fi case "$state_should" in absent) # remove lines starting with key - echo "sed '/^$key\($delimiter\+\)/d' \"$file\" | tee \"$file\" > /dev/null" + echo "sed '/^$key\($delimiter\+\)/d' \"$file\" > \"$file.cdist-tmp\"" + echo "mv \"$file.cdist-tmp\" \"$file\"" ;; present) case "$state_is" in @@ -44,7 +45,8 @@ case "$state_should" in ;; wrongvalue) # change exisiting value - echo "sed \"s|^$key\($delimiter\+\).*|$key\1$value|\" \"$file\" | tee \"$file\" > /dev/null" + echo "sed \"s|^$key\($delimiter\+\).*|$key\1$value|\" \"$file\" > \"$file.cdist-tmp\"" + echo "mv \"$file.cdist-tmp\" \"$file\"" ;; *) echo "Unknown explorer state: $state_is" >&2 diff --git a/conf/type/__rvm/gencode-remote b/conf/type/__rvm/gencode-remote index cc527678..1ba1d499 100755 --- a/conf/type/__rvm/gencode-remote +++ b/conf/type/__rvm/gencode-remote @@ -32,7 +32,9 @@ DONE removed) cat << DONE su - $user -c "rm -Rf \"\\\$HOME/.rvm\"; -sed '/rvm\/scripts\/rvm/d' \"\\\$HOME/.bashrc\" | tee \"\\\$HOME/.bashrc\" > /dev/null" +sed '/rvm\/scripts\/rvm/d' \"\\\$HOME/.bashrc\" > \"\\\$HOME/.bashrc.cdist-tmp\" +mv \"\\\$HOME/.bashrc.cdist-tmp\" \"\\\$HOME/.bashrc\"" + DONE ;; esac diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index f6036dc1..78a82de3 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -32,7 +32,8 @@ case "$state_should" in present) case "$os" in archlinux) - echo "sed 's/^\\(DAEMONS=.*\\))/\\1 $name)/' /etc/rc.conf | tee /etc/rc.conf > /dev/null" + echo "sed 's/^\\(DAEMONS=.*\\))/\\1 $name)/' /etc/rc.conf > /etc/rc.conf.cdist-tmp" + echo "mv /etc/rc.conf.cdist-tmp /etc/rc.conf" ;; debian|ubuntu) echo "update-rc.d \"$name\" defaults >/dev/null" @@ -66,7 +67,8 @@ case "$state_should" 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)/' | tee /etc/rc.conf > /dev/null" + 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" ;; debian|ubuntu) echo update-rc.d -f \"$name\" remove From f5437ccce6dba44723327738b185be132b714c89 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Fri, 6 Apr 2012 13:32:59 -0400 Subject: [PATCH 1479/4212] Bugfix for jail_list If jail_list wasn't already defined in /etc/rc.conf, gencode-remote wasn't adding the variable to the file. --- conf/type/__jail/gencode-remote | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index c0a35784..d32ea7d6 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -266,7 +266,12 @@ if [ "$onboot" = "true" ]; then cat <>/etc/rc.conf + fi unset jail_list rm -f /etc/rc.conf.bak EOF From 847fc9d8c168d0395d1f29458005e30f6f9e922d Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 11 Apr 2012 14:53:28 -0400 Subject: [PATCH 1480/4212] Multiple bugfixes fixed remote copy command fixed problem with code-remote when jail_enable wasn't in rc.conf fixed problem with code-remote when jail_list wasn't in rc.conf added check to see if /etc/devfs.rules exists before trying to use it added dependency on __directory/usr/jail --- conf/type/__jail/gencode-local | 2 +- conf/type/__jail/gencode-remote | 30 +++++++++++++++++++++------- conf/type/__jail/manifest | 35 +++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 8 deletions(-) create mode 100755 conf/type/__jail/manifest diff --git a/conf/type/__jail/gencode-local b/conf/type/__jail/gencode-local index 2d4415e3..6a66c658 100755 --- a/conf/type/__jail/gencode-local +++ b/conf/type/__jail/gencode-local @@ -29,6 +29,6 @@ jailbase="/usr/jail/jailbase.tgz" basepresent="$(cat "$__object/explorer/basepresent")" if [ "$basepresent" = "NONE" ]; then - echo "$__remote_copy" "$__object/files/jailbase.tgz" "${target_host}:${jailbase}" + echo "$__remote_copy" "$__type/files/jailbase.tgz" "$__target_host:${jailbase}" fi diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index d32ea7d6..56fe9b9a 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -212,6 +212,16 @@ EOF # Add the jail_$name_* lines to rc.conf cat <>/etc/rc.conf + elif [ ! "\$(echo \$jail_enable | tr '[a-z]' '[A-Z]')" = "YES" ]; then # jail_enable="NO" + sed -i '.bak' 's/^jail_enable=.*$/jail_enable="YES"/g' /etc/rc.conf # fix this -^ + rm -f /etc/rc.conf.bak + fi cat >>/etc/rc.conf <>/etc/rc.conf else - echo jail_list=\"\${jail_list}\" >>/etc/rc.conf + jail_list="\${jail_list} ${name}" + sed -i '.bak' "s/^jail_list=\".*\"/jail_list=\"\${jail_list}\"/" /etc/rc.conf + rm -f /etc/rc.conf.bak fi unset jail_list - rm -f /etc/rc.conf.bak EOF fi diff --git a/conf/type/__jail/manifest b/conf/type/__jail/manifest new file mode 100755 index 00000000..fc3d2ac7 --- /dev/null +++ b/conf/type/__jail/manifest @@ -0,0 +1,35 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# The __jail type creates, configures, and deletes FreeBSD jails for use as +# virtual machines. +# + +# Debug +#exec >&2 +#set -x + +jaildir="/usr/jail" + +__directory ${jaildir} --parents yes + +# Debug +#set +x + From 32d6cbb7a123683843eef903f0c616f6a7019c5a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 22 Apr 2012 01:20:32 +0200 Subject: [PATCH 1481/4212] ++todo Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 1dd73d87..11235f8a 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -6,6 +6,8 @@ Feel free to pick one! CORE ---- - support default parameter +- document and add paremeters for remote-copy and remote-exec! + - remove hack, make a feature of it TESTS ----- From bc1a2d769dbbe2b7eac314343c90107efd58fdd9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 22 Apr 2012 01:20:44 +0200 Subject: [PATCH 1482/4212] ++title line Signed-off-by: Nico Schottelius --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index e514df91..73e5c210 100644 --- a/README +++ b/README @@ -288,7 +288,7 @@ Interesting information are for instance * What are the pros/cons you see in cdist? * General comments/critics -### Nico Schottelius, Systems Group ETH Zurich and privately +### Nico Schottelius, Systems Group ETH Zurich, local.ch and privately Yes, I'm actually eating my own dogfood and currently managing From d39821782d989b194c436b5669bdb76a0037bf1f Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Mon, 23 Apr 2012 13:43:27 -0400 Subject: [PATCH 1483/4212] Copy /root to $jailbase/rw/$name/root Copies /root to ${jailbase}/rw/${name}/root Adds /root to /etc/fstab.${name} --- conf/type/__jail/gencode-remote | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index 56fe9b9a..23e8debc 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -197,6 +197,11 @@ cat < Date: Mon, 23 Apr 2012 14:39:26 -0400 Subject: [PATCH 1484/4212] Added jail_${name}_flags variable To make future work, such as resource limiting (rctl(8)) easier, added "-n ${name}" to jail_flags for each jail. --- conf/type/__jail/gencode-remote | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index 23e8debc..9b91bd50 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -198,8 +198,8 @@ cat < Date: Wed, 25 Apr 2012 17:18:16 +0200 Subject: [PATCH 1485/4212] inherit dependencies from defining object when setting up implicit dependencies through autorequire Signed-off-by: Steven Armstrong --- lib/cdist/emulator.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index c4b84feb..99b34554 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -160,10 +160,19 @@ class Emulator(object): def record_auto_requirements(self): """An object shall automatically depend on all objects that it defined in it's type manifest. """ - # __object_name is the name of the object whose type manifest is currenlty executed + # __object_name is the name of the object whose type manifest is currently executed __object_name = os.environ.get('__object_name', None) if __object_name: - _object = self.cdist_object.object_from_name(__object_name) - # prevent circular dependencies - if not _object.name in self.cdist_object.requirements: - _object.requirements.append(self.cdist_object.name) + # The object whose type manifest is currently run + parent = self.cdist_object.object_from_name(__object_name) + # The object currently being defined + current_object = self.cdist_object + # current_object shall have all dependencies that it's parent has + for req in parent.requirements: + if req not in current_object.requirements: + current_object.requirements.append(req) + # As parent defined current_object it shall automatically depend on it. + # But only if the user hasn't said otherwise. + # Must prevent circular dependencies. + if not parent.name in current_object.requirements: + parent.requirements.append(current_object.name) From 75aea916434c63681634be27c6d63f654739e5cb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 27 Apr 2012 11:39:08 +0200 Subject: [PATCH 1486/4212] ++changes(2.0.10) Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index e3f7d1a5..267be9e7 100644 --- a/doc/changelog +++ b/doc/changelog @@ -11,6 +11,8 @@ Changelog * Bugfix __start_on_boot: Correctly use sed and quotes (Steven Armstrong) * Feature __file: Support for --state exists (Steven Armstrong) * Feature core: Make variable __manifest available to type manifests + * Feature core: Correct parent dependency handling (Steven Armstrong) + * Bugfix several types: Fix sed for FreeBSD (Istvan Beregszaszi) 2.0.9: 2012-03-12 * Cleanup documentation: Fix environment variable list to be properly From 14e851341a7230eb50ac74565ea97a2d9b514d3c Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Fri, 27 Apr 2012 11:45:34 -0400 Subject: [PATCH 1487/4212] Implemented Nico's suggestions Parameterized {jailbase,jaildir} Replaced all usages of /usr/jail with $jaildir Explicitly fail if $os isn't FreeBSD Removed $__type/files/ as it is pointless to have now Updated man page --- conf/type/__jail/explorer/basepresent | 10 ++++++++-- conf/type/__jail/explorer/present | 8 +++++++- conf/type/__jail/explorer/status | 10 +++++++++- conf/type/__jail/files/jailbase | 1 - conf/type/__jail/gencode-local | 13 +++++++++---- conf/type/__jail/gencode-remote | 23 ++++++++++++++--------- conf/type/__jail/man.text | 19 ++++++++++++++----- conf/type/__jail/manifest | 13 ++++++++++++- conf/type/__jail/parameter/optional | 1 + conf/type/__jail/parameter/required | 1 + 10 files changed, 75 insertions(+), 24 deletions(-) delete mode 100644 conf/type/__jail/files/jailbase diff --git a/conf/type/__jail/explorer/basepresent b/conf/type/__jail/explorer/basepresent index aa155b03..f167a19c 100755 --- a/conf/type/__jail/explorer/basepresent +++ b/conf/type/__jail/explorer/basepresent @@ -18,20 +18,26 @@ # along with cdist. If not, see . # # -# See if the jailbase.tgz or /usr/jail/base dir exists +# See if the jailbase.tgz or $jaildir/base dir exists # # Debug #exec >&2 #set -x +if [ -f "$__object/parameter/jaildir" ]; then + jaildir="$(cat "$__object/parameter/name")" +else + jaildir="/usr/jail" +fi + name="base:jailbase.tgz" out="" save_IFS="$IFS" IFS=":" for cur in $name; do - if [ -e "/usr/jail/$cur" ]; then + if [ -e "${jaildir}/$cur" ]; then out="${out}:${cur}" fi done diff --git a/conf/type/__jail/explorer/present b/conf/type/__jail/explorer/present index a1f44302..2ba3b2af 100755 --- a/conf/type/__jail/explorer/present +++ b/conf/type/__jail/explorer/present @@ -31,7 +31,13 @@ else name=$__object_id fi -[ -d "/usr/jail/$name" ] && echo "EXISTS" || echo "NOTEXIST" +if [ -f "$__object/parameter/jaildir" ]; then + jaildir="$(cat "$__object/parameter/name")" +else + jaildir="/usr/jail" +fi + +[ -d "${jaildir}/$name" ] && echo "EXISTS" || echo "NOTEXIST" #set +x diff --git a/conf/type/__jail/explorer/status b/conf/type/__jail/explorer/status index 5f95f406..fe81eaf7 100755 --- a/conf/type/__jail/explorer/status +++ b/conf/type/__jail/explorer/status @@ -31,7 +31,15 @@ else name="$__object_id" fi -jls_output="$(jls | grep "[ ^I]\/usr\/jail\/${name}\$")" || true +if [ -f "$__object/parameter/jaildir" ]; then + jaildir="$(cat "$__object/parameter/name")" +else + jaildir="/usr/jail" +fi +# backslash-escaped $jaildir +sjaildir="$(echo ${jaildir} | sed 's#/#\\/#g')" + +jls_output="$(jls | grep "[ ^I]${sjaildir}\/${name}\$")" || true if [ -n "${jls_output}" ]; then echo "STARTED" diff --git a/conf/type/__jail/files/jailbase b/conf/type/__jail/files/jailbase deleted file mode 100644 index defb739a..00000000 --- a/conf/type/__jail/files/jailbase +++ /dev/null @@ -1 +0,0 @@ -Create a tarball jailbase.tgz in this directory containing the base filesystem for a jail. diff --git a/conf/type/__jail/gencode-local b/conf/type/__jail/gencode-local index 6a66c658..6292d943 100755 --- a/conf/type/__jail/gencode-local +++ b/conf/type/__jail/gencode-local @@ -22,13 +22,18 @@ # virtual machines. # -#FIXME: /usr/jail should never be hardcoded in this type -#FIXME: jailbase.tgz should not be hardcoded in this file +if [ -f "$__object/parameter/jaildir" ]; then + jaildir="$(cat "$__object/parameter/name")" +else + jaildir="/usr/jail" +fi -jailbase="/usr/jail/jailbase.tgz" +jailbase="$(cat "$__object/parameter/jailbase")" + +remotebase="${jaildir}/jailbase.tgz" basepresent="$(cat "$__object/explorer/basepresent")" if [ "$basepresent" = "NONE" ]; then - echo "$__remote_copy" "$__type/files/jailbase.tgz" "$__target_host:${jailbase}" + echo "$__remote_copy" "${jailbase}" "$__target_host:${remotebase}" fi diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index 9b91bd50..b52eb572 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -90,7 +90,12 @@ if [ -f "$__object/parameter/onboot" ]; then onboot="$(cat "$__object/parameter/onboot")" fi -jaildir="/usr/jail" +if [ -f "$__object/parameter/jaildir" ]; then + jaildir="$(cat "$__object/parameter/name")" +else + jaildir="/usr/jail" +fi + present="$(cat "$__object/explorer/present")" status="$(cat "$__object/explorer/status")" @@ -135,9 +140,9 @@ deleteJail() { fi EOF # Remove the jail's rw mountpoints - echo "rm -rf \"/usr/jail/rw/${name}\"" + echo "rm -rf \"${jailbase}/rw/${name}\"" # Remove the jail directory - echo "rm -rf \"/usr/jail/${name}\"" + echo "rm -rf \"${jailbase}/${name}\"" # Remove the jail's fstab echo "rm -f \"/etc/fstab.${name}\"" # Remove jail_$name_* lines from rc.conf @@ -207,12 +212,12 @@ EOF # Create the ro+rw mountpoint entries in fstab cat </etc/fstab.${name} <&2 #set -x -jaildir="/usr/jail" +# Can only be used on FreeBSD +os="$(cat "$__global/explorer/os")" +if [ ! "$os" = "freebsd" ]; then + echo "__jail can only be used on FreeBSD targets!" >&2 + exit 1 +fi + +if [ -f "$__object/parameter/jaildir" ]; then + jaildir="$(cat "$__object/parameter/name")" +else + jaildir="/usr/jail" +fi __directory ${jaildir} --parents yes diff --git a/conf/type/__jail/parameter/optional b/conf/type/__jail/parameter/optional index 85b94270..53b8895f 100644 --- a/conf/type/__jail/parameter/optional +++ b/conf/type/__jail/parameter/optional @@ -6,3 +6,4 @@ interface devfs-enable devfs-ruleset onboot +jaildir diff --git a/conf/type/__jail/parameter/required b/conf/type/__jail/parameter/required index ff72b5c7..29797ee6 100644 --- a/conf/type/__jail/parameter/required +++ b/conf/type/__jail/parameter/required @@ -1 +1,2 @@ state +jailbase From 4b11a6172dee9026558361de054b1b23131b8c5c Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Mon, 30 Apr 2012 17:29:08 -0400 Subject: [PATCH 1488/4212] Fixed variable naming in /etc/fstab.$name had referenced $jailbase when meaning to reference $jaildir --- conf/type/__jail/gencode-remote | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index b52eb572..7ebe26eb 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -140,9 +140,9 @@ deleteJail() { fi EOF # Remove the jail's rw mountpoints - echo "rm -rf \"${jailbase}/rw/${name}\"" + echo "rm -rf \"${jaildir}/rw/${name}\"" # Remove the jail directory - echo "rm -rf \"${jailbase}/${name}\"" + echo "rm -rf \"${jaildir}/${name}\"" # Remove the jail's fstab echo "rm -f \"/etc/fstab.${name}\"" # Remove jail_$name_* lines from rc.conf @@ -212,12 +212,12 @@ EOF # Create the ro+rw mountpoint entries in fstab cat </etc/fstab.${name} < Date: Wed, 2 May 2012 15:54:25 +0200 Subject: [PATCH 1489/4212] ++changes(2.0.10) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 267be9e7..980e0cdf 100644 --- a/doc/changelog +++ b/doc/changelog @@ -13,6 +13,7 @@ Changelog * Feature core: Make variable __manifest available to type manifests * Feature core: Correct parent dependency handling (Steven Armstrong) * Bugfix several types: Fix sed for FreeBSD (Istvan Beregszaszi) + * New Type: __jail (Jake Guffey) 2.0.9: 2012-03-12 * Cleanup documentation: Fix environment variable list to be properly From 7d61b777088c5b254c1cfad6a615bc619c79eab6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 3 May 2012 10:16:08 +0200 Subject: [PATCH 1490/4212] fix autorequire dependency handling - inherit explicit requirements that the user defined himself - but _not_ implicit requirements that cdist added for autorequire Changes: - added new .autorequire property to CdistObject to keep track of implicit autorequire dependencies - Emulator appends implicit requirements to this .autorequire property - DependencyResolver preprocess these .autorequire properties before resolving normal dependencies - refactored and documented DependencyResolver so it's clearer what happens and easier to use from tests - update test cases to match new DependencyResolver behaviour Signed-off-by: Steven Armstrong --- lib/cdist/config_install.py | 2 +- lib/cdist/core/cdist_object.py | 1 + lib/cdist/emulator.py | 6 +- lib/cdist/resolver.py | 80 +++++++++++++------ lib/cdist/test/autorequire/__init__.py | 78 ++++++++++++++++++ .../autorequire/fixtures/conf/explorer/.keep | 0 .../conf/manifest/circular_dependency | 2 + .../conf/manifest/implicit_dependencies | 3 + .../conf/type/__addifnosuchline/.keep | 0 .../fixtures/conf/type/__directory/.keep | 0 .../conf/type/__nfsroot_client/manifest | 3 + .../fixtures/conf/type/__package/manifest | 1 + .../conf/type/__package_special/.keep | 0 .../type/__root_ssh_authorized_key/manifest | 4 + .../fixtures/conf/type/__top/manifest | 2 + .../fixtures/conf/type/__user/.keep | 0 lib/cdist/test/emulator/__init__.py | 5 +- lib/cdist/test/resolver/__init__.py | 6 +- 18 files changed, 156 insertions(+), 37 deletions(-) create mode 100644 lib/cdist/test/autorequire/__init__.py create mode 100644 lib/cdist/test/autorequire/fixtures/conf/explorer/.keep create mode 100755 lib/cdist/test/autorequire/fixtures/conf/manifest/circular_dependency create mode 100755 lib/cdist/test/autorequire/fixtures/conf/manifest/implicit_dependencies create mode 100644 lib/cdist/test/autorequire/fixtures/conf/type/__addifnosuchline/.keep create mode 100644 lib/cdist/test/autorequire/fixtures/conf/type/__directory/.keep create mode 100755 lib/cdist/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest create mode 100755 lib/cdist/test/autorequire/fixtures/conf/type/__package/manifest create mode 100644 lib/cdist/test/autorequire/fixtures/conf/type/__package_special/.keep create mode 100755 lib/cdist/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest create mode 100755 lib/cdist/test/autorequire/fixtures/conf/type/__top/manifest create mode 100644 lib/cdist/test/autorequire/fixtures/conf/type/__user/.keep diff --git a/lib/cdist/config_install.py b/lib/cdist/config_install.py index 7cce240e..3aadca86 100644 --- a/lib/cdist/config_install.py +++ b/lib/cdist/config_install.py @@ -141,7 +141,7 @@ class ConfigInstall(object): self.local.type_path) dependency_resolver = resolver.DependencyResolver(objects) - self.log.debug(pprint.pformat(dependency_resolver.graph)) + self.log.debug(pprint.pformat(dependency_resolver.dependencies)) for cdist_object in dependency_resolver: self.log.debug("Run object: %s", cdist_object) diff --git a/lib/cdist/core/cdist_object.py b/lib/cdist/core/cdist_object.py index e12bcfbd..90a21e59 100644 --- a/lib/cdist/core/cdist_object.py +++ b/lib/cdist/core/cdist_object.py @@ -186,6 +186,7 @@ class CdistObject(object): return os.path.join(self.path, "explorer") requirements = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'require')) + autorequire = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'autorequire')) parameters = fsproperty.DirectoryDictProperty(lambda obj: os.path.join(obj.base_path, obj.parameter_path)) explorers = fsproperty.DirectoryDictProperty(lambda obj: os.path.join(obj.base_path, obj.explorer_path)) changed = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "changed")) diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 99b34554..39d8ca40 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -167,12 +167,8 @@ class Emulator(object): parent = self.cdist_object.object_from_name(__object_name) # The object currently being defined current_object = self.cdist_object - # current_object shall have all dependencies that it's parent has - for req in parent.requirements: - if req not in current_object.requirements: - current_object.requirements.append(req) # As parent defined current_object it shall automatically depend on it. # But only if the user hasn't said otherwise. # Must prevent circular dependencies. if not parent.name in current_object.requirements: - parent.requirements.append(current_object.name) + parent.autorequire.append(current_object.name) diff --git a/lib/cdist/resolver.py b/lib/cdist/resolver.py index 368c9eb8..7e3a1a68 100644 --- a/lib/cdist/resolver.py +++ b/lib/cdist/resolver.py @@ -50,36 +50,41 @@ class DependencyResolver(object): """Cdist's dependency resolver. Usage: - resolver = DependencyResolver(list_of_objects) - from pprint import pprint - pprint(resolver.graph) - - for cdist_object in resolver: - do_something_with(cdist_object) - + >> 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 = list(objects) # make sure we store as list, not generator - self._object_index = dict((o.name, o) for o in self.objects) - self._graph = None + self.objects = dict((o.name, o) for o in objects) + self._dependencies = None self.log = logger or log @property - def graph(self): + 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._graph is None: - graph = {} - for o in self.objects: + if self._dependencies is None: + self._dependencies = d = {} + self._preprocess_requirements() + for name,cdist_object in self.objects.items(): resolved = [] unresolved = [] - self.resolve_object_dependencies(o, resolved, unresolved) - graph[o.name] = resolved - self._graph = graph - return self._graph + self._resolve_object_dependencies(cdist_object, resolved, unresolved) + d[name] = resolved + return self._dependencies def find_requirements_by_name(self, requirements): """Takes a list of requirement patterns and returns a list of matching object instances. @@ -89,21 +94,44 @@ class DependencyResolver(object): find_requirements_by_name(['__type/object_id', '__other_type/*']) -> [, , ] """ - object_names = self._object_index.keys() + object_names = self.objects.keys() for pattern in requirements: found = False for requirement in fnmatch.filter(object_names, pattern): found = True - yield self._object_index[requirement] + 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._object_index: - yield self._object_index[singleton] + if singleton in self.objects: + yield self.objects[singleton] else: raise RequirementNotFoundError(pattern) - def resolve_object_dependencies(self, cdist_object, resolved, unresolved): + 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 cdist_object.requirements: + if requirement not in auto_requirement.requirements: + auto_requirement.requirements.append(requirement) + # 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. @@ -121,16 +149,16 @@ class DependencyResolver(object): if required_object not in resolved: if required_object in unresolved: raise CircularReferenceError(cdist_object, required_object) - self.resolve_object_dependencies(required_object, resolved, unresolved) + 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 while resolving dependencies. + """Iterate over all unique objects and yield them in the correct order. """ - iterable = itertools.chain(*self.graph.values()) + iterable = itertools.chain(*self.dependencies.values()) # Keep record of objects that have already been seen seen = set() seen_add = seen.add diff --git a/lib/cdist/test/autorequire/__init__.py b/lib/cdist/test/autorequire/__init__.py new file mode 100644 index 00000000..2263cbf9 --- /dev/null +++ b/lib/cdist/test/autorequire/__init__.py @@ -0,0 +1,78 @@ +# -*- 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.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') +local_base_path = fixtures + + +class AutorequireTestCase(test.CdistTestCase): + + def setUp(self): + self.orig_environ = os.environ + os.environ = os.environ.copy() + self.target_host = 'localhost' + self.temp_dir = self.mkdtemp() + os.environ['__cdist_out_dir'] = self.temp_dir + + self.context = cdist.context.Context( + target_host=self.target_host, + base_path=local_base_path, + 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.config.local.manifest_path, 'implicit_dependencies') + self.config.stage_prepare() + + objects = core.CdistObject.list_objects(self.config.local.object_path, self.config.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.config.local.manifest_path, 'circular_dependency') + self.config.stage_prepare() + # raises CircularDependecyError + self.config.stage_run() diff --git a/lib/cdist/test/autorequire/fixtures/conf/explorer/.keep b/lib/cdist/test/autorequire/fixtures/conf/explorer/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/autorequire/fixtures/conf/manifest/circular_dependency b/lib/cdist/test/autorequire/fixtures/conf/manifest/circular_dependency new file mode 100755 index 00000000..6ea308d1 --- /dev/null +++ b/lib/cdist/test/autorequire/fixtures/conf/manifest/circular_dependency @@ -0,0 +1,2 @@ +# this has triggered CircularReferenceError +__nfsroot_client test diff --git a/lib/cdist/test/autorequire/fixtures/conf/manifest/implicit_dependencies b/lib/cdist/test/autorequire/fixtures/conf/manifest/implicit_dependencies new file mode 100755 index 00000000..7d68aed2 --- /dev/null +++ b/lib/cdist/test/autorequire/fixtures/conf/manifest/implicit_dependencies @@ -0,0 +1,3 @@ +# this creates implicit dependencies through autorequire. +# this failed because autorequired dependencies where not aware of their anchestors dependencies +__top test diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__addifnosuchline/.keep b/lib/cdist/test/autorequire/fixtures/conf/type/__addifnosuchline/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__directory/.keep b/lib/cdist/test/autorequire/fixtures/conf/type/__directory/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest b/lib/cdist/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest new file mode 100755 index 00000000..f6cb7833 --- /dev/null +++ b/lib/cdist/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest @@ -0,0 +1,3 @@ +__user root +__root_ssh_authorized_key john +__root_ssh_authorized_key frank diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__package/manifest b/lib/cdist/test/autorequire/fixtures/conf/type/__package/manifest new file mode 100755 index 00000000..6f70e627 --- /dev/null +++ b/lib/cdist/test/autorequire/fixtures/conf/type/__package/manifest @@ -0,0 +1 @@ +__package_special "$__object_id" diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__package_special/.keep b/lib/cdist/test/autorequire/fixtures/conf/type/__package_special/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest b/lib/cdist/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest new file mode 100755 index 00000000..6224629f --- /dev/null +++ b/lib/cdist/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest @@ -0,0 +1,4 @@ +user="$__object_id" +__directory /root/.ssh +require="__directory/root/.ssh" \ + __addifnosuchline "ssh-root-$user" diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__top/manifest b/lib/cdist/test/autorequire/fixtures/conf/type/__top/manifest new file mode 100755 index 00000000..d6968c25 --- /dev/null +++ b/lib/cdist/test/autorequire/fixtures/conf/type/__top/manifest @@ -0,0 +1,2 @@ +__package b +require="__package/b" __package a diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__user/.keep b/lib/cdist/test/autorequire/fixtures/conf/type/__user/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index 370d3d82..077ea111 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -114,7 +114,8 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): self.manifest = core.Manifest(self.target_host, self.local) def tearDown(self): - shutil.rmtree(self.temp_dir) + pass + #shutil.rmtree(self.temp_dir) def test_autorequire(self): initial_manifest = os.path.join(self.local.manifest_path, "init") @@ -123,7 +124,7 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'singleton') self.manifest.run_type_manifest(cdist_object) expected = ['__planet/Saturn', '__moon/Prometheus'] - self.assertEqual(sorted(cdist_object.requirements), sorted(expected)) + self.assertEqual(sorted(cdist_object.autorequire), sorted(expected)) class ArgumentsTestCase(test.CdistTestCase): diff --git a/lib/cdist/test/resolver/__init__.py b/lib/cdist/test/resolver/__init__.py index ae8f6915..baae26de 100644 --- a/lib/cdist/test/resolver/__init__.py +++ b/lib/cdist/test/resolver/__init__.py @@ -69,7 +69,7 @@ class ResolverTestCase(test.CdistTestCase): first_man.requirements = [second_on_the.name] second_on_the.requirements = [third_moon.name] self.assertEqual( - self.dependency_resolver.graph['__first/man'], + self.dependency_resolver.dependencies['__first/man'], [third_moon, second_on_the, first_man] ) @@ -79,10 +79,10 @@ class ResolverTestCase(test.CdistTestCase): first_man.requirements = [first_woman.name] first_woman.requirements = [first_man.name] with self.assertRaises(resolver.CircularReferenceError): - self.dependency_resolver.graph + 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.graph + self.dependency_resolver.dependencies From 69badd6f2d5f7cd7a885acce06e4fc53f774df6d Mon Sep 17 00:00:00 2001 From: Chris Lamb Date: Thu, 10 May 2012 15:51:22 +0000 Subject: [PATCH 1491/4212] s/nows about/knows about/ Signed-off-by: Chris Lamb --- doc/man/man7/cdist-manifest.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man/man7/cdist-manifest.text b/doc/man/man7/cdist-manifest.text index 1f0e253d..b9dfe655 100644 --- a/doc/man/man7/cdist-manifest.text +++ b/doc/man/man7/cdist-manifest.text @@ -47,7 +47,7 @@ on given conditions. INITIAL AND TYPE MANIFESTS -------------------------- -Cdist nows about two types of manifests: The initial manifest and type +Cdist knows about two types of manifests: The initial manifest and type manifests. The initial manifest is used to define, which configurations to apply to which hosts. The type manifests are used to create objects from types. More about manifests in types can be found in cdist-type(7). From 1557630e91bdd4823522310284707ece25ffa65e Mon Sep 17 00:00:00 2001 From: Chris Lamb Date: Thu, 10 May 2012 16:20:43 +0000 Subject: [PATCH 1492/4212] s/specifiend/specified/ Signed-off-by: Chris Lamb --- conf/type/__addifnosuchline/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__addifnosuchline/man.text b/conf/type/__addifnosuchline/man.text index 3051ff36..ba3825ff 100644 --- a/conf/type/__addifnosuchline/man.text +++ b/conf/type/__addifnosuchline/man.text @@ -33,7 +33,7 @@ EXAMPLES -------- -------------------------------------------------------------------------------- -# Creates or appends the line specifiend in "include_www" to the file "lighttpd.conf" +# Creates or appends the line specified in "include_www" to the file "lighttpd.conf" __addifnosuchline www --file /etc/lighttpd.conf --line include_www # Adds the line "include_git" to the file "lighttpd.conf" From 42bcbc532b60672f4e208cde1c19d5d8055a3bcb Mon Sep 17 00:00:00 2001 From: Chris Lamb Date: Mon, 14 May 2012 16:00:02 +0100 Subject: [PATCH 1493/4212] Freenode.net, not freenode.org. Signed-off-by: Chris Lamb --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 73e5c210..abd38401 100644 --- a/README +++ b/README @@ -259,7 +259,7 @@ need to replace **\_\_file** calls in your manifests: ### IRC You can join the development ***IRC channel*** -[#cstar on irc.freenode.org](irc://irc.freenode.org/#cstar). +[#cstar on irc.freenode.net](irc://irc.freenode.org/#cstar). ### Mailing list From b2c21e24a95c1eed82fade6c2fe3381cf72332ff Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 14 May 2012 18:32:45 +0200 Subject: [PATCH 1494/4212] publishing more verbose Signed-off-by: Nico Schottelius --- build | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build b/build index b209e1c2..bec7f5a9 100755 --- a/build +++ b/build @@ -126,11 +126,11 @@ case "$1" in rm -f latest && ln -sf "$version" latest" ;; - p|pu|pub) - git push --mirror - git push --mirror github - git push --mirror sf - git push --mirror ethz + p|pu|pub) + for remote in "" github sf ethz; do + echo "Pushing to $remote" + git push --mirror $remote + done ;; clean) From d02a1374dd5817c15ef328d013e110d359aacae0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 14 May 2012 18:32:55 +0200 Subject: [PATCH 1495/4212] ++changes(2.0.10) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 980e0cdf..4ec97ab1 100644 --- a/doc/changelog +++ b/doc/changelog @@ -14,6 +14,7 @@ Changelog * Feature core: Correct parent dependency handling (Steven Armstrong) * Bugfix several types: Fix sed for FreeBSD (Istvan Beregszaszi) * New Type: __jail (Jake Guffey) + * Various smaller bugfixes (Chris Lamb) 2.0.9: 2012-03-12 * Cleanup documentation: Fix environment variable list to be properly From f1e8bfb8a766035d2556066b5522c6a51a3df9d1 Mon Sep 17 00:00:00 2001 From: Evax Software Date: Tue, 15 May 2012 09:58:45 +0200 Subject: [PATCH 1496/4212] improve version printing when run from a checkout --- lib/cdist/__init__.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index bd8e6483..3bde31ad 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -19,7 +19,17 @@ # # -VERSION = "2.0.9" +import os +import subprocess + +try: + with open(os.devnull, 'w') as devnull: + here = os.path.dirname(os.path.realpath(__file__)) + VERSION = subprocess.check_output( + 'cd "%s" && git describe' % here, + stderr=devnull, shell=True).decode('utf-8') +except: + VERSION = "2.0.9" BANNER = """ .. . .x+=:. s @@ -38,8 +48,6 @@ BANNER = """ DOT_CDIST = ".cdist" -import os - class Error(Exception): """Base exception class for this project""" pass From dfd60ca837c65c22391f9d70f5a93b782de5dc69 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 May 2012 10:08:19 +0200 Subject: [PATCH 1497/4212] __package uses present/absent Signed-off-by: Nico Schottelius --- conf/type/__rvm/manifest | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/conf/type/__rvm/manifest b/conf/type/__rvm/manifest index 8e63a2c5..482c0d17 100755 --- a/conf/type/__rvm/manifest +++ b/conf/type/__rvm/manifest @@ -19,7 +19,7 @@ # # rvm core dependencies -__package bash --state installed -__package curl --state installed -__package git-core --state installed -__package patch --state installed +__package bash --state present +__package curl --state present +__package git-core --state present +__package patch --state present From 196fb7e656b69db5bd37245cc4ecee66a726b89f Mon Sep 17 00:00:00 2001 From: Evax Software Date: Fri, 18 May 2012 10:43:39 +0200 Subject: [PATCH 1498/4212] use new rvm install command (fixes #67) --- conf/type/__rvm/gencode-remote | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/conf/type/__rvm/gencode-remote b/conf/type/__rvm/gencode-remote index 1ba1d499..fe9cc5f8 100755 --- a/conf/type/__rvm/gencode-remote +++ b/conf/type/__rvm/gencode-remote @@ -25,8 +25,7 @@ if [ "$state_is" != "$state_should" ]; then case "$state_should" in installed) cat << DONE -su - $user -c "bash -s stable < <(curl -s \ -https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)" +su - $user -c "curl -L get.rvm.io | bash -s stable" DONE ;; removed) From 5c700184119e0fbc1cade425f8dda5b551683e9a Mon Sep 17 00:00:00 2001 From: Evax Software Date: Fri, 18 May 2012 10:55:28 +0200 Subject: [PATCH 1499/4212] switch the __rvm type to the new present/absent state scheme --- conf/type/__rvm/explorer/state | 4 ++-- conf/type/__rvm/gencode-remote | 4 ++-- conf/type/__rvm/man.text | 6 +++--- conf/type/__rvm_gem/explorer/state | 6 +++--- conf/type/__rvm_gem/gencode-remote | 4 ++-- conf/type/__rvm_gem/man.text | 8 ++++---- conf/type/__rvm_gem/manifest | 6 +++--- conf/type/__rvm_gemset/explorer/state | 6 +++--- conf/type/__rvm_gemset/gencode-remote | 4 ++-- conf/type/__rvm_gemset/man.text | 8 ++++---- conf/type/__rvm_gemset/manifest | 4 ++-- conf/type/__rvm_ruby/explorer/state | 6 +++--- conf/type/__rvm_ruby/gencode-remote | 4 ++-- conf/type/__rvm_ruby/man.text | 8 ++++---- conf/type/__rvm_ruby/manifest | 4 ++-- 15 files changed, 41 insertions(+), 41 deletions(-) diff --git a/conf/type/__rvm/explorer/state b/conf/type/__rvm/explorer/state index 92fa6e07..d0da0d86 100755 --- a/conf/type/__rvm/explorer/state +++ b/conf/type/__rvm/explorer/state @@ -20,7 +20,7 @@ user="$__object_id" if su - $user -c "[ -d \"\$HOME/.rvm\" ]" ; then - echo "installed" + echo "present" else - echo "removed" + echo "absent" fi diff --git a/conf/type/__rvm/gencode-remote b/conf/type/__rvm/gencode-remote index fe9cc5f8..6c661302 100755 --- a/conf/type/__rvm/gencode-remote +++ b/conf/type/__rvm/gencode-remote @@ -23,12 +23,12 @@ state_is="$(cat "$__object/explorer/state")" state_should="$(cat "$__object/parameter/state")" if [ "$state_is" != "$state_should" ]; then case "$state_should" in - installed) + present) cat << DONE su - $user -c "curl -L get.rvm.io | bash -s stable" DONE ;; - removed) + absent) cat << DONE su - $user -c "rm -Rf \"\\\$HOME/.rvm\"; sed '/rvm\/scripts\/rvm/d' \"\\\$HOME/.bashrc\" > \"\\\$HOME/.bashrc.cdist-tmp\" diff --git a/conf/type/__rvm/man.text b/conf/type/__rvm/man.text index d54e2d1b..0a355dc6 100644 --- a/conf/type/__rvm/man.text +++ b/conf/type/__rvm/man.text @@ -16,7 +16,7 @@ RVM is the Ruby enVironment Manager for the Ruby programming language. REQUIRED PARAMETERS ------------------- state:: - Either "installed" or "removed". + Either "present" or "absent". EXAMPLES @@ -24,10 +24,10 @@ EXAMPLES -------------------------------------------------------------------------------- # Install rvm for user billie -__rvm billie --state installed +__rvm billie --state present # Remove rvm -__rvm billie --state removed +__rvm billie --state absent -------------------------------------------------------------------------------- diff --git a/conf/type/__rvm_gem/explorer/state b/conf/type/__rvm_gem/explorer/state index b0232985..09509a2e 100755 --- a/conf/type/__rvm_gem/explorer/state +++ b/conf/type/__rvm_gem/explorer/state @@ -24,7 +24,7 @@ ruby="$(echo "$gemset" | cut -d '@' -f 1)" gemsetname="$(echo "$gemset" | cut -d '@' -f2)" user="$(cat "$__object/parameter/user")" if su - "$user" -c "[ ! -d \"\$HOME/.rvm\" ]" ; then - echo "removed" + echo "absent" exit 0 fi if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" @@ -32,8 +32,8 @@ rvm list | grep -q $ruby"; then if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" rvm use $ruby > /dev/null; rvm gemset list | grep -q $gemsetname && rvm use $gemset > /dev/null && gem list | grep -q $gem"; then - echo "installed" + echo "present" exit 0 fi fi -echo "removed" +echo "absent" diff --git a/conf/type/__rvm_gem/gencode-remote b/conf/type/__rvm_gem/gencode-remote index 80e1becf..34a69624 100755 --- a/conf/type/__rvm_gem/gencode-remote +++ b/conf/type/__rvm_gem/gencode-remote @@ -27,13 +27,13 @@ user="$(cat "$__object/parameter/user")" state_should="$(cat "$__object/parameter/state")" if [ "$state_is" != "$state_should" ]; then case "$state_should" in - installed) + present) cat << DONE su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" rvm use $gemset; gem install $gem" DONE ;; - removed) + absent) cat << DONE su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" rvm use $gemset; gem uninstall $gem" diff --git a/conf/type/__rvm_gem/man.text b/conf/type/__rvm_gem/man.text index 27b16053..85b52d65 100644 --- a/conf/type/__rvm_gem/man.text +++ b/conf/type/__rvm_gem/man.text @@ -20,7 +20,7 @@ user:: gemset:: The gemset to use state:: - Either "installed" or "removed". + Either "present" or "absent". OPTIONAL PARAMETERS ------------------- @@ -32,14 +32,14 @@ EXAMPLES -------------------------------------------------------------------------------- # Install the rails gem in gemset ruby-1.9.3-p0@myset for user bill -__rvm_gemset rails --gemset ruby-1.9.3-p0@myset --user bill --state installed +__rvm_gemset rails --gemset ruby-1.9.3-p0@myset --user bill --state present # Do the same and also make ruby-1.9.3-p0@myset the default gemset __rvm_gemset rails --gemset ruby-1.9.3-p0@myset --user bill \ - --state installed --default yes + --state present --default yes # Remove it -__rvm_ruby rails --gemset ruby-1.9.3-p0@myset --user bill --state removed +__rvm_ruby rails --gemset ruby-1.9.3-p0@myset --user bill --state absent -------------------------------------------------------------------------------- diff --git a/conf/type/__rvm_gem/manifest b/conf/type/__rvm_gem/manifest index 245c865d..a551472d 100755 --- a/conf/type/__rvm_gem/manifest +++ b/conf/type/__rvm_gem/manifest @@ -31,8 +31,8 @@ else echo $default > "$__object/parameter/default" fi -__rvm "$user" --state installed +__rvm "$user" --state present require="__rvm/$user" \ - __rvm_ruby $ruby --user "$user" --state installed --default $default + __rvm_ruby $ruby --user "$user" --state present --default $default require="__rvm_ruby/$ruby" \ - __rvm_gemset $gemset --user "$user" --state installed --default $default + __rvm_gemset $gemset --user "$user" --state present --default $default diff --git a/conf/type/__rvm_gemset/explorer/state b/conf/type/__rvm_gemset/explorer/state index b33f570e..fbf11830 100755 --- a/conf/type/__rvm_gemset/explorer/state +++ b/conf/type/__rvm_gemset/explorer/state @@ -23,15 +23,15 @@ ruby="$(echo "$gemset" | cut -d '@' -f 1)" gemsetname="$(echo "$gemset" | cut -d '@' -f2)" user="$(cat "$__object/parameter/user")" if su - "$user" -c "[ ! -d \"\$HOME/.rvm\" ]" ; then - echo "removed" + echo "absent" exit 0 fi if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" rvm list | grep -q $ruby"; then if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" rvm use $ruby > /dev/null; rvm gemset list | grep -q $gemsetname"; then - echo "installed" + echo "present" exit 0 fi fi -echo "removed" +echo "absent" diff --git a/conf/type/__rvm_gemset/gencode-remote b/conf/type/__rvm_gemset/gencode-remote index 0e240462..75cc833a 100755 --- a/conf/type/__rvm_gemset/gencode-remote +++ b/conf/type/__rvm_gemset/gencode-remote @@ -27,7 +27,7 @@ default="$(cat "$__object/parameter/default")" state_should="$(cat "$__object/parameter/state")" if [ "$state_is" != "$state_should" ]; then case "$state_should" in - installed) + present) cat << DONE su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" rvm $gemset --create" @@ -43,7 +43,7 @@ DONE ;; esac ;; - removed) + absent) cat << DONE su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" rvm use $ruby; rvm --force gemset delete $gemsetname" diff --git a/conf/type/__rvm_gemset/man.text b/conf/type/__rvm_gemset/man.text index f1e3f2bf..10b6b411 100644 --- a/conf/type/__rvm_gemset/man.text +++ b/conf/type/__rvm_gemset/man.text @@ -18,7 +18,7 @@ REQUIRED PARAMETERS user:: The remote user account to use state:: - Either "installed" or "removed". + Either "present" or "absent". OPTIONAL PARAMETERS ------------------- @@ -30,13 +30,13 @@ EXAMPLES -------------------------------------------------------------------------------- # Install the gemset @myset for user charles on based on ruby-1.9.3-0 -__rvm_gemset ruby-1.9.3-p0@myset --user charles --state installed +__rvm_gemset ruby-1.9.3-p0@myset --user charles --state present # Do the same and make ruby-1.9.3-p0@myset the default gemset -__rvm_gemset ruby-1.9.3-p0@myset --user charles --state installed --default yes +__rvm_gemset ruby-1.9.3-p0@myset --user charles --state present --default yes # Remove the gemset @myset for user john -__rvm_ruby ruby-1.9.3-p0@myset --user john --state removed +__rvm_ruby ruby-1.9.3-p0@myset --user john --state absent -------------------------------------------------------------------------------- diff --git a/conf/type/__rvm_gemset/manifest b/conf/type/__rvm_gemset/manifest index 4fdf9cb1..b69395ea 100755 --- a/conf/type/__rvm_gemset/manifest +++ b/conf/type/__rvm_gemset/manifest @@ -30,7 +30,7 @@ else echo $default > "$__object/parameter/default" fi -__rvm "$user" --state installed +__rvm "$user" --state present require="__rvm/$user" \ - __rvm_ruby $ruby --user "$user" --state installed --default $default + __rvm_ruby $ruby --user "$user" --state present --default $default diff --git a/conf/type/__rvm_ruby/explorer/state b/conf/type/__rvm_ruby/explorer/state index 71d682be..43dafd4f 100755 --- a/conf/type/__rvm_ruby/explorer/state +++ b/conf/type/__rvm_ruby/explorer/state @@ -21,12 +21,12 @@ ruby="$__object_id" user="$(cat "$__object/parameter/user")" if su - "$user" -c "[ ! -d \"\$HOME/.rvm\" ]" ; then - echo "removed" + echo "absent" exit 0 fi if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" rvm list | grep -q $ruby"; then - echo "installed" + echo "present" else - echo "removed" + echo "absent" fi diff --git a/conf/type/__rvm_ruby/gencode-remote b/conf/type/__rvm_ruby/gencode-remote index a3bcf318..b25b4fe9 100755 --- a/conf/type/__rvm_ruby/gencode-remote +++ b/conf/type/__rvm_ruby/gencode-remote @@ -25,7 +25,7 @@ default="$(cat "$__object/parameter/default")" state_should="$(cat "$__object/parameter/state")" if [ "$state_is" != "$state_should" ]; then case "$state_should" in - installed) + present) echo "su - \"$user\" -c \"source \\\$HOME/.rvm/scripts/rvm;"\ "rvm install $ruby\"" case "$default" in @@ -37,7 +37,7 @@ if [ "$state_is" != "$state_should" ]; then ;; esac ;; - removed) + absent) echo "su - \"$user\" -c \"source \\\$HOME/.rvm/scripts/rvm;"\ "rvm remove $ruby\"" ;; diff --git a/conf/type/__rvm_ruby/man.text b/conf/type/__rvm_ruby/man.text index c3183a7b..c558cfe3 100644 --- a/conf/type/__rvm_ruby/man.text +++ b/conf/type/__rvm_ruby/man.text @@ -18,7 +18,7 @@ REQUIRED PARAMETERS user:: The remote user account to use state:: - Either "installed" or "removed". + Either "present" or "absent". OPTIONAL PARAMETERS ------------------- @@ -30,13 +30,13 @@ EXAMPLES -------------------------------------------------------------------------------- # Install ruby 1.9.3 through rvm for user thelonious -__rvm_ruby ruby-1.9.3-p0 --user thelonious --state installed +__rvm_ruby ruby-1.9.3-p0 --user thelonious --state present # Install ruby 1.9.3 through rvm for user ornette and make it the default -__rvm_ruby ruby-1.9.3-p0 --user ornette --state installed --default yes +__rvm_ruby ruby-1.9.3-p0 --user ornette --state present --default yes # Remove ruby 1.9.3 for user john -__rvm_ruby ruby-1.9.3-p0 --user john --state removed +__rvm_ruby ruby-1.9.3-p0 --user john --state absent -------------------------------------------------------------------------------- diff --git a/conf/type/__rvm_ruby/manifest b/conf/type/__rvm_ruby/manifest index c6e31244..581e98a8 100755 --- a/conf/type/__rvm_ruby/manifest +++ b/conf/type/__rvm_ruby/manifest @@ -78,6 +78,6 @@ case "$ruby" in ;; esac deps=$(eval echo \$$deps_list) -for p in $deps; do __package_${type} $p --state installed; done +for p in $deps; do __package_${type} $p --state present; done -__rvm "$user" --state installed +__rvm "$user" --state present From dee266aca00a728045b3f5a70ede57e058366b4e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 May 2012 16:39:13 +0200 Subject: [PATCH 1500/4212] ignore "no crontab for ..." message Signed-off-by: Nico Schottelius --- conf/type/__cron/explorer/entry | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__cron/explorer/entry b/conf/type/__cron/explorer/entry index 362c96fe..1b4bec42 100755 --- a/conf/type/__cron/explorer/entry +++ b/conf/type/__cron/explorer/entry @@ -24,7 +24,7 @@ user="$(cat "$__object/parameter/user")" prefix="#cdist:__cron/$name" suffix="#/cdist:__cron/$name" -crontab -u $user -l | awk -v prefix="$prefix" -v suffix="$suffix" ' +crontab -u $user -l 2>/dev/null | awk -v prefix="$prefix" -v suffix="$suffix" ' { if (index($0,prefix)) { triggered=1 From f873f12d77323516912ecbb165406d0da8178138 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 May 2012 16:39:55 +0200 Subject: [PATCH 1501/4212] ++changes(2.0.10) Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index 4ec97ab1..958da987 100644 --- a/doc/changelog +++ b/doc/changelog @@ -14,6 +14,8 @@ Changelog * Feature core: Correct parent dependency handling (Steven Armstrong) * Bugfix several types: Fix sed for FreeBSD (Istvan Beregszaszi) * New Type: __jail (Jake Guffey) + * Change Type: __rvm*: --state present/absent not installed/remvoed (Evax Software) + * Bugfix Type: __cron: Hide error output from crontab * Various smaller bugfixes (Chris Lamb) 2.0.9: 2012-03-12 From cd79d2b1eb1959cb91629629c6b11d827d096d08 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 May 2012 16:41:51 +0200 Subject: [PATCH 1502/4212] ++version Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index bd8e6483..0817a1cb 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -19,7 +19,7 @@ # # -VERSION = "2.0.9" +VERSION = "2.0.10" BANNER = """ .. . .x+=:. s From ab53f471f8915607314bdbf786d33b4c49d5b04c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 18 May 2012 16:42:14 +0200 Subject: [PATCH 1503/4212] ++date Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 958da987..63fcb6b0 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.0.10: +2.0.10: 2012-05-18 * Cleanup __group: No getent gshadow in old Redhat, use groupmod -g (Matt Coddington) * Bugfix __package_yum: Missing cat From c7fbdc8195f781d3affe82538f09ccb9b9759ae5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 22 May 2012 12:40:38 +0200 Subject: [PATCH 1504/4212] add --remote-exec and --remote-copy to command line args Signed-off-by: Nico Schottelius --- bin/cdist | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bin/cdist b/bin/cdist index c6467477..897ddbfc 100755 --- a/bin/cdist +++ b/bin/cdist @@ -68,6 +68,12 @@ def commandline(): parser['configinstall'].add_argument('-s', '--sequential', help='Operate on multiple hosts sequentially (default)', action='store_false', dest='parallel') + parser['configinstall'].add_argument('--remote-exec', + help='Command to use for remote execution (should behave like ssh)', + action='store_true', dest='remote_exec') + parser['configinstall'].add_argument('--remote-copy', + help='Command to use for remote copy (should behave like scp)', + action='store_true', dest='remote_copy') # Config parser['config'] = parser['sub'].add_parser('config', From 108283bbebb8319bcc99946eb58262e275f34cb6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 22 May 2012 13:01:31 +0200 Subject: [PATCH 1505/4212] add default values in argparse Signed-off-by: Nico Schottelius --- bin/cdist | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/bin/cdist b/bin/cdist index 897ddbfc..e011ec6d 100755 --- a/bin/cdist +++ b/bin/cdist @@ -68,12 +68,15 @@ def commandline(): parser['configinstall'].add_argument('-s', '--sequential', help='Operate on multiple hosts sequentially (default)', action='store_false', dest='parallel') - parser['configinstall'].add_argument('--remote-exec', - help='Command to use for remote execution (should behave like ssh)', - action='store_true', dest='remote_exec') + parser['configinstall'].add_argument('--remote-copy', help='Command to use for remote copy (should behave like scp)', - action='store_true', dest='remote_copy') + action='store', dest='remote_copy', + default="scp -o User=root -q") + 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") # Config parser['config'] = parser['sub'].add_parser('config', @@ -165,6 +168,8 @@ def configinstall_onehost(host, args, mode, parallel): context = cdist.context.Context( target_host=host, + remote_copy=args.remote_copy, + remote_exec=args.remote_exec, initial_manifest=args.manifest, base_path=args.cdist_home, exec_path=sys.argv[0], From 9f319ae1213caf8b36ceaf3708d20981442f4f2e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 22 May 2012 14:55:11 +0200 Subject: [PATCH 1506/4212] support passing remote_{exec, copy} to context Signed-off-by: Nico Schottelius --- lib/cdist/context.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index ab8677a7..c38d6b94 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -35,6 +35,8 @@ class Context(object): def __init__(self, target_host, + remote_copy, + remote_exec, initial_manifest=False, base_path=False, exec_path=sys.argv[0], @@ -70,10 +72,18 @@ class Context(object): self.initial_manifest = (initial_manifest or os.path.join(self.local.manifest_path, "init")) - # Remote + _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_exec = os.environ.setdefault('__remote_exec', "ssh -o User=root -q") - self.remote_copy = os.environ.setdefault('__remote_copy', "scp -o User=root -q") + 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) From 26d7eab852bae2eb43de9bcd4b615fc2ca0fa31e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 22 May 2012 15:06:04 +0200 Subject: [PATCH 1507/4212] document change + manpage Signed-off-by: Nico Schottelius --- doc/changelog | 3 +++ doc/man/man1/cdist.text | 29 ++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/doc/changelog b/doc/changelog index 63fcb6b0..966e876e 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.0.11: + * Add support for --remote-exec and --remote-copy parameters + 2.0.10: 2012-05-18 * Cleanup __group: No getent gshadow in old Redhat, use groupmod -g (Matt Coddington) diff --git a/doc/man/man1/cdist.text b/doc/man/man1/cdist.text index e46e84a3..b92fba18 100644 --- a/doc/man/man1/cdist.text +++ b/doc/man/man1/cdist.text @@ -41,23 +41,29 @@ CONFIG Configure a system -h, --help:: - Show the help screen + Show the help screen -c CDIST_HOME, --cdist-home CDIST_HOME:: - Instead of using the parent of the bin directory as cdist home, - use the specified directory + Instead of using the parent of the bin directory as cdist home, + use the specified directory -d, --debug:: - Enable debug output + Enable debug output -i MANIFEST, --initial-manifest MANIFEST:: - Path to a cdist manifest or - to read from stdin + Path to a cdist manifest or - to read from stdin -p, --parallel:: - Operate on multiple hosts in parallel + Operate on multiple hosts in parallel -s, --sequential:: - Operate on multiple hosts sequentially + Operate on multiple hosts sequentially + +--remote-copy REMOTE_COPY: + Command to use for remote copy (should behave like scp) + +--remote-exec REMOTE_EXEC: + Command to use for remote execution (should behave like ssh) EXAMPLES @@ -69,7 +75,12 @@ cdist config -d ikq05.ethz.ch # Configure hosts in parallel and use a different home directory cdist config -c ~/p/cdist-nutzung \ - -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch + -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 \ + --remote-copy /path/to/my/remote/copy \ + -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch # Display banner cdist banner @@ -98,7 +109,7 @@ The following exit values shall be returned: 0:: Successful completion 1:: - One or more host configuration failed. + One or more host configurations failed SEE ALSO From 02bd4fdf3fb75b118a767d6a99288e1a3f2ab1d9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 22 May 2012 15:10:02 +0200 Subject: [PATCH 1508/4212] add template for tutorial for remote-exec-copy Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-remote-exec-copy.text | 35 ++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 doc/man/man7/cdist-remote-exec-copy.text diff --git a/doc/man/man7/cdist-remote-exec-copy.text b/doc/man/man7/cdist-remote-exec-copy.text new file mode 100644 index 00000000..6010907a --- /dev/null +++ b/doc/man/man7/cdist-remote-exec-copy.text @@ -0,0 +1,35 @@ +cdist-remote-exec-copy(7) +========================= +Nico Schottelius +STEVEN HERE + + +NAME +---- +cdist-remote-exec-copy - How to get use remote exec and copy + + +INTRO +------- +What it is, how it works + + +EXAMPLES +-------------- +nfsroot, sudo (?), what exists + + +HACKER INFORMATION +------------------ +Not sure if needed, but may be helpful to explain how it +works internally + +SEE ALSO +-------- +- cdist(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 67a95b50aae82d818b32fef3f1ca022158f12345 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 22 May 2012 16:01:03 +0200 Subject: [PATCH 1509/4212] cool solution for variable sending Signed-off-by: Nico Schottelius --- doc/dev/todo/TAKEME | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index 11235f8a..87fc91c5 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -9,6 +9,8 @@ CORE - document and add paremeters for remote-copy and remote-exec! - remove hack, make a feature of it +- remove var=foo calls on remote side. Use -o SendEnv (yeah, see ssh_config(5)) + TESTS ----- - multiple defines of object: From 1b8b54f84fe6a23e531eb7a55528677b1fb18054 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 22 May 2012 17:21:58 +0200 Subject: [PATCH 1510/4212] use os.umask locally Signed-off-by: Nico Schottelius --- lib/cdist/exec/local.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index d3c6a0ce..8c9ef209 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -60,6 +60,9 @@ class Local(object): self.log = logging.getLogger(self.target_host) + # Setup file permissions using umask + os.umask(0o700) + def create_directories(self): self.mkdir(self.out_path) self.mkdir(self.global_explorer_out_path) @@ -73,8 +76,7 @@ class Local(object): def mkdir(self, path): """Create directory on the local side.""" self.log.debug("Local mkdir: %s", path) - # FIXME: dont set mode here, fix unittest mkdtemp instead - os.makedirs(path, mode=0o700, exist_ok=True) + os.makedirs(path, exist_ok=True) def run(self, command, env=None, return_output=False): """Run the given command with the given environment. From e05c5e699c4b36ec7db99a7322f357a984c6bfaa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 22 May 2012 17:24:58 +0200 Subject: [PATCH 1511/4212] always call umask 077 before doing stuff on the remote side Signed-off-by: Nico Schottelius --- lib/cdist/exec/remote.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 11b8c78e..173d1984 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -105,6 +105,9 @@ 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;") + # can't pass environment to remote side, so prepend command with # variable declarations if env: From 612fb4cb7b070f0a4d988db08751c1db0a7b285b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 22 May 2012 17:27:38 +0200 Subject: [PATCH 1512/4212] fix type and add fixme Signed-off-by: Nico Schottelius --- lib/cdist/exec/local.py | 2 +- lib/cdist/exec/remote.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index 8c9ef209..e510a8fb 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -61,7 +61,7 @@ class Local(object): self.log = logging.getLogger(self.target_host) # Setup file permissions using umask - os.umask(0o700) + os.umask(0o077) def create_directories(self): self.mkdir(self.out_path) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 173d1984..fb90939d 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -108,6 +108,7 @@ class Remote(object): # 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 if env: From 4017667952ad663b5c63a900f2ad93acd95ca7c5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 22 May 2012 17:28:38 +0200 Subject: [PATCH 1513/4212] ++changes(2.0.11) Signed-off-by: Nico Schottelius --- doc/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/changelog b/doc/changelog index 63fcb6b0..d3202c70 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.0.11: + * Fix insecure file/directory creation: Use umask 077 + 2.0.10: 2012-05-18 * Cleanup __group: No getent gshadow in old Redhat, use groupmod -g (Matt Coddington) From cfc20ce4eed5b556b72bcc0747432a2a95ff98c5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 23 May 2012 14:17:05 +0200 Subject: [PATCH 1514/4212] match on new version location in releasescript Signed-off-by: Nico Schottelius --- doc/dev/releasechecklist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index eba81dc0..92c603d6 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -13,7 +13,7 @@ echo "Testing documentation..." # get version changelog_version=$(grep '^[[:digit:]]' doc/changelog | head -n1 | sed 's/:.*//') #git_version=$(git describe) -lib_version=$(grep ^VERSION lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g') +lib_version=$(grep ^ VERSION lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g') # get date date_today="$(date +%Y-%m-%d)" From d2fbd1565529207e9e98a5c8a023c825d670ece1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 23 May 2012 14:17:49 +0200 Subject: [PATCH 1515/4212] ++version=2.0.11 Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- lib/cdist/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/changelog b/doc/changelog index d3202c70..e2605009 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.0.11: +2.0.11: 2012-05-23 * Fix insecure file/directory creation: Use umask 077 2.0.10: 2012-05-18 diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index b9289911..35dc72c7 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -29,7 +29,7 @@ try: 'cd "%s" && git describe' % here, stderr=devnull, shell=True).decode('utf-8') except: - VERSION = "2.0.10" + VERSION = "2.0.11" BANNER = """ .. . .x+=:. s From 7c7a6218759329618cec0919f30177e6c4d22bbb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 23 May 2012 14:19:58 +0200 Subject: [PATCH 1516/4212] fix manpage compile error Signed-off-by: Nico Schottelius --- conf/type/__jail/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__jail/man.text b/conf/type/__jail/man.text index b6725bde..8682effe 100644 --- a/conf/type/__jail/man.text +++ b/conf/type/__jail/man.text @@ -1,5 +1,5 @@ cdist-type__jail(7) -========================== +=================== Jake Guffey From a1879ebe0c7076c6345efdd4f0a6e7a78811ca2a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 23 May 2012 14:34:21 +0200 Subject: [PATCH 1517/4212] ++ quotes Signed-off-by: Nico Schottelius --- doc/dev/releasechecklist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index 92c603d6..410c988e 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -13,7 +13,7 @@ echo "Testing documentation..." # get version changelog_version=$(grep '^[[:digit:]]' doc/changelog | head -n1 | sed 's/:.*//') #git_version=$(git describe) -lib_version=$(grep ^ VERSION lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g') +lib_version=$(grep "^ VERSION" lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g') # get date date_today="$(date +%Y-%m-%d)" From 995e2c44eea7fe714bbcd71fbaff5aeae963e955 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 23 May 2012 14:39:41 +0200 Subject: [PATCH 1518/4212] correctly create branch variable Signed-off-by: Nico Schottelius --- doc/dev/releasechecklist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index 410c988e..71f2979e 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -41,7 +41,7 @@ read wait version=$lib_version # get target branch -branch=${version%.?} +branch=${version%\.*} # add tag printf "Enter tag description for %s> " "$version" @@ -49,7 +49,7 @@ read tagmessage git tag "$version" -m "$tagmessage" # Import into current version branch -printf "Press enter to git merge into $branch > " +printf "Press enter to git merge into branch \"$branch\" > " read prompt git checkout $branch git merge master From f2c71aab2ee109c44e65377b58794f3ade984618 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 23 May 2012 14:54:32 +0200 Subject: [PATCH 1519/4212] update description Signed-off-by: Nico Schottelius --- README | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README b/README index abd38401..ce494906 100644 --- a/README +++ b/README @@ -19,6 +19,9 @@ ## Introduction +cdist is a usable configuration management system. It adheres to +the KISS principle and is being used in small up to enterprise grade +environments. cdist is an alternative to other configuration management systems like [cfengine](http://www.cfengine.org/), [bcfg2](http://trac.mcs.anl.gov/projects/bcfg2), From f795b83c8e1af77208c0d610ddf578c271668b5c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 24 May 2012 15:15:38 +0200 Subject: [PATCH 1520/4212] prevent a hen/egg problem when handling unsupported python versions Signed-off-by: Steven Armstrong --- bin/cdist | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bin/cdist b/bin/cdist index c6467477..8d0dfc76 100755 --- a/bin/cdist +++ b/bin/cdist @@ -194,6 +194,13 @@ if __name__ == "__main__": # Sys is needed for sys.exit() import sys + cdistpythonversion = '3.2' + if sys.version < cdistpythonversion: + print('Cdist requires Python >= ' + cdistpythonversion + + ' on the source host.', file=sys.stderr) + sys.exit(1) + + exit_code = 0 try: @@ -201,11 +208,6 @@ if __name__ == "__main__": import os import re - cdistpythonversion = '3.2' - if sys.version < cdistpythonversion: - raise cdist.Error('Cdist requires Python >= ' + cdistpythonversion + - ' on the source host.') - # Ensure our /lib/ is included into PYTHON_PATH sys.path.insert(0, os.path.abspath( os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) From 2e930d5f25d0b7ac2811eea8ea026f6be3d210c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Gross?= Date: Thu, 24 May 2012 15:45:20 +0200 Subject: [PATCH 1521/4212] Add python3.2 for Debian squeezy how-to. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Gross --- README | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README b/README index ce494906..4521f80e 100644 --- a/README +++ b/README @@ -112,6 +112,21 @@ For Debian >= wheezy: For older Debian versions, installing python 3.2 manually is required. +On squeeze you can add following line in **/etc/apt/sources.list** + + deb http://ftp.debian.org/debian wheezy main + +And don't forget the pinning entry in **/etc/apt/preferences.d/wheezy**: + + Package: * + Pin: release n=wheezy + Pin-Priority: 1 + +Please be aware that both **openssh-server** and **openssh-client** might be +removed on **pyhton3.2** installation. You surely want to reinstall them: + + apt-get install -t wheezy openssh-server openssh-client + #### Fedora For Fedora >= 15: From 67bf4d15830f0fedf02dc18da17695c971cd5772 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 24 May 2012 15:50:31 +0200 Subject: [PATCH 1522/4212] Fix typos Signed-off-by: Nico Schottelius --- README | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README b/README index 4521f80e..932375c4 100644 --- a/README +++ b/README @@ -110,23 +110,24 @@ For Debian >= wheezy: aptitude install python3 -For older Debian versions, installing python 3.2 manually is required. - On squeeze you can add following line in **/etc/apt/sources.list** deb http://ftp.debian.org/debian wheezy main -And don't forget the pinning entry in **/etc/apt/preferences.d/wheezy**: +And add pinning entry in **/etc/apt/preferences.d/wheezy**: Package: * Pin: release n=wheezy Pin-Priority: 1 Please be aware that both **openssh-server** and **openssh-client** might be -removed on **pyhton3.2** installation. You surely want to reinstall them: +removed on **python3.2** installation. You surely want to reinstall them: apt-get install -t wheezy openssh-server openssh-client +For older Debian versions, installing python 3.2 manually is required. + + #### Fedora For Fedora >= 15: From 3013f6c96a1062c03f0903c859b99ff0efe3ea19 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 24 May 2012 15:51:28 +0200 Subject: [PATCH 1523/4212] ++changes(2.0.12) Signed-off-by: Nico Schottelius --- doc/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/changelog b/doc/changelog index e2605009..0e10533b 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,6 +4,10 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.0.12: + * Core: Correctly raise error on Python < 3.2 (Steven Armtrong) + * Documentation: Debian Squeeze hints (Sébastien Gross) + 2.0.11: 2012-05-23 * Fix insecure file/directory creation: Use umask 077 From b92621cad710dccd132ae4c79de3256b8d04db74 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 24 May 2012 15:53:53 +0200 Subject: [PATCH 1524/4212] add a way on how to add workaround for older pythor versions Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-05-24.makedirs.py-python3.1 | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 doc/dev/logs/2012-05-24.makedirs.py-python3.1 diff --git a/doc/dev/logs/2012-05-24.makedirs.py-python3.1 b/doc/dev/logs/2012-05-24.makedirs.py-python3.1 new file mode 100644 index 00000000..5ad82b29 --- /dev/null +++ b/doc/dev/logs/2012-05-24.makedirs.py-python3.1 @@ -0,0 +1,27 @@ +# From curl http://armstrong.cc/~steven/tmp/makedirs.py: + +#!/usr/bin/env python2 + +import os + +def makedirs(path, mode=0o777, exist_ok=False): + try: + os.makedirs(path, mode=mode, exist_ok=exist_ok) + except TypeError: + try: + os.makedirs(path, mode=mode) + except OSError as e: + if exist_ok and e.errno == 17: # File exists + pass + else: + raise + + +makedirs('/tmp/python/makedirs') + +try: + makedirs('/tmp/python/makedirs') +except OSError as e: + print(e) + +makedirs('/tmp/python/makedirs', exist_ok=True) From 046439a1ddec206706e368527f307492002dc18b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 25 May 2012 10:38:15 +0200 Subject: [PATCH 1525/4212] +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 4b33177d5476eacdae4a1640fdeee264c1060034 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 25 May 2012 17:07:59 +0200 Subject: [PATCH 1526/4212] remove install command for now Signed-off-by: Steven Armstrong --- bin/cdist | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/cdist b/bin/cdist index 8d0dfc76..b04f2eb2 100755 --- a/bin/cdist +++ b/bin/cdist @@ -75,9 +75,10 @@ def commandline(): parser['config'].set_defaults(func=config) # Install - parser['install'] = parser['sub'].add_parser('install', - parents=[parser['loglevel'], parser['configinstall']]) - parser['install'].set_defaults(func=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/" From eea9a72676c1ed9cf7fc7e910938bb7231e5b5a3 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 29 May 2012 09:29:01 +0200 Subject: [PATCH 1527/4212] bugfix: tell schroot which chroot to use Signed-off-by: Steven Armstrong --- other/examples/remote/schroot-uri | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/other/examples/remote/schroot-uri b/other/examples/remote/schroot-uri index a23277ec..9819c5a5 100755 --- a/other/examples/remote/schroot-uri +++ b/other/examples/remote/schroot-uri @@ -1,6 +1,6 @@ #!/bin/sh -e # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -49,7 +49,8 @@ my_name="${0##*/}" mode="$1"; shift log() { - echo "$@" | logger -t "cdist-$my_name-$mode" + # uncomment me for debugging + #echo "$@" | logger -t "cdist-$my_name-$mode" : } @@ -109,6 +110,9 @@ else copy_prefix="cp" copy_destination_prefix="" fi +log "exec_prefix: $exec_prefix" +log "copy_prefix: $copy_prefix" +log "copy_destination_prefix: $copy_destination_prefix" case "$mode" in exec) @@ -118,8 +122,9 @@ case "$mode" in ;; copy) # get directory for given chroot_name - schroot_directory="$($exec_prefix schroot $chroot_name --config | awk -F = '/directory=/ {print $2}')" + schroot_directory="$($exec_prefix schroot -c $schroot_name --config | awk -F = '/directory=/ {print $2}')" [ -n "$schroot_directory" ] || die "Failed to retreive schroot directory for schroot: $schroot_name" + log "schroot_directory: $schroot_directory" # prefix destination with chroot code="$copy_prefix $(echo "$@" | sed "s|$uri:|${copy_destination_prefix}${schroot_directory}|g")" ;; From 21b85e410e203a86dbd3cbc592ca3c4c1cab9441 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 29 May 2012 10:12:00 +0200 Subject: [PATCH 1528/4212] bugfix: its a method, not a function Signed-off-by: Steven Armstrong --- lib/cdist/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/context.py b/lib/cdist/context.py index c38d6b94..8b468739 100644 --- a/lib/cdist/context.py +++ b/lib/cdist/context.py @@ -72,7 +72,7 @@ class Context(object): self.initial_manifest = (initial_manifest or os.path.join(self.local.manifest_path, "init")) - _init_remote(remote_copy, remote_exec) + self._init_remote(remote_copy, remote_exec) # Remote stuff def _init_remote(self, remote_copy, remote_exec): From 5edf39f1114be85fe3b8d1b772f5625e3177a14f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 29 May 2012 11:02:23 +0200 Subject: [PATCH 1529/4212] no special case for rsync in core. handle implementation specific details in remote-copy script instead Signed-off-by: Steven Armstrong --- lib/cdist/exec/remote.py | 7 +------ other/examples/remote/rsync/copy | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index fb90939d..487beea3 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -77,12 +77,7 @@ class Remote(object): self.log.debug("Remote transfer: %s -> %s", source, destination) self.rmdir(destination) command = self._copy.split() - # support rsync by appending a "/" to the source if it's a directory - if os.path.isdir(source): - command.extend(["-r", source + "/", self.target_host + ":" + destination]) - else: - command.extend(["-r", source, self.target_host + ":" + destination]) - + command.extend(["-r", source, self.target_host + ":" + destination]) self._run_command(command) def run_script(self, script, env=None, return_output=False): diff --git a/other/examples/remote/rsync/copy b/other/examples/remote/rsync/copy index f6b93c5c..96d3f3de 100755 --- a/other/examples/remote/rsync/copy +++ b/other/examples/remote/rsync/copy @@ -24,7 +24,24 @@ # at /etc/passwd~cdist. # # Usage: -# __remote_copy="/path/to/this/script" cdist config target_host +# cdist config --remote-copy /path/to/this/script target_host # +# 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 + echo "directory: $arg" | logger + # if the source is a directory, it has to end with "/" for rsync to do the right thing + arg="${arg%/}/" + fi + set -- "$@" "$arg" +done + rsync --backup --suffix=~cdist -e 'ssh -o User=root' $@ From d052e2d510f3ec4506400bb35a4e81596660dcc7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 29 May 2012 11:03:15 +0200 Subject: [PATCH 1530/4212] --debug Signed-off-by: Steven Armstrong --- other/examples/remote/rsync/copy | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/other/examples/remote/rsync/copy b/other/examples/remote/rsync/copy index 96d3f3de..0d4bd165 100755 --- a/other/examples/remote/rsync/copy +++ b/other/examples/remote/rsync/copy @@ -33,11 +33,10 @@ index=0 for arg in $@; do if [ $index -eq 0 ]; then # reset $@ - set -- + set -- fi index=$((index+=1)) if [ $index -eq $source_index -a -d "$arg" ]; then - echo "directory: $arg" | logger # if the source is a directory, it has to end with "/" for rsync to do the right thing arg="${arg%/}/" fi From fc8ff292893e060a13e456e50454299f13e27f7e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 29 May 2012 11:14:21 +0200 Subject: [PATCH 1531/4212] update comments to work with arguments vs environment variables: /__remote_{exec,copy}/--remote-{exec,copy}/ Signed-off-by: Steven Armstrong --- other/examples/remote/chroot/copy | 2 +- other/examples/remote/chroot/exec | 2 +- other/examples/remote/schroot-uri | 6 ++++-- other/examples/remote/schroot/copy | 2 +- other/examples/remote/schroot/exec | 2 +- other/examples/remote/ssh/copy | 2 +- other/examples/remote/ssh/exec | 2 +- 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/other/examples/remote/chroot/copy b/other/examples/remote/chroot/copy index 528a5faf..8f8cb680 100755 --- a/other/examples/remote/chroot/copy +++ b/other/examples/remote/chroot/copy @@ -22,7 +22,7 @@ # to a remote target host. # # Usage: -# __remote_copy="/path/to/this/script /path/to/your/chroot" cdist config target-id +# cdist config --remote-copy "/path/to/this/script /path/to/your/chroot" target-id # log() { diff --git a/other/examples/remote/chroot/exec b/other/examples/remote/chroot/exec index 19e76b0e..4637f918 100755 --- a/other/examples/remote/chroot/exec +++ b/other/examples/remote/chroot/exec @@ -22,7 +22,7 @@ # on a remote target host. # # Usage: -# __remote_exec="/path/to/this/script /path/to/your/chroot" cdist config target-id +# cdist config --remote-exec "/path/to/this/script /path/to/your/chroot" target-id # log() { diff --git a/other/examples/remote/schroot-uri b/other/examples/remote/schroot-uri index 9819c5a5..5b50a195 100755 --- a/other/examples/remote/schroot-uri +++ b/other/examples/remote/schroot-uri @@ -21,8 +21,10 @@ # __remote_{exec,copy} script to run cdist against a schroot target uri # # Usage: -# __remote_exec="/path/to/this/script exec" cdist config target_uri -# __remote_copy="/path/to/this/script copy" cdist config target_uri +# cdist config \ +# --remote-exec "/path/to/this/script exec" \ +# --remote-copy "/path/to/this/script copy" \ +# target_uri # # # target_uri examples: # schroot:///chroot-name diff --git a/other/examples/remote/schroot/copy b/other/examples/remote/schroot/copy index 3587a4f2..cbd45573 100755 --- a/other/examples/remote/schroot/copy +++ b/other/examples/remote/schroot/copy @@ -21,7 +21,7 @@ # __remote_copy script to run cdist against a chroot on the target host over ssh. # # Usage: -# __remote_copy="/path/to/this/script schroot-chroot-name" cdist config target_host +# cdist config --remote-copy "/path/to/this/script schroot-chroot-name" target_host # log() { diff --git a/other/examples/remote/schroot/exec b/other/examples/remote/schroot/exec index 5b561de0..2510fd22 100755 --- a/other/examples/remote/schroot/exec +++ b/other/examples/remote/schroot/exec @@ -21,7 +21,7 @@ # __remote_exec script to run cdist against a chroot on the target host over ssh. # # Usage: -# __remote_exec="/path/to/this/script schroot-chroot-name" cdist config target_host +# cdist config --remote-exec "/path/to/this/script schroot-chroot-name" target_host # log() { diff --git a/other/examples/remote/ssh/copy b/other/examples/remote/ssh/copy index 0ecd8c52..5b0ed324 100755 --- a/other/examples/remote/ssh/copy +++ b/other/examples/remote/ssh/copy @@ -21,7 +21,7 @@ # same as cdist default # # Usage: -# __remote_copy="/path/to/this/script" cdist config target_host +# cdist config --remote-copy "/path/to/this/script" target_host # #echo "$@" | logger -t "cdist-ssh-copy" diff --git a/other/examples/remote/ssh/exec b/other/examples/remote/ssh/exec index b597a47f..2875c3fc 100755 --- a/other/examples/remote/ssh/exec +++ b/other/examples/remote/ssh/exec @@ -21,7 +21,7 @@ # same as cdist default # # Usage: -# __remote_exec="/path/to/this/script" cdist config target_host +# cdist config --remote-exec "/path/to/this/script" target_host # #echo "$@" | logger -t "cdist-ssh-exec" From d34ea9a9c968f8923ef0388a235458e529fbcf8a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 29 May 2012 12:00:03 +0200 Subject: [PATCH 1532/4212] add missing -c argument Signed-off-by: Steven Armstrong --- other/examples/remote/schroot/copy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/examples/remote/schroot/copy b/other/examples/remote/schroot/copy index cbd45573..d995055e 100755 --- a/other/examples/remote/schroot/copy +++ b/other/examples/remote/schroot/copy @@ -33,7 +33,7 @@ chroot_name="$1"; shift target_host="$__target_host" # get directory for given chroot_name -chroot="$(ssh -o User=root -q $target_host schroot $chroot_name --config | awk -F = '/directory=/ {print $2}')" +chroot="$(ssh -o User=root -q $target_host schroot -c $chroot_name --config | awk -F = '/directory=/ {print $2}')" # prefix destination with chroot code="$(echo "$@" | sed "s|$target_host:|$target_host:$chroot|g")" From 9d09407cc476993cc94380469b97fd350a8ec332 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 29 May 2012 12:04:35 +0200 Subject: [PATCH 1533/4212] ++doc Signed-off-by: Steven Armstrong --- other/examples/remote/rsync/copy | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/other/examples/remote/rsync/copy b/other/examples/remote/rsync/copy index 0d4bd165..76217caf 100755 --- a/other/examples/remote/rsync/copy +++ b/other/examples/remote/rsync/copy @@ -1,6 +1,7 @@ #!/bin/sh # # 2012 Matt Coddington (mcoddington at gmail.com) +# 2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -27,6 +28,9 @@ # 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 @@ -37,7 +41,6 @@ for arg in $@; do fi index=$((index+=1)) if [ $index -eq $source_index -a -d "$arg" ]; then - # if the source is a directory, it has to end with "/" for rsync to do the right thing arg="${arg%/}/" fi set -- "$@" "$arg" From cf980f2985f0fb4f4103155e05831dd259c327b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Gross?= Date: Tue, 29 May 2012 13:11:42 +0200 Subject: [PATCH 1534/4212] List all network interfaces in explorer/ifaces. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Gross --- conf/explorer/ifaces | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100755 conf/explorer/ifaces diff --git a/conf/explorer/ifaces b/conf/explorer/ifaces new file mode 100755 index 00000000..e5fd8a45 --- /dev/null +++ b/conf/explorer/ifaces @@ -0,0 +1,38 @@ +#!/bin/sh +# +# 2012 Sébastien Gross +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# List all network interfaces in explorer/ifaces. One interface per line. +# + +uname_s="$(uname -s)" + +case "$uname_s" in + Linux) + ifconfig | sed -n 's/^\([^[:space:]]\+\)[[:space:]].*/\1/p' + exit 0 + ;; + Darwin|*BSD) + ifconfig | sed -n 's/^\([^:]*\): flags.*/\1/p' + exit 0 + ;; +esac + +echo "Unknown OS" >&2 +exit 1 From 8e9e0a862a1fcb00c1b26bacacfdc870cd78bb76 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 29 May 2012 13:33:22 +0200 Subject: [PATCH 1535/4212] document how remote exec/copy is used Signed-off-by: Steven Armstrong --- doc/man/man7/cdist-remote-exec-copy.text | 31 ++++++++++++++++-------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/doc/man/man7/cdist-remote-exec-copy.text b/doc/man/man7/cdist-remote-exec-copy.text index 6010907a..d789b12d 100644 --- a/doc/man/man7/cdist-remote-exec-copy.text +++ b/doc/man/man7/cdist-remote-exec-copy.text @@ -1,29 +1,40 @@ cdist-remote-exec-copy(7) ========================= Nico Schottelius -STEVEN HERE NAME ---- -cdist-remote-exec-copy - How to get use remote exec and copy +cdist-remote-exec-copy - How to use remote exec and copy INTRO -------- -What it is, how it works +----- +Cdist interacts with the target host in two ways: +- it executes code (__remote_exec) +- and it copies files (__remote_copy) + +By default this is accomplished with ssh and scp respectively. +The default implementations used by cdist are: +__remote_exec: ssh -o User=root -q +__remote_copy: scp -o User=root -q + +The user can override these defaults by providing custom implementations and +passing them to cdist with the --remote-exec and/or --remote-copy arguments. + +For __remote_exec, the custom implementation must behave as if it where ssh. +For __remote_copy, it must behave like scp. + +With this simple interface the user can take total control of how cdist +interacts with the target when required, while the default implementation +remains as simple as possible. EXAMPLES -------------- -nfsroot, sudo (?), what exists +See cdist/other/examples/remote/ for some example implementations. -HACKER INFORMATION ------------------- -Not sure if needed, but may be helpful to explain how it -works internally - SEE ALSO -------- - cdist(7) From 78181f2a4db09ae367b8960c78168d5044c59351 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 29 May 2012 15:53:31 +0200 Subject: [PATCH 1536/4212] reorder changes for 2.0.12 Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 3546fe46..5ba9ff1c 100644 --- a/doc/changelog +++ b/doc/changelog @@ -6,11 +6,11 @@ Changelog 2.0.12: * Core: Correctly raise error on Python < 3.2 (Steven Armtrong) + * Core: Add support for --remote-exec and --remote-copy parameters * Documentation: Debian Squeeze hints (Sébastien Gross) 2.0.11: 2012-05-23 * Fix insecure file/directory creation: Use umask 077 - * Add support for --remote-exec and --remote-copy parameters 2.0.10: 2012-05-18 * Cleanup __group: No getent gshadow in old Redhat, use groupmod -g From c4aa68cfc18e83b39f9f113d275783ec02761a53 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 29 May 2012 15:53:57 +0200 Subject: [PATCH 1537/4212] ++version Signed-off-by: Nico Schottelius --- lib/cdist/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 35dc72c7..38a5f602 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -29,7 +29,7 @@ try: 'cd "%s" && git describe' % here, stderr=devnull, shell=True).decode('utf-8') except: - VERSION = "2.0.11" + VERSION = "2.0.12" BANNER = """ .. . .x+=:. s From bcacea46d72565df5f5d0b9d0b78aa88f1589cdf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 29 May 2012 15:57:38 +0200 Subject: [PATCH 1538/4212] ++date Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 5ba9ff1c..0b6ed4a1 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.0.12: +2.0.12: 2012-05-29 * Core: Correctly raise error on Python < 3.2 (Steven Armtrong) * Core: Add support for --remote-exec and --remote-copy parameters * Documentation: Debian Squeeze hints (Sébastien Gross) From 3cb85fc3f33a87e9f7855143a9debbc6db536239 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 30 May 2012 15:57:44 +0200 Subject: [PATCH 1539/4212] Bugfix __addifnosuchline: Missing quotes Signed-off-by: Nico Schottelius --- conf/type/__addifnosuchline/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__addifnosuchline/gencode-remote b/conf/type/__addifnosuchline/gencode-remote index f97789ae..1276e5d0 100755 --- a/conf/type/__addifnosuchline/gencode-remote +++ b/conf/type/__addifnosuchline/gencode-remote @@ -29,5 +29,5 @@ result=$(cat "$__object/explorer/findline") if [ "$result" = "NOTFOUND" ]; then line=$(cat "$__object/parameter/line") - echo "echo $line >> $file" + echo "echo \"$line\" >> $file" fi From 9d74696e62c434ba68f85158dcfaf3ff50043fa4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 30 May 2012 16:00:31 +0200 Subject: [PATCH 1540/4212] ++changes(2.0.13) Signed-off-by: Nico Schottelius --- doc/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/changelog b/doc/changelog index 0b6ed4a1..c3ececa4 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.0.13: + * Bugfix __addifnosuchline: Fixed quotes/interpolation bug ("a b" became "a b") + 2.0.12: 2012-05-29 * Core: Correctly raise error on Python < 3.2 (Steven Armtrong) * Core: Add support for --remote-exec and --remote-copy parameters From 4f303ecb27967c8fcd1a1c16236beee4dd50ddd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Gross?= Date: Wed, 30 May 2012 17:46:46 +0200 Subject: [PATCH 1541/4212] Fix ifconfig output parsing against various OSes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Gross --- conf/explorer/ifaces | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/conf/explorer/ifaces b/conf/explorer/ifaces index e5fd8a45..64ab8aa7 100755 --- a/conf/explorer/ifaces +++ b/conf/explorer/ifaces @@ -20,19 +20,22 @@ # # List all network interfaces in explorer/ifaces. One interface per line. # +# If your OS is not supported please provide a ifconfig output +# uname_s="$(uname -s)" -case "$uname_s" in - Linux) - ifconfig | sed -n 's/^\([^[:space:]]\+\)[[:space:]].*/\1/p' - exit 0 - ;; - Darwin|*BSD) - ifconfig | sed -n 's/^\([^:]*\): flags.*/\1/p' - exit 0 - ;; -esac +REGEXP='s/^(.*)(:[[:space:]]*flags=|Link encap).*/\1/p' -echo "Unknown OS" >&2 -exit 1 +case "$uname_s" in + Darwin) + ifconfig -a | sed -n -E "$REGEXP" + ;; + Linux|*BSD) + ifconfig -a | sed -n -r "$REGEXP" + ;; + *) + echo "Unsupported ifconfig output for $uname_s" >&2 + exit 1 + ;; +esac From dd3b96edffd39c8eae055bcb84706816f3a5d670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Gross?= Date: Wed, 30 May 2012 17:56:48 +0200 Subject: [PATCH 1542/4212] Add some ifconfig -a outputs for example. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Gross --- doc/dev/logs/2012-05-30.ifconfig-outputs | 177 +++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 doc/dev/logs/2012-05-30.ifconfig-outputs diff --git a/doc/dev/logs/2012-05-30.ifconfig-outputs b/doc/dev/logs/2012-05-30.ifconfig-outputs new file mode 100644 index 00000000..c314cce8 --- /dev/null +++ b/doc/dev/logs/2012-05-30.ifconfig-outputs @@ -0,0 +1,177 @@ +Here are some "ifconfig -a" outputs that help for the explorer/ifaces parser. + +The current regexp is 's/^(.*)(:[[:space:]]*flags=|Link encap).*/\1/p' + + +You should get the interface list when you run: + + ifconfig -a | sed -n -r 's/^(.*)(:[[:space:]]*flags=|Link encap).*/\1/p' + +If you don't maybe try to replace the sed -r option by -E (works on Darwin). + + +If you still don't get any output, the regexp might be wrong. + + + +On Archlinux: +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- +lo: flags=73 mtu 16436 metric 1 + inet 127.0.0.1 netmask 255.0.0.0 + inet6 ::1 prefixlen 128 scopeid 0x10 + loop txqueuelen 0 (Local Loopback) + RX packets 300081 bytes 49637437 (47.3 MiB) + RX errors 0 dropped 0 overruns 0 frame 0 + TX packets 300081 bytes 49637437 (47.3 MiB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + +wlan0: flags=4163 mtu 1500 metric 1 + inet 192.168.1.38 netmask 255.255.255.0 broadcast 192.168.1.255 + inet6 fe80::ba8d:12ff:fe15:fdfa prefixlen 64 scopeid 0x20 + ether b8:8d:12:15:fd:fa txqueuelen 1000 (Ethernet) + RX packets 421381 bytes 442228597 (421.7 MiB) + RX errors 0 dropped 0 overruns 0 frame 0 + TX packets 319266 bytes 41111233 (39.2 MiB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- + +On Debian Linux: +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- +eth0 Link encap:Ethernet HWaddr 00:16:17:55:2d:00 + inet addr:172.16.5.2 Bcast:172.16.255.255 Mask:255.255.0.0 + inet6 addr: fe80::216:17ff:fe55:2d00/64 Scope:Link + UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 + RX packets:2854022168 errors:5 dropped:0 overruns:0 frame:4 + TX packets:2200088072 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:1000 + RX bytes:2708386800354 (2.4 TiB) TX bytes:531552070314 (495.0 GiB) + Base address:0x3000 Memory:d0120000-d0140000 + +eth0:1 Link encap:Ethernet HWaddr 00:16:17:55:2d:00 + inet addr:172.16.5.1 Bcast:172.16.255.255 Mask:255.255.0.0 + UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 + Base address:0x3000 Memory:d0120000-d0140000 + +lo Link encap:Local Loopback + inet addr:127.0.0.1 Mask:255.0.0.0 + inet6 addr: ::1/128 Scope:Host + UP LOOPBACK RUNNING MTU:16436 Metric:1 + RX packets:36487087 errors:0 dropped:0 overruns:0 frame:0 + TX packets:36487087 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:0 + RX bytes:3388870184 (3.1 GiB) TX bytes:3388870184 (3.1 GiB) + +sit0 Link encap:IPv6-in-IPv4 + NOARP MTU:1480 Metric:1 + RX packets:0 errors:0 dropped:0 overruns:0 frame:0 + TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:0 + RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) + +tap0 Link encap:Ethernet HWaddr 16:db:17:fb:a1:4a + inet addr:10.254.0.1 Bcast:10.254.255.255 Mask:255.255.0.0 + inet6 addr: fe80::14db:17ff:fefb:a14a/64 Scope:Link + UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 + RX packets:0 errors:0 dropped:0 overruns:0 frame:0 + TX packets:6 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:100 + RX bytes:0 (0.0 B) TX bytes:468 (468.0 B) + +bond0 Link encap:Ethernet HWaddr 00:13:72:3c:bf:57 + inet6 addr: fe80::213:72ff:fe3c:bf57/64 Scope:Link + UP BROADCAST RUNNING MASTER MULTICAST MTU:1500 Metric:1 + RX packets:6930494799 errors:0 dropped:38584515 overruns:0 frame:17 + TX packets:1678579772 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:0 + RX bytes:10006832472618 (9.1 TiB) TX bytes:168031719693 (156.4 GiB) + +bond0.123 Link encap:Ethernet HWaddr 00:13:72:3c:bf:57 + inet addr:10.73.38.250 Bcast:10.73.38.255 Mask:255.255.255.0 + inet6 addr: fe80::213:72ff:fe3c:bf57/64 Scope:Link + UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 + RX packets:12382478 errors:0 dropped:5777 overruns:0 frame:0 + TX packets:564 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:0 + RX bytes:586071334 (558.9 MiB) TX bytes:64180 (62.6 KiB) + +tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:172.31.255.9 P-t-P:172.31.255.10 Mask:255.255.255.255 + UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1 + RX packets:9655 errors:0 dropped:0 overruns:0 frame:0 + TX packets:15118 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:100 + RX bytes:1760236 (1.6 MiB) TX bytes:14929984 (14.2 MiB) +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- + +On OpenBSD: +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- +lo0: flags=8049 mtu 33160 + priority: 0 + groups: lo + inet6 ::1 prefixlen 128 + inet6 fe80::1%lo0 prefixlen 64 scopeid 0x3 + inet 127.0.0.1 netmask 0xff000000 +em0: flags=8843 mtu 1500 + lladdr 00:50:56:b3:00:15 + priority: 0 + groups: egress + media: Ethernet autoselect (1000baseT full-duplex,master) + status: active + inet6 XXXX::XXX:XXXX:XXXX:XX%em0 prefixlen 64 scopeid 0x1 + inet6 XXXX:XXX:XXX:XX::XXX prefixlen 64 + inet XXX.XXX.XXX.XXX netmask 0xffffffc0 broadcast XXX.XXX.XXX.XXX +enc0: flags=0<> + priority: 0 + groups: enc + status: active +pflog0: flags=141 mtu 33160 + priority: 0 + groups: pflog +tun1: flags=8051 mtu 1500 + priority: 0 + groups: tun + status: active + inet 172.31.255.13 --> 172.31.255.14 netmask 0xffffffff +tun2: flags=8011 mtu 1500 + priority: 0 + groups: tun + status: down + inet 172.31.253.1 --> 172.31.253.2 netmask 0xffffffff +tun0: flags=8051 mtu 1500 + priority: 0 + groups: tun + status: active + inet 172.31.254.1 --> 172.31.254.2 netmask 0xffffffff +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- + +On Darwin: +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- +lo0: flags=8049 mtu 16384 + inet6 ::1 prefixlen 128 + inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 + inet 127.0.0.1 netmask 0xff000000 +gif0: flags=8010 mtu 1280 +stf0: flags=0<> mtu 1280 +en0: flags=8863 mtu 1500 + ether 34:15:9e:2e:8b:aa + inet6 fe80::3615:9eff:fe2e:8baa%en0 prefixlen 64 scopeid 0x4 + inet 192.168.1.102 netmask 0xffffff00 broadcast 192.168.1.255 + media: autoselect (100baseTX ) + status: active +en1: flags=8863 mtu 1500 + ether 7c:6d:62:a3:6f:57 + inet6 fe80::7e6d:62ff:fea3:6f57%en1 prefixlen 64 scopeid 0x5 + inet 192.168.2.105 netmask 0xffffff00 broadcast 192.168.2.255 + media: autoselect + status: active +fw0: flags=8863 mtu 4078 + lladdr 34:15:9e:ff:fe:2e:8b:aa + media: autoselect + status: inactive +tun0: flags=8851 mtu 1500 + inet 172.31.255.29 --> 172.31.255.30 netmask 0xffffffff + open (pid 24727) +tun1: flags=8851 mtu 1500 + inet 172.31.254.25 --> 172.31.254.26 netmask 0xffffffff + open (pid 24757) +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- From a306ebc0c85197a1e7ab46f0a3a263e7e9550308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Gross?= Date: Wed, 30 May 2012 17:56:48 +0200 Subject: [PATCH 1543/4212] Add some ifconfig -a outputs for example. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Gross --- doc/dev/logs/2012-05-30.ifconfig-outputs | 177 +++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 doc/dev/logs/2012-05-30.ifconfig-outputs diff --git a/doc/dev/logs/2012-05-30.ifconfig-outputs b/doc/dev/logs/2012-05-30.ifconfig-outputs new file mode 100644 index 00000000..c314cce8 --- /dev/null +++ b/doc/dev/logs/2012-05-30.ifconfig-outputs @@ -0,0 +1,177 @@ +Here are some "ifconfig -a" outputs that help for the explorer/ifaces parser. + +The current regexp is 's/^(.*)(:[[:space:]]*flags=|Link encap).*/\1/p' + + +You should get the interface list when you run: + + ifconfig -a | sed -n -r 's/^(.*)(:[[:space:]]*flags=|Link encap).*/\1/p' + +If you don't maybe try to replace the sed -r option by -E (works on Darwin). + + +If you still don't get any output, the regexp might be wrong. + + + +On Archlinux: +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- +lo: flags=73 mtu 16436 metric 1 + inet 127.0.0.1 netmask 255.0.0.0 + inet6 ::1 prefixlen 128 scopeid 0x10 + loop txqueuelen 0 (Local Loopback) + RX packets 300081 bytes 49637437 (47.3 MiB) + RX errors 0 dropped 0 overruns 0 frame 0 + TX packets 300081 bytes 49637437 (47.3 MiB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + +wlan0: flags=4163 mtu 1500 metric 1 + inet 192.168.1.38 netmask 255.255.255.0 broadcast 192.168.1.255 + inet6 fe80::ba8d:12ff:fe15:fdfa prefixlen 64 scopeid 0x20 + ether b8:8d:12:15:fd:fa txqueuelen 1000 (Ethernet) + RX packets 421381 bytes 442228597 (421.7 MiB) + RX errors 0 dropped 0 overruns 0 frame 0 + TX packets 319266 bytes 41111233 (39.2 MiB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- + +On Debian Linux: +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- +eth0 Link encap:Ethernet HWaddr 00:16:17:55:2d:00 + inet addr:172.16.5.2 Bcast:172.16.255.255 Mask:255.255.0.0 + inet6 addr: fe80::216:17ff:fe55:2d00/64 Scope:Link + UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 + RX packets:2854022168 errors:5 dropped:0 overruns:0 frame:4 + TX packets:2200088072 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:1000 + RX bytes:2708386800354 (2.4 TiB) TX bytes:531552070314 (495.0 GiB) + Base address:0x3000 Memory:d0120000-d0140000 + +eth0:1 Link encap:Ethernet HWaddr 00:16:17:55:2d:00 + inet addr:172.16.5.1 Bcast:172.16.255.255 Mask:255.255.0.0 + UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 + Base address:0x3000 Memory:d0120000-d0140000 + +lo Link encap:Local Loopback + inet addr:127.0.0.1 Mask:255.0.0.0 + inet6 addr: ::1/128 Scope:Host + UP LOOPBACK RUNNING MTU:16436 Metric:1 + RX packets:36487087 errors:0 dropped:0 overruns:0 frame:0 + TX packets:36487087 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:0 + RX bytes:3388870184 (3.1 GiB) TX bytes:3388870184 (3.1 GiB) + +sit0 Link encap:IPv6-in-IPv4 + NOARP MTU:1480 Metric:1 + RX packets:0 errors:0 dropped:0 overruns:0 frame:0 + TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:0 + RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) + +tap0 Link encap:Ethernet HWaddr 16:db:17:fb:a1:4a + inet addr:10.254.0.1 Bcast:10.254.255.255 Mask:255.255.0.0 + inet6 addr: fe80::14db:17ff:fefb:a14a/64 Scope:Link + UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 + RX packets:0 errors:0 dropped:0 overruns:0 frame:0 + TX packets:6 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:100 + RX bytes:0 (0.0 B) TX bytes:468 (468.0 B) + +bond0 Link encap:Ethernet HWaddr 00:13:72:3c:bf:57 + inet6 addr: fe80::213:72ff:fe3c:bf57/64 Scope:Link + UP BROADCAST RUNNING MASTER MULTICAST MTU:1500 Metric:1 + RX packets:6930494799 errors:0 dropped:38584515 overruns:0 frame:17 + TX packets:1678579772 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:0 + RX bytes:10006832472618 (9.1 TiB) TX bytes:168031719693 (156.4 GiB) + +bond0.123 Link encap:Ethernet HWaddr 00:13:72:3c:bf:57 + inet addr:10.73.38.250 Bcast:10.73.38.255 Mask:255.255.255.0 + inet6 addr: fe80::213:72ff:fe3c:bf57/64 Scope:Link + UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 + RX packets:12382478 errors:0 dropped:5777 overruns:0 frame:0 + TX packets:564 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:0 + RX bytes:586071334 (558.9 MiB) TX bytes:64180 (62.6 KiB) + +tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:172.31.255.9 P-t-P:172.31.255.10 Mask:255.255.255.255 + UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1 + RX packets:9655 errors:0 dropped:0 overruns:0 frame:0 + TX packets:15118 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:100 + RX bytes:1760236 (1.6 MiB) TX bytes:14929984 (14.2 MiB) +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- + +On OpenBSD: +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- +lo0: flags=8049 mtu 33160 + priority: 0 + groups: lo + inet6 ::1 prefixlen 128 + inet6 fe80::1%lo0 prefixlen 64 scopeid 0x3 + inet 127.0.0.1 netmask 0xff000000 +em0: flags=8843 mtu 1500 + lladdr 00:50:56:b3:00:15 + priority: 0 + groups: egress + media: Ethernet autoselect (1000baseT full-duplex,master) + status: active + inet6 XXXX::XXX:XXXX:XXXX:XX%em0 prefixlen 64 scopeid 0x1 + inet6 XXXX:XXX:XXX:XX::XXX prefixlen 64 + inet XXX.XXX.XXX.XXX netmask 0xffffffc0 broadcast XXX.XXX.XXX.XXX +enc0: flags=0<> + priority: 0 + groups: enc + status: active +pflog0: flags=141 mtu 33160 + priority: 0 + groups: pflog +tun1: flags=8051 mtu 1500 + priority: 0 + groups: tun + status: active + inet 172.31.255.13 --> 172.31.255.14 netmask 0xffffffff +tun2: flags=8011 mtu 1500 + priority: 0 + groups: tun + status: down + inet 172.31.253.1 --> 172.31.253.2 netmask 0xffffffff +tun0: flags=8051 mtu 1500 + priority: 0 + groups: tun + status: active + inet 172.31.254.1 --> 172.31.254.2 netmask 0xffffffff +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- + +On Darwin: +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- +lo0: flags=8049 mtu 16384 + inet6 ::1 prefixlen 128 + inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 + inet 127.0.0.1 netmask 0xff000000 +gif0: flags=8010 mtu 1280 +stf0: flags=0<> mtu 1280 +en0: flags=8863 mtu 1500 + ether 34:15:9e:2e:8b:aa + inet6 fe80::3615:9eff:fe2e:8baa%en0 prefixlen 64 scopeid 0x4 + inet 192.168.1.102 netmask 0xffffff00 broadcast 192.168.1.255 + media: autoselect (100baseTX ) + status: active +en1: flags=8863 mtu 1500 + ether 7c:6d:62:a3:6f:57 + inet6 fe80::7e6d:62ff:fea3:6f57%en1 prefixlen 64 scopeid 0x5 + inet 192.168.2.105 netmask 0xffffff00 broadcast 192.168.2.255 + media: autoselect + status: active +fw0: flags=8863 mtu 4078 + lladdr 34:15:9e:ff:fe:2e:8b:aa + media: autoselect + status: inactive +tun0: flags=8851 mtu 1500 + inet 172.31.255.29 --> 172.31.255.30 netmask 0xffffffff + open (pid 24727) +tun1: flags=8851 mtu 1500 + inet 172.31.254.25 --> 172.31.254.26 netmask 0xffffffff + open (pid 24757) +--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- From d7f180c99fd4540ef8cd924af5f7bc526e55fb72 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 30 May 2012 18:34:14 +0200 Subject: [PATCH 1544/4212] rename ifaces => interfaces (more explicit) Signed-off-by: Nico Schottelius --- conf/explorer/{ifaces => interfaces} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename conf/explorer/{ifaces => interfaces} (100%) diff --git a/conf/explorer/ifaces b/conf/explorer/interfaces similarity index 100% rename from conf/explorer/ifaces rename to conf/explorer/interfaces From 9291fd743660d9fc89ddf5cf23105a15ab26879a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 30 May 2012 18:34:47 +0200 Subject: [PATCH 1545/4212] ++changes(2.0.12) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index c3ececa4..4da583f7 100644 --- a/doc/changelog +++ b/doc/changelog @@ -6,6 +6,7 @@ Changelog 2.0.13: * Bugfix __addifnosuchline: Fixed quotes/interpolation bug ("a b" became "a b") + * New Explorer: interfaces (Sébastien Gross) 2.0.12: 2012-05-29 * Core: Correctly raise error on Python < 3.2 (Steven Armtrong) From 4b1c604e47a958627ad59b35b3b1cdcbc2b149b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Gross?= Date: Thu, 31 May 2012 00:23:28 +0200 Subject: [PATCH 1546/4212] Fix type authors for manpage generation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Gross --- conf/type/__cdistmarker/man.text | 2 +- conf/type/__ssh_authorized_key/man.text | 2 +- conf/type/__timezone/man.text | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/conf/type/__cdistmarker/man.text b/conf/type/__cdistmarker/man.text index 360598d8..1e9079f5 100644 --- a/conf/type/__cdistmarker/man.text +++ b/conf/type/__cdistmarker/man.text @@ -1,6 +1,6 @@ cdist-type__cdistmarker(7) ========================== -Daniel Maher +Daniel Maher NAME diff --git a/conf/type/__ssh_authorized_key/man.text b/conf/type/__ssh_authorized_key/man.text index af0c2017..b372b354 100644 --- a/conf/type/__ssh_authorized_key/man.text +++ b/conf/type/__ssh_authorized_key/man.text @@ -1,6 +1,6 @@ cdist-type__ssh_authorized_key(7) ================================= -Aurélien Bondis - aurelien.bondis AT gmail DOT com +Aurélien Bondis NAME diff --git a/conf/type/__timezone/man.text b/conf/type/__timezone/man.text index 89136855..6f0c5101 100644 --- a/conf/type/__timezone/man.text +++ b/conf/type/__timezone/man.text @@ -1,6 +1,6 @@ cdist-type__timezone(7) ======================= -Ramon Salvadó - rsalvado at gnuine dot com +Ramon Salvadó NAME From fc6a54b3bd1cdcd140cea87be3e05a27805f88a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Gross?= Date: Thu, 31 May 2012 00:28:32 +0200 Subject: [PATCH 1547/4212] Fix email address. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Gross --- conf/type/__cdistmarker/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__cdistmarker/man.text b/conf/type/__cdistmarker/man.text index 1e9079f5..ca5611a7 100644 --- a/conf/type/__cdistmarker/man.text +++ b/conf/type/__cdistmarker/man.text @@ -1,6 +1,6 @@ cdist-type__cdistmarker(7) ========================== -Daniel Maher +Daniel Maher NAME From 8564785f664d208e42ae6a6b633aac6013df32a9 Mon Sep 17 00:00:00 2001 From: contradict Date: Wed, 30 May 2012 17:21:19 -0700 Subject: [PATCH 1548/4212] Ensure __ssh_authorized_key sets proper group When --dstuser is specified, use an explorer to retrieve the group name and specify the group name on all created directories and files. --- .../__ssh_authorized_key/explorer/dstuser_group | 15 +++++++++++++++ conf/type/__ssh_authorized_key/manifest | 16 ++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 conf/type/__ssh_authorized_key/explorer/dstuser_group diff --git a/conf/type/__ssh_authorized_key/explorer/dstuser_group b/conf/type/__ssh_authorized_key/explorer/dstuser_group new file mode 100644 index 00000000..c79f8d9f --- /dev/null +++ b/conf/type/__ssh_authorized_key/explorer/dstuser_group @@ -0,0 +1,15 @@ +#!/bin/sh + +# Get option dstuser if defined +if [ -f "$__object/parameter/dstuser" ]; then + dstuser=`cat "$__object/parameter/dstuser"` +else + dstuser="root" +fi + +if id $dstuser >/dev/null 2>&1 ; then + id -ng $dstuser +else + echo "$__object_id: Destination user $dstuser does not exist" >&2 + exit 1 +fi diff --git a/conf/type/__ssh_authorized_key/manifest b/conf/type/__ssh_authorized_key/manifest index efadc3f6..d9db9c78 100755 --- a/conf/type/__ssh_authorized_key/manifest +++ b/conf/type/__ssh_authorized_key/manifest @@ -29,8 +29,13 @@ fi # Get option dstuser if defined if [ -f "$__object/parameter/dstuser" ]; then dstuser=`cat "$__object/parameter/dstuser"` +else + dstuser="root" fi +# retrieve destination group +dstgroup=$(cat "$__object/explorer/dstuser_group") + # if a source user is defined, use it's public key if [ "$srcuser" ]; then srcrsa="/home/${srcuser}/.ssh/id_rsa.pub" @@ -46,9 +51,16 @@ else sshpath="/root/.ssh" fi rsa=`cat $srcrsa` -__directory $sshpath +__directory $sshpath \ + --owner $dstuser \ + --group $dstgroup \ + --mode 700 # the file authorized_keys depends on the .ssh folder -require="__directory${sshpath}" __file "$sshpath/authorized_keys" --mode 640 +require="__directory${sshpath}" \ + __file "$sshpath/authorized_keys" \ + --mode 640 \ + --owner $dstuser \ + --group $dstgroup # the line added depends on authorized_keys existence require="__file${sshpath}/authorized_keys" __addifnosuchline sshkey --file \ "$sshpath/authorized_keys" --line "$rsa" From 5ad0805fa941958569a9ccdd9c94f0472a54e846 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 31 May 2012 19:25:17 +0200 Subject: [PATCH 1549/4212] ++changes(2.0.13) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 4da583f7..bbf4d5a1 100644 --- a/doc/changelog +++ b/doc/changelog @@ -5,6 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius 2.0.13: + * Bugfix __ssh_authorized_key: Ensure it sets proper group (contradict) * Bugfix __addifnosuchline: Fixed quotes/interpolation bug ("a b" became "a b") * New Explorer: interfaces (Sébastien Gross) From f087057c9812655fb0d7faabff5008dda7314a4e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 31 May 2012 19:30:51 +0200 Subject: [PATCH 1550/4212] use iproute2's ip, if available Signed-off-by: Nico Schottelius --- conf/explorer/interfaces | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/conf/explorer/interfaces b/conf/explorer/interfaces index 64ab8aa7..76ff32bb 100755 --- a/conf/explorer/interfaces +++ b/conf/explorer/interfaces @@ -23,8 +23,13 @@ # If your OS is not supported please provide a ifconfig output # -uname_s="$(uname -s)" +# Use ip, if available +if which ip >/dev/null 2>&1; then + ip -o link show | sed -n 's/^[0-9]\+: \(.\+\): <.*/\1/p' + exit 0 +fi +uname_s="$(uname -s)" REGEXP='s/^(.*)(:[[:space:]]*flags=|Link encap).*/\1/p' case "$uname_s" in From 3e502bbe88cfc2b01233348fd989d5f32ca907cb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 31 May 2012 19:37:06 +0200 Subject: [PATCH 1551/4212] note about csh Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-05-31.csh-compatibilty | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 doc/dev/logs/2012-05-31.csh-compatibilty diff --git a/doc/dev/logs/2012-05-31.csh-compatibilty b/doc/dev/logs/2012-05-31.csh-compatibilty new file mode 100644 index 00000000..b653a826 --- /dev/null +++ b/doc/dev/logs/2012-05-31.csh-compatibilty @@ -0,0 +1,10 @@ +If root's shell is csh or other non-sh compatible, we have problems. +See https://github.com/telmich/cdist/issues/54. + +Stuff to try out: + + - "-o SendEnv name" [may break remote exec/copy] + - cat * | /bin/sh -s could also work, needs testing though + +Somebody who is affected should give this a try, especially the 2nd +variant. From 06649d3478fa67220bbc3b24dde478e6e79dc028 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 4 Jun 2012 14:11:34 +0200 Subject: [PATCH 1552/4212] new feature: capture and forward stdin to types Signed-off-by: Steven Armstrong --- lib/cdist/emulator.py | 24 +++++++++ lib/cdist/test/emulator/__init__.py | 52 ++++++++++++++++++- .../emulator/fixtures/conf/explorer/.keep | 0 .../test/emulator/fixtures/conf/type/__file | 1 + .../conf/type/__file_from_stdin/manifest | 4 ++ .../type/__file_from_stdin/parameter/required | 1 + 6 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 lib/cdist/test/emulator/fixtures/conf/explorer/.keep create mode 120000 lib/cdist/test/emulator/fixtures/conf/type/__file create mode 100755 lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/manifest create mode 100644 lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/parameter/required diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 39d8ca40..5bde16b9 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -22,6 +23,7 @@ import argparse import logging import os +import sys import cdist from cdist import core @@ -67,6 +69,7 @@ class Emulator(object): self.commandline() self.setup_object() + self.save_stdin() self.record_requirements() self.record_auto_requirements() self.log.debug("Finished %s %s" % (self.cdist_object.path, self.parameters)) @@ -137,6 +140,27 @@ class Emulator(object): # Record / Append source self.cdist_object.source.append(self.object_source) + chunk_size = 8192 + def _read_stdin(self): + return sys.stdin.buffer.read(self.chunk_size) + def save_stdin(self): + """If something is written to stdin, save it in the object as + $__object/stdin so it can be accessed in manifest and gencode-* + scripts. + """ + if not sys.stdin.isatty(): + try: + # go directly to file instead of using CdistObject's api + # as that does not support streaming + path = os.path.join(self.cdist_object.absolute_path, 'stdin') + with open(path, 'wb') as fd: + chunk = self._read_stdin() + while chunk: + fd.write(chunk) + chunk = self._read_stdin() + except EnvironmentError as e: + raise cdist.Error('Failed to read from stdin: %s' % e) + def record_requirements(self): """record requirements""" diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index 077ea111..ff18fe87 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -21,12 +21,17 @@ import os import shutil +import string +import filecmp +import random import cdist from cdist import test from cdist.exec import local from cdist import emulator from cdist import core +from cdist import config +import cdist.context local_base_path = test.cdist_base_path @@ -114,8 +119,7 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): self.manifest = core.Manifest(self.target_host, self.local) def tearDown(self): - pass - #shutil.rmtree(self.temp_dir) + shutil.rmtree(self.temp_dir) def test_autorequire(self): initial_manifest = os.path.join(self.local.manifest_path, "init") @@ -216,3 +220,47 @@ class ArgumentsTestCase(test.CdistTestCase): 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): + + def setUp(self): + self.orig_environ = os.environ + os.environ = os.environ.copy() + self.target_host = 'localhost' + self.temp_dir = self.mkdtemp() + os.environ['__cdist_out_dir'] = self.temp_dir + local_base_path = fixtures + + self.context = cdist.context.Context( + target_host=self.target_host, + remote_copy='scp -o User=root -q', + remote_exec='ssh -o User=root -q', + base_path=local_base_path, + 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_file_from_stdin(self): + handle, destination = self.mkstemp(dir=self.temp_dir) + os.close(handle) + source_handle, source = self.mkstemp(dir=self.temp_dir) + candidates = string.ascii_letters+string.digits + with os.fdopen(source_handle, 'w') as fd: + for x in range(100): + fd.write(''.join(random.sample(candidates, len(candidates)))) + + handle, initial_manifest = self.mkstemp(dir=self.temp_dir) + with os.fdopen(handle, 'w') as fd: + fd.write('__file_from_stdin %s --source %s\n' % (destination, source)) + self.context.initial_manifest = initial_manifest + self.config.stage_prepare() + + cdist_type = core.CdistType(self.config.local.type_path, '__file') + cdist_object = core.CdistObject(cdist_type, self.config.local.object_path, destination) + # Test weither stdin has been stored correctly + self.assertTrue(filecmp.cmp(source, os.path.join(cdist_object.absolute_path, 'stdin'))) diff --git a/lib/cdist/test/emulator/fixtures/conf/explorer/.keep b/lib/cdist/test/emulator/fixtures/conf/explorer/.keep new file mode 100644 index 00000000..e69de29b diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__file b/lib/cdist/test/emulator/fixtures/conf/type/__file new file mode 120000 index 00000000..c57c4134 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__file @@ -0,0 +1 @@ +../../../../../../../conf/type/__file \ No newline at end of file diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/manifest b/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/manifest new file mode 100755 index 00000000..b4908cbf --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/manifest @@ -0,0 +1,4 @@ +#!/bin/sh + +source="$(cat "$__object/parameter/source")" +cat "$source" | __file "/$__object_id" --source /dev/null diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/parameter/required b/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/parameter/required new file mode 100644 index 00000000..5a18cd2f --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/parameter/required @@ -0,0 +1 @@ +source From 7ae1a2bc524565a3e38d4d2ecb90ef4d7f2af17f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 4 Jun 2012 14:17:42 +0200 Subject: [PATCH 1553/4212] allow __file to read source file from stdin Signed-off-by: Steven Armstrong --- conf/type/__file/gencode-local | 3 +++ conf/type/__file/man.text | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/conf/type/__file/gencode-local b/conf/type/__file/gencode-local index a55cfc2b..b74893fb 100755 --- a/conf/type/__file/gencode-local +++ b/conf/type/__file/gencode-local @@ -30,6 +30,9 @@ exists="$(cat "$__object/explorer/exists")" if [ "$state_should" = "present" ]; then if [ -f "$__object/parameter/source" ]; then source="$(cat "$__object/parameter/source")" + if [ "$source" = "-" ]; then + source="$__object/stdin" + fi if [ -f "$source" ]; then local_cksum="$(cksum < "$source")" diff --git a/conf/type/__file/man.text b/conf/type/__file/man.text index 0215027a..1c61fd51 100644 --- a/conf/type/__file/man.text +++ b/conf/type/__file/man.text @@ -39,6 +39,7 @@ owner:: source:: If supplied, copy this file from the host running cdist to the target. If not supplied, an empty file or directory will be created. + If source is '-' (dash), take what was written to stdin as the file content. EXAMPLES @@ -64,6 +65,12 @@ __file /etc/shadow --source "$__type/files/shadow" \ __file /home/frodo/.bashrc --source "/etc/skel/.bashrc" \ --state exists \ --owner frodo --mode 0600 + +# Take file content from stdin +__file /tmp/whatever --owner root --group root --mode 644 --source - << DONE +Here goes the content for /tmp/whatever +DONE + -------------------------------------------------------------------------------- From 56222d1f856a9770383c9c9dfa99d785a50121c5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 4 Jun 2012 16:14:28 +0200 Subject: [PATCH 1554/4212] document stdin reading Signed-off-by: Nico Schottelius --- doc/man/man7/cdist-type.text | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/doc/man/man7/cdist-type.text b/doc/man/man7/cdist-type.text index 92a2b36d..ed114aff 100644 --- a/doc/man/man7/cdist-type.text +++ b/doc/man/man7/cdist-type.text @@ -111,6 +111,33 @@ 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 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 From 27073fc2f0c3352594c5efdf65c1d5640a222688 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 4 Jun 2012 16:15:36 +0200 Subject: [PATCH 1555/4212] changes(2.0.13) += stdin reading Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index bbf4d5a1..9eff3efa 100644 --- a/doc/changelog +++ b/doc/changelog @@ -8,6 +8,8 @@ Changelog * Bugfix __ssh_authorized_key: Ensure it sets proper group (contradict) * Bugfix __addifnosuchline: Fixed quotes/interpolation bug ("a b" became "a b") * New Explorer: interfaces (Sébastien Gross) + * Feature core: Support reading from stdin in types (Steven Armstrong) + * Feature __file: Support reading from stdin with - syntax (Steven Armstrong) 2.0.12: 2012-05-29 * Core: Correctly raise error on Python < 3.2 (Steven Armtrong) From 36513997d9aba2b39dde1b448a127b25e73c4444 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 4 Jun 2012 22:01:32 +0200 Subject: [PATCH 1556/4212] =?UTF-8?q?implement=20multiple=20parameters=20b?= =?UTF-8?q?ased=20on=20https://github.com/telmich/cdist/pull/71=20by=20S?= =?UTF-8?q?=C3=A9bastien=20Gross?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Steven Armstrong --- doc/man/man7/cdist-type.text | 19 ++++++++++++++++--- lib/cdist/core/cdist_type.py | 34 ++++++++++++++++++++++++++++++++++ lib/cdist/emulator.py | 12 +++++++++--- lib/cdist/util/fsproperty.py | 6 +++++- 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/doc/man/man7/cdist-type.text b/doc/man/man7/cdist-type.text index 92a2b36d..725c583e 100644 --- a/doc/man/man7/cdist-type.text +++ b/doc/man/man7/cdist-type.text @@ -74,14 +74,19 @@ DEFINING PARAMETERS ------------------- Every type consists of required, optional and boolean parameters, which must be created in a newline seperated file in ***parameter/required***, -***parameter/optional*** and ***parameter/boolean***. If either is missing, -the type will have no required, no optional, no boolean or no parameters at -all. +***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. +If either is missing, the type will have no required, no optional, no boolean +or no parameters at all. Example: -------------------------------------------------------------------------------- echo servername >> conf/type/__nginx_vhost/parameter/required echo logdirectory >> conf/type/__nginx_vhost/parameter/optional +echo server_alias >> conf/type/__nginx_vhost/parameter/optional_multiple echo use_ssl >> conf/type/__nginx_vhost/parameter/boolean -------------------------------------------------------------------------------- @@ -108,6 +113,14 @@ 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 + -------------------------------------------------------------------------------- diff --git a/lib/cdist/core/cdist_type.py b/lib/cdist/core/cdist_type.py index 1d2472c4..86f3ced1 100644 --- a/lib/cdist/core/cdist_type.py +++ b/lib/cdist/core/cdist_type.py @@ -81,7 +81,9 @@ class CdistType(object): self.__explorers = None self.__required_parameters = None + self.__required_multiple_parameters = None self.__optional_parameters = None + self.__optional_multiple_parameters = None self.__boolean_parameters = None def __repr__(self): @@ -130,6 +132,22 @@ class CdistType(object): self.__required_parameters = parameters return self.__required_parameters + @property + def required_multiple_parameters(self): + """Return a list of required multiple parameters""" + if not self.__required_multiple_parameters: + parameters = [] + try: + with open(os.path.join(self.absolute_path, "parameter", "required_multiple")) as fd: + for line in fd: + parameters.append(line.strip()) + except EnvironmentError: + # error ignored + pass + finally: + self.__required_multiple_parameters = parameters + return self.__required_multiple_parameters + @property def optional_parameters(self): """Return a list of optional parameters""" @@ -146,6 +164,22 @@ class CdistType(object): self.__optional_parameters = parameters return self.__optional_parameters + @property + def optional_multiple_parameters(self): + """Return a list of optional multiple parameters""" + if not self.__optional_multiple_parameters: + parameters = [] + try: + with open(os.path.join(self.absolute_path, "parameter", "optional_multiple")) as fd: + for line in fd: + parameters.append(line.strip()) + except EnvironmentError: + # error ignored + pass + finally: + self.__optional_multiple_parameters = parameters + return self.__optional_multiple_parameters + @property def boolean_parameters(self): """Return a list of boolean parameters""" diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 39d8ca40..95f29a7b 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -89,12 +89,18 @@ class Emulator(object): parser = argparse.ArgumentParser(add_help=False, argument_default=argparse.SUPPRESS) - for parameter in self.cdist_type.optional_parameters: - argument = "--" + parameter - parser.add_argument(argument, dest=parameter, action='store', required=False) for parameter in self.cdist_type.required_parameters: argument = "--" + parameter parser.add_argument(argument, dest=parameter, action='store', required=True) + for parameter in self.cdist_type.required_multiple_parameters: + argument = "--" + parameter + parser.add_argument(argument, dest=parameter, action='append', required=True) + for parameter in self.cdist_type.optional_parameters: + argument = "--" + parameter + parser.add_argument(argument, dest=parameter, action='store', required=False) + for parameter in self.cdist_type.optional_multiple_parameters: + argument = "--" + parameter + parser.add_argument(argument, dest=parameter, action='append', required=False) for parameter in self.cdist_type.boolean_parameters: argument = "--" + parameter parser.add_argument(argument, dest=parameter, action='store_const', const='') diff --git a/lib/cdist/util/fsproperty.py b/lib/cdist/util/fsproperty.py index 55428c4d..5814b2b4 100644 --- a/lib/cdist/util/fsproperty.py +++ b/lib/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: - fd.write(str(value)) + if type(value) == type([]): + for v in value: + fd.write(str(v) + '\n') + else: + fd.write(str(value)) except EnvironmentError as e: raise cdist.Error(str(e)) From 06c87f92477c62b7e0315e1f790596f277dbee72 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 5 Jun 2012 18:28:47 +0200 Subject: [PATCH 1557/4212] changes(2.0.13) += multiple parameter support Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 9eff3efa..0d44af54 100644 --- a/doc/changelog +++ b/doc/changelog @@ -9,6 +9,7 @@ Changelog * Bugfix __addifnosuchline: Fixed quotes/interpolation bug ("a b" became "a b") * New Explorer: interfaces (Sébastien Gross) * Feature core: Support reading from stdin in types (Steven Armstrong) + * Feature core: Support multiple parameters for types (Steven Armstrong) * Feature __file: Support reading from stdin with - syntax (Steven Armstrong) 2.0.12: 2012-05-29 From 365b320e7cf5714a9386fcd6a8a11d36692c2d03 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 5 Jun 2012 18:32:09 +0200 Subject: [PATCH 1558/4212] ++version = 2.0.13 Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- lib/cdist/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/changelog b/doc/changelog index 0d44af54..60b21f90 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.0.13: +2.0.13: 2012-06-05 * Bugfix __ssh_authorized_key: Ensure it sets proper group (contradict) * Bugfix __addifnosuchline: Fixed quotes/interpolation bug ("a b" became "a b") * New Explorer: interfaces (Sébastien Gross) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 38a5f602..02df2f2f 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -29,7 +29,7 @@ try: 'cd "%s" && git describe' % here, stderr=devnull, shell=True).decode('utf-8') except: - VERSION = "2.0.12" + VERSION = "2.0.13" BANNER = """ .. . .x+=:. s From 8fd1053bef2814a79fdeb7ef1aacdbb26034175e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 6 Jun 2012 15:00:11 +0200 Subject: [PATCH 1559/4212] +wikipedia entry Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-06-06.wikipedia | 99 +++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 doc/dev/logs/2012-06-06.wikipedia diff --git a/doc/dev/logs/2012-06-06.wikipedia b/doc/dev/logs/2012-06-06.wikipedia new file mode 100644 index 00000000..696082e7 --- /dev/null +++ b/doc/dev/logs/2012-06-06.wikipedia @@ -0,0 +1,99 @@ +{{Infobox software +|name = cdist +|logo = +|screenshot = +|caption = +|collapsible = +|author = Nico Schottelius, Steven Armstrong +|developer = +|released = 2010 +|latest release version = 2.0.13 +|latest release date = 05-Jun-2012 +|frequently updated = +|programming language = [[Python_(programming_language)|Python]], [[Bourne shell]] +|operating system = [[GNU/Linux]], [[Unix-like]] +|platform = +|size = +|language = +|status = +|genre = [[Configuration management]] +|license = [[GPLv3]]. +|website = http://www.nico.schottelius.org/software/cdist/ +}} + +'''cdist''' is a usable configuration management system. It adheres to the KISS principle and is being used in small up to enterprise grade environments. cdist is an alternative to other configuration management systems like cfengine, bcfg2, chef and puppet. + +Its core is written in [[Python (programming language)|Python]] and the types are +written in [[Bourne Shell]]. Cdist is released under the [[GNU General Public License|GPL]]. +cdist has been a no. 1 topic on Hackernews for some time.cdist on hackernews https://news.ycombinator.com/item?id=3422678 + +cdist is actively being developed in Switzerland by the two main developer Nico Schottelius and Steven Armstrong. + + +==Architecture== + +cdist is being used to configure small to a large number of hosts in a scalable manner. +In cdist the user describes at a central position (the **initial manifest**), +what the target state of a system should be. So called **types** are being used to realise +the appropriate functionality on hosts. + +In comparison to other configuration management software, cdist + +* does not have any requirements on the target host besides SSH and a bourne shell +* operates in push based approach (a server pushes to the clients, clients usually do not poll) +* is highly scalable by design +** If configuring more hosts in parallel than possible on one host is needed, adding more CPUs or more configurations servers to scale out is supported. + + +== Configuration DSL == + +All user configurable parts are contained in manifests or gencode-scripts, which are shell scripts. +The idea behind shell scripts is to give the System Administrators a simple way DSL, that is known to them. +Although the core is written in Python, a user does not need to know any Python at all. + +When using the types in cdist, they are called like normal programs in manifests and can make use of +advanced parameter parsing as well as reading from stdin: + +
+# Provide a default file, but let the user change it
+__file /home/frodo/.bashrc --source "/etc/skel/.bashrc" \
+   --state exists \
+   --owner frodo --mode 0600
+
+# Take file content from stdin
+__file /tmp/whatever --owner root --group root --mode 644 --source - << DONE
+Here goes the content for /tmp/whatever
+DONE
+
+ +Access to paths and files within types is given by environment variables like $__object. + +==Platform support== + +cdist is known to be running on a variety of Unix flavors, but can in theory also run on Windows. This has not been tested though. + + +==Users== + +cdist is being used at various companies in Switzerland (for instance at [[ETH Zurich]]), the USA, Germany and France. +cdist is being watched on github by more than 100 people and has more than 30 forks.Github project page https://github.com/telmich/cdist + + +== See also == +{{Portal|Free software}} +* [[Comparison of open source configuration management software]] + +== References == +{{reflist}} + +== External links == +* [http://www.nico.schottelius.org/software/cdist/ cdist Website] +* [https://github.com/telmich/cdist Github home] +* [http://l.schottelius.org/mailman/listinfo/cdist cdist mailinglist] +* [https://freecode.com/projects/cdist cdist on freencode] + + +[[Category:Configuration management]] +[[Category:Free software programmed in Python]] +[[Category:2010 software]] + From a68efb59afcdb97801348ffcd87d0215bed12859 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 6 Jun 2012 15:18:02 +0200 Subject: [PATCH 1560/4212] add logo with subtitle Signed-off-by: Nico Schottelius --- doc/gfx/cdist-logo-cm.png | Bin 0 -> 2960 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/gfx/cdist-logo-cm.png diff --git a/doc/gfx/cdist-logo-cm.png b/doc/gfx/cdist-logo-cm.png new file mode 100644 index 0000000000000000000000000000000000000000..7d988cdcb8474c1cd21de4b4da614a724a59cf06 GIT binary patch literal 2960 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 fp#P!(h+8;dyP9_*fO%c4{ Date: Thu, 14 Jun 2012 10:41:04 -0400 Subject: [PATCH 1561/4212] bugfix was filling jail_list with $jail_enable --- conf/type/__jail/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index 7ebe26eb..2db3fac0 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -293,7 +293,7 @@ if [ "$onboot" = "true" ]; then # if necessary cat <>/etc/rc.conf else From a772b33abd86893b7570fea8f565e3370a2d1103 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 14 Jun 2012 17:01:59 +0200 Subject: [PATCH 1562/4212] changes(2.0.14)++ Signed-off-by: Nico Schottelius --- doc/changelog | 3 ++ doc/dev/logs/2012-06-06.wikipedia | 89 +++++++++++++++++++++---------- 2 files changed, 65 insertions(+), 27 deletions(-) diff --git a/doc/changelog b/doc/changelog index 60b21f90..45e20a58 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.0.14: + * Bugfix Type: __jail: Use correct variable (Jake Guffey) + 2.0.13: 2012-06-05 * Bugfix __ssh_authorized_key: Ensure it sets proper group (contradict) * Bugfix __addifnosuchline: Fixed quotes/interpolation bug ("a b" became "a b") diff --git a/doc/dev/logs/2012-06-06.wikipedia b/doc/dev/logs/2012-06-06.wikipedia index 696082e7..a9654f1b 100644 --- a/doc/dev/logs/2012-06-06.wikipedia +++ b/doc/dev/logs/2012-06-06.wikipedia @@ -1,3 +1,4 @@ +{{db-spam}} {{Infobox software |name = cdist |logo = @@ -21,35 +22,69 @@ |website = http://www.nico.schottelius.org/software/cdist/ }} -'''cdist''' is a usable configuration management system. It adheres to the KISS principle and is being used in small up to enterprise grade environments. cdist is an alternative to other configuration management systems like cfengine, bcfg2, chef and puppet. +'''cdist''' is a configuration management system, which adheres to the [[KISS_principle]]. It is being used in small up to enterprise grade environments. +cdist is an alternative to other configuration management systems [[CFEngine]], [[Bcfg2]], [[Chef (software)|Chef]] and [[Puppet (software)|Puppet]]. +cdist development started in 2010 at [[ETH Zurich]] and is actively being developed by a lot of [[FOSS]] contributors +and maintained by the two main developers Nico Schottelius and +Steven Armstrong. cdist is being watched on github by more than 100 people and has more than 30 forks.cdist development at https://github.com/telmich/cdist +The major part of the discussion about cdist happens on the mailinglistcdist mailinglist http://l.schottelius.org/mailman/listinfo/cdist +and on the IRC channel #cstar in the [[Freenode]] network. cdist is being used at various companies in Switzerland (for instance at [[ETH Zurich]]), the USA, Germany and France. + Its core is written in [[Python (programming language)|Python]] and the types are written in [[Bourne Shell]]. Cdist is released under the [[GNU General Public License|GPL]]. -cdist has been a no. 1 topic on Hackernews for some time.cdist on hackernews https://news.ycombinator.com/item?id=3422678 - -cdist is actively being developed in Switzerland by the two main developer Nico Schottelius and Steven Armstrong. +cdist has been a no. 1 topic on [[Hacker News]] for some time.cdist on [[Hacker News]] https://news.ycombinator.com/item?id=3422678 -==Architecture== +== Architecture == -cdist is being used to configure small to a large number of hosts in a scalable manner. -In cdist the user describes at a central position (the **initial manifest**), -what the target state of a system should be. So called **types** are being used to realise -the appropriate functionality on hosts. +cdist is split into two components: -In comparison to other configuration management software, cdist +* The core +* The configuration -* does not have any requirements on the target host besides SSH and a bourne shell -* operates in push based approach (a server pushes to the clients, clients usually do not poll) -* is highly scalable by design -** If configuring more hosts in parallel than possible on one host is needed, adding more CPUs or more configurations servers to scale out is supported. +=== Core === +The core of cdist is implemented in Python 3 and provides the executables to configure target hosts. The core operates in a push model: It connects +from the source host '''to''' the target hosts and configures the machines. For communication and file transfer [[SSH]] is being used. +To allow parallel configuration of hosts, the core supports a parallel mode in which it creates a child process for every connection. +This model allows cdist to scale horizontally with the available computing resources: If at a certain limit is reached and the capacity of the +available CPUs has been used, adding another CPU or distributing cdist to multiple hosts allows to configure more hosts in parallel. + +=== Configuration === + +The configuration is written in [[Bourne Shell]] and consists of + +* The initial manifest (which defines which host is assigned which types) +* Global Explorers (to gain information about the target system) +* Types (which provide all functionality and consist of a manifest, type explorers and gencode scripts) + +Although all of these are written in Shell script, the order of execution in the manifests does not matter: cdist employs a idempotent +configuration. + +=== Comparison === + +In comparison to most other configuration management software, cdist does not have any requirements on the target host besides SSH and a bourne shell. +It requires Python 3.2 on the source host, though.Why cdist requires Python 3.2 on the source host - http://www.nico.schottelius.org/blog/cdist-python-3.2-requirement/ +cdist operates in push based approach, in which a server pushes configurations to the client and the clients do not poll for updates. == Configuration DSL == All user configurable parts are contained in manifests or gencode-scripts, which are shell scripts. -The idea behind shell scripts is to give the System Administrators a simple way DSL, that is known to them. -Although the core is written in Python, a user does not need to know any Python at all. +Shell scripts were chosen, because Unix System Administrators are usually profound in reading +and writing shell scripts. + +cdist reads its configuration from the initial manifest ('''conf/manifest/init'''), in which hosts are mapped to +types: + +
+case "$__target_host" in
+    myhostname)
+        __package zsh --state present
+        __addifnosuchline /tmp/cdist-welcome --line "Welcome to cdist"
+    ;;
+esac
+
When using the types in cdist, they are called like normal programs in manifests and can make use of advanced parameter parsing as well as reading from stdin: @@ -66,18 +101,14 @@ Here goes the content for /tmp/whatever DONE +Dependencies are expressed by setting up the '''require''' environment variable: +
+      __directory /tmp/foobar
+      require="__directory//tmp/foobar" __file /tmp/foobar/baz
+
+ Access to paths and files within types is given by environment variables like $__object. -==Platform support== - -cdist is known to be running on a variety of Unix flavors, but can in theory also run on Windows. This has not been tested though. - - -==Users== - -cdist is being used at various companies in Switzerland (for instance at [[ETH Zurich]]), the USA, Germany and France. -cdist is being watched on github by more than 100 people and has more than 30 forks.Github project page https://github.com/telmich/cdist - == See also == {{Portal|Free software}} @@ -90,10 +121,14 @@ cdist is being watched on github by more than 100 people and has more than 30 fo * [http://www.nico.schottelius.org/software/cdist/ cdist Website] * [https://github.com/telmich/cdist Github home] * [http://l.schottelius.org/mailman/listinfo/cdist cdist mailinglist] -* [https://freecode.com/projects/cdist cdist on freencode] +* [https://freecode.com/projects/cdist cdist on freecode] [[Category:Configuration management]] [[Category:Free software programmed in Python]] [[Category:2010 software]] +[[Category:Linux configuration utilities]] +[[Category:Mac OS X]] +[[Category:Linux package management-related software]] +[[Category:Unix package management-related software]] From c8fa79d05350732d29ce23fa665d0c121999d7c4 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Thu, 14 Jun 2012 14:33:21 -0400 Subject: [PATCH 1563/4212] Parameter change Modified jailbase parameter such that it's only required when $state=present --- conf/type/__jail/gencode-local | 22 ++++++++++++++++++---- conf/type/__jail/gencode-remote | 14 +++++++++++++- conf/type/__jail/parameter/optional | 1 + conf/type/__jail/parameter/required | 1 - 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/conf/type/__jail/gencode-local b/conf/type/__jail/gencode-local index 6292d943..075a6ef1 100755 --- a/conf/type/__jail/gencode-local +++ b/conf/type/__jail/gencode-local @@ -28,12 +28,26 @@ else jaildir="/usr/jail" fi -jailbase="$(cat "$__object/parameter/jailbase")" +if [ -f "$__object/parameter/jailbase" ]; then + jailbase="$(cat "$__object/parameter/jailbase")" +else + jailbase="" +fi + +state="$(cat "$__object/parameter/state")" + +if [ "$state" = "present" ] && [ -z "$jailbase" ]; then + exec >&2 + echo "jailbase is a REQUIRED parameter when state=present!" + exit 1 +fi remotebase="${jaildir}/jailbase.tgz" basepresent="$(cat "$__object/explorer/basepresent")" -if [ "$basepresent" = "NONE" ]; then - echo "$__remote_copy" "${jailbase}" "$__target_host:${remotebase}" -fi +if [ "$state" = "present" ]; then + if [ "$basepresent" = "NONE" ]; then + echo "$__remote_copy" "${jailbase}" "$__target_host:${remotebase}" + fi # basepresent=NONE +fi # state=present diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index 2db3fac0..d26e02ac 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -177,6 +177,7 @@ cat < --- conf/type/__start_on_boot/gencode-remote | 4 ++-- conf/type/__start_on_boot/manifest | 24 ------------------------ 2 files changed, 2 insertions(+), 26 deletions(-) delete mode 100755 conf/type/__start_on_boot/manifest diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index 78a82de3..7bb69ff5 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -19,10 +19,10 @@ # # -state_should="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo present)" state_is=$(cat "$__object/explorer/state") -# Nothing todo, go away +# Short circuit if nothing is to be done [ "$state_should" = "$state_is" ] && exit 0 os=$(cat "$__global/explorer/os") diff --git a/conf/type/__start_on_boot/manifest b/conf/type/__start_on_boot/manifest deleted file mode 100755 index 6b5e1ca7..00000000 --- a/conf/type/__start_on_boot/manifest +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# 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 . -# - -# set default: present, if not setup -statefile="$__object/parameter/state" -[ -f "$statefile" ] || echo present > "$statefile" From 99b544c6e497c2a39ea2668a17c42959b8755367 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 15 Jun 2012 10:04:18 +0200 Subject: [PATCH 1567/4212] ++changes(2.0.14) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 9f93457a..e5384624 100644 --- a/doc/changelog +++ b/doc/changelog @@ -7,6 +7,7 @@ Changelog 2.0.14: * Bugfix Type: __jail: Use correct variable (Jake Guffey) * Change Type: __jail: Parameter jailbase now optional (Jake Guffey) + * Bugfix Type: __start_on_boot: Do not change parameters 2.0.13: 2012-06-05 * Bugfix __ssh_authorized_key: Ensure it sets proper group (contradict) From a3981f58fd04f4289046ee42b8125bab3d622cfe Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 15 Jun 2012 10:23:19 +0200 Subject: [PATCH 1568/4212] Initial support for SuSE, including zypper, including __start_on_boot Signed-off-by: Nico Schottelius --- conf/type/__package/manifest | 1 + conf/type/__package_yum/explorer/pkg_version | 4 +- .../__package_zypper/explorer/pkg_version | 30 +++++++++++ conf/type/__package_zypper/gencode-remote | 52 +++++++++++++++++++ conf/type/__package_zypper/man.text | 52 +++++++++++++++++++ conf/type/__package_zypper/parameter/optional | 1 + conf/type/__package_zypper/parameter/required | 1 + conf/type/__start_on_boot/explorer/state | 2 +- conf/type/__start_on_boot/gencode-remote | 4 +- 9 files changed, 142 insertions(+), 5 deletions(-) create mode 100755 conf/type/__package_zypper/explorer/pkg_version create mode 100755 conf/type/__package_zypper/gencode-remote create mode 100644 conf/type/__package_zypper/man.text create mode 100644 conf/type/__package_zypper/parameter/optional create mode 100644 conf/type/__package_zypper/parameter/required diff --git a/conf/type/__package/manifest b/conf/type/__package/manifest index 118525b1..6a84cb7f 100755 --- a/conf/type/__package/manifest +++ b/conf/type/__package/manifest @@ -35,6 +35,7 @@ else debian|ubuntu) type="apt" ;; freebsd) type="pkg_freebsd" ;; gentoo) type="emerge" ;; + suse) type="zypper" ;; openwrt) type="opkg" ;; *) echo "Don't know how to manage packages on: $os" >&2 diff --git a/conf/type/__package_yum/explorer/pkg_version b/conf/type/__package_yum/explorer/pkg_version index 0e078f68..fb3b7753 100755 --- a/conf/type/__package_yum/explorer/pkg_version +++ b/conf/type/__package_yum/explorer/pkg_version @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,7 +18,7 @@ # along with cdist. If not, see . # # -# Retrieve the status of a package - parsed dpkg output +# Retrieve the status of a package # if [ -f "$__object/parameter/name" ]; then diff --git a/conf/type/__package_zypper/explorer/pkg_version b/conf/type/__package_zypper/explorer/pkg_version new file mode 100755 index 00000000..fb3b7753 --- /dev/null +++ b/conf/type/__package_zypper/explorer/pkg_version @@ -0,0 +1,30 @@ +#!/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 status of a package +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +rpm -q --whatprovides "$name" 2>/dev/null || true diff --git a/conf/type/__package_zypper/gencode-remote b/conf/type/__package_zypper/gencode-remote new file mode 100755 index 00000000..3323d6b1 --- /dev/null +++ b/conf/type/__package_zypper/gencode-remote @@ -0,0 +1,52 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Manage packages with Zypper (mostly suse) +# + +# Debug +# exec >&2 +# set -x + +globalopts="--quiet --non-interactive" + +if [ -f "$__object/parameter/name" ]; then + name="$__object/parameter/name" +else + name="$__object_id" +fi + +state_should="$(cat "$__object/parameter/state")" + +# 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\" + ;; + absent) + echo pacman "$globalopts" remove \"$name\" + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/conf/type/__package_zypper/man.text b/conf/type/__package_zypper/man.text new file mode 100644 index 00000000..9cff9706 --- /dev/null +++ b/conf/type/__package_zypper/man.text @@ -0,0 +1,52 @@ +cdist-type__package_zypper(7) +============================= +Nico Schottelius + + +NAME +---- +cdist-type__package_zypper - Manage packages with zypper + + +DESCRIPTION +----------- +Zypper is usually used on the SuSE distribution to manage packages. + + +REQUIRED PARAMETERS +------------------- +state:: + The state the package should be in, either "present" or "absent" + + +OPTIONAL PARAMETERS +------------------- +name:: + If supplied, use the name and not the object id as the package name. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure zsh in 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 + +# Remove package +__package_zypper cfengine --state absent +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__package(7) + + +COPYING +------- +Copyright \(C) 2012 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__package_zypper/parameter/optional b/conf/type/__package_zypper/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/conf/type/__package_zypper/parameter/optional @@ -0,0 +1 @@ +name diff --git a/conf/type/__package_zypper/parameter/required b/conf/type/__package_zypper/parameter/required new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/conf/type/__package_zypper/parameter/required @@ -0,0 +1 @@ +state diff --git a/conf/type/__start_on_boot/explorer/state b/conf/type/__start_on_boot/explorer/state index bf24738a..6fd0ea92 100755 --- a/conf/type/__start_on_boot/explorer/state +++ b/conf/type/__start_on_boot/explorer/state @@ -49,7 +49,7 @@ case "$os" in [ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent" ;; - amazon|centos|fedora|owl|redhat) + amazon|centos|fedora|owl|redhat|suse) state=$(chkconfig --level "$runlevel" "$name" || echo absent) [ "$state" ] || state="present" ;; diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote index 7bb69ff5..7724e8c7 100755 --- a/conf/type/__start_on_boot/gencode-remote +++ b/conf/type/__start_on_boot/gencode-remote @@ -44,7 +44,7 @@ case "$state_should" in # echo rc-update add \"$name\" default # ;; - amazon|centos|fedora|owl|redhat) + amazon|centos|fedora|owl|redhat|suse) echo chkconfig \"$name\" on ;; @@ -79,7 +79,7 @@ case "$state_should" in # echo rc-update del \"$name\" # ;; - centos|fedora|owl|redhat) + centos|fedora|owl|redhat|suse) echo chkconfig \"$name\" off ;; From bd451a2e591319cba1730d89eeece9642c3726d5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 15 Jun 2012 13:31:59 +0200 Subject: [PATCH 1569/4212] remove obsolete submission Signed-off-by: Nico Schottelius --- .../__package_zypper/README.inclusion | 5 -- .../__package_zypper/explorer/pkg_version | 30 ----------- .../__package_zypper/gencode-remote | 51 ------------------ .../__package_zypper/man.text | 52 ------------------- .../__package_zypper/parameter/optional | 1 - .../__package_zypper/parameter/required | 1 - 6 files changed, 140 deletions(-) delete mode 100644 other/types_submitted_for_inclusion/__package_zypper/README.inclusion delete mode 100755 other/types_submitted_for_inclusion/__package_zypper/explorer/pkg_version delete mode 100755 other/types_submitted_for_inclusion/__package_zypper/gencode-remote delete mode 100644 other/types_submitted_for_inclusion/__package_zypper/man.text delete mode 100644 other/types_submitted_for_inclusion/__package_zypper/parameter/optional delete mode 100644 other/types_submitted_for_inclusion/__package_zypper/parameter/required diff --git a/other/types_submitted_for_inclusion/__package_zypper/README.inclusion b/other/types_submitted_for_inclusion/__package_zypper/README.inclusion deleted file mode 100644 index 1e073e3f..00000000 --- a/other/types_submitted_for_inclusion/__package_zypper/README.inclusion +++ /dev/null @@ -1,5 +0,0 @@ -This type was not accepted, because cleanups are needed and the -manpage does not build. - -If you read this and want this code available in the cdist core, -just fix it and submit a git url :-) diff --git a/other/types_submitted_for_inclusion/__package_zypper/explorer/pkg_version b/other/types_submitted_for_inclusion/__package_zypper/explorer/pkg_version deleted file mode 100755 index 0e078f68..00000000 --- a/other/types_submitted_for_inclusion/__package_zypper/explorer/pkg_version +++ /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 . -# -# -# Retrieve the status of a package - parsed dpkg output -# - -if [ -f "$__object/parameter/name" ]; then - name="$(cat "$__object/parameter/name")" -else - name="$__object_id" -fi - -rpm -q --whatprovides "$name" 2>/dev/null || true diff --git a/other/types_submitted_for_inclusion/__package_zypper/gencode-remote b/other/types_submitted_for_inclusion/__package_zypper/gencode-remote deleted file mode 100755 index 2d1112d3..00000000 --- a/other/types_submitted_for_inclusion/__package_zypper/gencode-remote +++ /dev/null @@ -1,51 +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 . -# -# -# Manage packages with yum (mostly Fedora) -# - -if [ -f "$__object/parameter/name" ]; then - name="$__object/parameter/name" -else - name="$__object_id" -fi - -state="$(cat "$__object/parameter/state")" - -opts="-n -q" - -not_installed="^no package provides" - -case "$state" in - installed) - if grep -q "$not_installed" "$__object/explorer/pkg_version"; then - echo zypper $opts install \"$name\" - fi - ;; - removed) - if ! grep -q "$not_installed" "$__object/explorer/pkg_version"; then - echo zypper $opts remove \"$name\" - fi - ;; - *) - echo "Unknown state: $state" >&2 - exit 1 - ;; -esac diff --git a/other/types_submitted_for_inclusion/__package_zypper/man.text b/other/types_submitted_for_inclusion/__package_zypper/man.text deleted file mode 100644 index 3a4f1026..00000000 --- a/other/types_submitted_for_inclusion/__package_zypper/man.text +++ /dev/null @@ -1,52 +0,0 @@ -cdist-type__package_zypper(7) -========================== -Franky Van Liedekerke - - -NAME ----- -cdist-type__package_zypper - Manage packages with zypper - - -DESCRIPTION ------------ -zypper is usually used on the Suse distribution to manage packages. - - -REQUIRED PARAMETERS -------------------- -state:: - Either "installed" or "removed". - - -OPTIONAL PARAMETERS -------------------- -name:: - If supplied, use the name and not the object id as the package name. - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Ensure zsh in installed -__package_zypper zsh --state installed - -# If you don't want to follow pythonX packages, but always use python -__package_zypper python --state installed --name python2 - -# Remove obsolete package -__package_zypper puppet --state removed --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- cdist-type__package(7) - - -COPYING -------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/other/types_submitted_for_inclusion/__package_zypper/parameter/optional b/other/types_submitted_for_inclusion/__package_zypper/parameter/optional deleted file mode 100644 index f121bdbf..00000000 --- a/other/types_submitted_for_inclusion/__package_zypper/parameter/optional +++ /dev/null @@ -1 +0,0 @@ -name diff --git a/other/types_submitted_for_inclusion/__package_zypper/parameter/required b/other/types_submitted_for_inclusion/__package_zypper/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/other/types_submitted_for_inclusion/__package_zypper/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state From f23e869277477973cac902b100ab74739e2fcb35 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 15 Jun 2012 13:32:12 +0200 Subject: [PATCH 1570/4212] ++changes(2.0.14) Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index e5384624..7d2c3efc 100644 --- a/doc/changelog +++ b/doc/changelog @@ -8,6 +8,8 @@ Changelog * Bugfix Type: __jail: Use correct variable (Jake Guffey) * Change Type: __jail: Parameter jailbase now optional (Jake Guffey) * Bugfix Type: __start_on_boot: Do not change parameters + * New Type: __package_zypper + * Feature Types: Initial Support for SuSE Linux 2.0.13: 2012-06-05 * Bugfix __ssh_authorized_key: Ensure it sets proper group (contradict) From 2a20b01a3f9462daeddd23b71c55cb2cf0a07d95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Gross?= Date: Mon, 18 Jun 2012 17:54:19 +0200 Subject: [PATCH 1571/4212] Shorten option for both useradd and usermod. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Signed-off-by: Sébastien Gross --- conf/type/__user/gencode-remote | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/conf/type/__user/gencode-remote b/conf/type/__user/gencode-remote index 8979c56e..bbf373d4 100755 --- a/conf/type/__user/gencode-remote +++ b/conf/type/__user/gencode-remote @@ -24,6 +24,22 @@ name="$__object_id" +# 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. +shorten_property() { + RET= + case "$1" in + comment) RET="-c";; + home) RET="-d";; + gid) RET="-g";; + groups) RET="-G";; + password) RET="-p";; + shell) RET="-s";; + uid) RET="-u";; + esac +} + cd "$__object/parameter" if grep -q "^${name}:" "$__object/explorer/passwd"; then for property in $(ls .); do @@ -67,7 +83,8 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then fi if [ "$new_value" != "$current_value" ]; then - set -- "$@" "--$property" \'$new_value\' + shorten_property $property + set -- "$@" "$RET" \'$new_value\' fi done @@ -79,7 +96,8 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then else for property in $(ls .); do new_value="$(cat "$property")" - set -- "$@" "--$property" \'$new_value\' + shorten_property $property + set -- "$@" "$RET" \'$new_value\' done echo useradd "$@" "$name" From d591b5f2be9b65264ee500fc8af56e17b5675d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Gross?= Date: Tue, 19 Jun 2012 10:29:20 +0200 Subject: [PATCH 1572/4212] Do not use global variable. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Gross --- conf/type/__user/gencode-remote | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/conf/type/__user/gencode-remote b/conf/type/__user/gencode-remote index bbf373d4..5a868b67 100755 --- a/conf/type/__user/gencode-remote +++ b/conf/type/__user/gencode-remote @@ -28,16 +28,17 @@ name="$__object_id" # systems (such as *BSD, Darwin) those commands do not handle GNU style long # options. shorten_property() { - RET= - case "$1" in - comment) RET="-c";; - home) RET="-d";; - gid) RET="-g";; - groups) RET="-G";; - password) RET="-p";; - shell) RET="-s";; - uid) RET="-u";; - esac + local ret="" + case "$1" in + comment) ret="-c";; + home) ret="-d";; + gid) ret="-g";; + groups) ret="-G";; + password) ret="-p";; + shell) ret="-s";; + uid) ret="-u";; + esac + echo "$ret" } cd "$__object/parameter" @@ -83,8 +84,8 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then fi if [ "$new_value" != "$current_value" ]; then - shorten_property $property - set -- "$@" "$RET" \'$new_value\' + local option=$(shorten_property $property) + set -- "$@" "$option" \'$new_value\' fi done @@ -96,8 +97,8 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then else for property in $(ls .); do new_value="$(cat "$property")" - shorten_property $property - set -- "$@" "$RET" \'$new_value\' + local option=$(shorten_property $property) + set -- "$@" "$option" \'$new_value\' done echo useradd "$@" "$name" From 61030f1c18f84df5d068166288ccd5cf4b3a5d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Gross?= Date: Tue, 19 Jun 2012 10:55:50 +0200 Subject: [PATCH 1573/4212] Remove local variables statements. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Gross --- conf/type/__user/gencode-remote | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/conf/type/__user/gencode-remote b/conf/type/__user/gencode-remote index 5a868b67..7e175f60 100755 --- a/conf/type/__user/gencode-remote +++ b/conf/type/__user/gencode-remote @@ -28,7 +28,7 @@ name="$__object_id" # systems (such as *BSD, Darwin) those commands do not handle GNU style long # options. shorten_property() { - local ret="" + unset ret case "$1" in comment) ret="-c";; home) ret="-d";; @@ -84,8 +84,7 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then fi if [ "$new_value" != "$current_value" ]; then - local option=$(shorten_property $property) - set -- "$@" "$option" \'$new_value\' + set -- "$@" "$(shorten_property $property)" \'$new_value\' fi done @@ -97,8 +96,7 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then else for property in $(ls .); do new_value="$(cat "$property")" - local option=$(shorten_property $property) - set -- "$@" "$option" \'$new_value\' + set -- "$@" "$(shorten_property $property)" \'$new_value\' done echo useradd "$@" "$name" From 37eabffd9ccaa4181a7c8d6f375a6ca189fdaa6c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 19 Jun 2012 14:17:50 +0200 Subject: [PATCH 1574/4212] ++changes(2.0.14) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 7d2c3efc..9160a817 100644 --- a/doc/changelog +++ b/doc/changelog @@ -8,6 +8,7 @@ Changelog * Bugfix Type: __jail: Use correct variable (Jake Guffey) * Change Type: __jail: Parameter jailbase now optional (Jake Guffey) * Bugfix Type: __start_on_boot: Do not change parameters + * Feature __user: Added support for BSDs (Sébastien Gross) * New Type: __package_zypper * Feature Types: Initial Support for SuSE Linux From f6bd5290b31da84cd374b00dfc5198167f6ef770 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 20 Jun 2012 17:14:47 -0400 Subject: [PATCH 1575/4212] Add FreeBSD support Modified explorer/gshadow to do nothing on FreeBSD (unsupported command) Modified gencode-remote to use short options (--long not supported in FreeBSD) --- conf/type/__group/explorer/gshadow | 6 +++++ conf/type/__group/gencode-remote | 42 ++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/conf/type/__group/explorer/gshadow b/conf/type/__group/explorer/gshadow index e3c2dd6c..5ab4ed80 100755 --- a/conf/type/__group/explorer/gshadow +++ b/conf/type/__group/explorer/gshadow @@ -23,6 +23,12 @@ name=$__object_id os_version="$($__explorer/os_version)" +os="$($__explorer/os)" + +if [ "$os" = "freebsd" ]; then + echo "FreeBSD does not have getent gshadow" + exit 0 +fi case "$os_version" in "Red Hat Enterprise Linux Server release "[45]*|"CentOS release "[45]*) diff --git a/conf/type/__group/gencode-remote b/conf/type/__group/gencode-remote index 2b4774ab..d2bdb6fb 100755 --- a/conf/type/__group/gencode-remote +++ b/conf/type/__group/gencode-remote @@ -24,6 +24,7 @@ name="$__object_id" os_version="$(cat "$__global/explorer/os_version")" +os="$(cat "$__global/explorer/os")" cd "$__object/parameter" if grep -q "^${name}:" "$__object/explorer/group"; then @@ -36,6 +37,10 @@ if grep -q "^${name}:" "$__object/explorer/group"; then case "$property" in password) current_value="$(awk -F: '{ print $2 }' < "$__object/explorer/gshadow")" + if [ "$os" = "freebsd" ]; then + echo "group/$name: FreeBSD doesn't support password modification" >&2 + exit 1 + fi case "$os_version" in "Red Hat Enterprise Linux Server release "[45]*|"CentOS release "[45]*) # TODO: Use gpasswd? Need to fix gshadow explorer first. @@ -57,15 +62,42 @@ if grep -q "^${name}:" "$__object/explorer/group"; then done if [ $# -gt 0 ]; then - echo groupmod "$@" "$name" - else - true + case $os in + freebsd) + echo pw group mod "$@" "$name" + ;; + *) + echo groupmod "$@" "$name" + ;; + esac fi else for property in $(ls .); do new_value="$(cat "$property")" - set -- "$@" "--$property" \"$new_value\" + if [ "$os" = "freebsd" ]; then + case $property in + gid) + proparg="-g" + ;; + *) + echo "Unknown property: $property" >&2 + exit 1 + ;; + esac + else + proparg="--$property" + fi + + set -- "$@" "$proparg" \"$new_value\" done - echo groupadd "$@" "$name" + case $os in + freebsd) + echo pw group add "$@" "$name" + ;; + *) + echo groupadd "$@" "$name" + ;; + esac fi + From 6264a9b718583626e8fdcb9608afb8da759b0541 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 20 Jun 2012 17:22:19 -0400 Subject: [PATCH 1576/4212] Don't use shadow passwords on FreeBSD shadow database doesn't exist by default in FreeBSD -- use "passwd" database --- conf/type/__user/explorer/shadow | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/conf/type/__user/explorer/shadow b/conf/type/__user/explorer/shadow index c75e36f4..a949ec51 100755 --- a/conf/type/__user/explorer/shadow +++ b/conf/type/__user/explorer/shadow @@ -22,6 +22,13 @@ # name=$__object_id +os="$($__explorer/os)" +# Default to using shadow passwords +database="shadow" -getent shadow "$name" || true +if [ "$os" = "freebsd" ]; then + database="passwd" +fi + +getent "$database" "$name" || true From ba576b3931719b15fa97234d5f5cdca244b9349e Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Thu, 21 Jun 2012 11:59:53 -0400 Subject: [PATCH 1577/4212] Don't symlink multiple times Was checking for existence of $jaildir/home -- never exists; will always create new symlink Changed to look for directory or symlink at $jaildir/base/home and respond accordingly --- conf/type/__jail/gencode-remote | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index 62aa7b60..71bb31b5 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -185,10 +185,12 @@ cat < Date: Fri, 22 Jun 2012 09:30:47 +0200 Subject: [PATCH 1578/4212] ignore errors in global explorers Signed-off-by: Steven Armstrong --- conf/explorer/hostname | 5 ++++- conf/explorer/interfaces | 5 +++++ conf/explorer/machine | 4 +++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/conf/explorer/hostname b/conf/explorer/hostname index a3ae4e15..429a5077 100755 --- a/conf/explorer/hostname +++ b/conf/explorer/hostname @@ -1,6 +1,7 @@ #!/bin/sh # # 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -19,4 +20,6 @@ # # -hostname +if which hostname >/dev/null 2>&1; then + hostname +fi diff --git a/conf/explorer/interfaces b/conf/explorer/interfaces index 76ff32bb..5333b408 100755 --- a/conf/explorer/interfaces +++ b/conf/explorer/interfaces @@ -29,6 +29,11 @@ if which ip >/dev/null 2>&1; then exit 0 fi +if ! which ifconfig >/dev/null 2>&1; then + # no ifconfig, nothing we could do + exit 0 +fi + uname_s="$(uname -s)" REGEXP='s/^(.*)(:[[:space:]]*flags=|Link encap).*/\1/p' diff --git a/conf/explorer/machine b/conf/explorer/machine index 25fc76a9..d295c8e0 100755 --- a/conf/explorer/machine +++ b/conf/explorer/machine @@ -22,4 +22,6 @@ # # -uname -m +if which uname >/dev/null 2>&1; then + uname -m +fi From b09d9786d25c31428f6175e1adaa84d6b9dbb6e6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 22 Jun 2012 15:36:14 +0200 Subject: [PATCH 1579/4212] sync and remove require different options Signed-off-by: Steven Armstrong --- conf/type/__package_pacman/gencode-remote | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/conf/type/__package_pacman/gencode-remote b/conf/type/__package_pacman/gencode-remote index 9defabe8..e585ee86 100755 --- a/conf/type/__package_pacman/gencode-remote +++ b/conf/type/__package_pacman/gencode-remote @@ -25,8 +25,6 @@ # exec >&2 # set -x -pacopts="--needed --noconfirm --noprogressbar" - if [ -f "$__object/parameter/name" ]; then name="$__object/parameter/name" else @@ -57,10 +55,10 @@ fi case "$state_should" in present) - echo pacman "$pacopts" -S \"$name\" + echo pacman --needed --noconfirm --noprogressbar -S \"$name\" ;; absent) - echo pacman "$pacopts" -R \"$name\" + echo pacman --noconfirm --noprogressbar -R \"$name\" ;; *) echo "Unknown state: $state_should" >&2 From 686554358a8f3b5eb64da8a4578d6d57e8fa62c9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 25 Jun 2012 19:12:00 +0200 Subject: [PATCH 1580/4212] ++changes(2.0.14) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 9160a817..a70cdefe 100644 --- a/doc/changelog +++ b/doc/changelog @@ -7,6 +7,7 @@ Changelog 2.0.14: * Bugfix Type: __jail: Use correct variable (Jake Guffey) * Change Type: __jail: Parameter jailbase now optional (Jake Guffey) + * Bugfix Type: __user: Use passwd database on FreeBSD (Jake Guffey) * Bugfix Type: __start_on_boot: Do not change parameters * Feature __user: Added support for BSDs (Sébastien Gross) * New Type: __package_zypper From 946d2b9d43b9336783809c0c28e5b72b0a43c988 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Mon, 25 Jun 2012 13:19:19 -0400 Subject: [PATCH 1581/4212] Change order of checks per telmich's suggestion in https://github.com/telmich/cdist/pull/82/files#r1043875 --- conf/type/__group/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__group/gencode-remote b/conf/type/__group/gencode-remote index d2bdb6fb..f42e8524 100755 --- a/conf/type/__group/gencode-remote +++ b/conf/type/__group/gencode-remote @@ -36,7 +36,6 @@ if grep -q "^${name}:" "$__object/explorer/group"; then case "$property" in password) - current_value="$(awk -F: '{ print $2 }' < "$__object/explorer/gshadow")" if [ "$os" = "freebsd" ]; then echo "group/$name: FreeBSD doesn't support password modification" >&2 exit 1 @@ -48,6 +47,7 @@ if grep -q "^${name}:" "$__object/explorer/group"; then exit 1 ;; esac + current_value="$(awk -F: '{ print $2 }' < "$__object/explorer/gshadow")" ;; gid) # set to -g to support older redhat/centos From fbdbbddf3bfd22808219bf15e94aea38b95c536b Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Mon, 25 Jun 2012 13:29:10 -0400 Subject: [PATCH 1582/4212] Align messages for "password" parameter Use same general message if the "password" parameter is given for a FreeBSD target host whether the group exists yet or not Make language clearer surrounding the default case --- conf/type/__group/gencode-remote | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/conf/type/__group/gencode-remote b/conf/type/__group/gencode-remote index f42e8524..bb6797c2 100755 --- a/conf/type/__group/gencode-remote +++ b/conf/type/__group/gencode-remote @@ -79,8 +79,14 @@ else gid) proparg="-g" ;; + password) + echo "group/$name: FreeBSD doesn't support password setting" >&2 + exit 1 + ;; *) - echo "Unknown property: $property" >&2 + # The type has been updated to support more properties than it knows how to handle for FreeBSD + # tell the user about this. + echo "Currently unknown property: $property" >&2 exit 1 ;; esac From d13a201cd092b5eb078988d53224a8ec52d4152b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 25 Jun 2012 20:19:10 +0200 Subject: [PATCH 1583/4212] /which/command -v/ Signed-off-by: Steven Armstrong --- conf/explorer/hostname | 2 +- conf/explorer/interfaces | 4 ++-- conf/explorer/lsb_codename | 2 +- conf/explorer/lsb_description | 2 +- conf/explorer/lsb_id | 2 +- conf/explorer/lsb_release | 2 +- conf/explorer/machine | 2 +- conf/explorer/runlevel | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/conf/explorer/hostname b/conf/explorer/hostname index 429a5077..2ae23759 100755 --- a/conf/explorer/hostname +++ b/conf/explorer/hostname @@ -20,6 +20,6 @@ # # -if which hostname >/dev/null 2>&1; then +if command -v hostname; then hostname fi diff --git a/conf/explorer/interfaces b/conf/explorer/interfaces index 5333b408..6804f2db 100755 --- a/conf/explorer/interfaces +++ b/conf/explorer/interfaces @@ -24,12 +24,12 @@ # # Use ip, if available -if which ip >/dev/null 2>&1; then +if command -v ip; then ip -o link show | sed -n 's/^[0-9]\+: \(.\+\): <.*/\1/p' exit 0 fi -if ! which ifconfig >/dev/null 2>&1; then +if ! command -v ifconfig; then # no ifconfig, nothing we could do exit 0 fi diff --git a/conf/explorer/lsb_codename b/conf/explorer/lsb_codename index 22b6d51e..eebd3e0f 100755 --- a/conf/explorer/lsb_codename +++ b/conf/explorer/lsb_codename @@ -25,7 +25,7 @@ case "$($__explorer/os)" in (. /etc/openwrt_release && echo "$DISTRIB_CODENAME") ;; *) - lsb_release=$(which lsb_release 2>/dev/null) + lsb_release=$(command -v lsb_release) if [ -x "$lsb_release" ]; then $lsb_release --short --codename fi diff --git a/conf/explorer/lsb_description b/conf/explorer/lsb_description index 48aff30d..23f45421 100755 --- a/conf/explorer/lsb_description +++ b/conf/explorer/lsb_description @@ -25,7 +25,7 @@ case "$($__explorer/os)" in (. /etc/openwrt_release && echo "$DISTRIB_DESCRIPTION") ;; *) - lsb_release=$(which lsb_release 2>/dev/null) + lsb_release=$(command -v lsb_release) if [ -x "$lsb_release" ]; then $lsb_release --short --description fi diff --git a/conf/explorer/lsb_id b/conf/explorer/lsb_id index 0dd0f9f4..9754eb63 100755 --- a/conf/explorer/lsb_id +++ b/conf/explorer/lsb_id @@ -25,7 +25,7 @@ case "$($__explorer/os)" in (. /etc/openwrt_release && echo "$DISTRIB_ID") ;; *) - lsb_release=$(which lsb_release 2>/dev/null) + lsb_release=$(command -v lsb_release) if [ -x "$lsb_release" ]; then $lsb_release --short --id fi diff --git a/conf/explorer/lsb_release b/conf/explorer/lsb_release index 8266171a..35b5547c 100755 --- a/conf/explorer/lsb_release +++ b/conf/explorer/lsb_release @@ -25,7 +25,7 @@ case "$($__explorer/os)" in (. /etc/openwrt_release && echo "$DISTRIB_RELEASE") ;; *) - lsb_release=$(which lsb_release 2>/dev/null) + lsb_release=$(command -v lsb_release) if [ -x "$lsb_release" ]; then $lsb_release --short --release fi diff --git a/conf/explorer/machine b/conf/explorer/machine index d295c8e0..bb6e0beb 100755 --- a/conf/explorer/machine +++ b/conf/explorer/machine @@ -22,6 +22,6 @@ # # -if which uname >/dev/null 2>&1; then +if command -v uname; then uname -m fi diff --git a/conf/explorer/runlevel b/conf/explorer/runlevel index 7cdd81ef..02d3a245 100755 --- a/conf/explorer/runlevel +++ b/conf/explorer/runlevel @@ -20,7 +20,7 @@ # set +e -executable=$(which runlevel 2>/dev/null) +executable=$(command -v runlevel) if [ -x "$executable" ]; then "$executable" | awk '{ print $2 }' fi From 676687dee114a48c1db861c9c84dcc2ae50e2758 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 28 Jun 2012 14:05:44 +0200 Subject: [PATCH 1584/4212] add hint for building from source Signed-off-by: Nico Schottelius --- README | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README b/README index 932375c4..d37569ef 100644 --- a/README +++ b/README @@ -104,6 +104,10 @@ Archlinux already has python >= 3.2, so you only need to do: pacman -S python +#### CentOS + +See the "From source" section + #### Debian For Debian >= wheezy: @@ -167,6 +171,22 @@ You can choose between Homebrew and Macports, either way works: port install python32 ln -s /opt/local/bin/python3.2 /opt/local/bin/python3 +#### From Source + +For those operating systems not yet support Python 3.2: + + pyversion=3.2.3 + wget http://www.python.org/ftp/python/$pyversion/Python-${pyversion}.tar.bz2 + tar xvfj Python-${pyversion}.tar.bz2 + cd Python-${pyversion} + ./configure + make + sudo make install + +This installs python 3.2 to /usr/local/bin. Ensure this directory is in +your PATH environment variable. + + ### Get cdist You can clone cdist from git, which gives you the advantage of having From 590a9e5026c75b8680a94d2202b01c09473868f5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Jul 2012 17:57:12 +0200 Subject: [PATCH 1585/4212] ++changes(2.0.14) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index a70cdefe..589e3100 100644 --- a/doc/changelog +++ b/doc/changelog @@ -10,6 +10,7 @@ Changelog * Bugfix Type: __user: Use passwd database on FreeBSD (Jake Guffey) * Bugfix Type: __start_on_boot: Do not change parameters * Feature __user: Added support for BSDs (Sébastien Gross) + * Feature __group: Added support for FreeBSD (Jake Guffey) * New Type: __package_zypper * Feature Types: Initial Support for SuSE Linux From 1116bcc504bb1ebba99d75e2fa9be1589ecb6480 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Tue, 14 Aug 2012 08:39:33 -0400 Subject: [PATCH 1586/4212] Migrate from useradd/usermod to pw useradd/usermod don't exist in freebsd. --- conf/type/__user/gencode-remote | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/conf/type/__user/gencode-remote b/conf/type/__user/gencode-remote index 7e175f60..baa6f354 100755 --- a/conf/type/__user/gencode-remote +++ b/conf/type/__user/gencode-remote @@ -24,6 +24,8 @@ name="$__object_id" +os="$(cat "$__global/explorer/os")" + # 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. @@ -89,7 +91,11 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then done if [ $# -gt 0 ]; then - echo usermod "$@" "$name" + if [ "$os" = "freebsd" ]; then + echo pw usermod "$@" "$name" + else + echo usermod "$@" "$name" + fi else true fi @@ -99,5 +105,9 @@ else set -- "$@" "$(shorten_property $property)" \'$new_value\' done - echo useradd "$@" "$name" + if [ "$os" = "freebsd" ]; then + echo pw useradd "$@" "$name" + else + echo useradd "$@" "$name" + fi fi From b6bff3a5515c6cf5a0ef4297c28e7cc1d58f2aa7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Sep 2012 14:06:19 +0200 Subject: [PATCH 1587/4212] version bump Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- lib/cdist/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/changelog b/doc/changelog index 589e3100..add17af2 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.0.14: +2.0.14: 2012-09-07 * Bugfix Type: __jail: Use correct variable (Jake Guffey) * Change Type: __jail: Parameter jailbase now optional (Jake Guffey) * Bugfix Type: __user: Use passwd database on FreeBSD (Jake Guffey) diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 02df2f2f..85bc5f77 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -29,7 +29,7 @@ try: 'cd "%s" && git describe' % here, stderr=devnull, shell=True).decode('utf-8') except: - VERSION = "2.0.13" + VERSION = "2.0.14" BANNER = """ .. . .x+=:. s From 0775b84c403d1dc3192a1739537df4436dda8cac Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Sep 2012 14:02:43 +0200 Subject: [PATCH 1588/4212] bugfix: make __object_name available in type explorers Signed-off-by: Steven Armstrong --- lib/cdist/core/explorer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cdist/core/explorer.py b/lib/cdist/core/explorer.py index d49b7ac4..da84cfaa 100644 --- a/lib/cdist/core/explorer.py +++ b/lib/cdist/core/explorer.py @@ -135,6 +135,7 @@ class Explorer(object): env.update({ '__object': os.path.join(self.remote.object_path, cdist_object.path), '__object_id': cdist_object.object_id, + '__object_name': cdist_object.name, '__object_fq': cdist_object.path, '__type_explorer': os.path.join(self.remote.type_path, cdist_type.explorer_path) }) From c88d648520e62afee41782528629a87cf4e854ac Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Sep 2012 14:44:04 +0200 Subject: [PATCH 1589/4212] ++changes(2.0.15) Signed-off-by: Nico Schottelius --- doc/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/changelog b/doc/changelog index add17af2..af693bba 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.0.15: + * Core: Make variable __object_name available in type explorers (Steven Armtrong) + 2.0.14: 2012-09-07 * Bugfix Type: __jail: Use correct variable (Jake Guffey) * Change Type: __jail: Parameter jailbase now optional (Jake Guffey) From 1ad176aa638b4a259981f55b51133d09a9d4d465 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Fri, 7 Sep 2012 10:02:37 -0400 Subject: [PATCH 1590/4212] Fixed use of onboot parameter onboot parameter was being checked against "true" but was being set as "yes/no" --- conf/type/__jail/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/type/__jail/gencode-remote b/conf/type/__jail/gencode-remote index 71bb31b5..4aff6509 100755 --- a/conf/type/__jail/gencode-remote +++ b/conf/type/__jail/gencode-remote @@ -300,8 +300,8 @@ END EOF fi -# Add $name to jail_list if $onboot=true -if [ "$onboot" = "true" ]; then +# Add $name to jail_list if $onboot=yes +if [ "$onboot" = "yes" ]; then # first check to see whether jail_enable="YES" exists in rc.conf or not and add it # if necessary From 16ac158c413f3d91f31f15a6c1137bdb1348e286 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Thu, 13 Sep 2012 17:17:37 -0400 Subject: [PATCH 1591/4212] Add FreeBSD support Added support for FreeBSD's mktemp Fixed typo in generated script with one too many "s --- conf/type/__cron/gencode-remote | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/conf/type/__cron/gencode-remote b/conf/type/__cron/gencode-remote index 947c75ae..37e0dc15 100755 --- a/conf/type/__cron/gencode-remote +++ b/conf/type/__cron/gencode-remote @@ -18,6 +18,7 @@ # along with cdist. If not, see . # +os="$(cat "$__global/explorer/os")" user="$(cat "$__object/parameter/user")" state_should="$(cat "$__object/parameter/state")" state_is=$(diff -q "$__object/parameter/entry" "$__object/explorer/entry" \ @@ -25,14 +26,21 @@ state_is=$(diff -q "$__object/parameter/entry" "$__object/explorer/entry" \ || 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) +tmp=\$($mktemp) crontab -u $user -l > \$tmp cat >> \$tmp << EOC -$(cat "$__object/parameter/entry")" +$(cat "$__object/parameter/entry") EOC crontab -u $user \$tmp rm \$tmp From a2e96ac435cd8fa98fad2edade8d5798fcb8d57f Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 19 Sep 2012 14:50:28 -0400 Subject: [PATCH 1592/4212] Initial commit Broke old __pf type into __pf_* Initial commit of __pf_ruleset type with basic logic --- conf/type/__pf_ruleset/explorer/cksum | 43 +++++++++++++ conf/type/__pf_ruleset/explorer/rcvar | 36 +++++++++++ conf/type/__pf_ruleset/gencode-local | 74 +++++++++++++++++++++++ conf/type/__pf_ruleset/gencode-remote | 41 +++++++++++++ conf/type/__pf_ruleset/man.text | 51 ++++++++++++++++ conf/type/__pf_ruleset/parameter/optional | 1 + conf/type/__pf_ruleset/parameter/required | 1 + conf/type/__pf_ruleset/singleton | 0 8 files changed, 247 insertions(+) create mode 100755 conf/type/__pf_ruleset/explorer/cksum create mode 100755 conf/type/__pf_ruleset/explorer/rcvar create mode 100644 conf/type/__pf_ruleset/gencode-local create mode 100644 conf/type/__pf_ruleset/gencode-remote create mode 100644 conf/type/__pf_ruleset/man.text create mode 100644 conf/type/__pf_ruleset/parameter/optional create mode 100644 conf/type/__pf_ruleset/parameter/required create mode 100644 conf/type/__pf_ruleset/singleton diff --git a/conf/type/__pf_ruleset/explorer/cksum b/conf/type/__pf_ruleset/explorer/cksum new file mode 100755 index 00000000..372e9193 --- /dev/null +++ b/conf/type/__pf_ruleset/explorer/cksum @@ -0,0 +1,43 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Get the 256 bit SHA2 checksum of the pf ruleset on the target host. +# + +# Debug +#exec >&2 +#set -x + +# Check /etc/rc.conf for pf's configuration file name. Default to /etc/pf.conf +# See if file exists and if so, get checksum + +RC="/etc/rc.conf" +TMP="$(grep '^pf_rules=' ${RC} | cut -d= -f2 | sed 's/"//g')" +PFCONF="${TMP:-"/etc/pf.conf"}" + +if [ -f "${PFCONF}" ]; then # The pf config file exists, find its cksum. + cksum -o 1 ${PFCONF} | cut -d= -f2 | sed 's/ //g' +else # the pf config file doesn't exist + echo NOTEXIST +fi + +# Debug +#set +x + diff --git a/conf/type/__pf_ruleset/explorer/rcvar b/conf/type/__pf_ruleset/explorer/rcvar new file mode 100755 index 00000000..20e9dfcc --- /dev/null +++ b/conf/type/__pf_ruleset/explorer/rcvar @@ -0,0 +1,36 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Get the location of the pf ruleset on the target host. +# + +# Debug +#exec >&2 +#set -x + +# Check /etc/rc.conf for pf's configuration file name. Default to /etc/pf.conf + +RC="/etc/rc.conf" +PFCONF="$(grep '^pf_rules=' ${RC} | cut -d= -f2 | sed 's/"//g')" +echo ${PFCONF:-"/etc/pf.conf"} + +# Debug +#set +x + diff --git a/conf/type/__pf_ruleset/gencode-local b/conf/type/__pf_ruleset/gencode-local new file mode 100644 index 00000000..7c2f877e --- /dev/null +++ b/conf/type/__pf_ruleset/gencode-local @@ -0,0 +1,74 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Manage pf(4) on *BSD +# + +# Debug +#exec >&2 +#set -x + +# Send files to $__target_host via $__remote_copy + +uname=$(uname) # Need to know what the cdist host is running so we know how to compute the ruleset's checksum +state=$(cat "$__object/parameter/state") + +if [ "$state" = "absent" ]; then # There is nothing more for a *local* script to do + exit 0 +fi + +if [ -f "$__object/parameter/source" ]; then + source=$(cat "$__object/parameter/source") +fi + +rcvar=$(cat "$__object/explorer/rcvar") +cksum=$(cat "$__object/explorer/cksum") + + +cat <&2 + exit 1 + ;; +esac + +if [ ! "${cksum}" = "NOTEXIST" ]; then + if [ ! "\${currentSum}" = "${cksum}" ]; then + $__remote_copy "${source}" "$__target_host:${rcvar}.new" + fi +else # File just doesn't exist yet + $__remote_copy "${source}" "$__target_host:${rcvar}.new" +fi + +if [ -n "${testscript}" ]; then + $__remote_copy "${testscript}" "$__target_host:${rcvar}.test" +fi +EOF + diff --git a/conf/type/__pf_ruleset/gencode-remote b/conf/type/__pf_ruleset/gencode-remote new file mode 100644 index 00000000..56aee3cb --- /dev/null +++ b/conf/type/__pf_ruleset/gencode-remote @@ -0,0 +1,41 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Manage pf(4) on *BSD +# + +# Debug +#exec >&2 +#set -x + +# Remove ${rcvar} in the case of --state absent + +state=$(cat "$__object/parameter/state") + +if [ ! "$state" = "absent" ]; then # There is nothing more for a *remote* script to do + exit 0 +fi + +rcvar=$(cat "$__object/explorer/rcvar") + +# --state absent, so ensure that .new doesn't exist and that conf is renamed to .old +echo rm \"${rcvar}.new\" +echo mv \"${rcvar}\" \"${rcvar.old}\" + diff --git a/conf/type/__pf_ruleset/man.text b/conf/type/__pf_ruleset/man.text new file mode 100644 index 00000000..68601fad --- /dev/null +++ b/conf/type/__pf_ruleset/man.text @@ -0,0 +1,51 @@ +cdist-type__pf_ruleset(7) +================================== +Jake Guffey + + +NAME +---- +cdist-type__pf_ruleset - Copy a pf(4) ruleset to $__target_host + + +DESCRIPTION +----------- +This type is used on *BSD systems to manage the pf firewall's ruleset. + + +REQUIRED PARAMETERS +------------------- +state:: + Either "absent" (no ruleset at all) or "present" + + +OPTIONAL PARAMETERS +------------------- +source:: + If supplied, use to define the ruleset to load onto the $__target_host for pf(4). + Note that this type is almost useless without a ruleset defined, but it's technically not + needed, e.g. for the case of disabling the firewall temporarily. + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Remove the current ruleset in place +__pf_ruleset --state absent + +# Enable the firewall with the ruleset defined in $__manifest/files/pf.conf +__pf_ruleset --state present --source $__manifest/files/pf.conf + +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- pf(4) + + +COPYING +------- +Copyright \(C) 2012 Jake Guffey. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__pf_ruleset/parameter/optional b/conf/type/__pf_ruleset/parameter/optional new file mode 100644 index 00000000..5a18cd2f --- /dev/null +++ b/conf/type/__pf_ruleset/parameter/optional @@ -0,0 +1 @@ +source diff --git a/conf/type/__pf_ruleset/parameter/required b/conf/type/__pf_ruleset/parameter/required new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/conf/type/__pf_ruleset/parameter/required @@ -0,0 +1 @@ +state diff --git a/conf/type/__pf_ruleset/singleton b/conf/type/__pf_ruleset/singleton new file mode 100644 index 00000000..e69de29b From f6de6d895732e7857be401ef621880fa30b40990 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Sep 2012 21:29:44 +0200 Subject: [PATCH 1593/4212] begin type __qemu_img Signed-off-by: Nico Schottelius --- conf/type/__qemu_img/explorer/exists | 28 +++++++++++++++++++++++++ conf/type/__qemu_img/gencode-remote | 20 ++++++++++++++++++ conf/type/__qemu_img/manifest | 14 +++++++++++++ conf/type/__qemu_img/parameter/optional | 1 + conf/type/__qemu_img/parameter/required | 1 + 5 files changed, 64 insertions(+) create mode 100755 conf/type/__qemu_img/explorer/exists create mode 100644 conf/type/__qemu_img/gencode-remote create mode 100644 conf/type/__qemu_img/manifest create mode 100644 conf/type/__qemu_img/parameter/optional create mode 100644 conf/type/__qemu_img/parameter/required diff --git a/conf/type/__qemu_img/explorer/exists b/conf/type/__qemu_img/explorer/exists new file mode 100755 index 00000000..c80b1181 --- /dev/null +++ b/conf/type/__qemu_img/explorer/exists @@ -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 + echo yes +fi diff --git a/conf/type/__qemu_img/gencode-remote b/conf/type/__qemu_img/gencode-remote new file mode 100644 index 00000000..acadcef0 --- /dev/null +++ b/conf/type/__qemu_img/gencode-remote @@ -0,0 +1,20 @@ +################################################################################ +# State: absent is handled by manifest - we need only to do stuff if image is +# not existing and state != absent +# +[ -f "$__object/parameter/state" ] && state="$(cat "$__object/parameter/state")" +[ "$state" = "absent" ] && exit 0 + +exists="$(cat "$__object/explorer/exists")" +[ "$exists" ] && exit 0 + +################################################################################ +# Still there? Create image +# + +format=qcow2 +[ -f "$__object/parameter/format" ] && format="$(cat "$__object/parameter/format")" +size="$(cat "$__object/parameter/size")" +vm="/$__object_id" + +echo qemu-img create -f \"$format\" \"$vm\" \"$size\" diff --git a/conf/type/__qemu_img/manifest b/conf/type/__qemu_img/manifest new file mode 100644 index 00000000..d343e188 --- /dev/null +++ b/conf/type/__qemu_img/manifest @@ -0,0 +1,14 @@ +################################################################################ +# Default settings +# + +format=qcow2 +[ -f "$__object/parameter/format" ] && format="$(cat "$__object/parameter/format")" +[ -f "$__object/parameter/state" ] && state="$(cat "$__object/parameter/state")" + +vm="/$__object_id" + +# Absent is ensured by __file, present by gencode-remote +if [ "$state" = "absent" ]; then + __file "$vm" --state absent +fi diff --git a/conf/type/__qemu_img/parameter/optional b/conf/type/__qemu_img/parameter/optional new file mode 100644 index 00000000..0e8469e7 --- /dev/null +++ b/conf/type/__qemu_img/parameter/optional @@ -0,0 +1 @@ +format diff --git a/conf/type/__qemu_img/parameter/required b/conf/type/__qemu_img/parameter/required new file mode 100644 index 00000000..2a613ba5 --- /dev/null +++ b/conf/type/__qemu_img/parameter/required @@ -0,0 +1 @@ +size From 52583e696f28f26ac9eadca78e563c2441409205 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Sep 2012 21:32:47 +0200 Subject: [PATCH 1594/4212] add manpage Signed-off-by: Nico Schottelius --- conf/type/__qemu_img/man.text | 51 +++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 conf/type/__qemu_img/man.text diff --git a/conf/type/__qemu_img/man.text b/conf/type/__qemu_img/man.text new file mode 100644 index 00000000..e2442172 --- /dev/null +++ b/conf/type/__qemu_img/man.text @@ -0,0 +1,51 @@ +cdist-type__qemu_img(7) +======================== +Nico Schottelius + + +NAME +---- +cdist-type__qemu_img - Manage VM disk images + + +DESCRIPTION +----------- +The qemu-img program is used to create qemu images for +qemu and (qemu-)kvm. + + +REQUIRED PARAMETERS +------------------- +size:: + Size of the image in qemu-img compatible units. + See qemu-img(1). + + +OPTIONAL PARAMETERS +------------------- +state:: + The state of the image file: either "present" or "absent". + Defaults to "present". + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure zsh in installed +__qemu_img /home/services/kvm/vm/myvmname/system-disk --size 50G + +# Remove image +__qemu_img /home/services/kvm/vm/myoldvm/system-disk --state absent +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +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). From 17858ebd0054e21d568646dcea2d0802bb9bcec8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Sep 2012 21:33:16 +0200 Subject: [PATCH 1595/4212] ++changes(2.0.15) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index af693bba..76019235 100644 --- a/doc/changelog +++ b/doc/changelog @@ -6,6 +6,7 @@ Changelog 2.0.15: * Core: Make variable __object_name available in type explorers (Steven Armtrong) + * New Type: __qemu_img 2.0.14: 2012-09-07 * Bugfix Type: __jail: Use correct variable (Jake Guffey) From c551bbbb692e03d3035165f7798c85e9cb76c8b9 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 19 Sep 2012 15:49:36 -0400 Subject: [PATCH 1596/4212] Initial commit Initial commit of __pf_apply type before actually creating logic --- conf/type/__pf_apply/gencode-remote | 34 +++++++++++++++++++ conf/type/__pf_apply/man.text | 52 +++++++++++++++++++++++++++++ conf/type/__pf_apply/singleton | 0 3 files changed, 86 insertions(+) create mode 100755 conf/type/__pf_apply/gencode-remote create mode 100644 conf/type/__pf_apply/man.text create mode 100644 conf/type/__pf_apply/singleton diff --git a/conf/type/__pf_apply/gencode-remote b/conf/type/__pf_apply/gencode-remote new file mode 100755 index 00000000..309eb12d --- /dev/null +++ b/conf/type/__pf_apply/gencode-remote @@ -0,0 +1,34 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Apply pf(4) ruleset on *BSD +# + +# Debug +#exec >&2 +#set -x + +cat < + + +NAME +---- +cdist-type__pf_apply - Apply pf(4) ruleset on *BSD + + +DESCRIPTION +----------- +This type is used on *BSD systems to manage the pf firewall's active ruleset. + + +REQUIRED PARAMETERS +------------------- +NONE + + +OPTIONAL PARAMETERS +------------------- +NONE + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Modify the ruleset on $__target_host: +__pf_ruleset --state present --source /my/pf/ruleset.conf +require="__pf_ruleset" \ + __pf_apply + +# Remove the ruleset on $__target_host (implies disabling pf(4): +__pf_ruleset --state absent +require="__pf_ruleset" \ + __pf_apply +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__pf_ruleset(7) +- pf(4) + + +COPYING +------- +Copyright \(C) 2012 Jake Guffey. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__pf_apply/singleton b/conf/type/__pf_apply/singleton new file mode 100644 index 00000000..e69de29b From 08aa7d8e8315652dbe86b6e8ad56227a28e80d3d Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 19 Sep 2012 16:15:06 -0400 Subject: [PATCH 1597/4212] Fleshed out gencode-remote logic Added logic into gencode-remote to enable/disable pf Added logic into gencode-remote to apply the new ruleset if necessary Added explorer to find ${rcvar} --- conf/type/__pf_apply/explorer/rcvar | 36 +++++++++++++++++++++++++++++ conf/type/__pf_apply/gencode-remote | 22 +++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100755 conf/type/__pf_apply/explorer/rcvar diff --git a/conf/type/__pf_apply/explorer/rcvar b/conf/type/__pf_apply/explorer/rcvar new file mode 100755 index 00000000..20e9dfcc --- /dev/null +++ b/conf/type/__pf_apply/explorer/rcvar @@ -0,0 +1,36 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Get the location of the pf ruleset on the target host. +# + +# Debug +#exec >&2 +#set -x + +# Check /etc/rc.conf for pf's configuration file name. Default to /etc/pf.conf + +RC="/etc/rc.conf" +PFCONF="$(grep '^pf_rules=' ${RC} | cut -d= -f2 | sed 's/"//g')" +echo ${PFCONF:-"/etc/pf.conf"} + +# Debug +#set +x + diff --git a/conf/type/__pf_apply/gencode-remote b/conf/type/__pf_apply/gencode-remote index 309eb12d..83529859 100755 --- a/conf/type/__pf_apply/gencode-remote +++ b/conf/type/__pf_apply/gencode-remote @@ -25,8 +25,28 @@ #exec >&2 #set -x +rcvar=$(cat "$__object/explorer/rcvar") + cat <&2 + fi +fi EOF # Debug From 205f32c78bcedd5f4291457753b7250f1ec95e7c Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 19 Sep 2012 16:37:18 -0400 Subject: [PATCH 1598/4212] Fixed generated code and explorer Generated code needed subshell escaped Explorer wasn't parsing output of cksum properly --- conf/type/__pf_ruleset/explorer/cksum | 2 +- conf/type/__pf_ruleset/gencode-local | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/conf/type/__pf_ruleset/explorer/cksum b/conf/type/__pf_ruleset/explorer/cksum index 372e9193..ce188ba0 100755 --- a/conf/type/__pf_ruleset/explorer/cksum +++ b/conf/type/__pf_ruleset/explorer/cksum @@ -33,7 +33,7 @@ TMP="$(grep '^pf_rules=' ${RC} | cut -d= -f2 | sed 's/"//g')" PFCONF="${TMP:-"/etc/pf.conf"}" if [ -f "${PFCONF}" ]; then # The pf config file exists, find its cksum. - cksum -o 1 ${PFCONF} | cut -d= -f2 | sed 's/ //g' + cksum -o 1 ${PFCONF} | cut -d= -f2 | awk '{print $1}' else # the pf config file doesn't exist echo NOTEXIST fi diff --git a/conf/type/__pf_ruleset/gencode-local b/conf/type/__pf_ruleset/gencode-local index 7c2f877e..b1ee6a14 100644 --- a/conf/type/__pf_ruleset/gencode-local +++ b/conf/type/__pf_ruleset/gencode-local @@ -45,13 +45,13 @@ cksum=$(cat "$__object/explorer/cksum") cat <&2 @@ -66,9 +66,8 @@ if [ ! "${cksum}" = "NOTEXIST" ]; then else # File just doesn't exist yet $__remote_copy "${source}" "$__target_host:${rcvar}.new" fi - -if [ -n "${testscript}" ]; then - $__remote_copy "${testscript}" "$__target_host:${rcvar}.test" -fi EOF +# Debug +#exec +x + From 995265d4a64df5d57cdaa61ca841cc49c3d1b440 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 19 Sep 2012 16:42:15 -0400 Subject: [PATCH 1599/4212] Allow pfctl -[de] to return 1 If pf is already enabled or disabled and we try to enable/disable it again, it returns 1. --- conf/type/__pf_apply/gencode-remote | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/conf/type/__pf_apply/gencode-remote b/conf/type/__pf_apply/gencode-remote index 83529859..72200b59 100755 --- a/conf/type/__pf_apply/gencode-remote +++ b/conf/type/__pf_apply/gencode-remote @@ -29,6 +29,8 @@ rcvar=$(cat "$__object/explorer/rcvar") cat < Date: Wed, 19 Sep 2012 17:00:22 -0400 Subject: [PATCH 1600/4212] Fix typo Generated code had unterminated string in first check, causing future check to fail --- conf/type/__pf_apply/gencode-remote | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/conf/type/__pf_apply/gencode-remote b/conf/type/__pf_apply/gencode-remote index 72200b59..aa3864b0 100755 --- a/conf/type/__pf_apply/gencode-remote +++ b/conf/type/__pf_apply/gencode-remote @@ -33,7 +33,7 @@ if [ -f "${rcvar}.old" ]; then # rcvar.old exists, we must need to disable pf # If it already is disabled, pfctl -d returns 1, go on with life pfctl -d # Cleanup - rm -f "${rcvar}.old + rm -f "${rcvar}.old" # This file shouldn't exist, but just in case... [ -f "${rcvar}" ] && rm -f "${rcvar}" elif [ -f "${rcvar}.new" ]; then # rcvar.new exists, we must need to apply it @@ -43,12 +43,15 @@ elif [ -f "${rcvar}.new" ]; then # rcvar.new exists, we must need to apply it pfctl -f "${rcvar}" ret="$?" # Cleanup - rm -f "${rcvar}.old + rm -f "${rcvar}.old" # This file shouldn't exist, but just in case... [ -f "${rcvar}" ] && rm -f "${rcvar}" if [ "$ret" -ne "0" ]; then # failed to configure new ruleset - echo "Failed to configure the new ruleset on ${__target_host}\!" >&2 + echo "Failed to configure the new ruleset on ${__target_host}!" >&2 fi +else # neither ${rcvar}.old nor ${rcvar}.new exist? error. + echo "Neither ${rcvar}.old nor ${rcvar}.new exist! Something is wrong." >&2 + exit 1 fi EOF From 629f751726e61ff77ef8ec344e66031c37c0bc50 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 19 Sep 2012 17:04:03 -0400 Subject: [PATCH 1601/4212] Removed ${rcvar} but never renamed ${rcvar}.new Was trying to load ${rcvar} into pf, but couldn't because new ruleset was never renamed. --- conf/type/__pf_apply/gencode-remote | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/conf/type/__pf_apply/gencode-remote b/conf/type/__pf_apply/gencode-remote index aa3864b0..9288d3e2 100755 --- a/conf/type/__pf_apply/gencode-remote +++ b/conf/type/__pf_apply/gencode-remote @@ -39,13 +39,14 @@ if [ -f "${rcvar}.old" ]; then # rcvar.old exists, we must need to disable pf elif [ -f "${rcvar}.new" ]; then # rcvar.new exists, we must need to apply it # Ensure that pf is enabled in the first place # If it already is enabled, pfctl -e returns 1, go on with life + [ -f "${rcvar}" ] && rm -f "${rcvar}" + mv "${rcvar}.new" "${rcvar}" pfctl -e || true pfctl -f "${rcvar}" ret="$?" # Cleanup + # This file shouldn't exist, but just in case rm -f "${rcvar}.old" - # This file shouldn't exist, but just in case... - [ -f "${rcvar}" ] && rm -f "${rcvar}" if [ "$ret" -ne "0" ]; then # failed to configure new ruleset echo "Failed to configure the new ruleset on ${__target_host}!" >&2 fi From 269b9eff84316b9390bf428dc523d98e42091f0d Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 19 Sep 2012 17:07:56 -0400 Subject: [PATCH 1602/4212] Escape inner variable ret was being set and checked in generated code but the $ wasn't being escaped --- conf/type/__pf_apply/gencode-remote | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/conf/type/__pf_apply/gencode-remote b/conf/type/__pf_apply/gencode-remote index 9288d3e2..5a027984 100755 --- a/conf/type/__pf_apply/gencode-remote +++ b/conf/type/__pf_apply/gencode-remote @@ -47,12 +47,9 @@ elif [ -f "${rcvar}.new" ]; then # rcvar.new exists, we must need to apply it # Cleanup # This file shouldn't exist, but just in case rm -f "${rcvar}.old" - if [ "$ret" -ne "0" ]; then # failed to configure new ruleset + if [ "\$ret" -ne "0" ]; then # failed to configure new ruleset echo "Failed to configure the new ruleset on ${__target_host}!" >&2 fi -else # neither ${rcvar}.old nor ${rcvar}.new exist? error. - echo "Neither ${rcvar}.old nor ${rcvar}.new exist! Something is wrong." >&2 - exit 1 fi EOF From 34ca94ffa2716404d456a095c65f6c88fdbb004c Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 19 Sep 2012 17:10:48 -0400 Subject: [PATCH 1603/4212] Fix typo referenced ${rcvar.old} rather than ${rcvar}.old --- conf/type/__pf_ruleset/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__pf_ruleset/gencode-remote b/conf/type/__pf_ruleset/gencode-remote index 56aee3cb..b35c47c4 100644 --- a/conf/type/__pf_ruleset/gencode-remote +++ b/conf/type/__pf_ruleset/gencode-remote @@ -37,5 +37,5 @@ rcvar=$(cat "$__object/explorer/rcvar") # --state absent, so ensure that .new doesn't exist and that conf is renamed to .old echo rm \"${rcvar}.new\" -echo mv \"${rcvar}\" \"${rcvar.old}\" +echo mv \"${rcvar}\" \"${rcvar}.old\" From a1793f66ff8445298c8b86b523e073f374cb80ac Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 19 Sep 2012 17:16:00 -0400 Subject: [PATCH 1604/4212] Add logic to check for existence of files before interacting with them if ${rcvar} or ${rcvar}.new don't exist, we can't rm/mv them. --- conf/type/__pf_ruleset/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/type/__pf_ruleset/gencode-remote b/conf/type/__pf_ruleset/gencode-remote index b35c47c4..4018bbd7 100644 --- a/conf/type/__pf_ruleset/gencode-remote +++ b/conf/type/__pf_ruleset/gencode-remote @@ -36,6 +36,6 @@ fi rcvar=$(cat "$__object/explorer/rcvar") # --state absent, so ensure that .new doesn't exist and that conf is renamed to .old -echo rm \"${rcvar}.new\" -echo mv \"${rcvar}\" \"${rcvar}.old\" +echo "[ -f \"${rcvar}.new\" ] && rm \"${rcvar}.new\"" +echo "[ -f \"${rcvar}\" ] && mv \"${rcvar}\" \"${rcvar}.old\"" From 7a67f8bc16e75330d95a11a3b35ab354dbdbad51 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 19 Sep 2012 17:18:45 -0400 Subject: [PATCH 1605/4212] Make code match up with comments If pf was already disabled, the code would exit upon trying to disable it again --- conf/type/__pf_apply/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__pf_apply/gencode-remote b/conf/type/__pf_apply/gencode-remote index 5a027984..94d02b3b 100755 --- a/conf/type/__pf_apply/gencode-remote +++ b/conf/type/__pf_apply/gencode-remote @@ -31,7 +31,7 @@ cat < Date: Wed, 19 Sep 2012 17:27:40 -0400 Subject: [PATCH 1606/4212] set -e doesn't like [ blah ] && blah syntax changed to if [ blah ]; then blah; fi format migrated echo usage to cat with HEREDOC to improve readability --- conf/type/__pf_ruleset/gencode-remote | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/conf/type/__pf_ruleset/gencode-remote b/conf/type/__pf_ruleset/gencode-remote index 4018bbd7..e5eece64 100644 --- a/conf/type/__pf_ruleset/gencode-remote +++ b/conf/type/__pf_ruleset/gencode-remote @@ -36,6 +36,12 @@ fi rcvar=$(cat "$__object/explorer/rcvar") # --state absent, so ensure that .new doesn't exist and that conf is renamed to .old -echo "[ -f \"${rcvar}.new\" ] && rm \"${rcvar}.new\"" -echo "[ -f \"${rcvar}\" ] && mv \"${rcvar}\" \"${rcvar}.old\"" +cat < Date: Wed, 19 Sep 2012 17:33:42 -0400 Subject: [PATCH 1607/4212] Migrate conditional syntax set -e doesn't like [ X ] && Y syntax, migrate to if [ X ]; then Y; fi --- conf/type/__pf_apply/gencode-remote | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/conf/type/__pf_apply/gencode-remote b/conf/type/__pf_apply/gencode-remote index 94d02b3b..1185696f 100755 --- a/conf/type/__pf_apply/gencode-remote +++ b/conf/type/__pf_apply/gencode-remote @@ -35,11 +35,15 @@ if [ -f "${rcvar}.old" ]; then # rcvar.old exists, we must need to disable pf # Cleanup rm -f "${rcvar}.old" # This file shouldn't exist, but just in case... - [ -f "${rcvar}" ] && rm -f "${rcvar}" + if [ -f "${rcvar}" ]; then + rm -f "${rcvar}" + fi elif [ -f "${rcvar}.new" ]; then # rcvar.new exists, we must need to apply it # Ensure that pf is enabled in the first place # If it already is enabled, pfctl -e returns 1, go on with life - [ -f "${rcvar}" ] && rm -f "${rcvar}" + if [ -f "${rcvar}" ]; + rm -f "${rcvar}" + fi mv "${rcvar}.new" "${rcvar}" pfctl -e || true pfctl -f "${rcvar}" From c01a7ebc456f5ec97b68c14384af4317c3baa301 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Wed, 19 Sep 2012 17:37:19 -0400 Subject: [PATCH 1608/4212] Left out ; then --- conf/type/__pf_apply/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__pf_apply/gencode-remote b/conf/type/__pf_apply/gencode-remote index 1185696f..3045ee60 100755 --- a/conf/type/__pf_apply/gencode-remote +++ b/conf/type/__pf_apply/gencode-remote @@ -41,7 +41,7 @@ if [ -f "${rcvar}.old" ]; then # rcvar.old exists, we must need to disable pf elif [ -f "${rcvar}.new" ]; then # rcvar.new exists, we must need to apply it # Ensure that pf is enabled in the first place # If it already is enabled, pfctl -e returns 1, go on with life - if [ -f "${rcvar}" ]; + if [ -f "${rcvar}" ]; then rm -f "${rcvar}" fi mv "${rcvar}.new" "${rcvar}" From 8ca3846a3ad89ed05a2235946bf59650a6074b12 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Sep 2012 10:42:16 +0200 Subject: [PATCH 1609/4212] begin with the new manual page Signed-off-by: Nico Schottelius --- conf/type/__line/man.text | 63 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 conf/type/__line/man.text diff --git a/conf/type/__line/man.text b/conf/type/__line/man.text new file mode 100644 index 00000000..c7fc3202 --- /dev/null +++ b/conf/type/__line/man.text @@ -0,0 +1,63 @@ +cdist-type__line(7) +=================== +Nico Schottelius + + +NAME +---- +cdist-type__line - Manage lines in files + + +DESCRIPTION +----------- +This cdist type allows you to add lines and remove lines from files. + + +REQUIRED PARAMETERS +------------------- + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent', defaults to 'present' + +line:: + Specifies the line which should be absent or present + + +regex:: + If supplied, search for this regex. + Otherwise entire line must be matched. + +file:: + If supplied, use this as the destination file. + Otherwise the object_id is used. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Manage the DAEMONS line in rc.conf +__line daemons --file /etc/rc.conf --line 'DAEMONS=(hwclock !network sshd crond postfix)' + +# Ensure the home mount is present in /etc/fstab - explicitly make it present +__line home-fstab \ + --file /etc/fstab \ + --line 'filer.fs:/vol/home /home nfs defaults 0 0' \ + --state present + +# Removes the line specifiend in "include_www" from the file "lighttpd.conf" +__line legacy_timezone --file /etc/rc.conf --regex 'TIMEZONE=.*' --state absent +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +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). From 7b571c53dd286599fb0482cba56c9b9344c3eb52 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Sep 2012 11:10:10 +0200 Subject: [PATCH 1610/4212] add explorer Signed-off-by: Nico Schottelius --- conf/type/__line/explorer/state | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100755 conf/type/__line/explorer/state diff --git a/conf/type/__line/explorer/state b/conf/type/__line/explorer/state new file mode 100755 index 00000000..d240bf4d --- /dev/null +++ b/conf/type/__line/explorer/state @@ -0,0 +1,40 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +file="/$__object_id" +[ -f "$__object/parameter/file" ] && file=$(cat "$__object/parameter/file") + +if [ -f "$__object/parameter/regex" ]; then + regex=$(cat "$__object/parameter/regex") +else + if [ ! -f "$__object/parameter/line" ]; then + echo "Parameter line and regex missing - cannot explore" >&2 + exit 1 + fi + regex="^$(cat "$__object/parameter/line")\$" +fi + +# Allow missing file - thus 2>/dev/null +if grep -q "$regex" "$file" 2>/dev/null; then + echo present +else + echo absent +fi From 5a154fa0a220e2e8b523a9885d3491600122b334 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Sep 2012 13:20:30 +0200 Subject: [PATCH 1611/4212] first gencode version Signed-off-by: Nico Schottelius --- conf/type/__line/gencode-remote | 50 +++++++++++++++++++++++++++++++++ conf/type/__line/man.text | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100755 conf/type/__line/gencode-remote diff --git a/conf/type/__line/gencode-remote b/conf/type/__line/gencode-remote new file mode 100755 index 00000000..9ca36177 --- /dev/null +++ b/conf/type/__line/gencode-remote @@ -0,0 +1,50 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +file="/$__object_id" +state_should="present" +[ -f "$__object/parameter/file" ] && file=$(cat "$__object/parameter/file") +[ -f "$__object/parameter/state" ] && state_should=$(cat "$__object/parameter/state") + +state_is="$(cat "$__object/explorer/state")" + +[ "$state_should" = "$state_is" ] && exit 0 + +case "$state_should" in + present) + if [ ! -f "$__object/parameter/line" ]; then + echo "Required parameter \"line\" is missing" >&2 + exit 1 + else + line=$(cat "$__object/parameter/line") + fi + + echo "echo \"$line\" >> $file" + + ;; + absent) + echo "echo q | ex -c \"/${line}/d|w|q\" \"${file}\"" + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/conf/type/__line/man.text b/conf/type/__line/man.text index c7fc3202..137e31d1 100644 --- a/conf/type/__line/man.text +++ b/conf/type/__line/man.text @@ -23,7 +23,7 @@ state:: line:: Specifies the line which should be absent or present - + Must be present, if state is present. regex:: If supplied, search for this regex. From fd490b39f125c992a160c98839fa261c6a418fd7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Sep 2012 15:25:05 +0200 Subject: [PATCH 1612/4212] add parameter Signed-off-by: Nico Schottelius --- conf/type/__line/parameter/optional | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 conf/type/__line/parameter/optional diff --git a/conf/type/__line/parameter/optional b/conf/type/__line/parameter/optional new file mode 100644 index 00000000..604a203e --- /dev/null +++ b/conf/type/__line/parameter/optional @@ -0,0 +1,4 @@ +state +regex +file +line From 9e40d7bc916fc072963f9c27ed45235e1ad7f947 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Sep 2012 17:35:14 +0200 Subject: [PATCH 1613/4212] clarify relation between line and regex Signed-off-by: Nico Schottelius --- conf/type/__line/gencode-remote | 17 +++++++++++++++-- conf/type/__line/man.text | 13 +++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/conf/type/__line/gencode-remote b/conf/type/__line/gencode-remote index 9ca36177..75cd92b4 100755 --- a/conf/type/__line/gencode-remote +++ b/conf/type/__line/gencode-remote @@ -20,8 +20,10 @@ # file="/$__object_id" +regex="" state_should="present" -[ -f "$__object/parameter/file" ] && file=$(cat "$__object/parameter/file") +[ -f "$__object/parameter/file" ] && file=$(cat "$__object/parameter/file") +[ -f "$__object/parameter/regex" ] && regex=$(cat "$__object/parameter/regex") [ -f "$__object/parameter/state" ] && state_should=$(cat "$__object/parameter/state") state_is="$(cat "$__object/explorer/state")" @@ -41,7 +43,18 @@ case "$state_should" in ;; absent) - echo "echo q | ex -c \"/${line}/d|w|q\" \"${file}\"" + if [ "$regex" -a "$line" ]; then + echo "Mutally exclusive parameters regex and line given for state absent" >&2 + exit 1 + fi + + [ "$line" ] && regex="^$line\$" + + cat << eof +tmp=\$(mktemp) +sed '/$regex/d' "$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/conf/type/__line/man.text b/conf/type/__line/man.text index 137e31d1..e1a5941c 100644 --- a/conf/type/__line/man.text +++ b/conf/type/__line/man.text @@ -23,11 +23,20 @@ state:: line:: Specifies the line which should be absent or present + Must be present, if state is present. + Must not be combined with regex, if state is absent. regex:: - If supplied, search for this regex. - Otherwise entire line must be matched. + If state is present, search for this pattern and add + given line, if the given regular expression does not match. + + In case of absent, ensure all lines matching the + regular expression are absent (cannot be combined with + the line parameter, if state is absent). + + If the regular expression contains / (slashes), they need + to be escaped with \ (backslash): / becomes \/. file:: If supplied, use this as the destination file. From 1e3f0749fc8c68cf8c4ae8fd1b9cc890e0a30859 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Sep 2012 17:39:14 +0200 Subject: [PATCH 1614/4212] setup line content early Signed-off-by: Nico Schottelius --- conf/type/__line/gencode-remote | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/conf/type/__line/gencode-remote b/conf/type/__line/gencode-remote index 75cd92b4..8ac273e2 100755 --- a/conf/type/__line/gencode-remote +++ b/conf/type/__line/gencode-remote @@ -25,6 +25,7 @@ state_should="present" [ -f "$__object/parameter/file" ] && file=$(cat "$__object/parameter/file") [ -f "$__object/parameter/regex" ] && regex=$(cat "$__object/parameter/regex") [ -f "$__object/parameter/state" ] && state_should=$(cat "$__object/parameter/state") +[ -f "$__object/parameter/line" ] && line=$(cat "$__object/parameter/line") state_is="$(cat "$__object/explorer/state")" @@ -32,11 +33,9 @@ state_is="$(cat "$__object/explorer/state")" case "$state_should" in present) - if [ ! -f "$__object/parameter/line" ]; then + if [ ! "$line" ]; then echo "Required parameter \"line\" is missing" >&2 exit 1 - else - line=$(cat "$__object/parameter/line") fi echo "echo \"$line\" >> $file" From d351029cea142e5fd0c8c13ba9a38f35d1026aa0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Sep 2012 17:42:01 +0200 Subject: [PATCH 1615/4212] deprecate __addifnosuchline and __removeline Signed-off-by: Nico Schottelius --- conf/type/__addifnosuchline/manifest | 1 + conf/type/__removeline/manifest | 1 + 2 files changed, 2 insertions(+) create mode 100644 conf/type/__addifnosuchline/manifest create mode 100644 conf/type/__removeline/manifest diff --git a/conf/type/__addifnosuchline/manifest b/conf/type/__addifnosuchline/manifest new file mode 100644 index 00000000..44ae555a --- /dev/null +++ b/conf/type/__addifnosuchline/manifest @@ -0,0 +1 @@ +echo "Type __addifnosuchline is deprecated and will be removed in cdist 2.1. Please use __line instead" >&2 diff --git a/conf/type/__removeline/manifest b/conf/type/__removeline/manifest new file mode 100644 index 00000000..7efb5d18 --- /dev/null +++ b/conf/type/__removeline/manifest @@ -0,0 +1 @@ +echo "Type __removeline is deprecated and will be removed in cdist 2.1. Please use __line instead" >&2 From a49665ce3d1d3f1e5ba709d0f7ab32c15e4873d4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Sep 2012 17:43:28 +0200 Subject: [PATCH 1616/4212] add WARNING prefix Signed-off-by: Nico Schottelius --- conf/type/__addifnosuchline/manifest | 2 +- conf/type/__removeline/manifest | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/type/__addifnosuchline/manifest b/conf/type/__addifnosuchline/manifest index 44ae555a..ccc82471 100644 --- a/conf/type/__addifnosuchline/manifest +++ b/conf/type/__addifnosuchline/manifest @@ -1 +1 @@ -echo "Type __addifnosuchline is deprecated and will be removed in cdist 2.1. Please use __line instead" >&2 +echo "WARNING: Type __addifnosuchline is deprecated and will be removed in cdist 2.1. Please use __line instead" >&2 diff --git a/conf/type/__removeline/manifest b/conf/type/__removeline/manifest index 7efb5d18..63528795 100644 --- a/conf/type/__removeline/manifest +++ b/conf/type/__removeline/manifest @@ -1 +1 @@ -echo "Type __removeline is deprecated and will be removed in cdist 2.1. Please use __line instead" >&2 +echo "WARNING: Type __removeline is deprecated and will be removed in cdist 2.1. Please use __line instead" >&2 From 065979b8d8e486b15dc922041935638861566927 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Sep 2012 17:44:24 +0200 Subject: [PATCH 1617/4212] ++changes(2.0.15) Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 76019235..2f9ecef5 100644 --- a/doc/changelog +++ b/doc/changelog @@ -7,6 +7,7 @@ Changelog 2.0.15: * Core: Make variable __object_name available in type explorers (Steven Armtrong) * New Type: __qemu_img + * New Type: __line 2.0.14: 2012-09-07 * Bugfix Type: __jail: Use correct variable (Jake Guffey) From b1b86b2ebfbb321060b293f2fa25bd11228d8072 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Sep 2012 17:46:03 +0200 Subject: [PATCH 1618/4212] remove __addifnosuchline and __removeline in 2.1 branch Signed-off-by: Nico Schottelius --- conf/type/__addifnosuchline/explorer/findline | 48 ----------------- conf/type/__addifnosuchline/gencode-remote | 33 ------------ conf/type/__addifnosuchline/man.text | 52 ------------------- conf/type/__addifnosuchline/manifest | 1 - .../type/__addifnosuchline/parameter/optional | 2 - .../type/__addifnosuchline/parameter/required | 1 - conf/type/__removeline/gencode-remote | 31 ----------- conf/type/__removeline/man.text | 50 ------------------ conf/type/__removeline/manifest | 1 - conf/type/__removeline/parameter/optional | 1 - conf/type/__removeline/parameter/required | 1 - 11 files changed, 221 deletions(-) delete mode 100755 conf/type/__addifnosuchline/explorer/findline delete mode 100755 conf/type/__addifnosuchline/gencode-remote delete mode 100644 conf/type/__addifnosuchline/man.text delete mode 100644 conf/type/__addifnosuchline/manifest delete mode 100644 conf/type/__addifnosuchline/parameter/optional delete mode 100644 conf/type/__addifnosuchline/parameter/required delete mode 100755 conf/type/__removeline/gencode-remote delete mode 100644 conf/type/__removeline/man.text delete mode 100644 conf/type/__removeline/manifest delete mode 100644 conf/type/__removeline/parameter/optional delete mode 100644 conf/type/__removeline/parameter/required diff --git a/conf/type/__addifnosuchline/explorer/findline b/conf/type/__addifnosuchline/explorer/findline deleted file mode 100755 index b45bd6ea..00000000 --- a/conf/type/__addifnosuchline/explorer/findline +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Daniel Roth (dani-cdist@d-roth.li) -# 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 . -# -# - -if [ -f "$__object/parameter/file" ]; then - file=$(cat "$__object/parameter/file") -else - file="/$__object_id" -fi - -if [ -f "$__object/parameter/regex" ]; then - regex=$(cat "$__object/parameter/regex") -else - wrap=$(cat "$__object/parameter/line") - regex="^$wrap\$" -fi - -if [ -f "$file" ]; then - # sh -e is our environment, we know what we do, - # skip error detection for now - set +e - grep -q "$regex" "$file" - if [ $? -eq 1 ]; then - echo "NOTFOUND" - else - echo "FOUND" - fi -else - echo "NOTFOUND" -fi diff --git a/conf/type/__addifnosuchline/gencode-remote b/conf/type/__addifnosuchline/gencode-remote deleted file mode 100755 index 1276e5d0..00000000 --- a/conf/type/__addifnosuchline/gencode-remote +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Daniel Roth (dani-cdist@d-roth.li) -# -# 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/file" ]; then - file=$(cat "$__object/parameter/file") -else - file="/$__object_id" -fi - -result=$(cat "$__object/explorer/findline") - -if [ "$result" = "NOTFOUND" ]; then - line=$(cat "$__object/parameter/line") - echo "echo \"$line\" >> $file" -fi diff --git a/conf/type/__addifnosuchline/man.text b/conf/type/__addifnosuchline/man.text deleted file mode 100644 index ba3825ff..00000000 --- a/conf/type/__addifnosuchline/man.text +++ /dev/null @@ -1,52 +0,0 @@ -cdist-type__addifnosuchline(7) -============================== -Daniel Roth - - -NAME ----- -cdist-type__addifnosuchline - Add a line (if not existing already) - - -DESCRIPTION ------------ -This type can be used to check a file for existence of a -specific line and adding it, if it was not found. - - -REQUIRED PARAMETERS -------------------- -line:: - Specifies the content which shall be added if not existing. - - -OPTIONAL PARAMETERS -------------------- -file:: - If supplied, use this as the destination file. - Otherwise the object_id is used. -regex:: - If supplied, search for this regex. - Otherwise entire line must be matched. - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Creates or appends the line specified in "include_www" to the file "lighttpd.conf" -__addifnosuchline www --file /etc/lighttpd.conf --line include_www - -# Adds the line "include_git" to the file "lighttpd.conf" -__addifnosuchline /etc/lighttpd.conf --line include_git --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2011 Daniel Roth. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__addifnosuchline/manifest b/conf/type/__addifnosuchline/manifest deleted file mode 100644 index ccc82471..00000000 --- a/conf/type/__addifnosuchline/manifest +++ /dev/null @@ -1 +0,0 @@ -echo "WARNING: Type __addifnosuchline is deprecated and will be removed in cdist 2.1. Please use __line instead" >&2 diff --git a/conf/type/__addifnosuchline/parameter/optional b/conf/type/__addifnosuchline/parameter/optional deleted file mode 100644 index 7ecfcde9..00000000 --- a/conf/type/__addifnosuchline/parameter/optional +++ /dev/null @@ -1,2 +0,0 @@ -file -regex diff --git a/conf/type/__addifnosuchline/parameter/required b/conf/type/__addifnosuchline/parameter/required deleted file mode 100644 index a999a0c2..00000000 --- a/conf/type/__addifnosuchline/parameter/required +++ /dev/null @@ -1 +0,0 @@ -line diff --git a/conf/type/__removeline/gencode-remote b/conf/type/__removeline/gencode-remote deleted file mode 100755 index 3ec466b9..00000000 --- a/conf/type/__removeline/gencode-remote +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Daniel Roth (dani-cdist@d-roth.li) -# -# 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/file" ]; then - file=$(cat "$__object/parameter/file") -else - file="/$__object_id" -fi - -line=$(cat "$__object/parameter/line") -echo "ex -c \"/${line}/d|w|q\" \"${file}\" < - - -NAME ----- -cdist-type__removeline - Remove a line (if existing) - - -DESCRIPTION ------------ -This type can be used to check a file for existence of a -specific line and removeing it, if it was found. - - -REQUIRED PARAMETERS -------------------- -line:: - Specifies the content which shall be removed if existing. - - -OPTIONAL PARAMETERS -------------------- -file:: - If supplied, use this as the destination file. - Otherwise the object_id is used. - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Removes the line specifiend in "include_www" from the file "lighttpd.conf" -__removeline www --file /etc/lighttpd.conf --line include_www - -# Removes the line "include_git" from the file "lighttpd.conf" -__removeline /etc/lighttpd.conf --line include_git --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2011 Daniel Roth. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__removeline/manifest b/conf/type/__removeline/manifest deleted file mode 100644 index 63528795..00000000 --- a/conf/type/__removeline/manifest +++ /dev/null @@ -1 +0,0 @@ -echo "WARNING: Type __removeline is deprecated and will be removed in cdist 2.1. Please use __line instead" >&2 diff --git a/conf/type/__removeline/parameter/optional b/conf/type/__removeline/parameter/optional deleted file mode 100644 index f73f3093..00000000 --- a/conf/type/__removeline/parameter/optional +++ /dev/null @@ -1 +0,0 @@ -file diff --git a/conf/type/__removeline/parameter/required b/conf/type/__removeline/parameter/required deleted file mode 100644 index a999a0c2..00000000 --- a/conf/type/__removeline/parameter/required +++ /dev/null @@ -1 +0,0 @@ -line From 24cae3cb21c5aeca4c350df387bf1b84cf067d3b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Sep 2012 17:47:40 +0200 Subject: [PATCH 1619/4212] +changelog for 2.1 Signed-off-by: Nico Schottelius --- doc/changelog-2.1 | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 doc/changelog-2.1 diff --git a/doc/changelog-2.1 b/doc/changelog-2.1 new file mode 100644 index 00000000..24de88f3 --- /dev/null +++ b/doc/changelog-2.1 @@ -0,0 +1,9 @@ +Changelog (v2.1 specific) +------------------------- + + * Changes are always commented with their author in (braces) + * Exception: No braces means author == Nico Schottelius + +2.1.0: + * Removed type __addifnosuchline (replaced by __line) + * Removed type __removeline (replaced by __line) From d6ce6e623a50d6ca744579887d7030754a8fcc81 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Sep 2012 17:48:54 +0200 Subject: [PATCH 1620/4212] +old bug Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-06-15.explorer-dep-problem | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 doc/dev/logs/2012-06-15.explorer-dep-problem diff --git a/doc/dev/logs/2012-06-15.explorer-dep-problem b/doc/dev/logs/2012-06-15.explorer-dep-problem new file mode 100644 index 00000000..30803032 --- /dev/null +++ b/doc/dev/logs/2012-06-15.explorer-dep-problem @@ -0,0 +1,4 @@ +Known bug rediscovered: + Explorer for __start_on_boot mysql runs before __package mysql was finished. + +Requires two runs to actually finish the task. From e4d1ea5bc9f9874048aeb14cbc9a872bd5e7c123 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Sep 2012 10:40:37 +0200 Subject: [PATCH 1621/4212] change --parents and --recurse to boolean Signed-off-by: Nico Schottelius --- conf/type/__directory/man.text | 7 ++++--- conf/type/__directory/parameter/boolean | 2 ++ conf/type/__directory/parameter/optional | 2 -- 3 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 conf/type/__directory/parameter/boolean diff --git a/conf/type/__directory/man.text b/conf/type/__directory/man.text index afba0875..3f005b55 100644 --- a/conf/type/__directory/man.text +++ b/conf/type/__directory/man.text @@ -32,14 +32,15 @@ mode:: owner:: User to chown to. + +OPTIONAL BOOLEAN PARAMETERS +--------------------------- parents:: - Whether to create parents as well (mkdir -p behaviour). Must be yes or no. + Whether to create parents as well (mkdir -p behaviour) recursive:: If supplied the chgrp and chown call will run recursively. This does *not* influence the behaviour of chmod. - Must be yes or no. - EXAMPLES -------- diff --git a/conf/type/__directory/parameter/boolean b/conf/type/__directory/parameter/boolean new file mode 100644 index 00000000..357c5e81 --- /dev/null +++ b/conf/type/__directory/parameter/boolean @@ -0,0 +1,2 @@ +parents +recursive diff --git a/conf/type/__directory/parameter/optional b/conf/type/__directory/parameter/optional index 27f9d76a..08798bc5 100644 --- a/conf/type/__directory/parameter/optional +++ b/conf/type/__directory/parameter/optional @@ -2,5 +2,3 @@ state group mode owner -parents -recursive From 1e765d7e777cbdcd73b10f518a8cc302e3bf1b83 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Sep 2012 10:43:11 +0200 Subject: [PATCH 1622/4212] remove parameter changing manifest Signed-off-by: Nico Schottelius --- .../__directory/explorer/{exists => state} | 0 conf/type/__directory/manifest | 23 ------------------- 2 files changed, 23 deletions(-) rename conf/type/__directory/explorer/{exists => state} (100%) delete mode 100755 conf/type/__directory/manifest diff --git a/conf/type/__directory/explorer/exists b/conf/type/__directory/explorer/state similarity index 100% rename from conf/type/__directory/explorer/exists rename to conf/type/__directory/explorer/state diff --git a/conf/type/__directory/manifest b/conf/type/__directory/manifest deleted file mode 100755 index a8ee5a6f..00000000 --- a/conf/type/__directory/manifest +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh -# -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# - -# set defaults -state="$(cat "$__object/parameter/state" 2>/dev/null \ - || echo "present" | tee "$__object/parameter/state")" From 30323456bf302fb75ae6ba294ef27f2c63b4cb78 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Sep 2012 11:03:53 +0200 Subject: [PATCH 1623/4212] cleanup gencode-remote Signed-off-by: Nico Schottelius --- conf/type/__directory/explorer/state | 4 +- conf/type/__directory/gencode-remote | 77 +++++++++++----------------- 2 files changed, 33 insertions(+), 48 deletions(-) diff --git a/conf/type/__directory/explorer/state b/conf/type/__directory/explorer/state index f8b85671..9bdd9024 100755 --- a/conf/type/__directory/explorer/state +++ b/conf/type/__directory/explorer/state @@ -24,7 +24,7 @@ destination="/$__object_id" if [ -e "$destination" ]; then - echo yes + echo present else - echo no + echo absent fi diff --git a/conf/type/__directory/gencode-remote b/conf/type/__directory/gencode-remote index e871547a..25553183 100755 --- a/conf/type/__directory/gencode-remote +++ b/conf/type/__directory/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -20,54 +20,39 @@ destination="/$__object_id" state_should="$(cat "$__object/parameter/state")" +state_is="$(cat "$__object/explorer/state")" + +[ "$state_should" = "$state_is" ] && exit 0 + +mkdiropt="" +grep yes "$__object/parameter/parents" >/dev/null 2>&1 && mkdiropt="-p" +recursive="" +grep yes "$__object/parameter/recursive" >/dev/null 2>&1 && recursive="-R" case "$state_should" in - present) - # Include parent directories? - if [ -f "$__object/parameter/parents" ]; then - parents="$(cat "$__object/parameter/parents")" - if [ yes = "$parents" ]; then - mkdiropt="-p" - else - mkdiropt="" - fi - fi + present) + echo mkdir $mkdiropt \"$destination\" - if [ -f "$__object/parameter/recursive" ]; then - if [ yes = "$(cat "$__object/parameter/recursive")" ]; then - recursive="-R" - fi - fi + # Mode settings + if [ -f "$__object/parameter/mode" ]; then + echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" + fi - # Only create if not already existent - if [ no = "$(cat "$__object/explorer/exists")" ]; then - echo mkdir $mkdiropt \"$destination\" - fi + # Group + if [ -f "$__object/parameter/group" ]; then + echo chgrp $recursive \"$(cat "$__object/parameter/group")\" \"$destination\" + fi - # Mode settings - if [ -f "$__object/parameter/mode" ]; then - echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" - fi - - # Group - if [ -f "$__object/parameter/group" ]; then - echo chgrp $recursive \"$(cat "$__object/parameter/group")\" \"$destination\" - fi - - # Owner - if [ -f "$__object/parameter/owner" ]; then - echo chown $recursive \"$(cat "$__object/parameter/owner")\" \"$destination\" - fi - ;; - absent) - # Only delete if it exists - if [ yes = "$(cat "$__object/explorer/exists")" ]; then - echo rm -rf \"$destination\" - fi - - ;; - *) - echo "Unknown state: $state_should" >&2 - exit 1 - ;; + # Owner + if [ -f "$__object/parameter/owner" ]; then + echo chown $recursive \"$(cat "$__object/parameter/owner")\" \"$destination\" + fi + ;; + absent) + echo rm -rf \"$destination\" + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; esac From 135299357b6ef4545f8de3c06cc4bf68ee89c3a1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Sep 2012 11:08:55 +0200 Subject: [PATCH 1624/4212] correctly setup state Signed-off-by: Nico Schottelius --- conf/type/__directory/gencode-remote | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/conf/type/__directory/gencode-remote b/conf/type/__directory/gencode-remote index 25553183..56bd73a1 100755 --- a/conf/type/__directory/gencode-remote +++ b/conf/type/__directory/gencode-remote @@ -18,12 +18,14 @@ # along with cdist. If not, see . # -destination="/$__object_id" -state_should="$(cat "$__object/parameter/state")" +# Check state and exit if nothing needs to be done +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="" grep yes "$__object/parameter/parents" >/dev/null 2>&1 && mkdiropt="-p" recursive="" From e82c11cce429ce68befbc5126e11ffb47b170997 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Sep 2012 11:10:38 +0200 Subject: [PATCH 1625/4212] add changes for 2.1 boolean version Signed-off-by: Nico Schottelius --- conf/type/__directory/gencode-remote | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/conf/type/__directory/gencode-remote b/conf/type/__directory/gencode-remote index 56bd73a1..21f4c5b6 100755 --- a/conf/type/__directory/gencode-remote +++ b/conf/type/__directory/gencode-remote @@ -18,7 +18,6 @@ # along with cdist. If not, see . # -# Check state and exit if nothing needs to be done state_should="present" [ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" state_is="$(cat "$__object/explorer/state")" @@ -27,9 +26,9 @@ state_is="$(cat "$__object/explorer/state")" destination="/$__object_id" mkdiropt="" -grep yes "$__object/parameter/parents" >/dev/null 2>&1 && mkdiropt="-p" +[ -f "$__object/parameter/parents" ] && mkdiropt="-p" recursive="" -grep yes "$__object/parameter/recursive" >/dev/null 2>&1 && recursive="-R" +[ -f "$__object/parameter/recursive" ] && recursive="-R" case "$state_should" in present) From bc203df95f76661f433e2d7b5f30c6afe09e9fe8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Sep 2012 11:12:32 +0200 Subject: [PATCH 1626/4212] update man for 2.1 Signed-off-by: Nico Schottelius --- conf/type/__directory/man.text | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/conf/type/__directory/man.text b/conf/type/__directory/man.text index 3f005b55..1f4def7d 100644 --- a/conf/type/__directory/man.text +++ b/conf/type/__directory/man.text @@ -33,8 +33,8 @@ owner:: User to chown to. -OPTIONAL BOOLEAN PARAMETERS ---------------------------- +BOOLEAN PARAMETERS +------------------ parents:: Whether to create parents as well (mkdir -p behaviour) @@ -42,6 +42,7 @@ recursive:: If supplied the chgrp and chown call will run recursively. This does *not* influence the behaviour of chmod. + EXAMPLES -------- @@ -56,13 +57,18 @@ __directory /tmp/foobar --state absent __directory /etc --owner root --group root --mode 0755 # Create nfs service directory, including parents -__directory /home/services/nfs --parents yes +__directory /home/services/nfs --parents # Change permissions recursively -__directory /home/services --recursive yes --owner root --group root +__directory /home/services --recursive --owner root --group root # Setup a temp directory __directory /local --mode 1777 + +# Take it all +__directory /home/services/kvm --recursive --parents \ + --owner root --group root --mode 0755 --state present + -------------------------------------------------------------------------------- From 9fbdfda3023b2f58f3d817f5af7d5ffdc56bebdc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Sep 2012 11:13:04 +0200 Subject: [PATCH 1627/4212] ++changes(2.1.0) Signed-off-by: Nico Schottelius --- doc/changelog-2.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog-2.1 b/doc/changelog-2.1 index 24de88f3..fd03e69c 100644 --- a/doc/changelog-2.1 +++ b/doc/changelog-2.1 @@ -7,3 +7,4 @@ Changelog (v2.1 specific) 2.1.0: * Removed type __addifnosuchline (replaced by __line) * Removed type __removeline (replaced by __line) + * Type __directory: Parameter --parents and --recursive are now boolean From 1b80f2806b55d52d6d7fe4c31d9b88aab88c10f6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Sep 2012 11:32:04 +0200 Subject: [PATCH 1628/4212] remove installed/removed state parameters (2.1 cleanup) Signed-off-by: Nico Schottelius --- conf/type/__package/man.text | 1 - conf/type/__package_apt/gencode-remote | 12 ------------ conf/type/__package_apt/man.text | 3 +-- conf/type/__package_luarocks/gencode-remote | 12 ------------ conf/type/__package_luarocks/man.text | 1 - conf/type/__package_opkg/gencode-remote | 1 - conf/type/__package_pacman/gencode-remote | 10 ---------- conf/type/__package_pacman/man.text | 1 - conf/type/__package_pkg_freebsd/gencode-remote | 1 - conf/type/__package_pkg_freebsd/man.text | 8 ++++---- conf/type/__package_pkg_openbsd/gencode-remote | 11 ----------- conf/type/__package_pkg_openbsd/man.text | 1 - conf/type/__package_rubygem/gencode-remote | 11 ----------- conf/type/__package_rubygem/man.text | 1 - conf/type/__package_yum/gencode-remote | 10 ---------- conf/type/__package_yum/man.text | 3 +-- conf/type/__process/gencode-remote | 10 ---------- 17 files changed, 6 insertions(+), 91 deletions(-) diff --git a/conf/type/__package/man.text b/conf/type/__package/man.text index 071a8bfb..0d8f8c9e 100644 --- a/conf/type/__package/man.text +++ b/conf/type/__package/man.text @@ -18,7 +18,6 @@ REQUIRED PARAMETERS ------------------- state:: The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS diff --git a/conf/type/__package_apt/gencode-remote b/conf/type/__package_apt/gencode-remote index 0bcdb946..a5bd7708 100755 --- a/conf/type/__package_apt/gencode-remote +++ b/conf/type/__package_apt/gencode-remote @@ -29,18 +29,6 @@ fi state_should="$(cat "$__object/parameter/state")" -# Correct pre 2.1 naming - FIXME in 2.1 -case "$state_should" in - installed) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="present" - ;; - removed) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="absent" - ;; -esac - # FIXME: use grep directly, state is a list, not a line! state_is="$(cat "$__object/explorer/state")" case "$state_is" in diff --git a/conf/type/__package_apt/man.text b/conf/type/__package_apt/man.text index fd9c1a9c..5848a131 100644 --- a/conf/type/__package_apt/man.text +++ b/conf/type/__package_apt/man.text @@ -18,7 +18,6 @@ REQUIRED PARAMETERS ------------------- state:: The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS @@ -50,5 +49,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is +Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__package_luarocks/gencode-remote b/conf/type/__package_luarocks/gencode-remote index 327f812c..1046a936 100755 --- a/conf/type/__package_luarocks/gencode-remote +++ b/conf/type/__package_luarocks/gencode-remote @@ -30,18 +30,6 @@ else fi state_should="$(cat "$__object/parameter/state")" -# Correct pre 2.1 naming - FIXME in 2.1 -case "$state_should" in - installed) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="present" - ;; - removed) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="absent" - ;; -esac - if grep -q "(installed)" "$__object/explorer/pkg_status"; then state_is="present" diff --git a/conf/type/__package_luarocks/man.text b/conf/type/__package_luarocks/man.text index 8b041b7c..75ac93fb 100644 --- a/conf/type/__package_luarocks/man.text +++ b/conf/type/__package_luarocks/man.text @@ -17,7 +17,6 @@ REQUIRED PARAMETERS ------------------- state:: The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS diff --git a/conf/type/__package_opkg/gencode-remote b/conf/type/__package_opkg/gencode-remote index bd9a599b..ab8b5ee8 100755 --- a/conf/type/__package_opkg/gencode-remote +++ b/conf/type/__package_opkg/gencode-remote @@ -54,4 +54,3 @@ if [ "$state_is" != "$state_should" ]; then ;; esac fi - diff --git a/conf/type/__package_pacman/gencode-remote b/conf/type/__package_pacman/gencode-remote index e585ee86..da1ac7c2 100755 --- a/conf/type/__package_pacman/gencode-remote +++ b/conf/type/__package_pacman/gencode-remote @@ -32,16 +32,6 @@ else fi state_should="$(cat "$__object/parameter/state")" -case "$state_should" in - installed) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="present" - ;; - removed) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="absent" - ;; -esac pkg_version="$(cat "$__object/explorer/pkg_version")" if [ -z "$pkg_version" ]; then diff --git a/conf/type/__package_pacman/man.text b/conf/type/__package_pacman/man.text index fe2abac8..4c23a2bd 100644 --- a/conf/type/__package_pacman/man.text +++ b/conf/type/__package_pacman/man.text @@ -18,7 +18,6 @@ REQUIRED PARAMETERS ------------------- state:: The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS diff --git a/conf/type/__package_pkg_freebsd/gencode-remote b/conf/type/__package_pkg_freebsd/gencode-remote index ef6632c0..21120d41 100755 --- a/conf/type/__package_pkg_freebsd/gencode-remote +++ b/conf/type/__package_pkg_freebsd/gencode-remote @@ -133,4 +133,3 @@ fi # Debug #set +x - diff --git a/conf/type/__package_pkg_freebsd/man.text b/conf/type/__package_pkg_freebsd/man.text index f41ac47a..fd9a6792 100644 --- a/conf/type/__package_pkg_freebsd/man.text +++ b/conf/type/__package_pkg_freebsd/man.text @@ -39,16 +39,16 @@ EXAMPLES -------------------------------------------------------------------------------- # Ensure zsh is installed -__package_pkg_freebsd zsh --state installed +__package_pkg_freebsd zsh --state present # Ensure vim is installed, use flavor no_x11 -__package_pkg_freebsd vim --state installed --flavor no_x11 +__package_pkg_freebsd vim --state present --flavor no_x11 # If you don't want to follow pythonX packages, but always use python -__package_pkg_freebsd python --state installed --name python2 +__package_pkg_freebsd python --state present --name python2 # Remove obsolete package -__package_pkg_freebsd puppet --state removed +__package_pkg_freebsd puppet --state absent -------------------------------------------------------------------------------- diff --git a/conf/type/__package_pkg_openbsd/gencode-remote b/conf/type/__package_pkg_openbsd/gencode-remote index 26dd4689..ed36f04a 100755 --- a/conf/type/__package_pkg_openbsd/gencode-remote +++ b/conf/type/__package_pkg_openbsd/gencode-remote @@ -43,17 +43,6 @@ else fi state_should="$(cat "$__object/parameter/state")" -# Correct pre 2.1 naming - FIXME in 2.1 -case "$state_should" in - installed) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="present" - ;; - removed) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="absent" - ;; -esac pkg_version="$(cat "$__object/explorer/pkg_version")" diff --git a/conf/type/__package_pkg_openbsd/man.text b/conf/type/__package_pkg_openbsd/man.text index 71cf9d4e..19bb2094 100644 --- a/conf/type/__package_pkg_openbsd/man.text +++ b/conf/type/__package_pkg_openbsd/man.text @@ -17,7 +17,6 @@ REQUIRED PARAMETERS ------------------- state:: The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS diff --git a/conf/type/__package_rubygem/gencode-remote b/conf/type/__package_rubygem/gencode-remote index 638c4252..dc755ad3 100755 --- a/conf/type/__package_rubygem/gencode-remote +++ b/conf/type/__package_rubygem/gencode-remote @@ -28,17 +28,6 @@ else fi state_should="$(cat "$__object/parameter/state")" -# Correct pre 2.1 naming - FIXME in 2.1 -case "$state_should" in - installed) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="present" - ;; - removed) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="absent" - ;; -esac if grep -q true "$__object/explorer/pkg_status"; then state_is="present" diff --git a/conf/type/__package_rubygem/man.text b/conf/type/__package_rubygem/man.text index 79bb8b52..afe2b358 100644 --- a/conf/type/__package_rubygem/man.text +++ b/conf/type/__package_rubygem/man.text @@ -17,7 +17,6 @@ REQUIRED PARAMETERS ------------------- state:: The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS diff --git a/conf/type/__package_yum/gencode-remote b/conf/type/__package_yum/gencode-remote index df2bf405..5f0e8ac8 100755 --- a/conf/type/__package_yum/gencode-remote +++ b/conf/type/__package_yum/gencode-remote @@ -28,16 +28,6 @@ else fi state_should="$(cat "$__object/parameter/state")" -case "$state_should" in - installed) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="present" - ;; - removed) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="absent" - ;; -esac if grep -q -E "(centos|redhat|amazon)" "$__global/explorer/os"; then opts="-y --quiet" diff --git a/conf/type/__package_yum/man.text b/conf/type/__package_yum/man.text index 9dfb394e..4aa3ddc0 100644 --- a/conf/type/__package_yum/man.text +++ b/conf/type/__package_yum/man.text @@ -19,7 +19,6 @@ REQUIRED PARAMETERS ------------------- state:: The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). OPTIONAL PARAMETERS @@ -51,5 +50,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is +Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__process/gencode-remote b/conf/type/__process/gencode-remote index 3411734e..e4519f3c 100755 --- a/conf/type/__process/gencode-remote +++ b/conf/type/__process/gencode-remote @@ -26,16 +26,6 @@ else fi state_should="$(cat "$__object/parameter/state")" -case "$state_should" in - running) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="present" - ;; - stopped) - echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 - state_should="absent" - ;; -esac runs="$(cat "$__object/explorer/runs")" if [ "$runs" ]; then From 3333df602b3f8c85ee092c69d23b53b304351790 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Sep 2012 11:35:56 +0200 Subject: [PATCH 1629/4212] change several type to accept only state absent/present Signed-off-by: Nico Schottelius --- doc/changelog-2.1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/changelog-2.1 b/doc/changelog-2.1 index fd03e69c..973dae99 100644 --- a/doc/changelog-2.1 +++ b/doc/changelog-2.1 @@ -8,3 +8,7 @@ Changelog (v2.1 specific) * Removed type __addifnosuchline (replaced by __line) * Removed type __removeline (replaced by __line) * Type __directory: Parameter --parents and --recursive are now boolean + * Type __package_apt, __package_luarocks, __package_opkg, + __package_pacman, __package_pkg_freebsd, __package_pkg_openbsd, + __package_rubygem, __package_yum, __process: + Parameter state accepts only "present" and "absent" From 6afec722329c296eeb772dc96a1b2ed8d018fce9 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Fri, 21 Sep 2012 10:06:16 -0400 Subject: [PATCH 1630/4212] Implement Nico's suggestions Modified behavior of cksum explorer to print nothing if the file doesn't exist Modified gencode-local to reflect cksum's new behavior Modified gencode-remote to check states explicitly and error on invalid state. --- conf/type/__pf_ruleset/explorer/cksum | 2 -- conf/type/__pf_ruleset/gencode-local | 2 +- conf/type/__pf_ruleset/gencode-remote | 28 ++++++++++++++------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/conf/type/__pf_ruleset/explorer/cksum b/conf/type/__pf_ruleset/explorer/cksum index ce188ba0..f8679836 100755 --- a/conf/type/__pf_ruleset/explorer/cksum +++ b/conf/type/__pf_ruleset/explorer/cksum @@ -34,8 +34,6 @@ PFCONF="${TMP:-"/etc/pf.conf"}" if [ -f "${PFCONF}" ]; then # The pf config file exists, find its cksum. cksum -o 1 ${PFCONF} | cut -d= -f2 | awk '{print $1}' -else # the pf config file doesn't exist - echo NOTEXIST fi # Debug diff --git a/conf/type/__pf_ruleset/gencode-local b/conf/type/__pf_ruleset/gencode-local index b1ee6a14..c2495509 100644 --- a/conf/type/__pf_ruleset/gencode-local +++ b/conf/type/__pf_ruleset/gencode-local @@ -59,7 +59,7 @@ case $uname in ;; esac -if [ ! "${cksum}" = "NOTEXIST" ]; then +if [ -n "${cksum}" ]; then if [ ! "\${currentSum}" = "${cksum}" ]; then $__remote_copy "${source}" "$__target_host:${rcvar}.new" fi diff --git a/conf/type/__pf_ruleset/gencode-remote b/conf/type/__pf_ruleset/gencode-remote index e5eece64..6e9030ea 100644 --- a/conf/type/__pf_ruleset/gencode-remote +++ b/conf/type/__pf_ruleset/gencode-remote @@ -28,20 +28,22 @@ # Remove ${rcvar} in the case of --state absent state=$(cat "$__object/parameter/state") - -if [ ! "$state" = "absent" ]; then # There is nothing more for a *remote* script to do - exit 0 -fi - rcvar=$(cat "$__object/explorer/rcvar") -# --state absent, so ensure that .new doesn't exist and that conf is renamed to .old -cat <&2 + exit 1 +fi From 9a45333e82327a4754be0d54c3b083c717cf961e Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Fri, 21 Sep 2012 10:11:56 -0400 Subject: [PATCH 1631/4212] Implement Nico's suggestions Removed unnecessary code from gencode-remote --- conf/type/__pf_apply/gencode-remote | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/conf/type/__pf_apply/gencode-remote b/conf/type/__pf_apply/gencode-remote index 3045ee60..f7c889b4 100755 --- a/conf/type/__pf_apply/gencode-remote +++ b/conf/type/__pf_apply/gencode-remote @@ -34,24 +34,13 @@ if [ -f "${rcvar}.old" ]; then # rcvar.old exists, we must need to disable pf pfctl -d || true # Cleanup rm -f "${rcvar}.old" - # This file shouldn't exist, but just in case... - if [ -f "${rcvar}" ]; then - rm -f "${rcvar}" - fi elif [ -f "${rcvar}.new" ]; then # rcvar.new exists, we must need to apply it # Ensure that pf is enabled in the first place # If it already is enabled, pfctl -e returns 1, go on with life - if [ -f "${rcvar}" ]; then - rm -f "${rcvar}" - fi mv "${rcvar}.new" "${rcvar}" pfctl -e || true pfctl -f "${rcvar}" - ret="$?" - # Cleanup - # This file shouldn't exist, but just in case - rm -f "${rcvar}.old" - if [ "\$ret" -ne "0" ]; then # failed to configure new ruleset + if [ "\$?" -ne "0" ]; then # failed to configure new ruleset echo "Failed to configure the new ruleset on ${__target_host}!" >&2 fi fi From 5761787b8482abd2c70b88288071c36625227e3a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Sep 2012 20:18:50 +0200 Subject: [PATCH 1632/4212] remove obsolete reference to tmp_dir Signed-off-by: Nico Schottelius --- doc/man/cdist-reference.text.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 2aa87aa1..3f9f7002 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -133,10 +133,6 @@ out/object/:: out/object//explorers:: Output of type specific explorers, per object. -tmp_dir:: - A tempdir and a tempfile is used by cdist internally, - which will be removed when the scripts end automatically. - TYPES ----- The following types are available: From 550ff8c7277e90aa0ae395b77eec3b34f43db2eb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Sep 2012 20:23:03 +0200 Subject: [PATCH 1633/4212] cleanup reference Signed-off-by: Nico Schottelius --- doc/man/cdist-reference.text.sh | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 3f9f7002..3f4f7c98 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -65,16 +65,16 @@ conf/:: Contains the (static) configuration like manifests, types and explorers. conf/manifest/init:: - This is the central entry point used by cdist-manifest-init(1). + This is the central entry point. It is an executable (+x bit set) shell script that can use values from the explorers to decide which configuration to create for the specified target host. - It should be primary used to define mapping from configurations to hosts. + Its intent is to used to define mapping from configurations to hosts. conf/manifest/*:: All other files in this directory are not directly used by cdist, but you can seperate configuration mappings, if you have a lot of code in the - manifest/init file. This may also be helpful to have different admins + conf/manifest/init file. This may also be helpful to have different admins maintain different groups of hosts. conf/explorer/:: @@ -96,10 +96,10 @@ conf/type//manifest:: Used to generate additional objects from a type. conf/type//gencode-local:: - Used to generate code to be executed on the server. + Used to generate code to be executed on the source host conf/type//gencode-remote:: - Used to generate code to be executed on the client. + Used to generate code to be executed on the target host conf/type//parameter/required:: Parameters required by type, \n seperated list. @@ -184,10 +184,9 @@ __object_id:: the filesystem database and ensured by the core). Note: Double slashes ("//") will not be fixed and result in an error. - __self:: DEPRECATED: Same as __object_name, do not use anymore, use __object_name instead. - Will be removed in cdist 3.x. + Will be removed in cdist 2.1. __object_name:: The full qualified name of the current object. Available for: type manifest, type explorer, type gencode From 57ed946414a9fe66bf5738ac6b287b56eed334d6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Sep 2012 20:25:37 +0200 Subject: [PATCH 1634/4212] Remove __self variable Signed-off-by: Nico Schottelius --- doc/changelog-2.1 | 1 + doc/man/cdist-reference.text.sh | 3 --- lib/cdist/core/code.py | 1 - lib/cdist/core/manifest.py | 1 - lib/cdist/test/code/__init__.py | 2 -- .../code/fixtures/conf/type/__dump_environment/gencode-local | 1 - lib/cdist/test/manifest/__init__.py | 1 - 7 files changed, 1 insertion(+), 9 deletions(-) diff --git a/doc/changelog-2.1 b/doc/changelog-2.1 index 973dae99..6398e7dc 100644 --- a/doc/changelog-2.1 +++ b/doc/changelog-2.1 @@ -5,6 +5,7 @@ Changelog (v2.1 specific) * Exception: No braces means author == Nico Schottelius 2.1.0: + * Core: Removed obsolete variable __self * Removed type __addifnosuchline (replaced by __line) * Removed type __removeline (replaced by __line) * Type __directory: Parameter --parents and --recursive are now boolean diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 3f4f7c98..cf1b852f 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -184,9 +184,6 @@ __object_id:: the filesystem database and ensured by the core). Note: Double slashes ("//") will not be fixed and result in an error. -__self:: - DEPRECATED: Same as __object_name, do not use anymore, use __object_name instead. - Will be removed in cdist 2.1. __object_name:: The full qualified name of the current object. Available for: type manifest, type explorer, type gencode diff --git a/lib/cdist/core/code.py b/lib/cdist/core/code.py index 2ffef9cf..fa1ed3c1 100644 --- a/lib/cdist/core/code.py +++ b/lib/cdist/core/code.py @@ -103,7 +103,6 @@ class Code(object): '__object': cdist_object.absolute_path, '__object_id': cdist_object.object_id, '__object_name': cdist_object.name, - '__self': cdist_object.name, }) return self.local.run_script(script, env=env, return_output=True) diff --git a/lib/cdist/core/manifest.py b/lib/cdist/core/manifest.py index 4b798883..5faeccd1 100644 --- a/lib/cdist/core/manifest.py +++ b/lib/cdist/core/manifest.py @@ -96,7 +96,6 @@ class Manifest(object): '__object': cdist_object.absolute_path, '__object_id': cdist_object.object_id, '__object_name': cdist_object.name, - '__self': cdist_object.name, '__type': cdist_object.cdist_type.absolute_path, '__cdist_manifest': script, }) diff --git a/lib/cdist/test/code/__init__.py b/lib/cdist/test/code/__init__.py index dc701cce..8a8583d7 100644 --- a/lib/cdist/test/code/__init__.py +++ b/lib/cdist/test/code/__init__.py @@ -78,7 +78,6 @@ class CodeTestCase(test.CdistTestCase): self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) self.assertEqual(output_dict['__object_name'], self.cdist_object.name) - self.assertEqual(output_dict['__self'], self.cdist_object.name) def test_run_gencode_remote_environment(self): output_string = self.code.run_gencode_remote(self.cdist_object) @@ -94,7 +93,6 @@ class CodeTestCase(test.CdistTestCase): self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) self.assertEqual(output_dict['__object_name'], self.cdist_object.name) - self.assertEqual(output_dict['__self'], self.cdist_object.name) def test_transfer_code_remote(self): self.cdist_object.code_remote = self.code.run_gencode_remote(self.cdist_object) diff --git a/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local b/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local index ed1265c9..771894fb 100755 --- a/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local +++ b/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local @@ -6,4 +6,3 @@ echo "echo __type: $__type" echo "echo __object: $__object" echo "echo __object_id: $__object_id" echo "echo __object_name: $__object_name" -echo "echo __self: $__self" diff --git a/lib/cdist/test/manifest/__init__.py b/lib/cdist/test/manifest/__init__.py index a188c788..a9846b1d 100644 --- a/lib/cdist/test/manifest/__init__.py +++ b/lib/cdist/test/manifest/__init__.py @@ -101,7 +101,6 @@ class ManifestTestCase(test.CdistTestCase): self.assertEqual(output_dict['__object'], cdist_object.absolute_path) self.assertEqual(output_dict['__object_id'], cdist_object.object_id) self.assertEqual(output_dict['__object_name'], cdist_object.name) - self.assertEqual(output_dict['__self'], cdist_object.name) def test_debug_env_setup(self): self.log.setLevel(logging.DEBUG) From 07902f2a0b09729bd09c3b60eaac8d43390a2267 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 1 Oct 2012 17:52:19 +0200 Subject: [PATCH 1635/4212] ++changes(2.0.15) Signed-off-by: Nico Schottelius --- doc/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changelog b/doc/changelog index 2f9ecef5..39ee0fad 100644 --- a/doc/changelog +++ b/doc/changelog @@ -8,6 +8,8 @@ Changelog * Core: Make variable __object_name available in type explorers (Steven Armtrong) * New Type: __qemu_img * New Type: __line + * New Type: __pf_apply (Jake Guffey) + * New Type: __pf_ruleset (Jake Guffey) 2.0.14: 2012-09-07 * Bugfix Type: __jail: Use correct variable (Jake Guffey) From 62c69c63b51d23e6277bfda948efd36fc0a27aa6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 2 Oct 2012 18:05:47 +0200 Subject: [PATCH 1636/4212] support root and user rvm Signed-off-by: Nico Schottelius --- conf/type/__rvm/explorer/state | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/conf/type/__rvm/explorer/state b/conf/type/__rvm/explorer/state index d0da0d86..f43f5509 100755 --- a/conf/type/__rvm/explorer/state +++ b/conf/type/__rvm/explorer/state @@ -19,8 +19,18 @@ # user="$__object_id" -if su - $user -c "[ -d \"\$HOME/.rvm\" ]" ; then - echo "present" + +# RVM behaves differently if root is the username / uid == 0 +if [ "$user" = "root" ]; then + if [ -d /usr/local/rvm ]; then + echo present + else + echo absent + fi else - echo "absent" + if su - $user -c "[ -d \"\$HOME/.rvm\" ]" ; then + echo "present" + else + echo "absent" + fi fi From 748fc8a258d52474ca2e2e811d1ff53a316472b0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 2 Oct 2012 18:06:15 +0200 Subject: [PATCH 1637/4212] support installing, even if rvm is already present Signed-off-by: Nico Schottelius --- conf/type/__rvm/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__rvm/gencode-remote b/conf/type/__rvm/gencode-remote index 6c661302..aa6ef647 100755 --- a/conf/type/__rvm/gencode-remote +++ b/conf/type/__rvm/gencode-remote @@ -25,7 +25,7 @@ if [ "$state_is" != "$state_should" ]; then case "$state_should" in present) cat << DONE -su - $user -c "curl -L get.rvm.io | bash -s stable" +su - $user -c "unset rvm_path; unset rvm_bin_path; unset rvm_prefix; unset rvm_version; curl -L get.rvm.io | bash -s stable" DONE ;; absent) From 8c0228bbaadfb7b6252959908bfc062af2f3a184 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 2 Oct 2012 18:09:52 +0200 Subject: [PATCH 1638/4212] allow failing cat on optional parameter Signed-off-by: Nico Schottelius --- conf/type/__rvm_gemset/gencode-remote | 2 +- conf/type/__rvm_ruby/gencode-remote | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/conf/type/__rvm_gemset/gencode-remote b/conf/type/__rvm_gemset/gencode-remote index 75cc833a..1604538d 100755 --- a/conf/type/__rvm_gemset/gencode-remote +++ b/conf/type/__rvm_gemset/gencode-remote @@ -23,7 +23,7 @@ ruby="$(echo "$gemset" | cut -d '@' -f 1)" gemsetname="$(echo "$gemset" | cut -d '@' -f 2)" state_is="$(cat "$__object/explorer/state")" user="$(cat "$__object/parameter/user")" -default="$(cat "$__object/parameter/default")" +default="$(cat "$__object/parameter/default" 2>/dev/null || true)" state_should="$(cat "$__object/parameter/state")" if [ "$state_is" != "$state_should" ]; then case "$state_should" in diff --git a/conf/type/__rvm_ruby/gencode-remote b/conf/type/__rvm_ruby/gencode-remote index b25b4fe9..0003cfe7 100755 --- a/conf/type/__rvm_ruby/gencode-remote +++ b/conf/type/__rvm_ruby/gencode-remote @@ -21,8 +21,9 @@ ruby="$__object_id" state_is="$(cat "$__object/explorer/state")" user="$(cat "$__object/parameter/user")" -default="$(cat "$__object/parameter/default")" +default="$(cat "$__object/parameter/default" 2>/dev/null || true)" state_should="$(cat "$__object/parameter/state")" + if [ "$state_is" != "$state_should" ]; then case "$state_should" in present) From 57adc731c45f1d2876c32d9db02e5e9a5fb99bf1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 2 Oct 2012 18:11:16 +0200 Subject: [PATCH 1639/4212] ++changes(2.0.15) - Fixes #66 Signed-off-by: Nico Schottelius --- doc/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog b/doc/changelog index 39ee0fad..05d6d96b 100644 --- a/doc/changelog +++ b/doc/changelog @@ -10,6 +10,7 @@ Changelog * New Type: __line * New Type: __pf_apply (Jake Guffey) * New Type: __pf_ruleset (Jake Guffey) + * Bugfix Type: __rvm: Make type work if rvm is already installed 2.0.14: 2012-09-07 * Bugfix Type: __jail: Use correct variable (Jake Guffey) From 61394f390976183d1f8c35c9a219ea683fb9df15 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 4 Oct 2012 10:10:41 +0200 Subject: [PATCH 1640/4212] correct comment Signed-off-by: Nico Schottelius --- conf/type/__qemu_img/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/type/__qemu_img/man.text b/conf/type/__qemu_img/man.text index e2442172..3e16f957 100644 --- a/conf/type/__qemu_img/man.text +++ b/conf/type/__qemu_img/man.text @@ -32,7 +32,7 @@ EXAMPLES -------- -------------------------------------------------------------------------------- -# Ensure zsh in installed +# Create a 50G size image __qemu_img /home/services/kvm/vm/myvmname/system-disk --size 50G # Remove image From 1fef54ecdfd90d3dd02e489119250957259dab65 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Sun, 7 Oct 2012 11:51:15 -0400 Subject: [PATCH 1641/4212] Fix __package* state usage Removed __package*/parameter/required Added state to __package*/parameter/optional Modified man pages for __package* Added optional check for state parameter Defaulted state parameter to "present" --- conf/type/__package/man.text | 8 +++++--- conf/type/__package/parameter/optional | 1 + conf/type/__package/parameter/required | 1 - conf/type/__package_apt/gencode-remote | 6 +++++- conf/type/__package_apt/man.text | 8 +++++--- conf/type/__package_apt/parameter/optional | 1 + conf/type/__package_apt/parameter/required | 1 - conf/type/__package_luarocks/gencode-remote | 6 +++++- conf/type/__package_luarocks/man.text | 8 +++++--- conf/type/__package_luarocks/parameter/optional | 1 + conf/type/__package_luarocks/parameter/required | 1 - conf/type/__package_opkg/gencode-remote | 7 ++++++- conf/type/__package_opkg/man.text | 6 ++++-- conf/type/__package_opkg/parameter/optional | 1 + conf/type/__package_opkg/parameter/required | 1 - conf/type/__package_pacman/gencode-remote | 6 +++++- conf/type/__package_pacman/man.text | 8 +++++--- conf/type/__package_pacman/parameter/optional | 1 + conf/type/__package_pacman/parameter/required | 1 - conf/type/__package_pip/gencode-remote | 6 +++++- conf/type/__package_pip/man.text | 6 ++++-- conf/type/__package_pip/parameter/optional | 1 + conf/type/__package_pip/parameter/required | 1 - conf/type/__package_pkg_freebsd/gencode-remote | 6 +++++- conf/type/__package_pkg_freebsd/man.text | 6 ++++-- conf/type/__package_pkg_freebsd/parameter/optional | 1 + conf/type/__package_pkg_freebsd/parameter/required | 1 - conf/type/__package_pkg_openbsd/gencode-remote | 6 +++++- conf/type/__package_pkg_openbsd/man.text | 8 +++++--- conf/type/__package_pkg_openbsd/parameter/optional | 1 + conf/type/__package_pkg_openbsd/parameter/required | 1 - conf/type/__package_rubygem/gencode-remote | 6 +++++- conf/type/__package_rubygem/man.text | 8 +++++--- conf/type/__package_rubygem/parameter/optional | 1 + conf/type/__package_rubygem/parameter/required | 1 - conf/type/__package_yum/gencode-remote | 6 +++++- conf/type/__package_yum/man.text | 8 +++++--- conf/type/__package_yum/parameter/optional | 1 + conf/type/__package_yum/parameter/required | 1 - conf/type/__package_zypper/gencode-remote | 6 +++++- conf/type/__package_zypper/man.text | 6 ++++-- conf/type/__package_zypper/parameter/optional | 1 + conf/type/__package_zypper/parameter/required | 1 - 43 files changed, 113 insertions(+), 50 deletions(-) delete mode 100644 conf/type/__package/parameter/required delete mode 100644 conf/type/__package_apt/parameter/required delete mode 100644 conf/type/__package_luarocks/parameter/required delete mode 100644 conf/type/__package_opkg/parameter/required delete mode 100644 conf/type/__package_pacman/parameter/required delete mode 100644 conf/type/__package_pip/parameter/required delete mode 100644 conf/type/__package_pkg_freebsd/parameter/required delete mode 100644 conf/type/__package_pkg_openbsd/parameter/required delete mode 100644 conf/type/__package_rubygem/parameter/required delete mode 100644 conf/type/__package_yum/parameter/required delete mode 100644 conf/type/__package_zypper/parameter/required diff --git a/conf/type/__package/man.text b/conf/type/__package/man.text index 071a8bfb..9ad9747a 100644 --- a/conf/type/__package/man.text +++ b/conf/type/__package/man.text @@ -16,9 +16,7 @@ It dispatches the actual work to the package system dependant types. REQUIRED PARAMETERS ------------------- -state:: - The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). +None OPTIONAL PARAMETERS @@ -35,6 +33,10 @@ type:: e.g. __package_apt for Debian __package_emerge for Gentoo +state:: + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). + EXAMPLES -------- diff --git a/conf/type/__package/parameter/optional b/conf/type/__package/parameter/optional index 6f793411..9982507e 100644 --- a/conf/type/__package/parameter/optional +++ b/conf/type/__package/parameter/optional @@ -2,3 +2,4 @@ name version type pkgsite +state diff --git a/conf/type/__package/parameter/required b/conf/type/__package/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/conf/type/__package/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state diff --git a/conf/type/__package_apt/gencode-remote b/conf/type/__package_apt/gencode-remote index 0bcdb946..14b2f884 100755 --- a/conf/type/__package_apt/gencode-remote +++ b/conf/type/__package_apt/gencode-remote @@ -27,7 +27,11 @@ else name="$__object_id" fi -state_should="$(cat "$__object/parameter/state")" +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi # Correct pre 2.1 naming - FIXME in 2.1 case "$state_should" in diff --git a/conf/type/__package_apt/man.text b/conf/type/__package_apt/man.text index fd9c1a9c..7e880054 100644 --- a/conf/type/__package_apt/man.text +++ b/conf/type/__package_apt/man.text @@ -16,9 +16,7 @@ manage packages. REQUIRED PARAMETERS ------------------- -state:: - The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). +None OPTIONAL PARAMETERS @@ -26,6 +24,10 @@ OPTIONAL PARAMETERS name:: If supplied, use the name and not the object id as the package name. +state:: + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). + EXAMPLES -------- diff --git a/conf/type/__package_apt/parameter/optional b/conf/type/__package_apt/parameter/optional index a52167d3..41b8e6cf 100644 --- a/conf/type/__package_apt/parameter/optional +++ b/conf/type/__package_apt/parameter/optional @@ -1,2 +1,3 @@ name version +state diff --git a/conf/type/__package_apt/parameter/required b/conf/type/__package_apt/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/conf/type/__package_apt/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state diff --git a/conf/type/__package_luarocks/gencode-remote b/conf/type/__package_luarocks/gencode-remote index 327f812c..e8a7240c 100755 --- a/conf/type/__package_luarocks/gencode-remote +++ b/conf/type/__package_luarocks/gencode-remote @@ -29,7 +29,11 @@ else name="$__object_id" fi -state_should="$(cat "$__object/parameter/state")" +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi # Correct pre 2.1 naming - FIXME in 2.1 case "$state_should" in installed) diff --git a/conf/type/__package_luarocks/man.text b/conf/type/__package_luarocks/man.text index 8b041b7c..75083821 100644 --- a/conf/type/__package_luarocks/man.text +++ b/conf/type/__package_luarocks/man.text @@ -15,9 +15,7 @@ LuaRocks is a deployment and management system for Lua modules. REQUIRED PARAMETERS ------------------- -state:: - The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). +None OPTIONAL PARAMETERS @@ -25,6 +23,10 @@ OPTIONAL PARAMETERS name:: If supplied, use the name and not the object id as the package name. +state:: + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). + EXAMPLES -------- diff --git a/conf/type/__package_luarocks/parameter/optional b/conf/type/__package_luarocks/parameter/optional index f121bdbf..1b423dc4 100644 --- a/conf/type/__package_luarocks/parameter/optional +++ b/conf/type/__package_luarocks/parameter/optional @@ -1 +1,2 @@ name +state diff --git a/conf/type/__package_luarocks/parameter/required b/conf/type/__package_luarocks/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/conf/type/__package_luarocks/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state diff --git a/conf/type/__package_opkg/gencode-remote b/conf/type/__package_opkg/gencode-remote index bd9a599b..99f86632 100755 --- a/conf/type/__package_opkg/gencode-remote +++ b/conf/type/__package_opkg/gencode-remote @@ -28,7 +28,12 @@ else name="$__object_id" fi -state_should="$(cat "$__object/parameter/state")" +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi + state_is="$(cat "$__object/explorer/pkg_status")" case "$state_is" in absent*) diff --git a/conf/type/__package_opkg/man.text b/conf/type/__package_opkg/man.text index 19d26af6..3d02d1ce 100644 --- a/conf/type/__package_opkg/man.text +++ b/conf/type/__package_opkg/man.text @@ -15,8 +15,7 @@ opkg is usually used on OpenWRT to manage packages. REQUIRED PARAMETERS ------------------- -state:: - The state the package should be in, either "present" or "absent" +None OPTIONAL PARAMETERS @@ -24,6 +23,9 @@ OPTIONAL PARAMETERS name:: If supplied, use the name and not the object id as the package name. +state:: + The state the package should be in, either "present" or "absent" + EXAMPLES -------- diff --git a/conf/type/__package_opkg/parameter/optional b/conf/type/__package_opkg/parameter/optional index f121bdbf..1b423dc4 100644 --- a/conf/type/__package_opkg/parameter/optional +++ b/conf/type/__package_opkg/parameter/optional @@ -1 +1,2 @@ name +state diff --git a/conf/type/__package_opkg/parameter/required b/conf/type/__package_opkg/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/conf/type/__package_opkg/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state diff --git a/conf/type/__package_pacman/gencode-remote b/conf/type/__package_pacman/gencode-remote index e585ee86..9918d28d 100755 --- a/conf/type/__package_pacman/gencode-remote +++ b/conf/type/__package_pacman/gencode-remote @@ -31,7 +31,11 @@ else name="$__object_id" fi -state_should="$(cat "$__object/parameter/state")" +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi case "$state_should" in installed) echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 diff --git a/conf/type/__package_pacman/man.text b/conf/type/__package_pacman/man.text index fe2abac8..b6d07c94 100644 --- a/conf/type/__package_pacman/man.text +++ b/conf/type/__package_pacman/man.text @@ -16,9 +16,7 @@ packages. REQUIRED PARAMETERS ------------------- -state:: - The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). +None OPTIONAL PARAMETERS @@ -26,6 +24,10 @@ OPTIONAL PARAMETERS name:: If supplied, use the name and not the object id as the package name. +state:: + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). + EXAMPLES -------- diff --git a/conf/type/__package_pacman/parameter/optional b/conf/type/__package_pacman/parameter/optional index f121bdbf..1b423dc4 100644 --- a/conf/type/__package_pacman/parameter/optional +++ b/conf/type/__package_pacman/parameter/optional @@ -1 +1,2 @@ name +state diff --git a/conf/type/__package_pacman/parameter/required b/conf/type/__package_pacman/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/conf/type/__package_pacman/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state diff --git a/conf/type/__package_pip/gencode-remote b/conf/type/__package_pip/gencode-remote index 0f15abdc..3456ced2 100644 --- a/conf/type/__package_pip/gencode-remote +++ b/conf/type/__package_pip/gencode-remote @@ -22,7 +22,11 @@ # state_is=$(cat "$__object/explorer/state") -state_should=$(cat "$__object/parameter/state") +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi [ "$state_is" = "$state_should" ] && exit 0 diff --git a/conf/type/__package_pip/man.text b/conf/type/__package_pip/man.text index 2a620658..21d4f9fd 100644 --- a/conf/type/__package_pip/man.text +++ b/conf/type/__package_pip/man.text @@ -16,8 +16,7 @@ It is also included in the python virtualenv environment. REQUIRED PARAMETERS ------------------- -state:: - Either "present" or "absent". +None OPTIONAL PARAMETERS @@ -28,6 +27,9 @@ name:: pip:: Instead of using pip from PATH, use the specific pip path. +state:: + Either "present" or "absent". + EXAMPLES -------- diff --git a/conf/type/__package_pip/parameter/optional b/conf/type/__package_pip/parameter/optional index a1b589e3..f32876f7 100644 --- a/conf/type/__package_pip/parameter/optional +++ b/conf/type/__package_pip/parameter/optional @@ -1 +1,2 @@ pip +state diff --git a/conf/type/__package_pip/parameter/required b/conf/type/__package_pip/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/conf/type/__package_pip/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state diff --git a/conf/type/__package_pkg_freebsd/gencode-remote b/conf/type/__package_pkg_freebsd/gencode-remote index ef6632c0..f7dbbd7f 100755 --- a/conf/type/__package_pkg_freebsd/gencode-remote +++ b/conf/type/__package_pkg_freebsd/gencode-remote @@ -63,7 +63,11 @@ if [ -f "$__object/parameter/pkgsite" ]; then pkgsite="$(cat "$__object/parameter/pkgsite")" fi -state="$(cat "$__object/parameter/state")" +if [ -f "$__object/parameter/state" ]; then + state="$(cat "$__object/parameter/state")" +else + state="present" +fi curr_version="$(cat "$__object/explorer/pkg_version")" add_cmd="pkg_add" rm_cmd="pkg_delete" diff --git a/conf/type/__package_pkg_freebsd/man.text b/conf/type/__package_pkg_freebsd/man.text index f41ac47a..3087cae1 100644 --- a/conf/type/__package_pkg_freebsd/man.text +++ b/conf/type/__package_pkg_freebsd/man.text @@ -15,8 +15,7 @@ This type is usually used on FreeBSD to manage packages. REQUIRED PARAMETERS ------------------- -state:: - Either "present" or "absent". +None OPTIONAL PARAMETERS @@ -33,6 +32,9 @@ version:: pkgsite:: If supplied, use to install from a specific package repository. +state:: + Either "present" or "absent". + EXAMPLES -------- diff --git a/conf/type/__package_pkg_freebsd/parameter/optional b/conf/type/__package_pkg_freebsd/parameter/optional index 3fb2f29e..8cb68f98 100644 --- a/conf/type/__package_pkg_freebsd/parameter/optional +++ b/conf/type/__package_pkg_freebsd/parameter/optional @@ -2,3 +2,4 @@ name flavor version pkgsite +state diff --git a/conf/type/__package_pkg_freebsd/parameter/required b/conf/type/__package_pkg_freebsd/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/conf/type/__package_pkg_freebsd/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state diff --git a/conf/type/__package_pkg_openbsd/gencode-remote b/conf/type/__package_pkg_openbsd/gencode-remote index 26dd4689..7788c210 100755 --- a/conf/type/__package_pkg_openbsd/gencode-remote +++ b/conf/type/__package_pkg_openbsd/gencode-remote @@ -42,7 +42,11 @@ else name="$__object_id" fi -state_should="$(cat "$__object/parameter/state")" +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi # Correct pre 2.1 naming - FIXME in 2.1 case "$state_should" in installed) diff --git a/conf/type/__package_pkg_openbsd/man.text b/conf/type/__package_pkg_openbsd/man.text index 71cf9d4e..91c8d378 100644 --- a/conf/type/__package_pkg_openbsd/man.text +++ b/conf/type/__package_pkg_openbsd/man.text @@ -15,9 +15,7 @@ This type is usually used on OpenBSD to manage packages. REQUIRED PARAMETERS ------------------- -state:: - The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). +None OPTIONAL PARAMETERS @@ -28,6 +26,10 @@ name:: flavor:: If supplied, use to avoid ambiguity. +state:: + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). + EXAMPLES -------- diff --git a/conf/type/__package_pkg_openbsd/parameter/optional b/conf/type/__package_pkg_openbsd/parameter/optional index 29b123ef..77fd22b3 100644 --- a/conf/type/__package_pkg_openbsd/parameter/optional +++ b/conf/type/__package_pkg_openbsd/parameter/optional @@ -1,2 +1,3 @@ name flavor +state diff --git a/conf/type/__package_pkg_openbsd/parameter/required b/conf/type/__package_pkg_openbsd/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/conf/type/__package_pkg_openbsd/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state diff --git a/conf/type/__package_rubygem/gencode-remote b/conf/type/__package_rubygem/gencode-remote index 638c4252..059e125e 100755 --- a/conf/type/__package_rubygem/gencode-remote +++ b/conf/type/__package_rubygem/gencode-remote @@ -27,7 +27,11 @@ else name="$__object_id" fi -state_should="$(cat "$__object/parameter/state")" +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi # Correct pre 2.1 naming - FIXME in 2.1 case "$state_should" in installed) diff --git a/conf/type/__package_rubygem/man.text b/conf/type/__package_rubygem/man.text index 79bb8b52..55b202dc 100644 --- a/conf/type/__package_rubygem/man.text +++ b/conf/type/__package_rubygem/man.text @@ -15,9 +15,7 @@ Rubygems is the default package management system for the Ruby programming langu REQUIRED PARAMETERS ------------------- -state:: - The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). +None OPTIONAL PARAMETERS @@ -25,6 +23,10 @@ OPTIONAL PARAMETERS name:: If supplied, use the name and not the object id as the package name. +state:: + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). + EXAMPLES -------- diff --git a/conf/type/__package_rubygem/parameter/optional b/conf/type/__package_rubygem/parameter/optional index f121bdbf..1b423dc4 100644 --- a/conf/type/__package_rubygem/parameter/optional +++ b/conf/type/__package_rubygem/parameter/optional @@ -1 +1,2 @@ name +state diff --git a/conf/type/__package_rubygem/parameter/required b/conf/type/__package_rubygem/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/conf/type/__package_rubygem/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state diff --git a/conf/type/__package_yum/gencode-remote b/conf/type/__package_yum/gencode-remote index df2bf405..71c8034a 100755 --- a/conf/type/__package_yum/gencode-remote +++ b/conf/type/__package_yum/gencode-remote @@ -27,7 +27,11 @@ else name="$__object_id" fi -state_should="$(cat "$__object/parameter/state")" +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi case "$state_should" in installed) echo "WARNING: ${__object_name}: $state_should is deprecated and will be removed in cdist 2.1. Please change to present/absent." >&2 diff --git a/conf/type/__package_yum/man.text b/conf/type/__package_yum/man.text index 9dfb394e..30c3f308 100644 --- a/conf/type/__package_yum/man.text +++ b/conf/type/__package_yum/man.text @@ -17,9 +17,7 @@ slightly confusing error message "Error: Nothing to do". REQUIRED PARAMETERS ------------------- -state:: - The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). +None OPTIONAL PARAMETERS @@ -27,6 +25,10 @@ OPTIONAL PARAMETERS name:: If supplied, use the name and not the object id as the package name. +state:: + The state the package should be in, either "present" or "absent" + (the old values "installed" or "removed" will be removed in cdist 2.1). + EXAMPLES -------- diff --git a/conf/type/__package_yum/parameter/optional b/conf/type/__package_yum/parameter/optional index f121bdbf..1b423dc4 100644 --- a/conf/type/__package_yum/parameter/optional +++ b/conf/type/__package_yum/parameter/optional @@ -1 +1,2 @@ name +state diff --git a/conf/type/__package_yum/parameter/required b/conf/type/__package_yum/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/conf/type/__package_yum/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state diff --git a/conf/type/__package_zypper/gencode-remote b/conf/type/__package_zypper/gencode-remote index 3323d6b1..ca9aec33 100755 --- a/conf/type/__package_zypper/gencode-remote +++ b/conf/type/__package_zypper/gencode-remote @@ -33,7 +33,11 @@ else name="$__object_id" fi -state_should="$(cat "$__object/parameter/state")" +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi # Exit if nothing is needed to be done [ "$state_is" = "$state_should" ] && exit 0 diff --git a/conf/type/__package_zypper/man.text b/conf/type/__package_zypper/man.text index 9cff9706..702d51e5 100644 --- a/conf/type/__package_zypper/man.text +++ b/conf/type/__package_zypper/man.text @@ -15,8 +15,7 @@ Zypper is usually used on the SuSE distribution to manage packages. REQUIRED PARAMETERS ------------------- -state:: - The state the package should be in, either "present" or "absent" +None OPTIONAL PARAMETERS @@ -24,6 +23,9 @@ OPTIONAL PARAMETERS name:: If supplied, use the name and not the object id as the package name. +state:: + The state the package should be in, either "present" or "absent" + EXAMPLES -------- diff --git a/conf/type/__package_zypper/parameter/optional b/conf/type/__package_zypper/parameter/optional index f121bdbf..1b423dc4 100644 --- a/conf/type/__package_zypper/parameter/optional +++ b/conf/type/__package_zypper/parameter/optional @@ -1 +1,2 @@ name +state diff --git a/conf/type/__package_zypper/parameter/required b/conf/type/__package_zypper/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/conf/type/__package_zypper/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state From 1c294c72f9444af3897931eb3d064eed59075249 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 8 Oct 2012 17:24:13 +0200 Subject: [PATCH 1642/4212] document font used for cdist logo Signed-off-by: Nico Schottelius --- doc/gfx/font-used | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/gfx/font-used diff --git a/doc/gfx/font-used b/doc/gfx/font-used new file mode 100644 index 00000000..46d3e5d3 --- /dev/null +++ b/doc/gfx/font-used @@ -0,0 +1 @@ +fraktur From 4cc3baf0575235e7df491e5593409e21e5781397 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 12 Oct 2012 09:00:50 +0200 Subject: [PATCH 1643/4212] import tag Signed-off-by: Nico Schottelius --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index d37569ef..ffd0bcb5 100644 --- a/README +++ b/README @@ -350,4 +350,4 @@ with cdist on more than **60** production machines of the The CBRG is managing most of their compute clusters with cdist. - +[[!tag cdist unix]] From 661a8bf831cecd826aad4792a3a0ebd2bf667187 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 18 Oct 2012 18:31:41 +0200 Subject: [PATCH 1644/4212] problems with conflicting types - for documentation Signed-off-by: Nico Schottelius --- .../logs/2012-10-17.conflicting-types-problem | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 doc/dev/logs/2012-10-17.conflicting-types-problem diff --git a/doc/dev/logs/2012-10-17.conflicting-types-problem b/doc/dev/logs/2012-10-17.conflicting-types-problem new file mode 100644 index 00000000..a976a7f7 --- /dev/null +++ b/doc/dev/logs/2012-10-17.conflicting-types-problem @@ -0,0 +1,19 @@ +Seen error: + +INFO: dns-vm-inx01: Generating and executing code for __package/bind-chroot +INFO: dns-vm-inx01: Generating and executing code for __directory/var/named +INFO: dns-vm-snr01: Running manifest and explorers for __directory/opt/local.ch/sys/icinga/conf.d +INFO: dns-vm-inx02: Running manifest and explorers for __directory/opt/local.ch/sys +mkdir: cannot create directory `/var/named': File exists +ERROR: Command failed: ssh -o User=root -q dns-vm-inx01 umask 077; /bin/sh -e /var/lib/cdist/object/__directory/var/named/.cdist/code-remote +INFO: dns-vm-snr01: Running manifest and explorers for __directory/opt/local.ch/web +INFO: dns-vm-inx02: Running manifest and explorers for __directory/opt/local.ch/sys/bin +INFO: dns-vm-snr02: Running manifest and explorers for __directory/opt/local.ch/web + + +Problem source: + +__directory/var/named explorer detects that the directory is missing +__package/named gencode-remote installs package, which creates directory +__directory/var/named gencode-remote outputs mkdir + From 9228168bc907a2530bcc340ccc2dfbce33f81121 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 18 Oct 2012 18:34:30 +0200 Subject: [PATCH 1645/4212] update comment Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-10-17.conflicting-types-problem | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/dev/logs/2012-10-17.conflicting-types-problem b/doc/dev/logs/2012-10-17.conflicting-types-problem index a976a7f7..5f35ddf7 100644 --- a/doc/dev/logs/2012-10-17.conflicting-types-problem +++ b/doc/dev/logs/2012-10-17.conflicting-types-problem @@ -17,3 +17,11 @@ __directory/var/named explorer detects that the directory is missing __package/named gencode-remote installs package, which creates directory __directory/var/named gencode-remote outputs mkdir +Solutions: + + - don't use __directory, because __package does already the job (clean solution) + - re-run explorer before gencode-* stage + - gencode-remote would have caught that + +Not sure yet - although the latter feature has been requested, the first +solution looks better (more clean) to this problem. From b7a8a84bfcf25e0d3a994b8e4f17e2740441658d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 24 Oct 2012 10:21:38 +0200 Subject: [PATCH 1646/4212] do nothing by default and prevent traceback If not given the function, we get: aceback (most recent call last): File "/home/users/nico/p/cdist/core/bin/cdist", line 243, in commandline() File "/home/users/nico/p/cdist/core/bin/cdist", line 107, in commandline args.func(args) AttributeError: 'Namespace' object has no attribute 'func' Signed-off-by: Nico Schottelius --- bin/cdist | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 75047acb..6b10bd32 100755 --- a/bin/cdist +++ b/bin/cdist @@ -39,12 +39,15 @@ def commandline(): help='Set log level to info, be more verbose', action='store_true', default=False) - # Main subcommand parser + # Main parser parser['main'] = argparse.ArgumentParser(description='cdist ' + cdist.VERSION, parents=[parser['loglevel']]) parser['main'].add_argument('-V', '--version', help='Show version', action='version', version='%(prog)s ' + cdist.VERSION) + #parser['main'].set_defaults(func=commandline_main) + + # Subcommand shell parser['sub'] = parser['main'].add_subparsers(title="Commands") # Banner @@ -103,6 +106,9 @@ def commandline(): log.debug(args) args.func(args) +def commandline_main(args): + pass + def config(args): configinstall(args, mode=cdist.config.Config) From 840dbc5fc2a7f363dd99e121fcd425daebeb92ee Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 24 Oct 2012 10:22:13 +0200 Subject: [PATCH 1647/4212] enable what I've committed just before Signed-off-by: Nico Schottelius --- bin/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 6b10bd32..8002119f 100755 --- a/bin/cdist +++ b/bin/cdist @@ -45,7 +45,7 @@ def commandline(): parser['main'].add_argument('-V', '--version', help='Show version', action='version', version='%(prog)s ' + cdist.VERSION) - #parser['main'].set_defaults(func=commandline_main) + parser['main'].set_defaults(func=commandline_main) # Subcommand shell parser['sub'] = parser['main'].add_subparsers(title="Commands") From 8a8192d3d375f0813028156fc46d34f197c31fd4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 24 Oct 2012 11:16:29 +0200 Subject: [PATCH 1648/4212] Revert "enable what I've committed just before" This reverts commit 840dbc5fc2a7f363dd99e121fcd425daebeb92ee. --- bin/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 8002119f..6b10bd32 100755 --- a/bin/cdist +++ b/bin/cdist @@ -45,7 +45,7 @@ def commandline(): parser['main'].add_argument('-V', '--version', help='Show version', action='version', version='%(prog)s ' + cdist.VERSION) - parser['main'].set_defaults(func=commandline_main) + #parser['main'].set_defaults(func=commandline_main) # Subcommand shell parser['sub'] = parser['main'].add_subparsers(title="Commands") From 5315c41903e61ed0013464e201abc33f38b90e2d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 24 Oct 2012 11:16:36 +0200 Subject: [PATCH 1649/4212] Revert "do nothing by default and prevent traceback" This reverts commit b7a8a84bfcf25e0d3a994b8e4f17e2740441658d. --- bin/cdist | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/bin/cdist b/bin/cdist index 6b10bd32..75047acb 100755 --- a/bin/cdist +++ b/bin/cdist @@ -39,15 +39,12 @@ def commandline(): help='Set log level to info, be more verbose', action='store_true', default=False) - # Main parser + # Main subcommand parser parser['main'] = argparse.ArgumentParser(description='cdist ' + cdist.VERSION, parents=[parser['loglevel']]) parser['main'].add_argument('-V', '--version', help='Show version', action='version', version='%(prog)s ' + cdist.VERSION) - #parser['main'].set_defaults(func=commandline_main) - - # Subcommand shell parser['sub'] = parser['main'].add_subparsers(title="Commands") # Banner @@ -106,9 +103,6 @@ def commandline(): log.debug(args) args.func(args) -def commandline_main(args): - pass - def config(args): configinstall(args, mode=cdist.config.Config) From 6d1e4d06cf0b3052ba9806973b74b358a72ee589 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 17:17:52 +0200 Subject: [PATCH 1650/4212] doc -> docs (pypi) Signed-off-by: Nico Schottelius --- .gitignore | 16 ++++++++-------- build | 8 ++++---- {doc => docs}/changelog | 0 {doc => docs}/changelog-2.1 | 0 {doc => docs}/dev/benchmark-oprofile | 0 {doc => docs}/dev/benchmark-parallel-deploy | 0 .../dev/debug/bach25-1.6.2-373-g6fd31f8 | 0 .../dev/debug/ikq04-1.6.2-373-g6fd31f8-dbg | 0 {doc => docs}/dev/fancy-ideas | 0 {doc => docs}/dev/git-post-commit-hook | 0 {doc => docs}/dev/header | 0 {doc => docs}/dev/lastchanges | 0 {doc => docs}/dev/logs/2010-09-25 | 0 {doc => docs}/dev/logs/2010-11-02.steven | 0 {doc => docs}/dev/logs/2010-11-09 | 0 {doc => docs}/dev/logs/2010-11-21 | 0 {doc => docs}/dev/logs/2010-11-29 | 0 {doc => docs}/dev/logs/2010-12-01 | 0 .../logs/2010-12-01.handwritten/SCAN0000.PDF | Bin .../logs/2010-12-01.handwritten/SCAN0001.PDF | Bin .../logs/2010-12-01.handwritten/SCAN0002.PDF | Bin .../logs/2010-12-01.handwritten/SCAN0003.PDF | Bin .../logs/2010-12-01.handwritten/SCAN0004.PDF | Bin {doc => docs}/dev/logs/2011-01-17 | 0 {doc => docs}/dev/logs/2011-01-18.type-creation | 0 {doc => docs}/dev/logs/2011-01-24 | 0 {doc => docs}/dev/logs/2011-02-03 | 0 {doc => docs}/dev/logs/2011-02-04.steven | 0 {doc => docs}/dev/logs/2011-02-22 | 0 {doc => docs}/dev/logs/2011-02-24 | 0 {doc => docs}/dev/logs/2011-02-27 | 0 {doc => docs}/dev/logs/2011-03-03 | 0 {doc => docs}/dev/logs/2011-03-07 | 0 {doc => docs}/dev/logs/2011-03-09 | 0 {doc => docs}/dev/logs/2011-03-15 | 0 .../dev/logs/2011-03-15.file_directory_link | 0 {doc => docs}/dev/logs/2011-03-23.autorequire | 0 .../dev/logs/2011-03-23.manifest_use_explorer | 0 {doc => docs}/dev/logs/2011-03-27.pgrep | 0 .../dev/logs/2011-03-28.execution-order | 0 {doc => docs}/dev/logs/2011-04-02.yum | 0 {doc => docs}/dev/logs/2011-04-04.openbsd | 0 {doc => docs}/dev/logs/2011-04-19 | 0 .../dev/logs/2011-04-20.slashdot-articles | 0 {doc => docs}/dev/logs/2011-04-21.benchmark-eth | 0 .../2011-04-21.benchmark-from-home.with-stdout | 0 {doc => docs}/dev/logs/2011-04-27 | 0 {doc => docs}/dev/logs/2011-04-27.benchmark | 0 .../dev/logs/2011-04-27.benchmark.dash | 0 {doc => docs}/dev/logs/2011-04-27.debug-timing | 0 {doc => docs}/dev/logs/2011-05-09 | 0 {doc => docs}/dev/logs/2011-05-10 | 0 {doc => docs}/dev/logs/2011-05-10.benchmark | 0 {doc => docs}/dev/logs/2011-05-12 | 0 .../dev/logs/2011-06-13.installation-via-cdist | 0 .../dev/logs/2011-06-14.library_for_user | 0 {doc => docs}/dev/logs/2011-06-24.cinst_preos | 0 .../dev/logs/2011-06-25.trigger-graphic | 0 {doc => docs}/dev/logs/2011-07-01.type-gencode | 0 .../dev/logs/2011-07-01.type-global-explorers | 0 .../dev/logs/2011-09-08.obsolete_debugging | 0 {doc => docs}/dev/logs/2011-09-12 | 0 .../dev/logs/2011-09-12.benchmark-home | 0 {doc => docs}/dev/logs/2011-09-13 | 0 .../2011-09-16.benchmark-r815-no-control-socket | 0 ...6.benchmark-r815-no-control-socket.dmidecode | 0 {doc => docs}/dev/logs/2011-10-04 | 0 {doc => docs}/dev/logs/2011-10-05 | 0 {doc => docs}/dev/logs/2011-10-06 | 0 .../dev/logs/2011-10-06.ssh_scp_sudo_chroot | 0 .../dev/logs/2011-10-11.emulator-output | 0 {doc => docs}/dev/logs/2011-10-12 | 0 {doc => docs}/dev/logs/2011-10-13.output | 0 {doc => docs}/dev/logs/2011-10-14.error-output | 0 .../dev/logs/2011-10-15.prefix-output-missing | 0 .../2011-10-15.ugly-output-on-breaking-explorer | 0 .../dev/logs/2011-10-16.keyboardirqoutputs | 0 .../dev/logs/2011-10-18.requirement-object | 0 .../dev/logs/2011-10-18.traceback-gencode | 0 .../dev/logs/2011-11-15.startup-yannick | 0 .../dev/logs/2012-01-06.python3-in-distros | 0 {doc => docs}/dev/logs/2012-01-07.urls | 0 {doc => docs}/dev/logs/2012-01-18.urls | 0 .../2012-02-08.explorer-depends-on-another-type | 0 .../dev/logs/2012-02-10.object_id-and-slashes | 0 {doc => docs}/dev/logs/2012-02-13.dependencies | 0 {doc => docs}/dev/logs/2012-02-15.steven | 0 {doc => docs}/dev/logs/2012-02-17.keyboardirq | 0 .../dev/logs/2012-02-20.debug-jake-deps | 0 .../logs/2012-02-20.error-does-not-contain-host | 0 .../dev/logs/2012-05-24.makedirs.py-python3.1 | 0 .../dev/logs/2012-05-30.ifconfig-outputs | 0 .../dev/logs/2012-05-31.csh-compatibilty | 0 {doc => docs}/dev/logs/2012-06-06.wikipedia | 0 .../dev/logs/2012-06-15.explorer-dep-problem | 0 .../logs/2012-10-17.conflicting-types-problem | 0 {doc => docs}/dev/logs/README | 0 {doc => docs}/dev/logs/linklist | 0 {doc => docs}/dev/logs/times | 0 {doc => docs}/dev/releasechecklist | 0 {doc => docs}/dev/show_all_exported_variables | 0 {doc => docs}/dev/sync-to-testhost | 0 {doc => docs}/dev/todo/3.0 | 0 {doc => docs}/dev/todo/TAKEME | 0 {doc => docs}/dev/todo/niconext | 0 {doc => docs}/dev/todo/performance-ideas | 0 {doc => docs}/dev/todo/steven | 0 {doc => docs}/dev/todo/tests | 0 {doc => docs}/gfx/cdist-automated-inverted.png | Bin {doc => docs}/gfx/cdist-automated.png | Bin {doc => docs}/gfx/cdist-automated.text | 0 {doc => docs}/gfx/cdist-logo-cm.png | Bin {doc => docs}/gfx/cdist-logo-inverted.png | Bin {doc => docs}/gfx/cdist-logo.png | Bin {doc => docs}/gfx/cdist-logo.text | 0 {doc => docs}/gfx/font-used | 0 {doc => docs}/man/cdist-reference.text.sh | 0 {doc => docs}/man/man1/cdist.text | 0 {doc => docs}/man/man7/cdist-best-practice.text | 0 {doc => docs}/man/man7/cdist-bootstrap.text | 0 {doc => docs}/man/man7/cdist-explorer.text | 0 {doc => docs}/man/man7/cdist-hacker.text | 0 {doc => docs}/man/man7/cdist-manifest.text | 0 {doc => docs}/man/man7/cdist-quickstart.text | 0 .../man/man7/cdist-remote-exec-copy.text | 0 {doc => docs}/man/man7/cdist-stages.text | 0 {doc => docs}/man/man7/cdist-tutorial.text | 0 {doc => docs}/man/man7/cdist-type.text | 0 {doc => docs}/speeches/.gitignore | 0 .../speeches/2011-03-18_hacker_erwachen.tex | 0 {doc => docs}/speeches/2011-04-27_sans.tex | 0 {doc => docs}/speeches/2011-05-20_cosin.tex | 0 ...ist-installation-in-less-than-60-seconds.mp4 | Bin 133 files changed, 12 insertions(+), 12 deletions(-) rename {doc => docs}/changelog (100%) rename {doc => docs}/changelog-2.1 (100%) rename {doc => docs}/dev/benchmark-oprofile (100%) rename {doc => docs}/dev/benchmark-parallel-deploy (100%) rename {doc => docs}/dev/debug/bach25-1.6.2-373-g6fd31f8 (100%) rename {doc => docs}/dev/debug/ikq04-1.6.2-373-g6fd31f8-dbg (100%) rename {doc => docs}/dev/fancy-ideas (100%) rename {doc => docs}/dev/git-post-commit-hook (100%) rename {doc => docs}/dev/header (100%) rename {doc => docs}/dev/lastchanges (100%) rename {doc => docs}/dev/logs/2010-09-25 (100%) rename {doc => docs}/dev/logs/2010-11-02.steven (100%) rename {doc => docs}/dev/logs/2010-11-09 (100%) rename {doc => docs}/dev/logs/2010-11-21 (100%) rename {doc => docs}/dev/logs/2010-11-29 (100%) rename {doc => docs}/dev/logs/2010-12-01 (100%) rename {doc => docs}/dev/logs/2010-12-01.handwritten/SCAN0000.PDF (100%) rename {doc => docs}/dev/logs/2010-12-01.handwritten/SCAN0001.PDF (100%) rename {doc => docs}/dev/logs/2010-12-01.handwritten/SCAN0002.PDF (100%) rename {doc => docs}/dev/logs/2010-12-01.handwritten/SCAN0003.PDF (100%) rename {doc => docs}/dev/logs/2010-12-01.handwritten/SCAN0004.PDF (100%) rename {doc => docs}/dev/logs/2011-01-17 (100%) rename {doc => docs}/dev/logs/2011-01-18.type-creation (100%) rename {doc => docs}/dev/logs/2011-01-24 (100%) rename {doc => docs}/dev/logs/2011-02-03 (100%) rename {doc => docs}/dev/logs/2011-02-04.steven (100%) rename {doc => docs}/dev/logs/2011-02-22 (100%) rename {doc => docs}/dev/logs/2011-02-24 (100%) rename {doc => docs}/dev/logs/2011-02-27 (100%) rename {doc => docs}/dev/logs/2011-03-03 (100%) rename {doc => docs}/dev/logs/2011-03-07 (100%) rename {doc => docs}/dev/logs/2011-03-09 (100%) rename {doc => docs}/dev/logs/2011-03-15 (100%) rename {doc => docs}/dev/logs/2011-03-15.file_directory_link (100%) rename {doc => docs}/dev/logs/2011-03-23.autorequire (100%) rename {doc => docs}/dev/logs/2011-03-23.manifest_use_explorer (100%) rename {doc => docs}/dev/logs/2011-03-27.pgrep (100%) rename {doc => docs}/dev/logs/2011-03-28.execution-order (100%) rename {doc => docs}/dev/logs/2011-04-02.yum (100%) rename {doc => docs}/dev/logs/2011-04-04.openbsd (100%) rename {doc => docs}/dev/logs/2011-04-19 (100%) rename {doc => docs}/dev/logs/2011-04-20.slashdot-articles (100%) rename {doc => docs}/dev/logs/2011-04-21.benchmark-eth (100%) rename {doc => docs}/dev/logs/2011-04-21.benchmark-from-home.with-stdout (100%) rename {doc => docs}/dev/logs/2011-04-27 (100%) rename {doc => docs}/dev/logs/2011-04-27.benchmark (100%) rename {doc => docs}/dev/logs/2011-04-27.benchmark.dash (100%) rename {doc => docs}/dev/logs/2011-04-27.debug-timing (100%) rename {doc => docs}/dev/logs/2011-05-09 (100%) rename {doc => docs}/dev/logs/2011-05-10 (100%) rename {doc => docs}/dev/logs/2011-05-10.benchmark (100%) rename {doc => docs}/dev/logs/2011-05-12 (100%) rename {doc => docs}/dev/logs/2011-06-13.installation-via-cdist (100%) rename {doc => docs}/dev/logs/2011-06-14.library_for_user (100%) rename {doc => docs}/dev/logs/2011-06-24.cinst_preos (100%) rename {doc => docs}/dev/logs/2011-06-25.trigger-graphic (100%) rename {doc => docs}/dev/logs/2011-07-01.type-gencode (100%) rename {doc => docs}/dev/logs/2011-07-01.type-global-explorers (100%) rename {doc => docs}/dev/logs/2011-09-08.obsolete_debugging (100%) rename {doc => docs}/dev/logs/2011-09-12 (100%) rename {doc => docs}/dev/logs/2011-09-12.benchmark-home (100%) rename {doc => docs}/dev/logs/2011-09-13 (100%) rename {doc => docs}/dev/logs/2011-09-16.benchmark-r815-no-control-socket (100%) rename {doc => docs}/dev/logs/2011-09-16.benchmark-r815-no-control-socket.dmidecode (100%) rename {doc => docs}/dev/logs/2011-10-04 (100%) rename {doc => docs}/dev/logs/2011-10-05 (100%) rename {doc => docs}/dev/logs/2011-10-06 (100%) rename {doc => docs}/dev/logs/2011-10-06.ssh_scp_sudo_chroot (100%) rename {doc => docs}/dev/logs/2011-10-11.emulator-output (100%) rename {doc => docs}/dev/logs/2011-10-12 (100%) rename {doc => docs}/dev/logs/2011-10-13.output (100%) rename {doc => docs}/dev/logs/2011-10-14.error-output (100%) rename {doc => docs}/dev/logs/2011-10-15.prefix-output-missing (100%) rename {doc => docs}/dev/logs/2011-10-15.ugly-output-on-breaking-explorer (100%) rename {doc => docs}/dev/logs/2011-10-16.keyboardirqoutputs (100%) rename {doc => docs}/dev/logs/2011-10-18.requirement-object (100%) rename {doc => docs}/dev/logs/2011-10-18.traceback-gencode (100%) rename {doc => docs}/dev/logs/2011-11-15.startup-yannick (100%) rename {doc => docs}/dev/logs/2012-01-06.python3-in-distros (100%) rename {doc => docs}/dev/logs/2012-01-07.urls (100%) rename {doc => docs}/dev/logs/2012-01-18.urls (100%) rename {doc => docs}/dev/logs/2012-02-08.explorer-depends-on-another-type (100%) rename {doc => docs}/dev/logs/2012-02-10.object_id-and-slashes (100%) rename {doc => docs}/dev/logs/2012-02-13.dependencies (100%) rename {doc => docs}/dev/logs/2012-02-15.steven (100%) rename {doc => docs}/dev/logs/2012-02-17.keyboardirq (100%) rename {doc => docs}/dev/logs/2012-02-20.debug-jake-deps (100%) rename {doc => docs}/dev/logs/2012-02-20.error-does-not-contain-host (100%) rename {doc => docs}/dev/logs/2012-05-24.makedirs.py-python3.1 (100%) rename {doc => docs}/dev/logs/2012-05-30.ifconfig-outputs (100%) rename {doc => docs}/dev/logs/2012-05-31.csh-compatibilty (100%) rename {doc => docs}/dev/logs/2012-06-06.wikipedia (100%) rename {doc => docs}/dev/logs/2012-06-15.explorer-dep-problem (100%) rename {doc => docs}/dev/logs/2012-10-17.conflicting-types-problem (100%) rename {doc => docs}/dev/logs/README (100%) rename {doc => docs}/dev/logs/linklist (100%) rename {doc => docs}/dev/logs/times (100%) rename {doc => docs}/dev/releasechecklist (100%) rename {doc => docs}/dev/show_all_exported_variables (100%) rename {doc => docs}/dev/sync-to-testhost (100%) rename {doc => docs}/dev/todo/3.0 (100%) rename {doc => docs}/dev/todo/TAKEME (100%) rename {doc => docs}/dev/todo/niconext (100%) rename {doc => docs}/dev/todo/performance-ideas (100%) rename {doc => docs}/dev/todo/steven (100%) rename {doc => docs}/dev/todo/tests (100%) rename {doc => docs}/gfx/cdist-automated-inverted.png (100%) rename {doc => docs}/gfx/cdist-automated.png (100%) rename {doc => docs}/gfx/cdist-automated.text (100%) rename {doc => docs}/gfx/cdist-logo-cm.png (100%) rename {doc => docs}/gfx/cdist-logo-inverted.png (100%) rename {doc => docs}/gfx/cdist-logo.png (100%) rename {doc => docs}/gfx/cdist-logo.text (100%) rename {doc => docs}/gfx/font-used (100%) rename {doc => docs}/man/cdist-reference.text.sh (100%) rename {doc => docs}/man/man1/cdist.text (100%) rename {doc => docs}/man/man7/cdist-best-practice.text (100%) rename {doc => docs}/man/man7/cdist-bootstrap.text (100%) rename {doc => docs}/man/man7/cdist-explorer.text (100%) rename {doc => docs}/man/man7/cdist-hacker.text (100%) rename {doc => docs}/man/man7/cdist-manifest.text (100%) rename {doc => docs}/man/man7/cdist-quickstart.text (100%) rename {doc => docs}/man/man7/cdist-remote-exec-copy.text (100%) rename {doc => docs}/man/man7/cdist-stages.text (100%) rename {doc => docs}/man/man7/cdist-tutorial.text (100%) rename {doc => docs}/man/man7/cdist-type.text (100%) rename {doc => docs}/speeches/.gitignore (100%) rename {doc => docs}/speeches/2011-03-18_hacker_erwachen.tex (100%) rename {doc => docs}/speeches/2011-04-27_sans.tex (100%) rename {doc => docs}/speeches/2011-05-20_cosin.tex (100%) rename {doc => docs}/video/cdist-installation-in-less-than-60-seconds.mp4 (100%) diff --git a/.gitignore b/.gitignore index 69a8ea98..fe52a82f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,14 +2,14 @@ .*.swp # Ignore generated manpages -doc/man/.marker -doc/man/man1/*.1 -doc/man/man7/*.7 -doc/man/man*/*.html -doc/man/man*/*.xml -doc/man/man7/cdist-type__*.text -doc/man/man7/cdist-reference.text -doc/man/man*/docbook-xsl.css +docs/man/.marker +docs/man/man1/*.1 +docs/man/man7/*.7 +docs/man/man*/*.html +docs/man/man*/*.xml +docs/man/man7/cdist-type__*.text +docs/man/man7/cdist-reference.text +docs/man/man*/docbook-xsl.css # Ignore cdist cache for version control /cache/ diff --git a/build b/build index bec7f5a9..d3f8ca3a 100755 --- a/build +++ b/build @@ -39,10 +39,10 @@ WEBMAN=$WEBBASE/man/$version WEBPAGE=${WEBBASE}.mdwn # Documentation -MANDIR=doc/man +MANDIR=docs/man MAN1DSTDIR=${MANDIR}/man1 MAN7DSTDIR=${MANDIR}/man7 -SPEECHESDIR=doc/speeches +SPEECHESDIR=docs/speeches case "$1" in man) @@ -75,7 +75,7 @@ case "$1" in mantype) for mansrc in conf/type/*/man.text; do - dst="$(echo $mansrc | sed -e 's;conf/;cdist-;' -e 's;/;;' -e 's;/man;;' -e 's;^;doc/man/man7/;')" + dst="$(echo $mansrc | sed -e 's;conf/;cdist-;' -e 's;/;;' -e 's;/man;;' -e 's;^;docs/man/man7/;')" ln -sf "../../../$mansrc" "$dst" done ;; @@ -85,7 +85,7 @@ case "$1" in ;; release) - ./doc/dev/releasechecklist + ./docs/dev/releasechecklist ;; speeches) diff --git a/doc/changelog b/docs/changelog similarity index 100% rename from doc/changelog rename to docs/changelog diff --git a/doc/changelog-2.1 b/docs/changelog-2.1 similarity index 100% rename from doc/changelog-2.1 rename to docs/changelog-2.1 diff --git a/doc/dev/benchmark-oprofile b/docs/dev/benchmark-oprofile similarity index 100% rename from doc/dev/benchmark-oprofile rename to docs/dev/benchmark-oprofile diff --git a/doc/dev/benchmark-parallel-deploy b/docs/dev/benchmark-parallel-deploy similarity index 100% rename from doc/dev/benchmark-parallel-deploy rename to docs/dev/benchmark-parallel-deploy diff --git a/doc/dev/debug/bach25-1.6.2-373-g6fd31f8 b/docs/dev/debug/bach25-1.6.2-373-g6fd31f8 similarity index 100% rename from doc/dev/debug/bach25-1.6.2-373-g6fd31f8 rename to docs/dev/debug/bach25-1.6.2-373-g6fd31f8 diff --git a/doc/dev/debug/ikq04-1.6.2-373-g6fd31f8-dbg b/docs/dev/debug/ikq04-1.6.2-373-g6fd31f8-dbg similarity index 100% rename from doc/dev/debug/ikq04-1.6.2-373-g6fd31f8-dbg rename to docs/dev/debug/ikq04-1.6.2-373-g6fd31f8-dbg diff --git a/doc/dev/fancy-ideas b/docs/dev/fancy-ideas similarity index 100% rename from doc/dev/fancy-ideas rename to docs/dev/fancy-ideas diff --git a/doc/dev/git-post-commit-hook b/docs/dev/git-post-commit-hook similarity index 100% rename from doc/dev/git-post-commit-hook rename to docs/dev/git-post-commit-hook diff --git a/doc/dev/header b/docs/dev/header similarity index 100% rename from doc/dev/header rename to docs/dev/header diff --git a/doc/dev/lastchanges b/docs/dev/lastchanges similarity index 100% rename from doc/dev/lastchanges rename to docs/dev/lastchanges diff --git a/doc/dev/logs/2010-09-25 b/docs/dev/logs/2010-09-25 similarity index 100% rename from doc/dev/logs/2010-09-25 rename to docs/dev/logs/2010-09-25 diff --git a/doc/dev/logs/2010-11-02.steven b/docs/dev/logs/2010-11-02.steven similarity index 100% rename from doc/dev/logs/2010-11-02.steven rename to docs/dev/logs/2010-11-02.steven diff --git a/doc/dev/logs/2010-11-09 b/docs/dev/logs/2010-11-09 similarity index 100% rename from doc/dev/logs/2010-11-09 rename to docs/dev/logs/2010-11-09 diff --git a/doc/dev/logs/2010-11-21 b/docs/dev/logs/2010-11-21 similarity index 100% rename from doc/dev/logs/2010-11-21 rename to docs/dev/logs/2010-11-21 diff --git a/doc/dev/logs/2010-11-29 b/docs/dev/logs/2010-11-29 similarity index 100% rename from doc/dev/logs/2010-11-29 rename to docs/dev/logs/2010-11-29 diff --git a/doc/dev/logs/2010-12-01 b/docs/dev/logs/2010-12-01 similarity index 100% rename from doc/dev/logs/2010-12-01 rename to docs/dev/logs/2010-12-01 diff --git a/doc/dev/logs/2010-12-01.handwritten/SCAN0000.PDF b/docs/dev/logs/2010-12-01.handwritten/SCAN0000.PDF similarity index 100% rename from doc/dev/logs/2010-12-01.handwritten/SCAN0000.PDF rename to docs/dev/logs/2010-12-01.handwritten/SCAN0000.PDF diff --git a/doc/dev/logs/2010-12-01.handwritten/SCAN0001.PDF b/docs/dev/logs/2010-12-01.handwritten/SCAN0001.PDF similarity index 100% rename from doc/dev/logs/2010-12-01.handwritten/SCAN0001.PDF rename to docs/dev/logs/2010-12-01.handwritten/SCAN0001.PDF diff --git a/doc/dev/logs/2010-12-01.handwritten/SCAN0002.PDF b/docs/dev/logs/2010-12-01.handwritten/SCAN0002.PDF similarity index 100% rename from doc/dev/logs/2010-12-01.handwritten/SCAN0002.PDF rename to docs/dev/logs/2010-12-01.handwritten/SCAN0002.PDF diff --git a/doc/dev/logs/2010-12-01.handwritten/SCAN0003.PDF b/docs/dev/logs/2010-12-01.handwritten/SCAN0003.PDF similarity index 100% rename from doc/dev/logs/2010-12-01.handwritten/SCAN0003.PDF rename to docs/dev/logs/2010-12-01.handwritten/SCAN0003.PDF diff --git a/doc/dev/logs/2010-12-01.handwritten/SCAN0004.PDF b/docs/dev/logs/2010-12-01.handwritten/SCAN0004.PDF similarity index 100% rename from doc/dev/logs/2010-12-01.handwritten/SCAN0004.PDF rename to docs/dev/logs/2010-12-01.handwritten/SCAN0004.PDF diff --git a/doc/dev/logs/2011-01-17 b/docs/dev/logs/2011-01-17 similarity index 100% rename from doc/dev/logs/2011-01-17 rename to docs/dev/logs/2011-01-17 diff --git a/doc/dev/logs/2011-01-18.type-creation b/docs/dev/logs/2011-01-18.type-creation similarity index 100% rename from doc/dev/logs/2011-01-18.type-creation rename to docs/dev/logs/2011-01-18.type-creation diff --git a/doc/dev/logs/2011-01-24 b/docs/dev/logs/2011-01-24 similarity index 100% rename from doc/dev/logs/2011-01-24 rename to docs/dev/logs/2011-01-24 diff --git a/doc/dev/logs/2011-02-03 b/docs/dev/logs/2011-02-03 similarity index 100% rename from doc/dev/logs/2011-02-03 rename to docs/dev/logs/2011-02-03 diff --git a/doc/dev/logs/2011-02-04.steven b/docs/dev/logs/2011-02-04.steven similarity index 100% rename from doc/dev/logs/2011-02-04.steven rename to docs/dev/logs/2011-02-04.steven diff --git a/doc/dev/logs/2011-02-22 b/docs/dev/logs/2011-02-22 similarity index 100% rename from doc/dev/logs/2011-02-22 rename to docs/dev/logs/2011-02-22 diff --git a/doc/dev/logs/2011-02-24 b/docs/dev/logs/2011-02-24 similarity index 100% rename from doc/dev/logs/2011-02-24 rename to docs/dev/logs/2011-02-24 diff --git a/doc/dev/logs/2011-02-27 b/docs/dev/logs/2011-02-27 similarity index 100% rename from doc/dev/logs/2011-02-27 rename to docs/dev/logs/2011-02-27 diff --git a/doc/dev/logs/2011-03-03 b/docs/dev/logs/2011-03-03 similarity index 100% rename from doc/dev/logs/2011-03-03 rename to docs/dev/logs/2011-03-03 diff --git a/doc/dev/logs/2011-03-07 b/docs/dev/logs/2011-03-07 similarity index 100% rename from doc/dev/logs/2011-03-07 rename to docs/dev/logs/2011-03-07 diff --git a/doc/dev/logs/2011-03-09 b/docs/dev/logs/2011-03-09 similarity index 100% rename from doc/dev/logs/2011-03-09 rename to docs/dev/logs/2011-03-09 diff --git a/doc/dev/logs/2011-03-15 b/docs/dev/logs/2011-03-15 similarity index 100% rename from doc/dev/logs/2011-03-15 rename to docs/dev/logs/2011-03-15 diff --git a/doc/dev/logs/2011-03-15.file_directory_link b/docs/dev/logs/2011-03-15.file_directory_link similarity index 100% rename from doc/dev/logs/2011-03-15.file_directory_link rename to docs/dev/logs/2011-03-15.file_directory_link diff --git a/doc/dev/logs/2011-03-23.autorequire b/docs/dev/logs/2011-03-23.autorequire similarity index 100% rename from doc/dev/logs/2011-03-23.autorequire rename to docs/dev/logs/2011-03-23.autorequire diff --git a/doc/dev/logs/2011-03-23.manifest_use_explorer b/docs/dev/logs/2011-03-23.manifest_use_explorer similarity index 100% rename from doc/dev/logs/2011-03-23.manifest_use_explorer rename to docs/dev/logs/2011-03-23.manifest_use_explorer diff --git a/doc/dev/logs/2011-03-27.pgrep b/docs/dev/logs/2011-03-27.pgrep similarity index 100% rename from doc/dev/logs/2011-03-27.pgrep rename to docs/dev/logs/2011-03-27.pgrep diff --git a/doc/dev/logs/2011-03-28.execution-order b/docs/dev/logs/2011-03-28.execution-order similarity index 100% rename from doc/dev/logs/2011-03-28.execution-order rename to docs/dev/logs/2011-03-28.execution-order diff --git a/doc/dev/logs/2011-04-02.yum b/docs/dev/logs/2011-04-02.yum similarity index 100% rename from doc/dev/logs/2011-04-02.yum rename to docs/dev/logs/2011-04-02.yum diff --git a/doc/dev/logs/2011-04-04.openbsd b/docs/dev/logs/2011-04-04.openbsd similarity index 100% rename from doc/dev/logs/2011-04-04.openbsd rename to docs/dev/logs/2011-04-04.openbsd diff --git a/doc/dev/logs/2011-04-19 b/docs/dev/logs/2011-04-19 similarity index 100% rename from doc/dev/logs/2011-04-19 rename to docs/dev/logs/2011-04-19 diff --git a/doc/dev/logs/2011-04-20.slashdot-articles b/docs/dev/logs/2011-04-20.slashdot-articles similarity index 100% rename from doc/dev/logs/2011-04-20.slashdot-articles rename to docs/dev/logs/2011-04-20.slashdot-articles diff --git a/doc/dev/logs/2011-04-21.benchmark-eth b/docs/dev/logs/2011-04-21.benchmark-eth similarity index 100% rename from doc/dev/logs/2011-04-21.benchmark-eth rename to docs/dev/logs/2011-04-21.benchmark-eth diff --git a/doc/dev/logs/2011-04-21.benchmark-from-home.with-stdout b/docs/dev/logs/2011-04-21.benchmark-from-home.with-stdout similarity index 100% rename from doc/dev/logs/2011-04-21.benchmark-from-home.with-stdout rename to docs/dev/logs/2011-04-21.benchmark-from-home.with-stdout diff --git a/doc/dev/logs/2011-04-27 b/docs/dev/logs/2011-04-27 similarity index 100% rename from doc/dev/logs/2011-04-27 rename to docs/dev/logs/2011-04-27 diff --git a/doc/dev/logs/2011-04-27.benchmark b/docs/dev/logs/2011-04-27.benchmark similarity index 100% rename from doc/dev/logs/2011-04-27.benchmark rename to docs/dev/logs/2011-04-27.benchmark diff --git a/doc/dev/logs/2011-04-27.benchmark.dash b/docs/dev/logs/2011-04-27.benchmark.dash similarity index 100% rename from doc/dev/logs/2011-04-27.benchmark.dash rename to docs/dev/logs/2011-04-27.benchmark.dash diff --git a/doc/dev/logs/2011-04-27.debug-timing b/docs/dev/logs/2011-04-27.debug-timing similarity index 100% rename from doc/dev/logs/2011-04-27.debug-timing rename to docs/dev/logs/2011-04-27.debug-timing diff --git a/doc/dev/logs/2011-05-09 b/docs/dev/logs/2011-05-09 similarity index 100% rename from doc/dev/logs/2011-05-09 rename to docs/dev/logs/2011-05-09 diff --git a/doc/dev/logs/2011-05-10 b/docs/dev/logs/2011-05-10 similarity index 100% rename from doc/dev/logs/2011-05-10 rename to docs/dev/logs/2011-05-10 diff --git a/doc/dev/logs/2011-05-10.benchmark b/docs/dev/logs/2011-05-10.benchmark similarity index 100% rename from doc/dev/logs/2011-05-10.benchmark rename to docs/dev/logs/2011-05-10.benchmark diff --git a/doc/dev/logs/2011-05-12 b/docs/dev/logs/2011-05-12 similarity index 100% rename from doc/dev/logs/2011-05-12 rename to docs/dev/logs/2011-05-12 diff --git a/doc/dev/logs/2011-06-13.installation-via-cdist b/docs/dev/logs/2011-06-13.installation-via-cdist similarity index 100% rename from doc/dev/logs/2011-06-13.installation-via-cdist rename to docs/dev/logs/2011-06-13.installation-via-cdist diff --git a/doc/dev/logs/2011-06-14.library_for_user b/docs/dev/logs/2011-06-14.library_for_user similarity index 100% rename from doc/dev/logs/2011-06-14.library_for_user rename to docs/dev/logs/2011-06-14.library_for_user diff --git a/doc/dev/logs/2011-06-24.cinst_preos b/docs/dev/logs/2011-06-24.cinst_preos similarity index 100% rename from doc/dev/logs/2011-06-24.cinst_preos rename to docs/dev/logs/2011-06-24.cinst_preos diff --git a/doc/dev/logs/2011-06-25.trigger-graphic b/docs/dev/logs/2011-06-25.trigger-graphic similarity index 100% rename from doc/dev/logs/2011-06-25.trigger-graphic rename to docs/dev/logs/2011-06-25.trigger-graphic diff --git a/doc/dev/logs/2011-07-01.type-gencode b/docs/dev/logs/2011-07-01.type-gencode similarity index 100% rename from doc/dev/logs/2011-07-01.type-gencode rename to docs/dev/logs/2011-07-01.type-gencode diff --git a/doc/dev/logs/2011-07-01.type-global-explorers b/docs/dev/logs/2011-07-01.type-global-explorers similarity index 100% rename from doc/dev/logs/2011-07-01.type-global-explorers rename to docs/dev/logs/2011-07-01.type-global-explorers diff --git a/doc/dev/logs/2011-09-08.obsolete_debugging b/docs/dev/logs/2011-09-08.obsolete_debugging similarity index 100% rename from doc/dev/logs/2011-09-08.obsolete_debugging rename to docs/dev/logs/2011-09-08.obsolete_debugging diff --git a/doc/dev/logs/2011-09-12 b/docs/dev/logs/2011-09-12 similarity index 100% rename from doc/dev/logs/2011-09-12 rename to docs/dev/logs/2011-09-12 diff --git a/doc/dev/logs/2011-09-12.benchmark-home b/docs/dev/logs/2011-09-12.benchmark-home similarity index 100% rename from doc/dev/logs/2011-09-12.benchmark-home rename to docs/dev/logs/2011-09-12.benchmark-home diff --git a/doc/dev/logs/2011-09-13 b/docs/dev/logs/2011-09-13 similarity index 100% rename from doc/dev/logs/2011-09-13 rename to docs/dev/logs/2011-09-13 diff --git a/doc/dev/logs/2011-09-16.benchmark-r815-no-control-socket b/docs/dev/logs/2011-09-16.benchmark-r815-no-control-socket similarity index 100% rename from doc/dev/logs/2011-09-16.benchmark-r815-no-control-socket rename to docs/dev/logs/2011-09-16.benchmark-r815-no-control-socket diff --git a/doc/dev/logs/2011-09-16.benchmark-r815-no-control-socket.dmidecode b/docs/dev/logs/2011-09-16.benchmark-r815-no-control-socket.dmidecode similarity index 100% rename from doc/dev/logs/2011-09-16.benchmark-r815-no-control-socket.dmidecode rename to docs/dev/logs/2011-09-16.benchmark-r815-no-control-socket.dmidecode diff --git a/doc/dev/logs/2011-10-04 b/docs/dev/logs/2011-10-04 similarity index 100% rename from doc/dev/logs/2011-10-04 rename to docs/dev/logs/2011-10-04 diff --git a/doc/dev/logs/2011-10-05 b/docs/dev/logs/2011-10-05 similarity index 100% rename from doc/dev/logs/2011-10-05 rename to docs/dev/logs/2011-10-05 diff --git a/doc/dev/logs/2011-10-06 b/docs/dev/logs/2011-10-06 similarity index 100% rename from doc/dev/logs/2011-10-06 rename to docs/dev/logs/2011-10-06 diff --git a/doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot b/docs/dev/logs/2011-10-06.ssh_scp_sudo_chroot similarity index 100% rename from doc/dev/logs/2011-10-06.ssh_scp_sudo_chroot rename to docs/dev/logs/2011-10-06.ssh_scp_sudo_chroot diff --git a/doc/dev/logs/2011-10-11.emulator-output b/docs/dev/logs/2011-10-11.emulator-output similarity index 100% rename from doc/dev/logs/2011-10-11.emulator-output rename to docs/dev/logs/2011-10-11.emulator-output diff --git a/doc/dev/logs/2011-10-12 b/docs/dev/logs/2011-10-12 similarity index 100% rename from doc/dev/logs/2011-10-12 rename to docs/dev/logs/2011-10-12 diff --git a/doc/dev/logs/2011-10-13.output b/docs/dev/logs/2011-10-13.output similarity index 100% rename from doc/dev/logs/2011-10-13.output rename to docs/dev/logs/2011-10-13.output diff --git a/doc/dev/logs/2011-10-14.error-output b/docs/dev/logs/2011-10-14.error-output similarity index 100% rename from doc/dev/logs/2011-10-14.error-output rename to docs/dev/logs/2011-10-14.error-output diff --git a/doc/dev/logs/2011-10-15.prefix-output-missing b/docs/dev/logs/2011-10-15.prefix-output-missing similarity index 100% rename from doc/dev/logs/2011-10-15.prefix-output-missing rename to docs/dev/logs/2011-10-15.prefix-output-missing diff --git a/doc/dev/logs/2011-10-15.ugly-output-on-breaking-explorer b/docs/dev/logs/2011-10-15.ugly-output-on-breaking-explorer similarity index 100% rename from doc/dev/logs/2011-10-15.ugly-output-on-breaking-explorer rename to docs/dev/logs/2011-10-15.ugly-output-on-breaking-explorer diff --git a/doc/dev/logs/2011-10-16.keyboardirqoutputs b/docs/dev/logs/2011-10-16.keyboardirqoutputs similarity index 100% rename from doc/dev/logs/2011-10-16.keyboardirqoutputs rename to docs/dev/logs/2011-10-16.keyboardirqoutputs diff --git a/doc/dev/logs/2011-10-18.requirement-object b/docs/dev/logs/2011-10-18.requirement-object similarity index 100% rename from doc/dev/logs/2011-10-18.requirement-object rename to docs/dev/logs/2011-10-18.requirement-object diff --git a/doc/dev/logs/2011-10-18.traceback-gencode b/docs/dev/logs/2011-10-18.traceback-gencode similarity index 100% rename from doc/dev/logs/2011-10-18.traceback-gencode rename to docs/dev/logs/2011-10-18.traceback-gencode diff --git a/doc/dev/logs/2011-11-15.startup-yannick b/docs/dev/logs/2011-11-15.startup-yannick similarity index 100% rename from doc/dev/logs/2011-11-15.startup-yannick rename to docs/dev/logs/2011-11-15.startup-yannick diff --git a/doc/dev/logs/2012-01-06.python3-in-distros b/docs/dev/logs/2012-01-06.python3-in-distros similarity index 100% rename from doc/dev/logs/2012-01-06.python3-in-distros rename to docs/dev/logs/2012-01-06.python3-in-distros diff --git a/doc/dev/logs/2012-01-07.urls b/docs/dev/logs/2012-01-07.urls similarity index 100% rename from doc/dev/logs/2012-01-07.urls rename to docs/dev/logs/2012-01-07.urls diff --git a/doc/dev/logs/2012-01-18.urls b/docs/dev/logs/2012-01-18.urls similarity index 100% rename from doc/dev/logs/2012-01-18.urls rename to docs/dev/logs/2012-01-18.urls diff --git a/doc/dev/logs/2012-02-08.explorer-depends-on-another-type b/docs/dev/logs/2012-02-08.explorer-depends-on-another-type similarity index 100% rename from doc/dev/logs/2012-02-08.explorer-depends-on-another-type rename to docs/dev/logs/2012-02-08.explorer-depends-on-another-type diff --git a/doc/dev/logs/2012-02-10.object_id-and-slashes b/docs/dev/logs/2012-02-10.object_id-and-slashes similarity index 100% rename from doc/dev/logs/2012-02-10.object_id-and-slashes rename to docs/dev/logs/2012-02-10.object_id-and-slashes diff --git a/doc/dev/logs/2012-02-13.dependencies b/docs/dev/logs/2012-02-13.dependencies similarity index 100% rename from doc/dev/logs/2012-02-13.dependencies rename to docs/dev/logs/2012-02-13.dependencies diff --git a/doc/dev/logs/2012-02-15.steven b/docs/dev/logs/2012-02-15.steven similarity index 100% rename from doc/dev/logs/2012-02-15.steven rename to docs/dev/logs/2012-02-15.steven diff --git a/doc/dev/logs/2012-02-17.keyboardirq b/docs/dev/logs/2012-02-17.keyboardirq similarity index 100% rename from doc/dev/logs/2012-02-17.keyboardirq rename to docs/dev/logs/2012-02-17.keyboardirq diff --git a/doc/dev/logs/2012-02-20.debug-jake-deps b/docs/dev/logs/2012-02-20.debug-jake-deps similarity index 100% rename from doc/dev/logs/2012-02-20.debug-jake-deps rename to docs/dev/logs/2012-02-20.debug-jake-deps diff --git a/doc/dev/logs/2012-02-20.error-does-not-contain-host b/docs/dev/logs/2012-02-20.error-does-not-contain-host similarity index 100% rename from doc/dev/logs/2012-02-20.error-does-not-contain-host rename to docs/dev/logs/2012-02-20.error-does-not-contain-host diff --git a/doc/dev/logs/2012-05-24.makedirs.py-python3.1 b/docs/dev/logs/2012-05-24.makedirs.py-python3.1 similarity index 100% rename from doc/dev/logs/2012-05-24.makedirs.py-python3.1 rename to docs/dev/logs/2012-05-24.makedirs.py-python3.1 diff --git a/doc/dev/logs/2012-05-30.ifconfig-outputs b/docs/dev/logs/2012-05-30.ifconfig-outputs similarity index 100% rename from doc/dev/logs/2012-05-30.ifconfig-outputs rename to docs/dev/logs/2012-05-30.ifconfig-outputs diff --git a/doc/dev/logs/2012-05-31.csh-compatibilty b/docs/dev/logs/2012-05-31.csh-compatibilty similarity index 100% rename from doc/dev/logs/2012-05-31.csh-compatibilty rename to docs/dev/logs/2012-05-31.csh-compatibilty diff --git a/doc/dev/logs/2012-06-06.wikipedia b/docs/dev/logs/2012-06-06.wikipedia similarity index 100% rename from doc/dev/logs/2012-06-06.wikipedia rename to docs/dev/logs/2012-06-06.wikipedia diff --git a/doc/dev/logs/2012-06-15.explorer-dep-problem b/docs/dev/logs/2012-06-15.explorer-dep-problem similarity index 100% rename from doc/dev/logs/2012-06-15.explorer-dep-problem rename to docs/dev/logs/2012-06-15.explorer-dep-problem diff --git a/doc/dev/logs/2012-10-17.conflicting-types-problem b/docs/dev/logs/2012-10-17.conflicting-types-problem similarity index 100% rename from doc/dev/logs/2012-10-17.conflicting-types-problem rename to docs/dev/logs/2012-10-17.conflicting-types-problem diff --git a/doc/dev/logs/README b/docs/dev/logs/README similarity index 100% rename from doc/dev/logs/README rename to docs/dev/logs/README diff --git a/doc/dev/logs/linklist b/docs/dev/logs/linklist similarity index 100% rename from doc/dev/logs/linklist rename to docs/dev/logs/linklist diff --git a/doc/dev/logs/times b/docs/dev/logs/times similarity index 100% rename from doc/dev/logs/times rename to docs/dev/logs/times diff --git a/doc/dev/releasechecklist b/docs/dev/releasechecklist similarity index 100% rename from doc/dev/releasechecklist rename to docs/dev/releasechecklist diff --git a/doc/dev/show_all_exported_variables b/docs/dev/show_all_exported_variables similarity index 100% rename from doc/dev/show_all_exported_variables rename to docs/dev/show_all_exported_variables diff --git a/doc/dev/sync-to-testhost b/docs/dev/sync-to-testhost similarity index 100% rename from doc/dev/sync-to-testhost rename to docs/dev/sync-to-testhost diff --git a/doc/dev/todo/3.0 b/docs/dev/todo/3.0 similarity index 100% rename from doc/dev/todo/3.0 rename to docs/dev/todo/3.0 diff --git a/doc/dev/todo/TAKEME b/docs/dev/todo/TAKEME similarity index 100% rename from doc/dev/todo/TAKEME rename to docs/dev/todo/TAKEME diff --git a/doc/dev/todo/niconext b/docs/dev/todo/niconext similarity index 100% rename from doc/dev/todo/niconext rename to docs/dev/todo/niconext diff --git a/doc/dev/todo/performance-ideas b/docs/dev/todo/performance-ideas similarity index 100% rename from doc/dev/todo/performance-ideas rename to docs/dev/todo/performance-ideas diff --git a/doc/dev/todo/steven b/docs/dev/todo/steven similarity index 100% rename from doc/dev/todo/steven rename to docs/dev/todo/steven diff --git a/doc/dev/todo/tests b/docs/dev/todo/tests similarity index 100% rename from doc/dev/todo/tests rename to docs/dev/todo/tests diff --git a/doc/gfx/cdist-automated-inverted.png b/docs/gfx/cdist-automated-inverted.png similarity index 100% rename from doc/gfx/cdist-automated-inverted.png rename to docs/gfx/cdist-automated-inverted.png diff --git a/doc/gfx/cdist-automated.png b/docs/gfx/cdist-automated.png similarity index 100% rename from doc/gfx/cdist-automated.png rename to docs/gfx/cdist-automated.png diff --git a/doc/gfx/cdist-automated.text b/docs/gfx/cdist-automated.text similarity index 100% rename from doc/gfx/cdist-automated.text rename to docs/gfx/cdist-automated.text diff --git a/doc/gfx/cdist-logo-cm.png b/docs/gfx/cdist-logo-cm.png similarity index 100% rename from doc/gfx/cdist-logo-cm.png rename to docs/gfx/cdist-logo-cm.png diff --git a/doc/gfx/cdist-logo-inverted.png b/docs/gfx/cdist-logo-inverted.png similarity index 100% rename from doc/gfx/cdist-logo-inverted.png rename to docs/gfx/cdist-logo-inverted.png diff --git a/doc/gfx/cdist-logo.png b/docs/gfx/cdist-logo.png similarity index 100% rename from doc/gfx/cdist-logo.png rename to docs/gfx/cdist-logo.png diff --git a/doc/gfx/cdist-logo.text b/docs/gfx/cdist-logo.text similarity index 100% rename from doc/gfx/cdist-logo.text rename to docs/gfx/cdist-logo.text diff --git a/doc/gfx/font-used b/docs/gfx/font-used similarity index 100% rename from doc/gfx/font-used rename to docs/gfx/font-used diff --git a/doc/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh similarity index 100% rename from doc/man/cdist-reference.text.sh rename to docs/man/cdist-reference.text.sh diff --git a/doc/man/man1/cdist.text b/docs/man/man1/cdist.text similarity index 100% rename from doc/man/man1/cdist.text rename to docs/man/man1/cdist.text diff --git a/doc/man/man7/cdist-best-practice.text b/docs/man/man7/cdist-best-practice.text similarity index 100% rename from doc/man/man7/cdist-best-practice.text rename to docs/man/man7/cdist-best-practice.text diff --git a/doc/man/man7/cdist-bootstrap.text b/docs/man/man7/cdist-bootstrap.text similarity index 100% rename from doc/man/man7/cdist-bootstrap.text rename to docs/man/man7/cdist-bootstrap.text diff --git a/doc/man/man7/cdist-explorer.text b/docs/man/man7/cdist-explorer.text similarity index 100% rename from doc/man/man7/cdist-explorer.text rename to docs/man/man7/cdist-explorer.text diff --git a/doc/man/man7/cdist-hacker.text b/docs/man/man7/cdist-hacker.text similarity index 100% rename from doc/man/man7/cdist-hacker.text rename to docs/man/man7/cdist-hacker.text diff --git a/doc/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text similarity index 100% rename from doc/man/man7/cdist-manifest.text rename to docs/man/man7/cdist-manifest.text diff --git a/doc/man/man7/cdist-quickstart.text b/docs/man/man7/cdist-quickstart.text similarity index 100% rename from doc/man/man7/cdist-quickstart.text rename to docs/man/man7/cdist-quickstart.text diff --git a/doc/man/man7/cdist-remote-exec-copy.text b/docs/man/man7/cdist-remote-exec-copy.text similarity index 100% rename from doc/man/man7/cdist-remote-exec-copy.text rename to docs/man/man7/cdist-remote-exec-copy.text diff --git a/doc/man/man7/cdist-stages.text b/docs/man/man7/cdist-stages.text similarity index 100% rename from doc/man/man7/cdist-stages.text rename to docs/man/man7/cdist-stages.text diff --git a/doc/man/man7/cdist-tutorial.text b/docs/man/man7/cdist-tutorial.text similarity index 100% rename from doc/man/man7/cdist-tutorial.text rename to docs/man/man7/cdist-tutorial.text diff --git a/doc/man/man7/cdist-type.text b/docs/man/man7/cdist-type.text similarity index 100% rename from doc/man/man7/cdist-type.text rename to docs/man/man7/cdist-type.text diff --git a/doc/speeches/.gitignore b/docs/speeches/.gitignore similarity index 100% rename from doc/speeches/.gitignore rename to docs/speeches/.gitignore diff --git a/doc/speeches/2011-03-18_hacker_erwachen.tex b/docs/speeches/2011-03-18_hacker_erwachen.tex similarity index 100% rename from doc/speeches/2011-03-18_hacker_erwachen.tex rename to docs/speeches/2011-03-18_hacker_erwachen.tex diff --git a/doc/speeches/2011-04-27_sans.tex b/docs/speeches/2011-04-27_sans.tex similarity index 100% rename from doc/speeches/2011-04-27_sans.tex rename to docs/speeches/2011-04-27_sans.tex diff --git a/doc/speeches/2011-05-20_cosin.tex b/docs/speeches/2011-05-20_cosin.tex similarity index 100% rename from doc/speeches/2011-05-20_cosin.tex rename to docs/speeches/2011-05-20_cosin.tex diff --git a/doc/video/cdist-installation-in-less-than-60-seconds.mp4 b/docs/video/cdist-installation-in-less-than-60-seconds.mp4 similarity index 100% rename from doc/video/cdist-installation-in-less-than-60-seconds.mp4 rename to docs/video/cdist-installation-in-less-than-60-seconds.mp4 From c9f728e073975ce395ef17164a3e175738fdf451 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 17:21:58 +0200 Subject: [PATCH 1651/4212] lib/cdist => cdist (pypi) Signed-off-by: Nico Schottelius --- {lib/cdist => cdist}/__init__.py | 0 {lib/cdist => cdist}/banner.py | 0 {lib/cdist => cdist}/config.py | 0 {lib/cdist => cdist}/config_install.py | 0 {lib/cdist => cdist}/context.py | 0 {lib/cdist => cdist}/core/__init__.py | 0 {lib/cdist => cdist}/core/cdist_object.py | 0 {lib/cdist => cdist}/core/cdist_type.py | 0 {lib/cdist => cdist}/core/code.py | 0 {lib/cdist => cdist}/core/explorer.py | 0 {lib/cdist => cdist}/core/manifest.py | 0 {lib/cdist => cdist}/emulator.py | 0 {lib/cdist => cdist}/exec/__init__.py | 0 {lib/cdist => cdist}/exec/local.py | 0 {lib/cdist => cdist}/exec/remote.py | 0 {lib/cdist => cdist}/install.py | 0 {lib/cdist => cdist}/resolver.py | 0 {lib/cdist => cdist}/test/__init__.py | 0 {lib/cdist => cdist}/test/__main__.py | 0 {lib/cdist => cdist}/test/autorequire/__init__.py | 0 .../cdist => cdist}/test/autorequire/fixtures/conf/explorer/.keep | 0 .../test/autorequire/fixtures/conf/manifest/circular_dependency | 0 .../test/autorequire/fixtures/conf/manifest/implicit_dependencies | 0 .../test/autorequire/fixtures/conf/type/__addifnosuchline/.keep | 0 .../test/autorequire/fixtures/conf/type/__directory/.keep | 0 .../test/autorequire/fixtures/conf/type/__nfsroot_client/manifest | 0 .../test/autorequire/fixtures/conf/type/__package/manifest | 0 .../test/autorequire/fixtures/conf/type/__package_special/.keep | 0 .../fixtures/conf/type/__root_ssh_authorized_key/manifest | 0 .../test/autorequire/fixtures/conf/type/__top/manifest | 0 .../test/autorequire/fixtures/conf/type/__user/.keep | 0 {lib/cdist => cdist}/test/banner/__init__.py | 0 {lib/cdist => cdist}/test/code/__init__.py | 0 .../test/code/fixtures/conf/type/__dump_environment/gencode-local | 0 .../code/fixtures/conf/type/__dump_environment/gencode-remote | 0 {lib/cdist => cdist}/test/emulator/__init__.py | 0 {lib/cdist => cdist}/test/emulator/fixtures/conf/explorer/.keep | 0 {lib/cdist => cdist}/test/emulator/fixtures/conf/manifest/init | 0 .../fixtures/conf/type/__arguments_boolean/parameter/boolean | 0 .../fixtures/conf/type/__arguments_optional/parameter/optional | 0 .../fixtures/conf/type/__arguments_required/parameter/required | 0 .../fixtures/conf/type/__arguments_with_dashes/parameter/required | 0 {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__file | 0 .../test/emulator/fixtures/conf/type/__file_from_stdin/manifest | 0 .../fixtures/conf/type/__file_from_stdin/parameter/required | 0 .../test/emulator/fixtures/conf/type/__moon/manifest | 0 .../test/emulator/fixtures/conf/type/__moon/parameter/optional | 0 .../test/emulator/fixtures/conf/type/__moon/parameter/required | 0 .../test/emulator/fixtures/conf/type/__planet/manifest | 0 .../test/emulator/fixtures/conf/type/__planet/parameter/optional | 0 .../test/emulator/fixtures/conf/type/__saturn/manifest | 0 .../test/emulator/fixtures/conf/type/__saturn/singleton | 0 {lib/cdist => cdist}/test/exec/__init__.py | 0 {lib/cdist => cdist}/test/exec/local.py | 0 {lib/cdist => cdist}/test/exec/remote.py | 0 {lib/cdist => cdist}/test/explorer/__init__.py | 0 {lib/cdist => cdist}/test/explorer/fixtures/conf/explorer/foobar | 0 {lib/cdist => cdist}/test/explorer/fixtures/conf/explorer/global | 0 .../test/explorer/fixtures/conf/type/__test_type/explorer/world | 0 .../type/__test_type_object_parameter/explorer/test_parameter | 0 {lib/cdist => cdist}/test/manifest/__init__.py | 0 .../test/manifest/fixtures/conf/manifest/dump_environment | 0 {lib/cdist => cdist}/test/manifest/fixtures/conf/manifest/init | 0 .../test/manifest/fixtures/conf/type/__dump_environment/manifest | 0 .../cdist => cdist}/test/manifest/fixtures/conf/type/__moon/.keep | 0 .../test/manifest/fixtures/conf/type/__moon/manifest | 0 .../test/manifest/fixtures/conf/type/__moon/parameter/optional | 0 .../test/manifest/fixtures/conf/type/__moon/parameter/required | 0 .../test/manifest/fixtures/conf/type/__planet/.keep | 0 .../test/manifest/fixtures/conf/type/__planet/manifest | 0 .../test/manifest/fixtures/conf/type/__planet/parameter/optional | 0 {lib/cdist => cdist}/test/object/__init__.py | 0 {lib/cdist => cdist}/test/object/fixtures/object/__first/.keep | 0 .../test/object/fixtures/object/__first/man/.cdist/.keep | 0 {lib/cdist => cdist}/test/object/fixtures/object/__second/.keep | 0 .../test/object/fixtures/object/__second/on-the/.cdist/.keep | 0 {lib/cdist => cdist}/test/object/fixtures/object/__third/.keep | 0 .../test/object/fixtures/object/__third/moon/.cdist/.keep | 0 .../object/fixtures/object/__third/moon/.cdist/parameter/name | 0 .../object/fixtures/object/__third/moon/.cdist/parameter/planet | 0 {lib/cdist => cdist}/test/object/fixtures/type/__first/.keep | 0 {lib/cdist => cdist}/test/object/fixtures/type/__second/.keep | 0 {lib/cdist => cdist}/test/object/fixtures/type/__third/.keep | 0 {lib/cdist => cdist}/test/resolver/__init__.py | 0 {lib/cdist => cdist}/test/resolver/fixtures/object/__first/.keep | 0 .../test/resolver/fixtures/object/__first/child/.cdist/.keep | 0 .../test/resolver/fixtures/object/__first/dog/.cdist/.keep | 0 .../test/resolver/fixtures/object/__first/man/.cdist/.keep | 0 .../test/resolver/fixtures/object/__first/woman/.cdist/.keep | 0 {lib/cdist => cdist}/test/resolver/fixtures/object/__second/.keep | 0 .../test/resolver/fixtures/object/__second/on-the/.cdist/.keep | 0 .../test/resolver/fixtures/object/__second/under-the/.cdist/.keep | 0 {lib/cdist => cdist}/test/resolver/fixtures/object/__third/.keep | 0 .../test/resolver/fixtures/object/__third/moon/.cdist/.keep | 0 .../resolver/fixtures/object/__third/moon/.cdist/parameter/name | 0 .../resolver/fixtures/object/__third/moon/.cdist/parameter/planet | 0 {lib/cdist => cdist}/test/resolver/fixtures/type/__first/.keep | 0 {lib/cdist => cdist}/test/resolver/fixtures/type/__second/.keep | 0 {lib/cdist => cdist}/test/resolver/fixtures/type/__third/.keep | 0 {lib/cdist => cdist}/test/type/__init__.py | 0 {lib/cdist => cdist}/test/type/fixtures/__install/install | 0 {lib/cdist => cdist}/test/type/fixtures/__name_path/.keep | 0 {lib/cdist => cdist}/test/type/fixtures/__not_install/.keep | 0 {lib/cdist => cdist}/test/type/fixtures/__not_singleton/.keep | 0 {lib/cdist => cdist}/test/type/fixtures/__singleton/singleton | 0 .../type/fixtures/__with_boolean_parameters/parameter/boolean | 0 .../test/type/fixtures/__with_explorers/explorer/whatever | 0 .../type/fixtures/__with_optional_parameters/parameter/optional | 0 .../type/fixtures/__with_required_parameters/parameter/required | 0 .../test/type/fixtures/__without_boolean_parameters/.keep | 0 {lib/cdist => cdist}/test/type/fixtures/__without_explorers/.keep | 0 .../test/type/fixtures/__without_optional_parameters/.keep | 0 .../test/type/fixtures/__without_required_parameters/.keep | 0 {lib/cdist => cdist}/test/type/fixtures/list_types/__first/.keep | 0 {lib/cdist => cdist}/test/type/fixtures/list_types/__second/.keep | 0 {lib/cdist => cdist}/test/type/fixtures/list_types/__third/.keep | 0 {lib/cdist => cdist}/test/util/__init__.py | 0 {lib/cdist => cdist}/test/util/fsproperty.py | 0 {lib/cdist => cdist}/util/__init__.py | 0 {lib/cdist => cdist}/util/fsproperty.py | 0 120 files changed, 0 insertions(+), 0 deletions(-) rename {lib/cdist => cdist}/__init__.py (100%) rename {lib/cdist => cdist}/banner.py (100%) rename {lib/cdist => cdist}/config.py (100%) rename {lib/cdist => cdist}/config_install.py (100%) rename {lib/cdist => cdist}/context.py (100%) rename {lib/cdist => cdist}/core/__init__.py (100%) rename {lib/cdist => cdist}/core/cdist_object.py (100%) rename {lib/cdist => cdist}/core/cdist_type.py (100%) rename {lib/cdist => cdist}/core/code.py (100%) rename {lib/cdist => cdist}/core/explorer.py (100%) rename {lib/cdist => cdist}/core/manifest.py (100%) rename {lib/cdist => cdist}/emulator.py (100%) rename {lib/cdist => cdist}/exec/__init__.py (100%) rename {lib/cdist => cdist}/exec/local.py (100%) rename {lib/cdist => cdist}/exec/remote.py (100%) rename {lib/cdist => cdist}/install.py (100%) rename {lib/cdist => cdist}/resolver.py (100%) rename {lib/cdist => cdist}/test/__init__.py (100%) rename {lib/cdist => cdist}/test/__main__.py (100%) rename {lib/cdist => cdist}/test/autorequire/__init__.py (100%) rename {lib/cdist => cdist}/test/autorequire/fixtures/conf/explorer/.keep (100%) rename {lib/cdist => cdist}/test/autorequire/fixtures/conf/manifest/circular_dependency (100%) rename {lib/cdist => cdist}/test/autorequire/fixtures/conf/manifest/implicit_dependencies (100%) rename {lib/cdist => cdist}/test/autorequire/fixtures/conf/type/__addifnosuchline/.keep (100%) rename {lib/cdist => cdist}/test/autorequire/fixtures/conf/type/__directory/.keep (100%) rename {lib/cdist => cdist}/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest (100%) rename {lib/cdist => cdist}/test/autorequire/fixtures/conf/type/__package/manifest (100%) rename {lib/cdist => cdist}/test/autorequire/fixtures/conf/type/__package_special/.keep (100%) rename {lib/cdist => cdist}/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest (100%) rename {lib/cdist => cdist}/test/autorequire/fixtures/conf/type/__top/manifest (100%) rename {lib/cdist => cdist}/test/autorequire/fixtures/conf/type/__user/.keep (100%) rename {lib/cdist => cdist}/test/banner/__init__.py (100%) rename {lib/cdist => cdist}/test/code/__init__.py (100%) rename {lib/cdist => cdist}/test/code/fixtures/conf/type/__dump_environment/gencode-local (100%) rename {lib/cdist => cdist}/test/code/fixtures/conf/type/__dump_environment/gencode-remote (100%) rename {lib/cdist => cdist}/test/emulator/__init__.py (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/explorer/.keep (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/manifest/init (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__arguments_boolean/parameter/boolean (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__arguments_optional/parameter/optional (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__arguments_required/parameter/required (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__arguments_with_dashes/parameter/required (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__file (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__file_from_stdin/manifest (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__file_from_stdin/parameter/required (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__moon/manifest (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__moon/parameter/optional (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__moon/parameter/required (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__planet/manifest (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__planet/parameter/optional (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__saturn/manifest (100%) rename {lib/cdist => cdist}/test/emulator/fixtures/conf/type/__saturn/singleton (100%) rename {lib/cdist => cdist}/test/exec/__init__.py (100%) rename {lib/cdist => cdist}/test/exec/local.py (100%) rename {lib/cdist => cdist}/test/exec/remote.py (100%) rename {lib/cdist => cdist}/test/explorer/__init__.py (100%) rename {lib/cdist => cdist}/test/explorer/fixtures/conf/explorer/foobar (100%) rename {lib/cdist => cdist}/test/explorer/fixtures/conf/explorer/global (100%) rename {lib/cdist => cdist}/test/explorer/fixtures/conf/type/__test_type/explorer/world (100%) rename {lib/cdist => cdist}/test/explorer/fixtures/conf/type/__test_type_object_parameter/explorer/test_parameter (100%) rename {lib/cdist => cdist}/test/manifest/__init__.py (100%) rename {lib/cdist => cdist}/test/manifest/fixtures/conf/manifest/dump_environment (100%) rename {lib/cdist => cdist}/test/manifest/fixtures/conf/manifest/init (100%) rename {lib/cdist => cdist}/test/manifest/fixtures/conf/type/__dump_environment/manifest (100%) rename {lib/cdist => cdist}/test/manifest/fixtures/conf/type/__moon/.keep (100%) rename {lib/cdist => cdist}/test/manifest/fixtures/conf/type/__moon/manifest (100%) rename {lib/cdist => cdist}/test/manifest/fixtures/conf/type/__moon/parameter/optional (100%) rename {lib/cdist => cdist}/test/manifest/fixtures/conf/type/__moon/parameter/required (100%) rename {lib/cdist => cdist}/test/manifest/fixtures/conf/type/__planet/.keep (100%) rename {lib/cdist => cdist}/test/manifest/fixtures/conf/type/__planet/manifest (100%) rename {lib/cdist => cdist}/test/manifest/fixtures/conf/type/__planet/parameter/optional (100%) rename {lib/cdist => cdist}/test/object/__init__.py (100%) rename {lib/cdist => cdist}/test/object/fixtures/object/__first/.keep (100%) rename {lib/cdist => cdist}/test/object/fixtures/object/__first/man/.cdist/.keep (100%) rename {lib/cdist => cdist}/test/object/fixtures/object/__second/.keep (100%) rename {lib/cdist => cdist}/test/object/fixtures/object/__second/on-the/.cdist/.keep (100%) rename {lib/cdist => cdist}/test/object/fixtures/object/__third/.keep (100%) rename {lib/cdist => cdist}/test/object/fixtures/object/__third/moon/.cdist/.keep (100%) rename {lib/cdist => cdist}/test/object/fixtures/object/__third/moon/.cdist/parameter/name (100%) rename {lib/cdist => cdist}/test/object/fixtures/object/__third/moon/.cdist/parameter/planet (100%) rename {lib/cdist => cdist}/test/object/fixtures/type/__first/.keep (100%) rename {lib/cdist => cdist}/test/object/fixtures/type/__second/.keep (100%) rename {lib/cdist => cdist}/test/object/fixtures/type/__third/.keep (100%) rename {lib/cdist => cdist}/test/resolver/__init__.py (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/object/__first/.keep (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/object/__first/child/.cdist/.keep (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/object/__first/dog/.cdist/.keep (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/object/__first/man/.cdist/.keep (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/object/__first/woman/.cdist/.keep (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/object/__second/.keep (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/object/__second/on-the/.cdist/.keep (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/object/__second/under-the/.cdist/.keep (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/object/__third/.keep (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/object/__third/moon/.cdist/.keep (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/type/__first/.keep (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/type/__second/.keep (100%) rename {lib/cdist => cdist}/test/resolver/fixtures/type/__third/.keep (100%) rename {lib/cdist => cdist}/test/type/__init__.py (100%) rename {lib/cdist => cdist}/test/type/fixtures/__install/install (100%) rename {lib/cdist => cdist}/test/type/fixtures/__name_path/.keep (100%) rename {lib/cdist => cdist}/test/type/fixtures/__not_install/.keep (100%) rename {lib/cdist => cdist}/test/type/fixtures/__not_singleton/.keep (100%) rename {lib/cdist => cdist}/test/type/fixtures/__singleton/singleton (100%) rename {lib/cdist => cdist}/test/type/fixtures/__with_boolean_parameters/parameter/boolean (100%) rename {lib/cdist => cdist}/test/type/fixtures/__with_explorers/explorer/whatever (100%) rename {lib/cdist => cdist}/test/type/fixtures/__with_optional_parameters/parameter/optional (100%) rename {lib/cdist => cdist}/test/type/fixtures/__with_required_parameters/parameter/required (100%) rename {lib/cdist => cdist}/test/type/fixtures/__without_boolean_parameters/.keep (100%) rename {lib/cdist => cdist}/test/type/fixtures/__without_explorers/.keep (100%) rename {lib/cdist => cdist}/test/type/fixtures/__without_optional_parameters/.keep (100%) rename {lib/cdist => cdist}/test/type/fixtures/__without_required_parameters/.keep (100%) rename {lib/cdist => cdist}/test/type/fixtures/list_types/__first/.keep (100%) rename {lib/cdist => cdist}/test/type/fixtures/list_types/__second/.keep (100%) rename {lib/cdist => cdist}/test/type/fixtures/list_types/__third/.keep (100%) rename {lib/cdist => cdist}/test/util/__init__.py (100%) rename {lib/cdist => cdist}/test/util/fsproperty.py (100%) rename {lib/cdist => cdist}/util/__init__.py (100%) rename {lib/cdist => cdist}/util/fsproperty.py (100%) diff --git a/lib/cdist/__init__.py b/cdist/__init__.py similarity index 100% rename from lib/cdist/__init__.py rename to cdist/__init__.py diff --git a/lib/cdist/banner.py b/cdist/banner.py similarity index 100% rename from lib/cdist/banner.py rename to cdist/banner.py diff --git a/lib/cdist/config.py b/cdist/config.py similarity index 100% rename from lib/cdist/config.py rename to cdist/config.py diff --git a/lib/cdist/config_install.py b/cdist/config_install.py similarity index 100% rename from lib/cdist/config_install.py rename to cdist/config_install.py diff --git a/lib/cdist/context.py b/cdist/context.py similarity index 100% rename from lib/cdist/context.py rename to cdist/context.py diff --git a/lib/cdist/core/__init__.py b/cdist/core/__init__.py similarity index 100% rename from lib/cdist/core/__init__.py rename to cdist/core/__init__.py diff --git a/lib/cdist/core/cdist_object.py b/cdist/core/cdist_object.py similarity index 100% rename from lib/cdist/core/cdist_object.py rename to cdist/core/cdist_object.py diff --git a/lib/cdist/core/cdist_type.py b/cdist/core/cdist_type.py similarity index 100% rename from lib/cdist/core/cdist_type.py rename to cdist/core/cdist_type.py diff --git a/lib/cdist/core/code.py b/cdist/core/code.py similarity index 100% rename from lib/cdist/core/code.py rename to cdist/core/code.py diff --git a/lib/cdist/core/explorer.py b/cdist/core/explorer.py similarity index 100% rename from lib/cdist/core/explorer.py rename to cdist/core/explorer.py diff --git a/lib/cdist/core/manifest.py b/cdist/core/manifest.py similarity index 100% rename from lib/cdist/core/manifest.py rename to cdist/core/manifest.py diff --git a/lib/cdist/emulator.py b/cdist/emulator.py similarity index 100% rename from lib/cdist/emulator.py rename to cdist/emulator.py diff --git a/lib/cdist/exec/__init__.py b/cdist/exec/__init__.py similarity index 100% rename from lib/cdist/exec/__init__.py rename to cdist/exec/__init__.py diff --git a/lib/cdist/exec/local.py b/cdist/exec/local.py similarity index 100% rename from lib/cdist/exec/local.py rename to cdist/exec/local.py diff --git a/lib/cdist/exec/remote.py b/cdist/exec/remote.py similarity index 100% rename from lib/cdist/exec/remote.py rename to cdist/exec/remote.py diff --git a/lib/cdist/install.py b/cdist/install.py similarity index 100% rename from lib/cdist/install.py rename to cdist/install.py diff --git a/lib/cdist/resolver.py b/cdist/resolver.py similarity index 100% rename from lib/cdist/resolver.py rename to cdist/resolver.py diff --git a/lib/cdist/test/__init__.py b/cdist/test/__init__.py similarity index 100% rename from lib/cdist/test/__init__.py rename to cdist/test/__init__.py diff --git a/lib/cdist/test/__main__.py b/cdist/test/__main__.py similarity index 100% rename from lib/cdist/test/__main__.py rename to cdist/test/__main__.py diff --git a/lib/cdist/test/autorequire/__init__.py b/cdist/test/autorequire/__init__.py similarity index 100% rename from lib/cdist/test/autorequire/__init__.py rename to cdist/test/autorequire/__init__.py diff --git a/lib/cdist/test/autorequire/fixtures/conf/explorer/.keep b/cdist/test/autorequire/fixtures/conf/explorer/.keep similarity index 100% rename from lib/cdist/test/autorequire/fixtures/conf/explorer/.keep rename to cdist/test/autorequire/fixtures/conf/explorer/.keep diff --git a/lib/cdist/test/autorequire/fixtures/conf/manifest/circular_dependency b/cdist/test/autorequire/fixtures/conf/manifest/circular_dependency similarity index 100% rename from lib/cdist/test/autorequire/fixtures/conf/manifest/circular_dependency rename to cdist/test/autorequire/fixtures/conf/manifest/circular_dependency diff --git a/lib/cdist/test/autorequire/fixtures/conf/manifest/implicit_dependencies b/cdist/test/autorequire/fixtures/conf/manifest/implicit_dependencies similarity index 100% rename from lib/cdist/test/autorequire/fixtures/conf/manifest/implicit_dependencies rename to cdist/test/autorequire/fixtures/conf/manifest/implicit_dependencies diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__addifnosuchline/.keep b/cdist/test/autorequire/fixtures/conf/type/__addifnosuchline/.keep similarity index 100% rename from lib/cdist/test/autorequire/fixtures/conf/type/__addifnosuchline/.keep rename to cdist/test/autorequire/fixtures/conf/type/__addifnosuchline/.keep diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__directory/.keep b/cdist/test/autorequire/fixtures/conf/type/__directory/.keep similarity index 100% rename from lib/cdist/test/autorequire/fixtures/conf/type/__directory/.keep rename to cdist/test/autorequire/fixtures/conf/type/__directory/.keep diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest b/cdist/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest similarity index 100% rename from lib/cdist/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest rename to cdist/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__package/manifest b/cdist/test/autorequire/fixtures/conf/type/__package/manifest similarity index 100% rename from lib/cdist/test/autorequire/fixtures/conf/type/__package/manifest rename to cdist/test/autorequire/fixtures/conf/type/__package/manifest diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__package_special/.keep b/cdist/test/autorequire/fixtures/conf/type/__package_special/.keep similarity index 100% rename from lib/cdist/test/autorequire/fixtures/conf/type/__package_special/.keep rename to cdist/test/autorequire/fixtures/conf/type/__package_special/.keep diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest b/cdist/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest similarity index 100% rename from lib/cdist/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest rename to cdist/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__top/manifest b/cdist/test/autorequire/fixtures/conf/type/__top/manifest similarity index 100% rename from lib/cdist/test/autorequire/fixtures/conf/type/__top/manifest rename to cdist/test/autorequire/fixtures/conf/type/__top/manifest diff --git a/lib/cdist/test/autorequire/fixtures/conf/type/__user/.keep b/cdist/test/autorequire/fixtures/conf/type/__user/.keep similarity index 100% rename from lib/cdist/test/autorequire/fixtures/conf/type/__user/.keep rename to cdist/test/autorequire/fixtures/conf/type/__user/.keep diff --git a/lib/cdist/test/banner/__init__.py b/cdist/test/banner/__init__.py similarity index 100% rename from lib/cdist/test/banner/__init__.py rename to cdist/test/banner/__init__.py diff --git a/lib/cdist/test/code/__init__.py b/cdist/test/code/__init__.py similarity index 100% rename from lib/cdist/test/code/__init__.py rename to cdist/test/code/__init__.py diff --git a/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local b/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local similarity index 100% rename from lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local rename to cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local diff --git a/lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-remote b/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-remote similarity index 100% rename from lib/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-remote rename to cdist/test/code/fixtures/conf/type/__dump_environment/gencode-remote diff --git a/lib/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py similarity index 100% rename from lib/cdist/test/emulator/__init__.py rename to cdist/test/emulator/__init__.py diff --git a/lib/cdist/test/emulator/fixtures/conf/explorer/.keep b/cdist/test/emulator/fixtures/conf/explorer/.keep similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/explorer/.keep rename to cdist/test/emulator/fixtures/conf/explorer/.keep diff --git a/lib/cdist/test/emulator/fixtures/conf/manifest/init b/cdist/test/emulator/fixtures/conf/manifest/init similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/manifest/init rename to cdist/test/emulator/fixtures/conf/manifest/init diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__arguments_boolean/parameter/boolean b/cdist/test/emulator/fixtures/conf/type/__arguments_boolean/parameter/boolean similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__arguments_boolean/parameter/boolean rename to cdist/test/emulator/fixtures/conf/type/__arguments_boolean/parameter/boolean diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__arguments_optional/parameter/optional b/cdist/test/emulator/fixtures/conf/type/__arguments_optional/parameter/optional similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__arguments_optional/parameter/optional rename to cdist/test/emulator/fixtures/conf/type/__arguments_optional/parameter/optional diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__arguments_required/parameter/required b/cdist/test/emulator/fixtures/conf/type/__arguments_required/parameter/required similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__arguments_required/parameter/required rename to cdist/test/emulator/fixtures/conf/type/__arguments_required/parameter/required diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__arguments_with_dashes/parameter/required b/cdist/test/emulator/fixtures/conf/type/__arguments_with_dashes/parameter/required similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__arguments_with_dashes/parameter/required rename to cdist/test/emulator/fixtures/conf/type/__arguments_with_dashes/parameter/required diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__file b/cdist/test/emulator/fixtures/conf/type/__file similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__file rename to cdist/test/emulator/fixtures/conf/type/__file diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/manifest b/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/manifest similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/manifest rename to cdist/test/emulator/fixtures/conf/type/__file_from_stdin/manifest diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/parameter/required b/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/parameter/required similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__file_from_stdin/parameter/required rename to cdist/test/emulator/fixtures/conf/type/__file_from_stdin/parameter/required diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__moon/manifest b/cdist/test/emulator/fixtures/conf/type/__moon/manifest similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__moon/manifest rename to cdist/test/emulator/fixtures/conf/type/__moon/manifest diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/optional b/cdist/test/emulator/fixtures/conf/type/__moon/parameter/optional similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/optional rename to cdist/test/emulator/fixtures/conf/type/__moon/parameter/optional diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/required b/cdist/test/emulator/fixtures/conf/type/__moon/parameter/required similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/required rename to cdist/test/emulator/fixtures/conf/type/__moon/parameter/required diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__planet/manifest b/cdist/test/emulator/fixtures/conf/type/__planet/manifest similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__planet/manifest rename to cdist/test/emulator/fixtures/conf/type/__planet/manifest diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__planet/parameter/optional b/cdist/test/emulator/fixtures/conf/type/__planet/parameter/optional similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__planet/parameter/optional rename to cdist/test/emulator/fixtures/conf/type/__planet/parameter/optional diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__saturn/manifest b/cdist/test/emulator/fixtures/conf/type/__saturn/manifest similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__saturn/manifest rename to cdist/test/emulator/fixtures/conf/type/__saturn/manifest diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__saturn/singleton b/cdist/test/emulator/fixtures/conf/type/__saturn/singleton similarity index 100% rename from lib/cdist/test/emulator/fixtures/conf/type/__saturn/singleton rename to cdist/test/emulator/fixtures/conf/type/__saturn/singleton diff --git a/lib/cdist/test/exec/__init__.py b/cdist/test/exec/__init__.py similarity index 100% rename from lib/cdist/test/exec/__init__.py rename to cdist/test/exec/__init__.py diff --git a/lib/cdist/test/exec/local.py b/cdist/test/exec/local.py similarity index 100% rename from lib/cdist/test/exec/local.py rename to cdist/test/exec/local.py diff --git a/lib/cdist/test/exec/remote.py b/cdist/test/exec/remote.py similarity index 100% rename from lib/cdist/test/exec/remote.py rename to cdist/test/exec/remote.py diff --git a/lib/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py similarity index 100% rename from lib/cdist/test/explorer/__init__.py rename to cdist/test/explorer/__init__.py diff --git a/lib/cdist/test/explorer/fixtures/conf/explorer/foobar b/cdist/test/explorer/fixtures/conf/explorer/foobar similarity index 100% rename from lib/cdist/test/explorer/fixtures/conf/explorer/foobar rename to cdist/test/explorer/fixtures/conf/explorer/foobar diff --git a/lib/cdist/test/explorer/fixtures/conf/explorer/global b/cdist/test/explorer/fixtures/conf/explorer/global similarity index 100% rename from lib/cdist/test/explorer/fixtures/conf/explorer/global rename to cdist/test/explorer/fixtures/conf/explorer/global diff --git a/lib/cdist/test/explorer/fixtures/conf/type/__test_type/explorer/world b/cdist/test/explorer/fixtures/conf/type/__test_type/explorer/world similarity index 100% rename from lib/cdist/test/explorer/fixtures/conf/type/__test_type/explorer/world rename to cdist/test/explorer/fixtures/conf/type/__test_type/explorer/world diff --git a/lib/cdist/test/explorer/fixtures/conf/type/__test_type_object_parameter/explorer/test_parameter b/cdist/test/explorer/fixtures/conf/type/__test_type_object_parameter/explorer/test_parameter similarity index 100% rename from lib/cdist/test/explorer/fixtures/conf/type/__test_type_object_parameter/explorer/test_parameter rename to cdist/test/explorer/fixtures/conf/type/__test_type_object_parameter/explorer/test_parameter diff --git a/lib/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py similarity index 100% rename from lib/cdist/test/manifest/__init__.py rename to cdist/test/manifest/__init__.py diff --git a/lib/cdist/test/manifest/fixtures/conf/manifest/dump_environment b/cdist/test/manifest/fixtures/conf/manifest/dump_environment similarity index 100% rename from lib/cdist/test/manifest/fixtures/conf/manifest/dump_environment rename to cdist/test/manifest/fixtures/conf/manifest/dump_environment diff --git a/lib/cdist/test/manifest/fixtures/conf/manifest/init b/cdist/test/manifest/fixtures/conf/manifest/init similarity index 100% rename from lib/cdist/test/manifest/fixtures/conf/manifest/init rename to cdist/test/manifest/fixtures/conf/manifest/init diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest b/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest similarity index 100% rename from lib/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest rename to cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__moon/.keep b/cdist/test/manifest/fixtures/conf/type/__moon/.keep similarity index 100% rename from lib/cdist/test/manifest/fixtures/conf/type/__moon/.keep rename to cdist/test/manifest/fixtures/conf/type/__moon/.keep diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__moon/manifest b/cdist/test/manifest/fixtures/conf/type/__moon/manifest similarity index 100% rename from lib/cdist/test/manifest/fixtures/conf/type/__moon/manifest rename to cdist/test/manifest/fixtures/conf/type/__moon/manifest diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__moon/parameter/optional b/cdist/test/manifest/fixtures/conf/type/__moon/parameter/optional similarity index 100% rename from lib/cdist/test/manifest/fixtures/conf/type/__moon/parameter/optional rename to cdist/test/manifest/fixtures/conf/type/__moon/parameter/optional diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__moon/parameter/required b/cdist/test/manifest/fixtures/conf/type/__moon/parameter/required similarity index 100% rename from lib/cdist/test/manifest/fixtures/conf/type/__moon/parameter/required rename to cdist/test/manifest/fixtures/conf/type/__moon/parameter/required diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__planet/.keep b/cdist/test/manifest/fixtures/conf/type/__planet/.keep similarity index 100% rename from lib/cdist/test/manifest/fixtures/conf/type/__planet/.keep rename to cdist/test/manifest/fixtures/conf/type/__planet/.keep diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__planet/manifest b/cdist/test/manifest/fixtures/conf/type/__planet/manifest similarity index 100% rename from lib/cdist/test/manifest/fixtures/conf/type/__planet/manifest rename to cdist/test/manifest/fixtures/conf/type/__planet/manifest diff --git a/lib/cdist/test/manifest/fixtures/conf/type/__planet/parameter/optional b/cdist/test/manifest/fixtures/conf/type/__planet/parameter/optional similarity index 100% rename from lib/cdist/test/manifest/fixtures/conf/type/__planet/parameter/optional rename to cdist/test/manifest/fixtures/conf/type/__planet/parameter/optional diff --git a/lib/cdist/test/object/__init__.py b/cdist/test/object/__init__.py similarity index 100% rename from lib/cdist/test/object/__init__.py rename to cdist/test/object/__init__.py diff --git a/lib/cdist/test/object/fixtures/object/__first/.keep b/cdist/test/object/fixtures/object/__first/.keep similarity index 100% rename from lib/cdist/test/object/fixtures/object/__first/.keep rename to cdist/test/object/fixtures/object/__first/.keep diff --git a/lib/cdist/test/object/fixtures/object/__first/man/.cdist/.keep b/cdist/test/object/fixtures/object/__first/man/.cdist/.keep similarity index 100% rename from lib/cdist/test/object/fixtures/object/__first/man/.cdist/.keep rename to cdist/test/object/fixtures/object/__first/man/.cdist/.keep diff --git a/lib/cdist/test/object/fixtures/object/__second/.keep b/cdist/test/object/fixtures/object/__second/.keep similarity index 100% rename from lib/cdist/test/object/fixtures/object/__second/.keep rename to cdist/test/object/fixtures/object/__second/.keep diff --git a/lib/cdist/test/object/fixtures/object/__second/on-the/.cdist/.keep b/cdist/test/object/fixtures/object/__second/on-the/.cdist/.keep similarity index 100% rename from lib/cdist/test/object/fixtures/object/__second/on-the/.cdist/.keep rename to cdist/test/object/fixtures/object/__second/on-the/.cdist/.keep diff --git a/lib/cdist/test/object/fixtures/object/__third/.keep b/cdist/test/object/fixtures/object/__third/.keep similarity index 100% rename from lib/cdist/test/object/fixtures/object/__third/.keep rename to cdist/test/object/fixtures/object/__third/.keep diff --git a/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/.keep b/cdist/test/object/fixtures/object/__third/moon/.cdist/.keep similarity index 100% rename from lib/cdist/test/object/fixtures/object/__third/moon/.cdist/.keep rename to cdist/test/object/fixtures/object/__third/moon/.cdist/.keep diff --git a/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name b/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name similarity index 100% rename from lib/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name rename to cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name diff --git a/lib/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet b/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet similarity index 100% rename from lib/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet rename to cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet diff --git a/lib/cdist/test/object/fixtures/type/__first/.keep b/cdist/test/object/fixtures/type/__first/.keep similarity index 100% rename from lib/cdist/test/object/fixtures/type/__first/.keep rename to cdist/test/object/fixtures/type/__first/.keep diff --git a/lib/cdist/test/object/fixtures/type/__second/.keep b/cdist/test/object/fixtures/type/__second/.keep similarity index 100% rename from lib/cdist/test/object/fixtures/type/__second/.keep rename to cdist/test/object/fixtures/type/__second/.keep diff --git a/lib/cdist/test/object/fixtures/type/__third/.keep b/cdist/test/object/fixtures/type/__third/.keep similarity index 100% rename from lib/cdist/test/object/fixtures/type/__third/.keep rename to cdist/test/object/fixtures/type/__third/.keep diff --git a/lib/cdist/test/resolver/__init__.py b/cdist/test/resolver/__init__.py similarity index 100% rename from lib/cdist/test/resolver/__init__.py rename to cdist/test/resolver/__init__.py diff --git a/lib/cdist/test/resolver/fixtures/object/__first/.keep b/cdist/test/resolver/fixtures/object/__first/.keep similarity index 100% rename from lib/cdist/test/resolver/fixtures/object/__first/.keep rename to cdist/test/resolver/fixtures/object/__first/.keep diff --git a/lib/cdist/test/resolver/fixtures/object/__first/child/.cdist/.keep b/cdist/test/resolver/fixtures/object/__first/child/.cdist/.keep similarity index 100% rename from lib/cdist/test/resolver/fixtures/object/__first/child/.cdist/.keep rename to cdist/test/resolver/fixtures/object/__first/child/.cdist/.keep diff --git a/lib/cdist/test/resolver/fixtures/object/__first/dog/.cdist/.keep b/cdist/test/resolver/fixtures/object/__first/dog/.cdist/.keep similarity index 100% rename from lib/cdist/test/resolver/fixtures/object/__first/dog/.cdist/.keep rename to cdist/test/resolver/fixtures/object/__first/dog/.cdist/.keep diff --git a/lib/cdist/test/resolver/fixtures/object/__first/man/.cdist/.keep b/cdist/test/resolver/fixtures/object/__first/man/.cdist/.keep similarity index 100% rename from lib/cdist/test/resolver/fixtures/object/__first/man/.cdist/.keep rename to cdist/test/resolver/fixtures/object/__first/man/.cdist/.keep diff --git a/lib/cdist/test/resolver/fixtures/object/__first/woman/.cdist/.keep b/cdist/test/resolver/fixtures/object/__first/woman/.cdist/.keep similarity index 100% rename from lib/cdist/test/resolver/fixtures/object/__first/woman/.cdist/.keep rename to cdist/test/resolver/fixtures/object/__first/woman/.cdist/.keep diff --git a/lib/cdist/test/resolver/fixtures/object/__second/.keep b/cdist/test/resolver/fixtures/object/__second/.keep similarity index 100% rename from lib/cdist/test/resolver/fixtures/object/__second/.keep rename to cdist/test/resolver/fixtures/object/__second/.keep diff --git a/lib/cdist/test/resolver/fixtures/object/__second/on-the/.cdist/.keep b/cdist/test/resolver/fixtures/object/__second/on-the/.cdist/.keep similarity index 100% rename from lib/cdist/test/resolver/fixtures/object/__second/on-the/.cdist/.keep rename to cdist/test/resolver/fixtures/object/__second/on-the/.cdist/.keep diff --git a/lib/cdist/test/resolver/fixtures/object/__second/under-the/.cdist/.keep b/cdist/test/resolver/fixtures/object/__second/under-the/.cdist/.keep similarity index 100% rename from lib/cdist/test/resolver/fixtures/object/__second/under-the/.cdist/.keep rename to cdist/test/resolver/fixtures/object/__second/under-the/.cdist/.keep diff --git a/lib/cdist/test/resolver/fixtures/object/__third/.keep b/cdist/test/resolver/fixtures/object/__third/.keep similarity index 100% rename from lib/cdist/test/resolver/fixtures/object/__third/.keep rename to cdist/test/resolver/fixtures/object/__third/.keep diff --git a/lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/.keep b/cdist/test/resolver/fixtures/object/__third/moon/.cdist/.keep similarity index 100% rename from lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/.keep rename to cdist/test/resolver/fixtures/object/__third/moon/.cdist/.keep diff --git a/lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name b/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name similarity index 100% rename from lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name rename to cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name diff --git a/lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet b/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet similarity index 100% rename from lib/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet rename to cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet diff --git a/lib/cdist/test/resolver/fixtures/type/__first/.keep b/cdist/test/resolver/fixtures/type/__first/.keep similarity index 100% rename from lib/cdist/test/resolver/fixtures/type/__first/.keep rename to cdist/test/resolver/fixtures/type/__first/.keep diff --git a/lib/cdist/test/resolver/fixtures/type/__second/.keep b/cdist/test/resolver/fixtures/type/__second/.keep similarity index 100% rename from lib/cdist/test/resolver/fixtures/type/__second/.keep rename to cdist/test/resolver/fixtures/type/__second/.keep diff --git a/lib/cdist/test/resolver/fixtures/type/__third/.keep b/cdist/test/resolver/fixtures/type/__third/.keep similarity index 100% rename from lib/cdist/test/resolver/fixtures/type/__third/.keep rename to cdist/test/resolver/fixtures/type/__third/.keep diff --git a/lib/cdist/test/type/__init__.py b/cdist/test/type/__init__.py similarity index 100% rename from lib/cdist/test/type/__init__.py rename to cdist/test/type/__init__.py diff --git a/lib/cdist/test/type/fixtures/__install/install b/cdist/test/type/fixtures/__install/install similarity index 100% rename from lib/cdist/test/type/fixtures/__install/install rename to cdist/test/type/fixtures/__install/install diff --git a/lib/cdist/test/type/fixtures/__name_path/.keep b/cdist/test/type/fixtures/__name_path/.keep similarity index 100% rename from lib/cdist/test/type/fixtures/__name_path/.keep rename to cdist/test/type/fixtures/__name_path/.keep diff --git a/lib/cdist/test/type/fixtures/__not_install/.keep b/cdist/test/type/fixtures/__not_install/.keep similarity index 100% rename from lib/cdist/test/type/fixtures/__not_install/.keep rename to cdist/test/type/fixtures/__not_install/.keep diff --git a/lib/cdist/test/type/fixtures/__not_singleton/.keep b/cdist/test/type/fixtures/__not_singleton/.keep similarity index 100% rename from lib/cdist/test/type/fixtures/__not_singleton/.keep rename to cdist/test/type/fixtures/__not_singleton/.keep diff --git a/lib/cdist/test/type/fixtures/__singleton/singleton b/cdist/test/type/fixtures/__singleton/singleton similarity index 100% rename from lib/cdist/test/type/fixtures/__singleton/singleton rename to cdist/test/type/fixtures/__singleton/singleton diff --git a/lib/cdist/test/type/fixtures/__with_boolean_parameters/parameter/boolean b/cdist/test/type/fixtures/__with_boolean_parameters/parameter/boolean similarity index 100% rename from lib/cdist/test/type/fixtures/__with_boolean_parameters/parameter/boolean rename to cdist/test/type/fixtures/__with_boolean_parameters/parameter/boolean diff --git a/lib/cdist/test/type/fixtures/__with_explorers/explorer/whatever b/cdist/test/type/fixtures/__with_explorers/explorer/whatever similarity index 100% rename from lib/cdist/test/type/fixtures/__with_explorers/explorer/whatever rename to cdist/test/type/fixtures/__with_explorers/explorer/whatever diff --git a/lib/cdist/test/type/fixtures/__with_optional_parameters/parameter/optional b/cdist/test/type/fixtures/__with_optional_parameters/parameter/optional similarity index 100% rename from lib/cdist/test/type/fixtures/__with_optional_parameters/parameter/optional rename to cdist/test/type/fixtures/__with_optional_parameters/parameter/optional diff --git a/lib/cdist/test/type/fixtures/__with_required_parameters/parameter/required b/cdist/test/type/fixtures/__with_required_parameters/parameter/required similarity index 100% rename from lib/cdist/test/type/fixtures/__with_required_parameters/parameter/required rename to cdist/test/type/fixtures/__with_required_parameters/parameter/required diff --git a/lib/cdist/test/type/fixtures/__without_boolean_parameters/.keep b/cdist/test/type/fixtures/__without_boolean_parameters/.keep similarity index 100% rename from lib/cdist/test/type/fixtures/__without_boolean_parameters/.keep rename to cdist/test/type/fixtures/__without_boolean_parameters/.keep diff --git a/lib/cdist/test/type/fixtures/__without_explorers/.keep b/cdist/test/type/fixtures/__without_explorers/.keep similarity index 100% rename from lib/cdist/test/type/fixtures/__without_explorers/.keep rename to cdist/test/type/fixtures/__without_explorers/.keep diff --git a/lib/cdist/test/type/fixtures/__without_optional_parameters/.keep b/cdist/test/type/fixtures/__without_optional_parameters/.keep similarity index 100% rename from lib/cdist/test/type/fixtures/__without_optional_parameters/.keep rename to cdist/test/type/fixtures/__without_optional_parameters/.keep diff --git a/lib/cdist/test/type/fixtures/__without_required_parameters/.keep b/cdist/test/type/fixtures/__without_required_parameters/.keep similarity index 100% rename from lib/cdist/test/type/fixtures/__without_required_parameters/.keep rename to cdist/test/type/fixtures/__without_required_parameters/.keep diff --git a/lib/cdist/test/type/fixtures/list_types/__first/.keep b/cdist/test/type/fixtures/list_types/__first/.keep similarity index 100% rename from lib/cdist/test/type/fixtures/list_types/__first/.keep rename to cdist/test/type/fixtures/list_types/__first/.keep diff --git a/lib/cdist/test/type/fixtures/list_types/__second/.keep b/cdist/test/type/fixtures/list_types/__second/.keep similarity index 100% rename from lib/cdist/test/type/fixtures/list_types/__second/.keep rename to cdist/test/type/fixtures/list_types/__second/.keep diff --git a/lib/cdist/test/type/fixtures/list_types/__third/.keep b/cdist/test/type/fixtures/list_types/__third/.keep similarity index 100% rename from lib/cdist/test/type/fixtures/list_types/__third/.keep rename to cdist/test/type/fixtures/list_types/__third/.keep diff --git a/lib/cdist/test/util/__init__.py b/cdist/test/util/__init__.py similarity index 100% rename from lib/cdist/test/util/__init__.py rename to cdist/test/util/__init__.py diff --git a/lib/cdist/test/util/fsproperty.py b/cdist/test/util/fsproperty.py similarity index 100% rename from lib/cdist/test/util/fsproperty.py rename to cdist/test/util/fsproperty.py diff --git a/lib/cdist/util/__init__.py b/cdist/util/__init__.py similarity index 100% rename from lib/cdist/util/__init__.py rename to cdist/util/__init__.py diff --git a/lib/cdist/util/fsproperty.py b/cdist/util/fsproperty.py similarity index 100% rename from lib/cdist/util/fsproperty.py rename to cdist/util/fsproperty.py From 814c5e04d9db3193b935f768f1f56fbc0d8fe244 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 17:42:38 +0200 Subject: [PATCH 1652/4212] add initial setup.py Signed-off-by: Nico Schottelius --- setup.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 setup.py diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..92194071 --- /dev/null +++ b/setup.py @@ -0,0 +1,34 @@ +from distutils.core import setup + +setup( + name = "cdist", + packages = ["cdist"], + version = "2.1.0", + description = "Usable configuration management system", + author = "Nico Schottelius", + author_email = "nico-cdist-pypi@schottelius.org", + url = "http://www.nico.schottelius.org/software/cdist/", + classifiers = [ + "Development Status :: 6 - Mature", + "Environment :: Console", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", + "Operating System :: MacOS :: MacOS X", + "Operating System :: POSIX", + "Operating System :: POSIX :: BSD", + "Operating System :: POSIX :: Linux", + "Operating System :: Unix", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Topic :: System :: Boot", + "Topic :: System :: Installation/Setup", + "Topic :: System :: Operating System", + "Topic :: System :: Software Distribution", + "Topic :: Utilities" + ], + long_description = ''' + cdist is a usable configuration management system. + It adheres to the KISS principle and is being used in small up to enterprise grade environments. + cdist is an alternative to other configuration management systems like cfengine, bcfg2, chef and puppet. + ''' +) From abb384c2708224ba20a535c63c22e5969aaa08b2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 17:43:20 +0200 Subject: [PATCH 1653/4212] add manifest for distutils Signed-off-by: Nico Schottelius --- MANIFEST.in | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..ae20db47 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +include docs/changelog docs/changelog-2.1 +recursive-include docs/gfx +recursive-include docs *.mdwn From 392ec3c5edbea53179325fabfbce47493ade48d5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 17:46:19 +0200 Subject: [PATCH 1654/4212] correct link to __file Signed-off-by: Nico Schottelius --- cdist/test/emulator/fixtures/conf/type/__file | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/test/emulator/fixtures/conf/type/__file b/cdist/test/emulator/fixtures/conf/type/__file index c57c4134..8458361c 120000 --- a/cdist/test/emulator/fixtures/conf/type/__file +++ b/cdist/test/emulator/fixtures/conf/type/__file @@ -1 +1 @@ -../../../../../../../conf/type/__file \ No newline at end of file +../../../../../../conf/type/__file \ No newline at end of file From f25989d779f9926a89ad4f7d1b3d39a03e8071e9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 18:28:19 +0200 Subject: [PATCH 1655/4212] build MANIFEST ourselves Signed-off-by: Nico Schottelius --- .gitignore | 3 ++- MANIFEST.in | 3 --- build | 57 +++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 44 insertions(+), 19 deletions(-) delete mode 100644 MANIFEST.in diff --git a/.gitignore b/.gitignore index fe52a82f..5fc6b0ad 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,6 @@ docs/man/man*/docbook-xsl.css # Ignore cdist cache for version control /cache/ -# Python / cache +# Python: cache, distutils __pycache__/ +MANIFEST diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index ae20db47..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include docs/changelog docs/changelog-2.1 -recursive-include docs/gfx -recursive-include docs *.mdwn diff --git a/build b/build index d3f8ca3a..59bc0b65 100755 --- a/build +++ b/build @@ -45,12 +45,37 @@ MAN7DSTDIR=${MANDIR}/man7 SPEECHESDIR=docs/speeches case "$1" in - man) - set -e - "$0" mangen - "$0" mantype - "$0" manbuild - ;; + man) + set -e + "$0" mangen + "$0" mantype + "$0" manbuild + ;; + + pypi-manifest) + : > MANIFEST + # bin + echo bin/cdist >> MANIFEST + + # conf + find conf >> MANIFEST + + # docs + ls docs/changelog* >> MANIFEST + find docs/gfx >> MANIFEST + find docs/man/ -name \*.text >> MANIFEST + find docs/man/ -name \*.text.sh >> MANIFEST + + # other + find other/ >> MANIFEST + + + ;; + + pypi) + $0 pypi-manifest + python3 setup.py sdist + ;; manbuild) trap abort INT @@ -133,15 +158,17 @@ case "$1" in 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 - ;; + 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 + ;; test) shift # skip t From 45a4719fb0c08dcc7ab00076881a07b578a68586 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 18:29:49 +0200 Subject: [PATCH 1656/4212] clean before running pypi Signed-off-by: Nico Schottelius --- build | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build b/build index 59bc0b65..fa0e78a2 100755 --- a/build +++ b/build @@ -73,6 +73,7 @@ case "$1" in ;; pypi) + $0 clean $0 pypi-manifest python3 setup.py sdist ;; @@ -168,6 +169,8 @@ case "$1" in | xargs rm -f find * -name __pycache__ | xargs rm -rf + + rm -f MANIFEST ;; test) From 65128e4bcfa7d73e25abc459914488a9b832df13 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 18:44:05 +0200 Subject: [PATCH 1657/4212] re-indent Signed-off-by: Nico Schottelius --- build | 287 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 146 insertions(+), 141 deletions(-) diff --git a/build b/build index fa0e78a2..bb8d60f5 100755 --- a/build +++ b/build @@ -45,157 +45,162 @@ MAN7DSTDIR=${MANDIR}/man7 SPEECHESDIR=docs/speeches case "$1" in - man) - set -e - "$0" mangen - "$0" mantype - "$0" manbuild - ;; + man) + set -e + "$0" mangen + "$0" mantype + "$0" manbuild + ;; - pypi-manifest) - : > MANIFEST - # bin - echo bin/cdist >> MANIFEST - - # conf - find conf >> MANIFEST + pypi-manifest) + # init MANIFEST + echo README > MANIFEST - # docs - ls docs/changelog* >> MANIFEST - find docs/gfx >> MANIFEST - find docs/man/ -name \*.text >> MANIFEST - find docs/man/ -name \*.text.sh >> MANIFEST + # bin + echo bin/cdist >> MANIFEST + + # main source + find cdist -type f >> MANIFEST - # other - find other/ >> MANIFEST + # conf + find conf -type f >> MANIFEST + + # docs + ls docs/changelog* >> MANIFEST + find docs/gfx -type f >> MANIFEST + find docs/man/ -type f -name \*.text >> MANIFEST + find docs/man/ -type f -name \*.text.sh >> MANIFEST + + # other + find other/ -type f >> MANIFEST - ;; + ;; - pypi) - $0 clean - $0 pypi-manifest - python3 setup.py sdist - ;; + pypi) + $0 clean + $0 pypi-manifest + python3 setup.py sdist + ;; - 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 - ;; - - mantype) - for mansrc in conf/type/*/man.text; do - dst="$(echo $mansrc | sed -e 's;conf/;cdist-;' -e 's;/;;' -e 's;/man;;' -e 's;^;docs/man/man7/;')" - ln -sf "../../../$mansrc" "$dst" - done - ;; - - mangen) - ${MANDIR}/cdist-reference.text.sh - ;; - - release) - ./docs/dev/releasechecklist - ;; - - speeches) - cd "$SPEECHESDIR" - for speech in *tex; do - pdflatex "$speech" - pdflatex "$speech" - pdflatex "$speech" - done - ;; - - webmain) - cp README ${WEBPAGE} - cd ${WEBDIR} && git commit -m "cdist main update" ${WEBPAGE} - cd ${WEBDIR} && make pub - ;; - - web) - cp README ${WEBPAGE} - rm -rf ${WEBMAN} - mkdir -p ${WEBMAN}/man1 ${WEBMAN}/man7 - - # old stuff - # rm -rf ${WEBDIR}/${WEBBASE}/speeches && mkdir ${WEBDIR}/${WEBBASE}/speeches - # cp ${SPEECHESDIR}/*.pdf ${WEBDIR}/${WEBBASE}/speeches - # git describe > ${WEBDIR}/${WEBBASE}/man/VERSION - - cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${WEBMAN}/man1 - cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${WEBMAN}/man7 - - cd ${WEBDIR} && git add ${WEBBASE} - cd ${WEBDIR} && git commit -m "cdist update" ${WEBBASE} ${WEBPAGE} - cd ${WEBDIR} && make 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 "$version" latest" - ;; - - p|pu|pub) - for remote in "" github sf ethz; do - echo "Pushing to $remote" - git push --mirror $remote + 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 - ;; - - 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 - - rm -f MANIFEST ;; - test) - shift # skip t - export PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib + mantype) + for mansrc in conf/type/*/man.text; do + dst="$(echo $mansrc | sed -e 's;conf/;cdist-;' -e 's;/;;' -e 's;/man;;' -e 's;^;docs/man/man7/;')" + ln -sf "../../../$mansrc" "$dst" + done + ;; - if [ $# -lt 1 ]; then - python3 -m cdist.test - else - python3 -m unittest "$@" - fi - ;; + mangen) + ${MANDIR}/cdist-reference.text.sh + ;; - *) - 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 - exit 1 - ;; + release) + ./docs/dev/releasechecklist + ;; + + speeches) + cd "$SPEECHESDIR" + for speech in *tex; do + pdflatex "$speech" + pdflatex "$speech" + pdflatex "$speech" + done + ;; + + webmain) + cp README ${WEBPAGE} + cd ${WEBDIR} && git commit -m "cdist main update" ${WEBPAGE} + cd ${WEBDIR} && make pub + ;; + + web) + cp README ${WEBPAGE} + rm -rf ${WEBMAN} + mkdir -p ${WEBMAN}/man1 ${WEBMAN}/man7 + + # old stuff + # rm -rf ${WEBDIR}/${WEBBASE}/speeches && mkdir ${WEBDIR}/${WEBBASE}/speeches + # cp ${SPEECHESDIR}/*.pdf ${WEBDIR}/${WEBBASE}/speeches + # git describe > ${WEBDIR}/${WEBBASE}/man/VERSION + + cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${WEBMAN}/man1 + cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${WEBMAN}/man7 + + cd ${WEBDIR} && git add ${WEBBASE} + cd ${WEBDIR} && git commit -m "cdist update" ${WEBBASE} ${WEBPAGE} + cd ${WEBDIR} && make 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 "$version" latest" + ;; + + p|pu|pub) + for remote in "" github sf ethz; do + echo "Pushing to $remote" + git push --mirror $remote + 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 + + rm -f MANIFEST + ;; + + test) + shift # skip t + export PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib + + if [ $# -lt 1 ]; then + python3 -m cdist.test + else + python3 -m unittest "$@" + fi + ;; + + *) + 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 + exit 1 + ;; esac From 37db1e8c2fe2ed469260769a8f78e0104ec2598e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 18:47:48 +0200 Subject: [PATCH 1658/4212] retry MANIFEST.in, when deleting cache before Signed-off-by: Nico Schottelius --- MANIFEST.in | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..6b86bbd0 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +include docs/changelog docs/changelog-2.1 +recursive-include docs/gfx *.png *.text +recursive-include docs *.text From d20ae0596d484c928df39b00f98c2ae4d223f7ce Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 19:07:50 +0200 Subject: [PATCH 1659/4212] pypi cleanups Signed-off-by: Nico Schottelius --- .gitignore | 1 + MANIFEST.in | 2 +- build | 77 +++++++++++++++++++---------------------------------- 3 files changed, 30 insertions(+), 50 deletions(-) diff --git a/.gitignore b/.gitignore index 5fc6b0ad..71b70251 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ docs/man/man*/docbook-xsl.css # Python: cache, distutils __pycache__/ MANIFEST +dist/ diff --git a/MANIFEST.in b/MANIFEST.in index 6b86bbd0..b4935a92 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ include docs/changelog docs/changelog-2.1 recursive-include docs/gfx *.png *.text -recursive-include docs *.text +recursive-include docs *.text *.html *.1 *.7 diff --git a/build b/build index bb8d60f5..4b5690ef 100755 --- a/build +++ b/build @@ -45,43 +45,12 @@ MAN7DSTDIR=${MANDIR}/man7 SPEECHESDIR=docs/speeches case "$1" in - man) - set -e - "$0" mangen - "$0" mantype - "$0" manbuild - ;; - - pypi-manifest) - # init MANIFEST - echo README > MANIFEST - - # bin - echo bin/cdist >> MANIFEST - - # main source - find cdist -type f >> MANIFEST - - # conf - find conf -type f >> MANIFEST - - # docs - ls docs/changelog* >> MANIFEST - find docs/gfx -type f >> MANIFEST - find docs/man/ -type f -name \*.text >> MANIFEST - find docs/man/ -type f -name \*.text.sh >> MANIFEST - - # other - find other/ -type f >> MANIFEST - - - ;; - - pypi) - $0 clean - $0 pypi-manifest - python3 setup.py sdist - ;; + man) + set -e + "$0" mangen + "$0" mantype + "$0" manbuild + ;; manbuild) trap abort INT @@ -119,6 +88,12 @@ case "$1" in ./docs/dev/releasechecklist ;; + pypi) + $0 very-clean + $0 man + python3 setup.py sdist + ;; + speeches) cd "$SPEECHESDIR" for speech in *tex; do @@ -164,19 +139,23 @@ case "$1" in 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 + 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 - rm -f MANIFEST - ;; + find * -name __pycache__ | xargs rm -rf + + rm -f MANIFEST + ;; + very-clean) + $0 clean + rm -rf cache/ + ;; test) shift # skip t From afbfc031f7a9bc794439fde2bacf0d6916b84c1f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 19:12:22 +0200 Subject: [PATCH 1660/4212] begin to split off version information from source Signed-off-by: Nico Schottelius --- .version | 1 + doc/dev/logs/2012-10-25.version-split | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 .version create mode 100644 doc/dev/logs/2012-10-25.version-split diff --git a/.version b/.version new file mode 100644 index 00000000..3d45b5c6 --- /dev/null +++ b/.version @@ -0,0 +1 @@ +2.0.14 diff --git a/doc/dev/logs/2012-10-25.version-split b/doc/dev/logs/2012-10-25.version-split new file mode 100644 index 00000000..975e1173 --- /dev/null +++ b/doc/dev/logs/2012-10-25.version-split @@ -0,0 +1,3 @@ +- store version in .version +- when distributed / packaged, include .version into sourcecode +- when in git checkout, use dynamic versioning From 637e4b28cbd091766ee51687be435d12bb6c2a32 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 22:19:27 +0200 Subject: [PATCH 1661/4212] include base for dynamic and static versioning Signed-off-by: Nico Schottelius --- build | 16 ++++++++++++++-- doc/dev/logs/2012-10-25.version-split | 7 ++++--- lib/cdist/__init__.py | 11 +++-------- lib/cdist/version.py | 1 + lib/cdist/version_dynamic.py | 27 +++++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 13 deletions(-) create mode 120000 lib/cdist/version.py create mode 100644 lib/cdist/version_dynamic.py diff --git a/build b/build index bec7f5a9..a9647ff1 100755 --- a/build +++ b/build @@ -134,7 +134,7 @@ case "$1" in ;; clean) - rm -f ${MAN7DSTDIR}/cdist-reference.text + rm -f ${MAN7DSTDIR}/cdist-reference.text lib/cdist/version.py find "${MANDIR}" -mindepth 2 -type l \ -o -name "*.1" \ -o -name "*.7" \ @@ -154,7 +154,19 @@ case "$1" in fi ;; - *) + version-dynamic) + cd lib/cdist/ + ln -sf version_dynamic.py version.py + ;; + + version-dist) + version=$(cat .version) + cd lib/cdist/ + echo "VERSION=\"$version\"" > version_static.py + ln -sf version_static.py version.py + ;; + + *) echo '' echo 'Welcome to cdist!' echo '' diff --git a/doc/dev/logs/2012-10-25.version-split b/doc/dev/logs/2012-10-25.version-split index 975e1173..f381c48f 100644 --- a/doc/dev/logs/2012-10-25.version-split +++ b/doc/dev/logs/2012-10-25.version-split @@ -1,3 +1,4 @@ -- store version in .version -- when distributed / packaged, include .version into sourcecode -- when in git checkout, use dynamic versioning +x store version in .version +x when distributed / packaged, include .version into sourcecode + split into two files +x when in git checkout, use dynamic versioning diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index 85bc5f77..02d708b1 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -22,14 +22,9 @@ import os import subprocess -try: - with open(os.devnull, 'w') as devnull: - here = os.path.dirname(os.path.realpath(__file__)) - VERSION = subprocess.check_output( - 'cd "%s" && git describe' % here, - stderr=devnull, shell=True).decode('utf-8') -except: - VERSION = "2.0.14" +import cdist.version + +VERSION = cdist.version.VERSION BANNER = """ .. . .x+=:. s diff --git a/lib/cdist/version.py b/lib/cdist/version.py new file mode 120000 index 00000000..153cf043 --- /dev/null +++ b/lib/cdist/version.py @@ -0,0 +1 @@ +version_dynamic.py \ No newline at end of file diff --git a/lib/cdist/version_dynamic.py b/lib/cdist/version_dynamic.py new file mode 100644 index 00000000..5f69f374 --- /dev/null +++ b/lib/cdist/version_dynamic.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# +# 2010-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 subprocess + +here = os.path.dirname(os.path.realpath(__file__)) +VERSION = subprocess.check_output('cd "%s" && git describe' % here, + shell=True).decode('utf-8') From d3c7abbaba7935efd8c4e6a9176ecef8ee36deb0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 22:32:05 +0200 Subject: [PATCH 1662/4212] ignore static version Signed-off-by: Nico Schottelius --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 69a8ea98..b86e4a99 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ doc/man/man*/docbook-xsl.css # Python / cache __pycache__/ + +# Is static and will never be included +lib/cdist/version_static.py From 91c1374657e9122e4527d1f08f8ad8d08c6990f4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 23:37:15 +0200 Subject: [PATCH 1663/4212] begin restructering for python package Signed-off-by: Nico Schottelius --- .gitignore | 2 +- .version | 2 +- bin/cdist | 233 +--------------- cdist.py | 248 ++++++++++++++++++ cdist/test/emulator/fixtures/conf/type/__file | 2 +- {lib/cdist => cdist}/version.py | 0 {lib/cdist => cdist}/version_dynamic.py | 0 7 files changed, 256 insertions(+), 231 deletions(-) create mode 100755 cdist.py rename {lib/cdist => cdist}/version.py (100%) rename {lib/cdist => cdist}/version_dynamic.py (100%) diff --git a/.gitignore b/.gitignore index 786c706d..707b5f66 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,4 @@ docs/man/man7/cdist-reference.text __pycache__/ MANIFEST dist/ -lib/cdist/version_static.py +cdist/version_static.py diff --git a/.version b/.version index 3d45b5c6..71f08595 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.0.14 +2.1.0-pre1 diff --git a/bin/cdist b/bin/cdist index 75047acb..15127d2b 100755 --- a/bin/cdist +++ b/bin/cdist @@ -1,7 +1,7 @@ -#!/usr/bin/env python3 +#!/bin/sh # -*- coding: utf-8 -*- # -# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -20,229 +20,6 @@ # # -def commandline(): - """Parse command line""" - import argparse - - import cdist.banner - import cdist.config - import cdist.install - - # Construct parser others can reuse - parser = {} - # Options _all_ parsers have in common - parser['loglevel'] = argparse.ArgumentParser(add_help=False) - parser['loglevel'].add_argument('-d', '--debug', - help='Set log level to debug', action='store_true', - default=False) - parser['loglevel'].add_argument('-v', '--verbose', - help='Set log level to info, be more verbose', - action='store_true', default=False) - - # Main subcommand parser - parser['main'] = argparse.ArgumentParser(description='cdist ' + cdist.VERSION, - parents=[parser['loglevel']]) - parser['main'].add_argument('-V', '--version', - help='Show version', action='version', - version='%(prog)s ' + cdist.VERSION) - parser['sub'] = parser['main'].add_subparsers(title="Commands") - - # Banner - parser['banner'] = parser['sub'].add_parser('banner', - 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='+', - help='one or more hosts to operate on') - parser['configinstall'].add_argument('-c', '--cdist-home', - help='Change cdist home (default: .. from bin directory)', - action='store') - 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('-p', '--parallel', - help='Operate on multiple hosts in parallel', - action='store_true', dest='parallel') - parser['configinstall'].add_argument('-s', '--sequential', - help='Operate on multiple hosts sequentially (default)', - action='store_false', dest='parallel') - - 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") - 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") - - # Config - parser['config'] = parser['sub'].add_parser('config', - parents=[parser['loglevel'], parser['configinstall']]) - parser['config'].set_defaults(func=config) - - # 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/" - - args = parser['main'].parse_args(sys.argv[1:]) - - # Loglevels are handled globally in here and debug wins over verbose - if args.verbose: - logging.root.setLevel(logging.INFO) - if args.debug: - logging.root.setLevel(logging.DEBUG) - - log.debug(args) - args.func(args) - -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 deploy to 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, - base_path=args.cdist_home, - exec_path=sys.argv[0], - debug=args.debug) - - c = mode(context) - c.deploy_and_cleanup() - context.cleanup() - - except cdist.Error as e: - # We are running in our own process here, need to sys.exit! - if parallel: - log.error(e) - 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 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 - - cdistpythonversion = '3.2' - if sys.version < cdistpythonversion: - print('Cdist requires Python >= ' + cdistpythonversion + - ' on the source host.', file=sys.stderr) - sys.exit(1) - - - exit_code = 0 - - try: - import logging - import os - import re - - # Ensure our /lib/ is included into PYTHON_PATH - sys.path.insert(0, os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) - - # And now import our stuff - import cdist - - log = logging.getLogger("cdist") - - logging.basicConfig(format='%(levelname)s: %(message)s') - - if re.match("__", os.path.basename(sys.argv[0])): - emulator() - else: - commandline() - - except KeyboardInterrupt: - pass - - except cdist.Error as e: - log.error(e) - exit_code = 1 - - # Determine exit code by return value of function - - sys.exit(exit_code) +# Wrapper for real script to allow execution from checkout +dir=${0%/*} +"$dir/../cdist.py" "$@" diff --git a/cdist.py b/cdist.py new file mode 100755 index 00000000..75047acb --- /dev/null +++ b/cdist.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 2010-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 . +# +# + +def commandline(): + """Parse command line""" + import argparse + + import cdist.banner + import cdist.config + import cdist.install + + # Construct parser others can reuse + parser = {} + # Options _all_ parsers have in common + parser['loglevel'] = argparse.ArgumentParser(add_help=False) + parser['loglevel'].add_argument('-d', '--debug', + help='Set log level to debug', action='store_true', + default=False) + parser['loglevel'].add_argument('-v', '--verbose', + help='Set log level to info, be more verbose', + action='store_true', default=False) + + # Main subcommand parser + parser['main'] = argparse.ArgumentParser(description='cdist ' + cdist.VERSION, + parents=[parser['loglevel']]) + parser['main'].add_argument('-V', '--version', + help='Show version', action='version', + version='%(prog)s ' + cdist.VERSION) + parser['sub'] = parser['main'].add_subparsers(title="Commands") + + # Banner + parser['banner'] = parser['sub'].add_parser('banner', + 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='+', + help='one or more hosts to operate on') + parser['configinstall'].add_argument('-c', '--cdist-home', + help='Change cdist home (default: .. from bin directory)', + action='store') + 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('-p', '--parallel', + help='Operate on multiple hosts in parallel', + action='store_true', dest='parallel') + parser['configinstall'].add_argument('-s', '--sequential', + help='Operate on multiple hosts sequentially (default)', + action='store_false', dest='parallel') + + 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") + 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") + + # Config + parser['config'] = parser['sub'].add_parser('config', + parents=[parser['loglevel'], parser['configinstall']]) + parser['config'].set_defaults(func=config) + + # 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/" + + args = parser['main'].parse_args(sys.argv[1:]) + + # Loglevels are handled globally in here and debug wins over verbose + if args.verbose: + logging.root.setLevel(logging.INFO) + if args.debug: + logging.root.setLevel(logging.DEBUG) + + log.debug(args) + args.func(args) + +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 deploy to 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, + base_path=args.cdist_home, + exec_path=sys.argv[0], + debug=args.debug) + + c = mode(context) + c.deploy_and_cleanup() + context.cleanup() + + except cdist.Error as e: + # We are running in our own process here, need to sys.exit! + if parallel: + log.error(e) + 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 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 + + cdistpythonversion = '3.2' + if sys.version < cdistpythonversion: + print('Cdist requires Python >= ' + cdistpythonversion + + ' on the source host.', file=sys.stderr) + sys.exit(1) + + + exit_code = 0 + + try: + import logging + import os + import re + + # Ensure our /lib/ is included into PYTHON_PATH + sys.path.insert(0, os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) + + # And now import our stuff + import cdist + + log = logging.getLogger("cdist") + + logging.basicConfig(format='%(levelname)s: %(message)s') + + if re.match("__", os.path.basename(sys.argv[0])): + emulator() + else: + commandline() + + except KeyboardInterrupt: + pass + + except cdist.Error as e: + log.error(e) + exit_code = 1 + + # Determine exit code by return value of function + + sys.exit(exit_code) diff --git a/cdist/test/emulator/fixtures/conf/type/__file b/cdist/test/emulator/fixtures/conf/type/__file index 8458361c..c57c4134 120000 --- a/cdist/test/emulator/fixtures/conf/type/__file +++ b/cdist/test/emulator/fixtures/conf/type/__file @@ -1 +1 @@ -../../../../../../conf/type/__file \ No newline at end of file +../../../../../../../conf/type/__file \ No newline at end of file diff --git a/lib/cdist/version.py b/cdist/version.py similarity index 100% rename from lib/cdist/version.py rename to cdist/version.py diff --git a/lib/cdist/version_dynamic.py b/cdist/version_dynamic.py similarity index 100% rename from lib/cdist/version_dynamic.py rename to cdist/version_dynamic.py From 136bb01a67fed7c55426b62cbe84b1dc8818a55f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 23:43:12 +0200 Subject: [PATCH 1664/4212] correct placement in build script Signed-off-by: Nico Schottelius --- build | 33 +++++++++++++++++++-------------- setup.py | 9 +++++++-- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/build b/build index 1dedabba..7d73224d 100755 --- a/build +++ b/build @@ -89,8 +89,13 @@ case "$1" in ;; pypi) - $0 very-clean - $0 man + #$0 very-clean + #$0 man + $0 version-dist + $0 sdist + $0 version-dynamic + ;; + sdist) python3 setup.py sdist ;; @@ -159,7 +164,6 @@ case "$1" in test) shift # skip t - export PYTHONPATH=$PYTHONPATH:$(pwd -P)/lib if [ $# -lt 1 ]; then python3 -m cdist.test @@ -168,6 +172,18 @@ case "$1" in fi ;; + version-dynamic) + cd cdist/ + ln -sf version_dynamic.py version.py + ;; + + version-dist) + version=$(cat .version) + cd cdist/ + echo "VERSION=\"$version\"" > version_static.py + ln -sf version_static.py version.py + ;; + *) echo '' echo 'Welcome to cdist!' @@ -183,15 +199,4 @@ case "$1" in exit 1 ;; - version-dynamic) - cd lib/cdist/ - ln -sf version_dynamic.py version.py - ;; - - version-dist) - version=$(cat .version) - cd lib/cdist/ - echo "VERSION=\"$version\"" > version_static.py - ln -sf version_static.py version.py - ;; esac diff --git a/setup.py b/setup.py index 92194071..62ee480c 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,14 @@ from distutils.core import setup +package_dir = {'': 'lib'} + +import cdist + setup( name = "cdist", - packages = ["cdist"], - version = "2.1.0", + packages = ["cdist", "cdist.core", "cdist.exec", "cdist.util" ], + scripts = ["cdist.py"], + version = cdist.version.VERSION, description = "Usable configuration management system", author = "Nico Schottelius", author_email = "nico-cdist-pypi@schottelius.org", From 3cf59fdf9a1ebdde176835dd2f986dd6465d6dd4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 23:45:56 +0200 Subject: [PATCH 1665/4212] always use dynamic version - on shipping included generated version Signed-off-by: Nico Schottelius --- bin/cdist | 1 + build | 12 ++---------- cdist/version.py | 1 - cdist/version_dynamic.py | 27 --------------------------- 4 files changed, 3 insertions(+), 38 deletions(-) delete mode 120000 cdist/version.py delete mode 100644 cdist/version_dynamic.py diff --git a/bin/cdist b/bin/cdist index 15127d2b..5c1239fb 100755 --- a/bin/cdist +++ b/bin/cdist @@ -22,4 +22,5 @@ # Wrapper for real script to allow execution from checkout dir=${0%/*} +"$dir/../build" version "$dir/../cdist.py" "$@" diff --git a/build b/build index 7d73224d..f8d6c74a 100755 --- a/build +++ b/build @@ -172,16 +172,8 @@ case "$1" in fi ;; - version-dynamic) - cd cdist/ - ln -sf version_dynamic.py version.py - ;; - - version-dist) - version=$(cat .version) - cd cdist/ - echo "VERSION=\"$version\"" > version_static.py - ln -sf version_static.py version.py + version) + echo "VERSION=\"$version\"" > cdist/version.py ;; *) diff --git a/cdist/version.py b/cdist/version.py deleted file mode 120000 index 153cf043..00000000 --- a/cdist/version.py +++ /dev/null @@ -1 +0,0 @@ -version_dynamic.py \ No newline at end of file diff --git a/cdist/version_dynamic.py b/cdist/version_dynamic.py deleted file mode 100644 index 5f69f374..00000000 --- a/cdist/version_dynamic.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: utf-8 -*- -# -# 2010-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 subprocess - -here = os.path.dirname(os.path.realpath(__file__)) -VERSION = subprocess.check_output('cd "%s" && git describe' % here, - shell=True).decode('utf-8') From af8f944aaf8d72bd6c9f9287cee40d8ac7ff7f08 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 23:47:32 +0200 Subject: [PATCH 1666/4212] package_dir not needed anymore Signed-off-by: Nico Schottelius --- setup.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/setup.py b/setup.py index 62ee480c..be907786 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,5 @@ from distutils.core import setup -package_dir = {'': 'lib'} - import cdist setup( From 85fcfb1744030f8f4f806abc745edbcb1745bf5d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 23:48:56 +0200 Subject: [PATCH 1667/4212] correct __file link again Signed-off-by: Nico Schottelius --- cdist/test/emulator/fixtures/conf/type/__file | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/test/emulator/fixtures/conf/type/__file b/cdist/test/emulator/fixtures/conf/type/__file index c57c4134..8458361c 120000 --- a/cdist/test/emulator/fixtures/conf/type/__file +++ b/cdist/test/emulator/fixtures/conf/type/__file @@ -1 +1 @@ -../../../../../../../conf/type/__file \ No newline at end of file +../../../../../../conf/type/__file \ No newline at end of file From 3826b6ce36b99dba101e821ec129c58e8da19e50 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 23:49:10 +0200 Subject: [PATCH 1668/4212] not needed to import our path anymore Signed-off-by: Nico Schottelius --- cdist.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cdist.py b/cdist.py index 75047acb..2066db55 100755 --- a/cdist.py +++ b/cdist.py @@ -219,16 +219,9 @@ if __name__ == "__main__": import logging import os import re - - # Ensure our /lib/ is included into PYTHON_PATH - sys.path.insert(0, os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib'))) - - # And now import our stuff import cdist log = logging.getLogger("cdist") - logging.basicConfig(format='%(levelname)s: %(message)s') if re.match("__", os.path.basename(sys.argv[0])): From c613f868a2564de8e814d15866a5ed37721862b6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 23:49:22 +0200 Subject: [PATCH 1669/4212] cleanups Signed-off-by: Nico Schottelius --- .gitignore | 2 +- build | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 707b5f66..0269a9fc 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,4 @@ docs/man/man7/cdist-reference.text __pycache__/ MANIFEST dist/ -cdist/version_static.py +cdist/version.py diff --git a/build b/build index f8d6c74a..75496c8d 100755 --- a/build +++ b/build @@ -146,6 +146,9 @@ case "$1" in clean) rm -f ${MAN7DSTDIR}/cdist-reference.text + rm -f cdist/version.py + rm -f MANIFEST + find "${MANDIR}" -mindepth 2 -type l \ -o -name "*.1" \ -o -name "*.7" \ @@ -154,8 +157,6 @@ case "$1" in | xargs rm -f find * -name __pycache__ | xargs rm -rf - - rm -f MANIFEST ;; very-clean) $0 clean From a21f5f787db135202b917f8e6e50ceb315076af6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 23:51:18 +0200 Subject: [PATCH 1670/4212] begin with pre first --- docs/changelog-2.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog-2.1 b/docs/changelog-2.1 index 6398e7dc..a5f7ca98 100644 --- a/docs/changelog-2.1 +++ b/docs/changelog-2.1 @@ -4,7 +4,7 @@ Changelog (v2.1 specific) * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.1.0: +2.1.0pre1: * Core: Removed obsolete variable __self * Removed type __addifnosuchline (replaced by __line) * Removed type __removeline (replaced by __line) From 66224f5bdc5b94595708c8c1c7fb95753c03b791 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Oct 2012 23:51:45 +0200 Subject: [PATCH 1671/4212] add some urls Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-05-23.urls | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 doc/dev/logs/2012-05-23.urls diff --git a/doc/dev/logs/2012-05-23.urls b/doc/dev/logs/2012-05-23.urls new file mode 100644 index 00000000..e37407b3 --- /dev/null +++ b/doc/dev/logs/2012-05-23.urls @@ -0,0 +1,5 @@ +http://nu-ex.com/cv.html + +https://lists.metalab.at/pipermail/devops/2012-January/000089.html + +http://www.ir0nik.com/wordpress/?p=121 From eb6687bd32a895f2adb8c41374d0824ee05e948f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 06:55:01 +0200 Subject: [PATCH 1672/4212] allow build to be called outside of the project directory Signed-off-by: Nico Schottelius --- build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build b/build index 75496c8d..8e30c8d4 100755 --- a/build +++ b/build @@ -26,6 +26,7 @@ # exit on any error #set -e +basedir=${0%/*} version=$(git describe) # Manpage and HTML @@ -44,6 +45,9 @@ MAN1DSTDIR=${MANDIR}/man1 MAN7DSTDIR=${MANDIR}/man7 SPEECHESDIR=docs/speeches +# Change to checkout directory +cd "$basedir" + case "$1" in man) set -e From 27a832676bd39251d895a4208fb99918e18a27ef Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 07:09:05 +0200 Subject: [PATCH 1673/4212] move logfile into new destination Signed-off-by: Nico Schottelius --- {doc => docs}/dev/logs/2012-10-25.version-split | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {doc => docs}/dev/logs/2012-10-25.version-split (100%) diff --git a/doc/dev/logs/2012-10-25.version-split b/docs/dev/logs/2012-10-25.version-split similarity index 100% rename from doc/dev/logs/2012-10-25.version-split rename to docs/dev/logs/2012-10-25.version-split From 0db38038a90ecc2b5fc56e813a4762e84485bb30 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 07:20:03 +0200 Subject: [PATCH 1674/4212] merge changelog-2.1 back into main changelog Signed-off-by: Nico Schottelius --- docs/changelog | 12 ++++++++++++ docs/changelog-2.1 | 15 --------------- 2 files changed, 12 insertions(+), 15 deletions(-) delete mode 100644 docs/changelog-2.1 diff --git a/docs/changelog b/docs/changelog index 05d6d96b..7475a566 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,18 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius + +2.1.0pre1: + * Core: Removed obsolete variable __self + * Removed type __addifnosuchline (replaced by __line) + * Removed type __removeline (replaced by __line) + * Type __directory: Parameter --parents and --recursive are now boolean + * Type __package_apt, __package_luarocks, __package_opkg, + __package_pacman, __package_pkg_freebsd, __package_pkg_openbsd, + __package_rubygem, __package_yum, __process: + Parameter state accepts only "present" and "absent" + * Initial support for pypi packaging + 2.0.15: * Core: Make variable __object_name available in type explorers (Steven Armtrong) * New Type: __qemu_img diff --git a/docs/changelog-2.1 b/docs/changelog-2.1 deleted file mode 100644 index a5f7ca98..00000000 --- a/docs/changelog-2.1 +++ /dev/null @@ -1,15 +0,0 @@ -Changelog (v2.1 specific) -------------------------- - - * Changes are always commented with their author in (braces) - * Exception: No braces means author == Nico Schottelius - -2.1.0pre1: - * Core: Removed obsolete variable __self - * Removed type __addifnosuchline (replaced by __line) - * Removed type __removeline (replaced by __line) - * Type __directory: Parameter --parents and --recursive are now boolean - * Type __package_apt, __package_luarocks, __package_opkg, - __package_pacman, __package_pkg_freebsd, __package_pkg_openbsd, - __package_rubygem, __package_yum, __process: - Parameter state accepts only "present" and "absent" From 80db8a01cf82a2f92d454c54aa7956d3e2dee7a3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 07:36:07 +0200 Subject: [PATCH 1675/4212] +linebreak Signed-off-by: Nico Schottelius --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index be907786..2de4a3c0 100644 --- a/setup.py +++ b/setup.py @@ -32,6 +32,7 @@ setup( long_description = ''' cdist is a usable configuration management system. It adheres to the KISS principle and is being used in small up to enterprise grade environments. - cdist is an alternative to other configuration management systems like cfengine, bcfg2, chef and puppet. + cdist is an alternative to other configuration management systems like + cfengine, bcfg2, chef and puppet. ''' ) From ca275133d3eab812703565895a2c6dbd70ac3627 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 07:36:56 +0200 Subject: [PATCH 1676/4212] add releasedate for 2.1.0pre1 Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 7475a566..e691c09d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,7 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius -2.1.0pre1: +2.1.0pre1: 2012-10-26 * Core: Removed obsolete variable __self * Removed type __addifnosuchline (replaced by __line) * Removed type __removeline (replaced by __line) From 9eb7503713820a28aee7532b968123c19b875ba9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 07:37:18 +0200 Subject: [PATCH 1677/4212] split clean-dist into its own section Signed-off-by: Nico Schottelius --- build | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/build b/build index 8e30c8d4..d7426feb 100755 --- a/build +++ b/build @@ -95,9 +95,8 @@ case "$1" in pypi) #$0 very-clean #$0 man - $0 version-dist + $0 version $0 sdist - $0 version-dynamic ;; sdist) python3 setup.py sdist @@ -150,8 +149,6 @@ case "$1" in clean) rm -f ${MAN7DSTDIR}/cdist-reference.text - rm -f cdist/version.py - rm -f MANIFEST find "${MANDIR}" -mindepth 2 -type l \ -o -name "*.1" \ @@ -162,9 +159,14 @@ case "$1" in find * -name __pycache__ | xargs rm -rf ;; + clean-dist) + rm -f cdist/version.py MANIFEST + rm -rf cache/ dist/ + ;; + very-clean) $0 clean - rm -rf cache/ + $0 clean-dist ;; test) From 3b04f5749e94a155bcc4a89b565374bcc7b3f36c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 08:31:54 +0200 Subject: [PATCH 1678/4212] change release script to setup version from changelog Signed-off-by: Nico Schottelius --- docs/dev/releasechecklist | 44 ++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/docs/dev/releasechecklist b/docs/dev/releasechecklist index 71f2979e..197ab2d3 100755 --- a/docs/dev/releasechecklist +++ b/docs/dev/releasechecklist @@ -1,48 +1,40 @@ #!/bin/sh # Nico Schottelius -files="doc/changelog lib/cdist/__init__.py" - -# Stuff to take care of when doing a release -echo "Preparing next release" - # Ensure documentation builds cleanly -echo "Testing documentation..." -./build clean && ./build man || exit 1 +echo "Verifying documentation building works ..." +## ./build clean && ./build man || exit 1 -# get version -changelog_version=$(grep '^[[:digit:]]' doc/changelog | head -n1 | sed 's/:.*//') -#git_version=$(git describe) -lib_version=$(grep "^ VERSION" lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g') +# get version from changelog and ensure it's not already present +changelog_version=$(grep '^[[:digit:]]' docs/changelog | head -n1 | sed 's/:.*//') -# get date +if git show --quiet $changelog_version >/dev/null 2>&1; then + echo "Version $changelog_version already exists, aborting." + exit 1 +fi + +echo "Target version from changelog: $changelog_version" + +# verify date in changelog date_today="$(date +%Y-%m-%d)" -date_changelog=$(grep '^[[:digit:]]' doc/changelog | head -n1 | sed 's/.*: //') - -echo "Ensure you fixed/prepared version files: $files" -echo "changelog: $changelog_version" -#echo "git: $git_version" -echo "lib: $lib_version" +date_changelog=$(grep '^[[:digit:]]' docs/changelog | head -n1 | sed 's/.*: //') if [ "$date_today" != "$date_changelog" ]; then - echo "Messed up date, not releasing:" + echo "Date in changelog is not today" echo "Changelog: $date_changelog" exit 1 fi -if [ "$lib_version" != "$changelog_version" ]; then - echo "Messed up versions, not releasing" - exit 1 -else - echo "Versions are sane, continuing" -fi echo "Press enter to continue" read wait -version=$lib_version +version=$changelog_version # get target branch branch=${version%\.*} +echo "Selecting branch $branch for merging" +exit 0 + # add tag printf "Enter tag description for %s> " "$version" read tagmessage From c29b7f68141a48657b3ef1dd267e74270179e630 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 11:59:43 +0200 Subject: [PATCH 1679/4212] checklist is now a helper Signed-off-by: Nico Schottelius --- docs/dev/{releasechecklist => releasehelper} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/dev/{releasechecklist => releasehelper} (100%) diff --git a/docs/dev/releasechecklist b/docs/dev/releasehelper similarity index 100% rename from docs/dev/releasechecklist rename to docs/dev/releasehelper From 1064d8edd50752f661c621b0c3aa4301c4bef5e6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 12:17:43 +0200 Subject: [PATCH 1680/4212] cleanup release and build script Signed-off-by: Nico Schottelius --- build | 5 ----- docs/dev/releasehelper | 16 ++++++++-------- 2 files changed, 8 insertions(+), 13 deletions(-) mode change 100755 => 100644 docs/dev/releasehelper diff --git a/build b/build index d7426feb..76057530 100755 --- a/build +++ b/build @@ -122,11 +122,6 @@ case "$1" in rm -rf ${WEBMAN} mkdir -p ${WEBMAN}/man1 ${WEBMAN}/man7 - # old stuff - # rm -rf ${WEBDIR}/${WEBBASE}/speeches && mkdir ${WEBDIR}/${WEBBASE}/speeches - # cp ${SPEECHESDIR}/*.pdf ${WEBDIR}/${WEBBASE}/speeches - # git describe > ${WEBDIR}/${WEBBASE}/man/VERSION - cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${WEBMAN}/man1 cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${WEBMAN}/man7 diff --git a/docs/dev/releasehelper b/docs/dev/releasehelper old mode 100755 new mode 100644 index 197ab2d3..4a570f89 --- a/docs/dev/releasehelper +++ b/docs/dev/releasehelper @@ -30,10 +30,10 @@ read wait version=$changelog_version # get target branch -branch=${version%\.*} +target_branch=${version%\.*} +current_branch=$(git rev-parse --abbrev-ref HEAD) -echo "Selecting branch $branch for merging" -exit 0 +echo "Selected branch $target_branch for merging $current_branch" # add tag printf "Enter tag description for %s> " "$version" @@ -41,14 +41,14 @@ read tagmessage git tag "$version" -m "$tagmessage" # Import into current version branch -printf "Press enter to git merge into branch \"$branch\" > " +printf "Press enter to git merge into branch \"$target_branch\" > " read prompt -git checkout $branch -git merge master -git checkout master +git checkout "$target_branch" +git merge "$current_branch" +git checkout "$current_branch" # Publish manpages and sourcecode -printf "Press enter to publish doc/ and code/ > " +printf "Press enter to publish doc/ code/ pypi for $version > " read prompt ./build web ./build pub From 281852ff27ee1a2d3803324da565da68cd825c8b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 12:19:41 +0200 Subject: [PATCH 1681/4212] use new helper Signed-off-by: Nico Schottelius --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index 76057530..16479304 100755 --- a/build +++ b/build @@ -89,7 +89,7 @@ case "$1" in ;; release) - ./docs/dev/releasechecklist + ./docs/dev/releasehelper ;; pypi) From aef91d972efc9acbb92a53097aece31bd7169894 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 12:23:47 +0200 Subject: [PATCH 1682/4212] more cleanups Signed-off-by: Nico Schottelius --- build | 1 - docs/dev/releasehelper | 0 2 files changed, 1 deletion(-) mode change 100644 => 100755 docs/dev/releasehelper diff --git a/build b/build index 16479304..2e6e7813 100755 --- a/build +++ b/build @@ -93,7 +93,6 @@ case "$1" in ;; pypi) - #$0 very-clean #$0 man $0 version $0 sdist diff --git a/docs/dev/releasehelper b/docs/dev/releasehelper old mode 100644 new mode 100755 From 7a34c6cd28697618a8b323c19d9fa27051e0a7fc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 17:40:38 +0200 Subject: [PATCH 1683/4212] add types to pypi distribution Signed-off-by: Nico Schottelius --- MANIFEST.in | 1 + docs/changelog | 3 +++ 2 files changed, 4 insertions(+) diff --git a/MANIFEST.in b/MANIFEST.in index b4935a92..319dad56 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,4 @@ include docs/changelog docs/changelog-2.1 recursive-include docs/gfx *.png *.text recursive-include docs *.text *.html *.1 *.7 +recursive-include conf * diff --git a/docs/changelog b/docs/changelog index e691c09d..3f170057 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius +2.1.0pre2: + * PyPi: Add conf/ directory to distribution + 2.1.0pre1: 2012-10-26 * Core: Removed obsolete variable __self * Removed type __addifnosuchline (replaced by __line) From 6627325b454ef36354204787eb8dd8a9f0752d21 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 17:42:26 +0200 Subject: [PATCH 1684/4212] build manpages before doing a pypi package Signed-off-by: Nico Schottelius --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index 2e6e7813..18dcfdab 100755 --- a/build +++ b/build @@ -93,7 +93,7 @@ case "$1" in ;; pypi) - #$0 man + $0 man $0 version $0 sdist ;; From cbd44a883780d7ec541b07eea9fde7305d941cff Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 17:53:35 +0200 Subject: [PATCH 1685/4212] begin initial PKGBUILD for archlinux Signed-off-by: Nico Schottelius --- PKGBUILD.in | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100755 PKGBUILD.in diff --git a/PKGBUILD.in b/PKGBUILD.in new file mode 100755 index 00000000..8e55946f --- /dev/null +++ b/PKGBUILD.in @@ -0,0 +1,26 @@ +#!/bin/sh + +version=$(git describe) +version=2.1.0pre1 + +outfile=${0%.in} + +cat << eof > "${outfile}" +pkgname=cdist +pkgver=$version +pkgrel=1 +pkgdesc='A Usable Configuration Management System"' +arch=('any') +url='http://www.nico.schottelius.org/software/cdist/' +license=('GPL3') +depends=('python3>=3.2.0') +source=("http://pypi.python.org/packages/source/c/cdist/cdist-\${pkgver}.tar.gz") + +package() { + python3 setup.py build install --root="${pkgdir}" + + #install -Dm644 offlineimap.1 "${pkgdir}"/usr/share/man/man1/offlineimap.1 + #install -Dm644 offlineimap.conf "${pkgdir}"/usr/share/offlineimap/offlineimap.conf + #install -Dm644 offlineimap.conf.minimal "${pkgdir}"/usr/share/offlineimap/offlineimap.conf.minimal +} +eof From 4c4b234feb401d26b52d004611fdc1366df4e1eb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 17:53:57 +0200 Subject: [PATCH 1686/4212] ignore generated PKGBUILD Signed-off-by: Nico Schottelius --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 0269a9fc..5d39eae1 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,6 @@ __pycache__/ MANIFEST dist/ cdist/version.py + +# Packaging: Archlinux +/PKGBUILD From 195036b7101db05002d85f478ba4151d0576e0c1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 18:13:17 +0200 Subject: [PATCH 1687/4212] creating basic cdist archlinux package works Signed-off-by: Nico Schottelius --- .gitignore | 4 ++++ PKGBUILD.in | 14 +++++++------- build | 13 +++++++++++-- setup.py | 2 +- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 5d39eae1..6e2d4437 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,7 @@ cdist/version.py # Packaging: Archlinux /PKGBUILD +/cdist-*.pkg.tar.xz +/cdist-*.tar.gz +/pkg +/src diff --git a/PKGBUILD.in b/PKGBUILD.in index 8e55946f..a4e744ae 100755 --- a/PKGBUILD.in +++ b/PKGBUILD.in @@ -1,8 +1,6 @@ #!/bin/sh version=$(git describe) -version=2.1.0pre1 - outfile=${0%.in} cat << eof > "${outfile}" @@ -13,14 +11,16 @@ pkgdesc='A Usable Configuration Management System"' arch=('any') url='http://www.nico.schottelius.org/software/cdist/' license=('GPL3') -depends=('python3>=3.2.0') +depends=('python>=3.2.0') source=("http://pypi.python.org/packages/source/c/cdist/cdist-\${pkgver}.tar.gz") package() { - python3 setup.py build install --root="${pkgdir}" + cd cdist-\${pkgver} + python3 setup.py build install --root="\${pkgdir}" + mv "\${pkgdir}"/usr/bin/cdist.py "\${pkgdir}"/usr/bin/cdist - #install -Dm644 offlineimap.1 "${pkgdir}"/usr/share/man/man1/offlineimap.1 - #install -Dm644 offlineimap.conf "${pkgdir}"/usr/share/offlineimap/offlineimap.conf - #install -Dm644 offlineimap.conf.minimal "${pkgdir}"/usr/share/offlineimap/offlineimap.conf.minimal + #install -Dm644 offlineimap.1 "\${pkgdir}"/usr/share/man/man1/offlineimap.1 } eof + +makepkg -g >> "${outfile}" diff --git a/build b/build index 18dcfdab..bb31ccc0 100755 --- a/build +++ b/build @@ -92,7 +92,12 @@ case "$1" in ./docs/dev/releasehelper ;; - pypi) + dist-archlinux) + ./PKGBUILD.in + makepkg + ;; + + dist-pypi) $0 man $0 version $0 sdist @@ -154,8 +159,12 @@ case "$1" in find * -name __pycache__ | xargs rm -rf ;; clean-dist) - rm -f cdist/version.py MANIFEST + 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/ ;; very-clean) diff --git a/setup.py b/setup.py index 2de4a3c0..900dac0f 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup( packages = ["cdist", "cdist.core", "cdist.exec", "cdist.util" ], scripts = ["cdist.py"], version = cdist.version.VERSION, - description = "Usable configuration management system", + description = "A Usable Configuration Management System", author = "Nico Schottelius", author_email = "nico-cdist-pypi@schottelius.org", url = "http://www.nico.schottelius.org/software/cdist/", From 992be4959a0aa660de8ea44abd2a36e2f7a9e119 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 18:14:04 +0200 Subject: [PATCH 1688/4212] ++changes(2.1.0pre2) Signed-off-by: Nico Schottelius --- docs/changelog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index 3f170057..295aa677 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,7 +6,8 @@ Changelog 2.1.0pre2: - * PyPi: Add conf/ directory to distribution + * Dist: PyPi: Add conf/ directory to distribution + * Dist: Initial support for archlinux packaging 2.1.0pre1: 2012-10-26 * Core: Removed obsolete variable __self @@ -17,7 +18,7 @@ Changelog __package_pacman, __package_pkg_freebsd, __package_pkg_openbsd, __package_rubygem, __package_yum, __process: Parameter state accepts only "present" and "absent" - * Initial support for pypi packaging + * Dist: Initial support for pypi packaging 2.0.15: * Core: Make variable __object_name available in type explorers (Steven Armtrong) From 3e573fa21e36f6e25884b3c94d13342340f0f08c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 18:20:09 +0200 Subject: [PATCH 1689/4212] begin to merge releasehelper into build Signed-off-by: Nico Schottelius --- build | 83 +++++++++++++++++++++++++++++++++++++++++- docs/dev/releasehelper | 64 -------------------------------- 2 files changed, 81 insertions(+), 66 deletions(-) delete mode 100755 docs/dev/releasehelper diff --git a/build b/build index bb31ccc0..7fb3c2ec 100755 --- a/build +++ b/build @@ -88,13 +88,26 @@ case "$1" in ${MANDIR}/cdist-reference.text.sh ;; - release) + dist) + $0 dist-pypi + + # Archlinux depends on successful pypi ;-) + $0 dist-archlinux + + $0 dist-post + ;; + + dist-prepare) ./docs/dev/releasehelper ;; + dist-post) + + ;; + dist-archlinux) ./PKGBUILD.in - makepkg + makepkg -c ;; dist-pypi) @@ -202,3 +215,69 @@ case "$1" in ;; esac + + +#!/bin/sh +# Nico Schottelius + +# Ensure documentation builds cleanly +echo "Verifying documentation building works ..." +## ./build clean && ./build man || exit 1 + +# get version from changelog and ensure it's not already present +changelog_version=$(grep '^[[:digit:]]' docs/changelog | head -n1 | sed 's/:.*//') + +if git show --quiet $changelog_version >/dev/null 2>&1; then + echo "Version $changelog_version already exists, aborting." + exit 1 +fi + +echo "Target version from changelog: $changelog_version" + +# verify date in changelog +date_today="$(date +%Y-%m-%d)" +date_changelog=$(grep '^[[:digit:]]' docs/changelog | head -n1 | sed 's/.*: //') + +if [ "$date_today" != "$date_changelog" ]; then + echo "Date in changelog is not today" + echo "Changelog: $date_changelog" + exit 1 +fi + +echo "Press enter to continue" +read wait +version=$changelog_version + +# get target branch +target_branch=${version%\.*} +current_branch=$(git rev-parse --abbrev-ref HEAD) + +echo "Selected branch $target_branch for merging $current_branch" + +# add tag +printf "Enter tag description for %s> " "$version" +read tagmessage +git tag "$version" -m "$tagmessage" + +# Import into current version branch +printf "Press enter to git merge into branch \"$target_branch\" > " +read prompt +git checkout "$target_branch" +git merge "$current_branch" +git checkout "$current_branch" + +# Publish manpages and sourcecode +printf "Press enter to publish doc/ code/ pypi for $version > " +read prompt +./build web +./build pub + +cat << notes +To be done manually... + + - freecode release + - blog entry + - linkedin entry + - mailinglist update + +notes diff --git a/docs/dev/releasehelper b/docs/dev/releasehelper deleted file mode 100755 index 4a570f89..00000000 --- a/docs/dev/releasehelper +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/sh -# Nico Schottelius - -# Ensure documentation builds cleanly -echo "Verifying documentation building works ..." -## ./build clean && ./build man || exit 1 - -# get version from changelog and ensure it's not already present -changelog_version=$(grep '^[[:digit:]]' docs/changelog | head -n1 | sed 's/:.*//') - -if git show --quiet $changelog_version >/dev/null 2>&1; then - echo "Version $changelog_version already exists, aborting." - exit 1 -fi - -echo "Target version from changelog: $changelog_version" - -# verify date in changelog -date_today="$(date +%Y-%m-%d)" -date_changelog=$(grep '^[[:digit:]]' docs/changelog | head -n1 | sed 's/.*: //') - -if [ "$date_today" != "$date_changelog" ]; then - echo "Date in changelog is not today" - echo "Changelog: $date_changelog" - exit 1 -fi - -echo "Press enter to continue" -read wait -version=$changelog_version - -# get target branch -target_branch=${version%\.*} -current_branch=$(git rev-parse --abbrev-ref HEAD) - -echo "Selected branch $target_branch for merging $current_branch" - -# add tag -printf "Enter tag description for %s> " "$version" -read tagmessage -git tag "$version" -m "$tagmessage" - -# Import into current version branch -printf "Press enter to git merge into branch \"$target_branch\" > " -read prompt -git checkout "$target_branch" -git merge "$current_branch" -git checkout "$current_branch" - -# Publish manpages and sourcecode -printf "Press enter to publish doc/ code/ pypi for $version > " -read prompt -./build web -./build pub - -cat << notes -To be done manually... - - - freecode release - - blog entry - - linkedin entry - - mailinglist update - -notes From e397f2a74cce0a1ae0a832415a06e238c7135d45 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 18:35:47 +0200 Subject: [PATCH 1690/4212] cleanup distribution process in build file Signed-off-by: Nico Schottelius --- build | 144 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 71 insertions(+), 73 deletions(-) diff --git a/build b/build index 7fb3c2ec..1aa76f3b 100755 --- a/build +++ b/build @@ -89,34 +89,98 @@ case "$1" in ;; dist) + set -e + # Do the checks + $0 dist-check + + # Git changes - everything depends on this + $0 dist-tag + $0 dist-branch-merge + $0 dist-pypi # Archlinux depends on successful pypi ;-) $0 dist-archlinux + # Update website (includes documentation) + $0 web + + $0 pub + $0 dist-post ;; - dist-prepare) - ./docs/dev/releasehelper + changelog-version) + # get version from changelog and ensure it's not already present + grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/:.*//' + ;; + + dist-check) + echo "Verifying documentation building works ..." + $0 clean && $0 man + + 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 + + echo "Target version from changelog: $changelog_version" + + # verify date in changelog + date_today="$(date +%Y-%m-%d)" + date_changelog=$(grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/.*: //') + + if [ "$date_today" != "$date_changelog" ]; then + echo "Date in changelog is not today" + echo "Changelog: $date_changelog" + exit 1 + fi + ;; dist-post) + cat << notes + To be done manually... + + - freecode release + - blog entry + - linkedin entry + - mailinglist update +notes + + ;; + + 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) + + 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" ;; dist-archlinux) ./PKGBUILD.in makepkg -c ;; - dist-pypi) $0 man $0 version - $0 sdist - ;; - sdist) - python3 setup.py sdist + python3 setup.py sdist update ;; speeches) @@ -215,69 +279,3 @@ case "$1" in ;; esac - - -#!/bin/sh -# Nico Schottelius - -# Ensure documentation builds cleanly -echo "Verifying documentation building works ..." -## ./build clean && ./build man || exit 1 - -# get version from changelog and ensure it's not already present -changelog_version=$(grep '^[[:digit:]]' docs/changelog | head -n1 | sed 's/:.*//') - -if git show --quiet $changelog_version >/dev/null 2>&1; then - echo "Version $changelog_version already exists, aborting." - exit 1 -fi - -echo "Target version from changelog: $changelog_version" - -# verify date in changelog -date_today="$(date +%Y-%m-%d)" -date_changelog=$(grep '^[[:digit:]]' docs/changelog | head -n1 | sed 's/.*: //') - -if [ "$date_today" != "$date_changelog" ]; then - echo "Date in changelog is not today" - echo "Changelog: $date_changelog" - exit 1 -fi - -echo "Press enter to continue" -read wait -version=$changelog_version - -# get target branch -target_branch=${version%\.*} -current_branch=$(git rev-parse --abbrev-ref HEAD) - -echo "Selected branch $target_branch for merging $current_branch" - -# add tag -printf "Enter tag description for %s> " "$version" -read tagmessage -git tag "$version" -m "$tagmessage" - -# Import into current version branch -printf "Press enter to git merge into branch \"$target_branch\" > " -read prompt -git checkout "$target_branch" -git merge "$current_branch" -git checkout "$current_branch" - -# Publish manpages and sourcecode -printf "Press enter to publish doc/ code/ pypi for $version > " -read prompt -./build web -./build pub - -cat << notes -To be done manually... - - - freecode release - - blog entry - - linkedin entry - - mailinglist update - -notes From 2307cdebfa1dd1759a1e37a52241919fa7b12f03 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 18:38:00 +0200 Subject: [PATCH 1691/4212] abort dist on any error Signed-off-by: Nico Schottelius --- build | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/build b/build index 1aa76f3b..5ecf481a 100755 --- a/build +++ b/build @@ -116,18 +116,19 @@ case "$1" in ;; dist-check) + set -e echo "Verifying documentation building works ..." - $0 clean && $0 man + $0 clean + $0 man 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 - echo "Target version from changelog: $changelog_version" - # verify date in changelog date_today="$(date +%Y-%m-%d)" date_changelog=$(grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/.*: //') From 0d46dc336766be528b8030da2fe21db466d8ca0d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 18:38:14 +0200 Subject: [PATCH 1692/4212] fix manpages of __pf_ruleset and __pf_apply Signed-off-by: Nico Schottelius --- conf/type/__pf_apply/man.text | 2 +- conf/type/__pf_ruleset/man.text | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/type/__pf_apply/man.text b/conf/type/__pf_apply/man.text index 55bf5745..2e0d7802 100644 --- a/conf/type/__pf_apply/man.text +++ b/conf/type/__pf_apply/man.text @@ -1,5 +1,5 @@ cdist-type__pf_apply(7) -================================== +======================= Jake Guffey diff --git a/conf/type/__pf_ruleset/man.text b/conf/type/__pf_ruleset/man.text index 68601fad..5c368e77 100644 --- a/conf/type/__pf_ruleset/man.text +++ b/conf/type/__pf_ruleset/man.text @@ -1,5 +1,5 @@ cdist-type__pf_ruleset(7) -================================== +========================= Jake Guffey From fd9aca7b3c1648edb5c489c1ca4669f00b72f86d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 18:39:22 +0200 Subject: [PATCH 1693/4212] release 2.1.0pre2 today Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 295aa677..dba70701 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,7 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius -2.1.0pre2: +2.1.0pre2: 2012-10-26 * Dist: PyPi: Add conf/ directory to distribution * Dist: Initial support for archlinux packaging From 24481781f94b13e6f8b92bbdba2a33969d0d29a9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 18:42:06 +0200 Subject: [PATCH 1694/4212] +comment Signed-off-by: Nico Schottelius --- build | 1 + 1 file changed, 1 insertion(+) diff --git a/build b/build index 5ecf481a..16029581 100755 --- a/build +++ b/build @@ -97,6 +97,7 @@ case "$1" in $0 dist-tag $0 dist-branch-merge + # Pypi first - is the base for others $0 dist-pypi # Archlinux depends on successful pypi ;-) From 8324c9dee4ba03aaf5aac066aa277aca2f9bd2dc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 26 Oct 2012 18:47:49 +0200 Subject: [PATCH 1695/4212] build source for archlinux as well as upload to pypi Signed-off-by: Nico Schottelius --- build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build b/build index 16029581..d295da14 100755 --- a/build +++ b/build @@ -178,11 +178,12 @@ notes dist-archlinux) ./PKGBUILD.in makepkg -c + makepkg -c --source ;; dist-pypi) $0 man $0 version - python3 setup.py sdist update + python3 setup.py sdist upload ;; speeches) From e2ba9ab1d2096072ef764e98d1ae400248d11f0e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 29 Oct 2012 22:18:32 +0100 Subject: [PATCH 1696/4212] add package data info Signed-off-by: Nico Schottelius --- MANIFEST.in | 3 +-- setup.py | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 319dad56..a675f446 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,3 @@ -include docs/changelog docs/changelog-2.1 +include docs/changelog recursive-include docs/gfx *.png *.text recursive-include docs *.text *.html *.1 *.7 -recursive-include conf * diff --git a/setup.py b/setup.py index 900dac0f..19fb28e6 100644 --- a/setup.py +++ b/setup.py @@ -1,10 +1,31 @@ from distutils.core import setup +#data_files=[('/usr/share/cdist', 'conf')], + # data_files=[('/tmp/cdist', ['conf'])], import cdist +import os + +def data_finder(data_dir): + entries = [] + for name in os.listdir(data_dir): + entry = os.path.join(data_dir, name) + if os.path.isdir(entry): + entries.extend(data_finder(entry)) + else: + entries.append(entry) + + return entries + +package_data = data_finder("conf") + + +print(package_data) + setup( name = "cdist", packages = ["cdist", "cdist.core", "cdist.exec", "cdist.util" ], + package_data={'cdist': package_data}, scripts = ["cdist.py"], version = cdist.version.VERSION, description = "A Usable Configuration Management System", From 63573a9797651ba90233e5f59a1a4360a3a15189 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 29 Oct 2012 22:50:27 +0100 Subject: [PATCH 1697/4212] make package_data work Signed-off-by: Nico Schottelius --- {conf => cdist/conf}/.gitignore | 0 {conf => cdist/conf}/README | 0 {conf => cdist/conf}/explorer/hostname | 0 {conf => cdist/conf}/explorer/interfaces | 0 {conf => cdist/conf}/explorer/lsb_codename | 0 {conf => cdist/conf}/explorer/lsb_description | 0 {conf => cdist/conf}/explorer/lsb_id | 0 {conf => cdist/conf}/explorer/lsb_release | 0 {conf => cdist/conf}/explorer/machine | 0 {conf => cdist/conf}/explorer/os | 0 {conf => cdist/conf}/explorer/os_version | 0 {conf => cdist/conf}/explorer/runlevel | 0 {conf => cdist/conf}/manifest/init.sample | 0 {conf => cdist/conf}/type/__apt_ppa/explorer/state | 0 .../conf}/type/__apt_ppa/files/remove-apt-repository | 0 {conf => cdist/conf}/type/__apt_ppa/gencode-remote | 0 {conf => cdist/conf}/type/__apt_ppa/man.text | 0 {conf => cdist/conf}/type/__apt_ppa/manifest | 0 {conf => cdist/conf}/type/__apt_ppa/parameter/required | 0 {conf => cdist/conf}/type/__apt_update_index/gencode-remote | 0 {conf => cdist/conf}/type/__apt_update_index/man.text | 0 {conf => cdist/conf}/type/__apt_update_index/singleton | 0 {conf => cdist/conf}/type/__autofs_map/man.text | 0 {conf => cdist/conf}/type/__autofs_map/manifest | 0 {conf => cdist/conf}/type/__autofs_map/parameter/optional | 0 {conf => cdist/conf}/type/__autofs_map/parameter/required | 0 .../conf}/type/__autofs_master/files/auto.master.header | 0 {conf => cdist/conf}/type/__autofs_master/gencode-local | 0 {conf => cdist/conf}/type/__autofs_master/man.text | 0 {conf => cdist/conf}/type/__autofs_master/manifest | 0 .../conf}/type/__autofs_master/parameter/optional | 0 {conf => cdist/conf}/type/__autofs_master/singleton | 0 {conf => cdist/conf}/type/__cdistmarker/gencode-remote | 0 {conf => cdist/conf}/type/__cdistmarker/man.text | 0 {conf => cdist/conf}/type/__cdistmarker/parameter/optional | 0 {conf => cdist/conf}/type/__cdistmarker/singleton | 0 {conf => cdist/conf}/type/__cron/explorer/entry | 0 {conf => cdist/conf}/type/__cron/gencode-remote | 0 {conf => cdist/conf}/type/__cron/man.text | 0 {conf => cdist/conf}/type/__cron/manifest | 0 {conf => cdist/conf}/type/__cron/parameter/optional | 0 {conf => cdist/conf}/type/__cron/parameter/required | 0 .../conf}/type/__debconf_set_selections/gencode-remote | 0 {conf => cdist/conf}/type/__debconf_set_selections/man.text | 0 .../conf}/type/__debconf_set_selections/parameter/required | 0 {conf => cdist/conf}/type/__directory/explorer/state | 0 {conf => cdist/conf}/type/__directory/gencode-remote | 0 {conf => cdist/conf}/type/__directory/man.text | 0 {conf => cdist/conf}/type/__directory/parameter/boolean | 0 {conf => cdist/conf}/type/__directory/parameter/optional | 0 {conf => cdist/conf}/type/__file/explorer/cksum | 0 {conf => cdist/conf}/type/__file/explorer/exists | 0 {conf => cdist/conf}/type/__file/gencode-local | 0 {conf => cdist/conf}/type/__file/gencode-remote | 0 {conf => cdist/conf}/type/__file/man.text | 0 {conf => cdist/conf}/type/__file/manifest | 0 {conf => cdist/conf}/type/__file/parameter/optional | 0 {conf => cdist/conf}/type/__group/TODO | 0 {conf => cdist/conf}/type/__group/explorer/group | 0 {conf => cdist/conf}/type/__group/explorer/gshadow | 0 {conf => cdist/conf}/type/__group/gencode-remote | 0 {conf => cdist/conf}/type/__group/man.text | 0 {conf => cdist/conf}/type/__group/parameter/optional | 0 {conf => cdist/conf}/type/__issue/files/archlinux | 0 {conf => cdist/conf}/type/__issue/files/default | 0 {conf => cdist/conf}/type/__issue/files/redhat | 0 {conf => cdist/conf}/type/__issue/man.text | 0 {conf => cdist/conf}/type/__issue/manifest | 0 {conf => cdist/conf}/type/__issue/parameter/optional | 0 {conf => cdist/conf}/type/__issue/singleton | 0 {conf => cdist/conf}/type/__jail/.gitignore | 0 {conf => cdist/conf}/type/__jail/explorer/basepresent | 0 {conf => cdist/conf}/type/__jail/explorer/present | 0 {conf => cdist/conf}/type/__jail/explorer/status | 0 {conf => cdist/conf}/type/__jail/gencode-local | 0 {conf => cdist/conf}/type/__jail/gencode-remote | 0 {conf => cdist/conf}/type/__jail/man.text | 0 {conf => cdist/conf}/type/__jail/manifest | 0 {conf => cdist/conf}/type/__jail/parameter/optional | 0 {conf => cdist/conf}/type/__jail/parameter/required | 0 {conf => cdist/conf}/type/__key_value/explorer/state | 0 {conf => cdist/conf}/type/__key_value/gencode-remote | 0 {conf => cdist/conf}/type/__key_value/man.text | 0 {conf => cdist/conf}/type/__key_value/manifest | 0 {conf => cdist/conf}/type/__key_value/parameter/optional | 0 {conf => cdist/conf}/type/__key_value/parameter/required | 0 {conf => cdist/conf}/type/__line/explorer/state | 0 {conf => cdist/conf}/type/__line/gencode-remote | 0 {conf => cdist/conf}/type/__line/man.text | 0 {conf => cdist/conf}/type/__line/parameter/optional | 0 {conf => cdist/conf}/type/__link/explorer/state | 0 {conf => cdist/conf}/type/__link/gencode-remote | 0 {conf => cdist/conf}/type/__link/man.text | 0 {conf => cdist/conf}/type/__link/manifest | 0 {conf => cdist/conf}/type/__link/parameter/optional | 0 {conf => cdist/conf}/type/__link/parameter/required | 0 {conf => cdist/conf}/type/__mkfs/gencode-remote | 0 {conf => cdist/conf}/type/__mkfs/install | 0 {conf => cdist/conf}/type/__mkfs/man.text | 0 {conf => cdist/conf}/type/__mkfs/manifest | 0 {conf => cdist/conf}/type/__mkfs/parameter/optional | 0 {conf => cdist/conf}/type/__mkfs/parameter/required | 0 {conf => cdist/conf}/type/__motd/files/motd | 0 {conf => cdist/conf}/type/__motd/man.text | 0 {conf => cdist/conf}/type/__motd/manifest | 0 {conf => cdist/conf}/type/__motd/parameter/optional | 0 {conf => cdist/conf}/type/__motd/singleton | 0 {conf => cdist/conf}/type/__mysql_database/gencode-remote | 0 {conf => cdist/conf}/type/__mysql_database/man.text | 0 .../conf}/type/__mysql_database/parameter/optional | 0 {conf => cdist/conf}/type/__package/man.text | 0 {conf => cdist/conf}/type/__package/manifest | 0 {conf => cdist/conf}/type/__package/parameter/optional | 0 {conf => cdist/conf}/type/__package_apt/explorer/state | 0 {conf => cdist/conf}/type/__package_apt/gencode-remote | 0 {conf => cdist/conf}/type/__package_apt/man.text | 0 {conf => cdist/conf}/type/__package_apt/notes.txt | 0 {conf => cdist/conf}/type/__package_apt/parameter/optional | 0 .../conf}/type/__package_luarocks/explorer/pkg_status | 0 {conf => cdist/conf}/type/__package_luarocks/gencode-remote | 0 {conf => cdist/conf}/type/__package_luarocks/man.text | 0 {conf => cdist/conf}/type/__package_luarocks/manifest | 0 .../conf}/type/__package_luarocks/parameter/optional | 0 .../conf}/type/__package_opkg/explorer/pkg_status | 0 {conf => cdist/conf}/type/__package_opkg/gencode-remote | 0 {conf => cdist/conf}/type/__package_opkg/man.text | 0 {conf => cdist/conf}/type/__package_opkg/parameter/optional | 0 .../conf}/type/__package_pacman/explorer/pkg_version | 0 {conf => cdist/conf}/type/__package_pacman/gencode-remote | 0 {conf => cdist/conf}/type/__package_pacman/man.text | 0 .../conf}/type/__package_pacman/parameter/optional | 0 {conf => cdist/conf}/type/__package_pip/explorer/state | 0 {conf => cdist/conf}/type/__package_pip/gencode-remote | 0 {conf => cdist/conf}/type/__package_pip/man.text | 0 {conf => cdist/conf}/type/__package_pip/parameter/optional | 0 .../conf}/type/__package_pkg_freebsd/explorer/pkg_version | 0 .../conf}/type/__package_pkg_freebsd/gencode-remote | 0 {conf => cdist/conf}/type/__package_pkg_freebsd/man.text | 0 .../conf}/type/__package_pkg_freebsd/parameter/optional | 0 .../conf}/type/__package_pkg_openbsd/explorer/pkg_version | 0 .../conf}/type/__package_pkg_openbsd/gencode-remote | 0 {conf => cdist/conf}/type/__package_pkg_openbsd/man.text | 0 .../conf}/type/__package_pkg_openbsd/parameter/optional | 0 .../conf}/type/__package_rubygem/explorer/pkg_status | 0 {conf => cdist/conf}/type/__package_rubygem/gencode-remote | 0 {conf => cdist/conf}/type/__package_rubygem/man.text | 0 .../conf}/type/__package_rubygem/parameter/optional | 0 .../conf}/type/__package_yum/explorer/pkg_version | 0 {conf => cdist/conf}/type/__package_yum/gencode-remote | 0 {conf => cdist/conf}/type/__package_yum/man.text | 0 {conf => cdist/conf}/type/__package_yum/parameter/optional | 0 .../conf}/type/__package_zypper/explorer/pkg_version | 0 {conf => cdist/conf}/type/__package_zypper/gencode-remote | 0 {conf => cdist/conf}/type/__package_zypper/man.text | 0 .../conf}/type/__package_zypper/parameter/optional | 0 {conf => cdist/conf}/type/__partition_msdos/install | 0 {conf => cdist/conf}/type/__partition_msdos/man.text | 0 {conf => cdist/conf}/type/__partition_msdos/manifest | 0 .../conf}/type/__partition_msdos/parameter/optional | 0 .../conf}/type/__partition_msdos/parameter/required | 0 .../conf}/type/__partition_msdos_apply/explorer/partitions | 0 .../conf}/type/__partition_msdos_apply/files/lib.sh | 0 .../conf}/type/__partition_msdos_apply/gencode-remote | 0 {conf => cdist/conf}/type/__partition_msdos_apply/install | 0 {conf => cdist/conf}/type/__partition_msdos_apply/man.text | 0 {conf => cdist/conf}/type/__partition_msdos_apply/singleton | 0 {conf => cdist/conf}/type/__pf_apply/explorer/rcvar | 0 {conf => cdist/conf}/type/__pf_apply/gencode-remote | 0 {conf => cdist/conf}/type/__pf_apply/man.text | 0 {conf => cdist/conf}/type/__pf_apply/singleton | 0 {conf => cdist/conf}/type/__pf_ruleset/explorer/cksum | 0 {conf => cdist/conf}/type/__pf_ruleset/explorer/rcvar | 0 {conf => cdist/conf}/type/__pf_ruleset/gencode-local | 0 {conf => cdist/conf}/type/__pf_ruleset/gencode-remote | 0 {conf => cdist/conf}/type/__pf_ruleset/man.text | 0 {conf => cdist/conf}/type/__pf_ruleset/parameter/optional | 0 {conf => cdist/conf}/type/__pf_ruleset/parameter/required | 0 {conf => cdist/conf}/type/__pf_ruleset/singleton | 0 .../conf}/type/__postgres_database/explorer/state | 0 .../conf}/type/__postgres_database/gencode-remote | 0 {conf => cdist/conf}/type/__postgres_database/man.text | 0 .../conf}/type/__postgres_database/parameter/optional | 0 .../conf}/type/__postgres_database/parameter/required | 0 {conf => cdist/conf}/type/__postgres_role/explorer/state | 0 {conf => cdist/conf}/type/__postgres_role/gencode-remote | 0 {conf => cdist/conf}/type/__postgres_role/man.text | 0 .../conf}/type/__postgres_role/parameter/optional | 0 .../conf}/type/__postgres_role/parameter/required | 0 {conf => cdist/conf}/type/__process/explorer/runs | 0 {conf => cdist/conf}/type/__process/gencode-remote | 0 {conf => cdist/conf}/type/__process/man.text | 0 {conf => cdist/conf}/type/__process/parameter/optional | 0 {conf => cdist/conf}/type/__process/parameter/required | 0 {conf => cdist/conf}/type/__qemu_img/explorer/exists | 0 {conf => cdist/conf}/type/__qemu_img/gencode-remote | 0 {conf => cdist/conf}/type/__qemu_img/man.text | 0 {conf => cdist/conf}/type/__qemu_img/manifest | 0 {conf => cdist/conf}/type/__qemu_img/parameter/optional | 0 {conf => cdist/conf}/type/__qemu_img/parameter/required | 0 {conf => cdist/conf}/type/__rvm/explorer/state | 0 {conf => cdist/conf}/type/__rvm/gencode-remote | 0 {conf => cdist/conf}/type/__rvm/man.text | 0 {conf => cdist/conf}/type/__rvm/manifest | 0 {conf => cdist/conf}/type/__rvm/parameter/required | 0 {conf => cdist/conf}/type/__rvm_gem/explorer/state | 0 {conf => cdist/conf}/type/__rvm_gem/gencode-remote | 0 {conf => cdist/conf}/type/__rvm_gem/man.text | 0 {conf => cdist/conf}/type/__rvm_gem/manifest | 0 {conf => cdist/conf}/type/__rvm_gem/parameter/optional | 0 {conf => cdist/conf}/type/__rvm_gem/parameter/required | 0 {conf => cdist/conf}/type/__rvm_gemset/explorer/state | 0 {conf => cdist/conf}/type/__rvm_gemset/gencode-remote | 0 {conf => cdist/conf}/type/__rvm_gemset/man.text | 0 {conf => cdist/conf}/type/__rvm_gemset/manifest | 0 {conf => cdist/conf}/type/__rvm_gemset/parameter/optional | 0 {conf => cdist/conf}/type/__rvm_gemset/parameter/required | 0 {conf => cdist/conf}/type/__rvm_ruby/explorer/state | 0 {conf => cdist/conf}/type/__rvm_ruby/gencode-remote | 0 {conf => cdist/conf}/type/__rvm_ruby/man.text | 0 {conf => cdist/conf}/type/__rvm_ruby/manifest | 0 {conf => cdist/conf}/type/__rvm_ruby/parameter/optional | 0 {conf => cdist/conf}/type/__rvm_ruby/parameter/required | 0 .../conf}/type/__ssh_authorized_key/explorer/dstuser_group | 0 {conf => cdist/conf}/type/__ssh_authorized_key/man.text | 0 {conf => cdist/conf}/type/__ssh_authorized_key/manifest | 0 .../conf}/type/__ssh_authorized_key/parameter/optional | 0 {conf => cdist/conf}/type/__start_on_boot/explorer/state | 0 {conf => cdist/conf}/type/__start_on_boot/gencode-remote | 0 {conf => cdist/conf}/type/__start_on_boot/man.text | 0 .../conf}/type/__start_on_boot/parameter/optional | 0 {conf => cdist/conf}/type/__timezone/man.text | 0 {conf => cdist/conf}/type/__timezone/manifest | 0 {conf => cdist/conf}/type/__user/TODO | 0 {conf => cdist/conf}/type/__user/explorer/group | 0 {conf => cdist/conf}/type/__user/explorer/passwd | 0 {conf => cdist/conf}/type/__user/explorer/shadow | 0 {conf => cdist/conf}/type/__user/gencode-remote | 0 {conf => cdist/conf}/type/__user/man.text | 0 {conf => cdist/conf}/type/__user/parameter/optional | 0 cdist/test/emulator/fixtures/conf/type/__file | 2 +- setup.py | 6 +++++- 241 files changed, 6 insertions(+), 2 deletions(-) rename {conf => cdist/conf}/.gitignore (100%) rename {conf => cdist/conf}/README (100%) rename {conf => cdist/conf}/explorer/hostname (100%) rename {conf => cdist/conf}/explorer/interfaces (100%) rename {conf => cdist/conf}/explorer/lsb_codename (100%) rename {conf => cdist/conf}/explorer/lsb_description (100%) rename {conf => cdist/conf}/explorer/lsb_id (100%) rename {conf => cdist/conf}/explorer/lsb_release (100%) rename {conf => cdist/conf}/explorer/machine (100%) rename {conf => cdist/conf}/explorer/os (100%) rename {conf => cdist/conf}/explorer/os_version (100%) rename {conf => cdist/conf}/explorer/runlevel (100%) rename {conf => cdist/conf}/manifest/init.sample (100%) rename {conf => cdist/conf}/type/__apt_ppa/explorer/state (100%) rename {conf => cdist/conf}/type/__apt_ppa/files/remove-apt-repository (100%) rename {conf => cdist/conf}/type/__apt_ppa/gencode-remote (100%) rename {conf => cdist/conf}/type/__apt_ppa/man.text (100%) rename {conf => cdist/conf}/type/__apt_ppa/manifest (100%) rename {conf => cdist/conf}/type/__apt_ppa/parameter/required (100%) rename {conf => cdist/conf}/type/__apt_update_index/gencode-remote (100%) rename {conf => cdist/conf}/type/__apt_update_index/man.text (100%) rename {conf => cdist/conf}/type/__apt_update_index/singleton (100%) rename {conf => cdist/conf}/type/__autofs_map/man.text (100%) rename {conf => cdist/conf}/type/__autofs_map/manifest (100%) rename {conf => cdist/conf}/type/__autofs_map/parameter/optional (100%) rename {conf => cdist/conf}/type/__autofs_map/parameter/required (100%) rename {conf => cdist/conf}/type/__autofs_master/files/auto.master.header (100%) rename {conf => cdist/conf}/type/__autofs_master/gencode-local (100%) rename {conf => cdist/conf}/type/__autofs_master/man.text (100%) rename {conf => cdist/conf}/type/__autofs_master/manifest (100%) rename {conf => cdist/conf}/type/__autofs_master/parameter/optional (100%) rename {conf => cdist/conf}/type/__autofs_master/singleton (100%) rename {conf => cdist/conf}/type/__cdistmarker/gencode-remote (100%) rename {conf => cdist/conf}/type/__cdistmarker/man.text (100%) rename {conf => cdist/conf}/type/__cdistmarker/parameter/optional (100%) rename {conf => cdist/conf}/type/__cdistmarker/singleton (100%) rename {conf => cdist/conf}/type/__cron/explorer/entry (100%) rename {conf => cdist/conf}/type/__cron/gencode-remote (100%) rename {conf => cdist/conf}/type/__cron/man.text (100%) rename {conf => cdist/conf}/type/__cron/manifest (100%) rename {conf => cdist/conf}/type/__cron/parameter/optional (100%) rename {conf => cdist/conf}/type/__cron/parameter/required (100%) rename {conf => cdist/conf}/type/__debconf_set_selections/gencode-remote (100%) rename {conf => cdist/conf}/type/__debconf_set_selections/man.text (100%) rename {conf => cdist/conf}/type/__debconf_set_selections/parameter/required (100%) rename {conf => cdist/conf}/type/__directory/explorer/state (100%) rename {conf => cdist/conf}/type/__directory/gencode-remote (100%) rename {conf => cdist/conf}/type/__directory/man.text (100%) rename {conf => cdist/conf}/type/__directory/parameter/boolean (100%) rename {conf => cdist/conf}/type/__directory/parameter/optional (100%) rename {conf => cdist/conf}/type/__file/explorer/cksum (100%) rename {conf => cdist/conf}/type/__file/explorer/exists (100%) rename {conf => cdist/conf}/type/__file/gencode-local (100%) rename {conf => cdist/conf}/type/__file/gencode-remote (100%) rename {conf => cdist/conf}/type/__file/man.text (100%) rename {conf => cdist/conf}/type/__file/manifest (100%) rename {conf => cdist/conf}/type/__file/parameter/optional (100%) rename {conf => cdist/conf}/type/__group/TODO (100%) rename {conf => cdist/conf}/type/__group/explorer/group (100%) rename {conf => cdist/conf}/type/__group/explorer/gshadow (100%) rename {conf => cdist/conf}/type/__group/gencode-remote (100%) rename {conf => cdist/conf}/type/__group/man.text (100%) rename {conf => cdist/conf}/type/__group/parameter/optional (100%) rename {conf => cdist/conf}/type/__issue/files/archlinux (100%) rename {conf => cdist/conf}/type/__issue/files/default (100%) rename {conf => cdist/conf}/type/__issue/files/redhat (100%) rename {conf => cdist/conf}/type/__issue/man.text (100%) rename {conf => cdist/conf}/type/__issue/manifest (100%) rename {conf => cdist/conf}/type/__issue/parameter/optional (100%) rename {conf => cdist/conf}/type/__issue/singleton (100%) rename {conf => cdist/conf}/type/__jail/.gitignore (100%) rename {conf => cdist/conf}/type/__jail/explorer/basepresent (100%) rename {conf => cdist/conf}/type/__jail/explorer/present (100%) rename {conf => cdist/conf}/type/__jail/explorer/status (100%) rename {conf => cdist/conf}/type/__jail/gencode-local (100%) rename {conf => cdist/conf}/type/__jail/gencode-remote (100%) rename {conf => cdist/conf}/type/__jail/man.text (100%) rename {conf => cdist/conf}/type/__jail/manifest (100%) rename {conf => cdist/conf}/type/__jail/parameter/optional (100%) rename {conf => cdist/conf}/type/__jail/parameter/required (100%) rename {conf => cdist/conf}/type/__key_value/explorer/state (100%) rename {conf => cdist/conf}/type/__key_value/gencode-remote (100%) rename {conf => cdist/conf}/type/__key_value/man.text (100%) rename {conf => cdist/conf}/type/__key_value/manifest (100%) rename {conf => cdist/conf}/type/__key_value/parameter/optional (100%) rename {conf => cdist/conf}/type/__key_value/parameter/required (100%) rename {conf => cdist/conf}/type/__line/explorer/state (100%) rename {conf => cdist/conf}/type/__line/gencode-remote (100%) rename {conf => cdist/conf}/type/__line/man.text (100%) rename {conf => cdist/conf}/type/__line/parameter/optional (100%) rename {conf => cdist/conf}/type/__link/explorer/state (100%) rename {conf => cdist/conf}/type/__link/gencode-remote (100%) rename {conf => cdist/conf}/type/__link/man.text (100%) rename {conf => cdist/conf}/type/__link/manifest (100%) rename {conf => cdist/conf}/type/__link/parameter/optional (100%) rename {conf => cdist/conf}/type/__link/parameter/required (100%) rename {conf => cdist/conf}/type/__mkfs/gencode-remote (100%) rename {conf => cdist/conf}/type/__mkfs/install (100%) rename {conf => cdist/conf}/type/__mkfs/man.text (100%) rename {conf => cdist/conf}/type/__mkfs/manifest (100%) rename {conf => cdist/conf}/type/__mkfs/parameter/optional (100%) rename {conf => cdist/conf}/type/__mkfs/parameter/required (100%) rename {conf => cdist/conf}/type/__motd/files/motd (100%) rename {conf => cdist/conf}/type/__motd/man.text (100%) rename {conf => cdist/conf}/type/__motd/manifest (100%) rename {conf => cdist/conf}/type/__motd/parameter/optional (100%) rename {conf => cdist/conf}/type/__motd/singleton (100%) rename {conf => cdist/conf}/type/__mysql_database/gencode-remote (100%) rename {conf => cdist/conf}/type/__mysql_database/man.text (100%) rename {conf => cdist/conf}/type/__mysql_database/parameter/optional (100%) rename {conf => cdist/conf}/type/__package/man.text (100%) rename {conf => cdist/conf}/type/__package/manifest (100%) rename {conf => cdist/conf}/type/__package/parameter/optional (100%) rename {conf => cdist/conf}/type/__package_apt/explorer/state (100%) rename {conf => cdist/conf}/type/__package_apt/gencode-remote (100%) rename {conf => cdist/conf}/type/__package_apt/man.text (100%) rename {conf => cdist/conf}/type/__package_apt/notes.txt (100%) rename {conf => cdist/conf}/type/__package_apt/parameter/optional (100%) rename {conf => cdist/conf}/type/__package_luarocks/explorer/pkg_status (100%) rename {conf => cdist/conf}/type/__package_luarocks/gencode-remote (100%) rename {conf => cdist/conf}/type/__package_luarocks/man.text (100%) rename {conf => cdist/conf}/type/__package_luarocks/manifest (100%) rename {conf => cdist/conf}/type/__package_luarocks/parameter/optional (100%) rename {conf => cdist/conf}/type/__package_opkg/explorer/pkg_status (100%) rename {conf => cdist/conf}/type/__package_opkg/gencode-remote (100%) rename {conf => cdist/conf}/type/__package_opkg/man.text (100%) rename {conf => cdist/conf}/type/__package_opkg/parameter/optional (100%) rename {conf => cdist/conf}/type/__package_pacman/explorer/pkg_version (100%) rename {conf => cdist/conf}/type/__package_pacman/gencode-remote (100%) rename {conf => cdist/conf}/type/__package_pacman/man.text (100%) rename {conf => cdist/conf}/type/__package_pacman/parameter/optional (100%) rename {conf => cdist/conf}/type/__package_pip/explorer/state (100%) rename {conf => cdist/conf}/type/__package_pip/gencode-remote (100%) rename {conf => cdist/conf}/type/__package_pip/man.text (100%) rename {conf => cdist/conf}/type/__package_pip/parameter/optional (100%) rename {conf => cdist/conf}/type/__package_pkg_freebsd/explorer/pkg_version (100%) rename {conf => cdist/conf}/type/__package_pkg_freebsd/gencode-remote (100%) rename {conf => cdist/conf}/type/__package_pkg_freebsd/man.text (100%) rename {conf => cdist/conf}/type/__package_pkg_freebsd/parameter/optional (100%) rename {conf => cdist/conf}/type/__package_pkg_openbsd/explorer/pkg_version (100%) rename {conf => cdist/conf}/type/__package_pkg_openbsd/gencode-remote (100%) rename {conf => cdist/conf}/type/__package_pkg_openbsd/man.text (100%) rename {conf => cdist/conf}/type/__package_pkg_openbsd/parameter/optional (100%) rename {conf => cdist/conf}/type/__package_rubygem/explorer/pkg_status (100%) rename {conf => cdist/conf}/type/__package_rubygem/gencode-remote (100%) rename {conf => cdist/conf}/type/__package_rubygem/man.text (100%) rename {conf => cdist/conf}/type/__package_rubygem/parameter/optional (100%) rename {conf => cdist/conf}/type/__package_yum/explorer/pkg_version (100%) rename {conf => cdist/conf}/type/__package_yum/gencode-remote (100%) rename {conf => cdist/conf}/type/__package_yum/man.text (100%) rename {conf => cdist/conf}/type/__package_yum/parameter/optional (100%) rename {conf => cdist/conf}/type/__package_zypper/explorer/pkg_version (100%) rename {conf => cdist/conf}/type/__package_zypper/gencode-remote (100%) rename {conf => cdist/conf}/type/__package_zypper/man.text (100%) rename {conf => cdist/conf}/type/__package_zypper/parameter/optional (100%) rename {conf => cdist/conf}/type/__partition_msdos/install (100%) rename {conf => cdist/conf}/type/__partition_msdos/man.text (100%) rename {conf => cdist/conf}/type/__partition_msdos/manifest (100%) rename {conf => cdist/conf}/type/__partition_msdos/parameter/optional (100%) rename {conf => cdist/conf}/type/__partition_msdos/parameter/required (100%) rename {conf => cdist/conf}/type/__partition_msdos_apply/explorer/partitions (100%) rename {conf => cdist/conf}/type/__partition_msdos_apply/files/lib.sh (100%) rename {conf => cdist/conf}/type/__partition_msdos_apply/gencode-remote (100%) rename {conf => cdist/conf}/type/__partition_msdos_apply/install (100%) rename {conf => cdist/conf}/type/__partition_msdos_apply/man.text (100%) rename {conf => cdist/conf}/type/__partition_msdos_apply/singleton (100%) rename {conf => cdist/conf}/type/__pf_apply/explorer/rcvar (100%) rename {conf => cdist/conf}/type/__pf_apply/gencode-remote (100%) rename {conf => cdist/conf}/type/__pf_apply/man.text (100%) rename {conf => cdist/conf}/type/__pf_apply/singleton (100%) rename {conf => cdist/conf}/type/__pf_ruleset/explorer/cksum (100%) rename {conf => cdist/conf}/type/__pf_ruleset/explorer/rcvar (100%) rename {conf => cdist/conf}/type/__pf_ruleset/gencode-local (100%) rename {conf => cdist/conf}/type/__pf_ruleset/gencode-remote (100%) rename {conf => cdist/conf}/type/__pf_ruleset/man.text (100%) rename {conf => cdist/conf}/type/__pf_ruleset/parameter/optional (100%) rename {conf => cdist/conf}/type/__pf_ruleset/parameter/required (100%) rename {conf => cdist/conf}/type/__pf_ruleset/singleton (100%) rename {conf => cdist/conf}/type/__postgres_database/explorer/state (100%) rename {conf => cdist/conf}/type/__postgres_database/gencode-remote (100%) rename {conf => cdist/conf}/type/__postgres_database/man.text (100%) rename {conf => cdist/conf}/type/__postgres_database/parameter/optional (100%) rename {conf => cdist/conf}/type/__postgres_database/parameter/required (100%) rename {conf => cdist/conf}/type/__postgres_role/explorer/state (100%) rename {conf => cdist/conf}/type/__postgres_role/gencode-remote (100%) rename {conf => cdist/conf}/type/__postgres_role/man.text (100%) rename {conf => cdist/conf}/type/__postgres_role/parameter/optional (100%) rename {conf => cdist/conf}/type/__postgres_role/parameter/required (100%) rename {conf => cdist/conf}/type/__process/explorer/runs (100%) rename {conf => cdist/conf}/type/__process/gencode-remote (100%) rename {conf => cdist/conf}/type/__process/man.text (100%) rename {conf => cdist/conf}/type/__process/parameter/optional (100%) rename {conf => cdist/conf}/type/__process/parameter/required (100%) rename {conf => cdist/conf}/type/__qemu_img/explorer/exists (100%) rename {conf => cdist/conf}/type/__qemu_img/gencode-remote (100%) rename {conf => cdist/conf}/type/__qemu_img/man.text (100%) rename {conf => cdist/conf}/type/__qemu_img/manifest (100%) rename {conf => cdist/conf}/type/__qemu_img/parameter/optional (100%) rename {conf => cdist/conf}/type/__qemu_img/parameter/required (100%) rename {conf => cdist/conf}/type/__rvm/explorer/state (100%) rename {conf => cdist/conf}/type/__rvm/gencode-remote (100%) rename {conf => cdist/conf}/type/__rvm/man.text (100%) rename {conf => cdist/conf}/type/__rvm/manifest (100%) rename {conf => cdist/conf}/type/__rvm/parameter/required (100%) rename {conf => cdist/conf}/type/__rvm_gem/explorer/state (100%) rename {conf => cdist/conf}/type/__rvm_gem/gencode-remote (100%) rename {conf => cdist/conf}/type/__rvm_gem/man.text (100%) rename {conf => cdist/conf}/type/__rvm_gem/manifest (100%) rename {conf => cdist/conf}/type/__rvm_gem/parameter/optional (100%) rename {conf => cdist/conf}/type/__rvm_gem/parameter/required (100%) rename {conf => cdist/conf}/type/__rvm_gemset/explorer/state (100%) rename {conf => cdist/conf}/type/__rvm_gemset/gencode-remote (100%) rename {conf => cdist/conf}/type/__rvm_gemset/man.text (100%) rename {conf => cdist/conf}/type/__rvm_gemset/manifest (100%) rename {conf => cdist/conf}/type/__rvm_gemset/parameter/optional (100%) rename {conf => cdist/conf}/type/__rvm_gemset/parameter/required (100%) rename {conf => cdist/conf}/type/__rvm_ruby/explorer/state (100%) rename {conf => cdist/conf}/type/__rvm_ruby/gencode-remote (100%) rename {conf => cdist/conf}/type/__rvm_ruby/man.text (100%) rename {conf => cdist/conf}/type/__rvm_ruby/manifest (100%) rename {conf => cdist/conf}/type/__rvm_ruby/parameter/optional (100%) rename {conf => cdist/conf}/type/__rvm_ruby/parameter/required (100%) rename {conf => cdist/conf}/type/__ssh_authorized_key/explorer/dstuser_group (100%) rename {conf => cdist/conf}/type/__ssh_authorized_key/man.text (100%) rename {conf => cdist/conf}/type/__ssh_authorized_key/manifest (100%) rename {conf => cdist/conf}/type/__ssh_authorized_key/parameter/optional (100%) rename {conf => cdist/conf}/type/__start_on_boot/explorer/state (100%) rename {conf => cdist/conf}/type/__start_on_boot/gencode-remote (100%) rename {conf => cdist/conf}/type/__start_on_boot/man.text (100%) rename {conf => cdist/conf}/type/__start_on_boot/parameter/optional (100%) rename {conf => cdist/conf}/type/__timezone/man.text (100%) rename {conf => cdist/conf}/type/__timezone/manifest (100%) rename {conf => cdist/conf}/type/__user/TODO (100%) rename {conf => cdist/conf}/type/__user/explorer/group (100%) rename {conf => cdist/conf}/type/__user/explorer/passwd (100%) rename {conf => cdist/conf}/type/__user/explorer/shadow (100%) rename {conf => cdist/conf}/type/__user/gencode-remote (100%) rename {conf => cdist/conf}/type/__user/man.text (100%) rename {conf => cdist/conf}/type/__user/parameter/optional (100%) diff --git a/conf/.gitignore b/cdist/conf/.gitignore similarity index 100% rename from conf/.gitignore rename to cdist/conf/.gitignore diff --git a/conf/README b/cdist/conf/README similarity index 100% rename from conf/README rename to cdist/conf/README diff --git a/conf/explorer/hostname b/cdist/conf/explorer/hostname similarity index 100% rename from conf/explorer/hostname rename to cdist/conf/explorer/hostname diff --git a/conf/explorer/interfaces b/cdist/conf/explorer/interfaces similarity index 100% rename from conf/explorer/interfaces rename to cdist/conf/explorer/interfaces diff --git a/conf/explorer/lsb_codename b/cdist/conf/explorer/lsb_codename similarity index 100% rename from conf/explorer/lsb_codename rename to cdist/conf/explorer/lsb_codename diff --git a/conf/explorer/lsb_description b/cdist/conf/explorer/lsb_description similarity index 100% rename from conf/explorer/lsb_description rename to cdist/conf/explorer/lsb_description diff --git a/conf/explorer/lsb_id b/cdist/conf/explorer/lsb_id similarity index 100% rename from conf/explorer/lsb_id rename to cdist/conf/explorer/lsb_id diff --git a/conf/explorer/lsb_release b/cdist/conf/explorer/lsb_release similarity index 100% rename from conf/explorer/lsb_release rename to cdist/conf/explorer/lsb_release diff --git a/conf/explorer/machine b/cdist/conf/explorer/machine similarity index 100% rename from conf/explorer/machine rename to cdist/conf/explorer/machine diff --git a/conf/explorer/os b/cdist/conf/explorer/os similarity index 100% rename from conf/explorer/os rename to cdist/conf/explorer/os diff --git a/conf/explorer/os_version b/cdist/conf/explorer/os_version similarity index 100% rename from conf/explorer/os_version rename to cdist/conf/explorer/os_version diff --git a/conf/explorer/runlevel b/cdist/conf/explorer/runlevel similarity index 100% rename from conf/explorer/runlevel rename to cdist/conf/explorer/runlevel diff --git a/conf/manifest/init.sample b/cdist/conf/manifest/init.sample similarity index 100% rename from conf/manifest/init.sample rename to cdist/conf/manifest/init.sample diff --git a/conf/type/__apt_ppa/explorer/state b/cdist/conf/type/__apt_ppa/explorer/state similarity index 100% rename from conf/type/__apt_ppa/explorer/state rename to cdist/conf/type/__apt_ppa/explorer/state diff --git a/conf/type/__apt_ppa/files/remove-apt-repository b/cdist/conf/type/__apt_ppa/files/remove-apt-repository similarity index 100% rename from conf/type/__apt_ppa/files/remove-apt-repository rename to cdist/conf/type/__apt_ppa/files/remove-apt-repository diff --git a/conf/type/__apt_ppa/gencode-remote b/cdist/conf/type/__apt_ppa/gencode-remote similarity index 100% rename from conf/type/__apt_ppa/gencode-remote rename to cdist/conf/type/__apt_ppa/gencode-remote diff --git a/conf/type/__apt_ppa/man.text b/cdist/conf/type/__apt_ppa/man.text similarity index 100% rename from conf/type/__apt_ppa/man.text rename to cdist/conf/type/__apt_ppa/man.text diff --git a/conf/type/__apt_ppa/manifest b/cdist/conf/type/__apt_ppa/manifest similarity index 100% rename from conf/type/__apt_ppa/manifest rename to cdist/conf/type/__apt_ppa/manifest diff --git a/conf/type/__apt_ppa/parameter/required b/cdist/conf/type/__apt_ppa/parameter/required similarity index 100% rename from conf/type/__apt_ppa/parameter/required rename to cdist/conf/type/__apt_ppa/parameter/required diff --git a/conf/type/__apt_update_index/gencode-remote b/cdist/conf/type/__apt_update_index/gencode-remote similarity index 100% rename from conf/type/__apt_update_index/gencode-remote rename to cdist/conf/type/__apt_update_index/gencode-remote diff --git a/conf/type/__apt_update_index/man.text b/cdist/conf/type/__apt_update_index/man.text similarity index 100% rename from conf/type/__apt_update_index/man.text rename to cdist/conf/type/__apt_update_index/man.text diff --git a/conf/type/__apt_update_index/singleton b/cdist/conf/type/__apt_update_index/singleton similarity index 100% rename from conf/type/__apt_update_index/singleton rename to cdist/conf/type/__apt_update_index/singleton diff --git a/conf/type/__autofs_map/man.text b/cdist/conf/type/__autofs_map/man.text similarity index 100% rename from conf/type/__autofs_map/man.text rename to cdist/conf/type/__autofs_map/man.text diff --git a/conf/type/__autofs_map/manifest b/cdist/conf/type/__autofs_map/manifest similarity index 100% rename from conf/type/__autofs_map/manifest rename to cdist/conf/type/__autofs_map/manifest diff --git a/conf/type/__autofs_map/parameter/optional b/cdist/conf/type/__autofs_map/parameter/optional similarity index 100% rename from conf/type/__autofs_map/parameter/optional rename to cdist/conf/type/__autofs_map/parameter/optional diff --git a/conf/type/__autofs_map/parameter/required b/cdist/conf/type/__autofs_map/parameter/required similarity index 100% rename from conf/type/__autofs_map/parameter/required rename to cdist/conf/type/__autofs_map/parameter/required diff --git a/conf/type/__autofs_master/files/auto.master.header b/cdist/conf/type/__autofs_master/files/auto.master.header similarity index 100% rename from conf/type/__autofs_master/files/auto.master.header rename to cdist/conf/type/__autofs_master/files/auto.master.header diff --git a/conf/type/__autofs_master/gencode-local b/cdist/conf/type/__autofs_master/gencode-local similarity index 100% rename from conf/type/__autofs_master/gencode-local rename to cdist/conf/type/__autofs_master/gencode-local diff --git a/conf/type/__autofs_master/man.text b/cdist/conf/type/__autofs_master/man.text similarity index 100% rename from conf/type/__autofs_master/man.text rename to cdist/conf/type/__autofs_master/man.text diff --git a/conf/type/__autofs_master/manifest b/cdist/conf/type/__autofs_master/manifest similarity index 100% rename from conf/type/__autofs_master/manifest rename to cdist/conf/type/__autofs_master/manifest diff --git a/conf/type/__autofs_master/parameter/optional b/cdist/conf/type/__autofs_master/parameter/optional similarity index 100% rename from conf/type/__autofs_master/parameter/optional rename to cdist/conf/type/__autofs_master/parameter/optional diff --git a/conf/type/__autofs_master/singleton b/cdist/conf/type/__autofs_master/singleton similarity index 100% rename from conf/type/__autofs_master/singleton rename to cdist/conf/type/__autofs_master/singleton diff --git a/conf/type/__cdistmarker/gencode-remote b/cdist/conf/type/__cdistmarker/gencode-remote similarity index 100% rename from conf/type/__cdistmarker/gencode-remote rename to cdist/conf/type/__cdistmarker/gencode-remote diff --git a/conf/type/__cdistmarker/man.text b/cdist/conf/type/__cdistmarker/man.text similarity index 100% rename from conf/type/__cdistmarker/man.text rename to cdist/conf/type/__cdistmarker/man.text diff --git a/conf/type/__cdistmarker/parameter/optional b/cdist/conf/type/__cdistmarker/parameter/optional similarity index 100% rename from conf/type/__cdistmarker/parameter/optional rename to cdist/conf/type/__cdistmarker/parameter/optional diff --git a/conf/type/__cdistmarker/singleton b/cdist/conf/type/__cdistmarker/singleton similarity index 100% rename from conf/type/__cdistmarker/singleton rename to cdist/conf/type/__cdistmarker/singleton diff --git a/conf/type/__cron/explorer/entry b/cdist/conf/type/__cron/explorer/entry similarity index 100% rename from conf/type/__cron/explorer/entry rename to cdist/conf/type/__cron/explorer/entry diff --git a/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote similarity index 100% rename from conf/type/__cron/gencode-remote rename to cdist/conf/type/__cron/gencode-remote diff --git a/conf/type/__cron/man.text b/cdist/conf/type/__cron/man.text similarity index 100% rename from conf/type/__cron/man.text rename to cdist/conf/type/__cron/man.text diff --git a/conf/type/__cron/manifest b/cdist/conf/type/__cron/manifest similarity index 100% rename from conf/type/__cron/manifest rename to cdist/conf/type/__cron/manifest diff --git a/conf/type/__cron/parameter/optional b/cdist/conf/type/__cron/parameter/optional similarity index 100% rename from conf/type/__cron/parameter/optional rename to cdist/conf/type/__cron/parameter/optional diff --git a/conf/type/__cron/parameter/required b/cdist/conf/type/__cron/parameter/required similarity index 100% rename from conf/type/__cron/parameter/required rename to cdist/conf/type/__cron/parameter/required diff --git a/conf/type/__debconf_set_selections/gencode-remote b/cdist/conf/type/__debconf_set_selections/gencode-remote similarity index 100% rename from conf/type/__debconf_set_selections/gencode-remote rename to cdist/conf/type/__debconf_set_selections/gencode-remote diff --git a/conf/type/__debconf_set_selections/man.text b/cdist/conf/type/__debconf_set_selections/man.text similarity index 100% rename from conf/type/__debconf_set_selections/man.text rename to cdist/conf/type/__debconf_set_selections/man.text diff --git a/conf/type/__debconf_set_selections/parameter/required b/cdist/conf/type/__debconf_set_selections/parameter/required similarity index 100% rename from conf/type/__debconf_set_selections/parameter/required rename to cdist/conf/type/__debconf_set_selections/parameter/required diff --git a/conf/type/__directory/explorer/state b/cdist/conf/type/__directory/explorer/state similarity index 100% rename from conf/type/__directory/explorer/state rename to cdist/conf/type/__directory/explorer/state diff --git a/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote similarity index 100% rename from conf/type/__directory/gencode-remote rename to cdist/conf/type/__directory/gencode-remote diff --git a/conf/type/__directory/man.text b/cdist/conf/type/__directory/man.text similarity index 100% rename from conf/type/__directory/man.text rename to cdist/conf/type/__directory/man.text diff --git a/conf/type/__directory/parameter/boolean b/cdist/conf/type/__directory/parameter/boolean similarity index 100% rename from conf/type/__directory/parameter/boolean rename to cdist/conf/type/__directory/parameter/boolean diff --git a/conf/type/__directory/parameter/optional b/cdist/conf/type/__directory/parameter/optional similarity index 100% rename from conf/type/__directory/parameter/optional rename to cdist/conf/type/__directory/parameter/optional diff --git a/conf/type/__file/explorer/cksum b/cdist/conf/type/__file/explorer/cksum similarity index 100% rename from conf/type/__file/explorer/cksum rename to cdist/conf/type/__file/explorer/cksum diff --git a/conf/type/__file/explorer/exists b/cdist/conf/type/__file/explorer/exists similarity index 100% rename from conf/type/__file/explorer/exists rename to cdist/conf/type/__file/explorer/exists diff --git a/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local similarity index 100% rename from conf/type/__file/gencode-local rename to cdist/conf/type/__file/gencode-local diff --git a/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote similarity index 100% rename from conf/type/__file/gencode-remote rename to cdist/conf/type/__file/gencode-remote diff --git a/conf/type/__file/man.text b/cdist/conf/type/__file/man.text similarity index 100% rename from conf/type/__file/man.text rename to cdist/conf/type/__file/man.text diff --git a/conf/type/__file/manifest b/cdist/conf/type/__file/manifest similarity index 100% rename from conf/type/__file/manifest rename to cdist/conf/type/__file/manifest diff --git a/conf/type/__file/parameter/optional b/cdist/conf/type/__file/parameter/optional similarity index 100% rename from conf/type/__file/parameter/optional rename to cdist/conf/type/__file/parameter/optional diff --git a/conf/type/__group/TODO b/cdist/conf/type/__group/TODO similarity index 100% rename from conf/type/__group/TODO rename to cdist/conf/type/__group/TODO diff --git a/conf/type/__group/explorer/group b/cdist/conf/type/__group/explorer/group similarity index 100% rename from conf/type/__group/explorer/group rename to cdist/conf/type/__group/explorer/group diff --git a/conf/type/__group/explorer/gshadow b/cdist/conf/type/__group/explorer/gshadow similarity index 100% rename from conf/type/__group/explorer/gshadow rename to cdist/conf/type/__group/explorer/gshadow diff --git a/conf/type/__group/gencode-remote b/cdist/conf/type/__group/gencode-remote similarity index 100% rename from conf/type/__group/gencode-remote rename to cdist/conf/type/__group/gencode-remote diff --git a/conf/type/__group/man.text b/cdist/conf/type/__group/man.text similarity index 100% rename from conf/type/__group/man.text rename to cdist/conf/type/__group/man.text diff --git a/conf/type/__group/parameter/optional b/cdist/conf/type/__group/parameter/optional similarity index 100% rename from conf/type/__group/parameter/optional rename to cdist/conf/type/__group/parameter/optional diff --git a/conf/type/__issue/files/archlinux b/cdist/conf/type/__issue/files/archlinux similarity index 100% rename from conf/type/__issue/files/archlinux rename to cdist/conf/type/__issue/files/archlinux diff --git a/conf/type/__issue/files/default b/cdist/conf/type/__issue/files/default similarity index 100% rename from conf/type/__issue/files/default rename to cdist/conf/type/__issue/files/default diff --git a/conf/type/__issue/files/redhat b/cdist/conf/type/__issue/files/redhat similarity index 100% rename from conf/type/__issue/files/redhat rename to cdist/conf/type/__issue/files/redhat diff --git a/conf/type/__issue/man.text b/cdist/conf/type/__issue/man.text similarity index 100% rename from conf/type/__issue/man.text rename to cdist/conf/type/__issue/man.text diff --git a/conf/type/__issue/manifest b/cdist/conf/type/__issue/manifest similarity index 100% rename from conf/type/__issue/manifest rename to cdist/conf/type/__issue/manifest diff --git a/conf/type/__issue/parameter/optional b/cdist/conf/type/__issue/parameter/optional similarity index 100% rename from conf/type/__issue/parameter/optional rename to cdist/conf/type/__issue/parameter/optional diff --git a/conf/type/__issue/singleton b/cdist/conf/type/__issue/singleton similarity index 100% rename from conf/type/__issue/singleton rename to cdist/conf/type/__issue/singleton diff --git a/conf/type/__jail/.gitignore b/cdist/conf/type/__jail/.gitignore similarity index 100% rename from conf/type/__jail/.gitignore rename to cdist/conf/type/__jail/.gitignore diff --git a/conf/type/__jail/explorer/basepresent b/cdist/conf/type/__jail/explorer/basepresent similarity index 100% rename from conf/type/__jail/explorer/basepresent rename to cdist/conf/type/__jail/explorer/basepresent diff --git a/conf/type/__jail/explorer/present b/cdist/conf/type/__jail/explorer/present similarity index 100% rename from conf/type/__jail/explorer/present rename to cdist/conf/type/__jail/explorer/present diff --git a/conf/type/__jail/explorer/status b/cdist/conf/type/__jail/explorer/status similarity index 100% rename from conf/type/__jail/explorer/status rename to cdist/conf/type/__jail/explorer/status diff --git a/conf/type/__jail/gencode-local b/cdist/conf/type/__jail/gencode-local similarity index 100% rename from conf/type/__jail/gencode-local rename to cdist/conf/type/__jail/gencode-local diff --git a/conf/type/__jail/gencode-remote b/cdist/conf/type/__jail/gencode-remote similarity index 100% rename from conf/type/__jail/gencode-remote rename to cdist/conf/type/__jail/gencode-remote diff --git a/conf/type/__jail/man.text b/cdist/conf/type/__jail/man.text similarity index 100% rename from conf/type/__jail/man.text rename to cdist/conf/type/__jail/man.text diff --git a/conf/type/__jail/manifest b/cdist/conf/type/__jail/manifest similarity index 100% rename from conf/type/__jail/manifest rename to cdist/conf/type/__jail/manifest diff --git a/conf/type/__jail/parameter/optional b/cdist/conf/type/__jail/parameter/optional similarity index 100% rename from conf/type/__jail/parameter/optional rename to cdist/conf/type/__jail/parameter/optional diff --git a/conf/type/__jail/parameter/required b/cdist/conf/type/__jail/parameter/required similarity index 100% rename from conf/type/__jail/parameter/required rename to cdist/conf/type/__jail/parameter/required diff --git a/conf/type/__key_value/explorer/state b/cdist/conf/type/__key_value/explorer/state similarity index 100% rename from conf/type/__key_value/explorer/state rename to cdist/conf/type/__key_value/explorer/state diff --git a/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote similarity index 100% rename from conf/type/__key_value/gencode-remote rename to cdist/conf/type/__key_value/gencode-remote diff --git a/conf/type/__key_value/man.text b/cdist/conf/type/__key_value/man.text similarity index 100% rename from conf/type/__key_value/man.text rename to cdist/conf/type/__key_value/man.text diff --git a/conf/type/__key_value/manifest b/cdist/conf/type/__key_value/manifest similarity index 100% rename from conf/type/__key_value/manifest rename to cdist/conf/type/__key_value/manifest diff --git a/conf/type/__key_value/parameter/optional b/cdist/conf/type/__key_value/parameter/optional similarity index 100% rename from conf/type/__key_value/parameter/optional rename to cdist/conf/type/__key_value/parameter/optional diff --git a/conf/type/__key_value/parameter/required b/cdist/conf/type/__key_value/parameter/required similarity index 100% rename from conf/type/__key_value/parameter/required rename to cdist/conf/type/__key_value/parameter/required diff --git a/conf/type/__line/explorer/state b/cdist/conf/type/__line/explorer/state similarity index 100% rename from conf/type/__line/explorer/state rename to cdist/conf/type/__line/explorer/state diff --git a/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote similarity index 100% rename from conf/type/__line/gencode-remote rename to cdist/conf/type/__line/gencode-remote diff --git a/conf/type/__line/man.text b/cdist/conf/type/__line/man.text similarity index 100% rename from conf/type/__line/man.text rename to cdist/conf/type/__line/man.text diff --git a/conf/type/__line/parameter/optional b/cdist/conf/type/__line/parameter/optional similarity index 100% rename from conf/type/__line/parameter/optional rename to cdist/conf/type/__line/parameter/optional diff --git a/conf/type/__link/explorer/state b/cdist/conf/type/__link/explorer/state similarity index 100% rename from conf/type/__link/explorer/state rename to cdist/conf/type/__link/explorer/state diff --git a/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote similarity index 100% rename from conf/type/__link/gencode-remote rename to cdist/conf/type/__link/gencode-remote diff --git a/conf/type/__link/man.text b/cdist/conf/type/__link/man.text similarity index 100% rename from conf/type/__link/man.text rename to cdist/conf/type/__link/man.text diff --git a/conf/type/__link/manifest b/cdist/conf/type/__link/manifest similarity index 100% rename from conf/type/__link/manifest rename to cdist/conf/type/__link/manifest diff --git a/conf/type/__link/parameter/optional b/cdist/conf/type/__link/parameter/optional similarity index 100% rename from conf/type/__link/parameter/optional rename to cdist/conf/type/__link/parameter/optional diff --git a/conf/type/__link/parameter/required b/cdist/conf/type/__link/parameter/required similarity index 100% rename from conf/type/__link/parameter/required rename to cdist/conf/type/__link/parameter/required diff --git a/conf/type/__mkfs/gencode-remote b/cdist/conf/type/__mkfs/gencode-remote similarity index 100% rename from conf/type/__mkfs/gencode-remote rename to cdist/conf/type/__mkfs/gencode-remote diff --git a/conf/type/__mkfs/install b/cdist/conf/type/__mkfs/install similarity index 100% rename from conf/type/__mkfs/install rename to cdist/conf/type/__mkfs/install diff --git a/conf/type/__mkfs/man.text b/cdist/conf/type/__mkfs/man.text similarity index 100% rename from conf/type/__mkfs/man.text rename to cdist/conf/type/__mkfs/man.text diff --git a/conf/type/__mkfs/manifest b/cdist/conf/type/__mkfs/manifest similarity index 100% rename from conf/type/__mkfs/manifest rename to cdist/conf/type/__mkfs/manifest diff --git a/conf/type/__mkfs/parameter/optional b/cdist/conf/type/__mkfs/parameter/optional similarity index 100% rename from conf/type/__mkfs/parameter/optional rename to cdist/conf/type/__mkfs/parameter/optional diff --git a/conf/type/__mkfs/parameter/required b/cdist/conf/type/__mkfs/parameter/required similarity index 100% rename from conf/type/__mkfs/parameter/required rename to cdist/conf/type/__mkfs/parameter/required diff --git a/conf/type/__motd/files/motd b/cdist/conf/type/__motd/files/motd similarity index 100% rename from conf/type/__motd/files/motd rename to cdist/conf/type/__motd/files/motd diff --git a/conf/type/__motd/man.text b/cdist/conf/type/__motd/man.text similarity index 100% rename from conf/type/__motd/man.text rename to cdist/conf/type/__motd/man.text diff --git a/conf/type/__motd/manifest b/cdist/conf/type/__motd/manifest similarity index 100% rename from conf/type/__motd/manifest rename to cdist/conf/type/__motd/manifest diff --git a/conf/type/__motd/parameter/optional b/cdist/conf/type/__motd/parameter/optional similarity index 100% rename from conf/type/__motd/parameter/optional rename to cdist/conf/type/__motd/parameter/optional diff --git a/conf/type/__motd/singleton b/cdist/conf/type/__motd/singleton similarity index 100% rename from conf/type/__motd/singleton rename to cdist/conf/type/__motd/singleton diff --git a/conf/type/__mysql_database/gencode-remote b/cdist/conf/type/__mysql_database/gencode-remote similarity index 100% rename from conf/type/__mysql_database/gencode-remote rename to cdist/conf/type/__mysql_database/gencode-remote diff --git a/conf/type/__mysql_database/man.text b/cdist/conf/type/__mysql_database/man.text similarity index 100% rename from conf/type/__mysql_database/man.text rename to cdist/conf/type/__mysql_database/man.text diff --git a/conf/type/__mysql_database/parameter/optional b/cdist/conf/type/__mysql_database/parameter/optional similarity index 100% rename from conf/type/__mysql_database/parameter/optional rename to cdist/conf/type/__mysql_database/parameter/optional diff --git a/conf/type/__package/man.text b/cdist/conf/type/__package/man.text similarity index 100% rename from conf/type/__package/man.text rename to cdist/conf/type/__package/man.text diff --git a/conf/type/__package/manifest b/cdist/conf/type/__package/manifest similarity index 100% rename from conf/type/__package/manifest rename to cdist/conf/type/__package/manifest diff --git a/conf/type/__package/parameter/optional b/cdist/conf/type/__package/parameter/optional similarity index 100% rename from conf/type/__package/parameter/optional rename to cdist/conf/type/__package/parameter/optional diff --git a/conf/type/__package_apt/explorer/state b/cdist/conf/type/__package_apt/explorer/state similarity index 100% rename from conf/type/__package_apt/explorer/state rename to cdist/conf/type/__package_apt/explorer/state diff --git a/conf/type/__package_apt/gencode-remote b/cdist/conf/type/__package_apt/gencode-remote similarity index 100% rename from conf/type/__package_apt/gencode-remote rename to cdist/conf/type/__package_apt/gencode-remote diff --git a/conf/type/__package_apt/man.text b/cdist/conf/type/__package_apt/man.text similarity index 100% rename from conf/type/__package_apt/man.text rename to cdist/conf/type/__package_apt/man.text diff --git a/conf/type/__package_apt/notes.txt b/cdist/conf/type/__package_apt/notes.txt similarity index 100% rename from conf/type/__package_apt/notes.txt rename to cdist/conf/type/__package_apt/notes.txt diff --git a/conf/type/__package_apt/parameter/optional b/cdist/conf/type/__package_apt/parameter/optional similarity index 100% rename from conf/type/__package_apt/parameter/optional rename to cdist/conf/type/__package_apt/parameter/optional diff --git a/conf/type/__package_luarocks/explorer/pkg_status b/cdist/conf/type/__package_luarocks/explorer/pkg_status similarity index 100% rename from conf/type/__package_luarocks/explorer/pkg_status rename to cdist/conf/type/__package_luarocks/explorer/pkg_status diff --git a/conf/type/__package_luarocks/gencode-remote b/cdist/conf/type/__package_luarocks/gencode-remote similarity index 100% rename from conf/type/__package_luarocks/gencode-remote rename to cdist/conf/type/__package_luarocks/gencode-remote diff --git a/conf/type/__package_luarocks/man.text b/cdist/conf/type/__package_luarocks/man.text similarity index 100% rename from conf/type/__package_luarocks/man.text rename to cdist/conf/type/__package_luarocks/man.text diff --git a/conf/type/__package_luarocks/manifest b/cdist/conf/type/__package_luarocks/manifest similarity index 100% rename from conf/type/__package_luarocks/manifest rename to cdist/conf/type/__package_luarocks/manifest diff --git a/conf/type/__package_luarocks/parameter/optional b/cdist/conf/type/__package_luarocks/parameter/optional similarity index 100% rename from conf/type/__package_luarocks/parameter/optional rename to cdist/conf/type/__package_luarocks/parameter/optional diff --git a/conf/type/__package_opkg/explorer/pkg_status b/cdist/conf/type/__package_opkg/explorer/pkg_status similarity index 100% rename from conf/type/__package_opkg/explorer/pkg_status rename to cdist/conf/type/__package_opkg/explorer/pkg_status diff --git a/conf/type/__package_opkg/gencode-remote b/cdist/conf/type/__package_opkg/gencode-remote similarity index 100% rename from conf/type/__package_opkg/gencode-remote rename to cdist/conf/type/__package_opkg/gencode-remote diff --git a/conf/type/__package_opkg/man.text b/cdist/conf/type/__package_opkg/man.text similarity index 100% rename from conf/type/__package_opkg/man.text rename to cdist/conf/type/__package_opkg/man.text diff --git a/conf/type/__package_opkg/parameter/optional b/cdist/conf/type/__package_opkg/parameter/optional similarity index 100% rename from conf/type/__package_opkg/parameter/optional rename to cdist/conf/type/__package_opkg/parameter/optional diff --git a/conf/type/__package_pacman/explorer/pkg_version b/cdist/conf/type/__package_pacman/explorer/pkg_version similarity index 100% rename from conf/type/__package_pacman/explorer/pkg_version rename to cdist/conf/type/__package_pacman/explorer/pkg_version diff --git a/conf/type/__package_pacman/gencode-remote b/cdist/conf/type/__package_pacman/gencode-remote similarity index 100% rename from conf/type/__package_pacman/gencode-remote rename to cdist/conf/type/__package_pacman/gencode-remote diff --git a/conf/type/__package_pacman/man.text b/cdist/conf/type/__package_pacman/man.text similarity index 100% rename from conf/type/__package_pacman/man.text rename to cdist/conf/type/__package_pacman/man.text diff --git a/conf/type/__package_pacman/parameter/optional b/cdist/conf/type/__package_pacman/parameter/optional similarity index 100% rename from conf/type/__package_pacman/parameter/optional rename to cdist/conf/type/__package_pacman/parameter/optional diff --git a/conf/type/__package_pip/explorer/state b/cdist/conf/type/__package_pip/explorer/state similarity index 100% rename from conf/type/__package_pip/explorer/state rename to cdist/conf/type/__package_pip/explorer/state diff --git a/conf/type/__package_pip/gencode-remote b/cdist/conf/type/__package_pip/gencode-remote similarity index 100% rename from conf/type/__package_pip/gencode-remote rename to cdist/conf/type/__package_pip/gencode-remote diff --git a/conf/type/__package_pip/man.text b/cdist/conf/type/__package_pip/man.text similarity index 100% rename from conf/type/__package_pip/man.text rename to cdist/conf/type/__package_pip/man.text diff --git a/conf/type/__package_pip/parameter/optional b/cdist/conf/type/__package_pip/parameter/optional similarity index 100% rename from conf/type/__package_pip/parameter/optional rename to cdist/conf/type/__package_pip/parameter/optional diff --git a/conf/type/__package_pkg_freebsd/explorer/pkg_version b/cdist/conf/type/__package_pkg_freebsd/explorer/pkg_version similarity index 100% rename from conf/type/__package_pkg_freebsd/explorer/pkg_version rename to cdist/conf/type/__package_pkg_freebsd/explorer/pkg_version diff --git a/conf/type/__package_pkg_freebsd/gencode-remote b/cdist/conf/type/__package_pkg_freebsd/gencode-remote similarity index 100% rename from conf/type/__package_pkg_freebsd/gencode-remote rename to cdist/conf/type/__package_pkg_freebsd/gencode-remote diff --git a/conf/type/__package_pkg_freebsd/man.text b/cdist/conf/type/__package_pkg_freebsd/man.text similarity index 100% rename from conf/type/__package_pkg_freebsd/man.text rename to cdist/conf/type/__package_pkg_freebsd/man.text diff --git a/conf/type/__package_pkg_freebsd/parameter/optional b/cdist/conf/type/__package_pkg_freebsd/parameter/optional similarity index 100% rename from conf/type/__package_pkg_freebsd/parameter/optional rename to cdist/conf/type/__package_pkg_freebsd/parameter/optional diff --git a/conf/type/__package_pkg_openbsd/explorer/pkg_version b/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version similarity index 100% rename from conf/type/__package_pkg_openbsd/explorer/pkg_version rename to cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version diff --git a/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote similarity index 100% rename from conf/type/__package_pkg_openbsd/gencode-remote rename to cdist/conf/type/__package_pkg_openbsd/gencode-remote diff --git a/conf/type/__package_pkg_openbsd/man.text b/cdist/conf/type/__package_pkg_openbsd/man.text similarity index 100% rename from conf/type/__package_pkg_openbsd/man.text rename to cdist/conf/type/__package_pkg_openbsd/man.text diff --git a/conf/type/__package_pkg_openbsd/parameter/optional b/cdist/conf/type/__package_pkg_openbsd/parameter/optional similarity index 100% rename from conf/type/__package_pkg_openbsd/parameter/optional rename to cdist/conf/type/__package_pkg_openbsd/parameter/optional diff --git a/conf/type/__package_rubygem/explorer/pkg_status b/cdist/conf/type/__package_rubygem/explorer/pkg_status similarity index 100% rename from conf/type/__package_rubygem/explorer/pkg_status rename to cdist/conf/type/__package_rubygem/explorer/pkg_status diff --git a/conf/type/__package_rubygem/gencode-remote b/cdist/conf/type/__package_rubygem/gencode-remote similarity index 100% rename from conf/type/__package_rubygem/gencode-remote rename to cdist/conf/type/__package_rubygem/gencode-remote diff --git a/conf/type/__package_rubygem/man.text b/cdist/conf/type/__package_rubygem/man.text similarity index 100% rename from conf/type/__package_rubygem/man.text rename to cdist/conf/type/__package_rubygem/man.text diff --git a/conf/type/__package_rubygem/parameter/optional b/cdist/conf/type/__package_rubygem/parameter/optional similarity index 100% rename from conf/type/__package_rubygem/parameter/optional rename to cdist/conf/type/__package_rubygem/parameter/optional diff --git a/conf/type/__package_yum/explorer/pkg_version b/cdist/conf/type/__package_yum/explorer/pkg_version similarity index 100% rename from conf/type/__package_yum/explorer/pkg_version rename to cdist/conf/type/__package_yum/explorer/pkg_version diff --git a/conf/type/__package_yum/gencode-remote b/cdist/conf/type/__package_yum/gencode-remote similarity index 100% rename from conf/type/__package_yum/gencode-remote rename to cdist/conf/type/__package_yum/gencode-remote diff --git a/conf/type/__package_yum/man.text b/cdist/conf/type/__package_yum/man.text similarity index 100% rename from conf/type/__package_yum/man.text rename to cdist/conf/type/__package_yum/man.text diff --git a/conf/type/__package_yum/parameter/optional b/cdist/conf/type/__package_yum/parameter/optional similarity index 100% rename from conf/type/__package_yum/parameter/optional rename to cdist/conf/type/__package_yum/parameter/optional diff --git a/conf/type/__package_zypper/explorer/pkg_version b/cdist/conf/type/__package_zypper/explorer/pkg_version similarity index 100% rename from conf/type/__package_zypper/explorer/pkg_version rename to cdist/conf/type/__package_zypper/explorer/pkg_version diff --git a/conf/type/__package_zypper/gencode-remote b/cdist/conf/type/__package_zypper/gencode-remote similarity index 100% rename from conf/type/__package_zypper/gencode-remote rename to cdist/conf/type/__package_zypper/gencode-remote diff --git a/conf/type/__package_zypper/man.text b/cdist/conf/type/__package_zypper/man.text similarity index 100% rename from conf/type/__package_zypper/man.text rename to cdist/conf/type/__package_zypper/man.text diff --git a/conf/type/__package_zypper/parameter/optional b/cdist/conf/type/__package_zypper/parameter/optional similarity index 100% rename from conf/type/__package_zypper/parameter/optional rename to cdist/conf/type/__package_zypper/parameter/optional diff --git a/conf/type/__partition_msdos/install b/cdist/conf/type/__partition_msdos/install similarity index 100% rename from conf/type/__partition_msdos/install rename to cdist/conf/type/__partition_msdos/install diff --git a/conf/type/__partition_msdos/man.text b/cdist/conf/type/__partition_msdos/man.text similarity index 100% rename from conf/type/__partition_msdos/man.text rename to cdist/conf/type/__partition_msdos/man.text diff --git a/conf/type/__partition_msdos/manifest b/cdist/conf/type/__partition_msdos/manifest similarity index 100% rename from conf/type/__partition_msdos/manifest rename to cdist/conf/type/__partition_msdos/manifest diff --git a/conf/type/__partition_msdos/parameter/optional b/cdist/conf/type/__partition_msdos/parameter/optional similarity index 100% rename from conf/type/__partition_msdos/parameter/optional rename to cdist/conf/type/__partition_msdos/parameter/optional diff --git a/conf/type/__partition_msdos/parameter/required b/cdist/conf/type/__partition_msdos/parameter/required similarity index 100% rename from conf/type/__partition_msdos/parameter/required rename to cdist/conf/type/__partition_msdos/parameter/required diff --git a/conf/type/__partition_msdos_apply/explorer/partitions b/cdist/conf/type/__partition_msdos_apply/explorer/partitions similarity index 100% rename from conf/type/__partition_msdos_apply/explorer/partitions rename to cdist/conf/type/__partition_msdos_apply/explorer/partitions diff --git a/conf/type/__partition_msdos_apply/files/lib.sh b/cdist/conf/type/__partition_msdos_apply/files/lib.sh similarity index 100% rename from conf/type/__partition_msdos_apply/files/lib.sh rename to cdist/conf/type/__partition_msdos_apply/files/lib.sh diff --git a/conf/type/__partition_msdos_apply/gencode-remote b/cdist/conf/type/__partition_msdos_apply/gencode-remote similarity index 100% rename from conf/type/__partition_msdos_apply/gencode-remote rename to cdist/conf/type/__partition_msdos_apply/gencode-remote diff --git a/conf/type/__partition_msdos_apply/install b/cdist/conf/type/__partition_msdos_apply/install similarity index 100% rename from conf/type/__partition_msdos_apply/install rename to cdist/conf/type/__partition_msdos_apply/install diff --git a/conf/type/__partition_msdos_apply/man.text b/cdist/conf/type/__partition_msdos_apply/man.text similarity index 100% rename from conf/type/__partition_msdos_apply/man.text rename to cdist/conf/type/__partition_msdos_apply/man.text diff --git a/conf/type/__partition_msdos_apply/singleton b/cdist/conf/type/__partition_msdos_apply/singleton similarity index 100% rename from conf/type/__partition_msdos_apply/singleton rename to cdist/conf/type/__partition_msdos_apply/singleton diff --git a/conf/type/__pf_apply/explorer/rcvar b/cdist/conf/type/__pf_apply/explorer/rcvar similarity index 100% rename from conf/type/__pf_apply/explorer/rcvar rename to cdist/conf/type/__pf_apply/explorer/rcvar diff --git a/conf/type/__pf_apply/gencode-remote b/cdist/conf/type/__pf_apply/gencode-remote similarity index 100% rename from conf/type/__pf_apply/gencode-remote rename to cdist/conf/type/__pf_apply/gencode-remote diff --git a/conf/type/__pf_apply/man.text b/cdist/conf/type/__pf_apply/man.text similarity index 100% rename from conf/type/__pf_apply/man.text rename to cdist/conf/type/__pf_apply/man.text diff --git a/conf/type/__pf_apply/singleton b/cdist/conf/type/__pf_apply/singleton similarity index 100% rename from conf/type/__pf_apply/singleton rename to cdist/conf/type/__pf_apply/singleton diff --git a/conf/type/__pf_ruleset/explorer/cksum b/cdist/conf/type/__pf_ruleset/explorer/cksum similarity index 100% rename from conf/type/__pf_ruleset/explorer/cksum rename to cdist/conf/type/__pf_ruleset/explorer/cksum diff --git a/conf/type/__pf_ruleset/explorer/rcvar b/cdist/conf/type/__pf_ruleset/explorer/rcvar similarity index 100% rename from conf/type/__pf_ruleset/explorer/rcvar rename to cdist/conf/type/__pf_ruleset/explorer/rcvar diff --git a/conf/type/__pf_ruleset/gencode-local b/cdist/conf/type/__pf_ruleset/gencode-local similarity index 100% rename from conf/type/__pf_ruleset/gencode-local rename to cdist/conf/type/__pf_ruleset/gencode-local diff --git a/conf/type/__pf_ruleset/gencode-remote b/cdist/conf/type/__pf_ruleset/gencode-remote similarity index 100% rename from conf/type/__pf_ruleset/gencode-remote rename to cdist/conf/type/__pf_ruleset/gencode-remote diff --git a/conf/type/__pf_ruleset/man.text b/cdist/conf/type/__pf_ruleset/man.text similarity index 100% rename from conf/type/__pf_ruleset/man.text rename to cdist/conf/type/__pf_ruleset/man.text diff --git a/conf/type/__pf_ruleset/parameter/optional b/cdist/conf/type/__pf_ruleset/parameter/optional similarity index 100% rename from conf/type/__pf_ruleset/parameter/optional rename to cdist/conf/type/__pf_ruleset/parameter/optional diff --git a/conf/type/__pf_ruleset/parameter/required b/cdist/conf/type/__pf_ruleset/parameter/required similarity index 100% rename from conf/type/__pf_ruleset/parameter/required rename to cdist/conf/type/__pf_ruleset/parameter/required diff --git a/conf/type/__pf_ruleset/singleton b/cdist/conf/type/__pf_ruleset/singleton similarity index 100% rename from conf/type/__pf_ruleset/singleton rename to cdist/conf/type/__pf_ruleset/singleton diff --git a/conf/type/__postgres_database/explorer/state b/cdist/conf/type/__postgres_database/explorer/state similarity index 100% rename from conf/type/__postgres_database/explorer/state rename to cdist/conf/type/__postgres_database/explorer/state diff --git a/conf/type/__postgres_database/gencode-remote b/cdist/conf/type/__postgres_database/gencode-remote similarity index 100% rename from conf/type/__postgres_database/gencode-remote rename to cdist/conf/type/__postgres_database/gencode-remote diff --git a/conf/type/__postgres_database/man.text b/cdist/conf/type/__postgres_database/man.text similarity index 100% rename from conf/type/__postgres_database/man.text rename to cdist/conf/type/__postgres_database/man.text diff --git a/conf/type/__postgres_database/parameter/optional b/cdist/conf/type/__postgres_database/parameter/optional similarity index 100% rename from conf/type/__postgres_database/parameter/optional rename to cdist/conf/type/__postgres_database/parameter/optional diff --git a/conf/type/__postgres_database/parameter/required b/cdist/conf/type/__postgres_database/parameter/required similarity index 100% rename from conf/type/__postgres_database/parameter/required rename to cdist/conf/type/__postgres_database/parameter/required diff --git a/conf/type/__postgres_role/explorer/state b/cdist/conf/type/__postgres_role/explorer/state similarity index 100% rename from conf/type/__postgres_role/explorer/state rename to cdist/conf/type/__postgres_role/explorer/state diff --git a/conf/type/__postgres_role/gencode-remote b/cdist/conf/type/__postgres_role/gencode-remote similarity index 100% rename from conf/type/__postgres_role/gencode-remote rename to cdist/conf/type/__postgres_role/gencode-remote diff --git a/conf/type/__postgres_role/man.text b/cdist/conf/type/__postgres_role/man.text similarity index 100% rename from conf/type/__postgres_role/man.text rename to cdist/conf/type/__postgres_role/man.text diff --git a/conf/type/__postgres_role/parameter/optional b/cdist/conf/type/__postgres_role/parameter/optional similarity index 100% rename from conf/type/__postgres_role/parameter/optional rename to cdist/conf/type/__postgres_role/parameter/optional diff --git a/conf/type/__postgres_role/parameter/required b/cdist/conf/type/__postgres_role/parameter/required similarity index 100% rename from conf/type/__postgres_role/parameter/required rename to cdist/conf/type/__postgres_role/parameter/required diff --git a/conf/type/__process/explorer/runs b/cdist/conf/type/__process/explorer/runs similarity index 100% rename from conf/type/__process/explorer/runs rename to cdist/conf/type/__process/explorer/runs diff --git a/conf/type/__process/gencode-remote b/cdist/conf/type/__process/gencode-remote similarity index 100% rename from conf/type/__process/gencode-remote rename to cdist/conf/type/__process/gencode-remote diff --git a/conf/type/__process/man.text b/cdist/conf/type/__process/man.text similarity index 100% rename from conf/type/__process/man.text rename to cdist/conf/type/__process/man.text diff --git a/conf/type/__process/parameter/optional b/cdist/conf/type/__process/parameter/optional similarity index 100% rename from conf/type/__process/parameter/optional rename to cdist/conf/type/__process/parameter/optional diff --git a/conf/type/__process/parameter/required b/cdist/conf/type/__process/parameter/required similarity index 100% rename from conf/type/__process/parameter/required rename to cdist/conf/type/__process/parameter/required diff --git a/conf/type/__qemu_img/explorer/exists b/cdist/conf/type/__qemu_img/explorer/exists similarity index 100% rename from conf/type/__qemu_img/explorer/exists rename to cdist/conf/type/__qemu_img/explorer/exists diff --git a/conf/type/__qemu_img/gencode-remote b/cdist/conf/type/__qemu_img/gencode-remote similarity index 100% rename from conf/type/__qemu_img/gencode-remote rename to cdist/conf/type/__qemu_img/gencode-remote diff --git a/conf/type/__qemu_img/man.text b/cdist/conf/type/__qemu_img/man.text similarity index 100% rename from conf/type/__qemu_img/man.text rename to cdist/conf/type/__qemu_img/man.text diff --git a/conf/type/__qemu_img/manifest b/cdist/conf/type/__qemu_img/manifest similarity index 100% rename from conf/type/__qemu_img/manifest rename to cdist/conf/type/__qemu_img/manifest diff --git a/conf/type/__qemu_img/parameter/optional b/cdist/conf/type/__qemu_img/parameter/optional similarity index 100% rename from conf/type/__qemu_img/parameter/optional rename to cdist/conf/type/__qemu_img/parameter/optional diff --git a/conf/type/__qemu_img/parameter/required b/cdist/conf/type/__qemu_img/parameter/required similarity index 100% rename from conf/type/__qemu_img/parameter/required rename to cdist/conf/type/__qemu_img/parameter/required diff --git a/conf/type/__rvm/explorer/state b/cdist/conf/type/__rvm/explorer/state similarity index 100% rename from conf/type/__rvm/explorer/state rename to cdist/conf/type/__rvm/explorer/state diff --git a/conf/type/__rvm/gencode-remote b/cdist/conf/type/__rvm/gencode-remote similarity index 100% rename from conf/type/__rvm/gencode-remote rename to cdist/conf/type/__rvm/gencode-remote diff --git a/conf/type/__rvm/man.text b/cdist/conf/type/__rvm/man.text similarity index 100% rename from conf/type/__rvm/man.text rename to cdist/conf/type/__rvm/man.text diff --git a/conf/type/__rvm/manifest b/cdist/conf/type/__rvm/manifest similarity index 100% rename from conf/type/__rvm/manifest rename to cdist/conf/type/__rvm/manifest diff --git a/conf/type/__rvm/parameter/required b/cdist/conf/type/__rvm/parameter/required similarity index 100% rename from conf/type/__rvm/parameter/required rename to cdist/conf/type/__rvm/parameter/required diff --git a/conf/type/__rvm_gem/explorer/state b/cdist/conf/type/__rvm_gem/explorer/state similarity index 100% rename from conf/type/__rvm_gem/explorer/state rename to cdist/conf/type/__rvm_gem/explorer/state diff --git a/conf/type/__rvm_gem/gencode-remote b/cdist/conf/type/__rvm_gem/gencode-remote similarity index 100% rename from conf/type/__rvm_gem/gencode-remote rename to cdist/conf/type/__rvm_gem/gencode-remote diff --git a/conf/type/__rvm_gem/man.text b/cdist/conf/type/__rvm_gem/man.text similarity index 100% rename from conf/type/__rvm_gem/man.text rename to cdist/conf/type/__rvm_gem/man.text diff --git a/conf/type/__rvm_gem/manifest b/cdist/conf/type/__rvm_gem/manifest similarity index 100% rename from conf/type/__rvm_gem/manifest rename to cdist/conf/type/__rvm_gem/manifest diff --git a/conf/type/__rvm_gem/parameter/optional b/cdist/conf/type/__rvm_gem/parameter/optional similarity index 100% rename from conf/type/__rvm_gem/parameter/optional rename to cdist/conf/type/__rvm_gem/parameter/optional diff --git a/conf/type/__rvm_gem/parameter/required b/cdist/conf/type/__rvm_gem/parameter/required similarity index 100% rename from conf/type/__rvm_gem/parameter/required rename to cdist/conf/type/__rvm_gem/parameter/required diff --git a/conf/type/__rvm_gemset/explorer/state b/cdist/conf/type/__rvm_gemset/explorer/state similarity index 100% rename from conf/type/__rvm_gemset/explorer/state rename to cdist/conf/type/__rvm_gemset/explorer/state diff --git a/conf/type/__rvm_gemset/gencode-remote b/cdist/conf/type/__rvm_gemset/gencode-remote similarity index 100% rename from conf/type/__rvm_gemset/gencode-remote rename to cdist/conf/type/__rvm_gemset/gencode-remote diff --git a/conf/type/__rvm_gemset/man.text b/cdist/conf/type/__rvm_gemset/man.text similarity index 100% rename from conf/type/__rvm_gemset/man.text rename to cdist/conf/type/__rvm_gemset/man.text diff --git a/conf/type/__rvm_gemset/manifest b/cdist/conf/type/__rvm_gemset/manifest similarity index 100% rename from conf/type/__rvm_gemset/manifest rename to cdist/conf/type/__rvm_gemset/manifest diff --git a/conf/type/__rvm_gemset/parameter/optional b/cdist/conf/type/__rvm_gemset/parameter/optional similarity index 100% rename from conf/type/__rvm_gemset/parameter/optional rename to cdist/conf/type/__rvm_gemset/parameter/optional diff --git a/conf/type/__rvm_gemset/parameter/required b/cdist/conf/type/__rvm_gemset/parameter/required similarity index 100% rename from conf/type/__rvm_gemset/parameter/required rename to cdist/conf/type/__rvm_gemset/parameter/required diff --git a/conf/type/__rvm_ruby/explorer/state b/cdist/conf/type/__rvm_ruby/explorer/state similarity index 100% rename from conf/type/__rvm_ruby/explorer/state rename to cdist/conf/type/__rvm_ruby/explorer/state diff --git a/conf/type/__rvm_ruby/gencode-remote b/cdist/conf/type/__rvm_ruby/gencode-remote similarity index 100% rename from conf/type/__rvm_ruby/gencode-remote rename to cdist/conf/type/__rvm_ruby/gencode-remote diff --git a/conf/type/__rvm_ruby/man.text b/cdist/conf/type/__rvm_ruby/man.text similarity index 100% rename from conf/type/__rvm_ruby/man.text rename to cdist/conf/type/__rvm_ruby/man.text diff --git a/conf/type/__rvm_ruby/manifest b/cdist/conf/type/__rvm_ruby/manifest similarity index 100% rename from conf/type/__rvm_ruby/manifest rename to cdist/conf/type/__rvm_ruby/manifest diff --git a/conf/type/__rvm_ruby/parameter/optional b/cdist/conf/type/__rvm_ruby/parameter/optional similarity index 100% rename from conf/type/__rvm_ruby/parameter/optional rename to cdist/conf/type/__rvm_ruby/parameter/optional diff --git a/conf/type/__rvm_ruby/parameter/required b/cdist/conf/type/__rvm_ruby/parameter/required similarity index 100% rename from conf/type/__rvm_ruby/parameter/required rename to cdist/conf/type/__rvm_ruby/parameter/required diff --git a/conf/type/__ssh_authorized_key/explorer/dstuser_group b/cdist/conf/type/__ssh_authorized_key/explorer/dstuser_group similarity index 100% rename from conf/type/__ssh_authorized_key/explorer/dstuser_group rename to cdist/conf/type/__ssh_authorized_key/explorer/dstuser_group diff --git a/conf/type/__ssh_authorized_key/man.text b/cdist/conf/type/__ssh_authorized_key/man.text similarity index 100% rename from conf/type/__ssh_authorized_key/man.text rename to cdist/conf/type/__ssh_authorized_key/man.text diff --git a/conf/type/__ssh_authorized_key/manifest b/cdist/conf/type/__ssh_authorized_key/manifest similarity index 100% rename from conf/type/__ssh_authorized_key/manifest rename to cdist/conf/type/__ssh_authorized_key/manifest diff --git a/conf/type/__ssh_authorized_key/parameter/optional b/cdist/conf/type/__ssh_authorized_key/parameter/optional similarity index 100% rename from conf/type/__ssh_authorized_key/parameter/optional rename to cdist/conf/type/__ssh_authorized_key/parameter/optional diff --git a/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state similarity index 100% rename from conf/type/__start_on_boot/explorer/state rename to cdist/conf/type/__start_on_boot/explorer/state diff --git a/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote similarity index 100% rename from conf/type/__start_on_boot/gencode-remote rename to cdist/conf/type/__start_on_boot/gencode-remote diff --git a/conf/type/__start_on_boot/man.text b/cdist/conf/type/__start_on_boot/man.text similarity index 100% rename from conf/type/__start_on_boot/man.text rename to cdist/conf/type/__start_on_boot/man.text diff --git a/conf/type/__start_on_boot/parameter/optional b/cdist/conf/type/__start_on_boot/parameter/optional similarity index 100% rename from conf/type/__start_on_boot/parameter/optional rename to cdist/conf/type/__start_on_boot/parameter/optional diff --git a/conf/type/__timezone/man.text b/cdist/conf/type/__timezone/man.text similarity index 100% rename from conf/type/__timezone/man.text rename to cdist/conf/type/__timezone/man.text diff --git a/conf/type/__timezone/manifest b/cdist/conf/type/__timezone/manifest similarity index 100% rename from conf/type/__timezone/manifest rename to cdist/conf/type/__timezone/manifest diff --git a/conf/type/__user/TODO b/cdist/conf/type/__user/TODO similarity index 100% rename from conf/type/__user/TODO rename to cdist/conf/type/__user/TODO diff --git a/conf/type/__user/explorer/group b/cdist/conf/type/__user/explorer/group similarity index 100% rename from conf/type/__user/explorer/group rename to cdist/conf/type/__user/explorer/group diff --git a/conf/type/__user/explorer/passwd b/cdist/conf/type/__user/explorer/passwd similarity index 100% rename from conf/type/__user/explorer/passwd rename to cdist/conf/type/__user/explorer/passwd diff --git a/conf/type/__user/explorer/shadow b/cdist/conf/type/__user/explorer/shadow similarity index 100% rename from conf/type/__user/explorer/shadow rename to cdist/conf/type/__user/explorer/shadow diff --git a/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote similarity index 100% rename from conf/type/__user/gencode-remote rename to cdist/conf/type/__user/gencode-remote diff --git a/conf/type/__user/man.text b/cdist/conf/type/__user/man.text similarity index 100% rename from conf/type/__user/man.text rename to cdist/conf/type/__user/man.text diff --git a/conf/type/__user/parameter/optional b/cdist/conf/type/__user/parameter/optional similarity index 100% rename from conf/type/__user/parameter/optional rename to cdist/conf/type/__user/parameter/optional diff --git a/cdist/test/emulator/fixtures/conf/type/__file b/cdist/test/emulator/fixtures/conf/type/__file index 8458361c..1ed684b9 120000 --- a/cdist/test/emulator/fixtures/conf/type/__file +++ b/cdist/test/emulator/fixtures/conf/type/__file @@ -1 +1 @@ -../../../../../../conf/type/__file \ No newline at end of file +../../../../../conf/type/__file \ No newline at end of file diff --git a/setup.py b/setup.py index 19fb28e6..d5dac616 100644 --- a/setup.py +++ b/setup.py @@ -11,14 +11,18 @@ def data_finder(data_dir): for name in os.listdir(data_dir): entry = os.path.join(data_dir, name) if os.path.isdir(entry): + entries.append(entry) entries.extend(data_finder(entry)) else: entries.append(entry) return entries +cur = os.getcwd() +os.chdir("cdist") package_data = data_finder("conf") - + # package_dir={'cdist': 'src/mypkg'}, +os.chdir(cur) print(package_data) From 8202cd0e7ad78c2df4969635932752d9752e0896 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 29 Oct 2012 22:56:29 +0100 Subject: [PATCH 1698/4212] remove some debug, remove adding dirs Signed-off-by: Nico Schottelius --- setup.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/setup.py b/setup.py index d5dac616..5b5e2a47 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,5 @@ from distutils.core import setup - -#data_files=[('/usr/share/cdist', 'conf')], - # data_files=[('/tmp/cdist', ['conf'])], import cdist - import os def data_finder(data_dir): @@ -11,7 +7,6 @@ def data_finder(data_dir): for name in os.listdir(data_dir): entry = os.path.join(data_dir, name) if os.path.isdir(entry): - entries.append(entry) entries.extend(data_finder(entry)) else: entries.append(entry) @@ -21,11 +16,8 @@ def data_finder(data_dir): cur = os.getcwd() os.chdir("cdist") package_data = data_finder("conf") - # package_dir={'cdist': 'src/mypkg'}, os.chdir(cur) -print(package_data) - setup( name = "cdist", packages = ["cdist", "cdist.core", "cdist.exec", "cdist.util" ], From 6c4480abfa138bbc99d59da6a3e3838c1a9c98cf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 29 Oct 2012 23:25:28 +0100 Subject: [PATCH 1699/4212] ++changes(2.1.0pre3) Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index dba70701..93d71ba2 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius +2.1.0pre3: 2012-10-29 + * Dist: PyPi: Types and explorer included as package data + 2.1.0pre2: 2012-10-26 * Dist: PyPi: Add conf/ directory to distribution * Dist: Initial support for archlinux packaging From cbb34de1b2bd1ebb0b7f11cac3933f40d00effc3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 29 Oct 2012 23:28:27 +0100 Subject: [PATCH 1700/4212] explorers are now below cdist/ Signed-off-by: Nico Schottelius --- 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 cf1b852f..8e3f49a2 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -49,7 +49,7 @@ The following global explorers are available: eof ( - cd ../../conf/explorer + cd ../../cdist/conf/explorer for explorer in *; do echo "- $explorer" done From e0bdcea78b1a59424e22de1ccf7ea8ec24b22f8b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 07:33:07 +0100 Subject: [PATCH 1701/4212] adjust type linking script Signed-off-by: Nico Schottelius --- build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build b/build index d295da14..a4550f67 100755 --- a/build +++ b/build @@ -78,8 +78,8 @@ case "$1" in ;; mantype) - for mansrc in conf/type/*/man.text; do - dst="$(echo $mansrc | sed -e 's;conf/;cdist-;' -e 's;/;;' -e 's;/man;;' -e 's;^;docs/man/man7/;')" + 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 ;; From 80e42c133ddb93edae8f6da303294a960f9d7b3a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 07:37:19 +0100 Subject: [PATCH 1702/4212] this is pre3, not pre2 Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 93d71ba2..118d9bfe 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,7 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius -2.1.0pre3: 2012-10-29 +2.1.0pre3: 2012-10-30 * Dist: PyPi: Types and explorer included as package data 2.1.0pre2: 2012-10-26 From a81525b101929bc334bb1414c431bd5c1cb92bed Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 07:41:42 +0100 Subject: [PATCH 1703/4212] add some thoughts on changes for multiple directory search for types and explorers Signed-off-by: Nico Schottelius --- docs/dev/logs/2012-10-29.installed_paths | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/dev/logs/2012-10-29.installed_paths diff --git a/docs/dev/logs/2012-10-29.installed_paths b/docs/dev/logs/2012-10-29.installed_paths new file mode 100644 index 00000000..f6824274 --- /dev/null +++ b/docs/dev/logs/2012-10-29.installed_paths @@ -0,0 +1,32 @@ + +Installed paths: (read first) + os.path.dirname(cdist.__file__) + + /conf/explorer + /conf/type + +User paths: (read after, overwrite)? + + $HOME/.cdist + + /explorer + /type + + /manifest + +Additional paths: + + CDIST_EXPLORER_EXTRA_PATH=... + CDIST_TYPE_EXTRA_PATH=... + + or + + -c dir -c dir2 -c ... => + add types and explorer from those directories + last one wins? + because they can only be appended to existing "$PATH" + +Open questions: + + - How to tell types to use global explorer? + - How to tell types to find other types? From 10b6c31ac8d14cec11e615827981ac0f49de8258 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 11:47:16 +0100 Subject: [PATCH 1704/4212] Rename cdist.py to scripts/cdist to avoid self import naming cdist cdist.py and running import cdist, imports itself and thus raises an interesting error: (virtualenv)[7:47] brief:virtualenv% cdist.py Traceback (most recent call last): File "", line 1512, in _find_and_load_unlocked AttributeError: 'module' object has no attribute '__path__' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/users/nico/oeffentlich/rechner/projekte/cdist/virtualenv/bin/cdist.py", line 230, in commandline() File "/home/users/nico/oeffentlich/rechner/projekte/cdist/virtualenv/bin/cdist.py", line 27, in commandline import cdist.banner ImportError: No module named 'cdist.banner'; cdist is not a package During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/users/nico/oeffentlich/rechner/projekte/cdist/virtualenv/bin/cdist.py", line 235, in except cdist.Error as e: AttributeError: 'module' object has no attribute 'Error' Also described on http://www.velocityreviews.com/forums/t953596-error-executing-import-html-parser-from-a-script.html Signed-off-by: Nico Schottelius --- bin/cdist | 5 ++++- cdist.py => scripts/cdist | 0 2 files changed, 4 insertions(+), 1 deletion(-) rename cdist.py => scripts/cdist (100%) diff --git a/bin/cdist b/bin/cdist index 5c1239fb..5a6ce92f 100755 --- a/bin/cdist +++ b/bin/cdist @@ -22,5 +22,8 @@ # Wrapper for real script to allow execution from checkout 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/../cdist.py" "$@" +PYTHONPATH="${dir}/../" "$dir/../scripts/cdist" "$@" diff --git a/cdist.py b/scripts/cdist similarity index 100% rename from cdist.py rename to scripts/cdist From c4274e789fe0d7349acf6307d15c0a15c01b5e2e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 11:51:27 +0100 Subject: [PATCH 1705/4212] include cdist from the scripts/ directory for shipping Signed-off-by: Nico Schottelius --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5b5e2a47..25fc4820 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ setup( name = "cdist", packages = ["cdist", "cdist.core", "cdist.exec", "cdist.util" ], package_data={'cdist': package_data}, - scripts = ["cdist.py"], + scripts = ["scripts/cdist"], version = cdist.version.VERSION, description = "A Usable Configuration Management System", author = "Nico Schottelius", From 01eef6b242cd87a608855fdd975bbd40e5ae220c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 14:53:53 +0100 Subject: [PATCH 1706/4212] ++changes(2.1.0pre4) Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 118d9bfe..242e0c2f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius +2.1.0pre4: + * Dist: PyPi: Move cdist.py to script/cdist to avoid double import + 2.1.0pre3: 2012-10-30 * Dist: PyPi: Types and explorer included as package data From 6ece8a97c71c5c0a946e515603015837562c68ac Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 14:54:05 +0100 Subject: [PATCH 1707/4212] use obsolete lib path Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index e510a8fb..9947ac64 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 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -20,8 +20,6 @@ # # -# FIXME: common base class with Remote? - import io import os import sys @@ -49,8 +47,6 @@ class Local(object): self.global_explorer_path = os.path.join(self.conf_path, "explorer") self.manifest_path = os.path.join(self.conf_path, "manifest") self.type_path = os.path.join(self.conf_path, "type") - # FIXME: should not be needed anywhere - self.lib_path = os.path.join(self.base_path, "lib") # Local output self.out_path = out_path From f09378eed05cd4b4c15b424dbdb751baa652ee8d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 14:57:49 +0100 Subject: [PATCH 1708/4212] path implementation done (in theory) Signed-off-by: Nico Schottelius --- ...0-30.path-for-types-and-global-explorer-implementation | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs/dev/logs/2012-10-30.path-for-types-and-global-explorer-implementation diff --git a/docs/dev/logs/2012-10-30.path-for-types-and-global-explorer-implementation b/docs/dev/logs/2012-10-30.path-for-types-and-global-explorer-implementation new file mode 100644 index 00000000..8a683a40 --- /dev/null +++ b/docs/dev/logs/2012-10-30.path-for-types-and-global-explorer-implementation @@ -0,0 +1,8 @@ +- Allow list of base directories, which may contain explorer/ or type/ subdirectories + - can use the existing -c parameter, only allow it to be specified multiple times +- for each directory, link the given explorer and types to a temporary conf/ directory + similar to bin/ +- last one wins strategy + - what is expected by the user + + From 18c0c937dd417900ae48c4e43df1e6ee4010e836 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 14:58:03 +0100 Subject: [PATCH 1709/4212] also add cache to user dir Signed-off-by: Nico Schottelius --- docs/dev/logs/2012-10-29.installed_paths | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/dev/logs/2012-10-29.installed_paths b/docs/dev/logs/2012-10-29.installed_paths index f6824274..3587390e 100644 --- a/docs/dev/logs/2012-10-29.installed_paths +++ b/docs/dev/logs/2012-10-29.installed_paths @@ -14,6 +14,8 @@ User paths: (read after, overwrite)? /manifest + /cache + Additional paths: CDIST_EXPLORER_EXTRA_PATH=... From 813651c14b87d30b5f2c028ac7d21d43efb67bb2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 15:59:02 +0100 Subject: [PATCH 1710/4212] allow passing conf_dir instead of cdist-home Signed-off-by: Nico Schottelius --- scripts/cdist | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index 2066db55..d5ea06d0 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -56,9 +56,9 @@ def commandline(): parser['configinstall'] = argparse.ArgumentParser(add_help=False) parser['configinstall'].add_argument('host', nargs='+', help='one or more hosts to operate on') - parser['configinstall'].add_argument('-c', '--cdist-home', - help='Change cdist home (default: .. from bin directory)', - action='store') + parser['configinstall'].add_argument('-c', '--conf-dir', + help='Add configuration directory (can be repeated, last one wins)', + action='append') parser['configinstall'].add_argument('-i', '--initial-manifest', help='Path to a cdist manifest or \'-\' to read from stdin.', dest='manifest', required=False) @@ -172,7 +172,7 @@ def configinstall_onehost(host, args, mode, parallel): remote_copy=args.remote_copy, remote_exec=args.remote_exec, initial_manifest=args.manifest, - base_path=args.cdist_home, + conf_dirs=args.conf_dir, exec_path=sys.argv[0], debug=args.debug) From b0e8c23078acd1f8ba73e3aa23c0bb24a5ec843a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 15:59:21 +0100 Subject: [PATCH 1711/4212] initial change to support multiple conf_dirs Signed-off-by: Nico Schottelius --- cdist/context.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/cdist/context.py b/cdist/context.py index 8b468739..64a8086e 100644 --- a/cdist/context.py +++ b/cdist/context.py @@ -38,26 +38,18 @@ class Context(object): remote_copy, remote_exec, initial_manifest=False, - base_path=False, + conf_dirs=[], exec_path=sys.argv[0], debug=False): - self.debug = debug - + self.debug = debug self.target_host = target_host - - # Only required for testing self.exec_path = exec_path # Context logging self.log = logging.getLogger(self.target_host) self.log.addFilter(self) - # Local base directory - self.base_path = (base_path or - os.path.abspath(os.path.join(os.path.dirname(__file__), - os.pardir, os.pardir))) - # 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: @@ -67,7 +59,7 @@ 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.base_path, self.out_path) + self.local = local.Local(self.target_host, self.conf_dirs, self.out_path) self.initial_manifest = (initial_manifest or os.path.join(self.local.manifest_path, "init")) From 1e264afa6343ffbab5c61d7d4b379d1454f8aee8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 16:05:37 +0100 Subject: [PATCH 1712/4212] refactor code to allow multiple directories to be passed in Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 107 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 18 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 9947ac64..4d94789b 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -37,32 +37,67 @@ class Local(object): Directly accessing the local side from python code is a bug. """ - def __init__(self, target_host, local_base_path, out_path): - self.target_host = target_host - self.base_path = local_base_path + def __init__(self, target_host, conf_dirs, out_path, cache_dir): - # Local input - self.cache_path = os.path.join(self.base_path, "cache") - self.conf_path = os.path.join(self.base_path, "conf") + self.target_host = target_host + self.add_conf_dirs = conf_dirs + self.out_path = out_path + + self._init_log() + self._init_permissions() + self._init_home_dir() + self._init_paths() + self._init_cache_dir() + self._init_conf_dirs() + + def _init_home_dir(self): + if 'HOME' in os.environ: + self.home_dir = os.environ['HOME'] + else: + self.home_dir = None + + def _init_log(self): + self.log = logging.getLogger(self.target_host) + + def _init_permissions(self): + # Setup file permissions using umask + os.umask(0o077) + + 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") + + # 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.type_path = os.path.join(self.conf_path, "type") - # Local output - self.out_path = out_path - self.bin_path = os.path.join(self.out_path, "bin") - self.global_explorer_out_path = os.path.join(self.out_path, "explorer") - self.object_path = os.path.join(self.out_path, "object") + def _init_conf_dirs(self): + self.conf_dirs = [] - self.log = logging.getLogger(self.target_host) + # Comes with the distribution + system_conf_dir = os.path.join(os.path.dirname(cdist.__file__), "conf") + self.conf_dirs.append(system_conf_dir) - # Setup file permissions using umask - os.umask(0o077) + # Is the default place for user created explorer, type and manifest + if self.home_dir: + user_conf_dir = os.path.join(self.home_dir, ".cdist") + self.conf_dirs.append(user_conf_dir) - def create_directories(self): - self.mkdir(self.out_path) - self.mkdir(self.global_explorer_out_path) - self.mkdir(self.bin_path) + # Add user supplied directories + self.conf_dirs.extend(self.add_conf_dirs) + + def _init_cache_dir(self, cache_dir): + if cache_dir: + self.cache_path = cache_dir + else: + if self.home_dir: + self.cache_path = os.path.join(self.home_dir, "cache") + else: + raise cdist.Error("No homedir setup and no cache dir location given") def rmdir(self, path): """Remove directory on the local side.""" @@ -107,6 +142,42 @@ class Local(object): return self.run(command, env, return_output) + def create_context_files_dirs(self): + self._create_context_dirs() + self._create_conf_path_and_link_conf_dirs() + + 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) + + def _create_conf_path_and_link_conf_dirs(self): + self.mkdir(self.conf_path) + + # Link destination directories + for sub_dir in [ "explorer", "manifest", "type" ]: + self.mkdir(os.path.join(self.conf_path, sub_dir)) + + # Iterate over all directories and link the to the output dir + for conf_dir in self.conf_dirs: + for sub_dir in [ "explorer", "manifest", "type" ]: + current_dir = os.path.join(conf_dir, sub_dir) + + for entry in os.listdir(current_dir): + rel_entry_path = os.path.join(sub_dir, entry) + src = os.path.join(self.conf_path, entry) + dst = os.path.join(conf_dir, sub_dir, entry) + + # Already exists? remove and link + if os.path.exists(dst): + os.ulink(dst) + + try: + os.symlink(src, dst) + except OSError as e: + raise cdist.Error("Linking %s %s to %s failed: %s" % (sub_dir, src, dst, e.__str__())) + def link_emulator(self, exec_path): """Link emulator to types""" src = os.path.abspath(exec_path) From cbe95b18e650b1fc1b6fe28059590ae94a437d6e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 16:06:27 +0100 Subject: [PATCH 1713/4212] rename function to reveal new task: create_files_dirs Signed-off-by: Nico Schottelius --- cdist/config_install.py | 4 ++-- cdist/exec/local.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 3aadca86..280f186c 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -48,7 +48,7 @@ class ConfigInstall(object): self.remote = context.remote # Initialise local directory structure - self.local.create_directories() + self.local.create_files_dirs() # Initialise remote directory structure self.remote.create_directories() diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 4d94789b..bb90ab6c 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -142,7 +142,7 @@ class Local(object): return self.run(command, env, return_output) - def create_context_files_dirs(self): + def create_files_dirs(self): self._create_context_dirs() self._create_conf_path_and_link_conf_dirs() From dcaa70e6be1487942adc687e54473bca8119d4a1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 16:07:00 +0100 Subject: [PATCH 1714/4212] be consistent in remote Signed-off-by: Nico Schottelius --- cdist/config_install.py | 2 +- cdist/exec/remote.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 280f186c..b7804a10 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -50,7 +50,7 @@ class ConfigInstall(object): # Initialise local directory structure self.local.create_files_dirs() # Initialise remote directory structure - self.remote.create_directories() + self.remote.create_files_dirs() self.explorer = core.Explorer(self.context.target_host, self.local, self.remote) self.manifest = core.Manifest(self.context.target_host, self.local) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 487beea3..07c6614b 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -57,7 +57,7 @@ class Remote(object): self.log = logging.getLogger(self.target_host) - def create_directories(self): + def create_files_dirs(self): self.rmdir(self.base_path) self.mkdir(self.base_path) self.mkdir(self.conf_path) From e41aae041a64d378be522a97456a1df93e9d3782 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 16:11:03 +0100 Subject: [PATCH 1715/4212] fix cache_dir syntax error Signed-off-by: Nico Schottelius --- cdist/context.py | 2 +- cdist/exec/local.py | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cdist/context.py b/cdist/context.py index 64a8086e..5fec530f 100644 --- a/cdist/context.py +++ b/cdist/context.py @@ -59,7 +59,7 @@ 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.conf_dirs, self.out_path) + self.local = local.Local(self.target_host, conf_dirs, self.out_path) self.initial_manifest = (initial_manifest or os.path.join(self.local.manifest_path, "init")) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index bb90ab6c..a5e838cb 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -37,7 +37,7 @@ class Local(object): Directly accessing the local side from python code is a bug. """ - def __init__(self, target_host, conf_dirs, out_path, cache_dir): + def __init__(self, target_host, conf_dirs, out_path, cache_dir=None): self.target_host = target_host self.add_conf_dirs = conf_dirs @@ -47,7 +47,7 @@ class Local(object): self._init_permissions() self._init_home_dir() self._init_paths() - self._init_cache_dir() + self._init_cache_dir(cache_dir) self._init_conf_dirs() def _init_home_dir(self): @@ -88,7 +88,8 @@ class Local(object): self.conf_dirs.append(user_conf_dir) # Add user supplied directories - self.conf_dirs.extend(self.add_conf_dirs) + if self.add_conf_dirs: + self.conf_dirs.extend(self.add_conf_dirs) def _init_cache_dir(self, cache_dir): if cache_dir: @@ -166,12 +167,12 @@ class Local(object): for entry in os.listdir(current_dir): rel_entry_path = os.path.join(sub_dir, entry) - src = os.path.join(self.conf_path, entry) - dst = os.path.join(conf_dir, sub_dir, entry) + src = os.path.join(conf_dir, sub_dir, entry) + dst = os.path.join(self.conf_path, entry) # Already exists? remove and link if os.path.exists(dst): - os.ulink(dst) + os.unlink(dst) try: os.symlink(src, dst) From 92d21a46251f00f37cc6855f4f8efa05c154c0b1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 16:14:02 +0100 Subject: [PATCH 1716/4212] remove init.sample from this place in the distribution Signed-off-by: Nico Schottelius --- cdist/conf/manifest/init.sample | 69 --------------------------------- 1 file changed, 69 deletions(-) delete mode 100755 cdist/conf/manifest/init.sample diff --git a/cdist/conf/manifest/init.sample b/cdist/conf/manifest/init.sample deleted file mode 100755 index fca959e2..00000000 --- a/cdist/conf/manifest/init.sample +++ /dev/null @@ -1,69 +0,0 @@ -# -# This is a sample manifest, but used in real world -# - -# This is debug and should not be in a production environment -# echo "We could access other manifests in $__manifest" - -# Every machine becomes a marker, so sysadmins know that automatic -# configurations are happening -__file /etc/cdist-configured - -case "$__target_host" in - # Everybody has this - localhost) - require="__file/etc/cdist-configured" __link /tmp/cdist-testfile \ - --source /etc/cdist-configured --type symbolic - require="__directory/tmp/cdist-test-dir" __file /tmp/cdist-test-dir/test-file \ - --mode 0750 --owner nobody --group root - __directory /tmp/cdist-test-dir --mode 4777 - - require="__file/etc/cdist-configured __link/tmp/cdist-testfile" \ - __file /tmp/cdist-another-testfile - - ;; - - # - # Examples using different types - # - - # - # Use an alias in /etc/hosts for localhost to use these hosts: - # - # 127.0.0.1 localhost.localdomain localhost cdist-archlinux - # - cdist-archlinux) - # This is the specific package type for pacman - __package_pacman zsh --state installed - - # The __package type autoselect the right type based on the os - __package vim --state installed - - # If the type is a singleton, it does not take an object id - __issue - ;; - # This is how it would look like on gentoo - cdist-gentoo) - # Same stuff for gentoo - __package tree --state installed - ;; - - cdist-debian) - __package_apt atop --state installed - __package apache2 --state removed - ;; - - cdist-redhat) - __issue - __motd - ;; - - # Real machines may be used with their hostname or fqdn, - # depending on how you call cdist-deploy-to - # machine) - # ... - # ;; - # machine.example.org) - # ... - # ;; -esac From e7be0cceab502fb77628230af0d3131b17edbc06 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 16:16:59 +0100 Subject: [PATCH 1717/4212] big change for pre4 Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 9 +++++++-- docs/changelog | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index a5e838cb..785d5ff2 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -165,15 +165,20 @@ class Local(object): for sub_dir in [ "explorer", "manifest", "type" ]: current_dir = os.path.join(conf_dir, sub_dir) + # Allow conf dirs to contain only partial content + if not os.path.exists(current_dir): + continue + 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) - dst = os.path.join(self.conf_path, entry) + dst = os.path.join(self.conf_path, sub_dir, entry) # Already exists? remove and link if os.path.exists(dst): os.unlink(dst) - + + self.log.debug("Linking %s to %s ..." % (src, dst)) try: os.symlink(src, dst) except OSError as e: diff --git a/docs/changelog b/docs/changelog index 242e0c2f..4b77af7a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 2.1.0pre4: * Dist: PyPi: Move cdist.py to script/cdist to avoid double import + * Added internal support for multiple configuration directories 2.1.0pre3: 2012-10-30 * Dist: PyPi: Types and explorer included as package data From c25c986992338e0b32de91098619cc8fc74954ec Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 16:33:18 +0100 Subject: [PATCH 1718/4212] re-add sample, but longer name Signed-off-by: Nico Schottelius --- cdist/conf/manifest/sample-from-distribution | 62 ++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100755 cdist/conf/manifest/sample-from-distribution diff --git a/cdist/conf/manifest/sample-from-distribution b/cdist/conf/manifest/sample-from-distribution new file mode 100755 index 00000000..56d52cf5 --- /dev/null +++ b/cdist/conf/manifest/sample-from-distribution @@ -0,0 +1,62 @@ +## # +## # Sample manifest from cdist distribution +## # +## +## # Every machine becomes a marker, so sysadmins know that automatic +## # configurations are happening +## __file /etc/cdist-configured +## __cdistmarker +## +## case "$__target_host" in +## # Everybody has this +## localhost) +## require="__file/etc/cdist-configured" __link /tmp/cdist-testfile \ +## --source /etc/cdist-configured --type symbolic +## require="__directory/tmp/cdist-test-dir" __file /tmp/cdist-test-dir/test-file \ +## --mode 0750 --owner nobody --group root +## __directory /tmp/cdist-test-dir --mode 4777 +## +## require="__file/etc/cdist-configured __link/tmp/cdist-testfile" \ +## __file /tmp/cdist-another-testfile +## +## ;; +## +## # +## # Use an alias in /etc/hosts for localhost to use these hosts: +## # +## # 127.0.0.1 localhost.localdomain localhost cdist-archlinux +## # +## cdist-archlinux) +## # This is the specific package type for pacman +## __package_pacman zsh --state installed +## +## # The __package type autoselect the right type based on the os +## __package vim --state installed +## +## # If the type is a singleton, it does not take an object id +## __issue +## ;; +## # This is how it would look like on gentoo +## cdist-gentoo) +## # Same stuff for gentoo +## __package tree --state installed +## ;; +## +## cdist-debian) +## __package_apt atop --state installed +## __package apache2 --state removed +## ;; +## +## cdist-redhat) +## __issue +## __motd +## ;; +## +## # Real machines may be used with their hostname or fqdn, +## # depending on how you call cdist +## # ... +## # ;; +## # machine.example.org) +## # ... +## # ;; +## esac From 1d1149deab6a48be34a49384b9afc79e42106af8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 16:36:32 +0100 Subject: [PATCH 1719/4212] +debug Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 785d5ff2..d0ff1765 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -162,6 +162,7 @@ class Local(object): # Iterate over all directories and link the to the output dir for conf_dir in self.conf_dirs: + self.log.debug("Checking conf_dir %s ..." % (conf_dir)) for sub_dir in [ "explorer", "manifest", "type" ]: current_dir = os.path.join(conf_dir, sub_dir) From 9ca0d4efe73bfe01b20585f5444ab18d38921f6d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Oct 2012 16:37:02 +0100 Subject: [PATCH 1720/4212] clarify changes for 2.1.0pre4 Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 4b77af7a..bc330818 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,7 +7,7 @@ Changelog 2.1.0pre4: * Dist: PyPi: Move cdist.py to script/cdist to avoid double import - * Added internal support for multiple configuration directories + * Added support for multiple configuration directories (no documentation) 2.1.0pre3: 2012-10-30 * Dist: PyPi: Types and explorer included as package data From 6af14263e3f1ddefc45cd0ea64e50617910f5c32 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 31 Oct 2012 08:12:01 +0100 Subject: [PATCH 1721/4212] past Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index bc330818..7eecab93 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,7 +6,7 @@ Changelog 2.1.0pre4: - * Dist: PyPi: Move cdist.py to script/cdist to avoid double import + * Dist: PyPi: Moved cdist.py to script/cdist to avoid double import * Added support for multiple configuration directories (no documentation) 2.1.0pre3: 2012-10-30 From dafc6c601757b8f2a4d7aa1211bddfb5e0f7cdd6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 31 Oct 2012 08:15:09 +0100 Subject: [PATCH 1722/4212] update changelog date Signed-off-by: Nico Schottelius --- docs/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index 7eecab93..d76f65bb 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,9 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius -2.1.0pre4: +2.1.0pre4: 2012-10-31 * Dist: PyPi: Moved cdist.py to script/cdist to avoid double import - * Added support for multiple configuration directories (no documentation) + * Core: Added support for multiple configuration directories (no documentation) 2.1.0pre3: 2012-10-30 * Dist: PyPi: Types and explorer included as package data From 2b22bfc0db25f262a4a369c82a4987c469443c87 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 31 Oct 2012 08:15:23 +0100 Subject: [PATCH 1723/4212] ignore freecode tempory script used to submit a release Signed-off-by: Nico Schottelius --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6e2d4437..b5f69ec7 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ cdist/version.py /cdist-*.tar.gz /pkg /src +freecode-release From f8b20d58546efddf77d1e4b78a46000958ab9fdb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 31 Oct 2012 08:18:02 +0100 Subject: [PATCH 1724/4212] skip unecessary merge in dist process Signed-off-by: Nico Schottelius --- build | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/build b/build index a4550f67..0af286f8 100755 --- a/build +++ b/build @@ -168,12 +168,16 @@ notes target_branch=${version%\.*} current_branch=$(git rev-parse --abbrev-ref HEAD) - 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" - ;; + 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 + ;; dist-archlinux) ./PKGBUILD.in From 59dd52d55528659956c074d308209d1ffbc83a9d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 31 Oct 2012 08:42:24 +0100 Subject: [PATCH 1725/4212] include uploading to aur in dist process Signed-off-by: Nico Schottelius --- build | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/build b/build index 0af286f8..158e3ef8 100755 --- a/build +++ b/build @@ -180,10 +180,21 @@ notes ;; dist-archlinux) + $0 dist-archlinux-makepkg + $0 dist-archlinux-aur-upload + ;; + + dist-archlinux-makepkg) ./PKGBUILD.in - makepkg -c makepkg -c --source ;; + + dist-archlinux-aur-upload) + version=$($0 changelog-version) + tar=cdist-${version}-1.src.tar.gz + burp -c system "$tar" + ;; + dist-pypi) $0 man $0 version From 876eebe1c7d620f467674c66d69b499bcbe6bdec Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 31 Oct 2012 08:52:40 +0100 Subject: [PATCH 1726/4212] begin to include automatic freecode submissions using cfreecode-api Signed-off-by: Nico Schottelius --- build | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/build b/build index 158e3ef8..e5f252e7 100755 --- a/build +++ b/build @@ -195,6 +195,39 @@ notes burp -c system "$tar" ;; + dist-freecode) + version=$($0 changelog-version) + api_token=$(awk '/machine freecode login/ { print $8 }' ~/.netrc) + + printf "Enter tag list for freecode release %s> " "$version" + read taglist + + printf "Enter changelog for freecode release %s> " "$version" + read changelog + + echo "Submit preview" + cat << eof +tag_list = $taglist +changelog = $changelog +version = $version +eof + printf "Press enter to submit to freecode> " + read dummy + + cat << eof | cfreecode-api cdist + { + "auth_code": "$api_token", + "release": { + "tag_list": "REPLACEME", + "version": "$version", + "changelog": "REPLACEMETOO", + "hidden_from_frontpage": false + } + } +eof + + ;; + dist-pypi) $0 man $0 version From 440c209248026fe3fc1a9078cd15de79c9a70816 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 31 Oct 2012 08:53:17 +0100 Subject: [PATCH 1727/4212] no need to ignore the file anymore as being piped now Signed-off-by: Nico Schottelius --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index b5f69ec7..6e2d4437 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,3 @@ cdist/version.py /cdist-*.tar.gz /pkg /src -freecode-release From 8f5d1f910f5fb08c79a8b174fcb19755f76408fc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 31 Oct 2012 09:35:08 +0100 Subject: [PATCH 1728/4212] fix asciidoc title issues (made box out of it) Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-remote-exec-copy.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/man/man7/cdist-remote-exec-copy.text b/docs/man/man7/cdist-remote-exec-copy.text index d789b12d..298891d6 100644 --- a/docs/man/man7/cdist-remote-exec-copy.text +++ b/docs/man/man7/cdist-remote-exec-copy.text @@ -31,7 +31,7 @@ remains as simple as possible. EXAMPLES --------------- +-------- See cdist/other/examples/remote/ for some example implementations. From c836a60a7e6697dfa587b71abcd19ad646b905f3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 31 Oct 2012 09:40:28 +0100 Subject: [PATCH 1729/4212] correct call to cfreecode-api Signed-off-by: Nico Schottelius --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index e5f252e7..9d7284d7 100755 --- a/build +++ b/build @@ -214,7 +214,7 @@ eof printf "Press enter to submit to freecode> " read dummy - cat << eof | cfreecode-api cdist + cat << eof | cfreecode-api release cdist { "auth_code": "$api_token", "release": { From 3a97ab910abe9a4a068c01a7345ef0dfe639de8f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 10:45:39 +0100 Subject: [PATCH 1730/4212] begin to split off readme Signed-off-by: Nico Schottelius --- README | 355 +------------------------------------------- docs/web/cdist.mdwn | 353 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 357 insertions(+), 351 deletions(-) create mode 100644 docs/web/cdist.mdwn diff --git a/README b/README index ffd0bcb5..a67e25e3 100644 --- a/README +++ b/README @@ -1,353 +1,6 @@ -[[!meta title="cdist - usable configuration management"]] +cdist +----- - - .. . .x+=:. s - dF @88> z` ^% :8 - '88bu. %8P . = 2.0.4)](man) - -### OS support - -cdist was tested or is know to run on at least - - * [Archlinux](http://www.archlinux.org/) - * [Debian](http://www.debian.org/) - * [CentOS](http://www.centos.org/) - * [Fedora](http://fedoraproject.org/) - * [Gentoo](http://www.gentoo.org/) - * [Mac OS X](http://www.apple.com/macosx/) - * [OpenBSD](http://www.openbsd.org) - * [Redhat](http://www.redhat.com/) - * [Ubuntu](http://www.ubuntu.com/) - * [XenServer](http://www.citrix.com/xenserver/) - - -## Requirements - -### Server - - * A posix like shell - * Python (>= 3.2 required) - * SSH client - * Asciidoc (for building the manpages) - -### Client ("target host") - - * A posix like shell - * SSH server - - -## Installation - -### Preparation - -Ensure you have Python 3.2 installed on the machine you use to **deploy to the targets** -(the ***source host***). - -#### Archlinux - -Archlinux already has python >= 3.2, so you only need to do: - - pacman -S python - -#### CentOS - -See the "From source" section - -#### Debian - -For Debian >= wheezy: - - aptitude install python3 - -On squeeze you can add following line in **/etc/apt/sources.list** - - deb http://ftp.debian.org/debian wheezy main - -And add pinning entry in **/etc/apt/preferences.d/wheezy**: - - Package: * - Pin: release n=wheezy - Pin-Priority: 1 - -Please be aware that both **openssh-server** and **openssh-client** might be -removed on **python3.2** installation. You surely want to reinstall them: - - apt-get install -t wheezy openssh-server openssh-client - -For older Debian versions, installing python 3.2 manually is required. - - -#### Fedora - -For Fedora >= 15: - - yum install python3 - -#### FreeBSD - -For the port: - - cd /usr/ports/lang/python32/ && make install clean - -For the package: - - pkg_add -r python32 - -#### Gentoo - -Gentoo only provides python 3.2 in testing packages (http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=3&chap=3). -If you want to ensure nothing breaks you must set back the python version to what was default before. - - emerge -av =python-3.2.2 --autounmask-write - emerge -av =python-3.2.2 - eselect python list - eselect python list set python3.2 - -#### Max OS X - -You can choose between Homebrew and Macports, either way works: - -[Homebrew](http://mxcl.github.com/homebrew/) variant: - - brew install python3 - -[Macports](http://www.macports.org/install.php) variant: - - port install python32 - ln -s /opt/local/bin/python3.2 /opt/local/bin/python3 - -#### From Source - -For those operating systems not yet support Python 3.2: - - pyversion=3.2.3 - wget http://www.python.org/ftp/python/$pyversion/Python-${pyversion}.tar.bz2 - tar xvfj Python-${pyversion}.tar.bz2 - cd Python-${pyversion} - ./configure - make - sudo make install - -This installs python 3.2 to /usr/local/bin. Ensure this directory is in -your PATH environment variable. - - -### Get cdist - -You can clone cdist from git, which gives you the advantage of having -a version control in place for development of your own stuff as well. -To install cdist, execute the following commands: - - git clone git://git.schottelius.org/cdist - cd cdist - export PATH=$PATH:$(pwd -P)/bin - - # If you want the manpages - ./build man - export MANPATH=$MANPATH:$(pwd -P)/doc/man - - -### Available versions - -There are at least the following branches available: - - * Development: master - * 2.0: Python rewrite of cdist core [stable branch] - -Old versions: - - * 1.7: Bugfixes, cleanups, new type and explorer rename - * 1.6: New types, cleaned up \_\_package* types, internal cleanup - * 1.5: Focus on object orientation instead of global stage orientation - * 1.4: Support for redefiniton of objects (if equal) - * 1.3: Support for local and remote code execution (current stable) - * 1.2: Dependencies supported - * 1.1: \_\_file to \_\_file, \_\_directory, \_\_link migration - * 1.0: First official release - -Other branches may be available for features or bugfixes, but they -may vanish at any point. To select a specific branch use - - # Generic code - git checkout -b origin/ - - # Stay on a specific version - version=2.0 - git checkout -b $version origin/$version - -### Mirrors - - * git://github.com/telmich/cdist.git ([github](https://github.com/telmich/cdist)) - * git://git.code.sf.net/p/cdist/code ([sourceforge](https://sourceforge.net/p/cdist/code)) - -## Update - -To upgrade cdist in the current branch use - - git pull - - # Also update the manpages - ./build man - export MANPATH=$MANPATH:$(pwd -P)/doc/man - -If you stay on a version branche (i.e. 1.0, 1.1., ...), nothing should break. -The master branch on the other hand is the development branch and may not be -working, break your setup or eat the tree in your garden. - -### Upgrading from 1.7 to 2.0 - -* Ensure python (>= 3.2) is installed on the server -* Use "cdist config host" instead of "cdist-deploy-to host" -* Use "cdist config -p host1 host2" instead of "cdist-mass-deploy" -* Use "cdist banner" for fun -* Use **\_\_object_fq** instead of **\_\_self** in manifests - -### Upgrading from 1.6 to 1.7 - -* If you used the global explorer **hardware_type**, you need to change - your code to use **machine** instead. - -### Upgrading from 1.5 to 1.6 - -* If you used **\_\_package_apt --preseed**, you need to use the new - type **\_\_debconf_set_selections** instead. -* The **\_\_package** types accepted either --state deinstalled or - --state uninstaaled. Starting with 1.6, it was made consistently - to --state removed. - -### Upgrading from 1.3 to 1.5 - -No incompatiblities. - -### Upgrading from 1.2 to 1.3 - -Rename **gencode** of every type to **gencode-remote**. - -### Upgrading from 1.1 to 1.2 - -No incompatiblities. - -### Upgrading from 1.0 to 1.1 - -In 1.1 the type **\_\_file** was split into **\_\_directory**, **\_\_file** and -**\_\_link**. The parameter **--type** was removed from **\_\_file**. Thus you -need to replace **\_\_file** calls in your manifests: - - * Remove --type from all \_\_file calls - * If type was symlink, use \_\_link and --type symbolic - * If type was directory, use \_\_directory - - -## Support - -### IRC - -You can join the development ***IRC channel*** -[#cstar on irc.freenode.net](irc://irc.freenode.org/#cstar). - -### Mailing list - -Bug reports, questions, patches, etc. should be send to the -[cdist mailing list](http://l.schottelius.org/mailman/listinfo/cdist). - -### Linkedin - -If you have an account -at [Linked in](http://www.linkedin.com/), -you can join the -[cdist group](http://www.linkedin.com/groups/cdist-configuration-management-3952797). - -### Commercial support - -You can request commercial support for cdist from -[my company](http://firma.schottelius.org/english/). - -## Used by - -If you're using cdist, feel free to send a report to the mailing list. -Interesting information are for instance - - * Which services do you manage? - * How many machines do you manage? - * What are the pros/cons you see in cdist? - * General comments/critics - -### Nico Schottelius, Systems Group ETH Zurich, local.ch and privately - -Yes, I'm actually eating my own dogfood and currently managing - - * [plone](http://plone.org/) (cms) - * [moinmoin](http://moinmo.in/) (wiki) - * [apache](http://httpd.apache.org/) (webserver) - * [kerberos (mit)](http://web.mit.edu/kerberos/) (authentication) - * [nss-pam-ldapd](http://arthurdejong.org/nss-pam-ldapd/) (authentication) - * [ircd-hybrid](http://www.ircd-hybrid.org/) (chat) - * [stunnel](http://stunnel.mirt.net/) (SSL tunnel) - * [mercurial-server](http://www.lshift.net/mercurial-server.html) (version control) - * [xfce](http://www.xfce.org/) (lightweight desktop environment) - * [slim](http://slim.berlios.de/) (graphical login manager for X11) - -with cdist on more than **60** production machines of the -[Systems Group](http://www.systems.ethz.ch) at the -[ETH Zurich](http://www.ethz.ch) as well at home. - -### Steven Armstrong, CBRG ETH Zurich - -The CBRG is managing most of their compute clusters with cdist. - -[[!tag cdist unix]] +For the web documentation have a look at docs/web/. diff --git a/docs/web/cdist.mdwn b/docs/web/cdist.mdwn new file mode 100644 index 00000000..ffd0bcb5 --- /dev/null +++ b/docs/web/cdist.mdwn @@ -0,0 +1,353 @@ +[[!meta title="cdist - usable configuration management"]] + + + .. . .x+=:. s + dF @88> z` ^% :8 + '88bu. %8P . = 2.0.4)](man) + +### OS support + +cdist was tested or is know to run on at least + + * [Archlinux](http://www.archlinux.org/) + * [Debian](http://www.debian.org/) + * [CentOS](http://www.centos.org/) + * [Fedora](http://fedoraproject.org/) + * [Gentoo](http://www.gentoo.org/) + * [Mac OS X](http://www.apple.com/macosx/) + * [OpenBSD](http://www.openbsd.org) + * [Redhat](http://www.redhat.com/) + * [Ubuntu](http://www.ubuntu.com/) + * [XenServer](http://www.citrix.com/xenserver/) + + +## Requirements + +### Server + + * A posix like shell + * Python (>= 3.2 required) + * SSH client + * Asciidoc (for building the manpages) + +### Client ("target host") + + * A posix like shell + * SSH server + + +## Installation + +### Preparation + +Ensure you have Python 3.2 installed on the machine you use to **deploy to the targets** +(the ***source host***). + +#### Archlinux + +Archlinux already has python >= 3.2, so you only need to do: + + pacman -S python + +#### CentOS + +See the "From source" section + +#### Debian + +For Debian >= wheezy: + + aptitude install python3 + +On squeeze you can add following line in **/etc/apt/sources.list** + + deb http://ftp.debian.org/debian wheezy main + +And add pinning entry in **/etc/apt/preferences.d/wheezy**: + + Package: * + Pin: release n=wheezy + Pin-Priority: 1 + +Please be aware that both **openssh-server** and **openssh-client** might be +removed on **python3.2** installation. You surely want to reinstall them: + + apt-get install -t wheezy openssh-server openssh-client + +For older Debian versions, installing python 3.2 manually is required. + + +#### Fedora + +For Fedora >= 15: + + yum install python3 + +#### FreeBSD + +For the port: + + cd /usr/ports/lang/python32/ && make install clean + +For the package: + + pkg_add -r python32 + +#### Gentoo + +Gentoo only provides python 3.2 in testing packages (http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=3&chap=3). +If you want to ensure nothing breaks you must set back the python version to what was default before. + + emerge -av =python-3.2.2 --autounmask-write + emerge -av =python-3.2.2 + eselect python list + eselect python list set python3.2 + +#### Max OS X + +You can choose between Homebrew and Macports, either way works: + +[Homebrew](http://mxcl.github.com/homebrew/) variant: + + brew install python3 + +[Macports](http://www.macports.org/install.php) variant: + + port install python32 + ln -s /opt/local/bin/python3.2 /opt/local/bin/python3 + +#### From Source + +For those operating systems not yet support Python 3.2: + + pyversion=3.2.3 + wget http://www.python.org/ftp/python/$pyversion/Python-${pyversion}.tar.bz2 + tar xvfj Python-${pyversion}.tar.bz2 + cd Python-${pyversion} + ./configure + make + sudo make install + +This installs python 3.2 to /usr/local/bin. Ensure this directory is in +your PATH environment variable. + + +### Get cdist + +You can clone cdist from git, which gives you the advantage of having +a version control in place for development of your own stuff as well. +To install cdist, execute the following commands: + + git clone git://git.schottelius.org/cdist + cd cdist + export PATH=$PATH:$(pwd -P)/bin + + # If you want the manpages + ./build man + export MANPATH=$MANPATH:$(pwd -P)/doc/man + + +### Available versions + +There are at least the following branches available: + + * Development: master + * 2.0: Python rewrite of cdist core [stable branch] + +Old versions: + + * 1.7: Bugfixes, cleanups, new type and explorer rename + * 1.6: New types, cleaned up \_\_package* types, internal cleanup + * 1.5: Focus on object orientation instead of global stage orientation + * 1.4: Support for redefiniton of objects (if equal) + * 1.3: Support for local and remote code execution (current stable) + * 1.2: Dependencies supported + * 1.1: \_\_file to \_\_file, \_\_directory, \_\_link migration + * 1.0: First official release + +Other branches may be available for features or bugfixes, but they +may vanish at any point. To select a specific branch use + + # Generic code + git checkout -b origin/ + + # Stay on a specific version + version=2.0 + git checkout -b $version origin/$version + +### Mirrors + + * git://github.com/telmich/cdist.git ([github](https://github.com/telmich/cdist)) + * git://git.code.sf.net/p/cdist/code ([sourceforge](https://sourceforge.net/p/cdist/code)) + +## Update + +To upgrade cdist in the current branch use + + git pull + + # Also update the manpages + ./build man + export MANPATH=$MANPATH:$(pwd -P)/doc/man + +If you stay on a version branche (i.e. 1.0, 1.1., ...), nothing should break. +The master branch on the other hand is the development branch and may not be +working, break your setup or eat the tree in your garden. + +### Upgrading from 1.7 to 2.0 + +* Ensure python (>= 3.2) is installed on the server +* Use "cdist config host" instead of "cdist-deploy-to host" +* Use "cdist config -p host1 host2" instead of "cdist-mass-deploy" +* Use "cdist banner" for fun +* Use **\_\_object_fq** instead of **\_\_self** in manifests + +### Upgrading from 1.6 to 1.7 + +* If you used the global explorer **hardware_type**, you need to change + your code to use **machine** instead. + +### Upgrading from 1.5 to 1.6 + +* If you used **\_\_package_apt --preseed**, you need to use the new + type **\_\_debconf_set_selections** instead. +* The **\_\_package** types accepted either --state deinstalled or + --state uninstaaled. Starting with 1.6, it was made consistently + to --state removed. + +### Upgrading from 1.3 to 1.5 + +No incompatiblities. + +### Upgrading from 1.2 to 1.3 + +Rename **gencode** of every type to **gencode-remote**. + +### Upgrading from 1.1 to 1.2 + +No incompatiblities. + +### Upgrading from 1.0 to 1.1 + +In 1.1 the type **\_\_file** was split into **\_\_directory**, **\_\_file** and +**\_\_link**. The parameter **--type** was removed from **\_\_file**. Thus you +need to replace **\_\_file** calls in your manifests: + + * Remove --type from all \_\_file calls + * If type was symlink, use \_\_link and --type symbolic + * If type was directory, use \_\_directory + + +## Support + +### IRC + +You can join the development ***IRC channel*** +[#cstar on irc.freenode.net](irc://irc.freenode.org/#cstar). + +### Mailing list + +Bug reports, questions, patches, etc. should be send to the +[cdist mailing list](http://l.schottelius.org/mailman/listinfo/cdist). + +### Linkedin + +If you have an account +at [Linked in](http://www.linkedin.com/), +you can join the +[cdist group](http://www.linkedin.com/groups/cdist-configuration-management-3952797). + +### Commercial support + +You can request commercial support for cdist from +[my company](http://firma.schottelius.org/english/). + +## Used by + +If you're using cdist, feel free to send a report to the mailing list. +Interesting information are for instance + + * Which services do you manage? + * How many machines do you manage? + * What are the pros/cons you see in cdist? + * General comments/critics + +### Nico Schottelius, Systems Group ETH Zurich, local.ch and privately + +Yes, I'm actually eating my own dogfood and currently managing + + * [plone](http://plone.org/) (cms) + * [moinmoin](http://moinmo.in/) (wiki) + * [apache](http://httpd.apache.org/) (webserver) + * [kerberos (mit)](http://web.mit.edu/kerberos/) (authentication) + * [nss-pam-ldapd](http://arthurdejong.org/nss-pam-ldapd/) (authentication) + * [ircd-hybrid](http://www.ircd-hybrid.org/) (chat) + * [stunnel](http://stunnel.mirt.net/) (SSL tunnel) + * [mercurial-server](http://www.lshift.net/mercurial-server.html) (version control) + * [xfce](http://www.xfce.org/) (lightweight desktop environment) + * [slim](http://slim.berlios.de/) (graphical login manager for X11) + +with cdist on more than **60** production machines of the +[Systems Group](http://www.systems.ethz.ch) at the +[ETH Zurich](http://www.ethz.ch) as well at home. + +### Steven Armstrong, CBRG ETH Zurich + +The CBRG is managing most of their compute clusters with cdist. + +[[!tag cdist unix]] From 081d3aea37ab23fad42bc64d83e9ac23cb64ae60 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 11:09:45 +0100 Subject: [PATCH 1731/4212] remove manifests, which are not needed anymore (in production without them for some months) Signed-off-by: Nico Schottelius --- cdist/conf/type/__rvm_gem/manifest | 38 ------------ cdist/conf/type/__rvm_gemset/manifest | 36 ------------ cdist/conf/type/__rvm_ruby/manifest | 83 --------------------------- 3 files changed, 157 deletions(-) delete mode 100755 cdist/conf/type/__rvm_gem/manifest delete mode 100755 cdist/conf/type/__rvm_gemset/manifest delete mode 100755 cdist/conf/type/__rvm_ruby/manifest diff --git a/cdist/conf/type/__rvm_gem/manifest b/cdist/conf/type/__rvm_gem/manifest deleted file mode 100755 index a551472d..00000000 --- a/cdist/conf/type/__rvm_gem/manifest +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# -# 2012 Evax Software -# -# 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 . -# - -gem="$__object_id" -gemset="$(cat "$__object/parameter/gemset")" -ruby="$(echo "$gemset" | cut -d '@' -f 1)" -gemsetname="$(echo "$gemset" | cut -d '@' -f 2)" -user="$(cat "$__object/parameter/user")" -state="$(cat "$__object/explorer/state")" -if [ -f "$__object/parameter/default" ]; then - default="$(cat "$__object/parameter/default")" -else - default="no" - echo $default > "$__object/parameter/default" -fi - -__rvm "$user" --state present -require="__rvm/$user" \ - __rvm_ruby $ruby --user "$user" --state present --default $default -require="__rvm_ruby/$ruby" \ - __rvm_gemset $gemset --user "$user" --state present --default $default diff --git a/cdist/conf/type/__rvm_gemset/manifest b/cdist/conf/type/__rvm_gemset/manifest deleted file mode 100755 index b69395ea..00000000 --- a/cdist/conf/type/__rvm_gemset/manifest +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -# -# 2012 Evax Software -# -# 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 . -# - -gemset="$__object_id" -ruby="$(echo "$gemset" | cut -d '@' -f 1)" -gemsetname="$(echo "$gemset" | cut -d '@' -f 2)" -user="$(cat "$__object/parameter/user")" -state="$(cat "$__object/explorer/state")" -if [ -f "$__object/parameter/default" ]; then - default="$(cat "$__object/parameter/default")" -else - default="no" - echo $default > "$__object/parameter/default" -fi - -__rvm "$user" --state present -require="__rvm/$user" \ - __rvm_ruby $ruby --user "$user" --state present --default $default - diff --git a/cdist/conf/type/__rvm_ruby/manifest b/cdist/conf/type/__rvm_ruby/manifest deleted file mode 100755 index 581e98a8..00000000 --- a/cdist/conf/type/__rvm_ruby/manifest +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/sh -# -# 2012 Evax Software -# -# 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/default" ]; then - default="$(cat "$__object/parameter/default")" -else - default="no" - echo "$default" > "$__object/parameter/default" -fi - -ruby="$__object_id" -user="$(cat "$__object/parameter/user")" -state="$(cat "$__object/explorer/state")" - -apt_ruby="build-essential openssl libreadline6 libreadline6-dev curl git-core -zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 -libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison -subversion" -apt_jruby="curl g++ openjdk-6-jre-headless" -apt_jruby_head="ant openjdk-6-jdk" -apt_ironruby="curl mono-2.0-devel" - -emerge_ruby="libiconv readline zlib openssl curl git libyaml sqlite libxslt -libtool gcc autoconf automake bison m4" -emerge_jruby="dev-java/sun-jdk dev-java/sun-jre-bin" -emerge_ironruby="dev-lang/mono" - -pacman_ruby="gcc patch curl zlib readline libxml2 libxslt git autoconf -diffutils make libtool bison subversion" -pacman_jruby="jdk jre curl" -pacman_ironruby="mono" - -yum_ruby="gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel -libffi-devel openssl-devel make bzip2 autoconf automake libtool bison -iconv-devel" -yum_jruby="java" - -os="$(cat "$__global/explorer/os")" -case "$os" in - archlinux) type="pacman" ;; - debian|ubuntu) type="apt" ;; - gentoo) type="emerge" ;; - fedora|redhat|centos) type="yum" ;; - *);; -esac -case "$ruby" in - ruby-head*) - deps_list="${type}_ruby_head" - ;; - ruby*) - deps_list="${type}_ruby" - ;; - jruby-head*) - deps_list="${type}_jruby_head" - ;; - jruby*) - deps_list="${type}_jruby" - ;; - ironruby*) - deps_list="${type}_ironruby" - ;; -esac -deps=$(eval echo \$$deps_list) -for p in $deps; do __package_${type} $p --state present; done - -__rvm "$user" --state present From 6771a13758820813af402e47f5c4ace4be854d65 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 13:30:45 +0100 Subject: [PATCH 1732/4212] pass exec_path from context to local, making it obsolete to manually add the argument to the _link_types_for_emulator Signed-off-by: Nico Schottelius --- cdist/config_install.py | 1 - cdist/context.py | 2 +- cdist/exec/local.py | 15 +++++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index b7804a10..2c1edc44 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -79,7 +79,6 @@ class ConfigInstall(object): def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" - self.local.link_emulator(self.context.exec_path) self.explorer.run_global_explorers(self.local.global_explorer_out_path) self.manifest.run_initial_manifest(self.context.initial_manifest) diff --git a/cdist/context.py b/cdist/context.py index 5fec530f..d3e30dec 100644 --- a/cdist/context.py +++ b/cdist/context.py @@ -59,7 +59,7 @@ 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, conf_dirs, self.out_path) + self.local = local.Local(self.target_host, conf_dirs, self.out_path, self.exec_path) self.initial_manifest = (initial_manifest or os.path.join(self.local.manifest_path, "init")) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index d0ff1765..d75917f5 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -37,11 +37,13 @@ class Local(object): Directly accessing the local side from python code is a bug. """ - def __init__(self, target_host, conf_dirs, out_path, cache_dir=None): + def __init__(self, target_host, conf_dirs, out_path, exec_path, cache_dir=None): self.target_host = target_host - self.add_conf_dirs = conf_dirs self.out_path = out_path + self.exec_path = exec_path + + self._add_conf_dirs = conf_dirs self._init_log() self._init_permissions() @@ -88,8 +90,8 @@ class Local(object): self.conf_dirs.append(user_conf_dir) # Add user supplied directories - if self.add_conf_dirs: - self.conf_dirs.extend(self.add_conf_dirs) + if self._add_conf_dirs: + self.conf_dirs.extend(self._add_conf_dirs) def _init_cache_dir(self, cache_dir): if cache_dir: @@ -146,6 +148,7 @@ class Local(object): def create_files_dirs(self): self._create_context_dirs() self._create_conf_path_and_link_conf_dirs() + self._link_types_for_emulator() def _create_context_dirs(self): self.mkdir(self.out_path) @@ -185,9 +188,9 @@ class Local(object): except OSError as e: raise cdist.Error("Linking %s %s to %s failed: %s" % (sub_dir, src, dst, e.__str__())) - def link_emulator(self, exec_path): + def _link_types_for_emulator(self): """Link emulator to types""" - src = os.path.abspath(exec_path) + src = os.path.abspath(self.exec_path) for cdist_type in core.CdistType.list_types(self.type_path): dst = os.path.join(self.bin_path, cdist_type.name) self.log.debug("Linking emulator: %s to %s", src, dst) From 4946fe26541a91b815bc553344adf82b970d0786 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 13:34:48 +0100 Subject: [PATCH 1733/4212] adjust paths in test --- cdist/test/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/test/__init__.py b/cdist/test/__init__.py index faa9dc2d..f8e71287 100644 --- a/cdist/test/__init__.py +++ b/cdist/test/__init__.py @@ -24,9 +24,9 @@ import unittest import tempfile cdist_base_path = os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../")) + os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../../")) -cdist_exec_path = os.path.join(cdist_base_path, "bin/cdist") +cdist_exec_path = os.path.join(cdist_base_path, "scripts/cdist") class CdistTestCase(unittest.TestCase): From 32a94a0f89e0ba8002ff0135e66e425d4fd93c96 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 13:35:52 +0100 Subject: [PATCH 1734/4212] adjust emulator test to pass exec_path to local Signed-off-by: Nico Schottelius --- cdist/test/emulator/__init__.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index ff18fe87..679fd149 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -45,8 +45,8 @@ class EmulatorTestCase(test.CdistTestCase): os.close(handle) self.target_host = 'localhost' out_path = self.temp_dir - self.local = local.Local(self.target_host, local_base_path, out_path) - self.local.create_directories() + self.local = local.Local(self.target_host, local_base_path, out_path, test.cdist_exec_path) + self.local.create_files_dirs() self.env = { 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), '__target_host': self.target_host, @@ -113,9 +113,8 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): self.target_host = 'localhost' out_path = self.temp_dir _local_base_path = fixtures - self.local = local.Local(self.target_host, _local_base_path, out_path) - self.local.create_directories() - self.local.link_emulator(cdist.test.cdist_exec_path) + self.local = local.Local(self.target_host, _local_base_path, out_path, test.cdist_exec_path) + self.local.create_files_dirs() self.manifest = core.Manifest(self.target_host, self.local) def tearDown(self): @@ -140,9 +139,8 @@ class ArgumentsTestCase(test.CdistTestCase): handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) _local_base_path = fixtures - self.local = local.Local(self.target_host, _local_base_path, out_path) - self.local.create_directories() - self.local.link_emulator(test.cdist_exec_path) + self.local = local.Local(self.target_host, _local_base_path, out_path, test.cdist_exec_path) + self.local.create_files_dirs() self.env = { 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), '__target_host': self.target_host, From 6eddaaf09057b26157c27fe3ef3f1606b89d7ef5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 13:46:01 +0100 Subject: [PATCH 1735/4212] rename parameter correctly to add_conf_dirs 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 d75917f5..2406c8d5 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -37,13 +37,13 @@ class Local(object): Directly accessing the local side from python code is a bug. """ - def __init__(self, target_host, conf_dirs, out_path, exec_path, cache_dir=None): + def __init__(self, target_host, out_path, exec_path, add_conf_dirs=[], cache_dir=None): self.target_host = target_host self.out_path = out_path self.exec_path = exec_path - self._add_conf_dirs = conf_dirs + self._add_conf_dirs = add_conf_dirs self._init_log() self._init_permissions() From d944f2ac19985dd76c8bdca0b3be34536a5db51a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 14:13:52 +0100 Subject: [PATCH 1736/4212] add pythonpath for testing --- build | 1 + 1 file changed, 1 insertion(+) diff --git a/build b/build index 9d7284d7..57dc275b 100755 --- a/build +++ b/build @@ -302,6 +302,7 @@ eof test) shift # skip t + export PYTHONPATH="$(pwd -P)" if [ $# -lt 1 ]; then python3 -m cdist.test From 6ecfb28d9346830c8c643b0b36aac3597cfacb7a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 14:14:52 +0100 Subject: [PATCH 1737/4212] name parameter correctly add_conf_dirs Signed-off-by: Nico Schottelius --- cdist/context.py | 4 ++-- scripts/cdist | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/context.py b/cdist/context.py index d3e30dec..92e683a3 100644 --- a/cdist/context.py +++ b/cdist/context.py @@ -38,7 +38,7 @@ class Context(object): remote_copy, remote_exec, initial_manifest=False, - conf_dirs=[], + add_conf_dirs=[], exec_path=sys.argv[0], debug=False): @@ -59,7 +59,7 @@ 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, conf_dirs, self.out_path, self.exec_path) + self.local = local.Local(self.target_host, self.out_path, self.exec_path, add_conf_dirs=add_conf_dirs) self.initial_manifest = (initial_manifest or os.path.join(self.local.manifest_path, "init")) diff --git a/scripts/cdist b/scripts/cdist index d5ea06d0..00ebbf18 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -172,7 +172,7 @@ def configinstall_onehost(host, args, mode, parallel): remote_copy=args.remote_copy, remote_exec=args.remote_exec, initial_manifest=args.manifest, - conf_dirs=args.conf_dir, + add_conf_dirs=args.conf_dir, exec_path=sys.argv[0], debug=args.debug) From 1177286d4e678547bc1df228e4e97008fe12551f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 14:42:55 +0100 Subject: [PATCH 1738/4212] cleanups of tests (especially exec.local) Signed-off-by: Nico Schottelius --- cdist/test/exec/local.py | 29 +++++++++++++++-------------- cdist/test/manifest/__init__.py | 3 +-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cdist/test/exec/local.py b/cdist/test/exec/local.py index e6f2c2b0..ebfc64af 100644 --- a/cdist/test/exec/local.py +++ b/cdist/test/exec/local.py @@ -1,6 +1,7 @@ # -*- 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. # @@ -25,9 +26,6 @@ import shutil import string import random -#import logging -#logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s') - import cdist from cdist import test from cdist.exec import local @@ -35,17 +33,22 @@ from cdist.exec import local import os.path as op my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') -local_base_path = fixtures - class LocalTestCase(test.CdistTestCase): def setUp(self): - self.temp_dir = self.mkdtemp() + target_host = 'localhost' + self.temp_dir = self.mkdtemp() self.out_path = self.temp_dir - self.base_path = local_base_path - self.local = local.Local(target_host, self.base_path, self.out_path) + + self.local = local.Local( + target_host=target_host, + out_path=self.out_path, + exec_path=test.cdist_exec_path + ) + + self.home_dir = os.path.join(os.environ['HOME'], ".cdist") def tearDown(self): shutil.rmtree(self.temp_dir) @@ -53,10 +56,7 @@ class LocalTestCase(test.CdistTestCase): ### test api def test_cache_path(self): - self.assertEqual(self.local.cache_path, os.path.join(self.base_path, "cache")) - - def test_conf_path(self): - self.assertEqual(self.local.conf_path, os.path.join(self.base_path, "conf")) + self.assertEqual(self.local.cache_path, os.path.join(self.home_dir, "cache")) def test_global_explorer_path(self): self.assertEqual(self.local.global_explorer_path, os.path.join(self.base_path, "conf", "explorer")) @@ -117,7 +117,8 @@ class LocalTestCase(test.CdistTestCase): self.local.rmdir(temp_dir) self.assertFalse(os.path.isdir(temp_dir)) - def test_create_directories(self): - self.local.create_directories() + def test_create_files_dirs(self): + self.local.create_files_dirs() self.assertTrue(os.path.isdir(self.local.out_path)) self.assertTrue(os.path.isdir(self.local.bin_path)) + self.assertTrue(os.path.isdir(self.local.conf_path)) diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index a9846b1d..61a815a9 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -49,8 +49,7 @@ class ManifestTestCase(test.CdistTestCase): self.target_host = 'localhost' out_path = self.temp_dir self.local = local.Local(self.target_host, local_base_path, out_path) - self.local.create_directories() - self.local.link_emulator(cdist.test.cdist_exec_path) + self.local.create_files_dirs() self.manifest = manifest.Manifest(self.target_host, self.local) self.log = logging.getLogger(self.target_host) From 69a38443328c93d6ae30ed8f50433f9b3694f35a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 14:48:51 +0100 Subject: [PATCH 1739/4212] fix some tests and fix home_dir lookup Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 2 +- cdist/test/exec/local.py | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 2406c8d5..4a9660ef 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -54,7 +54,7 @@ class Local(object): def _init_home_dir(self): if 'HOME' in os.environ: - self.home_dir = os.environ['HOME'] + self.home_dir = os.path.join(os.environ['HOME'], ".cdist") else: self.home_dir = None diff --git a/cdist/test/exec/local.py b/cdist/test/exec/local.py index ebfc64af..f74302df 100644 --- a/cdist/test/exec/local.py +++ b/cdist/test/exec/local.py @@ -58,14 +58,8 @@ class LocalTestCase(test.CdistTestCase): def test_cache_path(self): self.assertEqual(self.local.cache_path, os.path.join(self.home_dir, "cache")) - def test_global_explorer_path(self): - self.assertEqual(self.local.global_explorer_path, os.path.join(self.base_path, "conf", "explorer")) - - def test_manifest_path(self): - self.assertEqual(self.local.manifest_path, os.path.join(self.base_path, "conf", "manifest")) - - def test_type_path(self): - self.assertEqual(self.local.type_path, os.path.join(self.base_path, "conf", "type")) + def test_conf_path(self): + self.assertEqual(self.local.conf_path, os.path.join(self.out_path, "conf")) def test_out_path(self): self.assertEqual(self.local.out_path, self.out_path) @@ -81,6 +75,18 @@ class LocalTestCase(test.CdistTestCase): ### /test api + ### test internal implementation + + def test_global_explorer_path(self): + self.assertEqual(self.local.global_explorer_path, os.path.join(self.out_path, "conf", "explorer")) + + def test_manifest_path(self): + self.assertEqual(self.local.manifest_path, os.path.join(self.out_path, "conf", "manifest")) + + def test_type_path(self): + self.assertEqual(self.local.type_path, os.path.join(self.out_path, "conf", "type")) + + ### other tests def test_run_success(self): self.local.run(['/bin/true']) @@ -98,7 +104,7 @@ class LocalTestCase(test.CdistTestCase): handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: fd.writelines(["#!/bin/sh\n", "/bin/false"]) - self.assertRaises(local.LocalScriptError, self.local.run_script, script) + self.assertRaises(cdist.Error, self.local.run_script, script) def test_run_script_get_output(self): handle, script = self.mkstemp(dir=self.temp_dir) From af241653670318d514212d903b995ec9202a64f8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 15:17:46 +0100 Subject: [PATCH 1740/4212] introduce home_dir as a property Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 4a9660ef..2f870033 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -47,16 +47,20 @@ class Local(object): self._init_log() self._init_permissions() - self._init_home_dir() self._init_paths() self._init_cache_dir(cache_dir) self._init_conf_dirs() - def _init_home_dir(self): + @property + def dist_conf_dir(self): + return os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), "conf")) + + @property + def home_dir(self): if 'HOME' in os.environ: - self.home_dir = os.path.join(os.environ['HOME'], ".cdist") + return os.path.join(os.environ['HOME'], ".cdist") else: - self.home_dir = None + return = None def _init_log(self): self.log = logging.getLogger(self.target_host) @@ -81,13 +85,12 @@ class Local(object): self.conf_dirs = [] # Comes with the distribution - system_conf_dir = os.path.join(os.path.dirname(cdist.__file__), "conf") + system_conf_dir = os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), "conf")) self.conf_dirs.append(system_conf_dir) # Is the default place for user created explorer, type and manifest if self.home_dir: - user_conf_dir = os.path.join(self.home_dir, ".cdist") - self.conf_dirs.append(user_conf_dir) + self.conf_dirs.append(self.home_dir) # Add user supplied directories if self._add_conf_dirs: @@ -152,13 +155,12 @@ class Local(object): 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) def _create_conf_path_and_link_conf_dirs(self): - self.mkdir(self.conf_path) - # Link destination directories for sub_dir in [ "explorer", "manifest", "type" ]: self.mkdir(os.path.join(self.conf_path, sub_dir)) From 528901bdeee3f963d42e30e0408edeb459b56732 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 15:20:10 +0100 Subject: [PATCH 1741/4212] update a lot of tests for new exec.local Signed-off-by: Nico Schottelius --- cdist/core/cdist_type.py | 1 - cdist/exec/local.py | 2 +- cdist/test/autorequire/__init__.py | 6 +++-- cdist/test/code/__init__.py | 2 +- cdist/test/emulator/__init__.py | 23 +++++++++++-------- cdist/test/exec/local.py | 36 ++++++++++++++++++++++++++++++ cdist/test/explorer/__init__.py | 2 +- 7 files changed, 57 insertions(+), 15 deletions(-) diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index 86f3ced1..44e192fc 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -24,7 +24,6 @@ import os import cdist - class NoSuchTypeError(cdist.Error): def __init__(self, type_path, type_absolute_path): self.type_path = type_path diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 2f870033..7ef11458 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -60,7 +60,7 @@ class Local(object): if 'HOME' in os.environ: return os.path.join(os.environ['HOME'], ".cdist") else: - return = None + return None def _init_log(self): self.log = logging.getLogger(self.target_host) diff --git a/cdist/test/autorequire/__init__.py b/cdist/test/autorequire/__init__.py index 2263cbf9..bd763fd3 100644 --- a/cdist/test/autorequire/__init__.py +++ b/cdist/test/autorequire/__init__.py @@ -34,7 +34,7 @@ import cdist.context import os.path as op my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') -local_base_path = fixtures +add_conf_dir = op.join(fixtures, 'conf') class AutorequireTestCase(test.CdistTestCase): @@ -48,7 +48,9 @@ class AutorequireTestCase(test.CdistTestCase): self.context = cdist.context.Context( target_host=self.target_host, - base_path=local_base_path, + remote_copy='/bin/true', + remote_exec='/bin/true', + add_conf_dirs=add_conf_dir, exec_path=test.cdist_exec_path, debug=False) self.config = config.Config(self.context) diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 8a8583d7..8bc937b0 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -44,7 +44,7 @@ class CodeTestCase(test.CdistTestCase): self.local_base_path = local_base_path self.out_path = self.mkdtemp() self.local = local.Local(self.target_host, self.local_base_path, self.out_path) - self.local.create_directories() + self.local.create_files_dirs() self.remote_base_path = self.mkdtemp() self.user = getpass.getuser() diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 679fd149..1b77bdb6 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -33,8 +33,6 @@ from cdist import core from cdist import config import cdist.context -local_base_path = test.cdist_base_path - class EmulatorTestCase(test.CdistTestCase): def setUp(self): @@ -45,7 +43,10 @@ class EmulatorTestCase(test.CdistTestCase): os.close(handle) self.target_host = 'localhost' out_path = self.temp_dir - self.local = local.Local(self.target_host, local_base_path, out_path, test.cdist_exec_path) + self.local = local.Local( + target_host=self.target_host, + out_path=out_path, + exec_path=test.cdist_exec_path) self.local.create_files_dirs() self.env = { 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), @@ -112,8 +113,10 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): self.temp_dir = self.mkdtemp() self.target_host = 'localhost' out_path = self.temp_dir - _local_base_path = fixtures - self.local = local.Local(self.target_host, _local_base_path, out_path, test.cdist_exec_path) + self.local = local.Local( + target_host=self.target_host, + out_path=out_path, + exec_path=test.cdist_exec_path) self.local.create_files_dirs() self.manifest = core.Manifest(self.target_host, self.local) @@ -138,9 +141,13 @@ class ArgumentsTestCase(test.CdistTestCase): out_path = self.temp_dir handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) - _local_base_path = fixtures - self.local = local.Local(self.target_host, _local_base_path, out_path, test.cdist_exec_path) + + self.local = local.Local( + target_host=self.target_host, + out_path=out_path, + exec_path=test.cdist_exec_path) self.local.create_files_dirs() + self.env = { 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), '__target_host': self.target_host, @@ -228,13 +235,11 @@ class StdinTestCase(test.CdistTestCase): self.target_host = 'localhost' self.temp_dir = self.mkdtemp() os.environ['__cdist_out_dir'] = self.temp_dir - local_base_path = fixtures self.context = cdist.context.Context( target_host=self.target_host, remote_copy='scp -o User=root -q', remote_exec='ssh -o User=root -q', - base_path=local_base_path, exec_path=test.cdist_exec_path, debug=False) self.config = config.Config(self.context) diff --git a/cdist/test/exec/local.py b/cdist/test/exec/local.py index f74302df..687c13a5 100644 --- a/cdist/test/exec/local.py +++ b/cdist/test/exec/local.py @@ -33,6 +33,7 @@ from cdist.exec import local import os.path as op my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') +conf_dir = op.join(fixtures, "conf") class LocalTestCase(test.CdistTestCase): @@ -86,6 +87,41 @@ class LocalTestCase(test.CdistTestCase): def test_type_path(self): self.assertEqual(self.local.type_path, os.path.join(self.out_path, "conf", "type")) + def test_dist_conf_dir_linking(self): + """Ensure that links are correctly created for types included in distribution""" + + test_type="__file" + + link_test_local = local.Local( + target_host='localhost', + out_path=self.out_path, + exec_path=test.cdist_exec_path, + ) + + link_test_local._create_conf_path_and_link_conf_dirs() + + our_type_dir = os.path.join(link_test_local.type_path, test_type) + + self.assertTrue(os.path.isdir(our_type_dir)) + + def test_added_conf_dir_linking(self): + """Ensure that links are correctly created for types in added conf directories""" + + test_type="__cdist_test_type" + + link_test_local = local.Local( + target_host='localhost', + out_path=self.out_path, + exec_path=test.cdist_exec_path, + add_conf_dirs=[conf_dir] + ) + + link_test_local._create_conf_path_and_link_conf_dirs() + + our_type_dir = os.path.join(link_test_local.type_path, test_type) + + self.assertTrue(os.path.isdir(our_type_dir)) + ### other tests def test_run_success(self): diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index 257ad8a9..528cb786 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -45,7 +45,7 @@ class ExplorerClassTestCase(test.CdistTestCase): self.local_base_path = local_base_path self.out_path = self.mkdtemp() self.local = local.Local(self.target_host, self.local_base_path, self.out_path) - self.local.create_directories() + self.local.create_files_dirs() self.remote_base_path = self.mkdtemp() self.user = getpass.getuser() From 0dd4942d96e6636bdfd05f3d70c78d960dbdc169 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 15:25:57 +0100 Subject: [PATCH 1742/4212] pre5 updates Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index d76f65bb..db6dbe59 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius +2.1.0pre5: 2012-11-01 + * Core: First round of tests updated to work with multiple configuration directories + 2.1.0pre4: 2012-10-31 * Dist: PyPi: Moved cdist.py to script/cdist to avoid double import * Core: Added support for multiple configuration directories (no documentation) From 8a40ba789a13ee55b8879aa18a1c5f7a66af3996 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 15:39:36 +0100 Subject: [PATCH 1743/4212] include freecode dist into dist process Signed-off-by: Nico Schottelius --- build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build b/build index 57dc275b..0dca69c9 100755 --- a/build +++ b/build @@ -108,6 +108,8 @@ case "$1" in $0 pub + $0 dist-freecode + $0 dist-post ;; @@ -214,7 +216,7 @@ eof printf "Press enter to submit to freecode> " read dummy - cat << eof | cfreecode-api release cdist + cat << eof | cfreecode-api release-add cdist { "auth_code": "$api_token", "release": { From f264cf9f6cfb1678377c57d7ee7d9e5ce464a1fe Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 17:45:34 +0100 Subject: [PATCH 1744/4212] insert the actual data into the release process for freecode Signed-off-by: Nico Schottelius --- build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build b/build index 0dca69c9..def72470 100755 --- a/build +++ b/build @@ -220,9 +220,9 @@ eof { "auth_code": "$api_token", "release": { - "tag_list": "REPLACEME", + "tag_list": "$taglist", "version": "$version", - "changelog": "REPLACEMETOO", + "changelog": "$changelog", "hidden_from_frontpage": false } } From 5ec586f7641f22a0d4fa565e48dd3eb3a9519a25 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 18:21:56 +0100 Subject: [PATCH 1745/4212] begin to cleanup explorer test case Signed-off-by: Nico Schottelius --- cdist/test/__init__.py | 4 ++++ cdist/test/explorer/__init__.py | 40 ++++++++++++++++++++------------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/cdist/test/__init__.py b/cdist/test/__init__.py index f8e71287..3d9b1a2e 100644 --- a/cdist/test/__init__.py +++ b/cdist/test/__init__.py @@ -28,9 +28,13 @@ cdist_base_path = os.path.abspath( cdist_exec_path = os.path.join(cdist_base_path, "scripts/cdist") +global_fixtures_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "fixtures")) class CdistTestCase(unittest.TestCase): + remote_exec = os.path.join(global_fixtures_dir, "remote", "exec") + remote_copy = os.path.join(global_fixtures_dir, "remote", "copy") + def mkdtemp(self, **kwargs): return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index 528cb786..7801df5d 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 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -35,35 +35,45 @@ from cdist.core import explorer import os.path as op my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') -local_base_path = fixtures +conf_dir = op.join(fixtures, "conf") class ExplorerClassTestCase(test.CdistTestCase): def setUp(self): self.target_host = 'localhost' - self.local_base_path = local_base_path - self.out_path = self.mkdtemp() - self.local = local.Local(self.target_host, self.local_base_path, self.out_path) + self.temp_dir = self.mkdtemp() + self.out_path = os.path.join(self.temp_dir, "out") + self.remote_base_path = os.path.join(self.temp_dir, "remote") + + self.local = local.Local( + target_host=self.target_host, + out_path=self.out_path, + exec_path=test.cdist_exec_path, + add_conf_dirs=[conf_dir]) + self.local.create_files_dirs() - self.remote_base_path = self.mkdtemp() - self.user = getpass.getuser() - remote_exec = "ssh -o User=%s -q" % self.user - remote_copy = "scp -o User=%s -q" % self.user - self.remote = remote.Remote(self.target_host, self.remote_base_path, remote_exec, remote_copy) + self.remote = remote.Remote( + self.target_host, + self.remote_base_path, + self.remote_exec, + self.remote_copy) - self.explorer = explorer.Explorer(self.target_host, self.local, self.remote) + self.explorer = explorer.Explorer( + self.target_host, + self.local, + self.remote) self.log = logging.getLogger(self.target_host) def tearDown(self): - shutil.rmtree(self.out_path) - shutil.rmtree(self.remote_base_path) + shutil.rmtree(self.temp_dir) def test_list_global_explorer_names(self): - expected = ['foobar', 'global'] - self.assertEqual(self.explorer.list_global_explorer_names(), expected) + names = self.explorer.list_global_explorer_names() + self.assertIn("foobar", names) + self.assertIn("global", names) def test_transfer_global_explorers(self): self.explorer.transfer_global_explorers() From 09fd8090324f0e706a11fb2ae9c091ec977dd42d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 18:22:52 +0100 Subject: [PATCH 1746/4212] add new remote handler which turns remote into local ;-) Signed-off-by: Nico Schottelius --- cdist/test/fixtures/remote/copy | 28 ++++++++++++++++++++++++++++ cdist/test/fixtures/remote/exec | 29 +++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100755 cdist/test/fixtures/remote/copy create mode 100755 cdist/test/fixtures/remote/exec diff --git a/cdist/test/fixtures/remote/copy b/cdist/test/fixtures/remote/copy new file mode 100755 index 00000000..475155da --- /dev/null +++ b/cdist/test/fixtures/remote/copy @@ -0,0 +1,28 @@ +#!/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 . +# +# + +recursive=$1; shift +src=$1; shift +dst=$1; shift + +dst=$(echo $dst | sed "s/^${__target_host}://") + +cp "$recursive" "$src" "$dst" diff --git a/cdist/test/fixtures/remote/exec b/cdist/test/fixtures/remote/exec new file mode 100755 index 00000000..ac658313 --- /dev/null +++ b/cdist/test/fixtures/remote/exec @@ -0,0 +1,29 @@ +#!/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 . +# +# +# same as cdist default +# +# Usage: +# cdist config --remote-exec "/path/to/this/script" target_host +# + +target_host=$1; shift +# echo "Executing $@ (for $target_host)" +/bin/sh -c "$@" From 184e2bd9c56a751bfc6fa6ed300618fac36f6719 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 1 Nov 2012 18:25:29 +0100 Subject: [PATCH 1747/4212] add new remote that does local calls Signed-off-by: Nico Schottelius --- cdist/test/fixtures/remote | 1 + docs/changelog | 3 +++ other/examples/remote/local/README | 3 +++ .../test/fixtures/remote => other/examples/remote/local}/copy | 0 .../test/fixtures/remote => other/examples/remote/local}/exec | 0 5 files changed, 7 insertions(+) create mode 120000 cdist/test/fixtures/remote create mode 100644 other/examples/remote/local/README rename {cdist/test/fixtures/remote => other/examples/remote/local}/copy (100%) rename {cdist/test/fixtures/remote => other/examples/remote/local}/exec (100%) diff --git a/cdist/test/fixtures/remote b/cdist/test/fixtures/remote new file mode 120000 index 00000000..c5db6358 --- /dev/null +++ b/cdist/test/fixtures/remote @@ -0,0 +1 @@ +../../../other/examples/remote/local \ No newline at end of file diff --git a/docs/changelog b/docs/changelog index db6dbe59..2cdf6cbf 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius +2.1.0pre6: + * New Example: Turn remote calls into local calls (used for unittesting) + 2.1.0pre5: 2012-11-01 * Core: First round of tests updated to work with multiple configuration directories diff --git a/other/examples/remote/local/README b/other/examples/remote/local/README new file mode 100644 index 00000000..cfd350f9 --- /dev/null +++ b/other/examples/remote/local/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/other/examples/remote/local/copy similarity index 100% rename from cdist/test/fixtures/remote/copy rename to other/examples/remote/local/copy diff --git a/cdist/test/fixtures/remote/exec b/other/examples/remote/local/exec similarity index 100% rename from cdist/test/fixtures/remote/exec rename to other/examples/remote/local/exec From 90fad0fe83176dd5a07fc690f527c97dba34c32b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 14:15:14 +0100 Subject: [PATCH 1748/4212] create remote base in test - needed? Signed-off-by: Nico Schottelius --- cdist/test/explorer/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index 7801df5d..bb39d006 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -45,6 +45,7 @@ class ExplorerClassTestCase(test.CdistTestCase): self.temp_dir = self.mkdtemp() self.out_path = os.path.join(self.temp_dir, "out") 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, From ccb3c8780f1091d3ed889b5e63ffe900e8f26c0c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 14:16:27 +0100 Subject: [PATCH 1749/4212] ++release date Signed-off-by: Nico Schottelius --- doc/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog b/doc/changelog index 05d6d96b..e5abb6b5 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.0.15: +2.0.15: 2012-11-02 * Core: Make variable __object_name available in type explorers (Steven Armtrong) * New Type: __qemu_img * New Type: __line From afa5f884c5bd73ec3c07b5920145fe50c67f6fe7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 14:25:55 +0100 Subject: [PATCH 1750/4212] rought migration document Signed-off-by: Nico Schottelius --- docs/dev/logs/2012-11-02.migration_to_2.1 | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 docs/dev/logs/2012-11-02.migration_to_2.1 diff --git a/docs/dev/logs/2012-11-02.migration_to_2.1 b/docs/dev/logs/2012-11-02.migration_to_2.1 new file mode 100644 index 00000000..2ef8df22 --- /dev/null +++ b/docs/dev/logs/2012-11-02.migration_to_2.1 @@ -0,0 +1,40 @@ +create a new branch to ensure nothing breaks + + % git checkout -b 2.1_merge + +fetch latest upstream changes (change origin if you use another +remote name for upstream cdist) + + % git fetch -v origin + +Now try to merge upstream into the new branch. + + + % git merge origin/2.1 + +fix any conflicts that may have been occurred due to local changes +and then **git add** and *git commit** those changes. + +As the types have a new location, **cdist/conf/** now, you have to move +your own types there as well: + + % git mv conf/type/* cdist/conf/ + +The manifest location also changed, so move this one as well: + + % git mv conf/manifest/* cdist/conf/manifest/ + +Use **git status** to review the changes and ensure they +are in the git database: + + % git commit -m "Move types and manifests for 2.1 migration" + +This should be everything necessary for a 2.1 migration. Test the result +by running cdist on one of your staging hosts: + + % ./bin/cdist config -v staging-host + + +You can now cleanup the empty conf/ directory: + + % rmdir conf/* && rmdir conf From 6e107fa92c121482be9f9804b57b154116fc697b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 16:27:28 +0100 Subject: [PATCH 1751/4212] Export PYTHONPATH so it's available for the emulator Signed-off-by: Nico Schottelius --- bin/cdist | 6 +++++- docs/changelog | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/cdist b/bin/cdist index 5a6ce92f..dfe4fa00 100755 --- a/bin/cdist +++ b/bin/cdist @@ -26,4 +26,8 @@ dir=${0%/*} # Ensure version is present - the bundled/shipped version contains a static version, # the git version contains a dynamic version "$dir/../build" version -PYTHONPATH="${dir}/../" "$dir/../scripts/cdist" "$@" + +libdir=$(cd "${dir}/../" && pwd -P) +export PYTHONPATH="${libdir}" + +"$dir/../scripts/cdist" "$@" diff --git a/docs/changelog b/docs/changelog index 9b6a391f..3062d44b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog 2.1.0pre6: * New Example: Turn remote calls into local calls (used for unittesting) + * Core: Export PYTHONPATH, it's also needed by emulator 2.1.0pre5: 2012-11-01 * Core: First round of tests updated to work with multiple configuration directories From 384a20ffbca66330279837cccc742fb9e7459ede Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 16:58:52 +0100 Subject: [PATCH 1752/4212] building ruby requires bzip2 to be present to extract the tar.bz2 Signed-off-by: Nico Schottelius --- cdist/conf/type/__rvm_ruby/manifest | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100755 cdist/conf/type/__rvm_ruby/manifest diff --git a/cdist/conf/type/__rvm_ruby/manifest b/cdist/conf/type/__rvm_ruby/manifest new file mode 100755 index 00000000..65cf80a1 --- /dev/null +++ b/cdist/conf/type/__rvm_ruby/manifest @@ -0,0 +1,25 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +# Required packages for building ruby +for package in bzip2; do + __package --state present +done From 5eac7512a5fd613e99586a422e8d68d6106f3af5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 17:04:00 +0100 Subject: [PATCH 1753/4212] fix dependencies for __rvm_ruby Signed-off-by: Nico Schottelius --- cdist/conf/type/__rvm_ruby/manifest | 2 +- docs/changelog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__rvm_ruby/manifest b/cdist/conf/type/__rvm_ruby/manifest index 65cf80a1..6d5f4977 100755 --- a/cdist/conf/type/__rvm_ruby/manifest +++ b/cdist/conf/type/__rvm_ruby/manifest @@ -20,6 +20,6 @@ # # Required packages for building ruby -for package in bzip2; do +for package in bzip2 gcc make; do __package --state present done diff --git a/docs/changelog b/docs/changelog index 3062d44b..f848d83c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 2.1.0pre6: * New Example: Turn remote calls into local calls (used for unittesting) * Core: Export PYTHONPATH, it's also needed by emulator + * Type __rvm_ruby: Add clean package dependencies 2.1.0pre5: 2012-11-01 * Core: First round of tests updated to work with multiple configuration directories From 13fc5aa8f5b1a3a92b59fe00c6e7d53bd6158c8f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 17:15:16 +0100 Subject: [PATCH 1754/4212] use shortcut version to exit if nothing is to be done Signed-off-by: Nico Schottelius --- cdist/conf/type/__rvm_gem/gencode-remote | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/cdist/conf/type/__rvm_gem/gencode-remote b/cdist/conf/type/__rvm_gem/gencode-remote index 34a69624..0b855fc0 100755 --- a/cdist/conf/type/__rvm_gem/gencode-remote +++ b/cdist/conf/type/__rvm_gem/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2012 Evax Software +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -25,19 +26,20 @@ gemsetname="$(echo "$gemset" | cut -d '@' -f 2)" state_is="$(cat "$__object/explorer/state")" user="$(cat "$__object/parameter/user")" state_should="$(cat "$__object/parameter/state")" -if [ "$state_is" != "$state_should" ]; then - case "$state_should" in - present) - cat << DONE + +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + cat << DONE su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" rvm use $gemset; gem install $gem" DONE - ;; - absent) - cat << DONE + ;; + absent) + cat << DONE su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" rvm use $gemset; gem uninstall $gem" DONE - ;; - esac -fi + ;; +esac From d97f6794d0cf65a839c22dcb71c781ee79ef6ba4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 17:16:25 +0100 Subject: [PATCH 1755/4212] run rvm as user, not as root Signed-off-by: Nico Schottelius --- cdist/conf/type/__rvm_gem/gencode-remote | 6 ++---- docs/changelog | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__rvm_gem/gencode-remote b/cdist/conf/type/__rvm_gem/gencode-remote index 0b855fc0..3aef45ef 100755 --- a/cdist/conf/type/__rvm_gem/gencode-remote +++ b/cdist/conf/type/__rvm_gem/gencode-remote @@ -32,14 +32,12 @@ state_should="$(cat "$__object/parameter/state")" case "$state_should" in present) cat << DONE -su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" -rvm use $gemset; gem install $gem" +su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm; rvm use $gemset; gem install $gem"\" DONE ;; absent) cat << DONE -su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" -rvm use $gemset; gem uninstall $gem" +su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm; rvm use $gemset; gem uninstall $gem"\" DONE ;; esac diff --git a/docs/changelog b/docs/changelog index f848d83c..a2c78210 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,7 +7,8 @@ Changelog 2.1.0pre6: * New Example: Turn remote calls into local calls (used for unittesting) * Core: Export PYTHONPATH, it's also needed by emulator - * Type __rvm_ruby: Add clean package dependencies + * Bugfix Type __rvm_ruby: Add clean package dependencies + * Bugfix Type __rvm_gem: Run rvm as user, not as root 2.1.0pre5: 2012-11-01 * Core: First round of tests updated to work with multiple configuration directories From c779e16fe23c6e3bf340ecde633bae4972893058 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 17:18:57 +0100 Subject: [PATCH 1756/4212] __rvm: use shortcut version Signed-off-by: Nico Schottelius --- cdist/conf/type/__rvm/gencode-remote | 23 ++++++++++++----------- docs/changelog | 1 + 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/cdist/conf/type/__rvm/gencode-remote b/cdist/conf/type/__rvm/gencode-remote index aa6ef647..dbc6ba60 100755 --- a/cdist/conf/type/__rvm/gencode-remote +++ b/cdist/conf/type/__rvm/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2012 Evax Software +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -21,20 +22,20 @@ user="$__object_id" state_is="$(cat "$__object/explorer/state")" state_should="$(cat "$__object/parameter/state")" -if [ "$state_is" != "$state_should" ]; then - case "$state_should" in - present) - cat << DONE + +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + cat << DONE su - $user -c "unset rvm_path; unset rvm_bin_path; unset rvm_prefix; unset rvm_version; curl -L get.rvm.io | bash -s stable" DONE - ;; - absent) - cat << DONE + ;; + absent) + cat << DONE su - $user -c "rm -Rf \"\\\$HOME/.rvm\"; sed '/rvm\/scripts\/rvm/d' \"\\\$HOME/.bashrc\" > \"\\\$HOME/.bashrc.cdist-tmp\" mv \"\\\$HOME/.bashrc.cdist-tmp\" \"\\\$HOME/.bashrc\"" - DONE - ;; - esac -fi + ;; +esac diff --git a/docs/changelog b/docs/changelog index a2c78210..e9423925 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ Changelog * Core: Export PYTHONPATH, it's also needed by emulator * Bugfix Type __rvm_ruby: Add clean package dependencies * Bugfix Type __rvm_gem: Run rvm as user, not as root + * Cleanup Type __rvm: Use shortcut version 2.1.0pre5: 2012-11-01 * Core: First round of tests updated to work with multiple configuration directories From d5955bbb4d0f0e341cd3be258d7c1ac59b0c4ea9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 17:19:30 +0100 Subject: [PATCH 1757/4212] reference dependency package as well Signed-off-by: Nico Schottelius --- cdist/conf/type/__rvm_ruby/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__rvm_ruby/manifest b/cdist/conf/type/__rvm_ruby/manifest index 6d5f4977..db8fd830 100755 --- a/cdist/conf/type/__rvm_ruby/manifest +++ b/cdist/conf/type/__rvm_ruby/manifest @@ -21,5 +21,5 @@ # Required packages for building ruby for package in bzip2 gcc make; do - __package --state present + __package "$package" --state present done From df88d98ea05565fa64452c9eb7ab816454849e3a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 17:35:13 +0100 Subject: [PATCH 1758/4212] many cleanups to __rvm* types Signed-off-by: Nico Schottelius --- cdist/conf/type/__rvm_gem/gencode-remote | 7 ++-- cdist/conf/type/__rvm_gemset/explorer/state | 6 ++-- cdist/conf/type/__rvm_gemset/gencode-remote | 37 ++++++++++----------- docs/changelog | 2 +- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/cdist/conf/type/__rvm_gem/gencode-remote b/cdist/conf/type/__rvm_gem/gencode-remote index 3aef45ef..1fe6e78e 100755 --- a/cdist/conf/type/__rvm_gem/gencode-remote +++ b/cdist/conf/type/__rvm_gem/gencode-remote @@ -1,5 +1,4 @@ -#!/bin/sh -# +#!/bin/sh # # 2012 Evax Software # 2012 Nico Schottelius (nico-cdist at schottelius.org) # @@ -32,12 +31,12 @@ state_should="$(cat "$__object/parameter/state")" case "$state_should" in present) cat << DONE -su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm; rvm use $gemset; gem install $gem"\" +su - "$user" -c 'source ~/.rvm/scripts/rvm; rvm use "$gemset"; gem install "$gem"' DONE ;; absent) cat << DONE -su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm; rvm use $gemset; gem uninstall $gem"\" +su - "$user" -c 'source ~/.rvm/scripts/rvm; rvm use "$gemset"; gem uninstall "$gem"' DONE ;; esac diff --git a/cdist/conf/type/__rvm_gemset/explorer/state b/cdist/conf/type/__rvm_gemset/explorer/state index fbf11830..c8d573b5 100755 --- a/cdist/conf/type/__rvm_gemset/explorer/state +++ b/cdist/conf/type/__rvm_gemset/explorer/state @@ -22,13 +22,13 @@ gemset="$__object_id" ruby="$(echo "$gemset" | cut -d '@' -f 1)" gemsetname="$(echo "$gemset" | cut -d '@' -f2)" user="$(cat "$__object/parameter/user")" -if su - "$user" -c "[ ! -d \"\$HOME/.rvm\" ]" ; then +if su - "$user" -c "[ ! -d ~/.rvm ]" ; then echo "absent" exit 0 fi -if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" +if su - "$user" -c "source ~/.rvm/scripts/rvm rvm list | grep -q $ruby"; then - if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" + if su - "$user" -c "source ~/.rvm/scripts/rvm rvm use $ruby > /dev/null; rvm gemset list | grep -q $gemsetname"; then echo "present" exit 0 diff --git a/cdist/conf/type/__rvm_gemset/gencode-remote b/cdist/conf/type/__rvm_gemset/gencode-remote index 1604538d..1fd14061 100755 --- a/cdist/conf/type/__rvm_gemset/gencode-remote +++ b/cdist/conf/type/__rvm_gemset/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2012 Evax Software +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -25,29 +26,27 @@ state_is="$(cat "$__object/explorer/state")" user="$(cat "$__object/parameter/user")" default="$(cat "$__object/parameter/default" 2>/dev/null || true)" state_should="$(cat "$__object/parameter/state")" -if [ "$state_is" != "$state_should" ]; then - case "$state_should" in - present) - cat << DONE -su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" -rvm $gemset --create" + +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + cat << DONE +su - "$user" -c "source ~/.rvm/scripts/rvm; rvm $gemset --create" DONE - case "$default" in + case "$default" in no) ;; *) - cat << DONE -su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" -rvm use --default $gemset" + cat << DONE +su - "$user" -c "source ~/.rvm/scripts/rvm; rvm use --default $gemset" DONE ;; - esac - ;; - absent) - cat << DONE -su - "$user" -c "source \"\\\$HOME/.rvm/scripts/rvm\" -rvm use $ruby; rvm --force gemset delete $gemsetname" + esac + ;; + absent) + cat << DONE +su - "$user" -c "source ~/.rvm/scripts/rvm; rvm use $ruby; rvm --force gemset delete $gemsetname" DONE - ;; - esac -fi + ;; +esac diff --git a/docs/changelog b/docs/changelog index e9423925..b91b01c7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,7 +9,7 @@ Changelog * Core: Export PYTHONPATH, it's also needed by emulator * Bugfix Type __rvm_ruby: Add clean package dependencies * Bugfix Type __rvm_gem: Run rvm as user, not as root - * Cleanup Type __rvm: Use shortcut version + * Cleanup Type __rvm, __rvm_gemset: Use shortcut version 2.1.0pre5: 2012-11-01 * Core: First round of tests updated to work with multiple configuration directories From 0eac132b83fe4ea44517fe9f051412cbd1552c8d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 21:46:08 +0100 Subject: [PATCH 1759/4212] adjust gemset explorer to work with new rvm version (fixes #108) See https://github.com/wayneeseguin/rvm/issues/1285 Signed-off-by: Nico Schottelius --- cdist/conf/type/__rvm_gemset/explorer/state | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__rvm_gemset/explorer/state b/cdist/conf/type/__rvm_gemset/explorer/state index c8d573b5..fa643a6e 100755 --- a/cdist/conf/type/__rvm_gemset/explorer/state +++ b/cdist/conf/type/__rvm_gemset/explorer/state @@ -22,14 +22,14 @@ gemset="$__object_id" ruby="$(echo "$gemset" | cut -d '@' -f 1)" gemsetname="$(echo "$gemset" | cut -d '@' -f2)" user="$(cat "$__object/parameter/user")" -if su - "$user" -c "[ ! -d ~/.rvm ]" ; then + +if [ ! -e "~$user/.rvm/scripts/rvm" ] ; then echo "absent" exit 0 fi -if su - "$user" -c "source ~/.rvm/scripts/rvm -rvm list | grep -q $ruby"; then - if su - "$user" -c "source ~/.rvm/scripts/rvm -rvm use $ruby > /dev/null; rvm gemset list | grep -q $gemsetname"; then + +if su - "$user" -c 'source ~/.rvm/scripts/rvm; rvm list strings | grep -q "^$ruby\$"'; then + if su - "$user" -c 'source ~/.rvm/scripts/rvm; rvm use "$ruby" > /dev/null; rvm gemset list strings | cut -f 1 -d " " | grep -q "^$gemsetname\$"'; then echo "present" exit 0 fi From 5308d2cfe7363414be071b889ef6e93a9e800776 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 22:35:52 +0100 Subject: [PATCH 1760/4212] link to role from database Signed-off-by: Nico Schottelius --- cdist/conf/type/__postgres_database/man.text | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__postgres_database/man.text b/cdist/conf/type/__postgres_database/man.text index 06cb736f..d01ca8f6 100644 --- a/cdist/conf/type/__postgres_database/man.text +++ b/cdist/conf/type/__postgres_database/man.text @@ -36,6 +36,7 @@ __postgres_database mydbname --state present --owner mydbusername SEE ALSO -------- - cdist-type(7) +- cdist-type__postgres_role(7) COPYING From 03d224c74c7578f555562480026437d8a7d72401 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 22:43:19 +0100 Subject: [PATCH 1761/4212] add hint to db from role Signed-off-by: Nico Schottelius --- cdist/conf/type/__postgres_role/man.text | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__postgres_role/man.text b/cdist/conf/type/__postgres_role/man.text index bcc7b5d7..9b917060 100644 --- a/cdist/conf/type/__postgres_role/man.text +++ b/cdist/conf/type/__postgres_role/man.text @@ -49,6 +49,7 @@ __postgres_role dbcustomer --state present --password 'bla' --createdb true SEE ALSO -------- - cdist-type(7) +- cdist-type__postgres_database(7) - http://www.postgresql.org/docs/current/static/sql-createrole.html From b6f61a632f0d49e8f90f8adafb25afda149b0167 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 22:56:45 +0100 Subject: [PATCH 1762/4212] __postgres_role: switch to boolean, use shortcut version Signed-off-by: Nico Schottelius --- .../conf/type/__postgres_role/gencode-remote | 45 +++++++++---------- cdist/conf/type/__postgres_role/man.text | 13 ++++-- .../type/__postgres_role/parameter/boolean | 5 +++ .../type/__postgres_role/parameter/optional | 5 --- docs/changelog | 4 ++ 5 files changed, 38 insertions(+), 34 deletions(-) create mode 100644 cdist/conf/type/__postgres_role/parameter/boolean diff --git a/cdist/conf/type/__postgres_role/gencode-remote b/cdist/conf/type/__postgres_role/gencode-remote index a3280c09..c9de4707 100755 --- a/cdist/conf/type/__postgres_role/gencode-remote +++ b/cdist/conf/type/__postgres_role/gencode-remote @@ -22,33 +22,28 @@ name="$__object_id" state_is="$(cat "$__object/explorer/state")" state_should="$(cat "$__object/parameter/state")" -if [ "$state_is" != "$state_should" ]; then - case "$state_should" in - present) - optional="password - login - createdb - createrole - superuser" - for parameter in $optional; do - if [ -f "$__object/parameter/$parameter" ]; then - value="$(cat "$__object/parameter/$parameter")" - eval $parameter=$value +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + if [ -f "$__object/parameter/password" ]; then + password="$(cat "$__object/parameter/$parameter")" + fi + booleans="" + for boolean in login createdb createrole superuser; do + if [ ! -f "$__object/parameter/$boolean" ]; then + boolean="no${boolean}" fi - done + upper=$(echo $boolean | tr '[a-z]' '[A-Z]') + booleans="$booleans $upper" + done [ -n "$password" ] && password="PASSWORD '$password'" - [ "$login" = "true" ] && login="LOGIN" || login="NOLOGIN" - [ "$createdb" = "true" ] && createdb="CREATEDB" || createdb="NOCREATEDB" - [ "$createrole" = "true" ] && createrole="CREATEROLE" || createrole="NOCREATEROLE" - [ "$superuser" = "true" ] && superuser="SUPERUSER" || superuser="NOSUPERUSER" - [ "$inherit" = "true" ] && inherit="INHERIT" || inherit="NOINHERIT" - cmd="CREATE ROLE $name WITH $password $login $createdb $createrole $superuser $inherit" + cmd="CREATE ROLE $name WITH $password $booleans" echo "su - postgres -c \"psql -c \\\"$cmd\\\"\"" - ;; - absent) - echo "su - postgres -c \"dropuser \\\"$name\\\"\"" - ;; - esac -fi + ;; + absent) + echo "su - postgres -c \"dropuser \\\"$name\\\"\"" + ;; +esac diff --git a/cdist/conf/type/__postgres_role/man.text b/cdist/conf/type/__postgres_role/man.text index 9b917060..4f13fa53 100644 --- a/cdist/conf/type/__postgres_role/man.text +++ b/cdist/conf/type/__postgres_role/man.text @@ -21,17 +21,22 @@ state:: OPTIONAL PARAMETERS ------------------- -All optional parameter map directly to the corresponding postgres createrole +All parameter map directly to the corresponding postgres createrole parameters. password:: + +BOOLEAN PARAMETERS +------------------ +All parameter map directly to the corresponding postgres createrole +parameters. + login:: createdb:: createrole:: superuser:: inherit:: - EXAMPLES -------- @@ -40,9 +45,9 @@ __postgres_role myrole --state present __postgres_role myrole --state present --password 'secret' -__postgres_role admin --state present --password 'very-secret' --superuser true +__postgres_role admin --state present --password 'very-secret' --superuser -__postgres_role dbcustomer --state present --password 'bla' --createdb true +__postgres_role dbcustomer --state present --password 'bla' --createdb -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__postgres_role/parameter/boolean b/cdist/conf/type/__postgres_role/parameter/boolean new file mode 100644 index 00000000..a581b3fd --- /dev/null +++ b/cdist/conf/type/__postgres_role/parameter/boolean @@ -0,0 +1,5 @@ +login +createdb +createrole +superuser +inherit diff --git a/cdist/conf/type/__postgres_role/parameter/optional b/cdist/conf/type/__postgres_role/parameter/optional index c5abb57f..f3097ab1 100644 --- a/cdist/conf/type/__postgres_role/parameter/optional +++ b/cdist/conf/type/__postgres_role/parameter/optional @@ -1,6 +1 @@ password -login -createdb -createrole -superuser -inherit diff --git a/docs/changelog b/docs/changelog index b91b01c7..56750722 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,10 @@ Changelog * Bugfix Type __rvm_ruby: Add clean package dependencies * Bugfix Type __rvm_gem: Run rvm as user, not as root * Cleanup Type __rvm, __rvm_gemset: Use shortcut version + * Bugfix __rvm_gemset: Correctly check for gemsets + * Cleanup Type __postgres_database, __postgres_role: Reference each other + in documentation + * Cleanp Type __postgres_role: Use boolean parameters where appropriate 2.1.0pre5: 2012-11-01 * Core: First round of tests updated to work with multiple configuration directories From 2d69eb07c198e46ece48cda8c0142d6002d5dfcb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 2 Nov 2012 22:57:23 +0100 Subject: [PATCH 1763/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 56750722..1df72293 100644 --- a/docs/changelog +++ b/docs/changelog @@ -14,6 +14,7 @@ Changelog * Cleanup Type __postgres_database, __postgres_role: Reference each other in documentation * Cleanp Type __postgres_role: Use boolean parameters where appropriate + * Cleanp Type __postgres_role: Use shortcut version 2.1.0pre5: 2012-11-01 * Core: First round of tests updated to work with multiple configuration directories From 1db1168c9ab09919efe49e37dc0cac3b1a6a04dd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 5 Nov 2012 21:42:39 +0100 Subject: [PATCH 1764/4212] move doc into new location Signed-off-by: Nico Schottelius --- {doc => docs}/dev/logs/2012-05-23.urls | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {doc => docs}/dev/logs/2012-05-23.urls (100%) diff --git a/doc/dev/logs/2012-05-23.urls b/docs/dev/logs/2012-05-23.urls similarity index 100% rename from doc/dev/logs/2012-05-23.urls rename to docs/dev/logs/2012-05-23.urls From 43061dc1b3068ab239f6eee78b8ea3ebc23895b7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 5 Nov 2012 22:44:20 +0100 Subject: [PATCH 1765/4212] +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 1df72293..6a3e29ba 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.1.0pre6: +2.1.0pre6: 2012-11-05 * New Example: Turn remote calls into local calls (used for unittesting) * Core: Export PYTHONPATH, it's also needed by emulator * Bugfix Type __rvm_ruby: Add clean package dependencies From 9bdb715b7d3b75b733db15a4198576a96d936719 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 16:42:18 +0100 Subject: [PATCH 1766/4212] ensure all parameters for exec are executed Signed-off-by: Nico Schottelius --- other/examples/remote/local/copy | 1 - other/examples/remote/local/exec | 8 +------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/other/examples/remote/local/copy b/other/examples/remote/local/copy index 475155da..644fee15 100755 --- a/other/examples/remote/local/copy +++ b/other/examples/remote/local/copy @@ -24,5 +24,4 @@ src=$1; shift dst=$1; shift dst=$(echo $dst | sed "s/^${__target_host}://") - cp "$recursive" "$src" "$dst" diff --git a/other/examples/remote/local/exec b/other/examples/remote/local/exec index ac658313..838513a9 100755 --- a/other/examples/remote/local/exec +++ b/other/examples/remote/local/exec @@ -18,12 +18,6 @@ # along with cdist. If not, see . # # -# same as cdist default -# -# Usage: -# cdist config --remote-exec "/path/to/this/script" target_host -# target_host=$1; shift -# echo "Executing $@ (for $target_host)" -/bin/sh -c "$@" +echo "$@" | /bin/sh From 4a67d768d5655f9c7bdc1df0ac0a31685d38fd63 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 16:47:51 +0100 Subject: [PATCH 1767/4212] fix all explorer test cases Signed-off-by: Nico Schottelius --- cdist/test/explorer/__init__.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index bb39d006..266a1073 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -60,6 +60,7 @@ class ExplorerClassTestCase(test.CdistTestCase): self.remote_base_path, self.remote_exec, self.remote_copy) + self.remote.create_files_dirs() self.explorer = explorer.Explorer( self.target_host, @@ -83,14 +84,20 @@ class ExplorerClassTestCase(test.CdistTestCase): self.assertEqual(sorted(os.listdir(source)), sorted(os.listdir(destination))) def test_run_global_explorer(self): + """Checkt that running ONE global explorer works""" self.explorer.transfer_global_explorers() output = self.explorer.run_global_explorer('global') self.assertEqual(output, 'global\n') def test_run_global_explorers(self): + """Ensure output is created for every global explorer""" out_path = self.mkdtemp() + self.explorer.run_global_explorers(out_path) - self.assertEqual(sorted(os.listdir(out_path)), sorted(['foobar', 'global'])) + names = sorted(self.explorer.list_global_explorer_names()) + output = sorted(os.listdir(out_path)) + + self.assertEqual(names, output) shutil.rmtree(out_path) def test_list_type_explorer_names(self): From 04bd5d88c36482b82f50adad7928cb3409137df4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 16:58:30 +0100 Subject: [PATCH 1768/4212] Fix tests for code Signed-off-by: Nico Schottelius --- cdist/exec/remote.py | 2 +- cdist/test/code/__init__.py | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 07c6614b..d4d2cb2b 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 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 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 8bc937b0..473c4b39 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -34,23 +34,27 @@ from cdist.core import code import os.path as op my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') -local_base_path = fixtures +conf_dir = op.join(fixtures, 'conf') class CodeTestCase(test.CdistTestCase): def setUp(self): self.target_host = 'localhost' - self.local_base_path = local_base_path self.out_path = self.mkdtemp() - self.local = local.Local(self.target_host, self.local_base_path, self.out_path) + + self.local = local.Local( + target_host=self.target_host, + out_path = self.out_path, + exec_path = cdist.test.cdist_exec_path, + add_conf_dirs=[conf_dir]) self.local.create_files_dirs() self.remote_base_path = self.mkdtemp() - self.user = getpass.getuser() - remote_exec = "ssh -o User=%s -q" % self.user - remote_copy = "scp -o User=%s -q" % self.user + 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.create_files_dirs() self.code = code.Code(self.target_host, self.local, self.remote) From 8dfbb4a9dd7bad57566c7d9021524244b16cbb8f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 16:59:21 +0100 Subject: [PATCH 1769/4212] ++changes for next version Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 6a3e29ba..16e6e25d 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.1.0pre7: + * Core: Tests for "cdist.code" work again + 2.1.0pre6: 2012-11-05 * New Example: Turn remote calls into local calls (used for unittesting) * Core: Export PYTHONPATH, it's also needed by emulator From bb1a8d8e661eb04f3d972451e279521b520b8ea6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 17:01:20 +0100 Subject: [PATCH 1770/4212] fixup manifest tests Signed-off-by: Nico Schottelius --- cdist/test/code/__init__.py | 1 + cdist/test/manifest/__init__.py | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 473c4b39..f5d445ab 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index 61a815a9..0de04743 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -1,6 +1,7 @@ # -*- 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. # @@ -37,8 +38,7 @@ from cdist.core import manifest import os.path as op my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') -local_base_path = fixtures - +conf_dir = op.join(fixtures, 'conf') class ManifestTestCase(test.CdistTestCase): @@ -48,8 +48,13 @@ class ManifestTestCase(test.CdistTestCase): self.temp_dir = self.mkdtemp() self.target_host = 'localhost' out_path = self.temp_dir - self.local = local.Local(self.target_host, local_base_path, out_path) + self.local = local.Local( + target_host=self.target_host, + out_path=out_path, + exec_path = cdist.test.cdist_exec_path, + add_conf_dirs=[conf_dir]) self.local.create_files_dirs() + self.manifest = manifest.Manifest(self.target_host, self.local) self.log = logging.getLogger(self.target_host) From 474d901fdad4bc319b08a3bdc49e19e396d52b50 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 17:02:05 +0100 Subject: [PATCH 1771/4212] ++changes next version Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 16e6e25d..3f1dec49 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,7 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius 2.1.0pre7: - * Core: Tests for "cdist.code" work again + * Core: Tests for "test.code", "test.manifest" work again 2.1.0pre6: 2012-11-05 * New Example: Turn remote calls into local calls (used for unittesting) From c47d0fae1c67f576e810304eb4b004ce807f03d8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 17:28:26 +0100 Subject: [PATCH 1772/4212] fix autorequire test case and fix cdist_base_path test assignment Signed-off-by: Nico Schottelius --- cdist/context.py | 2 +- cdist/test/__init__.py | 4 ++-- cdist/test/autorequire/__init__.py | 16 +++++++++++----- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cdist/context.py b/cdist/context.py index 92e683a3..2855f228 100644 --- a/cdist/context.py +++ b/cdist/context.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # diff --git a/cdist/test/__init__.py b/cdist/test/__init__.py index 3d9b1a2e..a8c6103b 100644 --- a/cdist/test/__init__.py +++ b/cdist/test/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -24,7 +24,7 @@ import unittest import tempfile cdist_base_path = os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../../")) + os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../")) cdist_exec_path = os.path.join(cdist_base_path, "scripts/cdist") diff --git a/cdist/test/autorequire/__init__.py b/cdist/test/autorequire/__init__.py index bd763fd3..4b47b06b 100644 --- a/cdist/test/autorequire/__init__.py +++ b/cdist/test/autorequire/__init__.py @@ -1,6 +1,7 @@ # -*- 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. # @@ -36,7 +37,6 @@ 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): @@ -44,15 +44,21 @@ class AutorequireTestCase(test.CdistTestCase): os.environ = os.environ.copy() self.target_host = 'localhost' self.temp_dir = self.mkdtemp() - os.environ['__cdist_out_dir'] = self.temp_dir + + 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='/bin/true', - remote_exec='/bin/true', - add_conf_dirs=add_conf_dir, + 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): From e4024736689b2695f11ae20327c4794644e2ad77 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 21:32:20 +0100 Subject: [PATCH 1773/4212] ++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 3f1dec49..93c3cf69 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,7 +5,8 @@ Changelog * Exception: No braces means author == Nico Schottelius 2.1.0pre7: - * Core: Tests for "test.code", "test.manifest" work again + * Core: Tests for autorequire, code, manifest work again + * Core: Print error message on missing initial manifest 2.1.0pre6: 2012-11-05 * New Example: Turn remote calls into local calls (used for unittesting) From a22e729a3cf7ddab5465b311be602ee36eb095ce Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 21:32:37 +0100 Subject: [PATCH 1774/4212] raise special error on missing manifest Signed-off-by: Nico Schottelius --- cdist/core/manifest.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 5faeccd1..ecc4a490 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 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -25,6 +25,20 @@ import os import cdist +class NoInitialManifestError(cdist.Error): + """ + Display missing initial manifest + """ + + def __init__(self, manifest_path): + if os.path.islink(manifest_path): + self.message = "%s -> %s" (manifest_path, os.path.realpath(manifest_path)) + else: + self.message = manifest_path + + def __str__(self): + return "Initial manifest missing: %s" % self.message + ''' common: runs only locally, does not need remote @@ -84,6 +98,11 @@ class Manifest(object): env['__manifest'] = self.local.manifest_path env['__cdist_manifest'] = script self.log.info("Running initial manifest " + self.local.manifest_path) + + if not os.path.isfile(self.local.manifest_path): + print("fooooobar") + raise NoInitialManifestError(self.local.manifest_path) + self.local.run_script(script, env=env) def run_type_manifest(self, cdist_object): From 866f23ea2cc1d4f6b9961f5c892efcae2e2caddf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 21:32:54 +0100 Subject: [PATCH 1775/4212] inject conf_dir for emulator test Signed-off-by: Nico Schottelius --- cdist/test/emulator/__init__.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 1b77bdb6..871083f8 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -1,6 +1,7 @@ # -*- 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. # @@ -33,6 +34,12 @@ from cdist import core 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') +conf_dir = op.join(fixtures, 'conf') + + class EmulatorTestCase(test.CdistTestCase): def setUp(self): @@ -46,7 +53,8 @@ class EmulatorTestCase(test.CdistTestCase): self.local = local.Local( target_host=self.target_host, out_path=out_path, - exec_path=test.cdist_exec_path) + exec_path=test.cdist_exec_path, + add_conf_dirs=[conf_dir]) self.local.create_files_dirs() self.env = { 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), From aedb3669c74e786c312fd261d74182077b51ecd4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 21:46:02 +0100 Subject: [PATCH 1776/4212] print hint if initial manifest is missing Signed-off-by: Nico Schottelius --- cdist/context.py | 2 +- cdist/core/manifest.py | 17 +---------------- scripts/cdist | 2 +- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/cdist/context.py b/cdist/context.py index 2855f228..767b17a8 100644 --- a/cdist/context.py +++ b/cdist/context.py @@ -87,6 +87,6 @@ class Context(object): def filter(self, record): """Add hostname to logs via logging Filter""" - record.msg = self.target_host + ": " + record.msg + record.msg = self.target_host + ": " + str(record.msg) return True diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index ecc4a490..61d92992 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -25,20 +25,6 @@ import os import cdist -class NoInitialManifestError(cdist.Error): - """ - Display missing initial manifest - """ - - def __init__(self, manifest_path): - if os.path.islink(manifest_path): - self.message = "%s -> %s" (manifest_path, os.path.realpath(manifest_path)) - else: - self.message = manifest_path - - def __str__(self): - return "Initial manifest missing: %s" % self.message - ''' common: runs only locally, does not need remote @@ -100,8 +86,7 @@ class Manifest(object): self.log.info("Running initial manifest " + self.local.manifest_path) if not os.path.isfile(self.local.manifest_path): - print("fooooobar") - raise NoInitialManifestError(self.local.manifest_path) + raise cdist.Error("Initial manifest is missing") self.local.run_script(script, env=env) diff --git a/scripts/cdist b/scripts/cdist index 00ebbf18..fd18933a 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -181,9 +181,9 @@ def configinstall_onehost(host, args, mode, parallel): 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: - log.error(e) sys.exit(1) else: raise From 28bf0c3ed8f8bcee36caa07839b8163986d29872 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 21:52:11 +0100 Subject: [PATCH 1777/4212] setup target_host for tests in test main class Signed-off-by: Nico Schottelius --- cdist/test/__init__.py | 2 ++ cdist/test/emulator/__init__.py | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/test/__init__.py b/cdist/test/__init__.py index a8c6103b..ab767699 100644 --- a/cdist/test/__init__.py +++ b/cdist/test/__init__.py @@ -35,6 +35,8 @@ class CdistTestCase(unittest.TestCase): remote_exec = os.path.join(global_fixtures_dir, "remote", "exec") remote_copy = os.path.join(global_fixtures_dir, "remote", "copy") + target_host = 'cdisttesthost' + def mkdtemp(self, **kwargs): return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 871083f8..f9743e16 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -39,7 +39,6 @@ my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') conf_dir = op.join(fixtures, 'conf') - class EmulatorTestCase(test.CdistTestCase): def setUp(self): @@ -48,7 +47,6 @@ class EmulatorTestCase(test.CdistTestCase): self.temp_dir = self.mkdtemp() handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) - self.target_host = 'localhost' out_path = self.temp_dir self.local = local.Local( target_host=self.target_host, From 6482863c5d1bc7c75e6b0babe05524ff9bd6cbf0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 22:32:18 +0100 Subject: [PATCH 1778/4212] allow manifest to return env for usage from external Signed-off-by: Nico Schottelius --- cdist/core/manifest.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 61d92992..324374c3 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -78,29 +78,37 @@ class Manifest(object): self.env.update({'__cdist_debug': "yes" }) - def run_initial_manifest(self, script): + def env_initial_manifest(self, script): env = os.environ.copy() env.update(self.env) env['__manifest'] = self.local.manifest_path env['__cdist_manifest'] = script + + return env + + def run_initial_manifest(self, script): self.log.info("Running initial manifest " + self.local.manifest_path) if not os.path.isfile(self.local.manifest_path): raise cdist.Error("Initial manifest is missing") - self.local.run_script(script, env=env) + self.local.run_script(script, env=self.env_initial_manifest(script)) + + def env_type_manifest(self, cdist_object): + env = os.environ.copy() + env.update(self.env) + env.update({ + '__manifest': self.local.manifest_path, + '__object': cdist_object.absolute_path, + '__object_id': cdist_object.object_id, + '__object_name': cdist_object.name, + '__type': cdist_object.cdist_type.absolute_path, + '__cdist_manifest': script, + }) + + return env def run_type_manifest(self, cdist_object): script = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) if os.path.isfile(script): - env = os.environ.copy() - env.update(self.env) - env.update({ - '__manifest': self.local.manifest_path, - '__object': cdist_object.absolute_path, - '__object_id': cdist_object.object_id, - '__object_name': cdist_object.name, - '__type': cdist_object.cdist_type.absolute_path, - '__cdist_manifest': script, - }) - self.local.run_script(script, env=env) + self.local.run_script(script, env=self.env_type_manifest(cdist_object)) From 9cf80f5fdfb2bced3dc58178b7b3f4e3d6871da5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Nov 2012 22:39:25 +0100 Subject: [PATCH 1779/4212] make use of env provided by manifest Signed-off-by: Nico Schottelius --- cdist/test/emulator/__init__.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index f9743e16..26530f44 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -39,6 +39,7 @@ my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') conf_dir = op.join(fixtures, 'conf') +import logging class EmulatorTestCase(test.CdistTestCase): def setUp(self): @@ -48,20 +49,17 @@ class EmulatorTestCase(test.CdistTestCase): handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) out_path = self.temp_dir + self.local = local.Local( target_host=self.target_host, out_path=out_path, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) + logging.root.setLevel(logging.DEBUG) self.local.create_files_dirs() - self.env = { - 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), - '__target_host': self.target_host, - '__global': self.local.out_path, - '__cdist_type_base_path': self.local.type_path, # for use in type emulator - '__manifest': self.local.manifest_path, - '__cdist_manifest': self.script, - } + + self.manifest = core.Manifest(self.target_host, self.local) + self.env = self.manifest.env_initial_manifest(self.script) def tearDown(self): os.environ = self.orig_environ From e785092935b710fa48e1b9ca2d673ed69d5ea2a3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 09:07:18 +0100 Subject: [PATCH 1780/4212] allow Manifest to differentiate between supplied and implicit found initial manifest Signed-off-by: Nico Schottelius --- cdist/core/manifest.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 324374c3..74d45947 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -86,15 +86,19 @@ class Manifest(object): return env - def run_initial_manifest(self, script): - self.log.info("Running initial manifest " + self.local.manifest_path) + def run_initial_manifest(self, initial_manifest=None): + if not initial_manifest: + initial_manifest = self.local.initial_manifest - if not os.path.isfile(self.local.manifest_path): - raise cdist.Error("Initial manifest is missing") + self.log.info("Running initial manifest " + initial_manifest) - self.local.run_script(script, env=self.env_initial_manifest(script)) + if not os.path.isfile(initial_manifest): + raise cdist.Error("Initial manifest is missing: %s" % initial_manifest) + + self.local.run_script(script, env=self.env_initial_manifest(initial_manifest)) def env_type_manifest(self, cdist_object): + type_manifest = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) env = os.environ.copy() env.update(self.env) env.update({ @@ -103,12 +107,12 @@ class Manifest(object): '__object_id': cdist_object.object_id, '__object_name': cdist_object.name, '__type': cdist_object.cdist_type.absolute_path, - '__cdist_manifest': script, + '__cdist_manifest': type_manifest, }) return env def run_type_manifest(self, cdist_object): - script = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) - if os.path.isfile(script): - self.local.run_script(script, env=self.env_type_manifest(cdist_object)) + type_manifest = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) + if os.path.isfile(type_manifest): + self.local.run_script(type_manifest, env=self.env_type_manifest(cdist_object)) From 7b51e22922d2d118737594d65e111c8bef3348ee Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 09:58:47 +0100 Subject: [PATCH 1781/4212] allow to read stdin from different handle than sys.stdin in emulator Signed-off-by: Nico Schottelius --- cdist/emulator.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index dedb52ed..2d344f09 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -29,8 +29,9 @@ import cdist from cdist import core class Emulator(object): - def __init__(self, argv): + def __init__(self, argv, stdin=sys.stdin): self.argv = argv + self.stdin = stdin self.object_id = False self.global_path = os.environ['__global'] @@ -148,13 +149,13 @@ class Emulator(object): chunk_size = 8192 def _read_stdin(self): - return sys.stdin.buffer.read(self.chunk_size) + return self.stdin.buffer.read(self.chunk_size) def save_stdin(self): """If something is written to stdin, save it in the object as $__object/stdin so it can be accessed in manifest and gencode-* scripts. """ - if not sys.stdin.isatty(): + if not self.stdin.isatty(): try: # go directly to file instead of using CdistObject's api # as that does not support streaming From a32d3abd338937e1b7d9331204a477eb93746d80 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 10:25:47 +0100 Subject: [PATCH 1782/4212] allow to pass in environment into emulator Signed-off-by: Nico Schottelius --- cdist/emulator.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 2d344f09..f65c9bec 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -29,17 +29,17 @@ import cdist from cdist import core class Emulator(object): - def __init__(self, argv, stdin=sys.stdin): + def __init__(self, argv, stdin=sys.stdin, env=os.environ): self.argv = argv self.stdin = stdin self.object_id = False - self.global_path = os.environ['__global'] - self.target_host = os.environ['__target_host'] + self.global_path = self.env['__global'] + self.target_host = self.env['__target_host'] # Internally only - self.object_source = os.environ['__cdist_manifest'] - self.type_base_path = os.environ['__cdist_type_base_path'] + self.object_source = self.env['__cdist_manifest'] + self.type_base_path = self.env['__cdist_type_base_path'] self.object_base_path = os.path.join(self.global_path, "object") @@ -63,7 +63,7 @@ class Emulator(object): def run(self): """Emulate type commands (i.e. __file and co)""" - if '__install' in os.environ: + 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 @@ -80,7 +80,7 @@ class Emulator(object): logformat = '%(levelname)s: %(message)s' logging.basicConfig(format=logformat) - if '__cdist_debug' in os.environ: + if '__cdist_debug' in self.env: logging.root.setLevel(logging.DEBUG) else: logging.root.setLevel(logging.INFO) @@ -171,8 +171,8 @@ class Emulator(object): def record_requirements(self): """record requirements""" - if "require" in os.environ: - requirements = os.environ['require'] + if "require" in self.env: + requirements = self.env['require'] self.log.debug("reqs = " + requirements) for requirement in requirements.split(" "): # Ignore empty fields - probably the only field anyway @@ -192,7 +192,7 @@ class Emulator(object): """An object shall automatically depend on all objects that it defined in it's type manifest. """ # __object_name is the name of the object whose type manifest is currently executed - __object_name = os.environ.get('__object_name', None) + __object_name = self.env.get('__object_name', None) if __object_name: # The object whose type manifest is currently run parent = self.cdist_object.object_from_name(__object_name) From 1e4833781efb3bb38109a0348470597bed941113 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 10:48:30 +0100 Subject: [PATCH 1783/4212] distinguish between user supplied and derived manifest on error printing Signed-off-by: Nico Schottelius --- cdist/core/manifest.py | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 74d45947..1e34afbf 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -57,6 +57,29 @@ type manifeste is: creates: new objects through type emulator ''' +class NoInitialManifestError(cdist.Error): + """ + Display missing initial manifest: + - Display path if user given + - try to resolve link if it is a link + - Omit path if default (is a linked path in temp directory without + much help) + """ + + def __init__(self, manifest_path, user_supplied): + msg_header = "Initial manifest missing" + + if user_supplied: + if os.path.islink(manifest_path): + self.message = "%s: %s -> %s" (msg_header, manifest_path, os.path.realpath(manifest_path)) + else: + self.message = "%s: %s" (msg_header, manifest_path) + else: + self.message = "%s" (msg_header) + + def __str__(self): + return repr(self.message) + class Manifest(object): """Executes cdist manifests. @@ -70,44 +93,47 @@ class Manifest(object): self.env = { 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), - '__target_host': self.target_host, - '__global': self.local.out_path, '__cdist_type_base_path': self.local.type_path, # for use in type emulator + '__global': self.local.out_path, + '__target_host': self.target_host, } if self.log.getEffectiveLevel() == logging.DEBUG: self.env.update({'__cdist_debug': "yes" }) - def env_initial_manifest(self, script): + def env_initial_manifest(self, initial_manifest): env = os.environ.copy() env.update(self.env) + env['__cdist_manifest'] = initial_manifest env['__manifest'] = self.local.manifest_path - env['__cdist_manifest'] = script return env def run_initial_manifest(self, initial_manifest=None): if not initial_manifest: initial_manifest = self.local.initial_manifest + user_supplied = False + else: + user_supplied = True self.log.info("Running initial manifest " + initial_manifest) if not os.path.isfile(initial_manifest): - raise cdist.Error("Initial manifest is missing: %s" % initial_manifest) + raise NoInitialManifestError(initial_manifest, user_supplied) - self.local.run_script(script, env=self.env_initial_manifest(initial_manifest)) + self.local.run_script(initial_manifest, env=self.env_initial_manifest(initial_manifest)) def env_type_manifest(self, cdist_object): type_manifest = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) env = os.environ.copy() env.update(self.env) env.update({ + '__cdist_manifest': type_manifest, '__manifest': self.local.manifest_path, '__object': cdist_object.absolute_path, '__object_id': cdist_object.object_id, '__object_name': cdist_object.name, '__type': cdist_object.cdist_type.absolute_path, - '__cdist_manifest': type_manifest, }) return env From 45d5e4719a83185670b4b57a469f166494c387e3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 10:49:11 +0100 Subject: [PATCH 1784/4212] read from stdin using read, not buffer.read() to be compatible with other IO streams Signed-off-by: Nico Schottelius --- cdist/emulator.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index f65c9bec..53c6914d 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -32,6 +32,8 @@ class Emulator(object): def __init__(self, argv, stdin=sys.stdin, env=os.environ): self.argv = argv self.stdin = stdin + self.env = env + self.object_id = False self.global_path = self.env['__global'] @@ -147,9 +149,8 @@ class Emulator(object): # Record / Append source self.cdist_object.source.append(self.object_source) - chunk_size = 8192 def _read_stdin(self): - return self.stdin.buffer.read(self.chunk_size) + return self.stdin.read() def save_stdin(self): """If something is written to stdin, save it in the object as $__object/stdin so it can be accessed in manifest and gencode-* From 217d2bcb23516b3cfe5fa733928db91a6b8fdbca Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 10:49:51 +0100 Subject: [PATCH 1785/4212] Fix test: StdinTestCase Signed-off-by: Nico Schottelius --- cdist/test/autorequire/__init__.py | 1 - cdist/test/emulator/__init__.py | 69 ++++++++++++------- cdist/test/emulator/fixtures/conf/type/__file | 1 - 3 files changed, 45 insertions(+), 26 deletions(-) delete mode 120000 cdist/test/emulator/fixtures/conf/type/__file diff --git a/cdist/test/autorequire/__init__.py b/cdist/test/autorequire/__init__.py index 4b47b06b..2a647954 100644 --- a/cdist/test/autorequire/__init__.py +++ b/cdist/test/autorequire/__init__.py @@ -42,7 +42,6 @@ class AutorequireTestCase(test.CdistTestCase): def setUp(self): self.orig_environ = os.environ os.environ = os.environ.copy() - self.target_host = 'localhost' self.temp_dir = self.mkdtemp() self.out_dir = os.path.join(self.temp_dir, "out") diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 26530f44..ec254a21 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -20,6 +20,7 @@ # # +import io import os import shutil import string @@ -141,7 +142,6 @@ class ArgumentsTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() - self.target_host = 'localhost' out_path = self.temp_dir handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) @@ -236,38 +236,59 @@ class StdinTestCase(test.CdistTestCase): def setUp(self): self.orig_environ = os.environ os.environ = os.environ.copy() - self.target_host = 'localhost' + self.temp_dir = self.mkdtemp() - os.environ['__cdist_out_dir'] = self.temp_dir + out_path = os.path.join(self.temp_dir, "out") - self.context = cdist.context.Context( + self.local = local.Local( target_host=self.target_host, - remote_copy='scp -o User=root -q', - remote_exec='ssh -o User=root -q', + out_path=out_path, exec_path=test.cdist_exec_path, - debug=False) - self.config = config.Config(self.context) + add_conf_dirs=[conf_dir]) + self.local.create_files_dirs() + + self.manifest = core.Manifest( + target_host=self.target_host, + local = self.local) + def tearDown(self): os.environ = self.orig_environ shutil.rmtree(self.temp_dir) def test_file_from_stdin(self): - handle, destination = self.mkstemp(dir=self.temp_dir) - os.close(handle) - source_handle, source = self.mkstemp(dir=self.temp_dir) - candidates = string.ascii_letters+string.digits - with os.fdopen(source_handle, 'w') as fd: - for x in range(100): - fd.write(''.join(random.sample(candidates, len(candidates)))) + """ + Test whether reading from stdin works + """ - handle, initial_manifest = self.mkstemp(dir=self.temp_dir) - with os.fdopen(handle, 'w') as fd: - fd.write('__file_from_stdin %s --source %s\n' % (destination, source)) - self.context.initial_manifest = initial_manifest - self.config.stage_prepare() + ###################################################################### + # Create string with random content + random_string = str(random.sample(range(1000), 800)) + random_buffer = io.BytesIO(bytes(random_string, 'utf-8')) - cdist_type = core.CdistType(self.config.local.type_path, '__file') - cdist_object = core.CdistObject(cdist_type, self.config.local.object_path, destination) - # Test weither stdin has been stored correctly - self.assertTrue(filecmp.cmp(source, os.path.join(cdist_object.absolute_path, 'stdin'))) + ###################################################################### + # Prepare required args and environment for emulator + type_name = '__file' + object_id = "cdist-test-id" + argv = [type_name, object_id] + + initial_manifest_path = "/cdist-test/path/that/does/not/exist" + env = self.manifest.env_initial_manifest(initial_manifest_path) + + ###################################################################### + # Create path where stdin should reside at + cdist_type = core.CdistType(self.local.type_path, type_name) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, object_id) + stdin_out_path = os.path.join(cdist_object.absolute_path, 'stdin') + + ###################################################################### + # Run emulator + emu = emulator.Emulator(argv, stdin=random_buffer, env=env) + emu.run() + + ###################################################################### + # Read where emulator should have placed stdin + with open(stdin_out_path, 'r') as fd: + stdin_saved_by_emulator = fd.read() + + self.assertEqual(random_string, stdin_saved_by_emulator) diff --git a/cdist/test/emulator/fixtures/conf/type/__file b/cdist/test/emulator/fixtures/conf/type/__file deleted file mode 120000 index 1ed684b9..00000000 --- a/cdist/test/emulator/fixtures/conf/type/__file +++ /dev/null @@ -1 +0,0 @@ -../../../../../conf/type/__file \ No newline at end of file From 4dd0f61934cb2123eafefe9a16d65b9b86406040 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 10:51:13 +0100 Subject: [PATCH 1786/4212] --whitespace Signed-off-by: Nico Schottelius --- cdist/test/emulator/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index ec254a21..ecbb97a3 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -212,7 +212,7 @@ class ArgumentsTestCase(test.CdistTestCase): # argv = [type_name, object_id, '--required1', value] # os.environ.update(self.env) # emu = emulator.Emulator(argv) -# +# # self.assertRaises(SystemExit, emu.run) def test_optional(self): @@ -251,7 +251,7 @@ class StdinTestCase(test.CdistTestCase): self.manifest = core.Manifest( target_host=self.target_host, local = self.local) - + def tearDown(self): os.environ = self.orig_environ shutil.rmtree(self.temp_dir) From e2e1d0bb67cfb4578177c0b2cd3ce86fbda5e76c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 11:05:29 +0100 Subject: [PATCH 1787/4212] include % Signed-off-by: Nico Schottelius --- cdist/core/manifest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 1e34afbf..19639618 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -71,11 +71,11 @@ class NoInitialManifestError(cdist.Error): if user_supplied: if os.path.islink(manifest_path): - self.message = "%s: %s -> %s" (msg_header, manifest_path, os.path.realpath(manifest_path)) + self.message = "%s: %s -> %s" % (msg_header, manifest_path, os.path.realpath(manifest_path)) else: - self.message = "%s: %s" (msg_header, manifest_path) + self.message = "%s: %s" % (msg_header, manifest_path) else: - self.message = "%s" (msg_header) + self.message = "%s" % (msg_header) def __str__(self): return repr(self.message) From 7d57d1df79a6e91efbe50eeddfe501085f96496e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 11:05:40 +0100 Subject: [PATCH 1788/4212] update emulator tests to work again Signed-off-by: Nico Schottelius --- cdist/test/emulator/__init__.py | 57 +++++++++++---------------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index ecbb97a3..fc0b6695 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -40,12 +40,9 @@ my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') conf_dir = op.join(fixtures, 'conf') -import logging class EmulatorTestCase(test.CdistTestCase): def setUp(self): - self.orig_environ = os.environ - os.environ = os.environ.copy() self.temp_dir = self.mkdtemp() handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) @@ -56,72 +53,61 @@ class EmulatorTestCase(test.CdistTestCase): out_path=out_path, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) - logging.root.setLevel(logging.DEBUG) 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): - os.environ = self.orig_environ shutil.rmtree(self.temp_dir) def test_nonexistent_type_exec(self): argv = ['__does-not-exist'] - os.environ.update(self.env) - self.assertRaises(core.NoSuchTypeError, emulator.Emulator, argv) + self.assertRaises(core.NoSuchTypeError, emulator.Emulator, argv, env=self.env) def test_nonexistent_type_requirement(self): argv = ['__file', '/tmp/foobar'] - os.environ.update(self.env) - os.environ['require'] = '__does-not-exist/some-id' - emu = emulator.Emulator(argv) + self.env['require'] = '__does-not-exist/some-id' + emu = emulator.Emulator(argv, env=self.env) self.assertRaises(core.NoSuchTypeError, emu.run) def test_illegal_object_id_requirement(self): argv = ['__file', '/tmp/foobar'] - os.environ.update(self.env) - os.environ['require'] = '__file/bad/id/with/.cdist/inside' - emu = emulator.Emulator(argv) + self.env['require'] = '__file/bad/id/with/.cdist/inside' + emu = emulator.Emulator(argv, env=self.env) self.assertRaises(core.IllegalObjectIdError, emu.run) def test_missing_object_id_requirement(self): argv = ['__file', '/tmp/foobar'] - os.environ.update(self.env) - os.environ['require'] = '__file' - emu = emulator.Emulator(argv) + self.env['require'] = '__file' + emu = emulator.Emulator(argv, env=self.env) self.assertRaises(core.IllegalObjectIdError, emu.run) def test_singleton_object_requirement(self): argv = ['__file', '/tmp/foobar'] - os.environ.update(self.env) - os.environ['require'] = '__issue' - emu = emulator.Emulator(argv) + self.env['require'] = '__issue' + emu = emulator.Emulator(argv, env=self.env) emu.run() # if we get here all is fine def test_requirement_pattern(self): argv = ['__file', '/tmp/foobar'] - os.environ.update(self.env) - os.environ['require'] = '__file/etc/*' - emu = emulator.Emulator(argv) + self.env['require'] = '__file/etc/*' + emu = emulator.Emulator(argv, env=self.env) # if we get here all is fine -import os.path as op -my_dir = op.abspath(op.dirname(__file__)) -fixtures = op.join(my_dir, 'fixtures') - class AutoRequireEmulatorTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() - self.target_host = 'localhost' - out_path = self.temp_dir + out_path = os.path.join(self.temp_dir, "out") + self.local = local.Local( target_host=self.target_host, out_path=out_path, - exec_path=test.cdist_exec_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) @@ -149,17 +135,12 @@ class ArgumentsTestCase(test.CdistTestCase): self.local = local.Local( target_host=self.target_host, out_path=out_path, - exec_path=test.cdist_exec_path) + exec_path=test.cdist_exec_path, + add_conf_dirs=[conf_dir]) self.local.create_files_dirs() - self.env = { - 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), - '__target_host': self.target_host, - '__global': self.local.out_path, - '__cdist_type_base_path': self.local.type_path, # for use in type emulator - '__manifest': self.local.manifest_path, - '__cdist_manifest': self.script, - } + 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) From 1bb3c82d729a1c0b721f10000e2012218812d467 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 11:47:26 +0100 Subject: [PATCH 1789/4212] cleanup some logging stuff Signed-off-by: Nico Schottelius --- cdist/test/code/__init__.py | 5 +---- cdist/test/explorer/__init__.py | 3 --- cdist/test/manifest/__init__.py | 2 ++ 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index f5d445ab..284ef9c0 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -20,10 +20,9 @@ # # +import getpass import os import shutil -import getpass -import logging import cdist from cdist import core @@ -63,8 +62,6 @@ class CodeTestCase(test.CdistTestCase): self.cdist_object = core.CdistObject(self.cdist_type, self.local.object_path, 'whatever') self.cdist_object.create() - self.log = logging.getLogger("cdist") - def tearDown(self): shutil.rmtree(self.out_path) shutil.rmtree(self.remote_base_path) diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index 266a1073..a97b538a 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -23,7 +23,6 @@ import os import shutil import getpass -import logging import cdist from cdist import core @@ -67,8 +66,6 @@ class ExplorerClassTestCase(test.CdistTestCase): self.local, self.remote) - self.log = logging.getLogger(self.target_host) - def tearDown(self): shutil.rmtree(self.temp_dir) diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index 0de04743..727017e7 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -107,6 +107,8 @@ class ManifestTestCase(test.CdistTestCase): self.assertEqual(output_dict['__object_name'], cdist_object.name) def test_debug_env_setup(self): + current_level = self.log.getEffectiveLevel() self.log.setLevel(logging.DEBUG) manifest = cdist.core.manifest.Manifest(self.target_host, self.local) self.assertTrue("__cdist_debug" in manifest.env) + self.log.setLevel(current_level) From 37ea64d23b00e6f70e288ebb266950ac8d755f93 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 12:12:26 +0100 Subject: [PATCH 1790/4212] automate blog & ml Signed-off-by: Nico Schottelius --- build | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/build b/build index def72470..776da03f 100755 --- a/build +++ b/build @@ -35,6 +35,7 @@ A2XH="a2x -f xhtml --no-xmllint -a encoding=UTF-8" # Developer webbase WEBDIR=$HOME/niconetz +WEBBLOG=$WEBDIR/blog WEBBASE=$WEBDIR/software/cdist WEBMAN=$WEBBASE/man/$version WEBPAGE=${WEBBASE}.mdwn @@ -108,9 +109,14 @@ case "$1" in $0 pub + $0 dist-blog $0 dist-freecode + $0 dist-ml + $0 dist-manual + ;; - $0 dist-post + 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" ;; changelog-version) @@ -144,15 +150,78 @@ case "$1" in ;; - dist-post) + blog) + version=$($0 changelog-version) + blogfile=$WEBBLOG/cdist-${version}-released.mdwn + cat << eof > "$blogfile" +[[!meta title="Cdist $version released"]] + +Here's a short overview about the changes found in this release: + +eof + + $0 changelog-changes >> "$blogfile" + + cat << eof >> "$blogfile" +For more information visit the [[cdist homepage|software/cdist]]. + +[[!tag cdist config unix]] +eof + ;; + + dist-blog) + $0 blog + version=$($0 changelog-version) + file=cdist-${version}-released.mdwn + cd $WEBBBLOG + git add "$file" + git commit -m "New cdist version (blogentry): $version" "$file" + git push + ;; + + dist-ml) + $0 blog + version=$($0 changelog-version) + to_a=cdist + to_d=l.schottelius.org + to=${to_a}@${to_d} + + from_a=nico-cdist + from_d=schottelius.org + from=${from_a}@${from_d} + + ( + cat << eof +From: Nico -telmich- Schottelius <$from> +To: cdist mailing list <$to> +Subject: [cdist] cdist $version released + +Hello .*, + +cdist $version has been released with the following changes: + +eof + + "$0" changelog-changes + cat << eof + +Cheers, + +Nico + +-- +Automatisation at its best level. With cdist. +eof + ) | /usr/sbin/sendmail -f "$from" "$to" + ;; + + + dist-manual) cat << notes To be done manually... - - freecode release - - blog entry - linkedin entry - - mailinglist update notes ;; From c53d1807524c30ee497782dae347e1026a595329 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 12:12:33 +0100 Subject: [PATCH 1791/4212] release 2.1.0pre7 Signed-off-by: Nico Schottelius --- docs/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index 93c3cf69..f8030609 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.1.0pre7: - * Core: Tests for autorequire, code, manifest work again +2.1.0pre7: 2012-11-07 + * Core: All unit tests restored back to working * Core: Print error message on missing initial manifest 2.1.0pre6: 2012-11-05 From e786803daec2d598bcc2853469dccb297e0d6cfc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 12:13:06 +0100 Subject: [PATCH 1792/4212] strip prefix away Signed-off-by: Nico Schottelius --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index 776da03f..34775a31 100755 --- a/build +++ b/build @@ -194,7 +194,7 @@ eof cat << eof From: Nico -telmich- Schottelius <$from> To: cdist mailing list <$to> -Subject: [cdist] cdist $version released +Subject: cdist $version released Hello .*, From 7a1f81dc7b15defa8ae41fdf9f227dd8213fead1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 7 Nov 2012 16:54:34 +0100 Subject: [PATCH 1793/4212] remove install types Signed-off-by: Steven Armstrong --- cdist/conf/type/__mkfs/gencode-remote | 38 ----- cdist/conf/type/__mkfs/install | 0 cdist/conf/type/__mkfs/man.text | 57 -------- cdist/conf/type/__mkfs/manifest | 31 ---- cdist/conf/type/__mkfs/parameter/optional | 3 - cdist/conf/type/__mkfs/parameter/required | 1 - cdist/conf/type/__partition_msdos/install | 0 cdist/conf/type/__partition_msdos/man.text | 62 -------- cdist/conf/type/__partition_msdos/manifest | 41 ------ .../type/__partition_msdos/parameter/optional | 3 - .../type/__partition_msdos/parameter/required | 1 - .../explorer/partitions | 3 - .../type/__partition_msdos_apply/files/lib.sh | 61 -------- .../__partition_msdos_apply/gencode-remote | 138 ------------------ .../conf/type/__partition_msdos_apply/install | 0 .../type/__partition_msdos_apply/man.text | 42 ------ .../type/__partition_msdos_apply/singleton | 0 17 files changed, 481 deletions(-) delete mode 100755 cdist/conf/type/__mkfs/gencode-remote delete mode 100644 cdist/conf/type/__mkfs/install delete mode 100644 cdist/conf/type/__mkfs/man.text delete mode 100755 cdist/conf/type/__mkfs/manifest delete mode 100644 cdist/conf/type/__mkfs/parameter/optional delete mode 100644 cdist/conf/type/__mkfs/parameter/required delete mode 100644 cdist/conf/type/__partition_msdos/install delete mode 100644 cdist/conf/type/__partition_msdos/man.text delete mode 100755 cdist/conf/type/__partition_msdos/manifest delete mode 100644 cdist/conf/type/__partition_msdos/parameter/optional delete mode 100644 cdist/conf/type/__partition_msdos/parameter/required delete mode 100755 cdist/conf/type/__partition_msdos_apply/explorer/partitions delete mode 100644 cdist/conf/type/__partition_msdos_apply/files/lib.sh delete mode 100755 cdist/conf/type/__partition_msdos_apply/gencode-remote delete mode 100644 cdist/conf/type/__partition_msdos_apply/install delete mode 100644 cdist/conf/type/__partition_msdos_apply/man.text delete mode 100644 cdist/conf/type/__partition_msdos_apply/singleton diff --git a/cdist/conf/type/__mkfs/gencode-remote b/cdist/conf/type/__mkfs/gencode-remote deleted file mode 100755 index b3561bad..00000000 --- a/cdist/conf/type/__mkfs/gencode-remote +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# - -device="$(cat "$__object/parameter/device")" -type="$(cat "$__object/parameter/type")" - -if [ "$type" = "swap" ]; then - echo "mkswap $device" -else - command="mkfs -t $type -q" - if [ -f "$__object/parameter/options" ]; then - options="$(cat "$__object/parameter/options")" - command="$command $options" - fi - command="$command $device" - if [ -f "$__object/parameter/blocks" ]; then - blocks="$(cat "$__object/parameter/blocks")" - command="$command $blocks" - fi - echo "$command" -fi diff --git a/cdist/conf/type/__mkfs/install b/cdist/conf/type/__mkfs/install deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/conf/type/__mkfs/man.text b/cdist/conf/type/__mkfs/man.text deleted file mode 100644 index 4320c639..00000000 --- a/cdist/conf/type/__mkfs/man.text +++ /dev/null @@ -1,57 +0,0 @@ -cdist-type__mkfs(7) -=================== -Steven Armstrong - - -NAME ----- -cdist-type__mkfs - build a linux file system - - -DESCRIPTION ------------ -This cdist type is a wrapper for the mkfs command. - - -REQUIRED PARAMETERS -------------------- -type:: - The filesystem type to use. Same as mkfs -t. - - -OPTIONAL PARAMETERS -------------------- -device:: - defaults to object_id - -options:: - file system-specific options to be passed to the mkfs command - -blocks:: - the number of blocks to be used for the file system - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# reiserfs /dev/sda5 -__mkfs /dev/sda5 --type reiserfs -# same thing with explicit device -__mkfs whatever --device /dev/sda5 --type reiserfs - -# jfs with journal on /dev/sda2 -__mkfs /dev/sda1 --type jfs --options "-j /dev/sda2" --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- mkfs(8) - - -COPYING -------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__mkfs/manifest b/cdist/conf/type/__mkfs/manifest deleted file mode 100755 index e9d275a4..00000000 --- a/cdist/conf/type/__mkfs/manifest +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -# -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# - -# set defaults -if [ -f "$__object/parameter/device" ]; then - device="(cat "$__object/parameter/device")" -else - device="/$__object_id" - echo "$device" > "$__object/parameter/device" -fi - -type="(cat "$__object/parameter/type")" - -options="(cat "$__object/parameter/options")" diff --git a/cdist/conf/type/__mkfs/parameter/optional b/cdist/conf/type/__mkfs/parameter/optional deleted file mode 100644 index 86aeae30..00000000 --- a/cdist/conf/type/__mkfs/parameter/optional +++ /dev/null @@ -1,3 +0,0 @@ -device -options -blocks diff --git a/cdist/conf/type/__mkfs/parameter/required b/cdist/conf/type/__mkfs/parameter/required deleted file mode 100644 index aa80e646..00000000 --- a/cdist/conf/type/__mkfs/parameter/required +++ /dev/null @@ -1 +0,0 @@ -type diff --git a/cdist/conf/type/__partition_msdos/install b/cdist/conf/type/__partition_msdos/install deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/conf/type/__partition_msdos/man.text b/cdist/conf/type/__partition_msdos/man.text deleted file mode 100644 index 78220ee0..00000000 --- a/cdist/conf/type/__partition_msdos/man.text +++ /dev/null @@ -1,62 +0,0 @@ -cdist-type__partition_msdos(7) -============================== -Steven Armstrong - - -NAME ----- -cdist-type__partition_msdos - creates msdos partitions - - -DESCRIPTION ------------ -This cdist type allows you to create msdos paritions. - - -REQUIRED PARAMETERS -------------------- -type:: - the partition type used in fdisk (such as 82 or 83) or "extended" - - -OPTIONAL PARAMETERS -------------------- -partition:: - defaults to object_id -bootable:: - mark partition as bootable, true or false, defaults to false -size:: - the size of the partition (such as 32M or 15G, whole numbers - only), '+' for remaining space, or 'n%' for percentage of remaining - (these should only be used after all specific partition sizes are - specified). Defaults to +. - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# 128MB, linux, bootable -__partition_msdos /dev/sda1 --type 83 --size 128M --bootable true -# 512MB, swap -__partition_msdos /dev/sda2 --type 82 --size 512M -# 100GB, extended -__partition_msdos /dev/sda3 --type extended --size 100G -# 10GB, linux -__partition_msdos /dev/sda5 --type 83 --size 10G -# 50% of the free space of the extended partition, linux -__partition_msdos /dev/sda6 --type 83 --size 50% -# rest of the extended partition, linux -__partition_msdos /dev/sda7 --type 83 --size + --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__partition_msdos/manifest b/cdist/conf/type/__partition_msdos/manifest deleted file mode 100755 index 21e43856..00000000 --- a/cdist/conf/type/__partition_msdos/manifest +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -# -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# - -# set defaults -if [ -f "$__object/parameter/partition" ]; then - partition="(cat "$__object/parameter/partition")" -else - partition="/$__object_id" - echo "$partition" > "$__object/parameter/partition" -fi -device="$(echo "$partition" | sed 's/[0-9]//g')" -echo "$device" > "$__object/parameter/device" -minor="$(echo "$partition" | sed 's/[^0-9]//g')" -echo "$minor" > "$__object/parameter/minor" - -if [ ! -f "$__object/parameter/bootable" ]; then - echo "false" > "$__object/parameter/bootable" -fi -if [ ! -f "$__object/parameter/size" ]; then - echo "+" > "$__object/parameter/size" -fi - -# pull in the type that actually does something with the above parameters -require="$__object_name" __partition_msdos_apply diff --git a/cdist/conf/type/__partition_msdos/parameter/optional b/cdist/conf/type/__partition_msdos/parameter/optional deleted file mode 100644 index b2b0a4c2..00000000 --- a/cdist/conf/type/__partition_msdos/parameter/optional +++ /dev/null @@ -1,3 +0,0 @@ -partition -bootable -size diff --git a/cdist/conf/type/__partition_msdos/parameter/required b/cdist/conf/type/__partition_msdos/parameter/required deleted file mode 100644 index aa80e646..00000000 --- a/cdist/conf/type/__partition_msdos/parameter/required +++ /dev/null @@ -1 +0,0 @@ -type diff --git a/cdist/conf/type/__partition_msdos_apply/explorer/partitions b/cdist/conf/type/__partition_msdos_apply/explorer/partitions deleted file mode 100755 index 6be61af4..00000000 --- a/cdist/conf/type/__partition_msdos_apply/explorer/partitions +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -cat /proc/partitions diff --git a/cdist/conf/type/__partition_msdos_apply/files/lib.sh b/cdist/conf/type/__partition_msdos_apply/files/lib.sh deleted file mode 100644 index 5767ea43..00000000 --- a/cdist/conf/type/__partition_msdos_apply/files/lib.sh +++ /dev/null @@ -1,61 +0,0 @@ -die() { - echo "[__partition_msdos_apply] $@" >&2 - exit 1 -} -debug() { - #echo "[__partition_msdos_apply] $@" >&2 - : -} - -fdisk_command() { - local device="$1" - local cmd="$2" - - debug fdisk_command "running fdisk command '${cmd}' on device ${device}" - printf "${cmd}\nw\n" | fdisk -c -u "$device" - # give disk some time - sleep 1 - return $? -} - -create_disklabel() { - local device=$1 - - debug create_disklabel "creating new msdos disklabel" - fdisk_command ${device} "o" - return $? -} - -create_partition() { - local device="$1" - local minor="$2" - local size="$3" - local type="$4" - local primary_count="$5" - - if [ "$type" = "extended" -o "$type" = "5" ]; then - # Extended partition - primary_extended="e\n" - first_minor="${minor}\n" - [ "${minor}" = "4" ] && first_minor="" - type_minor="${minor}\n" - [ "${minor}" = "1" ] && type_minor="" - type="5" - elif [ "${minor}" -lt "5" ]; then - primary_extended="p\n" - first_minor="${minor}\n" - [ "${minor}" = "4" ] && first_minor="" - type_minor="${minor}\n" - [ "${minor}" = "1" ] && type_minor="" - else - # Logical partitions - first_minor="${minor}\n" - type_minor="${minor}\n" - primary_extended="l\n" - [ "$primary_count" -gt "3" ] && primary_extended="" - fi - [ -n "${size}" ] && size="+${size}M" - fdisk_command ${device} "n\n${primary_extended}${first_minor}\n${size}\nt\n${type_minor}${type}\n" - return $? -} - diff --git a/cdist/conf/type/__partition_msdos_apply/gencode-remote b/cdist/conf/type/__partition_msdos_apply/gencode-remote deleted file mode 100755 index 5dab7070..00000000 --- a/cdist/conf/type/__partition_msdos_apply/gencode-remote +++ /dev/null @@ -1,138 +0,0 @@ -#!/bin/sh -# -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# - -die() { - echo "[__partition_msdos_apply] $@" >&2 - exit 1 -} -debug() { - #echo "[__partition_msdos_apply] $@" >&2 - : -} - -# Convert a size specifier 1G 100M or 50% into the corresponding numeric MB. -size_to_mb() { - local size=$1 - local available_size="$2" - - local number_suffix="$(echo ${size} | sed -e 's:\.[0-9]\+::' -e 's:\([0-9]\+\)\([MmGg%]\)[Bb]\?:\1|\2:')" - local number="$(echo ${number_suffix} | cut -d '|' -f1)" - local suffix="$(echo ${number_suffix} | cut -d '|' -f2)" - - case "$suffix" in - M|m) - size="$number" - ;; - G|g) - size="$(( $number * 1024 ))" - ;; - %) - size="$(( $available_size * $number / 100 ))" - ;; - *) - size="-1" - esac - echo "$size" -} - -# include function library for use on target -cat "$__type/files/lib.sh" - -partitions="$__object/explorer/partitions" -objects=$(find "$__global/object/__partition_msdos" -path "*.cdist") -current_device="" -available_device_size= -available_extended_size= -available_size= -primary_count=0 -for object in $objects; do - device="$(cat "$object/parameter/device")" - if [ "$current_device" != "$device" ]; then - echo "create_disklabel \"$device\" || die 'Failed to create disklabel for $device'" - current_device="$device" - device_name=$(echo ${device} | sed -e 's:^/dev/::;s:/:\\/:g') - available_device_size=$(( $(awk "/${device_name}\$/ { print \$3; }" "$partitions") / 1024)) - # make sure we don't go past the end of the drive - available_device_size=$((available_device_size - 2)) - available_extended_size=0 - primary_count=0 - debug "----- $device" - debug "current_device=$current_device" - debug "available_device_size=$available_device_size" - fi - - type="$(cat "$object/parameter/type")" - partition="$(cat "$object/parameter/partition")" - minor="$(cat "$object/parameter/minor")" - - bootable="$(cat "$object/parameter/bootable")" - size="$(cat "$object/parameter/size")" - - - if [ "${minor}" -lt "5" ]; then - # Primary partitions - primary_count=$(( $primary_count + 1 )) - available_size=$available_device_size - else - # Logical partitions - available_size=$available_extended_size - fi - - if [ "$size" = "+" ]; then - # use rest of device - partition_size="" - available_size=0 - else - partition_size=$(size_to_mb "$size" "$available_size") - available_size="$(( $available_size - $partition_size ))" - fi - - if [ "${minor}" -lt "5" ]; then - # Primary partitions - available_device_size=$available_size - if [ "$type" = "extended" -o "$type" = "5" ]; then - # Extended partition - available_extended_size=$partition_size - fi - else - # Logical paritions - available_extended_size=$available_size - fi - - [ "$partition_size" = "-1" ] && die "could not translate size '$size' to a usable value" - debug "----- $partition" - debug "primary_count=$primary_count" - debug "current_device=$current_device" - debug "device=$device" - debug "type=$type" - debug "partition=$partition" - debug "minor=$minor" - debug "bootable=$bootable" - debug "size=$size" - debug "partition_size=$partition_size" - debug "available_size=$available_size" - debug "available_device_size=$available_device_size" - debug "available_extended_size=$available_extended_size" - debug "----------" - - echo "create_partition '$device' '$minor' '$partition_size' '$type' '$primary_count' \ - || die 'Failed to create partition: $partition'" -done - diff --git a/cdist/conf/type/__partition_msdos_apply/install b/cdist/conf/type/__partition_msdos_apply/install deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/conf/type/__partition_msdos_apply/man.text b/cdist/conf/type/__partition_msdos_apply/man.text deleted file mode 100644 index 6cc53b77..00000000 --- a/cdist/conf/type/__partition_msdos_apply/man.text +++ /dev/null @@ -1,42 +0,0 @@ -cdist-type__partition_msdos_apply(7) -==================================== -Steven Armstrong - - -NAME ----- -cdist-type__partition_msdos_apply - Apply dos partition settings - - -DESCRIPTION ------------ -Create the partitions defined with __partition_msdos - - -REQUIRED PARAMETERS -------------------- -None - - -OPTIONAL PARAMETERS -------------------- -None. - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -__partition_msdos_apply --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- cdist-type__partition_msdos_apply(7) - -COPYING -------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__partition_msdos_apply/singleton b/cdist/conf/type/__partition_msdos_apply/singleton deleted file mode 100644 index e69de29b..00000000 From 03cc2a63b163fabd2654843acbabba5d00301d1b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 7 Nov 2012 14:28:30 +0100 Subject: [PATCH 1794/4212] types to handle autofs maps Signed-off-by: Steven Armstrong --- cdist/conf/type/__autofs/man.text | 42 +++++++++ .../gencode-local => __autofs/manifest} | 26 ++++-- .../{__autofs_master => __autofs}/singleton | 0 cdist/conf/type/__autofs_map/explorer/entry | 50 ++++++++++ cdist/conf/type/__autofs_map/gencode-remote | 93 +++++++++++++++++++ cdist/conf/type/__autofs_map/man.text | 20 +++- cdist/conf/type/__autofs_map/manifest | 45 +++++---- .../conf/type/__autofs_map/parameter/boolean | 1 + .../__autofs_master/files/auto.master.header | 3 - .../type/__autofs_master/parameter/optional | 1 - .../gencode-remote} | 24 +++-- .../man.text | 23 ++--- cdist/conf/type/__autofs_reload/singleton | 0 13 files changed, 273 insertions(+), 55 deletions(-) create mode 100644 cdist/conf/type/__autofs/man.text rename cdist/conf/type/{__autofs_master/gencode-local => __autofs/manifest} (59%) rename cdist/conf/type/{__autofs_master => __autofs}/singleton (100%) create mode 100755 cdist/conf/type/__autofs_map/explorer/entry create mode 100755 cdist/conf/type/__autofs_map/gencode-remote create mode 100644 cdist/conf/type/__autofs_map/parameter/boolean delete mode 100644 cdist/conf/type/__autofs_master/files/auto.master.header delete mode 100644 cdist/conf/type/__autofs_master/parameter/optional rename cdist/conf/type/{__autofs_master/manifest => __autofs_reload/gencode-remote} (62%) rename cdist/conf/type/{__autofs_master => __autofs_reload}/man.text (51%) create mode 100644 cdist/conf/type/__autofs_reload/singleton diff --git a/cdist/conf/type/__autofs/man.text b/cdist/conf/type/__autofs/man.text new file mode 100644 index 00000000..9b343309 --- /dev/null +++ b/cdist/conf/type/__autofs/man.text @@ -0,0 +1,42 @@ +cdist-type__autofs(7) +===================== +Steven Armstrong + + +NAME +---- +cdist-type__autofs - install and start autofs + + +DESCRIPTION +----------- +This space intentionally left blank. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__autofs +-------------------------------------------------------------------------------- + + +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/__autofs_master/gencode-local b/cdist/conf/type/__autofs/manifest similarity index 59% rename from cdist/conf/type/__autofs_master/gencode-local rename to cdist/conf/type/__autofs/manifest index 701f97a8..31844415 100755 --- a/cdist/conf/type/__autofs_master/gencode-local +++ b/cdist/conf/type/__autofs/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -17,10 +17,22 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# -# Generate auto.master config based on all defined __autofs_map ojbects. -# -auto_master="$__object/files/auto.master" -cat "$(cat "$__object/parameter/header")" > "$auto_master" -find "$__global/object/__autofs_map" -path "*.cdist/parameter/entry" | xargs cat >> "$auto_master" + +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 + ubuntu|debian|archlinux) + __package autofs --state present + __start_on_boot autofs --state present + ;; + *) + not_supported + ;; +esac diff --git a/cdist/conf/type/__autofs_master/singleton b/cdist/conf/type/__autofs/singleton similarity index 100% rename from cdist/conf/type/__autofs_master/singleton rename to cdist/conf/type/__autofs/singleton diff --git a/cdist/conf/type/__autofs_map/explorer/entry b/cdist/conf/type/__autofs_map/explorer/entry new file mode 100755 index 00000000..7aa26518 --- /dev/null +++ b/cdist/conf/type/__autofs_map/explorer/entry @@ -0,0 +1,50 @@ +#!/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 . +# + +candidates="/etc/auto.master /etc/autofs/auto.master" +find_auto_master() { + # get the path of the auto.master file + for candidate in $candidates; do + if [ -f "$candidate" ]; then + echo "$candidate" + return + fi + done +} + +auto_master="$(find_auto_master)" + +# no auto.master, nothing we could do +[ -f "$auto_master" ] || 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 + } +}' "$auto_master" diff --git a/cdist/conf/type/__autofs_map/gencode-remote b/cdist/conf/type/__autofs_map/gencode-remote new file mode 100755 index 00000000..fa6acffb --- /dev/null +++ b/cdist/conf/type/__autofs_map/gencode-remote @@ -0,0 +1,93 @@ +#!/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 . +# + +entry="$__object/files/entry" +state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo present)" +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 + +cat << DONE +candidates="/etc/auto.master /etc/autofs/auto.master" +find_auto_master() { + # get the path of the auto.master file + for candidate in \$candidates; do + if [ -f "\$candidate" ]; then + echo "\$candidate" + return + fi + done +} + +auto_master="\$(find_auto_master)" + +if [ ! -f "\$auto_master" ]; then + echo "Could not determine auto.master location, tried: \$candidates" >&2 + exit 1 +fi +DONE + +remove_entry() { + # NOTE: keep variables in sync in manifest/explorer/gencode-* + prefix="#cdist:$__object_name" + suffix="#/cdist:$__object_name" + cat << DONE +awk -v prefix="$prefix" -v suffix="$suffix" ' +{ + if (index(\$0,prefix)) { + triggered=1 + } + if (triggered) { + if (index(\$0,suffix)) { + triggered=0 + } + } else { + print + } +}' "\$auto_master" > "\$auto_master"+ +mv -f "\$auto_master"+ "\$auto_master" +DONE +} + +case "$state_should" in + present) + if [ "$state_is" = "changed" ]; then + remove_entry + fi + cat << DONE +cat >> "\$auto_master" << EOC +$(cat "$entry") +EOC +DONE + ;; + absent) + remove_entry + ;; +esac diff --git a/cdist/conf/type/__autofs_map/man.text b/cdist/conf/type/__autofs_map/man.text index 941e22da..50ce2fa8 100644 --- a/cdist/conf/type/__autofs_map/man.text +++ b/cdist/conf/type/__autofs_map/man.text @@ -36,25 +36,35 @@ comment:: auto.master. +BOOLEAN PARAMETERS +------------------ +noreload:: + don't reload autofs after the entry has been changed + + EXAMPLES -------- -------------------------------------------------------------------------------- -# Add auto mounter at /net +# Add auto mounter at /net and reload __autofs_map /net --map /etc/auto.net --type program -# Add auto mounter at /pub -__autofs_map /pub --map /etc/auto.pub \ - --type file --options nosuid,rw,bg,hard,intr --ghost +# Add auto mounter at /pub and don't reload +__autofs_map /pub \ + --map /etc/auto.pub \ + --type file \ + --options "nosuid,rw,bg,hard,intr --ghost" \ + --noreload -------------------------------------------------------------------------------- SEE ALSO -------- - cdist-type(7) +- cdist-type__autofs_reload(7) COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is +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/__autofs_map/manifest b/cdist/conf/type/__autofs_map/manifest index d86ea799..58dc0f98 100755 --- a/cdist/conf/type/__autofs_map/manifest +++ b/cdist/conf/type/__autofs_map/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011 - 2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -20,23 +20,36 @@ name="/$__object_id" map="$(cat "$__object/parameter/map")" +type="$(cat "$__object/parameter/type" 2>/dev/null || echo "file")" +options="$(cat "$__object/parameter/options" 2>/dev/null || true)" -if [ -f "$__object/parameter/type" ]; then - type="$(cat "$__object/parameter/type")" -else - type="file" - echo "$type" > "$__object/parameter/type" -fi +# NOTE: keep variables in sync in manifest/explorer/gencode-* +prefix="#cdist:$__object_name" +suffix="#/cdist:$__object_name" -# Generate entry for use in auto.master -entry="${name} ${type}:${map}" -if [ -f "$__object/parameter/options" ]; then - entry="$entry $(cat "$__object/parameter/options")" -fi +mkdir "$__object/files" + +# Generate entry for inclusion in auto.master +entry="$__object/files/entry" +echo "$prefix" > "$entry" if [ -f "$__object/parameter/comment" ]; then - echo "# $(cat "$__object/parameter/comment")" > "$__object/parameter/entry" + echo "# $(cat "$__object/parameter/comment")" >> "$entry" fi -echo "$entry" >> "$__object/parameter/entry" - -require="$__object_name" __autofs_master +echo "$name $type:$map $options" >> $entry +echo "$suffix" >> "$entry" +# Reload autofs after changes if the user wishes this +if [ ! -f "$__object/parameter/noreload" ]; then + state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo present)" + 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" __autofs_reload + fi +fi diff --git a/cdist/conf/type/__autofs_map/parameter/boolean b/cdist/conf/type/__autofs_map/parameter/boolean new file mode 100644 index 00000000..862edc87 --- /dev/null +++ b/cdist/conf/type/__autofs_map/parameter/boolean @@ -0,0 +1 @@ +noreload diff --git a/cdist/conf/type/__autofs_master/files/auto.master.header b/cdist/conf/type/__autofs_master/files/auto.master.header deleted file mode 100644 index 53590257..00000000 --- a/cdist/conf/type/__autofs_master/files/auto.master.header +++ /dev/null @@ -1,3 +0,0 @@ -# Generated from cdist __autofs_master -# Do not change this file. Changes will be overwritten. - diff --git a/cdist/conf/type/__autofs_master/parameter/optional b/cdist/conf/type/__autofs_master/parameter/optional deleted file mode 100644 index 8e83f898..00000000 --- a/cdist/conf/type/__autofs_master/parameter/optional +++ /dev/null @@ -1 +0,0 @@ -header diff --git a/cdist/conf/type/__autofs_master/manifest b/cdist/conf/type/__autofs_reload/gencode-remote similarity index 62% rename from cdist/conf/type/__autofs_master/manifest rename to cdist/conf/type/__autofs_reload/gencode-remote index e429842e..883602e2 100755 --- a/cdist/conf/type/__autofs_master/manifest +++ b/cdist/conf/type/__autofs_reload/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -19,13 +19,19 @@ # -if [ ! -f "$__object/parameter/header" ]; then - echo "$__type/files/auto.master.header" > "$__object/parameter/header" -fi +os=$(cat "$__global/explorer/os") -[ -d "$__object/files" ] || mkdir "$__object/files" -require="$__object_name" __file /etc/auto.master --source "$__object/files/auto.master" \ - --mode 644 \ - --owner root \ - --group root +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 + ubuntu|debian|archlinux) + echo "pkill -HUP automount" + ;; + *) + not_supported + ;; +esac diff --git a/cdist/conf/type/__autofs_master/man.text b/cdist/conf/type/__autofs_reload/man.text similarity index 51% rename from cdist/conf/type/__autofs_master/man.text rename to cdist/conf/type/__autofs_reload/man.text index 641c8393..d2085a98 100644 --- a/cdist/conf/type/__autofs_master/man.text +++ b/cdist/conf/type/__autofs_reload/man.text @@ -1,38 +1,33 @@ -cdist-type__autofs_master(7) +cdist-type__autofs_reload(7) ============================ Steven Armstrong NAME ---- -cdist-type__autofs_master - Generate the auto.master file +cdist-type__autofs_reload - tell automounter to reload config file DESCRIPTION ----------- -This cdist type generates a auto.master configuration from given __autofs_map -definitions. See cdist-type__auto_map(7). +This space intentionally left blank. REQUIRED PARAMETERS ------------------- -None +None. + OPTIONAL PARAMETERS ------------------- -header:: - Absolute path to a file used as the header for the generated auto.master - file. +None. + EXAMPLES -------- -------------------------------------------------------------------------------- -# auto.master with default header -__autofs_master - -# auto.master with custom header -__autofs_master --header /path/to/header +__autofs_reload -------------------------------------------------------------------------------- @@ -43,5 +38,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is +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/__autofs_reload/singleton b/cdist/conf/type/__autofs_reload/singleton new file mode 100644 index 00000000..e69de29b From 7e951fd4d184a2948c808039e0ed92a83ef07974 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 7 Nov 2012 15:16:04 +0100 Subject: [PATCH 1795/4212] __apt_ppa: /installed/present/ Signed-off-by: Steven Armstrong --- cdist/conf/type/__apt_ppa/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__apt_ppa/manifest b/cdist/conf/type/__apt_ppa/manifest index 04c66ce0..e7ad0c26 100755 --- a/cdist/conf/type/__apt_ppa/manifest +++ b/cdist/conf/type/__apt_ppa/manifest @@ -20,7 +20,7 @@ name="$__object_id" -__package python-software-properties --state installed +__package python-software-properties --state present require="__package/python-software-properties" \ __file /usr/local/bin/remove-apt-repository \ From 8f525fbc8345997b3a4cb93f88afb32968c3f7fd Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 7 Nov 2012 15:46:25 +0100 Subject: [PATCH 1796/4212] __apt_update_index: ignore top level directory Signed-off-by: Steven Armstrong --- cdist/conf/type/__apt_update_index/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__apt_update_index/gencode-remote b/cdist/conf/type/__apt_update_index/gencode-remote index e66ff7a3..61ce11a9 100755 --- a/cdist/conf/type/__apt_update_index/gencode-remote +++ b/cdist/conf/type/__apt_update_index/gencode-remote @@ -20,7 +20,7 @@ # run 'apt-get update' if anything in /etc/apt is newer then /var/lib/apt/lists cat << DONE -if find /etc/apt -cnewer /var/lib/apt/lists | grep . > /dev/null; then +if find /etc/apt -mindepth 1 -cnewer /var/lib/apt/lists | grep . > /dev/null; then apt-get update || apt-get update fi DONE From f769b395c27a8eaf5ebdda518d2c9a201d9a5d46 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 7 Nov 2012 16:28:21 +0100 Subject: [PATCH 1797/4212] __file: implement --state exists Signed-off-by: Steven Armstrong --- cdist/conf/type/__file/gencode-local | 2 +- cdist/conf/type/__file/gencode-remote | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index b74893fb..a6c55abf 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -27,7 +27,7 @@ exists="$(cat "$__object/explorer/exists")" [ "$state_should" = "exists" -a "$exists" = "yes" ] && exit 0 # nothing to do -if [ "$state_should" = "present" ]; then +if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then if [ -f "$__object/parameter/source" ]; then source="$(cat "$__object/parameter/source")" if [ "$source" = "-" ]; then diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index 2b4c7e45..04a1ea78 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -26,7 +26,7 @@ state_should="$(cat "$__object/parameter/state")" exists="$(cat "$__object/explorer/exists")" case "$state_should" in - present) + present|exists) # No source? Create empty file if [ ! -f "$__object/parameter/source" ]; then if [ "$exists" = "no" ]; then From 324a88c435b89395c1c67b800588ef7ef0aa10db Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 7 Nov 2012 16:49:55 +0100 Subject: [PATCH 1798/4212] __timezone: set timezone in /etc/timezone on debuntu Signed-off-by: Steven Armstrong --- cdist/conf/type/__timezone/gencode-remote | 30 +++++++++++++++++++++++ cdist/conf/type/__timezone/manifest | 21 +++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100755 cdist/conf/type/__timezone/gencode-remote diff --git a/cdist/conf/type/__timezone/gencode-remote b/cdist/conf/type/__timezone/gencode-remote new file mode 100755 index 00000000..b4782d4b --- /dev/null +++ b/cdist/conf/type/__timezone/gencode-remote @@ -0,0 +1,30 @@ +#!/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 . +# +# +# This type allows to configure the desired localtime timezone. + +timezone="$__object_id" +os=$(cat "$__global/explorer/os") + +case "$os" in + ubuntu|debian) + echo "echo \"$timezone\" > /etc/timezone" + ;; +esac diff --git a/cdist/conf/type/__timezone/manifest b/cdist/conf/type/__timezone/manifest index b0bae209..7583c9c9 100755 --- a/cdist/conf/type/__timezone/manifest +++ b/cdist/conf/type/__timezone/manifest @@ -1,6 +1,7 @@ #!/bin/sh # # 2011 Ramon Salvadó (rsalvado at gnuine dot com) +# 2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -22,7 +23,25 @@ timezone="$__object_id" -__package tzdata --state installed +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 + ubuntu|debian|archlinux) + : + ;; + *) + not_supported + ;; +esac + +# same for all supported os's +__package tzdata --state present require="__package/tzdata" __link /etc/localtime \ --source "/usr/share/zoneinfo/${timezone}" \ --type symbolic From 6adb20b8292851b67a7357ee28ed4ab7eb321dc3 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 7 Nov 2012 16:52:44 +0100 Subject: [PATCH 1799/4212] __ssh_authorized_key: /installed/present/ Signed-off-by: Steven Armstrong --- cdist/conf/type/__ssh_authorized_key/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__ssh_authorized_key/manifest b/cdist/conf/type/__ssh_authorized_key/manifest index d9db9c78..8984d5d4 100755 --- a/cdist/conf/type/__ssh_authorized_key/manifest +++ b/cdist/conf/type/__ssh_authorized_key/manifest @@ -21,7 +21,7 @@ # This type allows to send a public ssh key from a user to the # authorized_keys of another # -#require="__package openssh-server --state installed" +#require="__package openssh-server --state present" # Get option srcuser if defined if [ -f "$__object/parameter/srcuser" ]; then srcuser=`cat "$__object/parameter/srcuser"` From 489fa2a8be06260c241ec2c71f535c63577cadac Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 17:21:22 +0100 Subject: [PATCH 1800/4212] +quotes Signed-off-by: Nico Schottelius --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index 34775a31..baad93be 100755 --- a/build +++ b/build @@ -173,7 +173,7 @@ eof $0 blog version=$($0 changelog-version) file=cdist-${version}-released.mdwn - cd $WEBBBLOG + cd "$WEBBLOG" git add "$file" git commit -m "New cdist version (blogentry): $version" "$file" git push From ace897de258ade3f0597f81f7850de745a3cd149 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 17:28:27 +0100 Subject: [PATCH 1801/4212] simplify timezone manifest Signed-off-by: Nico Schottelius --- cdist/conf/type/__timezone/manifest | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/cdist/conf/type/__timezone/manifest b/cdist/conf/type/__timezone/manifest index 7583c9c9..76fa5c97 100755 --- a/cdist/conf/type/__timezone/manifest +++ b/cdist/conf/type/__timezone/manifest @@ -2,6 +2,7 @@ # # 2011 Ramon Salvadó (rsalvado at gnuine dot com) # 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -22,26 +23,16 @@ # This type allows to configure the desired localtime timezone. timezone="$__object_id" - 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 - ubuntu|debian|archlinux) - : - ;; - *) - not_supported - ;; + archlinux|debian|ubuntu) + __package tzdata --state present + require="__package/tzdata" __link /etc/localtime \ + --source "/usr/share/zoneinfo/${timezone}" \ + --type symbolic + ;; + *) + echo "Unsupported OS $os" >&2 + ;; esac - -# same for all supported os's -__package tzdata --state present -require="__package/tzdata" __link /etc/localtime \ - --source "/usr/share/zoneinfo/${timezone}" \ - --type symbolic From a4b2e2ce9556ef82f02126080a1c531ed2dbaf46 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 17:34:21 +0100 Subject: [PATCH 1802/4212] ++changes(next version) Signed-off-by: Nico Schottelius --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index f8030609..863f6db3 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 +2.1.0pre8: + * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, + __ssh_authorized_key, __timezone, all install types (Steven Armstrong) + 2.1.0pre7: 2012-11-07 * Core: All unit tests restored back to working * Core: Print error message on missing initial manifest From 265d1af56a8a1d59080b63bff8aa24c8db4df42b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 17:40:39 +0100 Subject: [PATCH 1803/4212] rename vm to diskimage, ensure state is setup Signed-off-by: Nico Schottelius --- cdist/conf/type/__qemu_img/gencode-remote | 7 ++++--- cdist/conf/type/__qemu_img/manifest | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__qemu_img/gencode-remote b/cdist/conf/type/__qemu_img/gencode-remote index acadcef0..e5ff1b4f 100644 --- a/cdist/conf/type/__qemu_img/gencode-remote +++ b/cdist/conf/type/__qemu_img/gencode-remote @@ -2,7 +2,8 @@ # State: absent is handled by manifest - we need only to do stuff if image is # not existing and state != absent # -[ -f "$__object/parameter/state" ] && state="$(cat "$__object/parameter/state")" +state="present" +[ -f "$__object/parameter/state" ] state="$(cat "$__object/parameter/state")" [ "$state" = "absent" ] && exit 0 exists="$(cat "$__object/explorer/exists")" @@ -15,6 +16,6 @@ exists="$(cat "$__object/explorer/exists")" format=qcow2 [ -f "$__object/parameter/format" ] && format="$(cat "$__object/parameter/format")" size="$(cat "$__object/parameter/size")" -vm="/$__object_id" +diskimage="/$__object_id" -echo qemu-img create -f \"$format\" \"$vm\" \"$size\" +echo qemu-img create -f \"$format\" \"$diskimage\" \"$size\" diff --git a/cdist/conf/type/__qemu_img/manifest b/cdist/conf/type/__qemu_img/manifest index d343e188..b835301d 100644 --- a/cdist/conf/type/__qemu_img/manifest +++ b/cdist/conf/type/__qemu_img/manifest @@ -3,12 +3,13 @@ # format=qcow2 +state=present [ -f "$__object/parameter/format" ] && format="$(cat "$__object/parameter/format")" [ -f "$__object/parameter/state" ] && state="$(cat "$__object/parameter/state")" -vm="/$__object_id" +diskimage="/$__object_id" # Absent is ensured by __file, present by gencode-remote if [ "$state" = "absent" ]; then - __file "$vm" --state absent + __file "$diskimage" --state absent fi From a0add17cf804696f634b85b31bcab4329d4b0903 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 17:44:54 +0100 Subject: [PATCH 1804/4212] ++exit 1 Signed-off-by: Nico Schottelius --- cdist/conf/type/__timezone/manifest | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__timezone/manifest b/cdist/conf/type/__timezone/manifest index 76fa5c97..81de0217 100755 --- a/cdist/conf/type/__timezone/manifest +++ b/cdist/conf/type/__timezone/manifest @@ -34,5 +34,6 @@ case "$os" in ;; *) echo "Unsupported OS $os" >&2 + exit 1 ;; esac From 7a44f3057412b2a600c91b7feabe59f32a95571f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 17:47:55 +0100 Subject: [PATCH 1805/4212] simplify manifest Signed-off-by: Nico Schottelius --- cdist/conf/type/__autofs/manifest | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/cdist/conf/type/__autofs/manifest b/cdist/conf/type/__autofs/manifest index 31844415..4a726c0a 100755 --- a/cdist/conf/type/__autofs/manifest +++ b/cdist/conf/type/__autofs/manifest @@ -1,6 +1,7 @@ #!/bin/sh # # 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -21,18 +22,13 @@ 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 - ubuntu|debian|archlinux) - __package autofs --state present - __start_on_boot autofs --state present - ;; - *) - not_supported - ;; + ubuntu|debian|archlinux) + __package autofs --state present + __start_on_boot autofs --state present + ;; + *) + echo "Unsupported OS: $os" >&2 + exit 1 + ;; esac From 8ab408f890970a92d88ccf39c770a37c10d58fa9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 17:52:05 +0100 Subject: [PATCH 1806/4212] remove parameter change code Signed-off-by: Nico Schottelius --- cdist/conf/type/__file/gencode-local | 5 +++-- cdist/conf/type/__file/gencode-remote | 5 +++-- cdist/conf/type/__file/manifest | 24 ------------------------ 3 files changed, 6 insertions(+), 28 deletions(-) delete mode 100755 cdist/conf/type/__file/manifest diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index a6c55abf..087011c4 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -22,7 +22,8 @@ # destination="/$__object_id" -state_should="$(cat "$__object/parameter/state")" +state_should=present +[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" exists="$(cat "$__object/explorer/exists")" [ "$state_should" = "exists" -a "$exists" = "yes" ] && exit 0 # nothing to do diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index 04a1ea78..8b03e919 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -22,7 +22,8 @@ # destination="/$__object_id" -state_should="$(cat "$__object/parameter/state")" +state_should=present +[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" exists="$(cat "$__object/explorer/exists")" case "$state_should" in diff --git a/cdist/conf/type/__file/manifest b/cdist/conf/type/__file/manifest deleted file mode 100755 index 6b5e1ca7..00000000 --- a/cdist/conf/type/__file/manifest +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# 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 . -# - -# set default: present, if not setup -statefile="$__object/parameter/state" -[ -f "$statefile" ] || echo present > "$statefile" From 2cfa046cdd373df9248375fc52498786b6a1778e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 17:57:47 +0100 Subject: [PATCH 1807/4212] indentions, whitespace Signed-off-by: Nico Schottelius --- cdist/conf/type/__issue/manifest | 21 +++++++++---------- cdist/conf/type/__ssh_authorized_key/manifest | 1 - 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/cdist/conf/type/__issue/manifest b/cdist/conf/type/__issue/manifest index eff6b808..d2720f2d 100755 --- a/cdist/conf/type/__issue/manifest +++ b/cdist/conf/type/__issue/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -24,17 +24,16 @@ destination=/etc/issue os="$(cat "$__global/explorer/os")" if [ -f "$__object/parameter/source" ]; then - source="$(cat "$__object/parameter/source")" - echo using $source + source="$(cat "$__object/parameter/source")" else - case "$os" in - archlinux|redhat) - source="$__type/files/$os" - ;; - *) - source="$__type/files/default" - ;; - esac + case "$os" in + archlinux|redhat) + source="$__type/files/$os" + ;; + *) + source="$__type/files/default" + ;; + esac fi __file "$destination" --source "$source" diff --git a/cdist/conf/type/__ssh_authorized_key/manifest b/cdist/conf/type/__ssh_authorized_key/manifest index 8984d5d4..86c58740 100755 --- a/cdist/conf/type/__ssh_authorized_key/manifest +++ b/cdist/conf/type/__ssh_authorized_key/manifest @@ -64,4 +64,3 @@ require="__directory${sshpath}" \ # the line added depends on authorized_keys existence require="__file${sshpath}/authorized_keys" __addifnosuchline sshkey --file \ "$sshpath/authorized_keys" --line "$rsa" - From 7814ece7b7745b0bb97140d23c2f65fe98e70d0e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 18:01:30 +0100 Subject: [PATCH 1808/4212] remove parameter changing code Signed-off-by: Nico Schottelius --- cdist/conf/type/__link/gencode-remote | 50 +++++++++++++-------------- cdist/conf/type/__link/manifest | 24 ------------- 2 files changed, 24 insertions(+), 50 deletions(-) delete mode 100755 cdist/conf/type/__link/manifest diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote index 8d4cc3d5..2975ef69 100755 --- a/cdist/conf/type/__link/gencode-remote +++ b/cdist/conf/type/__link/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -27,35 +27,33 @@ type="$(cat "$__object/parameter/type")" source="$(cat "$__object/parameter/source")" case "$type" in - symbolic) - lnopt="-s" - ;; - hard) - lnopt="" - ;; - *) - echo "Unknown type: $type" >&2 - exit 1 - ;; + symbolic) + lnopt="-s" + ;; + hard) + lnopt="" + ;; + *) + echo "Unknown link type: $type" >&2 + exit 1 + ;; esac state_is="$(cat "$__object/explorer/state")" -state_should="$(cat "$__object/parameter/state")" +state_should=present +[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" -if [ "$state_should" = "$state_is" ]; then - # nothing to do - exit 0 -fi +[ "$state_should" = "$state_is" ] && exit 0 case "$state_should" in - present) - echo ln ${lnopt} -f \"$source\" \"$destination\" - ;; - absent) - echo rm -f \"$destination\" - ;; - *) - echo "Unknown state: $state_should" >&2 - exit 1 - ;; + present) + echo ln ${lnopt} -f \"$source\" \"$destination\" + ;; + absent) + echo rm -f \"$destination\" + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; esac diff --git a/cdist/conf/type/__link/manifest b/cdist/conf/type/__link/manifest deleted file mode 100755 index 6b5e1ca7..00000000 --- a/cdist/conf/type/__link/manifest +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# 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 . -# - -# set default: present, if not setup -statefile="$__object/parameter/state" -[ -f "$statefile" ] || echo present > "$statefile" From 82830f191dc040e1e4087604260c10f20de44a7e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 18:04:49 +0100 Subject: [PATCH 1809/4212] link __process to __start_on_boot and vice versa Signed-off-by: Nico Schottelius --- cdist/conf/type/__process/man.text | 3 +-- cdist/conf/type/__start_on_boot/man.text | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__process/man.text b/cdist/conf/type/__process/man.text index 961a7f9a..929ba6a0 100644 --- a/cdist/conf/type/__process/man.text +++ b/cdist/conf/type/__process/man.text @@ -17,8 +17,6 @@ REQUIRED PARAMETERS ------------------- state:: State of the process: Either present or absent - (old values "stopped" and "running" are deprecated and will be removed in - cdist 2.1). OPTIONAL PARAMETERS @@ -66,6 +64,7 @@ __process rpcstatd --state present --start "/etc/init.d/statd start" \ SEE ALSO -------- - cdist-type(7) +- cdist-type__start_on_boot(7) COPYING diff --git a/cdist/conf/type/__start_on_boot/man.text b/cdist/conf/type/__start_on_boot/man.text index 0e75c9ab..58a68d65 100644 --- a/cdist/conf/type/__start_on_boot/man.text +++ b/cdist/conf/type/__start_on_boot/man.text @@ -45,6 +45,7 @@ __start_on_boot puppet --state absent SEE ALSO -------- - cdist-type(7) +- cdist-type__process(7) COPYING From aeff2bcb0f0523f4a02698910fbc3295baeb9b23 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 18:06:11 +0100 Subject: [PATCH 1810/4212] indention Signed-off-by: Nico Schottelius --- cdist/conf/type/__process/explorer/runs | 6 +++--- cdist/conf/type/__process/gencode-remote | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__process/explorer/runs b/cdist/conf/type/__process/explorer/runs index 240ebef9..561e2fe9 100755 --- a/cdist/conf/type/__process/explorer/runs +++ b/cdist/conf/type/__process/explorer/runs @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -22,9 +22,9 @@ # if [ -f "$__object/parameter/name" ]; then - name="$(cat "$__object/parameter/name")" + name="$(cat "$__object/parameter/name")" else - name="$__object_id" + name="$__object_id" fi pgrep -x -f "$name" || true diff --git a/cdist/conf/type/__process/gencode-remote b/cdist/conf/type/__process/gencode-remote index e4519f3c..fdb6033a 100755 --- a/cdist/conf/type/__process/gencode-remote +++ b/cdist/conf/type/__process/gencode-remote @@ -20,9 +20,9 @@ # if [ -f "$__object/parameter/name" ]; then - name="$(cat "$__object/parameter/name")" + name="$(cat "$__object/parameter/name")" else - name="$__object_id" + name="$__object_id" fi state_should="$(cat "$__object/parameter/state")" From 347c620eedd1385aea2492884bbc799372311293 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 18:08:03 +0100 Subject: [PATCH 1811/4212] indent Signed-off-by: Nico Schottelius --- cdist/conf/type/__file/explorer/cksum | 14 +++++++------- cdist/conf/type/__file/explorer/exists | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cdist/conf/type/__file/explorer/cksum b/cdist/conf/type/__file/explorer/cksum index dcad99ba..335e4e7a 100755 --- a/cdist/conf/type/__file/explorer/cksum +++ b/cdist/conf/type/__file/explorer/cksum @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -24,11 +24,11 @@ destination="/$__object_id" if [ -e "$destination" ]; then - if [ -f "$destination" ]; then - cksum < "$destination" - else - echo "NO REGULAR FILE" - fi + if [ -f "$destination" ]; then + cksum < "$destination" + else + echo "NO REGULAR FILE" + fi else - echo "NO FILE FOUND, NO CHECKSUM CALCULATED." + echo "NO FILE FOUND, NO CHECKSUM CALCULATED." fi diff --git a/cdist/conf/type/__file/explorer/exists b/cdist/conf/type/__file/explorer/exists index f8b85671..c319cb5d 100755 --- a/cdist/conf/type/__file/explorer/exists +++ b/cdist/conf/type/__file/explorer/exists @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -24,7 +24,7 @@ destination="/$__object_id" if [ -e "$destination" ]; then - echo yes + echo yes else - echo no + echo no fi From 13d6644966ca8319eef99c49cedd1a8e518a2b1c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 18:10:15 +0100 Subject: [PATCH 1812/4212] do not report errors on missing gemset Signed-off-by: Nico Schottelius --- cdist/conf/type/__rvm_gem/explorer/state | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__rvm_gem/explorer/state b/cdist/conf/type/__rvm_gem/explorer/state index 09509a2e..4146d666 100755 --- a/cdist/conf/type/__rvm_gem/explorer/state +++ b/cdist/conf/type/__rvm_gem/explorer/state @@ -1,6 +1,7 @@ #!/bin/sh # # 2012 Evax Software +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -30,8 +31,8 @@ fi if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" rvm list | grep -q $ruby"; then if su - "$user" -c "source \"\$HOME/.rvm/scripts/rvm\" -rvm use $ruby > /dev/null; rvm gemset list | grep -q $gemsetname && -rvm use $gemset > /dev/null && gem list | grep -q $gem"; then +rvm use $ruby > /dev/null 2>&1; rvm gemset list | grep -q $gemsetname && +rvm use $gemset > /dev/null 2>&1 && gem list | grep -q $gem"; then echo "present" exit 0 fi From 47424bf200c7e0fb2361f0b710c892e48153d1f7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 18:15:15 +0100 Subject: [PATCH 1813/4212] update __package* manpages Signed-off-by: Nico Schottelius --- cdist/conf/type/__package/man.text | 2 +- cdist/conf/type/__package_pip/man.text | 2 +- cdist/conf/type/__package_pkg_freebsd/man.text | 10 +++++----- cdist/conf/type/__package_pkg_openbsd/man.text | 2 +- cdist/conf/type/__package_rubygem/man.text | 2 +- cdist/conf/type/__package_yum/man.text | 3 +-- cdist/conf/type/__package_zypper/man.text | 2 +- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/cdist/conf/type/__package/man.text b/cdist/conf/type/__package/man.text index 69ecf0ad..229ccf92 100644 --- a/cdist/conf/type/__package/man.text +++ b/cdist/conf/type/__package/man.text @@ -34,7 +34,7 @@ type:: __package_emerge for Gentoo state:: - The state the package should be in, either "present" or "absent" + either "present" or "absent", defaults to "present" EXAMPLES diff --git a/cdist/conf/type/__package_pip/man.text b/cdist/conf/type/__package_pip/man.text index 21d4f9fd..8cb7d80a 100644 --- a/cdist/conf/type/__package_pip/man.text +++ b/cdist/conf/type/__package_pip/man.text @@ -28,7 +28,7 @@ pip:: Instead of using pip from PATH, use the specific pip path. state:: - Either "present" or "absent". + Either "present" or "absent", defaults to "present" EXAMPLES diff --git a/cdist/conf/type/__package_pkg_freebsd/man.text b/cdist/conf/type/__package_pkg_freebsd/man.text index f1589037..71387148 100644 --- a/cdist/conf/type/__package_pkg_freebsd/man.text +++ b/cdist/conf/type/__package_pkg_freebsd/man.text @@ -21,19 +21,19 @@ None OPTIONAL PARAMETERS ------------------- name:: - If supplied, use the name and not the object id as the package name. + If supplied, use the name and not the object id as the package name. flavor:: - If supplied, use to avoid ambiguity. + If supplied, use to avoid ambiguity. version:: - If supplied, use to install a specific version of the package named. + If supplied, use to install a specific version of the package named. pkgsite:: - If supplied, use to install from a specific package repository. + If supplied, use to install from a specific package repository. state:: - Either "present" or "absent". + Either "present" or "absent", defaults to "present" EXAMPLES diff --git a/cdist/conf/type/__package_pkg_openbsd/man.text b/cdist/conf/type/__package_pkg_openbsd/man.text index 8fcc3216..f523a892 100644 --- a/cdist/conf/type/__package_pkg_openbsd/man.text +++ b/cdist/conf/type/__package_pkg_openbsd/man.text @@ -27,7 +27,7 @@ flavor:: If supplied, use to avoid ambiguity. state:: - The state the package should be in, either "present" or "absent" + Either "present" or "absent", defaults to "present" EXAMPLES diff --git a/cdist/conf/type/__package_rubygem/man.text b/cdist/conf/type/__package_rubygem/man.text index feefe699..a808c2aa 100644 --- a/cdist/conf/type/__package_rubygem/man.text +++ b/cdist/conf/type/__package_rubygem/man.text @@ -24,7 +24,7 @@ name:: If supplied, use the name and not the object id as the package name. state:: - The state the package should be in, either "present" or "absent" + Either "present" or "absent", defaults to "present" EXAMPLES diff --git a/cdist/conf/type/__package_yum/man.text b/cdist/conf/type/__package_yum/man.text index 9aabf7fb..d958dd1e 100644 --- a/cdist/conf/type/__package_yum/man.text +++ b/cdist/conf/type/__package_yum/man.text @@ -26,8 +26,7 @@ name:: If supplied, use the name and not the object id as the package name. state:: - The state the package should be in, either "present" or "absent" - (the old values "installed" or "removed" will be removed in cdist 2.1). + Either "present" or "absent", defaults to "present" EXAMPLES diff --git a/cdist/conf/type/__package_zypper/man.text b/cdist/conf/type/__package_zypper/man.text index 702d51e5..e2261d33 100644 --- a/cdist/conf/type/__package_zypper/man.text +++ b/cdist/conf/type/__package_zypper/man.text @@ -24,7 +24,7 @@ name:: If supplied, use the name and not the object id as the package name. state:: - The state the package should be in, either "present" or "absent" + Either "present" or "absent", defaults to "present" EXAMPLES From 344e08dddae8c2a03b4ac135a3feb72c02a6ff27 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 18:22:25 +0100 Subject: [PATCH 1814/4212] Archive __autofs types (fixes #116) Signed-off-by: Nico Schottelius --- other/archived_types/.README.unmaintained | 1 + other/archived_types/README | 3 +++ other/archived_types/__autofs/README | 1 + {cdist/conf/type => other/archived_types}/__autofs/man.text | 0 {cdist/conf/type => other/archived_types}/__autofs/manifest | 0 {cdist/conf/type => other/archived_types}/__autofs/singleton | 0 other/archived_types/__autofs_map/README | 1 + .../type => other/archived_types}/__autofs_map/explorer/entry | 0 .../type => other/archived_types}/__autofs_map/gencode-remote | 0 .../conf/type => other/archived_types}/__autofs_map/man.text | 0 .../conf/type => other/archived_types}/__autofs_map/manifest | 0 .../archived_types}/__autofs_map/parameter/boolean | 0 .../archived_types}/__autofs_map/parameter/optional | 0 .../archived_types}/__autofs_map/parameter/required | 0 other/archived_types/__autofs_reload/README | 1 + .../archived_types}/__autofs_reload/gencode-remote | 0 .../type => other/archived_types}/__autofs_reload/man.text | 0 .../type => other/archived_types}/__autofs_reload/singleton | 0 18 files changed, 7 insertions(+) create mode 100644 other/archived_types/.README.unmaintained create mode 100644 other/archived_types/README create mode 120000 other/archived_types/__autofs/README rename {cdist/conf/type => other/archived_types}/__autofs/man.text (100%) rename {cdist/conf/type => other/archived_types}/__autofs/manifest (100%) rename {cdist/conf/type => other/archived_types}/__autofs/singleton (100%) create mode 120000 other/archived_types/__autofs_map/README rename {cdist/conf/type => other/archived_types}/__autofs_map/explorer/entry (100%) rename {cdist/conf/type => other/archived_types}/__autofs_map/gencode-remote (100%) rename {cdist/conf/type => other/archived_types}/__autofs_map/man.text (100%) rename {cdist/conf/type => other/archived_types}/__autofs_map/manifest (100%) rename {cdist/conf/type => other/archived_types}/__autofs_map/parameter/boolean (100%) rename {cdist/conf/type => other/archived_types}/__autofs_map/parameter/optional (100%) rename {cdist/conf/type => other/archived_types}/__autofs_map/parameter/required (100%) create mode 120000 other/archived_types/__autofs_reload/README rename {cdist/conf/type => other/archived_types}/__autofs_reload/gencode-remote (100%) rename {cdist/conf/type => other/archived_types}/__autofs_reload/man.text (100%) rename {cdist/conf/type => other/archived_types}/__autofs_reload/singleton (100%) diff --git a/other/archived_types/.README.unmaintained b/other/archived_types/.README.unmaintained new file mode 100644 index 00000000..e9795911 --- /dev/null +++ b/other/archived_types/.README.unmaintained @@ -0,0 +1 @@ +This type is not maintained by anymore and has thus been removed from cdist. diff --git a/other/archived_types/README b/other/archived_types/README new file mode 100644 index 00000000..32cd1f3d --- /dev/null +++ b/other/archived_types/README @@ -0,0 +1,3 @@ +This directory contains types that used to be included with +cdist, but are not in use anymore. Have a look at the README +file in each type, to find out why it was removed. diff --git a/other/archived_types/__autofs/README b/other/archived_types/__autofs/README new file mode 120000 index 00000000..7495e43b --- /dev/null +++ b/other/archived_types/__autofs/README @@ -0,0 +1 @@ +../.README.unmaintained \ No newline at end of file diff --git a/cdist/conf/type/__autofs/man.text b/other/archived_types/__autofs/man.text similarity index 100% rename from cdist/conf/type/__autofs/man.text rename to other/archived_types/__autofs/man.text diff --git a/cdist/conf/type/__autofs/manifest b/other/archived_types/__autofs/manifest similarity index 100% rename from cdist/conf/type/__autofs/manifest rename to other/archived_types/__autofs/manifest diff --git a/cdist/conf/type/__autofs/singleton b/other/archived_types/__autofs/singleton similarity index 100% rename from cdist/conf/type/__autofs/singleton rename to other/archived_types/__autofs/singleton diff --git a/other/archived_types/__autofs_map/README b/other/archived_types/__autofs_map/README new file mode 120000 index 00000000..7495e43b --- /dev/null +++ b/other/archived_types/__autofs_map/README @@ -0,0 +1 @@ +../.README.unmaintained \ No newline at end of file diff --git a/cdist/conf/type/__autofs_map/explorer/entry b/other/archived_types/__autofs_map/explorer/entry similarity index 100% rename from cdist/conf/type/__autofs_map/explorer/entry rename to other/archived_types/__autofs_map/explorer/entry diff --git a/cdist/conf/type/__autofs_map/gencode-remote b/other/archived_types/__autofs_map/gencode-remote similarity index 100% rename from cdist/conf/type/__autofs_map/gencode-remote rename to other/archived_types/__autofs_map/gencode-remote diff --git a/cdist/conf/type/__autofs_map/man.text b/other/archived_types/__autofs_map/man.text similarity index 100% rename from cdist/conf/type/__autofs_map/man.text rename to other/archived_types/__autofs_map/man.text diff --git a/cdist/conf/type/__autofs_map/manifest b/other/archived_types/__autofs_map/manifest similarity index 100% rename from cdist/conf/type/__autofs_map/manifest rename to other/archived_types/__autofs_map/manifest diff --git a/cdist/conf/type/__autofs_map/parameter/boolean b/other/archived_types/__autofs_map/parameter/boolean similarity index 100% rename from cdist/conf/type/__autofs_map/parameter/boolean rename to other/archived_types/__autofs_map/parameter/boolean diff --git a/cdist/conf/type/__autofs_map/parameter/optional b/other/archived_types/__autofs_map/parameter/optional similarity index 100% rename from cdist/conf/type/__autofs_map/parameter/optional rename to other/archived_types/__autofs_map/parameter/optional diff --git a/cdist/conf/type/__autofs_map/parameter/required b/other/archived_types/__autofs_map/parameter/required similarity index 100% rename from cdist/conf/type/__autofs_map/parameter/required rename to other/archived_types/__autofs_map/parameter/required diff --git a/other/archived_types/__autofs_reload/README b/other/archived_types/__autofs_reload/README new file mode 120000 index 00000000..7495e43b --- /dev/null +++ b/other/archived_types/__autofs_reload/README @@ -0,0 +1 @@ +../.README.unmaintained \ No newline at end of file diff --git a/cdist/conf/type/__autofs_reload/gencode-remote b/other/archived_types/__autofs_reload/gencode-remote similarity index 100% rename from cdist/conf/type/__autofs_reload/gencode-remote rename to other/archived_types/__autofs_reload/gencode-remote diff --git a/cdist/conf/type/__autofs_reload/man.text b/other/archived_types/__autofs_reload/man.text similarity index 100% rename from cdist/conf/type/__autofs_reload/man.text rename to other/archived_types/__autofs_reload/man.text diff --git a/cdist/conf/type/__autofs_reload/singleton b/other/archived_types/__autofs_reload/singleton similarity index 100% rename from cdist/conf/type/__autofs_reload/singleton rename to other/archived_types/__autofs_reload/singleton From 0eda57986fd205a7a64abbfd12a0e9103ff9d72e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 18:28:58 +0100 Subject: [PATCH 1815/4212] remove parameter changing code in __key_value (fixes #114,#36) Signed-off-by: Nico Schottelius --- cdist/conf/type/__key_value/gencode-remote | 61 +++++++++++----------- cdist/conf/type/__key_value/manifest | 10 ++-- 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index b3ffeb46..5fa24d5b 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,42 +19,42 @@ # along with cdist. If not, see . # -key="$(cat "$__object/parameter/key")" +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")" + file="$(cat "$__object/parameter/file")" delimiter="$(cat "$__object/parameter/delimiter")" value="$(cat "$__object/parameter/value")" state_is="$(cat "$__object/explorer/state")" -state_should="$(cat "$__object/parameter/state")" -if [ "$state_is" = "$state_should" ]; then - # nothing to do - exit 0 -fi +[ "$state_is" = "$state_should" ] && exit 0 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\"" - ;; - present) - case "$state_is" in - absent) - # add new key and value - echo "echo \"${key}${delimiter}${value}\" >> \"$file\"" - ;; - wrongvalue) - # change exisiting value - echo "sed \"s|^$key\($delimiter\+\).*|$key\1$value|\" \"$file\" > \"$file.cdist-tmp\"" - echo "mv \"$file.cdist-tmp\" \"$file\"" - ;; - *) - echo "Unknown explorer state: $state_is" >&2 - exit 1 - esac - ;; - *) - echo "Unknown state: $state_should" >&2 - exit 1 + absent) + # remove lines starting with key + echo "sed '/^$key\($delimiter\+\)/d' \"$file\" > \"$file.cdist-tmp\"" + echo "mv \"$file.cdist-tmp\" \"$file\"" + ;; + present) + case "$state_is" in + absent) + # add new key and value + echo "echo \"${key}${delimiter}${value}\" >> \"$file\"" + ;; + wrongvalue) + # change exisiting value + echo "sed \"s|^$key\($delimiter\+\).*|$key\1$value|\" \"$file\" > \"$file.cdist-tmp\"" + echo "mv \"$file.cdist-tmp\" \"$file\"" + ;; + *) + echo "Unknown explorer state: $state_is" >&2 + exit 1 + esac + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 esac diff --git a/cdist/conf/type/__key_value/manifest b/cdist/conf/type/__key_value/manifest index 2e75e175..8ed9cc9c 100755 --- a/cdist/conf/type/__key_value/manifest +++ b/cdist/conf/type/__key_value/manifest @@ -1,6 +1,7 @@ #!/bin/sh # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,13 +19,10 @@ # along with cdist. If not, see . # -# set defaults -key="$(cat "$__object/parameter/key" 2>/dev/null \ - || echo "$__object_id" | tee "$__object/parameter/key")" -state="$(cat "$__object/parameter/state" 2>/dev/null \ - || echo "present" | tee "$__object/parameter/state")" +state_should=present +[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" -if [ "$state" = "present" -a ! -f "$__object/parameter/value" ]; then +if [ "$state_should" = "present" -a ! -f "$__object/parameter/value" ]; then echo "Missing required parameter 'value'" >&2 exit 1 fi From 91eccc892056172bdac3db0d34219ba72f1fe0e1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 18:57:52 +0100 Subject: [PATCH 1816/4212] ++changes(next_version) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 863f6db3..5d3c1698 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 2.1.0pre8: * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, __ssh_authorized_key, __timezone, all install types (Steven Armstrong) + * Types: Remove all parameter changing code 2.1.0pre7: 2012-11-07 * Core: All unit tests restored back to working From 3d4bb3837f073d820c833267e19a0ffd3f25d20b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 19:22:02 +0100 Subject: [PATCH 1817/4212] documentation cleanups Signed-off-by: Nico Schottelius --- cdist/conf/type/__package/man.text | 2 +- cdist/conf/type/__package_apt/man.text | 2 +- cdist/conf/type/__package_luarocks/man.text | 2 +- cdist/conf/type/__package_opkg/man.text | 2 +- cdist/conf/type/__package_pacman/man.text | 5 ++--- cdist/conf/type/__package_pip/man.text | 2 +- cdist/conf/type/__pf_ruleset/man.text | 1 + cdist/conf/type/__postgres_role/man.text | 2 +- cdist/conf/type/__process/man.text | 14 +++++++------- cdist/conf/type/__qemu_img/man.text | 3 +-- cdist/conf/type/__rvm/man.text | 2 +- cdist/conf/type/__rvm_gem/man.text | 8 ++++---- cdist/conf/type/__rvm_gemset/man.text | 6 +++--- cdist/conf/type/__rvm_ruby/man.text | 10 +++++----- cdist/conf/type/__start_on_boot/man.text | 2 +- 15 files changed, 31 insertions(+), 32 deletions(-) diff --git a/cdist/conf/type/__package/man.text b/cdist/conf/type/__package/man.text index 229ccf92..b656c890 100644 --- a/cdist/conf/type/__package/man.text +++ b/cdist/conf/type/__package/man.text @@ -34,7 +34,7 @@ type:: __package_emerge for Gentoo state:: - either "present" or "absent", defaults to "present" + Either "present" or "absent", defaults to "present" EXAMPLES diff --git a/cdist/conf/type/__package_apt/man.text b/cdist/conf/type/__package_apt/man.text index 35c34d33..5d4656c1 100644 --- a/cdist/conf/type/__package_apt/man.text +++ b/cdist/conf/type/__package_apt/man.text @@ -25,7 +25,7 @@ name:: If supplied, use the name and not the object id as the package name. state:: - The state the package should be in, either "present" or "absent" + Either "present" or "absent", defaults to "present" EXAMPLES diff --git a/cdist/conf/type/__package_luarocks/man.text b/cdist/conf/type/__package_luarocks/man.text index 18a80a79..657f68e5 100644 --- a/cdist/conf/type/__package_luarocks/man.text +++ b/cdist/conf/type/__package_luarocks/man.text @@ -24,7 +24,7 @@ name:: If supplied, use the name and not the object id as the package name. state:: - The state the package should be in, either "present" or "absent" + Either "present" or "absent", defaults to "present" EXAMPLES diff --git a/cdist/conf/type/__package_opkg/man.text b/cdist/conf/type/__package_opkg/man.text index 3d02d1ce..aeb0a1c5 100644 --- a/cdist/conf/type/__package_opkg/man.text +++ b/cdist/conf/type/__package_opkg/man.text @@ -24,7 +24,7 @@ name:: If supplied, use the name and not the object id as the package name. state:: - The state the package should be in, either "present" or "absent" + Either "present" or "absent", defaults to "present" EXAMPLES diff --git a/cdist/conf/type/__package_pacman/man.text b/cdist/conf/type/__package_pacman/man.text index 17c2037a..2e24ecd9 100644 --- a/cdist/conf/type/__package_pacman/man.text +++ b/cdist/conf/type/__package_pacman/man.text @@ -10,8 +10,7 @@ cdist-type__package_pacman - Manage packages with pacman DESCRIPTION ----------- -Pacman is usually used on the Archlinux distribution to manage -packages. +Pacman is usually used on the Archlinux distribution to manage packages. REQUIRED PARAMETERS @@ -25,7 +24,7 @@ name:: If supplied, use the name and not the object id as the package name. state:: - The state the package should be in, either "present" or "absent" + Either "present" or "absent", defaults to "present" EXAMPLES diff --git a/cdist/conf/type/__package_pip/man.text b/cdist/conf/type/__package_pip/man.text index 8cb7d80a..5f619871 100644 --- a/cdist/conf/type/__package_pip/man.text +++ b/cdist/conf/type/__package_pip/man.text @@ -28,7 +28,7 @@ pip:: Instead of using pip from PATH, use the specific pip path. state:: - Either "present" or "absent", defaults to "present" + Either "present" or "absent", defaults to "present" EXAMPLES diff --git a/cdist/conf/type/__pf_ruleset/man.text b/cdist/conf/type/__pf_ruleset/man.text index 5c368e77..0dc07f71 100644 --- a/cdist/conf/type/__pf_ruleset/man.text +++ b/cdist/conf/type/__pf_ruleset/man.text @@ -26,6 +26,7 @@ source:: Note that this type is almost useless without a ruleset defined, but it's technically not needed, e.g. for the case of disabling the firewall temporarily. + EXAMPLES -------- diff --git a/cdist/conf/type/__postgres_role/man.text b/cdist/conf/type/__postgres_role/man.text index 4f13fa53..904f0831 100644 --- a/cdist/conf/type/__postgres_role/man.text +++ b/cdist/conf/type/__postgres_role/man.text @@ -16,7 +16,7 @@ This cdist type allows you to create or drop postgres roles. REQUIRED PARAMETERS ------------------- state:: - either 'present' or 'absent' + Either "present" or "absent", defaults to "present" OPTIONAL PARAMETERS diff --git a/cdist/conf/type/__process/man.text b/cdist/conf/type/__process/man.text index 929ba6a0..0d457ead 100644 --- a/cdist/conf/type/__process/man.text +++ b/cdist/conf/type/__process/man.text @@ -16,23 +16,23 @@ This cdist type allows you to define the state of a process. REQUIRED PARAMETERS ------------------- state:: - State of the process: Either present or absent + Either "present" or "absent", defaults to "present" OPTIONAL PARAMETERS ------------------- name:: - Process name to match on when using pgrep -f -x. + Process name to match on when using pgrep -f -x. - This is useful, if the name starts with a "/", - because the leading slash is stripped away from - the object id by cdist. + This is useful, if the name starts with a "/", + because the leading slash is stripped away from + the object id by cdist. stop:: - Executable to use for stopping the process. + Executable to use for stopping the process. start:: - Executable to use for starting the process. + Executable to use for starting the process. EXAMPLES diff --git a/cdist/conf/type/__qemu_img/man.text b/cdist/conf/type/__qemu_img/man.text index 3e16f957..39188ab0 100644 --- a/cdist/conf/type/__qemu_img/man.text +++ b/cdist/conf/type/__qemu_img/man.text @@ -24,8 +24,7 @@ size:: OPTIONAL PARAMETERS ------------------- state:: - The state of the image file: either "present" or "absent". - Defaults to "present". + Either "present" or "absent", defaults to "present" EXAMPLES diff --git a/cdist/conf/type/__rvm/man.text b/cdist/conf/type/__rvm/man.text index 0a355dc6..c1f83e60 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". EXAMPLES diff --git a/cdist/conf/type/__rvm_gem/man.text b/cdist/conf/type/__rvm_gem/man.text index 85b52d65..fbf9a622 100644 --- a/cdist/conf/type/__rvm_gem/man.text +++ b/cdist/conf/type/__rvm_gem/man.text @@ -16,16 +16,16 @@ RVM is the Ruby enVironment Manager for the Ruby programming language. REQUIRED PARAMETERS ------------------- user:: - The remote user account to use + The remote user account to use gemset:: - The gemset to use + The gemset to use state:: - Either "present" or "absent". + Either "present" or "absent" OPTIONAL PARAMETERS ------------------- default:: - Make the selected gemset the default + Make the selected gemset the default EXAMPLES -------- diff --git a/cdist/conf/type/__rvm_gemset/man.text b/cdist/conf/type/__rvm_gemset/man.text index 10b6b411..26e866ba 100644 --- a/cdist/conf/type/__rvm_gemset/man.text +++ b/cdist/conf/type/__rvm_gemset/man.text @@ -16,14 +16,14 @@ RVM is the Ruby enVironment Manager for the Ruby programming language. REQUIRED PARAMETERS ------------------- user:: - The remote user account to use + The remote user account to use state:: - Either "present" or "absent". + Either "present" or "absent". OPTIONAL PARAMETERS ------------------- default:: - If set to anything but "no" (the default), set the given gemset as default. + If set to anything but "no" (the default), set the given gemset as default. EXAMPLES -------- diff --git a/cdist/conf/type/__rvm_ruby/man.text b/cdist/conf/type/__rvm_ruby/man.text index c558cfe3..90a7b654 100644 --- a/cdist/conf/type/__rvm_ruby/man.text +++ b/cdist/conf/type/__rvm_ruby/man.text @@ -16,14 +16,14 @@ RVM is the Ruby enVironment Manager for the Ruby programming language. REQUIRED PARAMETERS ------------------- user:: - The remote user account to use + The remote user account to use state:: - Either "present" or "absent". + Either "present" or "absent". -OPTIONAL PARAMETERS -------------------- +BOOLEAN PARAMETERS +------------------ default: - If set to anything but "no" (the default), set the given version as default + If set to anything but "no" (the default), set the given version as default EXAMPLES -------- diff --git a/cdist/conf/type/__start_on_boot/man.text b/cdist/conf/type/__start_on_boot/man.text index 58a68d65..6d804884 100644 --- a/cdist/conf/type/__start_on_boot/man.text +++ b/cdist/conf/type/__start_on_boot/man.text @@ -24,7 +24,7 @@ None. OPTIONAL PARAMETERS ------------------- state:: - 'present' or 'absent', defaults to 'present' + Either "present" or "absent", defaults to "present" EXAMPLES From 482ec3c5d8bcd0d9dc4b7ba7df8bdfe39870f001 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 19:27:17 +0100 Subject: [PATCH 1818/4212] make --default boolean in type __rvm_ruby Signed-off-by: Nico Schottelius --- cdist/conf/type/__rvm_ruby/gencode-remote | 41 ++++++++++--------- cdist/conf/type/__rvm_ruby/man.text | 4 +- .../parameter/{optional => boolean} | 0 3 files changed, 23 insertions(+), 22 deletions(-) rename cdist/conf/type/__rvm_ruby/parameter/{optional => boolean} (100%) diff --git a/cdist/conf/type/__rvm_ruby/gencode-remote b/cdist/conf/type/__rvm_ruby/gencode-remote index 0003cfe7..f1de3906 100755 --- a/cdist/conf/type/__rvm_ruby/gencode-remote +++ b/cdist/conf/type/__rvm_ruby/gencode-remote @@ -24,23 +24,24 @@ user="$(cat "$__object/parameter/user")" default="$(cat "$__object/parameter/default" 2>/dev/null || true)" state_should="$(cat "$__object/parameter/state")" -if [ "$state_is" != "$state_should" ]; then - case "$state_should" in - present) - echo "su - \"$user\" -c \"source \\\$HOME/.rvm/scripts/rvm;"\ - "rvm install $ruby\"" - case "$default" in - no) - ;; - *) - echo "su - \"$user\" -c \"source \\\$HOME/.rvm/scripts/rvm;"\ - "rvm use --default $ruby\"" - ;; - esac - ;; - absent) - echo "su - \"$user\" -c \"source \\\$HOME/.rvm/scripts/rvm;"\ - "rvm remove $ruby\"" - ;; - esac -fi +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + echo "su - \"$user\" -c \"source \\\$HOME/.rvm/scripts/rvm;"\ + "rvm install $ruby\"" + if [ -f "$__object/parameter/default" ]; then + echo "su - \"$user\" -c \"source \\\$HOME/.rvm/scripts/rvm;"\ + "rvm use --default $ruby\"" + fi + ;; + absent) + echo "su - \"$user\" -c \"source \\\$HOME/.rvm/scripts/rvm;"\ + "rvm remove $ruby\"" + ;; + + *) + echo "Unknown state $state_should" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__rvm_ruby/man.text b/cdist/conf/type/__rvm_ruby/man.text index 90a7b654..dbbab85e 100644 --- a/cdist/conf/type/__rvm_ruby/man.text +++ b/cdist/conf/type/__rvm_ruby/man.text @@ -23,7 +23,7 @@ state:: BOOLEAN PARAMETERS ------------------ default: - If set to anything but "no" (the default), set the given version as default + Set the given version as default EXAMPLES -------- @@ -33,7 +33,7 @@ EXAMPLES __rvm_ruby ruby-1.9.3-p0 --user thelonious --state present # Install ruby 1.9.3 through rvm for user ornette and make it the default -__rvm_ruby ruby-1.9.3-p0 --user ornette --state present --default yes +__rvm_ruby ruby-1.9.3-p0 --user ornette --state present --default # Remove ruby 1.9.3 for user john __rvm_ruby ruby-1.9.3-p0 --user john --state absent diff --git a/cdist/conf/type/__rvm_ruby/parameter/optional b/cdist/conf/type/__rvm_ruby/parameter/boolean similarity index 100% rename from cdist/conf/type/__rvm_ruby/parameter/optional rename to cdist/conf/type/__rvm_ruby/parameter/boolean From fc7564c829db210c888fcbabc58f1019f03cc685 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Nov 2012 19:28:24 +0100 Subject: [PATCH 1819/4212] ++changes(next_version) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 5d3c1698..df5c1b2b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ Changelog * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, __ssh_authorized_key, __timezone, all install types (Steven Armstrong) * Types: Remove all parameter changing code + * Type __rvm_ruby: Change parameter "default" to be boolean 2.1.0pre7: 2012-11-07 * Core: All unit tests restored back to working From bbea7123f3422519bdabb41f760a1a5e77ad88c7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 11 Nov 2012 13:09:46 +0100 Subject: [PATCH 1820/4212] cdist prefix required Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-quickstart.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/man/man7/cdist-quickstart.text b/docs/man/man7/cdist-quickstart.text index 51943d41..b718da64 100644 --- a/docs/man/man7/cdist-quickstart.text +++ b/docs/man/man7/cdist-quickstart.text @@ -77,7 +77,7 @@ git clone git://git.schottelius.org/cdist # Create manifest (maps configuration to host(s) cd cdist -echo '__file /etc/cdist-configured' > conf/manifest/init +echo '__file /etc/cdist-configured' > cdist/conf/manifest/init # Configure localhost in verbose mode ./bin/cdist config -v localhost From 03ec09c771f0f89fae4b7f54c37476f04b435a4b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 14 Nov 2012 20:51:52 +0100 Subject: [PATCH 1821/4212] ++changes 2.1 documentation Signed-off-by: Nico Schottelius --- docs/dev/logs/2012-11-02.migration_to_2.1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/dev/logs/2012-11-02.migration_to_2.1 b/docs/dev/logs/2012-11-02.migration_to_2.1 index 2ef8df22..6c736a5c 100644 --- a/docs/dev/logs/2012-11-02.migration_to_2.1 +++ b/docs/dev/logs/2012-11-02.migration_to_2.1 @@ -38,3 +38,10 @@ by running cdist on one of your staging hosts: You can now cleanup the empty conf/ directory: % rmdir conf/* && rmdir conf + + + +-------------------------------------------------------------------------------- + +Boolean parameter introduced: + __directory /path/to --parents yes => __directory /path/to --parents From a498330bd3122b6abd150c543b89f22af85065bc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 09:32:44 +0100 Subject: [PATCH 1822/4212] remove _read_stdin and open stdin file in non-binary mode Signed-off-by: Nico Schottelius --- cdist/emulator.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 53c6914d..b6ee5166 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -149,8 +149,6 @@ class Emulator(object): # Record / Append source self.cdist_object.source.append(self.object_source) - def _read_stdin(self): - return self.stdin.read() def save_stdin(self): """If something is written to stdin, save it in the object as $__object/stdin so it can be accessed in manifest and gencode-* @@ -160,12 +158,10 @@ class Emulator(object): try: # go directly to file instead of using CdistObject's api # as that does not support streaming + # FIXME: no streaming needed anymore path = os.path.join(self.cdist_object.absolute_path, 'stdin') - with open(path, 'wb') as fd: - chunk = self._read_stdin() - while chunk: - fd.write(chunk) - chunk = self._read_stdin() + with open(path, 'w') as fd: + fd.write(self.stdin.read()) except EnvironmentError as e: raise cdist.Error('Failed to read from stdin: %s' % e) From 2fca87eda855449734b6e5588d3da60f94e1a7e5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 09:34:19 +0100 Subject: [PATCH 1823/4212] ++comment Signed-off-by: Nico Schottelius --- cdist/emulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index b6ee5166..e54bd0dc 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -158,7 +158,7 @@ class Emulator(object): try: # go directly to file instead of using CdistObject's api # as that does not support streaming - # FIXME: no streaming needed anymore + # FIXME: no streaming needed anymore - use a raw file (not yet there?) path = os.path.join(self.cdist_object.absolute_path, 'stdin') with open(path, 'w') as fd: fd.write(self.stdin.read()) From 80c6592ec8676c1963573d54e3aa80008b7d100b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 09:49:37 +0100 Subject: [PATCH 1824/4212] add hints to related manpages Signed-off-by: Nico Schottelius --- cdist/conf/type/__user/man.text | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__user/man.text b/cdist/conf/type/__user/man.text index e571c7c5..7be2c2f2 100644 --- a/cdist/conf/type/__user/man.text +++ b/cdist/conf/type/__user/man.text @@ -54,6 +54,7 @@ __user foobar --uid 1001 --shell /bin/zsh --home /home/foobar SEE ALSO -------- - cdist-type(7) +- usermod(8) or pw(8) COPYING From 91de1b08aa76e1c750ebab6946d809166fcefd0d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 10:53:24 +0100 Subject: [PATCH 1825/4212] replace ascii logo by png logo (search engines don't like the ascii version Signed-off-by: Nico Schottelius --- docs/web/cdist.mdwn | 15 +-------------- docs/web/cdist/cdist-logo.png | Bin 0 -> 1542 bytes 2 files changed, 1 insertion(+), 14 deletions(-) create mode 100644 docs/web/cdist/cdist-logo.png diff --git a/docs/web/cdist.mdwn b/docs/web/cdist.mdwn index ffd0bcb5..d25714b5 100644 --- a/docs/web/cdist.mdwn +++ b/docs/web/cdist.mdwn @@ -1,19 +1,6 @@ [[!meta title="cdist - usable configuration management"]] - - .. . .x+=:. s - dF @88> z` ^% :8 - '88bu. %8P . Px#22e~?MF0Q*|NsA`*`M72000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipS@ z0U8oZ%R(#w00o9gL_t(o!|j;OOC(1Wz^mIa(<@6fGKU5*AnRX5Vhb0Zp zl-0j^^}hPms}|z_>pi<{At%Dr`U@U4gF4RoGSKpzdV%|9@IftRZLXV9@rE>N@N!C~ zGe!OUp&qdMyVA_e*UFQ*nQ6FwG6UDY#;;ZQdr1m53*5jARMf$*1#sLK#5utjPU&db zU785>|Q;`jcYt&fW8y13Dv?GjzEFS5zgd^L_8Dcpp*UC7%Q|3g| zeW!0Xc2ln5Rr4S=Vw`9rom{QR%eaLoD99VfwGKs%e!wYXuc>Ro!YNg8JEj$j^K%vMI*!X+fZJ61zup&| z_&2@o@#j2c4Ow58Hv--l{9E;X!t)PThohc&SqQ&#?tli zeQ~q`w_7_Q4-|PvJ%@O73;v3uexPskGwxuUxYYml(wYAUI%ek9r9qEY?};s1j`9Ns zws+2%V_kFL`}_%&3B=6YnssgO7v^UEE^rn<`DuRG-WhWykyiNA+NRs7e#(n=#)dSo zC4b`2WX@hcQKUGP1Q;~i_~10#_Lg>}wnLWcfIX@<+++6!>FOsE(lNYg;o!>kuYLrZ zgn0Pmn(d&{8hK&l4S+j!SA~?-kZ(d{hS{KtRyo7mHqy$s_JuIA?hdVknB7 zLmcRLeo>TXD!t|!#KppS^(U1G?uTqIrW6TN&L%q)1U|fh!8$5_6|fyo5;wJD>?Nn8 z7@(SuyO_)`(2ft;4l8l7-_6;9W~(mlmj~#Vqtq{l($Q`rzu?yO%mX=fdC=B&2+U{e4Ydo2tmeVMoEvfXx48|#$#HqW zTvw#rm^=`@-JY`kV#Va)&A7P1?!T;r((*!4!$HtGcXKPzc`S^6g>{Se%ENDB0rpaV z5LWU)8vnI-KXJt}pCil*k@~kQ_nrqXYSH9EMl)|%efJ-1(-zZu5F_WnM!-h{74^xT z;0|clXTjlN%3T{{fFAO-|Ift!@>@-G2m|qxhyoK=0!BZA|iCn43h9NNJLMXkOv16dzyd&)Y5*|k+R=&8w!jnSNv6LK39 saY9X~U}r+kn~+ Date: Thu, 15 Nov 2012 11:15:27 +0100 Subject: [PATCH 1826/4212] split off features Signed-off-by: Nico Schottelius --- docs/web/cdist.mdwn | 29 ----------------------------- docs/web/cdist/features.mdwn | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 29 deletions(-) create mode 100644 docs/web/cdist/features.mdwn diff --git a/docs/web/cdist.mdwn b/docs/web/cdist.mdwn index d25714b5..a69ea034 100644 --- a/docs/web/cdist.mdwn +++ b/docs/web/cdist.mdwn @@ -2,11 +2,6 @@ ![cdist-logo](cdist-logo.png "cdist logo") -[[!toc levels=3]] - -## Introduction - -cdist is a usable configuration management system. It adheres to the KISS principle and is being used in small up to enterprise grade environments. cdist is an alternative to other configuration management systems like @@ -14,30 +9,6 @@ cdist is an alternative to other configuration management systems like [bcfg2](http://trac.mcs.anl.gov/projects/bcfg2), [chef](http://wiki.opscode.com/display/chef/) and [puppet](http://www.puppetlabs.com/). -But cdist ticks differently, here is the feature set that makes it unique: - -[[!table data=""" -Keywords | Description -Simplicity | There is only one type to extend cdist called ***type*** -Design | Type and core cleanly seperated -Design | Sticks completly to the KISS (keep it simple and stupid) paradigma -Design | Meaningful error messages - do not lose time debugging error messages -Design | Consistency in behaviour, naming and documentation -Design | No surprise factor: Only do what is obviously clear, no magic -Design | Define target state, do not focus on methods or scripts -Design | Push architecture: Instantly apply your changes -Small core | cdist's core is very small - less code, less bugs -Fast development | Focus on straightforwardness of type creation is a main development objective -Fast development | Batteries included: A lot of requirements can be solved using standard types -Modern Programming Language | cdist is written in Python -Requirements, Scalability | No central server needed, cdist operates in push mode and can be run from any computer -Requirements, Scalability, Upgrade | cdist only needs to be updated on the master, not on the target hosts -Requirements, Security | Uses well-know [SSH](http://www.openssh.com/) as transport protocol -Requirements, Simplicity | Requires only shell and SSH server on the target -UNIX | Reuse of existing tools like cat, find, mv, ... -UNIX, familar environment, documentation | Is available as manpages and HTML -UNIX, simplicity, familar environment | cdist is configured in POSIX shell -"""]] ### Documentation diff --git a/docs/web/cdist/features.mdwn b/docs/web/cdist/features.mdwn new file mode 100644 index 00000000..1b3525ac --- /dev/null +++ b/docs/web/cdist/features.mdwn @@ -0,0 +1,22 @@ +[[!table data=""" +Keywords | Description +Simplicity | There is only one type to extend cdist called ***type*** +Design | Type and core cleanly seperated +Design | Sticks completly to the KISS (keep it simple and stupid) paradigma +Design | Meaningful error messages - do not lose time debugging error messages +Design | Consistency in behaviour, naming and documentation +Design | No surprise factor: Only do what is obviously clear, no magic +Design | Define target state, do not focus on methods or scripts +Design | Push architecture: Instantly apply your changes +Small core | cdist's core is very small - less code, less bugs +Fast development | Focus on straightforwardness of type creation is a main development objective +Fast development | Batteries included: A lot of requirements can be solved using standard types +Modern Programming Language | cdist is written in Python +Requirements, Scalability | No central server needed, cdist operates in push mode and can be run from any computer +Requirements, Scalability, Upgrade | cdist only needs to be updated on the master, not on the target hosts +Requirements, Security | Uses well-know [SSH](http://www.openssh.com/) as transport protocol +Requirements, Simplicity | Requires only shell and SSH server on the target +UNIX | Reuse of existing tools like cat, find, mv, ... +UNIX, familar environment, documentation | Is available as manpages and HTML +UNIX, simplicity, familar environment | cdist is configured in POSIX shell +"""]] From 2d59bb01a5a3a70a161313de54fd36e0870e2f5d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 11:24:04 +0100 Subject: [PATCH 1827/4212] split install/update into its own file Signed-off-by: Nico Schottelius --- docs/web/cdist.mdwn | 226 +---------------------------- docs/web/cdist/features.mdwn | 2 + docs/web/cdist/install-update.mdwn | 218 ++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+), 224 deletions(-) create mode 100644 docs/web/cdist/install-update.mdwn diff --git a/docs/web/cdist.mdwn b/docs/web/cdist.mdwn index a69ea034..4d8fe82b 100644 --- a/docs/web/cdist.mdwn +++ b/docs/web/cdist.mdwn @@ -10,13 +10,8 @@ cdist is an alternative to other configuration management systems like [chef](http://wiki.opscode.com/display/chef/) and [puppet](http://www.puppetlabs.com/). -### Documentation - -The cdist documentation is included as manpages in the distribution. -You can browse the documentation online as well: - - * [latest version](man/latest) - * [all versions (>= 2.0.4)](man) + * Browse the **documentation** for the [latest version](man/latest) or [all versions (>= 2.0.4)](man) + * Read how to [[install or update cdist|install-update]] ### OS support @@ -34,223 +29,6 @@ cdist was tested or is know to run on at least * [XenServer](http://www.citrix.com/xenserver/) -## Requirements - -### Server - - * A posix like shell - * Python (>= 3.2 required) - * SSH client - * Asciidoc (for building the manpages) - -### Client ("target host") - - * A posix like shell - * SSH server - - -## Installation - -### Preparation - -Ensure you have Python 3.2 installed on the machine you use to **deploy to the targets** -(the ***source host***). - -#### Archlinux - -Archlinux already has python >= 3.2, so you only need to do: - - pacman -S python - -#### CentOS - -See the "From source" section - -#### Debian - -For Debian >= wheezy: - - aptitude install python3 - -On squeeze you can add following line in **/etc/apt/sources.list** - - deb http://ftp.debian.org/debian wheezy main - -And add pinning entry in **/etc/apt/preferences.d/wheezy**: - - Package: * - Pin: release n=wheezy - Pin-Priority: 1 - -Please be aware that both **openssh-server** and **openssh-client** might be -removed on **python3.2** installation. You surely want to reinstall them: - - apt-get install -t wheezy openssh-server openssh-client - -For older Debian versions, installing python 3.2 manually is required. - - -#### Fedora - -For Fedora >= 15: - - yum install python3 - -#### FreeBSD - -For the port: - - cd /usr/ports/lang/python32/ && make install clean - -For the package: - - pkg_add -r python32 - -#### Gentoo - -Gentoo only provides python 3.2 in testing packages (http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=3&chap=3). -If you want to ensure nothing breaks you must set back the python version to what was default before. - - emerge -av =python-3.2.2 --autounmask-write - emerge -av =python-3.2.2 - eselect python list - eselect python list set python3.2 - -#### Max OS X - -You can choose between Homebrew and Macports, either way works: - -[Homebrew](http://mxcl.github.com/homebrew/) variant: - - brew install python3 - -[Macports](http://www.macports.org/install.php) variant: - - port install python32 - ln -s /opt/local/bin/python3.2 /opt/local/bin/python3 - -#### From Source - -For those operating systems not yet support Python 3.2: - - pyversion=3.2.3 - wget http://www.python.org/ftp/python/$pyversion/Python-${pyversion}.tar.bz2 - tar xvfj Python-${pyversion}.tar.bz2 - cd Python-${pyversion} - ./configure - make - sudo make install - -This installs python 3.2 to /usr/local/bin. Ensure this directory is in -your PATH environment variable. - - -### Get cdist - -You can clone cdist from git, which gives you the advantage of having -a version control in place for development of your own stuff as well. -To install cdist, execute the following commands: - - git clone git://git.schottelius.org/cdist - cd cdist - export PATH=$PATH:$(pwd -P)/bin - - # If you want the manpages - ./build man - export MANPATH=$MANPATH:$(pwd -P)/doc/man - - -### Available versions - -There are at least the following branches available: - - * Development: master - * 2.0: Python rewrite of cdist core [stable branch] - -Old versions: - - * 1.7: Bugfixes, cleanups, new type and explorer rename - * 1.6: New types, cleaned up \_\_package* types, internal cleanup - * 1.5: Focus on object orientation instead of global stage orientation - * 1.4: Support for redefiniton of objects (if equal) - * 1.3: Support for local and remote code execution (current stable) - * 1.2: Dependencies supported - * 1.1: \_\_file to \_\_file, \_\_directory, \_\_link migration - * 1.0: First official release - -Other branches may be available for features or bugfixes, but they -may vanish at any point. To select a specific branch use - - # Generic code - git checkout -b origin/ - - # Stay on a specific version - version=2.0 - git checkout -b $version origin/$version - -### Mirrors - - * git://github.com/telmich/cdist.git ([github](https://github.com/telmich/cdist)) - * git://git.code.sf.net/p/cdist/code ([sourceforge](https://sourceforge.net/p/cdist/code)) - -## Update - -To upgrade cdist in the current branch use - - git pull - - # Also update the manpages - ./build man - export MANPATH=$MANPATH:$(pwd -P)/doc/man - -If you stay on a version branche (i.e. 1.0, 1.1., ...), nothing should break. -The master branch on the other hand is the development branch and may not be -working, break your setup or eat the tree in your garden. - -### Upgrading from 1.7 to 2.0 - -* Ensure python (>= 3.2) is installed on the server -* Use "cdist config host" instead of "cdist-deploy-to host" -* Use "cdist config -p host1 host2" instead of "cdist-mass-deploy" -* Use "cdist banner" for fun -* Use **\_\_object_fq** instead of **\_\_self** in manifests - -### Upgrading from 1.6 to 1.7 - -* If you used the global explorer **hardware_type**, you need to change - your code to use **machine** instead. - -### Upgrading from 1.5 to 1.6 - -* If you used **\_\_package_apt --preseed**, you need to use the new - type **\_\_debconf_set_selections** instead. -* The **\_\_package** types accepted either --state deinstalled or - --state uninstaaled. Starting with 1.6, it was made consistently - to --state removed. - -### Upgrading from 1.3 to 1.5 - -No incompatiblities. - -### Upgrading from 1.2 to 1.3 - -Rename **gencode** of every type to **gencode-remote**. - -### Upgrading from 1.1 to 1.2 - -No incompatiblities. - -### Upgrading from 1.0 to 1.1 - -In 1.1 the type **\_\_file** was split into **\_\_directory**, **\_\_file** and -**\_\_link**. The parameter **--type** was removed from **\_\_file**. Thus you -need to replace **\_\_file** calls in your manifests: - - * Remove --type from all \_\_file calls - * If type was symlink, use \_\_link and --type symbolic - * If type was directory, use \_\_directory - - ## Support ### IRC diff --git a/docs/web/cdist/features.mdwn b/docs/web/cdist/features.mdwn index 1b3525ac..c1fecb53 100644 --- a/docs/web/cdist/features.mdwn +++ b/docs/web/cdist/features.mdwn @@ -1,3 +1,5 @@ +But cdist ticks differently, here is the feature set that makes it unique: + [[!table data=""" Keywords | Description Simplicity | There is only one type to extend cdist called ***type*** diff --git a/docs/web/cdist/install-update.mdwn b/docs/web/cdist/install-update.mdwn new file mode 100644 index 00000000..67d9df8c --- /dev/null +++ b/docs/web/cdist/install-update.mdwn @@ -0,0 +1,218 @@ +## Requirements + +### Server + + * A posix like shell + * Python (>= 3.2 required) + * SSH client + * Asciidoc (for building the manpages) + +### Client ("target host") + + * A posix like shell + * SSH server + + +## Installation + +### Preparation + +Ensure you have Python 3.2 installed on the machine you use to **deploy to the targets** +(the ***source host***). + +#### Archlinux + +Archlinux already has python >= 3.2, so you only need to do: + + pacman -S python + +#### CentOS + +See the "From source" section + +#### Debian + +For Debian >= wheezy: + + aptitude install python3 + +On squeeze you can add following line in **/etc/apt/sources.list** + + deb http://ftp.debian.org/debian wheezy main + +And add pinning entry in **/etc/apt/preferences.d/wheezy**: + + Package: * + Pin: release n=wheezy + Pin-Priority: 1 + +Please be aware that both **openssh-server** and **openssh-client** might be +removed on **python3.2** installation. You surely want to reinstall them: + + apt-get install -t wheezy openssh-server openssh-client + +For older Debian versions, installing python 3.2 manually is required. + + +#### Fedora + +For Fedora >= 15: + + yum install python3 + +#### FreeBSD + +For the port: + + cd /usr/ports/lang/python32/ && make install clean + +For the package: + + pkg_add -r python32 + +#### Gentoo + +Gentoo only provides python 3.2 in testing packages (http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=3&chap=3). +If you want to ensure nothing breaks you must set back the python version to what was default before. + + emerge -av =python-3.2.2 --autounmask-write + emerge -av =python-3.2.2 + eselect python list + eselect python list set python3.2 + +#### Max OS X + +You can choose between Homebrew and Macports, either way works: + +[Homebrew](http://mxcl.github.com/homebrew/) variant: + + brew install python3 + +[Macports](http://www.macports.org/install.php) variant: + + port install python32 + ln -s /opt/local/bin/python3.2 /opt/local/bin/python3 + +#### From Source + +For those operating systems not yet support Python 3.2: + + pyversion=3.2.3 + wget http://www.python.org/ftp/python/$pyversion/Python-${pyversion}.tar.bz2 + tar xvfj Python-${pyversion}.tar.bz2 + cd Python-${pyversion} + ./configure + make + sudo make install + +This installs python 3.2 to /usr/local/bin. Ensure this directory is in +your PATH environment variable. + + +### Get cdist + +You can clone cdist from git, which gives you the advantage of having +a version control in place for development of your own stuff as well. +To install cdist, execute the following commands: + + git clone git://git.schottelius.org/cdist + cd cdist + export PATH=$PATH:$(pwd -P)/bin + + # If you want the manpages + ./build man + export MANPATH=$MANPATH:$(pwd -P)/doc/man + + +### Available versions + +There are at least the following branches available: + + * Development: master + * 2.0: Python rewrite of cdist core [stable branch] + +Old versions: + + * 1.7: Bugfixes, cleanups, new type and explorer rename + * 1.6: New types, cleaned up \_\_package* types, internal cleanup + * 1.5: Focus on object orientation instead of global stage orientation + * 1.4: Support for redefiniton of objects (if equal) + * 1.3: Support for local and remote code execution (current stable) + * 1.2: Dependencies supported + * 1.1: \_\_file to \_\_file, \_\_directory, \_\_link migration + * 1.0: First official release + +Other branches may be available for features or bugfixes, but they +may vanish at any point. To select a specific branch use + + # Generic code + git checkout -b origin/ + + # Stay on a specific version + version=2.0 + git checkout -b $version origin/$version + +### Mirrors + + * git://github.com/telmich/cdist.git ([github](https://github.com/telmich/cdist)) + * git://git.code.sf.net/p/cdist/code ([sourceforge](https://sourceforge.net/p/cdist/code)) + +## Update + +To upgrade cdist in the current branch use + + git pull + + # Also update the manpages + ./build man + export MANPATH=$MANPATH:$(pwd -P)/doc/man + +If you stay on a version branche (i.e. 1.0, 1.1., ...), nothing should break. +The master branch on the other hand is the development branch and may not be +working, break your setup or eat the tree in your garden. + +### Upgrading from 1.7 to 2.0 + +* Ensure python (>= 3.2) is installed on the server +* Use "cdist config host" instead of "cdist-deploy-to host" +* Use "cdist config -p host1 host2" instead of "cdist-mass-deploy" +* Use "cdist banner" for fun +* Use **\_\_object_fq** instead of **\_\_self** in manifests + +### Upgrading from 1.6 to 1.7 + +* If you used the global explorer **hardware_type**, you need to change + your code to use **machine** instead. + +### Upgrading from 1.5 to 1.6 + +* If you used **\_\_package_apt --preseed**, you need to use the new + type **\_\_debconf_set_selections** instead. +* The **\_\_package** types accepted either --state deinstalled or + --state uninstaaled. Starting with 1.6, it was made consistently + to --state removed. + +### Upgrading from 1.3 to 1.5 + +No incompatiblities. + +### Upgrading from 1.2 to 1.3 + +Rename **gencode** of every type to **gencode-remote**. + +### Upgrading from 1.1 to 1.2 + +No incompatiblities. + +### Upgrading from 1.0 to 1.1 + +In 1.1 the type **\_\_file** was split into **\_\_directory**, **\_\_file** and +**\_\_link**. The parameter **--type** was removed from **\_\_file**. Thus you +need to replace **\_\_file** calls in your manifests: + + * Remove --type from all \_\_file calls + * If type was symlink, use \_\_link and --type symbolic + * If type was directory, use \_\_directory + + +[[!tag cdist unix]] From b6d3bfe64f353448ca9ec6e420ee07fe5e612865 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 11:25:57 +0100 Subject: [PATCH 1828/4212] split off support Signed-off-by: Nico Schottelius --- docs/web/cdist.mdwn | 26 ++------------------------ docs/web/cdist/support.mdwn | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 24 deletions(-) create mode 100644 docs/web/cdist/support.mdwn diff --git a/docs/web/cdist.mdwn b/docs/web/cdist.mdwn index 4d8fe82b..fff727bf 100644 --- a/docs/web/cdist.mdwn +++ b/docs/web/cdist.mdwn @@ -12,6 +12,7 @@ and [puppet](http://www.puppetlabs.com/). * Browse the **documentation** for the [latest version](man/latest) or [all versions (>= 2.0.4)](man) * Read how to [[install or update cdist|install-update]] + * [[Support|support]] ### OS support @@ -21,6 +22,7 @@ cdist was tested or is know to run on at least * [Debian](http://www.debian.org/) * [CentOS](http://www.centos.org/) * [Fedora](http://fedoraproject.org/) + * [FreeBSD](http://www.freebsd.org) * [Gentoo](http://www.gentoo.org/) * [Mac OS X](http://www.apple.com/macosx/) * [OpenBSD](http://www.openbsd.org) @@ -29,30 +31,6 @@ cdist was tested or is know to run on at least * [XenServer](http://www.citrix.com/xenserver/) -## Support - -### IRC - -You can join the development ***IRC channel*** -[#cstar on irc.freenode.net](irc://irc.freenode.org/#cstar). - -### Mailing list - -Bug reports, questions, patches, etc. should be send to the -[cdist mailing list](http://l.schottelius.org/mailman/listinfo/cdist). - -### Linkedin - -If you have an account -at [Linked in](http://www.linkedin.com/), -you can join the -[cdist group](http://www.linkedin.com/groups/cdist-configuration-management-3952797). - -### Commercial support - -You can request commercial support for cdist from -[my company](http://firma.schottelius.org/english/). - ## Used by If you're using cdist, feel free to send a report to the mailing list. diff --git a/docs/web/cdist/support.mdwn b/docs/web/cdist/support.mdwn new file mode 100644 index 00000000..47ee1193 --- /dev/null +++ b/docs/web/cdist/support.mdwn @@ -0,0 +1,23 @@ +## Support + +### IRC + +You can join the development ***IRC channel*** +[#cstar on irc.freenode.net](irc://irc.freenode.org/#cstar). + +### Mailing list + +Bug reports, questions, patches, etc. should be send to the +[cdist mailing list](http://l.schottelius.org/mailman/listinfo/cdist). + +### Linkedin + +If you have an account +at [Linked in](http://www.linkedin.com/), +you can join the +[cdist group](http://www.linkedin.com/groups/cdist-configuration-management-3952797). + +### Commercial support + +You can request commercial support for cdist from +[my company](http://firma.schottelius.org/english/). From 7272a7b13cfbdf02fc0659f055c3c6938dfc7186 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 11:36:28 +0100 Subject: [PATCH 1829/4212] move operating sytems to a new page Signed-off-by: Nico Schottelius --- docs/web/cdist.mdwn | 34 ---------------------------------- docs/web/cdist/features.mdwn | 2 ++ docs/web/cdist/os.mdwn | 15 +++++++++++++++ docs/web/cdist/support.mdwn | 2 ++ 4 files changed, 19 insertions(+), 34 deletions(-) create mode 100644 docs/web/cdist/os.mdwn diff --git a/docs/web/cdist.mdwn b/docs/web/cdist.mdwn index fff727bf..ab501f56 100644 --- a/docs/web/cdist.mdwn +++ b/docs/web/cdist.mdwn @@ -30,38 +30,4 @@ cdist was tested or is know to run on at least * [Ubuntu](http://www.ubuntu.com/) * [XenServer](http://www.citrix.com/xenserver/) - -## Used by - -If you're using cdist, feel free to send a report to the mailing list. -Interesting information are for instance - - * Which services do you manage? - * How many machines do you manage? - * What are the pros/cons you see in cdist? - * General comments/critics - -### Nico Schottelius, Systems Group ETH Zurich, local.ch and privately - -Yes, I'm actually eating my own dogfood and currently managing - - * [plone](http://plone.org/) (cms) - * [moinmoin](http://moinmo.in/) (wiki) - * [apache](http://httpd.apache.org/) (webserver) - * [kerberos (mit)](http://web.mit.edu/kerberos/) (authentication) - * [nss-pam-ldapd](http://arthurdejong.org/nss-pam-ldapd/) (authentication) - * [ircd-hybrid](http://www.ircd-hybrid.org/) (chat) - * [stunnel](http://stunnel.mirt.net/) (SSL tunnel) - * [mercurial-server](http://www.lshift.net/mercurial-server.html) (version control) - * [xfce](http://www.xfce.org/) (lightweight desktop environment) - * [slim](http://slim.berlios.de/) (graphical login manager for X11) - -with cdist on more than **60** production machines of the -[Systems Group](http://www.systems.ethz.ch) at the -[ETH Zurich](http://www.ethz.ch) as well at home. - -### Steven Armstrong, CBRG ETH Zurich - -The CBRG is managing most of their compute clusters with cdist. - [[!tag cdist unix]] diff --git a/docs/web/cdist/features.mdwn b/docs/web/cdist/features.mdwn index c1fecb53..a97f2013 100644 --- a/docs/web/cdist/features.mdwn +++ b/docs/web/cdist/features.mdwn @@ -22,3 +22,5 @@ UNIX | Reuse of existing tools like cat, find, mv, ... UNIX, familar environment, documentation | Is available as manpages and HTML UNIX, simplicity, familar environment | cdist is configured in POSIX shell """]] + +[[!tag cdist unix]] diff --git a/docs/web/cdist/os.mdwn b/docs/web/cdist/os.mdwn new file mode 100644 index 00000000..d53bc1c9 --- /dev/null +++ b/docs/web/cdist/os.mdwn @@ -0,0 +1,15 @@ +cdist was tested or is know to run on at least + + * [Archlinux](http://www.archlinux.org/) + * [Debian](http://www.debian.org/) + * [CentOS](http://www.centos.org/) + * [Fedora](http://fedoraproject.org/) + * [FreeBSD](http://www.freebsd.org) + * [Gentoo](http://www.gentoo.org/) + * [Mac OS X](http://www.apple.com/macosx/) + * [OpenBSD](http://www.openbsd.org) + * [Redhat](http://www.redhat.com/) + * [Ubuntu](http://www.ubuntu.com/) + * [XenServer](http://www.citrix.com/xenserver/) + +[[!tag cdist unix]] diff --git a/docs/web/cdist/support.mdwn b/docs/web/cdist/support.mdwn index 47ee1193..7515070d 100644 --- a/docs/web/cdist/support.mdwn +++ b/docs/web/cdist/support.mdwn @@ -21,3 +21,5 @@ you can join the You can request commercial support for cdist from [my company](http://firma.schottelius.org/english/). + +[[!tag cdist unix]] From 8ab91009e10caec87751943d894d3e8f39cd04b5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 12:00:25 +0100 Subject: [PATCH 1830/4212] Cleanup of install, update and general documentation Signed-off-by: Nico Schottelius --- docs/web/cdist.mdwn | 22 +--- .../{install-update.mdwn => install.mdwn} | 109 +++++------------- docs/web/cdist/update.mdwn | 59 ++++++++++ 3 files changed, 91 insertions(+), 99 deletions(-) rename docs/web/cdist/{install-update.mdwn => install.mdwn} (59%) create mode 100644 docs/web/cdist/update.mdwn diff --git a/docs/web/cdist.mdwn b/docs/web/cdist.mdwn index ab501f56..e0e1f504 100644 --- a/docs/web/cdist.mdwn +++ b/docs/web/cdist.mdwn @@ -10,24 +10,10 @@ cdist is an alternative to other configuration management systems like [chef](http://wiki.opscode.com/display/chef/) and [puppet](http://www.puppetlabs.com/). - * Browse the **documentation** for the [latest version](man/latest) or [all versions (>= 2.0.4)](man) - * Read how to [[install or update cdist|install-update]] + * **Documentation** for the [latest version](man/latest) or [all versions (>= 2.0.4)](man) + * [[Installation|install]] + * [[Update|update]] + * [[Supported Operating Systems|os]] * [[Support|support]] -### OS support - -cdist was tested or is know to run on at least - - * [Archlinux](http://www.archlinux.org/) - * [Debian](http://www.debian.org/) - * [CentOS](http://www.centos.org/) - * [Fedora](http://fedoraproject.org/) - * [FreeBSD](http://www.freebsd.org) - * [Gentoo](http://www.gentoo.org/) - * [Mac OS X](http://www.apple.com/macosx/) - * [OpenBSD](http://www.openbsd.org) - * [Redhat](http://www.redhat.com/) - * [Ubuntu](http://www.ubuntu.com/) - * [XenServer](http://www.citrix.com/xenserver/) - [[!tag cdist unix]] diff --git a/docs/web/cdist/install-update.mdwn b/docs/web/cdist/install.mdwn similarity index 59% rename from docs/web/cdist/install-update.mdwn rename to docs/web/cdist/install.mdwn index 67d9df8c..43b0e3e1 100644 --- a/docs/web/cdist/install-update.mdwn +++ b/docs/web/cdist/install.mdwn @@ -1,42 +1,44 @@ +[[!toc levels=3]] + ## Requirements -### Server +### Source Host - * A posix like shell +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 required) * SSH client * Asciidoc (for building the manpages) -### Client ("target host") +### Target Hosts - * A posix like shell + * /bin/sh: A posix like shell (for instance bash, dash, zsh) * SSH server - -## Installation - -### Preparation +## Python Installation Ensure you have Python 3.2 installed on the machine you use to **deploy to the targets** (the ***source host***). -#### Archlinux +### Archlinux -Archlinux already has python >= 3.2, so you only need to do: +Archlinux includes a recent python in the extra repository. +You can install it using pacman -S python -#### CentOS +### CentOS See the "From source" section #### Debian -For Debian >= wheezy: +For Debian **wheezy** or newer: aptitude install python3 -On squeeze you can add following line in **/etc/apt/sources.list** +On **squeeze** you can add following line in **/etc/apt/sources.list** deb http://ftp.debian.org/debian wheezy main @@ -51,16 +53,16 @@ removed on **python3.2** installation. You surely want to reinstall them: apt-get install -t wheezy openssh-server openssh-client -For older Debian versions, installing python 3.2 manually is required. +For older Debian versions, installing python 3.2 from source is required. +### Fedora -#### Fedora - -For Fedora >= 15: +Fedora 15 and newer includes a recent python. +You can install it using yum install python3 -#### FreeBSD +### FreeBSD For the port: @@ -70,7 +72,9 @@ For the package: pkg_add -r python32 -#### Gentoo +You can also use any newer version, but at least python 3.2 is required. + +### Gentoo Gentoo only provides python 3.2 in testing packages (http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=3&chap=3). If you want to ensure nothing breaks you must set back the python version to what was default before. @@ -80,7 +84,7 @@ If you want to ensure nothing breaks you must set back the python version to wha eselect python list eselect python list set python3.2 -#### Max OS X +### Max OS X You can choose between Homebrew and Macports, either way works: @@ -93,7 +97,7 @@ You can choose between Homebrew and Macports, either way works: port install python32 ln -s /opt/local/bin/python3.2 /opt/local/bin/python3 -#### From Source +### From Source For those operating systems not yet support Python 3.2: @@ -109,7 +113,7 @@ This installs python 3.2 to /usr/local/bin. Ensure this directory is in your PATH environment variable. -### Get cdist +## Install cdist You can clone cdist from git, which gives you the advantage of having a version control in place for development of your own stuff as well. @@ -129,7 +133,8 @@ To install cdist, execute the following commands: There are at least the following branches available: * Development: master - * 2.0: Python rewrite of cdist core [stable branch] + * 2.0: Current stable branch + * 2.1: Currently experimental - the next stable branch Old versions: @@ -157,62 +162,4 @@ may vanish at any point. To select a specific branch use * git://github.com/telmich/cdist.git ([github](https://github.com/telmich/cdist)) * git://git.code.sf.net/p/cdist/code ([sourceforge](https://sourceforge.net/p/cdist/code)) -## Update - -To upgrade cdist in the current branch use - - git pull - - # Also update the manpages - ./build man - export MANPATH=$MANPATH:$(pwd -P)/doc/man - -If you stay on a version branche (i.e. 1.0, 1.1., ...), nothing should break. -The master branch on the other hand is the development branch and may not be -working, break your setup or eat the tree in your garden. - -### Upgrading from 1.7 to 2.0 - -* Ensure python (>= 3.2) is installed on the server -* Use "cdist config host" instead of "cdist-deploy-to host" -* Use "cdist config -p host1 host2" instead of "cdist-mass-deploy" -* Use "cdist banner" for fun -* Use **\_\_object_fq** instead of **\_\_self** in manifests - -### Upgrading from 1.6 to 1.7 - -* If you used the global explorer **hardware_type**, you need to change - your code to use **machine** instead. - -### Upgrading from 1.5 to 1.6 - -* If you used **\_\_package_apt --preseed**, you need to use the new - type **\_\_debconf_set_selections** instead. -* The **\_\_package** types accepted either --state deinstalled or - --state uninstaaled. Starting with 1.6, it was made consistently - to --state removed. - -### Upgrading from 1.3 to 1.5 - -No incompatiblities. - -### Upgrading from 1.2 to 1.3 - -Rename **gencode** of every type to **gencode-remote**. - -### Upgrading from 1.1 to 1.2 - -No incompatiblities. - -### Upgrading from 1.0 to 1.1 - -In 1.1 the type **\_\_file** was split into **\_\_directory**, **\_\_file** and -**\_\_link**. The parameter **--type** was removed from **\_\_file**. Thus you -need to replace **\_\_file** calls in your manifests: - - * Remove --type from all \_\_file calls - * If type was symlink, use \_\_link and --type symbolic - * If type was directory, use \_\_directory - - [[!tag cdist unix]] diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn new file mode 100644 index 00000000..085075e7 --- /dev/null +++ b/docs/web/cdist/update.mdwn @@ -0,0 +1,59 @@ +## Update + +To upgrade cdist in the current branch use + + git pull + + # Also update the manpages + ./build man + export MANPATH=$MANPATH:$(pwd -P)/doc/man + +If you stay on a version branche (i.e. 1.0, 1.1., ...), nothing should break. +The master branch on the other hand is the development branch and may not be +working, break your setup or eat the tree in your garden. + +### Upgrading from 1.7 to 2.0 + +* Ensure python (>= 3.2) is installed on the server +* Use "cdist config host" instead of "cdist-deploy-to host" +* Use "cdist config -p host1 host2" instead of "cdist-mass-deploy" +* Use "cdist banner" for fun +* Use **\_\_object_fq** instead of **\_\_self** in manifests + +### Upgrading from 1.6 to 1.7 + +* If you used the global explorer **hardware_type**, you need to change + your code to use **machine** instead. + +### Upgrading from 1.5 to 1.6 + +* If you used **\_\_package_apt --preseed**, you need to use the new + type **\_\_debconf_set_selections** instead. +* The **\_\_package** types accepted either --state deinstalled or + --state uninstaaled. Starting with 1.6, it was made consistently + to --state removed. + +### Upgrading from 1.3 to 1.5 + +No incompatiblities. + +### Upgrading from 1.2 to 1.3 + +Rename **gencode** of every type to **gencode-remote**. + +### Upgrading from 1.1 to 1.2 + +No incompatiblities. + +### Upgrading from 1.0 to 1.1 + +In 1.1 the type **\_\_file** was split into **\_\_directory**, **\_\_file** and +**\_\_link**. The parameter **--type** was removed from **\_\_file**. Thus you +need to replace **\_\_file** calls in your manifests: + + * Remove --type from all \_\_file calls + * If type was symlink, use \_\_link and --type symbolic + * If type was directory, use \_\_directory + + +[[!tag cdist unix]] From caa49167ca5b5d33427d61725dbd78b1ec868f2a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 12:10:28 +0100 Subject: [PATCH 1831/4212] +title Signed-off-by: Nico Schottelius --- docs/web/cdist/os.mdwn | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/web/cdist/os.mdwn b/docs/web/cdist/os.mdwn index d53bc1c9..24992439 100644 --- a/docs/web/cdist/os.mdwn +++ b/docs/web/cdist/os.mdwn @@ -1,3 +1,5 @@ +[[!meta title="Supported Operating Systems"]] + cdist was tested or is know to run on at least * [Archlinux](http://www.archlinux.org/) From 7550f4de3ec2df6d8acd21ce5f9446f644bf9657 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 12:10:36 +0100 Subject: [PATCH 1832/4212] reorder comparision Signed-off-by: Nico Schottelius --- docs/web/cdist.mdwn | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/web/cdist.mdwn b/docs/web/cdist.mdwn index e0e1f504..cd2a7567 100644 --- a/docs/web/cdist.mdwn +++ b/docs/web/cdist.mdwn @@ -2,18 +2,19 @@ ![cdist-logo](cdist-logo.png "cdist logo") -the KISS principle and is being used in small up to enterprise grade -environments. +cdist is a usable configuration management system. +It adheres to the KISS principle and +is being used in small up to enterprise grade environments. cdist is an alternative to other configuration management systems like -[cfengine](http://www.cfengine.org/), [bcfg2](http://trac.mcs.anl.gov/projects/bcfg2), [chef](http://wiki.opscode.com/display/chef/) +[cfengine](http://www.cfengine.org/), and [puppet](http://www.puppetlabs.com/). - * **Documentation** for the [latest version](man/latest) or [all versions (>= 2.0.4)](man) + * [[Documentation|documentation]] + * [[Supported Operating Systems|os]] * [[Installation|install]] * [[Update|update]] - * [[Supported Operating Systems|os]] * [[Support|support]] [[!tag cdist unix]] From b512a76db93b7f3823fc6f2e3b9209b5f5890f90 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 14:02:17 +0100 Subject: [PATCH 1833/4212] documentation pointers Signed-off-by: Nico Schottelius --- docs/web/cdist/documentation.mdwn | 5 +++ docs/web/cdist/install.mdwn | 61 ++++++++++++++++--------------- 2 files changed, 36 insertions(+), 30 deletions(-) create mode 100644 docs/web/cdist/documentation.mdwn diff --git a/docs/web/cdist/documentation.mdwn b/docs/web/cdist/documentation.mdwn new file mode 100644 index 00000000..aa751a4b --- /dev/null +++ b/docs/web/cdist/documentation.mdwn @@ -0,0 +1,5 @@ + +* [Latest documentation](man/latest) +* [All versions](man) + +[[!tag cdist unix]] diff --git a/docs/web/cdist/install.mdwn b/docs/web/cdist/install.mdwn index 43b0e3e1..95dc8c9b 100644 --- a/docs/web/cdist/install.mdwn +++ b/docs/web/cdist/install.mdwn @@ -1,3 +1,4 @@ +[[!meta title="How to install cdist"]] [[!toc levels=3]] ## Requirements @@ -7,7 +8,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 required) + * Python >= 3.2 * SSH client * Asciidoc (for building the manpages) @@ -16,10 +17,14 @@ This is the machine you use to configure the target hosts. * /bin/sh: A posix like shell (for instance bash, dash, zsh) * SSH server -## Python Installation +## Requirement Installation: Python >= 3.2 -Ensure you have Python 3.2 installed on the machine you use to **deploy to the targets** -(the ***source host***). +Ensure you have at least Python 3.2 or newer installed on +the **source host**. +You can check this by running **python -V**: + + % python -V + Python 3.3.0 ### Archlinux @@ -32,7 +37,7 @@ You can install it using See the "From source" section -#### Debian +### Debian For Debian **wheezy** or newer: @@ -97,9 +102,13 @@ You can choose between Homebrew and Macports, either way works: port install python32 ln -s /opt/local/bin/python3.2 /opt/local/bin/python3 +### Redhat + +See the "From source" section + ### From Source -For those operating systems not yet support Python 3.2: +For those operating systems not yet supporting Python 3.2: pyversion=3.2.3 wget http://www.python.org/ftp/python/$pyversion/Python-${pyversion}.tar.bz2 @@ -109,43 +118,35 @@ For those operating systems not yet support Python 3.2: make sudo make install -This installs python 3.2 to /usr/local/bin. Ensure this directory is in -your PATH environment variable. - +This installs python 3.2 to /usr/local/bin. +Ensure this directory is in your PATH environment variable. ## Install cdist -You can clone cdist from git, which gives you the advantage of having -a version control in place for development of your own stuff as well. +You can install cdist either from git or as a python package. + +### From git + +Cloning cdist from git gives you the advantage of having +a version control in place for development of your own stuff +immediately. + To install cdist, execute the following commands: git clone git://git.schottelius.org/cdist cd cdist export PATH=$PATH:$(pwd -P)/bin - # If you want the manpages +If you want to build and use the manpages, run: + ./build man export MANPATH=$MANPATH:$(pwd -P)/doc/man +#### Available versions in git -### Available versions - -There are at least the following branches available: - - * Development: master - * 2.0: Current stable branch - * 2.1: Currently experimental - the next stable branch - -Old versions: - - * 1.7: Bugfixes, cleanups, new type and explorer rename - * 1.6: New types, cleaned up \_\_package* types, internal cleanup - * 1.5: Focus on object orientation instead of global stage orientation - * 1.4: Support for redefiniton of objects (if equal) - * 1.3: Support for local and remote code execution (current stable) - * 1.2: Dependencies supported - * 1.1: \_\_file to \_\_file, \_\_directory, \_\_link migration - * 1.0: First official release + * The active development takes place in the **master** branch + * The current stable version can be found in the **2.0** branch + * The upcoming stable version can be found in the **2.1** branch Other branches may be available for features or bugfixes, but they may vanish at any point. To select a specific branch use From 373120814ce6b7752c93b09c64b5c178c34b86fa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 14:02:38 +0100 Subject: [PATCH 1834/4212] update install/update instructions Signed-off-by: Nico Schottelius --- docs/web/cdist/install.mdwn | 22 +++++++++++++------ docs/web/cdist/update.mdwn | 43 +++++++++++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/docs/web/cdist/install.mdwn b/docs/web/cdist/install.mdwn index 95dc8c9b..79d8705d 100644 --- a/docs/web/cdist/install.mdwn +++ b/docs/web/cdist/install.mdwn @@ -152,15 +152,25 @@ Other branches may be available for features or bugfixes, but they may vanish at any point. To select a specific branch use # Generic code - git checkout -b origin/ - - # Stay on a specific version - version=2.0 - git checkout -b $version origin/$version + git checkout -b origin/ -### Mirrors +So for instance if you want to use and stay with version 2.0, you can use + + git checkout -b 2.0 origin/2.0 + +#### Git Mirrors + +If the main site is down, you can acquire cdist from one of the following sites: * git://github.com/telmich/cdist.git ([github](https://github.com/telmich/cdist)) * git://git.code.sf.net/p/cdist/code ([sourceforge](https://sourceforge.net/p/cdist/code)) +### Python Package + +Cdist is available as a python package at +[PyPi](http://pypi.python.org/pypi/cdist/). You can install it using + + pip install cdist + + [[!tag cdist unix]] diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index 085075e7..5f427369 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -1,4 +1,6 @@ -## Update +[[!meta title="How to update cdist"]] + +## Update The Git Installation To upgrade cdist in the current branch use @@ -12,20 +14,43 @@ 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. -### Upgrading from 1.7 to 2.0 +## Update The Python Package -* Ensure python (>= 3.2) is installed on the server +To upgrade to the lastet version do + + pip install --upgrade cdist + +## Update Instructions / Hints + +### Updating from 2.0 to 2.1 + + * Type __package* and __process use --state **present** or **absent**. + The states **removed/installed** and **stopped/running** have been removed. + Support for the new states is already present in 2.0. + * Type __directory: Parameter --parents and --recursive are now boolean + and the old "yes/no" values need to be removed + * Type **__addifnosuchline** and **__removeline** have been replaced by **__line** + * The **conf** directory is now located at **cdist/conf**. + You need to migrate your types, explorers and manifests + manually to the new location. + * Replace the variable **__self** by **__object_name** + Support for the variable **__object_name** is already present in 2.0. + + +### Updating from 1.7 to 2.0 + +* Ensure python (>= 3.2) is installed on the source host * Use "cdist config host" instead of "cdist-deploy-to host" * Use "cdist config -p host1 host2" instead of "cdist-mass-deploy" * Use "cdist banner" for fun * Use **\_\_object_fq** instead of **\_\_self** in manifests -### Upgrading from 1.6 to 1.7 +### Updating from 1.6 to 1.7 * If you used the global explorer **hardware_type**, you need to change your code to use **machine** instead. -### Upgrading from 1.5 to 1.6 +### Updating from 1.5 to 1.6 * If you used **\_\_package_apt --preseed**, you need to use the new type **\_\_debconf_set_selections** instead. @@ -33,19 +58,19 @@ working, break your setup or eat the tree in your garden. --state uninstaaled. Starting with 1.6, it was made consistently to --state removed. -### Upgrading from 1.3 to 1.5 +### Updating from 1.3 to 1.5 No incompatiblities. -### Upgrading from 1.2 to 1.3 +### Updating from 1.2 to 1.3 Rename **gencode** of every type to **gencode-remote**. -### Upgrading from 1.1 to 1.2 +### Updating from 1.1 to 1.2 No incompatiblities. -### Upgrading from 1.0 to 1.1 +### Updating from 1.0 to 1.1 In 1.1 the type **\_\_file** was split into **\_\_directory**, **\_\_file** and **\_\_link**. The parameter **--type** was removed from **\_\_file**. Thus you From 38e84a8b69f611d67148c8f3a50b1e169017a241 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 14:06:25 +0100 Subject: [PATCH 1835/4212] fix title Signed-off-by: Nico Schottelius --- docs/web/cdist/update.mdwn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index 5f427369..c34c83ee 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -20,7 +20,7 @@ To upgrade to the lastet version do pip install --upgrade cdist -## Update Instructions / Hints +## Update Instructions ### Updating from 2.0 to 2.1 @@ -43,7 +43,7 @@ To upgrade to the lastet version do * Use "cdist config host" instead of "cdist-deploy-to host" * Use "cdist config -p host1 host2" instead of "cdist-mass-deploy" * Use "cdist banner" for fun -* Use **\_\_object_fq** instead of **\_\_self** in manifests +* Use **\_\_object_name** instead of **\_\_self** in manifests ### Updating from 1.6 to 1.7 From cad5015962704ea7d6c441713a4743a7f97935cd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 14:08:27 +0100 Subject: [PATCH 1836/4212] no autofs* anymore Signed-off-by: Nico Schottelius --- docs/web/cdist/update.mdwn | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index c34c83ee..a916575a 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -35,6 +35,8 @@ To upgrade to the lastet version do manually to the new location. * Replace the variable **__self** by **__object_name** Support for the variable **__object_name** is already present in 2.0. + * The types __autofs, __autofs_map and __autofs_reload have been removed + (no maintainer, no users) ### Updating from 1.7 to 2.0 From c51edff9f586361dfc13237c2bdf26317f260d30 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 14:15:54 +0100 Subject: [PATCH 1837/4212] ++changes(2.1.0pre8) Signed-off-by: Nico Schottelius --- docs/changelog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index df5c1b2b..c6ea4ffc 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,15 +4,16 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.1.0pre8: +2.1.0pre8: 2012-11-15 * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, __ssh_authorized_key, __timezone, all install types (Steven Armstrong) * Types: Remove all parameter changing code * Type __rvm_ruby: Change parameter "default" to be boolean + * Documentation: Web documentation cleaned up 2.1.0pre7: 2012-11-07 * Core: All unit tests restored back to working - * Core: Print error message on missing initial manifest + * Core: Print error message when missing the initial manifest 2.1.0pre6: 2012-11-05 * New Example: Turn remote calls into local calls (used for unittesting) From 5ffd52334052e0b6074992a964bc1a85c96bade5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 14:33:08 +0100 Subject: [PATCH 1838/4212] doc and doc building update Signed-off-by: Nico Schottelius --- build | 36 +++++++++++++++---------------- docs/web/cdist/documentation.mdwn | 6 ++++-- docs/web/cdist/update.mdwn | 16 ++++++++------ 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/build b/build index baad93be..f1e0bf8e 100755 --- a/build +++ b/build @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -34,9 +34,10 @@ A2XM="a2x -f manpage --no-xmllint -a encoding=UTF-8" A2XH="a2x -f xhtml --no-xmllint -a encoding=UTF-8" # Developer webbase -WEBDIR=$HOME/niconetz +WEBDIR=$HOME/www.nico.schottelius.org WEBBLOG=$WEBDIR/blog -WEBBASE=$WEBDIR/software/cdist +WEBTOPDIR=$WEBDIR/software +WEBBASE=$WEBTOPDIR/cdist WEBMAN=$WEBBASE/man/$version WEBPAGE=${WEBBASE}.mdwn @@ -89,6 +90,13 @@ case "$1" in ${MANDIR}/cdist-reference.text.sh ;; + man-pub) + rm -rf "${WEBMAN}" + mkdir -p "${WEBMAN}/man1" "${WEBMAN}/man7" + cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${WEBMAN}/man1 + cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${WEBMAN}/man7 + ;; + dist) set -e # Do the checks @@ -314,23 +322,15 @@ eof done ;; - webmain) - cp README ${WEBPAGE} - cd ${WEBDIR} && git commit -m "cdist main update" ${WEBPAGE} - cd ${WEBDIR} && make pub - ;; - web) - cp README ${WEBPAGE} - rm -rf ${WEBMAN} - mkdir -p ${WEBMAN}/man1 ${WEBMAN}/man7 + set -e + rsync -av "${basedir}/docs/web/" "${WEBTOPDIR}" - cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${WEBMAN}/man1 - cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${WEBMAN}/man7 - - cd ${WEBDIR} && git add ${WEBBASE} - cd ${WEBDIR} && git commit -m "cdist update" ${WEBBASE} ${WEBPAGE} - cd ${WEBDIR} && make pub + $0 man-pub + + cd "${WEBDIR}" && git add "${WEBBASE}" + cd "${WEBDIR}" && git commit -m "cdist update" "${WEBBASE}" "${WEBPAGE}" + cd "${WEBDIR}" && make pub # Fix ikiwiki, which does not like symlinks for pseudo security ssh tee.schottelius.org \ diff --git a/docs/web/cdist/documentation.mdwn b/docs/web/cdist/documentation.mdwn index aa751a4b..ba829101 100644 --- a/docs/web/cdist/documentation.mdwn +++ b/docs/web/cdist/documentation.mdwn @@ -1,5 +1,7 @@ +[[!meta title="Documentation"]] -* [Latest documentation](man/latest) -* [All versions](man) +You can browse the latest +[latest version of the manpages](man/latest) or +have a look at [all versions](man). [[!tag cdist unix]] diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index a916575a..7fac8444 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -24,18 +24,20 @@ To upgrade to the lastet version do ### Updating from 2.0 to 2.1 - * Type __package* and __process use --state **present** or **absent**. + * Type **\_\_package* and \_\_process** use --state **present** or **absent**. The states **removed/installed** and **stopped/running** have been removed. Support for the new states is already present in 2.0. - * Type __directory: Parameter --parents and --recursive are now boolean - and the old "yes/no" values need to be removed - * Type **__addifnosuchline** and **__removeline** have been replaced by **__line** + * Type **\_\_directory**: Parameter --parents and --recursive are now boolean + The old "yes/no" values need to be removed. + * Type **\_\_rvm_ruby**: Parameter --default is now boolean + The old "yes/no" values need to be removed. + * Type **\_\_addifnosuchline** and **\_\_removeline** have been replaced by **\_\_line** * The **conf** directory is now located at **cdist/conf**. You need to migrate your types, explorers and manifests manually to the new location. - * Replace the variable **__self** by **__object_name** - Support for the variable **__object_name** is already present in 2.0. - * The types __autofs, __autofs_map and __autofs_reload have been removed + * Replace the variable **\_\_self** by **\_\_object_name** + Support for the variable **\_\_object_name** is already present in 2.0. + * The types **\_\_autofs**, **\_\_autofs_map** and **\_\_autofs_reload** have been removed (no maintainer, no users) From 625f67f45fb6d331df36e1d083eca0c0be2ad023 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 14:36:45 +0100 Subject: [PATCH 1839/4212] exchange comma Signed-off-by: Nico Schottelius --- docs/web/cdist.mdwn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/web/cdist.mdwn b/docs/web/cdist.mdwn index cd2a7567..ee24e910 100644 --- a/docs/web/cdist.mdwn +++ b/docs/web/cdist.mdwn @@ -7,8 +7,8 @@ It adheres to the KISS principle and is being used in small up to enterprise grade environments. cdist is an alternative to other configuration management systems like [bcfg2](http://trac.mcs.anl.gov/projects/bcfg2), -[chef](http://wiki.opscode.com/display/chef/) -[cfengine](http://www.cfengine.org/), +[chef](http://wiki.opscode.com/display/chef/), +[cfengine](http://www.cfengine.org/) and [puppet](http://www.puppetlabs.com/). * [[Documentation|documentation]] From 447092ced4e712da9532a064e747203e30d4e2d9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 14:43:11 +0100 Subject: [PATCH 1840/4212] hint to the documentation on the install site Signed-off-by: Nico Schottelius --- docs/web/cdist/install.mdwn | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/web/cdist/install.mdwn b/docs/web/cdist/install.mdwn index 79d8705d..ad97cd2b 100644 --- a/docs/web/cdist/install.mdwn +++ b/docs/web/cdist/install.mdwn @@ -172,5 +172,8 @@ Cdist is available as a python package at pip install cdist +## Use cdist + +[[Dig into the documentation|documentation]] to get started with cdist! [[!tag cdist unix]] From c10080ec2f86728e2f6d4cb8bb021390c2a7bb10 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 14:47:42 +0100 Subject: [PATCH 1841/4212] add path prefix for manpages Signed-off-by: Nico Schottelius --- docs/web/cdist/documentation.mdwn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/web/cdist/documentation.mdwn b/docs/web/cdist/documentation.mdwn index ba829101..e5fd9bc9 100644 --- a/docs/web/cdist/documentation.mdwn +++ b/docs/web/cdist/documentation.mdwn @@ -1,7 +1,7 @@ [[!meta title="Documentation"]] You can browse the latest -[latest version of the manpages](man/latest) or -have a look at [all versions](man). +[latest version of the manpages](/software/cdist/man/latest) or +have a look at [all versions](/software/cdist/man). [[!tag cdist unix]] From a3f3d2a3b35698df66a123cf0c034c0c2c454810 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 14:54:15 +0100 Subject: [PATCH 1842/4212] call man-pub in dist, but not in web releases Signed-off-by: Nico Schottelius --- build | 8 ++++++-- docs/web/cdist/update.mdwn | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/build b/build index f1e0bf8e..b19be55a 100755 --- a/build +++ b/build @@ -91,6 +91,8 @@ case "$1" in ;; man-pub) + $0 man + rm -rf "${WEBMAN}" mkdir -p "${WEBMAN}/man1" "${WEBMAN}/man7" cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${WEBMAN}/man1 @@ -115,6 +117,10 @@ case "$1" in # Update website (includes documentation) $0 web + # Update manpages on website + $0 man-pub + + # update git repos $0 pub $0 dist-blog @@ -326,8 +332,6 @@ eof set -e rsync -av "${basedir}/docs/web/" "${WEBTOPDIR}" - $0 man-pub - cd "${WEBDIR}" && git add "${WEBBASE}" cd "${WEBDIR}" && git commit -m "cdist update" "${WEBBASE}" "${WEBPAGE}" cd "${WEBDIR}" && make pub diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index 7fac8444..c62acc8f 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -40,7 +40,6 @@ To upgrade to the lastet version do * The types **\_\_autofs**, **\_\_autofs_map** and **\_\_autofs_reload** have been removed (no maintainer, no users) - ### Updating from 1.7 to 2.0 * Ensure python (>= 3.2) is installed on the source host From 018ba02111db60fd6c125ac8089690e5e1fbd2c2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 15:03:55 +0100 Subject: [PATCH 1843/4212] no past Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index c6ea4ffc..151ff45c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,7 +9,7 @@ Changelog __ssh_authorized_key, __timezone, all install types (Steven Armstrong) * Types: Remove all parameter changing code * Type __rvm_ruby: Change parameter "default" to be boolean - * Documentation: Web documentation cleaned up + * Documentation: Web documentation clean up 2.1.0pre7: 2012-11-07 * Core: All unit tests restored back to working From 8457e6cfd1581ec875c5a0b1ff38ea0cbdaf6c1b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 15:17:15 +0100 Subject: [PATCH 1844/4212] also git add & commit the manpages Signed-off-by: Nico Schottelius --- build | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build b/build index b19be55a..fb01c565 100755 --- a/build +++ b/build @@ -93,10 +93,13 @@ case "$1" in man-pub) $0 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" ;; dist) From 19426574f723617b12a4dfd05d31650e10a31883 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 16:49:00 +0100 Subject: [PATCH 1845/4212] remove obsolete move Signed-off-by: Nico Schottelius --- PKGBUILD.in | 3 --- 1 file changed, 3 deletions(-) diff --git a/PKGBUILD.in b/PKGBUILD.in index a4e744ae..68bd6add 100755 --- a/PKGBUILD.in +++ b/PKGBUILD.in @@ -17,9 +17,6 @@ source=("http://pypi.python.org/packages/source/c/cdist/cdist-\${pkgver}.tar.gz" package() { cd cdist-\${pkgver} python3 setup.py build install --root="\${pkgdir}" - mv "\${pkgdir}"/usr/bin/cdist.py "\${pkgdir}"/usr/bin/cdist - - #install -Dm644 offlineimap.1 "\${pkgdir}"/usr/share/man/man1/offlineimap.1 } eof From 18dd0ebd337a550429954cac7646b5a7b2cdea74 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 17:37:15 +0100 Subject: [PATCH 1846/4212] ensure global and type explorers are executable on the remote side Signed-off-by: Nico Schottelius --- cdist/core/explorer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index da84cfaa..86ce52ac 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -98,6 +98,7 @@ class Explorer(object): """Transfer the global explorers to the remote side.""" self.remote.mkdir(self.remote.global_explorer_path) self.remote.transfer(self.local.global_explorer_path, self.remote.global_explorer_path) + self.remote.run(["chmod", "0700", "%s/*" % (self.remote.global_explorer_path)]) def run_global_explorer(self, explorer): """Run the given global explorer and return it's output.""" @@ -152,6 +153,7 @@ class Explorer(object): destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) self.remote.mkdir(destination) self.remote.transfer(source, destination) + self.remote.run(["chmod", "0700", "%s" % (destination)]) self._type_explorers_transferred.append(cdist_type.name) def transfer_object_parameters(self, cdist_object): From f834352e881d6ab75b4a2496dbf8c28c0798d18b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 17:38:43 +0100 Subject: [PATCH 1847/4212] document changes for next version, fixes #122 Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 151ff45c..a2c72ed9 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: Ensure global and type explorers are executable + 2.1.0pre8: 2012-11-15 * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, __ssh_authorized_key, __timezone, all install types (Steven Armstrong) From e6bf22603651d3941c000ce671cc57e58d01b784 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 17:47:06 +0100 Subject: [PATCH 1848/4212] convert __rvm_gmeset to boolean parameter Signed-off-by: Nico Schottelius --- cdist/conf/type/__rvm_gemset/gencode-remote | 12 ++++-------- cdist/conf/type/__rvm_gemset/man.text | 7 ++++--- .../__rvm_gemset/parameter/{optional => boolean} | 0 3 files changed, 8 insertions(+), 11 deletions(-) rename cdist/conf/type/__rvm_gemset/parameter/{optional => boolean} (100%) diff --git a/cdist/conf/type/__rvm_gemset/gencode-remote b/cdist/conf/type/__rvm_gemset/gencode-remote index 1fd14061..f0c0052b 100755 --- a/cdist/conf/type/__rvm_gemset/gencode-remote +++ b/cdist/conf/type/__rvm_gemset/gencode-remote @@ -24,7 +24,6 @@ ruby="$(echo "$gemset" | cut -d '@' -f 1)" gemsetname="$(echo "$gemset" | cut -d '@' -f 2)" state_is="$(cat "$__object/explorer/state")" user="$(cat "$__object/parameter/user")" -default="$(cat "$__object/parameter/default" 2>/dev/null || true)" state_should="$(cat "$__object/parameter/state")" [ "$state_is" = "$state_should" ] && exit 0 @@ -34,15 +33,12 @@ case "$state_should" in cat << DONE su - "$user" -c "source ~/.rvm/scripts/rvm; rvm $gemset --create" DONE - case "$default" in - no) - ;; - *) - cat << DONE + if -f "$__object/parameter/default"; then + cat << DONE su - "$user" -c "source ~/.rvm/scripts/rvm; rvm use --default $gemset" DONE - ;; - esac + fi + ;; absent) cat << DONE diff --git a/cdist/conf/type/__rvm_gemset/man.text b/cdist/conf/type/__rvm_gemset/man.text index 26e866ba..44c0c555 100644 --- a/cdist/conf/type/__rvm_gemset/man.text +++ b/cdist/conf/type/__rvm_gemset/man.text @@ -20,10 +20,11 @@ user:: state:: Either "present" or "absent". -OPTIONAL PARAMETERS +BOOLEAN PARAMETERS ------------------- default:: - If set to anything but "no" (the default), set the given gemset as default. + If present, set the given gemset as default. + EXAMPLES -------- @@ -33,7 +34,7 @@ EXAMPLES __rvm_gemset ruby-1.9.3-p0@myset --user charles --state present # Do the same and make ruby-1.9.3-p0@myset the default gemset -__rvm_gemset ruby-1.9.3-p0@myset --user charles --state present --default yes +__rvm_gemset ruby-1.9.3-p0@myset --user charles --state present --default # Remove the gemset @myset for user john __rvm_ruby ruby-1.9.3-p0@myset --user john --state absent diff --git a/cdist/conf/type/__rvm_gemset/parameter/optional b/cdist/conf/type/__rvm_gemset/parameter/boolean similarity index 100% rename from cdist/conf/type/__rvm_gemset/parameter/optional rename to cdist/conf/type/__rvm_gemset/parameter/boolean From bec3569724156a541390d22aa7b1ddff3ddf6bd0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Nov 2012 17:48:01 +0100 Subject: [PATCH 1849/4212] document more changes for next release Signed-off-by: Nico Schottelius --- docs/changelog | 1 + docs/web/cdist/update.mdwn | 2 ++ 2 files changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index a2c72ed9..46c9fa50 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog next: * Core: Ensure global and type explorers are executable + * Type __rvm_gemset: Change parameter "default" to be boolean 2.1.0pre8: 2012-11-15 * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index c62acc8f..2316cf68 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -31,6 +31,8 @@ To upgrade to the lastet version do The old "yes/no" values need to be removed. * Type **\_\_rvm_ruby**: Parameter --default is now boolean The old "yes/no" values need to be removed. + * Type **\_\_rvm_gemset**: Parameter --default is now boolean + The old "yes/no" values need to be removed. * Type **\_\_addifnosuchline** and **\_\_removeline** have been replaced by **\_\_line** * The **conf** directory is now located at **cdist/conf**. You need to migrate your types, explorers and manifests From e4910933b109c4d0858a0fa6ee901d211544e6e1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 16 Nov 2012 14:56:20 +0100 Subject: [PATCH 1850/4212] __apt_ppa: /enabled/present/ -e /disabled/absent/ Signed-off-by: Steven Armstrong --- cdist/conf/type/__apt_ppa/explorer/state | 2 +- cdist/conf/type/__apt_ppa/gencode-remote | 20 +++++++++++--------- cdist/conf/type/__apt_ppa/man.text | 6 +++--- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/cdist/conf/type/__apt_ppa/explorer/state b/cdist/conf/type/__apt_ppa/explorer/state index 8a5638b2..2d8ca7c5 100755 --- a/cdist/conf/type/__apt_ppa/explorer/state +++ b/cdist/conf/type/__apt_ppa/explorer/state @@ -29,5 +29,5 @@ repo_name="${name#ppa:}" repo_file_name="$(echo "$repo_name" | sed "s:\/:\-:")-${DISTRIB_CODENAME}.list" [ -s "/etc/apt/sources.list.d/${repo_file_name}" ] \ - && echo enabled || echo disabled + && echo present || echo absent diff --git a/cdist/conf/type/__apt_ppa/gencode-remote b/cdist/conf/type/__apt_ppa/gencode-remote index 0e7fe163..0ea8011c 100755 --- a/cdist/conf/type/__apt_ppa/gencode-remote +++ b/cdist/conf/type/__apt_ppa/gencode-remote @@ -22,14 +22,16 @@ name="$__object_id" state_should="$(cat "$__object/parameter/state")" state_is="$(cat "$__object/explorer/state")" -if [ "$state_should" != "$state_is" ]; then - case "$state_should" in - enabled) - echo add-apt-repository \"$name\" - ;; - disabled) - echo remove-apt-repository \"$name\" - ;; - esac +if [ "$state_should" == "$state_is" ]; then + # Nothing to do, move along + exit 0 fi +case "$state_should" in + present) + echo add-apt-repository \"$name\" + ;; + absent) + echo remove-apt-repository \"$name\" + ;; +esac diff --git a/cdist/conf/type/__apt_ppa/man.text b/cdist/conf/type/__apt_ppa/man.text index f986eb2d..6a5990d5 100644 --- a/cdist/conf/type/__apt_ppa/man.text +++ b/cdist/conf/type/__apt_ppa/man.text @@ -16,7 +16,7 @@ This cdist type allows manage ubuntu ppa repositories. REQUIRED PARAMETERS ------------------- state:: - The state the ppa should be in, either "enabled" or "disabled". + The state the ppa should be in, either "present" or "absent". OPTIONAL PARAMETERS @@ -29,10 +29,10 @@ EXAMPLES -------------------------------------------------------------------------------- # Enable a ppa repository -__apt_ppa ppa:sans-intern/missing-bits --state enabled +__apt_ppa ppa:sans-intern/missing-bits --state present # Disable a ppa repository -__apt_ppa ppa:sans-intern/missing-bits --state disabled +__apt_ppa ppa:sans-intern/missing-bits --state absent -------------------------------------------------------------------------------- From 6c685e61d58959dac82653a34d68e32d9f20cbcc Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 15 Nov 2012 14:54:28 +0100 Subject: [PATCH 1851/4212] fixes #126 Signed-off-by: Steven Armstrong --- cdist/emulator.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/emulator.py b/cdist/emulator.py index e54bd0dc..42744fab 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -135,6 +135,8 @@ 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 28e8632097ae6b0bd1db92d100ea75a72f498a35 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 16 Nov 2012 15:31:33 +0100 Subject: [PATCH 1852/4212] new type: __user_group: manage user groups Signed-off-by: Steven Armstrong --- cdist/conf/type/__user_groups/explorer/group | 23 ++++++++ cdist/conf/type/__user_groups/gencode-remote | 46 ++++++++++++++++ cdist/conf/type/__user_groups/man.text | 52 +++++++++++++++++++ .../type/__user_groups/parameter/optional | 2 + .../__user_groups/parameter/required_multiple | 1 + 5 files changed, 124 insertions(+) create mode 100755 cdist/conf/type/__user_groups/explorer/group create mode 100755 cdist/conf/type/__user_groups/gencode-remote create mode 100644 cdist/conf/type/__user_groups/man.text create mode 100644 cdist/conf/type/__user_groups/parameter/optional create mode 100644 cdist/conf/type/__user_groups/parameter/required_multiple diff --git a/cdist/conf/type/__user_groups/explorer/group b/cdist/conf/type/__user_groups/explorer/group new file mode 100755 index 00000000..a8cb63af --- /dev/null +++ b/cdist/conf/type/__user_groups/explorer/group @@ -0,0 +1,23 @@ +#!/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 . +# + +user="$(cat "$__object/parameter/user" 2>/dev/null || echo "$__object_id")" + +(id --groups --name "$user" | tr ' ' '\n' | sort) 2>/dev/null || true diff --git a/cdist/conf/type/__user_groups/gencode-remote b/cdist/conf/type/__user_groups/gencode-remote new file mode 100755 index 00000000..c5e4a35e --- /dev/null +++ b/cdist/conf/type/__user_groups/gencode-remote @@ -0,0 +1,46 @@ +#!/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 . +# + +user="$(cat "$__object/parameter/user" 2>/dev/null || echo "$__object_id")" +state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" + +mkdir "$__object/files" +# file has to be sorted for comparison with `comm` +sort "$__object/parameter/group" > "$__object/files/group.sorted" + +case "$state_should" in + present) + changed_groups="$(comm -13 "$__object/explorer/group" "$__object/files/group.sorted")" + action="-a" + ;; + absent) + changed_groups="$(comm -12 "$__object/explorer/group" "$__object/files/group.sorted")" + action="-d" + ;; +esac + +if [ -z "$changed_groups" ]; then + # Nothing to do, move along + exit 0 +fi + +for group in $changed_groups; do + echo "gpasswd $action \"$user\" \"$group\"" +done diff --git a/cdist/conf/type/__user_groups/man.text b/cdist/conf/type/__user_groups/man.text new file mode 100644 index 00000000..d45784fe --- /dev/null +++ b/cdist/conf/type/__user_groups/man.text @@ -0,0 +1,52 @@ +cdist-type__user_groups(7) +========================== +Steven Armstrong + + +NAME +---- +cdist-type__user_groups - manage user groups + + +DESCRIPTION +----------- +Adds or removes a user from one or more groups. + + +REQUIRED PARAMETERS +------------------- +group:: + the group to which this user should be added or removed. + Can be specified multiple times. + + +OPTIONAL PARAMETERS +------------------- +user:: + the name of the user. Defaults to object_id + +state:: + absent or present. Defaults to present. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__user_groups nginx --group webuser1 --group webuser2 + +# remove user nginx from groups webuser2 +__user_groups nginx-webuser2 --user nginx \ + --group webuser2 --state absent +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +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/__user_groups/parameter/optional b/cdist/conf/type/__user_groups/parameter/optional new file mode 100644 index 00000000..7d9ecf60 --- /dev/null +++ b/cdist/conf/type/__user_groups/parameter/optional @@ -0,0 +1,2 @@ +user +state diff --git a/cdist/conf/type/__user_groups/parameter/required_multiple b/cdist/conf/type/__user_groups/parameter/required_multiple new file mode 100644 index 00000000..3a60ccec --- /dev/null +++ b/cdist/conf/type/__user_groups/parameter/required_multiple @@ -0,0 +1 @@ +group From b0ac5fe78d913f03f24e17d36222a6638cda0a73 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 16 Nov 2012 21:18:08 +0100 Subject: [PATCH 1853/4212] update __jail type to match changed signature of __directory: fixes #135 Signed-off-by: Steven Armstrong --- cdist/conf/type/__jail/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__jail/manifest b/cdist/conf/type/__jail/manifest index b2ecf2bc..0570d62d 100755 --- a/cdist/conf/type/__jail/manifest +++ b/cdist/conf/type/__jail/manifest @@ -39,7 +39,7 @@ else jaildir="/usr/jail" fi -__directory ${jaildir} --parents yes +__directory ${jaildir} --parents # Debug #set +x From aedda96f3e3dbb3f261cfab87721819baa49f304 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 18 Nov 2012 12:36:12 +0100 Subject: [PATCH 1854/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 46c9fa50..b1cf62ff 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog next: * Core: Ensure global and type explorers are executable * Type __rvm_gemset: Change parameter "default" to be boolean + * New Type: __user_groups (Steven Armstrong) 2.1.0pre8: 2012-11-15 * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, From 1774b50e479411d658e49e638ac4e8572ce3ccd0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 18 Nov 2012 23:20:22 +0100 Subject: [PATCH 1855/4212] argh - side effects Signed-off-by: Nico Schottelius --- .../logs/2012-11-18.problematic-side-effects | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 docs/dev/logs/2012-11-18.problematic-side-effects diff --git a/docs/dev/logs/2012-11-18.problematic-side-effects b/docs/dev/logs/2012-11-18.problematic-side-effects new file mode 100644 index 00000000..032a9f80 --- /dev/null +++ b/docs/dev/logs/2012-11-18.problematic-side-effects @@ -0,0 +1,22 @@ +- Problem: Installing xbmc package creates user xbmc. +As xbmc is the first user, it gets the uid 1000. + +Later on trying to create the user "nutzer" with uid 1000 fails, because +xbmc already has that uid. + + +INFO: matte: Generating and executing code for __package/upower +INFO: matte: Generating and executing code for __nico_managed_desktop/singleton +ln -s '/usr/lib/systemd/system/slim.service' '/etc/systemd/system/display-manager.service' +INFO: matte: Generating and executing code for __directory/etc/sudoers.d +INFO: matte: Generating and executing code for __file/etc/sudoers.d/nico +INFO: matte: Generating and executing code for __cdistmarker/singleton +INFO: matte: Generating and executing code for __package_pacman/sudo +INFO: matte: Generating and executing code for __package/sudo +INFO: matte: Generating and executing code for __package_pacman/xf86-video-intel +INFO: matte: Generating and executing code for __user/nutzer +useradd: UID 1000 is not unique +ERROR: matte: Command failed: ssh -o User=root -q matte umask 077; /bin/sh -e /var/lib/cdist/object/__user/nutzer/.cdist/code-remote +INFO: Total processing time for 1 host(s): 3512.761916399002 +ERROR: Failed to deploy to the following hosts: matte +[17:40] brief:nico% ./bin/cdist config -v matte From 327a0f2844d93c13c36ae99385a5fdaaa9656534 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 18 Nov 2012 23:31:19 +0100 Subject: [PATCH 1856/4212] remove --groups from __user type Signed-off-by: Nico Schottelius --- cdist/conf/type/__user/man.text | 2 -- cdist/conf/type/__user/parameter/optional | 1 - docs/changelog | 1 + docs/web/cdist/update.mdwn | 1 + 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__user/man.text b/cdist/conf/type/__user/man.text index 7be2c2f2..9db4a9f0 100644 --- a/cdist/conf/type/__user/man.text +++ b/cdist/conf/type/__user/man.text @@ -26,8 +26,6 @@ home:: see above gid:: see above -groups:: - see above password:: see above shell:: diff --git a/cdist/conf/type/__user/parameter/optional b/cdist/conf/type/__user/parameter/optional index fe02e227..e3cf52d5 100644 --- a/cdist/conf/type/__user/parameter/optional +++ b/cdist/conf/type/__user/parameter/optional @@ -1,7 +1,6 @@ comment home gid -groups password shell uid diff --git a/docs/changelog b/docs/changelog index b1cf62ff..68b35eac 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ next: * Core: Ensure global and type explorers are executable * Type __rvm_gemset: Change parameter "default" to be boolean * New Type: __user_groups (Steven Armstrong) + * Type __user: Remove --groups support (now provided by __user_groups) 2.1.0pre8: 2012-11-15 * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index 2316cf68..22b92769 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -41,6 +41,7 @@ To upgrade to the lastet version do Support for the variable **\_\_object_name** is already present in 2.0. * The types **\_\_autofs**, **\_\_autofs_map** and **\_\_autofs_reload** have been removed (no maintainer, no users) + * Type **\_\_user**: Parameter --groups removed (use the new \_\_user_groups type) ### Updating from 1.7 to 2.0 From 13968d16f6fc06c5ca958b6489b29c8b1ed18a19 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Nov 2012 10:36:52 +0100 Subject: [PATCH 1857/4212] change __jail to boolean, fixes #128 Signed-off-by: Nico Schottelius --- cdist/conf/type/__jail/gencode-remote | 23 ++++++----------------- cdist/conf/type/__jail/man.text | 22 +++++++++++----------- cdist/conf/type/__jail/parameter/boolean | 3 +++ cdist/conf/type/__jail/parameter/optional | 3 --- 4 files changed, 20 insertions(+), 31 deletions(-) create mode 100644 cdist/conf/type/__jail/parameter/boolean diff --git a/cdist/conf/type/__jail/gencode-remote b/cdist/conf/type/__jail/gencode-remote index 4aff6509..56a1b643 100755 --- a/cdist/conf/type/__jail/gencode-remote +++ b/cdist/conf/type/__jail/gencode-remote @@ -34,15 +34,8 @@ fi state="$(cat "$__object/parameter/state")" -if [ -f "$__object/parameter/started" ]; then - started="$(cat "$__object/parameter/started")" -else - if [ ! "$state" = "present" ]; then - started="false" - else - started="true" - fi -fi +started="false" +[ -f "$__object/parameter/started" -a "$state" = "present" ] && started="true" if [ -f "$__object/parameter/ip" ]; then ip="$(cat "$__object/parameter/ip")" @@ -66,8 +59,8 @@ if [ -f "$__object/parameter/interface" ]; then interface="$(cat "$__object/parameter/interface")" fi -if [ -f "$__object/parameter/devfs-enable" ]; then - devfsenable="$(cat "$__object/parameter/devfs-enable")" +if [ -f "$__object/parameter/devfs-disable" ]; then + devfsenable="false" else devfsenable="true" fi @@ -82,12 +75,12 @@ fi # is pointless. Treat this as an error. if [ -n "$devfsruleset" -a "$devfsenable" = "false" ]; then exec >&2 - echo "Can't have --devfs-ruleset defined without --devfs-enable true." + echo "Can't have --devfs-ruleset defined without --devfs-disable" exit 1 fi if [ -f "$__object/parameter/onboot" ]; then - onboot="$(cat "$__object/parameter/onboot")" + onboot="true" fi if [ -f "$__object/parameter/jaildir" ]; then @@ -357,7 +350,3 @@ else # The jail does not currently exist exit 0 fi fi - -# Debug -#set +x - diff --git a/cdist/conf/type/__jail/man.text b/cdist/conf/type/__jail/man.text index 8682effe..62b6e02e 100644 --- a/cdist/conf/type/__jail/man.text +++ b/cdist/conf/type/__jail/man.text @@ -27,9 +27,6 @@ OPTIONAL PARAMETERS name:: The name of the jail. Default is to use the object_id as the jail name. -started:: - Either "true" or "false." Defaults to true. - ip:: The ifconfig style IP/netmask combination to use for the jail guest. If the state parameter is "present," this parameter is required. @@ -41,23 +38,26 @@ interface:: The name of the physical interface on the jail server to bind the jail to. Defaults to the first interface found in the output of ifconfig -l. -devfs-enable:: - Whether to allow devfs mounting within the jail. Must be "true" or "false." - Defaults to true. - devfs-ruleset:: The name of the devfs ruleset to associate with the jail. Defaults to "jailrules." This ruleset must be copied to the server via another type. To use this option, devfs-enable must be "true." -onboot:: - Whether to add the jail to rc.conf's jail_list variable. Must be either - "true" or "false." Defaults to false. - jaildir:: The location on the remote server to use for hosting jail filesystems. Defaults to /usr/jail. +BOOLEAN PARAMETERS +------------------ +started:: + Whether to start jail + +devfs-disable:: + Whether to disallow devfs mounting within the jail + +onboot:: + Whether to add the jail to rc.conf's jail_list variable. + CAVEATS ------- diff --git a/cdist/conf/type/__jail/parameter/boolean b/cdist/conf/type/__jail/parameter/boolean new file mode 100644 index 00000000..1dd61f6b --- /dev/null +++ b/cdist/conf/type/__jail/parameter/boolean @@ -0,0 +1,3 @@ +onboot +started +devfs-disable diff --git a/cdist/conf/type/__jail/parameter/optional b/cdist/conf/type/__jail/parameter/optional index 1b5f0810..08ecd469 100644 --- a/cdist/conf/type/__jail/parameter/optional +++ b/cdist/conf/type/__jail/parameter/optional @@ -1,10 +1,7 @@ name -started ip hostname interface -devfs-enable devfs-ruleset -onboot jaildir jailbase From 6d430524f1a0ee661dbd1c4af1aac6d721a0d064 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 19 Nov 2012 12:04:07 +0100 Subject: [PATCH 1858/4212] binary all the way, fixes issue #138 Signed-off-by: Steven Armstrong --- cdist/emulator.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 42744fab..a9c760cb 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -29,7 +29,7 @@ import cdist from cdist import core class Emulator(object): - def __init__(self, argv, stdin=sys.stdin, env=os.environ): + def __init__(self, argv, stdin=sys.stdin.buffer, env=os.environ): self.argv = argv self.stdin = stdin self.env = env @@ -151,6 +151,10 @@ class Emulator(object): # Record / Append source self.cdist_object.source.append(self.object_source) + chunk_size = 65536 + def _read_stdin(self): + return self.stdin.read(self.chunk_size) + def save_stdin(self): """If something is written to stdin, save it in the object as $__object/stdin so it can be accessed in manifest and gencode-* @@ -160,10 +164,12 @@ class Emulator(object): try: # go directly to file instead of using CdistObject's api # as that does not support streaming - # FIXME: no streaming needed anymore - use a raw file (not yet there?) path = os.path.join(self.cdist_object.absolute_path, 'stdin') - with open(path, 'w') as fd: - fd.write(self.stdin.read()) + with open(path, 'wb') as fd: + chunk = self._read_stdin() + while chunk: + fd.write(chunk) + chunk = self._read_stdin() except EnvironmentError as e: raise cdist.Error('Failed to read from stdin: %s' % e) From 84770b9ef2afbfa1232845ce6538b56df99cee3a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 19 Nov 2012 11:25:56 +0100 Subject: [PATCH 1859/4212] implement before/after to declare dependencies and deprecate require Signed-off-by: Steven Armstrong --whitespace Signed-off-by: Steven Armstrong --- cdist/core/cdist_object.py | 2 ++ cdist/emulator.py | 25 +++++++++++++++++++++---- cdist/resolver.py | 17 ++++++++++++++--- cdist/test/object/__init__.py | 1 + 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 90a21e59..7e587bf3 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -186,6 +186,8 @@ class CdistObject(object): return os.path.join(self.path, "explorer") requirements = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'require')) + before = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'before')) + after = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'after')) 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)) diff --git a/cdist/emulator.py b/cdist/emulator.py index a9c760cb..bd3661d3 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -23,6 +23,7 @@ import argparse import logging import os +import warnings import sys import cdist @@ -92,8 +93,12 @@ class Emulator(object): def commandline(self): """Parse command line""" + self.meta_parameters = dict.fromkeys(('after', 'before')) + meta_parser = argparse.ArgumentParser(add_help=False) + for meta_parameter in self.meta_parameters.keys(): + meta_parser.add_argument('--%s' % meta_parameter, action='append', required=False) - parser = argparse.ArgumentParser(add_help=False, argument_default=argparse.SUPPRESS) + parser = argparse.ArgumentParser(add_help=False, parents=[meta_parser], argument_default=argparse.SUPPRESS) for parameter in self.cdist_type.required_parameters: argument = "--" + parameter @@ -119,6 +124,11 @@ class Emulator(object): self.args = parser.parse_args(self.argv[1:]) self.log.debug('Args: %s' % self.args) + # Handle meta parameters + for meta_parameter in self.meta_parameters.keys(): + if meta_parameter in self.args: + self.meta_parameters[meta_parameter] = getattr(self.args, meta_parameter) + delattr(self.args, meta_parameter) def setup_object(self): # Setup object_id - FIXME: unset / do not setup anymore! @@ -175,10 +185,18 @@ class Emulator(object): def record_requirements(self): """record requirements""" + for key in ('before', 'after'): + if key in self.meta_parameters and self.meta_parameters[key]: + for value in self.meta_parameters[key]: + self.log.debug("Recording requirement: %s %s %s", self.cdist_object.name, key, value) + dependency_list = getattr(self.cdist_object, key) + # append to the object.after or object.before lists + dependency_list.append(value) if "require" in self.env: + warnings.warn("The 'require' envrionment variable is deprecated. Use the --before and --after meta parameters to define dependencies.", category=PendingDeprecationWarning, stacklevel=2) + requirements = self.env['require'] - self.log.debug("reqs = " + requirements) for requirement in requirements.split(" "): # Ignore empty fields - probably the only field anyway if len(requirement) == 0: continue @@ -187,11 +205,10 @@ class Emulator(object): cdist_object = self.cdist_object.object_from_name(requirement) self.log.debug("Recording requirement: " + requirement) - # Save the sanitised version, not the user supplied one # (__file//bar => __file/bar) # This ensures pattern matching is done against sanitised list - self.cdist_object.requirements.append(cdist_object.name) + self.cdist_object.after.append(cdist_object.name) def record_auto_requirements(self): """An object shall automatically depend on all objects that it defined in it's type manifest. diff --git a/cdist/resolver.py b/cdist/resolver.py index 7e3a1a68..d181d066 100644 --- a/cdist/resolver.py +++ b/cdist/resolver.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -109,10 +109,21 @@ class DependencyResolver(object): raise RequirementNotFoundError(pattern) def _preprocess_requirements(self): - """Find all autorequire dependencies and merge them to be just requirements - for further processing. + """Find all before, after and autorequire dependencies and merge them + to be just requirements for further processing. """ for cdist_object in self.objects.values(): + if cdist_object.after: + cdist_object.requirements.extend(cdist_object.after) + # 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.after = [] + if cdist_object.before: + for other_object in self.find_requirements_by_name(cdist_object.before): + other_object.requirements.append(cdist_object.name) + # 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.before = [] if cdist_object.autorequire: # The objects (children) that this cdist_object (parent) defined # in it's type manifest shall inherit all explicit requirements diff --git a/cdist/test/object/__init__.py b/cdist/test/object/__init__.py index 3a91f709..7bdc037e 100644 --- a/cdist/test/object/__init__.py +++ b/cdist/test/object/__init__.py @@ -87,6 +87,7 @@ class ObjectTestCase(test.CdistTestCase): self.cdist_object.code_local = '' self.cdist_object.code_remote = '' self.cdist_object.state = '' + self.cdist_object.requirements = [] def test_name(self): self.assertEqual(self.cdist_object.name, '__third/moon') From 7f0ae7928a3e2bb37c7db20d23251fdd156c8f0a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 19 Nov 2012 13:04:57 +0100 Subject: [PATCH 1860/4212] fix state explorer to properly detect already existing ppa Signed-off-by: Steven Armstrong --- cdist/conf/type/__apt_ppa/explorer/state | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__apt_ppa/explorer/state b/cdist/conf/type/__apt_ppa/explorer/state index 2d8ca7c5..2bb4f65a 100755 --- a/cdist/conf/type/__apt_ppa/explorer/state +++ b/cdist/conf/type/__apt_ppa/explorer/state @@ -26,7 +26,7 @@ name="$__object_id" . /etc/lsb-release repo_name="${name#ppa:}" -repo_file_name="$(echo "$repo_name" | sed "s:\/:\-:")-${DISTRIB_CODENAME}.list" +repo_file_name="$(echo "$repo_name" | sed -e "s|[/:]|-|" -e "s|\.|_|")-${DISTRIB_CODENAME}.list" [ -s "/etc/apt/sources.list.d/${repo_file_name}" ] \ && echo present || echo absent From a8d4544c46bd54f920bff016ae372ccf56aa913f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Nov 2012 13:28:56 +0100 Subject: [PATCH 1861/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 68b35eac..d2c5f5fe 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ next: * Type __rvm_gemset: Change parameter "default" to be boolean * New Type: __user_groups (Steven Armstrong) * Type __user: Remove --groups support (now provided by __user_groups) + * Core: Support for --after and --before parameters 2.1.0pre8: 2012-11-15 * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, From 52368b0116106dd959bb5d90f88a6bb328ccf32b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Nov 2012 13:35:40 +0100 Subject: [PATCH 1862/4212] ++changes, ++update notes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + docs/web/cdist/update.mdwn | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index d2c5f5fe..943d83e4 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ next: * Type __rvm_gemset: Change parameter "default" to be boolean * New Type: __user_groups (Steven Armstrong) * Type __user: Remove --groups support (now provided by __user_groups) + * Type __apt_ppa: Bugfix: Installeded ppa detection (Steven Armstrong) * Core: Support for --after and --before parameters 2.1.0pre8: 2012-11-15 diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index 22b92769..3331ec85 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -42,6 +42,7 @@ To upgrade to the lastet version do * The types **\_\_autofs**, **\_\_autofs_map** and **\_\_autofs_reload** have been removed (no maintainer, no users) * Type **\_\_user**: Parameter --groups removed (use the new \_\_user_groups type) + * require="" is deprecated: Use --after and --before as parameters instead ### Updating from 1.7 to 2.0 From 4718b81a08c4b95ad76a654723d655a7ee62a324 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Nov 2012 13:40:35 +0100 Subject: [PATCH 1863/4212] Documentation cleanup (old pre-boolean variant) Signed-off-by: Nico Schottelius --- cdist/conf/type/__rvm_gem/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__rvm_gem/man.text b/cdist/conf/type/__rvm_gem/man.text index fbf9a622..2b72e7ae 100644 --- a/cdist/conf/type/__rvm_gem/man.text +++ b/cdist/conf/type/__rvm_gem/man.text @@ -36,7 +36,7 @@ __rvm_gemset rails --gemset ruby-1.9.3-p0@myset --user bill --state present # Do the same and also make ruby-1.9.3-p0@myset the default gemset __rvm_gemset rails --gemset ruby-1.9.3-p0@myset --user bill \ - --state present --default yes + --state present --default # Remove it __rvm_ruby rails --gemset ruby-1.9.3-p0@myset --user bill --state absent From d419722a2429c9527ee02dd3d7db1e50e6cf3272 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Nov 2012 13:43:45 +0100 Subject: [PATCH 1864/4212] adapt documentation to use boolean parameter as well Signed-off-by: Nico Schottelius --- cdist/conf/type/__jail/man.text | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__jail/man.text b/cdist/conf/type/__jail/man.text index 62b6e02e..f4b9e3a1 100644 --- a/cdist/conf/type/__jail/man.text +++ b/cdist/conf/type/__jail/man.text @@ -78,7 +78,7 @@ __jail www --state present --ip "192.168.1.2" --jailbase /my/jail/base.tgz __jail www --state absent --jailbase /my/jail/base.tgz # Ensure that the jail called www is started -__jail www --state present --started true \ +__jail www --state present --started \ --ip "192.168.1.2 netmask 255.255.255.0" \ --jailbase /my/jail/base.tgz @@ -88,10 +88,10 @@ __jail thisjail --state present --name www \ --jailbase /my/jail/base.tgz # Go nuts -__jail lotsofoptions --state present --name testjail --started true \ +__jail lotsofoptions --state present --name testjail --started \ --ip "192.168.1.100 netmask 255.255.255.0" \ --hostname "testjail.example.com" --interface "em0" \ - --onboot yes --jailbase /my/jail/base.tgz --jaildir /jails + --onboot --jailbase /my/jail/base.tgz --jaildir /jails -------------------------------------------------------------------------------- From d4fc49fa6be78ada6f9dc3e86919825394e5fc9e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Nov 2012 15:13:57 +0100 Subject: [PATCH 1865/4212] begin manpage Signed-off-by: Nico Schottelius --- .../conf}/type/__git/gencode-remote | 0 cdist/conf/type/__git/man.text | 68 +++++++++++++++++++ {conf => cdist/conf}/type/__git/manifest | 0 .../conf}/type/__git/parameter/required | 0 4 files changed, 68 insertions(+) rename {conf => cdist/conf}/type/__git/gencode-remote (100%) create mode 100644 cdist/conf/type/__git/man.text rename {conf => cdist/conf}/type/__git/manifest (100%) rename {conf => cdist/conf}/type/__git/parameter/required (100%) diff --git a/conf/type/__git/gencode-remote b/cdist/conf/type/__git/gencode-remote similarity index 100% rename from conf/type/__git/gencode-remote rename to cdist/conf/type/__git/gencode-remote diff --git a/cdist/conf/type/__git/man.text b/cdist/conf/type/__git/man.text new file mode 100644 index 00000000..230f43c3 --- /dev/null +++ b/cdist/conf/type/__git/man.text @@ -0,0 +1,68 @@ +cdist-type__git(7) +================== +Nico Schottelius + + +NAME +---- +cdist-type__git - Get and or keep git repositories up-to-date + + +DESCRIPTION +----------- +This cdist type allows you to clone and keep git repositories +up-to-date. + + +REQUIRED PARAMETERS +------------------- +source:: + Specifies the git remote to clone from + + +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" + +branch:: + The remote branch to check out + +BOOLEAN PARAMETERS +------------------ +up-to-date:: + Whether to git merge on each run + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Create hard git of /etc/shadow +__git /home/services/dokuwiki --source /etc/shadow --type hard + +# Relative symbolic git +__git /etc/apache2/sites-enabled/www.test.ch \ + --source ../sites-available/www.test.ch \ + --type symbolic + +# Absolute symbolic git +__git /opt/plone --source /home/services/plone --type symbolic + +# Remove git +__git /opt/plone --state absent +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__git/manifest b/cdist/conf/type/__git/manifest similarity index 100% rename from conf/type/__git/manifest rename to cdist/conf/type/__git/manifest diff --git a/conf/type/__git/parameter/required b/cdist/conf/type/__git/parameter/required similarity index 100% rename from conf/type/__git/parameter/required rename to cdist/conf/type/__git/parameter/required From 2fe647a1f718979da09b8cde00f9e4c4a1ccca9f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Nov 2012 15:17:46 +0100 Subject: [PATCH 1866/4212] Revert "implement before/after to declare dependencies and deprecate require" Comment from asteven: Some problems showed up while updating the docs and tests. You should revert the merge for now. This reverts commit 84770b9ef2afbfa1232845ce6538b56df99cee3a. --- cdist/core/cdist_object.py | 2 -- cdist/emulator.py | 25 ++++--------------------- cdist/resolver.py | 17 +++-------------- cdist/test/object/__init__.py | 1 - 4 files changed, 7 insertions(+), 38 deletions(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 7e587bf3..90a21e59 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -186,8 +186,6 @@ class CdistObject(object): return os.path.join(self.path, "explorer") requirements = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'require')) - before = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'before')) - after = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'after')) 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)) diff --git a/cdist/emulator.py b/cdist/emulator.py index bd3661d3..a9c760cb 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -23,7 +23,6 @@ import argparse import logging import os -import warnings import sys import cdist @@ -93,12 +92,8 @@ class Emulator(object): def commandline(self): """Parse command line""" - self.meta_parameters = dict.fromkeys(('after', 'before')) - meta_parser = argparse.ArgumentParser(add_help=False) - for meta_parameter in self.meta_parameters.keys(): - meta_parser.add_argument('--%s' % meta_parameter, action='append', required=False) - parser = argparse.ArgumentParser(add_help=False, parents=[meta_parser], argument_default=argparse.SUPPRESS) + parser = argparse.ArgumentParser(add_help=False, argument_default=argparse.SUPPRESS) for parameter in self.cdist_type.required_parameters: argument = "--" + parameter @@ -124,11 +119,6 @@ class Emulator(object): self.args = parser.parse_args(self.argv[1:]) self.log.debug('Args: %s' % self.args) - # Handle meta parameters - for meta_parameter in self.meta_parameters.keys(): - if meta_parameter in self.args: - self.meta_parameters[meta_parameter] = getattr(self.args, meta_parameter) - delattr(self.args, meta_parameter) def setup_object(self): # Setup object_id - FIXME: unset / do not setup anymore! @@ -185,18 +175,10 @@ class Emulator(object): def record_requirements(self): """record requirements""" - for key in ('before', 'after'): - if key in self.meta_parameters and self.meta_parameters[key]: - for value in self.meta_parameters[key]: - self.log.debug("Recording requirement: %s %s %s", self.cdist_object.name, key, value) - dependency_list = getattr(self.cdist_object, key) - # append to the object.after or object.before lists - dependency_list.append(value) if "require" in self.env: - warnings.warn("The 'require' envrionment variable is deprecated. Use the --before and --after meta parameters to define dependencies.", category=PendingDeprecationWarning, stacklevel=2) - requirements = self.env['require'] + self.log.debug("reqs = " + requirements) for requirement in requirements.split(" "): # Ignore empty fields - probably the only field anyway if len(requirement) == 0: continue @@ -205,10 +187,11 @@ class Emulator(object): cdist_object = self.cdist_object.object_from_name(requirement) self.log.debug("Recording requirement: " + requirement) + # Save the sanitised version, not the user supplied one # (__file//bar => __file/bar) # This ensures pattern matching is done against sanitised list - self.cdist_object.after.append(cdist_object.name) + self.cdist_object.requirements.append(cdist_object.name) def record_auto_requirements(self): """An object shall automatically depend on all objects that it defined in it's type manifest. diff --git a/cdist/resolver.py b/cdist/resolver.py index d181d066..7e3a1a68 100644 --- a/cdist/resolver.py +++ b/cdist/resolver.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2011-2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -109,21 +109,10 @@ class DependencyResolver(object): raise RequirementNotFoundError(pattern) def _preprocess_requirements(self): - """Find all before, after and autorequire dependencies and merge them - to be just requirements for further processing. + """Find all autorequire dependencies and merge them to be just requirements + for further processing. """ for cdist_object in self.objects.values(): - if cdist_object.after: - cdist_object.requirements.extend(cdist_object.after) - # 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.after = [] - if cdist_object.before: - for other_object in self.find_requirements_by_name(cdist_object.before): - other_object.requirements.append(cdist_object.name) - # 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.before = [] if cdist_object.autorequire: # The objects (children) that this cdist_object (parent) defined # in it's type manifest shall inherit all explicit requirements diff --git a/cdist/test/object/__init__.py b/cdist/test/object/__init__.py index 7bdc037e..3a91f709 100644 --- a/cdist/test/object/__init__.py +++ b/cdist/test/object/__init__.py @@ -87,7 +87,6 @@ class ObjectTestCase(test.CdistTestCase): self.cdist_object.code_local = '' self.cdist_object.code_remote = '' self.cdist_object.state = '' - self.cdist_object.requirements = [] def test_name(self): self.assertEqual(self.cdist_object.name, '__third/moon') From 785c9ad4aae5df68a5a074c37a0584f8e0346f12 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Nov 2012 15:20:22 +0100 Subject: [PATCH 1867/4212] no after/before for now (--changes) Signed-off-by: Nico Schottelius --- docs/changelog | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 943d83e4..798a5b00 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,7 +10,6 @@ next: * New Type: __user_groups (Steven Armstrong) * Type __user: Remove --groups support (now provided by __user_groups) * Type __apt_ppa: Bugfix: Installeded ppa detection (Steven Armstrong) - * Core: Support for --after and --before parameters 2.1.0pre8: 2012-11-15 * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, From 3dfad32d4c35b62f60612889e515300479e599ed Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Nov 2012 17:24:01 +0100 Subject: [PATCH 1868/4212] add new type: __localch_kvm_vm Signed-off-by: Nico Schottelius --- cdist/conf/type/__localch_kvm_vm/README | 10 +++ cdist/conf/type/__localch_kvm_vm/manifest | 72 +++++++++++++++++++ .../type/__localch_kvm_vm/parameter/optional | 4 ++ .../type/__localch_kvm_vm/parameter/required | 2 + 4 files changed, 88 insertions(+) create mode 100644 cdist/conf/type/__localch_kvm_vm/README create mode 100644 cdist/conf/type/__localch_kvm_vm/manifest create mode 100644 cdist/conf/type/__localch_kvm_vm/parameter/optional create mode 100644 cdist/conf/type/__localch_kvm_vm/parameter/required diff --git a/cdist/conf/type/__localch_kvm_vm/README b/cdist/conf/type/__localch_kvm_vm/README new file mode 100644 index 00000000..9752aad2 --- /dev/null +++ b/cdist/conf/type/__localch_kvm_vm/README @@ -0,0 +1,10 @@ +To be executed on the Xen Host. +Using "xe" tool from Citrix Xen. + +Todo: + + - Setup DNS -> bind + - via puppet + - move away from puppet to cdist (intrusive) + - Boot VM + - Kickstart diff --git a/cdist/conf/type/__localch_kvm_vm/manifest b/cdist/conf/type/__localch_kvm_vm/manifest new file mode 100644 index 00000000..3e5df044 --- /dev/null +++ b/cdist/conf/type/__localch_kvm_vm/manifest @@ -0,0 +1,72 @@ +################################################################################ +# Default VM parameters +# +cores=4 +memory=$((8*1024*1024*1024)) +system_disk_size=$((50*1024*1024*1024)) + +[ -f "$__object/parameter/memory" ] && memory="$(cat "$__object/parameter/memory")" +[ -f "$__object/parameter/cores" ] && cores="$(cat "$__object/parameter/cores")" +[ -f "$__object/parameter/system-disk-size" ] && system_disk_size="$(cat "$__object/parameter/system-disk-size")" + +# Convert memory to MiB (kvm/qemu requirement) +memory_mebibytes=$(($memory/(1024*1024))) + +################################################################################ +# Required VM parameters +# +nic_pz="$(cat "$__object/parameter/nic-pz")" +nic_fz="$(cat "$__object/parameter/nic-fz")" +vm=$__object_id + +basedir=/opt/local.ch/sys/kvm/vm/$vm +system_disk=$basedir/system-disk +start_on_boot=$basedir/start-on-boot +vnc_socket=unix:$basedir/vnc +pidfile=$basedir/pid +monitor=$basedir/monitor + +mkdir -p "$__object/files" +start_file_source=$__object/files/start +start_file_destination=$basedir/start + +#Base VM directory +__directory $basedir --parents yes \ + --owner root --group root + +cat << eof > "$start_file_source" +#!/bin/sh +# Generated shell script - do not modify +# + +/usr/libexec/qemu-kvm \\ + -name $vm \\ + -enable-kvm \\ + -m $memory_mebibytes \\ + -drive file=${system_disk},if=virtio \\ + -vnc $vnc_socket \\ + -cpu host \\ + -boot order=nc \\ + -pidfile "$pidfile" \\ + -monitor "unix:$monitor,server,nowait" \\ + -net nic,macaddr=$nic_pz,model=virtio,vlan=200 \\ + -net tap,script=/opt/local.ch/sys/kvm/bin/ifup-pz,downscript=/opt/local.ch/sys/kvm/bin/ifdown,vlan=200 \\ + -net nic,macaddr=$nic_fz,model=virtio,vlan=300 \\ + -net tap,script=/opt/local.ch/sys/kvm/bin/ifup-fz,downscript=/opt/local.ch/sys/kvm/bin/ifdown,vlan=300 \\ + -smp $cores +eof + +require="__directory/$basedir" __file $start_file_destination \ + --source $start_file_source --mode 0755 --owner root --group root + +require="__directory/$basedir" __qemu_img "$system_disk" \ + --size "$system_disk_size" + +# Normally, create a flag to start a VM on boot (if not +# explicitly told we should not) +if [ ! -f "$__object/parameter/do-not-start-on-boot" ]; then + require="__directory/$basedir" __file "$start_on_boot" \ + --mode 0600 --owner root --group root +else + __file "$start_on_boot" --state absent +fi diff --git a/cdist/conf/type/__localch_kvm_vm/parameter/optional b/cdist/conf/type/__localch_kvm_vm/parameter/optional new file mode 100644 index 00000000..1b05d9fb --- /dev/null +++ b/cdist/conf/type/__localch_kvm_vm/parameter/optional @@ -0,0 +1,4 @@ +cores +memory +system-disk-size +do-not-start-on-boot diff --git a/cdist/conf/type/__localch_kvm_vm/parameter/required b/cdist/conf/type/__localch_kvm_vm/parameter/required new file mode 100644 index 00000000..01161205 --- /dev/null +++ b/cdist/conf/type/__localch_kvm_vm/parameter/required @@ -0,0 +1,2 @@ +nic-pz +nic-fz From a6452cfabd1215decdfaa8dbe4e254fb272f189f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Nov 2012 17:24:38 +0100 Subject: [PATCH 1869/4212] rename type to reflect new environment Signed-off-by: Nico Schottelius --- cdist/conf/type/{__localch_kvm_vm => __nico_kvm_vm}/README | 0 cdist/conf/type/{__localch_kvm_vm => __nico_kvm_vm}/manifest | 0 .../type/{__localch_kvm_vm => __nico_kvm_vm}/parameter/optional | 0 .../type/{__localch_kvm_vm => __nico_kvm_vm}/parameter/required | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename cdist/conf/type/{__localch_kvm_vm => __nico_kvm_vm}/README (100%) rename cdist/conf/type/{__localch_kvm_vm => __nico_kvm_vm}/manifest (100%) rename cdist/conf/type/{__localch_kvm_vm => __nico_kvm_vm}/parameter/optional (100%) rename cdist/conf/type/{__localch_kvm_vm => __nico_kvm_vm}/parameter/required (100%) diff --git a/cdist/conf/type/__localch_kvm_vm/README b/cdist/conf/type/__nico_kvm_vm/README similarity index 100% rename from cdist/conf/type/__localch_kvm_vm/README rename to cdist/conf/type/__nico_kvm_vm/README diff --git a/cdist/conf/type/__localch_kvm_vm/manifest b/cdist/conf/type/__nico_kvm_vm/manifest similarity index 100% rename from cdist/conf/type/__localch_kvm_vm/manifest rename to cdist/conf/type/__nico_kvm_vm/manifest diff --git a/cdist/conf/type/__localch_kvm_vm/parameter/optional b/cdist/conf/type/__nico_kvm_vm/parameter/optional similarity index 100% rename from cdist/conf/type/__localch_kvm_vm/parameter/optional rename to cdist/conf/type/__nico_kvm_vm/parameter/optional diff --git a/cdist/conf/type/__localch_kvm_vm/parameter/required b/cdist/conf/type/__nico_kvm_vm/parameter/required similarity index 100% rename from cdist/conf/type/__localch_kvm_vm/parameter/required rename to cdist/conf/type/__nico_kvm_vm/parameter/required From 8408f433e997ed7eccbafd5fe847da8bce2704b6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Nov 2012 17:27:35 +0100 Subject: [PATCH 1870/4212] remove type from here - goes into cdist-nico repo Signed-off-by: Nico Schottelius --- cdist/conf/type/__nico_kvm_vm/README | 10 --- cdist/conf/type/__nico_kvm_vm/manifest | 72 ------------------- .../type/__nico_kvm_vm/parameter/optional | 4 -- .../type/__nico_kvm_vm/parameter/required | 2 - 4 files changed, 88 deletions(-) delete mode 100644 cdist/conf/type/__nico_kvm_vm/README delete mode 100644 cdist/conf/type/__nico_kvm_vm/manifest delete mode 100644 cdist/conf/type/__nico_kvm_vm/parameter/optional delete mode 100644 cdist/conf/type/__nico_kvm_vm/parameter/required diff --git a/cdist/conf/type/__nico_kvm_vm/README b/cdist/conf/type/__nico_kvm_vm/README deleted file mode 100644 index 9752aad2..00000000 --- a/cdist/conf/type/__nico_kvm_vm/README +++ /dev/null @@ -1,10 +0,0 @@ -To be executed on the Xen Host. -Using "xe" tool from Citrix Xen. - -Todo: - - - Setup DNS -> bind - - via puppet - - move away from puppet to cdist (intrusive) - - Boot VM - - Kickstart diff --git a/cdist/conf/type/__nico_kvm_vm/manifest b/cdist/conf/type/__nico_kvm_vm/manifest deleted file mode 100644 index 3e5df044..00000000 --- a/cdist/conf/type/__nico_kvm_vm/manifest +++ /dev/null @@ -1,72 +0,0 @@ -################################################################################ -# Default VM parameters -# -cores=4 -memory=$((8*1024*1024*1024)) -system_disk_size=$((50*1024*1024*1024)) - -[ -f "$__object/parameter/memory" ] && memory="$(cat "$__object/parameter/memory")" -[ -f "$__object/parameter/cores" ] && cores="$(cat "$__object/parameter/cores")" -[ -f "$__object/parameter/system-disk-size" ] && system_disk_size="$(cat "$__object/parameter/system-disk-size")" - -# Convert memory to MiB (kvm/qemu requirement) -memory_mebibytes=$(($memory/(1024*1024))) - -################################################################################ -# Required VM parameters -# -nic_pz="$(cat "$__object/parameter/nic-pz")" -nic_fz="$(cat "$__object/parameter/nic-fz")" -vm=$__object_id - -basedir=/opt/local.ch/sys/kvm/vm/$vm -system_disk=$basedir/system-disk -start_on_boot=$basedir/start-on-boot -vnc_socket=unix:$basedir/vnc -pidfile=$basedir/pid -monitor=$basedir/monitor - -mkdir -p "$__object/files" -start_file_source=$__object/files/start -start_file_destination=$basedir/start - -#Base VM directory -__directory $basedir --parents yes \ - --owner root --group root - -cat << eof > "$start_file_source" -#!/bin/sh -# Generated shell script - do not modify -# - -/usr/libexec/qemu-kvm \\ - -name $vm \\ - -enable-kvm \\ - -m $memory_mebibytes \\ - -drive file=${system_disk},if=virtio \\ - -vnc $vnc_socket \\ - -cpu host \\ - -boot order=nc \\ - -pidfile "$pidfile" \\ - -monitor "unix:$monitor,server,nowait" \\ - -net nic,macaddr=$nic_pz,model=virtio,vlan=200 \\ - -net tap,script=/opt/local.ch/sys/kvm/bin/ifup-pz,downscript=/opt/local.ch/sys/kvm/bin/ifdown,vlan=200 \\ - -net nic,macaddr=$nic_fz,model=virtio,vlan=300 \\ - -net tap,script=/opt/local.ch/sys/kvm/bin/ifup-fz,downscript=/opt/local.ch/sys/kvm/bin/ifdown,vlan=300 \\ - -smp $cores -eof - -require="__directory/$basedir" __file $start_file_destination \ - --source $start_file_source --mode 0755 --owner root --group root - -require="__directory/$basedir" __qemu_img "$system_disk" \ - --size "$system_disk_size" - -# Normally, create a flag to start a VM on boot (if not -# explicitly told we should not) -if [ ! -f "$__object/parameter/do-not-start-on-boot" ]; then - require="__directory/$basedir" __file "$start_on_boot" \ - --mode 0600 --owner root --group root -else - __file "$start_on_boot" --state absent -fi diff --git a/cdist/conf/type/__nico_kvm_vm/parameter/optional b/cdist/conf/type/__nico_kvm_vm/parameter/optional deleted file mode 100644 index 1b05d9fb..00000000 --- a/cdist/conf/type/__nico_kvm_vm/parameter/optional +++ /dev/null @@ -1,4 +0,0 @@ -cores -memory -system-disk-size -do-not-start-on-boot diff --git a/cdist/conf/type/__nico_kvm_vm/parameter/required b/cdist/conf/type/__nico_kvm_vm/parameter/required deleted file mode 100644 index 01161205..00000000 --- a/cdist/conf/type/__nico_kvm_vm/parameter/required +++ /dev/null @@ -1,2 +0,0 @@ -nic-pz -nic-fz From b996dcbae187ed5ab635d884bff80553e588a88b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Nov 2012 17:42:39 +0100 Subject: [PATCH 1871/4212] bugfix __qemu_img Signed-off-by: Nico Schottelius --- cdist/conf/type/__qemu_img/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__qemu_img/gencode-remote b/cdist/conf/type/__qemu_img/gencode-remote index e5ff1b4f..2a76cf8f 100644 --- a/cdist/conf/type/__qemu_img/gencode-remote +++ b/cdist/conf/type/__qemu_img/gencode-remote @@ -3,7 +3,7 @@ # not existing and state != absent # state="present" -[ -f "$__object/parameter/state" ] state="$(cat "$__object/parameter/state")" +[ -f "$__object/parameter/state" ] && state="$(cat "$__object/parameter/state")" [ "$state" = "absent" ] && exit 0 exists="$(cat "$__object/explorer/exists")" From 661e33ac4b20cab30cb1d18075ed335f42b28042 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 20 Nov 2012 18:09:57 +0100 Subject: [PATCH 1872/4212] document on how to speed up shell execution Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-best-practice.text | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/man/man7/cdist-best-practice.text b/docs/man/man7/cdist-best-practice.text index a8851f7f..818c423a 100644 --- a/docs/man/man7/cdist-best-practice.text +++ b/docs/man/man7/cdist-best-practice.text @@ -30,6 +30,15 @@ Host * ControlPersist 10 -------------------------------------------------------------------------------- +SPEEDING UP SHELL EXECUTION +---------------------------- +On the source host, ensure that /bin/sh is *not* bash: bash is quite slow for +script execution. Instead, you could use dash after installing it: + +-------------------------------------------------------------------------------- +ln -sf /bin/dash /bin/sh +-------------------------------------------------------------------------------- + MULTI MASTER OR ENVIRONMENT SETUPS ---------------------------------- From 8bf196fdc0b62ce807ac5b526455dd64aaf6975b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 20 Nov 2012 22:41:38 +0100 Subject: [PATCH 1873/4212] add helpful log message when resolving dependencies Signed-off-by: Nico Schottelius --- cdist/resolver.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/resolver.py b/cdist/resolver.py index 7e3a1a68..c1b2c292 100644 --- a/cdist/resolver.py +++ b/cdist/resolver.py @@ -77,6 +77,7 @@ 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._preprocess_requirements() for name,cdist_object in self.objects.items(): From a1ed12b382a9efb872c28cf372746b14ae1011d5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 21 Nov 2012 09:21:13 +0100 Subject: [PATCH 1874/4212] roadmap proposal Signed-off-by: Nico Schottelius --- docs/dev/logs/2012-11-21.roadmap-proposal | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 docs/dev/logs/2012-11-21.roadmap-proposal diff --git a/docs/dev/logs/2012-11-21.roadmap-proposal b/docs/dev/logs/2012-11-21.roadmap-proposal new file mode 100644 index 00000000..cd60ffe6 --- /dev/null +++ b/docs/dev/logs/2012-11-21.roadmap-proposal @@ -0,0 +1,6 @@ +Target version proposed date features +2.1. 2012-12-01 initial support for before/after requirements +2.2. 2013-03-01 initial notifications support, + replace require="" with before/after +2.3. 2013-06-01 installation support: pre-os and install types +2.4. 2013-09-01 performance speedup via parallelisation From 9e9271fd4f91d859145280c732d3f5dde8fc67cc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 21 Nov 2012 09:44:38 +0100 Subject: [PATCH 1875/4212] why should I use cdist? Signed-off-by: Nico Schottelius --- docs/web/cdist.mdwn | 1 + docs/web/cdist/why.mdwn | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 docs/web/cdist/why.mdwn diff --git a/docs/web/cdist.mdwn b/docs/web/cdist.mdwn index ee24e910..74457fc8 100644 --- a/docs/web/cdist.mdwn +++ b/docs/web/cdist.mdwn @@ -11,6 +11,7 @@ cdist is an alternative to other configuration management systems like [cfengine](http://www.cfengine.org/) and [puppet](http://www.puppetlabs.com/). + * [[Why should I use cdist?|why]] * [[Documentation|documentation]] * [[Supported Operating Systems|os]] * [[Installation|install]] diff --git a/docs/web/cdist/why.mdwn b/docs/web/cdist/why.mdwn new file mode 100644 index 00000000..883d6338 --- /dev/null +++ b/docs/web/cdist/why.mdwn @@ -0,0 +1,37 @@ +[[!meta title="Why should I use cdist?"]] + +There are several motivations to use cdist, these +are probably the most popular ones. + +## Known language + +Cdist is being configured in +[shell script](https://en.wikipedia.org/wiki/Shell_script). +Shell script is used by UNIX system engineers for decades. +So when cdist is introduced, your staff does not need to learn a new +[DSL](https://en.wikipedia.org/wiki/Domain-specific_language) +or programming language. + +## Powerful language + +Not only is shell scripting widely known by system engineers, +but it is also a very powerful language. Here are some features +which make daily work easy: + + * Configuration can react dynamicly on explored values + * High level string manipulation (using sed, awk, grep) + * Conditional support (**if, case**) + * Loop support (**for, while**) + * Support for dependencies between cdist types + +## More than shell scripting + +If you compare regular shell scripting with cdist, there is one major +difference: When using cdist types, +the results are +[idempotent](https://en.wikipedia.org/wiki/Idempotence). +In practise, that means it does not matter in which order you +call cdist types, the result is always the same. + + +[[!tag cdist unix]] From 2b32e1e9f434744eaed836298ebd3b4b2463373b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 21 Nov 2012 11:26:52 +0100 Subject: [PATCH 1876/4212] more reasons to use cdist Signed-off-by: Nico Schottelius --- docs/web/cdist/why.mdwn | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/docs/web/cdist/why.mdwn b/docs/web/cdist/why.mdwn index 883d6338..6aa3516f 100644 --- a/docs/web/cdist/why.mdwn +++ b/docs/web/cdist/why.mdwn @@ -1,5 +1,7 @@ [[!meta title="Why should I use cdist?"]] +[[!toc]] + There are several motivations to use cdist, these are probably the most popular ones. @@ -30,8 +32,40 @@ If you compare regular shell scripting with cdist, there is one major difference: When using cdist types, the results are [idempotent](https://en.wikipedia.org/wiki/Idempotence). -In practise, that means it does not matter in which order you +In practise that means it does not matter in which order you call cdist types, the result is always the same. +## Zero dependency configuration management + +Cdist requires very litte on a target system. Even better, +in almost all cases all dependencies are usually fulfilled. +Cdist does not require an agent or a high level programming +languages on the target host: it will run on any host that +has an **ssh server running** and a posix compatible shell +(**/bin/sh**). + +## Push based distribution + +Cdist uses the push based model for configuration. In this +scenario, one (or more) computers connect the target hosts +and apply the configuration. That way the source host has +very little requirements: Cdist can even run on a sysadmin +notebook that is loosely connected to the network and has +limited amount of resources. + +Furthermore, from a security point of view, only one machine +needs access to the target hosts. No target hosts will ever +need to connect back to the source host, which contains the +full configuration. + +## Highly scalable + +If at some point you manage more hosts than can be handled from +a single source host, you can simply add more resources: Either +add more cores to one host or add hosts. +Cdist will utilise the given resources in parallel. + +## Integration into inventory management + [[!tag cdist unix]] From 4d63694e20b3d564d148e272b0afb0c6c8002649 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 21 Nov 2012 11:34:32 +0100 Subject: [PATCH 1877/4212] introduce new web-doc target to publish only the web documentation Signed-off-by: Nico Schottelius --- build | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/build b/build index fb01c565..6fe8960f 100755 --- a/build +++ b/build @@ -331,14 +331,17 @@ eof done ;; - web) - set -e + 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 + ;; + 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 && From 9c99346ddf77935a81d80d24472ffa232b506847 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 21 Nov 2012 16:09:00 +0100 Subject: [PATCH 1878/4212] remove emtpy heading Signed-off-by: Nico Schottelius --- docs/web/cdist/why.mdwn | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/web/cdist/why.mdwn b/docs/web/cdist/why.mdwn index 6aa3516f..0fcdf5c5 100644 --- a/docs/web/cdist/why.mdwn +++ b/docs/web/cdist/why.mdwn @@ -65,7 +65,4 @@ a single source host, you can simply add more resources: Either add more cores to one host or add hosts. Cdist will utilise the given resources in parallel. -## Integration into inventory management - - [[!tag cdist unix]] From 0c15d0ff024db2cfa8f29a8fcec39c5bd8b1e5b3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 21 Nov 2012 22:52:14 +0100 Subject: [PATCH 1879/4212] ++ideas Signed-off-by: Nico Schottelius --- docs/dev/logs/2012-11-21.idea-shell-testing | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 docs/dev/logs/2012-11-21.idea-shell-testing diff --git a/docs/dev/logs/2012-11-21.idea-shell-testing b/docs/dev/logs/2012-11-21.idea-shell-testing new file mode 100644 index 00000000..2a657053 --- /dev/null +++ b/docs/dev/logs/2012-11-21.idea-shell-testing @@ -0,0 +1,3 @@ +Use roundup for testing included types? + + http://bmizerany.github.com/roundup/ From 1bd27fffaefffeb040a353da629ddad2a68d73a8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Nov 2012 10:57:10 +0100 Subject: [PATCH 1880/4212] __jail: started -> stopped, correct help output Signed-off-by: Nico Schottelius --- cdist/conf/type/__jail/gencode-remote | 6 +++--- cdist/conf/type/__jail/man.text | 4 ++-- cdist/conf/type/__jail/parameter/boolean | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__jail/gencode-remote b/cdist/conf/type/__jail/gencode-remote index 56a1b643..1f326bf1 100755 --- a/cdist/conf/type/__jail/gencode-remote +++ b/cdist/conf/type/__jail/gencode-remote @@ -34,8 +34,8 @@ fi state="$(cat "$__object/parameter/state")" -started="false" -[ -f "$__object/parameter/started" -a "$state" = "present" ] && started="true" +started="true" +[ -f "$__object/parameter/stopped" ] && started="false" if [ -f "$__object/parameter/ip" ]; then ip="$(cat "$__object/parameter/ip")" @@ -75,7 +75,7 @@ fi # is pointless. Treat this as an error. if [ -n "$devfsruleset" -a "$devfsenable" = "false" ]; then exec >&2 - echo "Can't have --devfs-ruleset defined without --devfs-disable" + echo "Can't have --devfs-ruleset defined with --devfs-disable" exit 1 fi diff --git a/cdist/conf/type/__jail/man.text b/cdist/conf/type/__jail/man.text index f4b9e3a1..48794637 100644 --- a/cdist/conf/type/__jail/man.text +++ b/cdist/conf/type/__jail/man.text @@ -49,8 +49,8 @@ jaildir:: BOOLEAN PARAMETERS ------------------ -started:: - Whether to start jail +stopped:: + Do not start the jail devfs-disable:: Whether to disallow devfs mounting within the jail diff --git a/cdist/conf/type/__jail/parameter/boolean b/cdist/conf/type/__jail/parameter/boolean index 1dd61f6b..39144f6f 100644 --- a/cdist/conf/type/__jail/parameter/boolean +++ b/cdist/conf/type/__jail/parameter/boolean @@ -1,3 +1,3 @@ onboot -started +stopped devfs-disable From 868421bf16ffbc06f65278948997c73ad959ee5d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 30 Nov 2012 10:01:37 +0100 Subject: [PATCH 1881/4212] Update examples to match new parameters Signed-off-by: Nico Schottelius --- cdist/conf/type/__jail/man.text | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__jail/man.text b/cdist/conf/type/__jail/man.text index 48794637..b439e0f5 100644 --- a/cdist/conf/type/__jail/man.text +++ b/cdist/conf/type/__jail/man.text @@ -77,8 +77,8 @@ __jail www --state present --ip "192.168.1.2" --jailbase /my/jail/base.tgz # Remove the jail called www __jail www --state absent --jailbase /my/jail/base.tgz -# Ensure that the jail called www is started -__jail www --state present --started \ +# The jail www should not be started +__jail www --state present --stopped \ --ip "192.168.1.2 netmask 255.255.255.0" \ --jailbase /my/jail/base.tgz @@ -88,7 +88,7 @@ __jail thisjail --state present --name www \ --jailbase /my/jail/base.tgz # Go nuts -__jail lotsofoptions --state present --name testjail --started \ +__jail lotsofoptions --state present --name testjail \ --ip "192.168.1.100 netmask 255.255.255.0" \ --hostname "testjail.example.com" --interface "em0" \ --onboot --jailbase /my/jail/base.tgz --jaildir /jails From 8e6073bc6f2061dfb8138a1064b8ebfd4262dcb9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 30 Nov 2012 10:21:12 +0100 Subject: [PATCH 1882/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index 798a5b00..87971c08 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,12 +4,16 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -next: - * Core: Ensure global and type explorers are executable +2.1.0: + * Core: Ensure global explorers are executable + * Core: Ensure type explorers are executable (Steven Armstrong) * Type __rvm_gemset: Change parameter "default" to be boolean * New Type: __user_groups (Steven Armstrong) * Type __user: Remove --groups support (now provided by __user_groups) * Type __apt_ppa: Bugfix: Installeded ppa detection (Steven Armstrong) + * Type __jail: Change optional parameter "started" to boolean "stopped" parameter, + change optional parameter "devfs-enable" to boolean "devfs-disable" parameter and + change optional parameter "onboot" to boolean. 2.1.0pre8: 2012-11-15 * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, From 3a419ed58b58ae80bca2b731d582a85744e1e656 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 30 Nov 2012 10:29:20 +0100 Subject: [PATCH 1883/4212] make type explorers executable after transfering them Signed-off-by: Steven Armstrong --- cdist/core/explorer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 86ce52ac..d926552a 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -153,7 +153,7 @@ class Explorer(object): destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) self.remote.mkdir(destination) self.remote.transfer(source, destination) - self.remote.run(["chmod", "0700", "%s" % (destination)]) + self.remote.run(["chmod", "0700", "%s/*" % (destination)]) self._type_explorers_transferred.append(cdist_type.name) def transfer_object_parameters(self, cdist_object): From 1ef5bcaa74cecefc85c0d53d484e2559bc3aba7d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 30 Nov 2012 11:59:38 +0100 Subject: [PATCH 1884/4212] new type: __ssh_authorized_keys - manage ssh authorized_keys files Signed-off-by: Steven Armstrong --- .../type/__ssh_authorized_keys/explorer/entry | 45 ++++++++ .../__ssh_authorized_keys/explorer/passwd | 23 ++++ .../type/__ssh_authorized_keys/gencode-remote | 82 ++++++++++++++ .../conf/type/__ssh_authorized_keys/man.text | 101 ++++++++++++++++++ .../conf/type/__ssh_authorized_keys/manifest | 74 +++++++++++++ .../__ssh_authorized_keys/parameter/boolean | 2 + .../__ssh_authorized_keys/parameter/optional | 4 + .../parameter/required_multiple | 1 + 8 files changed, 332 insertions(+) create mode 100755 cdist/conf/type/__ssh_authorized_keys/explorer/entry create mode 100755 cdist/conf/type/__ssh_authorized_keys/explorer/passwd create mode 100755 cdist/conf/type/__ssh_authorized_keys/gencode-remote create mode 100644 cdist/conf/type/__ssh_authorized_keys/man.text create mode 100755 cdist/conf/type/__ssh_authorized_keys/manifest create mode 100644 cdist/conf/type/__ssh_authorized_keys/parameter/boolean create mode 100644 cdist/conf/type/__ssh_authorized_keys/parameter/optional create mode 100644 cdist/conf/type/__ssh_authorized_keys/parameter/required_multiple diff --git a/cdist/conf/type/__ssh_authorized_keys/explorer/entry b/cdist/conf/type/__ssh_authorized_keys/explorer/entry new file mode 100755 index 00000000..9992d32d --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_keys/explorer/entry @@ -0,0 +1,45 @@ +#!/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/explorer/passwd b/cdist/conf/type/__ssh_authorized_keys/explorer/passwd new file mode 100755 index 00000000..e6352ee0 --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_keys/explorer/passwd @@ -0,0 +1,23 @@ +#!/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")" + +getent passwd "$owner" || true diff --git a/cdist/conf/type/__ssh_authorized_keys/gencode-remote b/cdist/conf/type/__ssh_authorized_keys/gencode-remote new file mode 100755 index 00000000..cc86cc19 --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_keys/gencode-remote @@ -0,0 +1,82 @@ +#!/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="$(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) +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/man.text b/cdist/conf/type/__ssh_authorized_keys/man.text new file mode 100644 index 00000000..7177f26e --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_keys/man.text @@ -0,0 +1,101 @@ +cdist-type__ssh_authorized_keys(7) +================================== +Steven Armstrong + + +NAME +---- +cdist-type__ssh_authorized_keys - manage ssh authorized_keys files + + +DESCRIPTION +----------- +Adds or removes ssh keys from a authorized_keys file. + +This type also manages the directory containing the authorized_keys +file and sets strict ownership and permissions. You can disable this feature +with the --noparent boolean parameter. + +The existence, ownership and permissions of the authorized_keys file itself are +also managed. This can be disabled with the --nofile boolean parameter. It is +then left to the user to ensure that the file exists and that ownership and +permissions work with ssh. + + +REQUIRED PARAMETERS +------------------- +key:: + the ssh key which shall be added to this authorized_keys file. + Must be a string and can be specified multiple times. + + +OPTIONAL PARAMETERS +------------------- +owner:: + the user owning the authorized_keys file, defaults to object_id. + +state:: + if the given keys should be 'present' or 'absent', defaults to 'present'. + +file:: + an alternative destination file, defaults to ~$owner/.ssh/authorized_keys + +comment:: + an optional comment + + +BOOLEAN PARAMETERS +------------------ +noparent:: + don't create or change ownership and permissions of the directory containing + the authorized_keys file + +nofile:: + don't manage existence, ownership and permissions of the the authorized_keys + file + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# add your ssh key to remote root's authorized_keys file +__ssh_authorized_keys root \ + --key "$(cat ~/.ssh/id_rsa.pub)" + +# allow key to login as user-name +__ssh_authorized_keys user-name \ + --key "ssh-rsa AXYZAAB3NzaC1yc2..." + +# same as above, but with explicit owner, two keys and a comment +__ssh_authorized_keys some-fancy-id \ + --owner user-name \ + --key "ssh-rsa AXYZAAB3NzaC1yc2..." \ + --key "ssh-rsa AZXYAAB3NzaC1yc2..." \ + --comment "allow the members of project foo to login" + +# same as above, but authorized_keys file in non standard location +__ssh_authorized_keys some-fancy-id \ + --file /etc/ssh/keys/user-name/authorized_keys \ + --owner user-name \ + --key "ssh-rsa AXYZAAB3NzaC1yc2..." + +# same as above, but directory and authorized_keys file is created elswhere +__ssh_authorized_keys some-fancy-id \ + --file /etc/ssh/keys/user-name/authorized_keys \ + --owner user-name \ + --noparent \ + --nofile \ + --key "ssh-rsa AXYZAAB3NzaC1yc2..." +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +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/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest new file mode 100755 index 00000000..268b1fbe --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -0,0 +1,74 @@ +#!/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")" +state="$(cat "$__object/parameter/present" 2>/dev/null || echo "present")" +if [ -f "$__object/parameter/file" ]; then + file="$(cat "$__object/parameter/file")" +else + home="$(cut -d':' -f 6 "$__object/explorer/passwd")" + if [ -z "$home" ]; then + echo "Failed to get home directory from explorer." >&2 + exit 1 + fi + file="$home/.ssh/authorized_keys" +fi + +if [ ! -f "$__object/parameter/noparent" -o ! -f "$__object/parameter/nofile" ]; then + group="$(cut -d':' -f 4 "$__object/explorer/passwd")" + if [ -z "$group" ]; then + echo "Failed to get owners group from explorer." >&2 + exit 1 + fi + + if [ ! -f "$__object/parameter/noparent" ]; then + # 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 \ + --owner "$owner" --group "$group" --mode 0700 + export require="__directory/$ssh_directory" + fi + if [ ! -f "$__object/parameter/nofile" ]; then + # Ensure that authorized_keys file exists and has the right permissions. + __file "$file" \ + --owner "$owner" \ + --group "$group" \ + --mode 0600 \ + --state exists + 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" +fi +cat "$__object/parameter/key" >> "$entry" +# ensure we have a newline after keys +echo >> "$entry" +echo "$suffix" >> "$entry" diff --git a/cdist/conf/type/__ssh_authorized_keys/parameter/boolean b/cdist/conf/type/__ssh_authorized_keys/parameter/boolean new file mode 100644 index 00000000..4bb126fe --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_keys/parameter/boolean @@ -0,0 +1,2 @@ +noparent +nofile diff --git a/cdist/conf/type/__ssh_authorized_keys/parameter/optional b/cdist/conf/type/__ssh_authorized_keys/parameter/optional new file mode 100644 index 00000000..bfbd72ab --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_keys/parameter/optional @@ -0,0 +1,4 @@ +owner +state +file +comment diff --git a/cdist/conf/type/__ssh_authorized_keys/parameter/required_multiple b/cdist/conf/type/__ssh_authorized_keys/parameter/required_multiple new file mode 100644 index 00000000..06bfde49 --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_keys/parameter/required_multiple @@ -0,0 +1 @@ +key From f37f3d201ce2174626ab41e47b4c93000a933dc4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 30 Nov 2012 14:41:47 +0100 Subject: [PATCH 1885/4212] __ssh_authorized_key has been superseeded by __ssh_authorized_keys Signed-off-by: Nico Schottelius --- .../explorer/dstuser_group | 15 ----- cdist/conf/type/__ssh_authorized_key/man.text | 46 ------------- cdist/conf/type/__ssh_authorized_key/manifest | 66 ------------------- .../__ssh_authorized_key/parameter/optional | 2 - 4 files changed, 129 deletions(-) delete mode 100644 cdist/conf/type/__ssh_authorized_key/explorer/dstuser_group delete mode 100644 cdist/conf/type/__ssh_authorized_key/man.text delete mode 100755 cdist/conf/type/__ssh_authorized_key/manifest delete mode 100644 cdist/conf/type/__ssh_authorized_key/parameter/optional diff --git a/cdist/conf/type/__ssh_authorized_key/explorer/dstuser_group b/cdist/conf/type/__ssh_authorized_key/explorer/dstuser_group deleted file mode 100644 index c79f8d9f..00000000 --- a/cdist/conf/type/__ssh_authorized_key/explorer/dstuser_group +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -# Get option dstuser if defined -if [ -f "$__object/parameter/dstuser" ]; then - dstuser=`cat "$__object/parameter/dstuser"` -else - dstuser="root" -fi - -if id $dstuser >/dev/null 2>&1 ; then - id -ng $dstuser -else - echo "$__object_id: Destination user $dstuser does not exist" >&2 - exit 1 -fi diff --git a/cdist/conf/type/__ssh_authorized_key/man.text b/cdist/conf/type/__ssh_authorized_key/man.text deleted file mode 100644 index b372b354..00000000 --- a/cdist/conf/type/__ssh_authorized_key/man.text +++ /dev/null @@ -1,46 +0,0 @@ -cdist-type__ssh_authorized_key(7) -================================= -Aurélien Bondis - - -NAME ----- -cdist-type__ssh_authorized_key - Sends a user's public key to another user's authorized_keys - - -DESCRIPTION ------------ -This type sends a rsa key. By default uses root's key and sends it to root's authorized_keys - - -REQUIRED PARAMETERS -------------------- -None. - - -OPTIONAL PARAMETERS -------------------- -srcuser:: the user to take the rsa public key from -dstuser:: the user to give the rsa public key to - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -#deploy root's public key -__ssh_authorized_key admin -#deploy bob's public key to alice's authorized_keys -__ssh_authorized_key --srcuser bob --dstuser alice --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__ssh_authorized_key/manifest b/cdist/conf/type/__ssh_authorized_key/manifest deleted file mode 100755 index 86c58740..00000000 --- a/cdist/conf/type/__ssh_authorized_key/manifest +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/sh -# -# 2011 Aurélien Bondis aurelien.bondis AT gmail DOT com -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# This type allows to send a public ssh key from a user to the -# authorized_keys of another -# -#require="__package openssh-server --state present" -# Get option srcuser if defined -if [ -f "$__object/parameter/srcuser" ]; then - srcuser=`cat "$__object/parameter/srcuser"` -fi -# Get option dstuser if defined -if [ -f "$__object/parameter/dstuser" ]; then - dstuser=`cat "$__object/parameter/dstuser"` -else - dstuser="root" -fi - -# retrieve destination group -dstgroup=$(cat "$__object/explorer/dstuser_group") - -# if a source user is defined, use it's public key -if [ "$srcuser" ]; then - srcrsa="/home/${srcuser}/.ssh/id_rsa.pub" -# if no source user is defined we use root's public key -else - srcrsa="/root/.ssh/id_rsa.pub" -fi -# if a destination user is defined, insert in it's authorized_keys -if [ "$dstuser" ]; then - sshpath="/home/$dstuser/.ssh" -# if no destination user is defined we use root's home -else - sshpath="/root/.ssh" -fi -rsa=`cat $srcrsa` -__directory $sshpath \ - --owner $dstuser \ - --group $dstgroup \ - --mode 700 -# the file authorized_keys depends on the .ssh folder -require="__directory${sshpath}" \ - __file "$sshpath/authorized_keys" \ - --mode 640 \ - --owner $dstuser \ - --group $dstgroup -# the line added depends on authorized_keys existence -require="__file${sshpath}/authorized_keys" __addifnosuchline sshkey --file \ - "$sshpath/authorized_keys" --line "$rsa" diff --git a/cdist/conf/type/__ssh_authorized_key/parameter/optional b/cdist/conf/type/__ssh_authorized_key/parameter/optional deleted file mode 100644 index 4903f5be..00000000 --- a/cdist/conf/type/__ssh_authorized_key/parameter/optional +++ /dev/null @@ -1,2 +0,0 @@ -srcuser -dstuser From de9b38a2015fbc16692ea3c4d3311fa435a570b7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 30 Nov 2012 14:51:15 +0100 Subject: [PATCH 1886/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 2 ++ docs/web/cdist/update.mdwn | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index 87971c08..ba73785c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -14,6 +14,8 @@ Changelog * Type __jail: Change optional parameter "started" to boolean "stopped" parameter, change optional parameter "devfs-enable" to boolean "devfs-disable" parameter and change optional parameter "onboot" to boolean. + * New Type: __ssh_authorized_keys (Steven Armstrong) + * Remove Type __ssh_authorized_key: Superseeded by __ssh_authorized_keys 2.1.0pre8: 2012-11-15 * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index 3331ec85..a50e7224 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -42,6 +42,8 @@ To upgrade to the lastet version do * The types **\_\_autofs**, **\_\_autofs_map** and **\_\_autofs_reload** have been removed (no maintainer, no users) * Type **\_\_user**: Parameter --groups removed (use the new \_\_user_groups type) + * Type **\_\_ssh_authorized_key** has been replaced by more flexible type + **\_\_ssh_authorized_keys** * require="" is deprecated: Use --after and --before as parameters instead ### Updating from 1.7 to 2.0 From 56b6c95ed4811b64dc869da277c89febe9a1e029 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 30 Nov 2012 13:48:34 +0100 Subject: [PATCH 1887/4212] implement conf-dir from CDIST_PATH environment variable Signed-off-by: Steven Armstrong --- cdist/context.py | 2 +- cdist/exec/local.py | 9 ++++++++- cdist/test/exec/local.py | 19 +++++++++++++++++++ docs/man/man1/cdist.text | 13 +++++++++---- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/cdist/context.py b/cdist/context.py index 767b17a8..e0391be8 100644 --- a/cdist/context.py +++ b/cdist/context.py @@ -38,7 +38,7 @@ class Context(object): remote_copy, remote_exec, initial_manifest=False, - add_conf_dirs=[], + add_conf_dirs=None, exec_path=sys.argv[0], debug=False): diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 7ef11458..7f640411 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -23,6 +23,7 @@ import io import os import sys +import re import subprocess import shutil import logging @@ -37,7 +38,7 @@ 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=[], cache_dir=None): + def __init__(self, target_host, out_path, exec_path, add_conf_dirs=None, cache_dir=None): self.target_host = target_host self.out_path = out_path @@ -92,6 +93,12 @@ class Local(object): if self.home_dir: self.conf_dirs.append(self.home_dir) + # Add directories defined in the CDIST_PATH environment variable + if 'CDIST_PATH' in os.environ: + cdist_path_dirs = re.split(r'(? Date: Sat, 1 Dec 2012 17:16:39 +0100 Subject: [PATCH 1888/4212] integrate CDIST_PATH Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index ba73785c..9efe27c9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -16,6 +16,7 @@ Changelog change optional parameter "onboot" to boolean. * New Type: __ssh_authorized_keys (Steven Armstrong) * Remove Type __ssh_authorized_key: Superseeded by __ssh_authorized_keys + * Support for CDIST_PATH (Steven Armstrong) 2.1.0pre8: 2012-11-15 * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, From 4d2b576553f317d267bed690939e44467aa231b1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 3 Dec 2012 09:47:48 +0100 Subject: [PATCH 1889/4212] allow setting up version when running outside dir Signed-off-by: Nico Schottelius --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index 6fe8960f..d6c9a172 100755 --- a/build +++ b/build @@ -27,7 +27,7 @@ #set -e basedir=${0%/*} -version=$(git describe) +version=$(cd "$basedir" && git describe) # Manpage and HTML A2XM="a2x -f manpage --no-xmllint -a encoding=UTF-8" From 8b91e3116afda0a20d4da5e0554fac9b5759c39f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Dec 2012 23:07:21 +0100 Subject: [PATCH 1890/4212] create working version of __git Signed-off-by: Nico Schottelius --- cdist/conf/type/__git/explorer/state | 30 ++++++++++++++++ cdist/conf/type/__git/gencode-remote | 46 ++++++++++++++++++++++++ cdist/conf/type/__git/man.text | 30 ++++------------ cdist/conf/type/__git/manifest | 33 ++++++++++++++++- cdist/conf/type/__git/parameter/optional | 2 ++ 5 files changed, 116 insertions(+), 25 deletions(-) create mode 100755 cdist/conf/type/__git/explorer/state create mode 100644 cdist/conf/type/__git/parameter/optional diff --git a/cdist/conf/type/__git/explorer/state b/cdist/conf/type/__git/explorer/state new file mode 100755 index 00000000..e0719579 --- /dev/null +++ b/cdist/conf/type/__git/explorer/state @@ -0,0 +1,30 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Check whether repository exists +# + +destination="/$__object_id/.git" + +if [ -d "$destination" ]; then + echo present +else + echo absent +fi diff --git a/cdist/conf/type/__git/gencode-remote b/cdist/conf/type/__git/gencode-remote index 8b137891..0f665d59 100644 --- a/cdist/conf/type/__git/gencode-remote +++ b/cdist/conf/type/__git/gencode-remote @@ -1 +1,47 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +state_is="$(cat "$__object/explorer/state")" +state_should=present +[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" + +branch=master +[ -f "$__object/parameter/branch" ] && branch="$(cat "$__object/parameter/branch")" + +source="$(cat "$__object/parameter/source")" + +destination="/$__object_id" + +[ "$state_should" = "$state_is" ] && exit 0 + +case $state_should in + present) + echo git clone --quiet --branch "$branch" "$source" "$destination" + ;; + # Handled in manifest + absent) + ;; + + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__git/man.text b/cdist/conf/type/__git/man.text index 230f43c3..5597a52d 100644 --- a/cdist/conf/type/__git/man.text +++ b/cdist/conf/type/__git/man.text @@ -10,8 +10,7 @@ cdist-type__git - Get and or keep git repositories up-to-date DESCRIPTION ----------- -This cdist type allows you to clone and keep git repositories -up-to-date. +This cdist type allows you to clone git repositories REQUIRED PARAMETERS @@ -22,38 +21,21 @@ source:: 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" branch:: - The remote branch to check out - -BOOLEAN PARAMETERS ------------------- -up-to-date:: - Whether to git merge on each run + Create this branch by checking out the remote branch of this name EXAMPLES -------- -------------------------------------------------------------------------------- -# Create hard git of /etc/shadow -__git /home/services/dokuwiki --source /etc/shadow --type hard +__git /home/services/dokuwiki --source git://github.com/splitbrain/dokuwiki.git -# Relative symbolic git -__git /etc/apache2/sites-enabled/www.test.ch \ - --source ../sites-available/www.test.ch \ - --type symbolic - -# Absolute symbolic git -__git /opt/plone --source /home/services/plone --type symbolic - -# Remove git -__git /opt/plone --state absent +# Checkout cdist, stay on branch 2.1 +__git /home/nico/cdist --source git://github.com/telmich/cdist.git --branch 2.1 -------------------------------------------------------------------------------- @@ -64,5 +46,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +Copyright \(C) 2012 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__git/manifest b/cdist/conf/type/__git/manifest index c0eb2c23..866515d7 100644 --- a/cdist/conf/type/__git/manifest +++ b/cdist/conf/type/__git/manifest @@ -1 +1,32 @@ -__package git +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Ensure git is present +# + +__package git --state present + +state_should=present +[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" + +# Let __directory handle removal of git repos +if [ "$state_should" = absent ]; then + __directory "$__object_id" --state absent +fi diff --git a/cdist/conf/type/__git/parameter/optional b/cdist/conf/type/__git/parameter/optional new file mode 100644 index 00000000..671134d6 --- /dev/null +++ b/cdist/conf/type/__git/parameter/optional @@ -0,0 +1,2 @@ +state +branch From ad1f0f77b8059ab05fbc180f7c0879cd9de0468a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Dec 2012 23:07:49 +0100 Subject: [PATCH 1891/4212] reformat changelog for 2.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 9efe27c9..da84bd8c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,13 +8,14 @@ Changelog * Core: Ensure global explorers are executable * Core: Ensure type explorers are executable (Steven Armstrong) * Type __rvm_gemset: Change parameter "default" to be boolean - * New Type: __user_groups (Steven Armstrong) * Type __user: Remove --groups support (now provided by __user_groups) * Type __apt_ppa: Bugfix: Installeded ppa detection (Steven Armstrong) * Type __jail: Change optional parameter "started" to boolean "stopped" parameter, change optional parameter "devfs-enable" to boolean "devfs-disable" parameter and change optional parameter "onboot" to boolean. + * New Type: __git * New Type: __ssh_authorized_keys (Steven Armstrong) + * New Type: __user_groups (Steven Armstrong) * Remove Type __ssh_authorized_key: Superseeded by __ssh_authorized_keys * Support for CDIST_PATH (Steven Armstrong) From 3167ececc62dbdaf06ca8e8a71cd84743cab0c91 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Dec 2012 23:16:03 +0100 Subject: [PATCH 1892/4212] add owner/group support to __git Signed-off-by: Nico Schottelius --- cdist/conf/type/__git/manifest | 21 ++++++++++++++++++--- cdist/conf/type/__git/parameter/optional | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__git/manifest b/cdist/conf/type/__git/manifest index 866515d7..e8c9b233 100644 --- a/cdist/conf/type/__git/manifest +++ b/cdist/conf/type/__git/manifest @@ -26,7 +26,22 @@ __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 -if [ "$state_should" = absent ]; then - __directory "$__object_id" --state absent -fi + +case "$state_should" in + present) + __directory "$__object_id" --state present $dirparams --recursive + ;; + + absent) + __directory "$__object_id" --state absent + ;; + + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__git/parameter/optional b/cdist/conf/type/__git/parameter/optional index 671134d6..d9684aaa 100644 --- a/cdist/conf/type/__git/parameter/optional +++ b/cdist/conf/type/__git/parameter/optional @@ -1,2 +1,4 @@ state branch +group +owner From 839af573b1e716ed64f19eb2dee7ee90f96d52aa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Dec 2012 23:19:47 +0100 Subject: [PATCH 1893/4212] move new types to the top Signed-off-by: Nico Schottelius --- docs/changelog | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/changelog b/docs/changelog index da84bd8c..4e0a5d99 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,15 +7,15 @@ Changelog 2.1.0: * Core: Ensure global explorers are executable * Core: Ensure type explorers are executable (Steven Armstrong) + * New Type: __git + * New Type: __ssh_authorized_keys (Steven Armstrong) + * New Type: __user_groups (Steven Armstrong) * Type __rvm_gemset: Change parameter "default" to be boolean * Type __user: Remove --groups support (now provided by __user_groups) * Type __apt_ppa: Bugfix: Installeded ppa detection (Steven Armstrong) * Type __jail: Change optional parameter "started" to boolean "stopped" parameter, change optional parameter "devfs-enable" to boolean "devfs-disable" parameter and change optional parameter "onboot" to boolean. - * New Type: __git - * New Type: __ssh_authorized_keys (Steven Armstrong) - * New Type: __user_groups (Steven Armstrong) * Remove Type __ssh_authorized_key: Superseeded by __ssh_authorized_keys * Support for CDIST_PATH (Steven Armstrong) From fe143d57b87ad0fce0b59b08dd255ecdde511778 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Dec 2012 23:43:24 +0100 Subject: [PATCH 1894/4212] add new type: __rbenv Signed-off-by: Nico Schottelius --- cdist/conf/type/__rbenv/explorer/homedir | 25 +++++++++++++ cdist/conf/type/__rbenv/man.text | 43 ++++++++++++++++++++++ cdist/conf/type/__rbenv/manifest | 34 +++++++++++++++++ cdist/conf/type/__rbenv/parameter/optional | 1 + 4 files changed, 103 insertions(+) create mode 100755 cdist/conf/type/__rbenv/explorer/homedir create mode 100644 cdist/conf/type/__rbenv/man.text create mode 100644 cdist/conf/type/__rbenv/manifest create mode 100644 cdist/conf/type/__rbenv/parameter/optional diff --git a/cdist/conf/type/__rbenv/explorer/homedir b/cdist/conf/type/__rbenv/explorer/homedir new file mode 100755 index 00000000..8dc25535 --- /dev/null +++ b/cdist/conf/type/__rbenv/explorer/homedir @@ -0,0 +1,25 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# Check whether repository exists +# + +user="$__object_id" +su - "$user" -c "pwd -P" diff --git a/cdist/conf/type/__rbenv/man.text b/cdist/conf/type/__rbenv/man.text new file mode 100644 index 00000000..bee57f76 --- /dev/null +++ b/cdist/conf/type/__rbenv/man.text @@ -0,0 +1,43 @@ +cdist-type__rbenv(7) +==================== +Nico Schottelius + + +NAME +---- +cdist-type__rbenv - Manage rbenv installation + + +DESCRIPTION +----------- +This cdist type allows you to manage rbenv installations. +It also installs ruby-build. + + +OPTIONAL PARAMETERS +------------------- +state:: + Either "present" or "absent", defaults to "present" + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Install rbenv including ruby-build for nico +__rbenv nico + +# Bastian does not need rbenv anymore, he began to code C99 +__rbenv bastian --state absent +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2012 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__rbenv/manifest b/cdist/conf/type/__rbenv/manifest new file mode 100644 index 00000000..2e8769a4 --- /dev/null +++ b/cdist/conf/type/__rbenv/manifest @@ -0,0 +1,34 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +homedir="$(cat "$__object/explorer/homedir")" +state_should=present +[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" + +rbenvdir="$homedir/.rbenv" +rubybuilddir="$rbenvdir/plugins/ruby-build" + +__git "$rbenvdir" --source git://github.com/sstephenson/rbenv.git \ + --state "$state_should" + +require="__git/$rbendir" __git "$rubybuilddir" \ + --source git://github.com/sstephenson/ruby-build.git \ + --state "$state_should" diff --git a/cdist/conf/type/__rbenv/parameter/optional b/cdist/conf/type/__rbenv/parameter/optional new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/cdist/conf/type/__rbenv/parameter/optional @@ -0,0 +1 @@ +state From ed7b6d1a68a68e9b12bb9740fc86842c167f21a7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Dec 2012 00:01:01 +0100 Subject: [PATCH 1895/4212] add linebreak, add broken require Signed-off-by: Nico Schottelius --- cdist/conf/type/__rbenv/manifest | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__rbenv/manifest b/cdist/conf/type/__rbenv/manifest index 2e8769a4..8f912861 100644 --- a/cdist/conf/type/__rbenv/manifest +++ b/cdist/conf/type/__rbenv/manifest @@ -26,9 +26,13 @@ state_should=present rbenvdir="$homedir/.rbenv" rubybuilddir="$rbenvdir/plugins/ruby-build" -__git "$rbenvdir" --source git://github.com/sstephenson/rbenv.git \ +__git "$rbenvdir" \ + --source git://github.com/sstephenson/rbenv.git \ + --owner "$__object_id" \ --state "$state_should" -require="__git/$rbendir" __git "$rubybuilddir" \ +#__git "$rubybuilddir" \ +require="__git/$rbenvdir" __git "$rubybuilddir" \ --source git://github.com/sstephenson/ruby-build.git \ + --owner "$__object_id" \ --state "$state_should" From 765c5bb50cd6cc13993e1f5a761eb31f851920b7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Dec 2012 13:43:18 -0800 Subject: [PATCH 1896/4212] insert date for 2.1.0 Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 4e0a5d99..d61af31e 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.1.0: +2.1.0: 2012-12-08 * Core: Ensure global explorers are executable * Core: Ensure type explorers are executable (Steven Armstrong) * New Type: __git From f64aaf74b7f17ea862ecf2787ebd61a5b8c4aec4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Dec 2012 13:44:02 -0800 Subject: [PATCH 1897/4212] +quotes Signed-off-by: Nico Schottelius --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index d6c9a172..572fb768 100755 --- a/build +++ b/build @@ -341,7 +341,7 @@ eof web) set -e - $0 web-doc + "$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 && From d12645f23041cc28bdc4cc53cbec5e945d1c6bb8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Dec 2012 13:53:11 -0800 Subject: [PATCH 1898/4212] not an Signed-off-by: Nico Schottelius --- docs/web/cdist/why.mdwn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web/cdist/why.mdwn b/docs/web/cdist/why.mdwn index 0fcdf5c5..6dcfd441 100644 --- a/docs/web/cdist/why.mdwn +++ b/docs/web/cdist/why.mdwn @@ -41,7 +41,7 @@ Cdist requires very litte on a target system. Even better, in almost all cases all dependencies are usually fulfilled. Cdist does not require an agent or a high level programming languages on the target host: it will run on any host that -has an **ssh server running** and a posix compatible shell +has a **ssh server running** and a posix compatible shell (**/bin/sh**). ## Push based distribution From dc41c7a9e6437dc71a88ea456311b8658e7c89a0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Dec 2012 14:08:01 -0800 Subject: [PATCH 1899/4212] reference the upgrade guide for 2.0 to 2.1 Signed-off-by: Nico Schottelius --- docs/web/cdist/update.mdwn | 2 + docs/web/cdist/update/2.0-to-2.1.mdwn | 118 ++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 docs/web/cdist/update/2.0-to-2.1.mdwn diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index a50e7224..a1120db0 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -24,6 +24,8 @@ To upgrade to the lastet version do ### Updating from 2.0 to 2.1 +Have a look at the upgrade guide for [[2.0 to 2.1|2.0-to-2.1]]. + * Type **\_\_package* and \_\_process** use --state **present** or **absent**. The states **removed/installed** and **stopped/running** have been removed. Support for the new states is already present in 2.0. diff --git a/docs/web/cdist/update/2.0-to-2.1.mdwn b/docs/web/cdist/update/2.0-to-2.1.mdwn new file mode 100644 index 00000000..6fb072b9 --- /dev/null +++ b/docs/web/cdist/update/2.0-to-2.1.mdwn @@ -0,0 +1,118 @@ +[[!meta title="Update Guide for 2.0 to 2.1"]] + +## Introduction + +When changing your installation from 2.0 to 2.1, there are +a lot of changes coming up. 2.1 is mainly a cleanup release, +which removes long time deprecated behaviour, but also makes +a lot of things more consistent and allows you to split off your types, +explorers and manifest to custom directories. + +This document will guide you to a successful update. + +## Preperation + +As for every software and system you use in production, you should first of +all make a backup of your data. To prevent any breakage, it is +recommended to create a new git branch to do the update on: + + % git checkout -b update_to_2.1 + +This also ensure that whenever you need to do a change in your +2.0 based tree, you can simply go back to that branch, apply the change +and configure your systems - independently of your update progress! + +Next fetch the latest upstream changes, I assume that +origin refers to one of the upstream mirrors (change origin if you use +another remote name for upstream cdist): + + % git fetch -v origin + +## Merge the changes + +Now try to merge upstream into the new branch. + + % git merge origin/2.1 + +Fix any conflicts that may have been occurred due to local changes +and then **git add** and *git commit** those changes. This should seldomly +occur and if, it's mostly for people hacking on the cdist core. + +## Move "conf" directory + +One of the biggest changes in cdist 2.1 is that you can have multiple +**conf** directories: Indeed, the new default behaviour of cdist is to +search for conf directories + + * below the python module (cdist/conf in the source tree or in the installed location) + * at ~/.cdist/ (on conf suffix there) + +So you can now choose, where to store your types. + +### Integrate your conf/ back into the tree + +If you choose to store your types together with the upstream types, +you can just move all your stuff below **cdist/conf**: + + % git mv conf/type/* cdist/conf/type + % git mv conf/manifest/* cdist/conf/manifest + % git mv conf/explorer/* cdist/conf/explorer + % git commit -m "Re-Integrate my conf directory into cdist 2.1 tree" + +### Move your conf/ directory to ~/.cdist + +If you want to store your site specific +configuration outside of the cdist tree, you +can move your conf/ directory to your homedirectory ($HOME) under ~/.cdist: + + % mv conf ~/.cdist + % git rm -r conf + % git commit -m "Move my conf directory to ~/.cdist" + +It it still recommended to use a version control system like git in it: + + % cd ~/.cdist + % git init + % git add . + % git commit -m "Create new git repository containing my cdist configuration" + +## Test the migration + +Some of the types shipped with upstream were changed, so you may want to test +the result by running cdist on one of your staging target hosts: + + % ./bin/cdist config -v staging-host + +All incompatibilities are listed on the [[cdist update page|software/cdist/update]], +so you can browse through the list and update your configuration. + +## Final Cleanups + +When everything is tested, there are some cleanups to be done to finalise the update. + +### When continuing to keep conf/ in the tree + +You can then merge back your changes into the master tree and continue to work +as normal. + +### When using ~/.cdist + +If you decided to move your site specific code to ~/.cdist, you can now switch your +**master** branch or version branch to upstream directly. Assumnig you are in the +cdist directory, having your previous branch checked out, you can create a clean +state using the following commands: + + % upstream_branch=2.1 + % current_branch=$(git rev-parse --abbrev-ref HEAD) + % git checkout -b archive_my_own_tree + % git branch -D "$current_branch" + % git checkout -b "$current_branch" "origin/$upstream_branch" + +Afther these commands, your previous main branch is accessible at +**archive_my_own_tree** and your branch is now tracking upstream. + +## Questions? Critics? Hint?? + +If you think this manual helped or misses some information, do not +hesitate to contact us on any of the usual ways (irc, mailinglist, +github issue tracker, ...). From 98e86ae345a65fbb8519aa2ca082818d8fd6ccac Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Dec 2012 14:15:03 -0800 Subject: [PATCH 1900/4212] update, not grade 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 a1120db0..e486dff9 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -24,7 +24,7 @@ To upgrade to the lastet version do ### Updating from 2.0 to 2.1 -Have a look at the upgrade guide for [[2.0 to 2.1|2.0-to-2.1]]. +Have a look at the update guide for [[2.0 to 2.1|2.0-to-2.1]]. * Type **\_\_package* and \_\_process** use --state **present** or **absent**. The states **removed/installed** and **stopped/running** have been removed. From dc277b10c7602b8f3460776708af49d59a930aae Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Dec 2012 14:15:28 -0800 Subject: [PATCH 1901/4212] -typo Signed-off-by: Nico Schottelius --- docs/web/cdist/update/2.0-to-2.1.mdwn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web/cdist/update/2.0-to-2.1.mdwn b/docs/web/cdist/update/2.0-to-2.1.mdwn index 6fb072b9..1d0037ab 100644 --- a/docs/web/cdist/update/2.0-to-2.1.mdwn +++ b/docs/web/cdist/update/2.0-to-2.1.mdwn @@ -111,7 +111,7 @@ state using the following commands: Afther these commands, your previous main branch is accessible at **archive_my_own_tree** and your branch is now tracking upstream. -## Questions? Critics? Hint?? +## Questions? Critics? Hints? If you think this manual helped or misses some information, do not hesitate to contact us on any of the usual ways (irc, mailinglist, From 55aad252001064f534d83aa4bb7e8674e16d5a61 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 9 Dec 2012 08:34:29 -0800 Subject: [PATCH 1902/4212] almost the eight Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index d61af31e..e7f77870 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.1.0: 2012-12-08 +2.1.0: 2012-12-09 * Core: Ensure global explorers are executable * Core: Ensure type explorers are executable (Steven Armstrong) * New Type: __git From 67c7351bec864fb65d294883698f2beb567fb02e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 9 Dec 2012 11:49:26 -0800 Subject: [PATCH 1903/4212] install the right package, not pyro... Signed-off-by: Nico Schottelius --- cdist/conf/type/__package_pip/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__package_pip/gencode-remote b/cdist/conf/type/__package_pip/gencode-remote index 3456ced2..ec1c89f8 100644 --- a/cdist/conf/type/__package_pip/gencode-remote +++ b/cdist/conf/type/__package_pip/gencode-remote @@ -46,10 +46,10 @@ fi case "$state_should" in present) - echo $pip install -q pyro + echo $pip install -q "$name" ;; absent) - echo $pip uninstall -q -y pyro + echo $pip uninstall -q -y "$name" ;; *) echo "Unknown state: $state_should" >&2 From e4c830ebca34555aa3e11b3fd1a32013458fb3e5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 9 Dec 2012 11:50:03 -0800 Subject: [PATCH 1904/4212] update changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index e7f77870..a255f42b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -16,6 +16,7 @@ Changelog * Type __jail: Change optional parameter "started" to boolean "stopped" parameter, change optional parameter "devfs-enable" to boolean "devfs-disable" parameter and change optional parameter "onboot" to boolean. + * Type __package_pip: Bugfix: Installeded the package, not pyro * Remove Type __ssh_authorized_key: Superseeded by __ssh_authorized_keys * Support for CDIST_PATH (Steven Armstrong) From 224157610597d657e769f1d65c08f3fa53d4f0bd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 9 Dec 2012 14:26:11 -0800 Subject: [PATCH 1905/4212] document $HOME/.cdist Signed-off-by: Nico Schottelius --- docs/man/cdist-reference.text.sh | 48 +++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 8e3f49a2..8d230028 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -59,62 +59,78 @@ cat << eof PATHS ----- -If not specified otherwise, all paths are relative to the checkout directory. +$HOME/.cdist:: + The standard cdist configuration directory relative to your home directory + This is usually the place you want to store your site specific configuration -conf/:: - Contains the (static) configuration like manifests, types and explorers. +cdist/conf/:: + The distribution configuration directory + This contains types and explorers to be used -conf/manifest/init:: +confdir:: + Cdist will use all available configuration directories and create + a temporary confdir containing links to the real configuration directories. + This way it is possible to merge configuration directories. + + By default it consists of everything in $HOME/.cdist and cdist/conf/. + + For more details see cdist(1) + +confdir/manifest/init:: This is the central entry point. It is an executable (+x bit set) shell script that can use values from the explorers to decide which configuration to create for the specified target host. Its intent is to used to define mapping from configurations to hosts. -conf/manifest/*:: +confdir/manifest/*:: All other files in this directory are not directly used by cdist, but you can seperate configuration mappings, if you have a lot of code in the conf/manifest/init file. This may also be helpful to have different admins maintain different groups of hosts. -conf/explorer/:: +confdir/explorer/:: Contains explorers to be run on the target hosts, see cdist-explorer(7). -conf/type/:: +confdir/type/:: Contains all available types, which are used to provide some kind of functionality. See cdist-type(7). -conf/type//:: +confdir/type//:: Home of the type . This directory is referenced by the variable __type (see below). -conf/type//man.text:: +confdir/type//man.text:: Manpage in Asciidoc format (required for inclusion into upstream) -conf/type//manifest:: +confdir/type//manifest:: Used to generate additional objects from a type. -conf/type//gencode-local:: +confdir/type//gencode-local:: Used to generate code to be executed on the source host -conf/type//gencode-remote:: +confdir/type//gencode-remote:: Used to generate code to be executed on the target host -conf/type//parameter/required:: +confdir/type//parameter/required:: Parameters required by type, \n seperated list. -conf/type//parameter/optional:: +confdir/type//parameter/optional:: Parameters optionally accepted by type, \n seperated list. -conf/type//parameter/boolean:: +confdir/type//parameter/boolean:: Boolean parameters accepted by type, \n seperated list. -conf/type//explorer:: +confdir/type//explorer:: Location of the type specific explorers. This directory is referenced by the variable __type_explorer (see below). See cdist-explorer(7). +confdir/type//files:: + This directory is reserved for user data and will not be used + by cdist at any time + out/:: This directory contains output of cdist and is usually located in a temporary directory and thus will be removed after the run. From dd9083327d8dfb298c3ad507190e70e15e19371c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 9 Dec 2012 14:41:50 -0800 Subject: [PATCH 1906/4212] update confdir paths Signed-off-by: Nico Schottelius --- docs/man/cdist-reference.text.sh | 4 ++-- docs/man/man1/cdist.text | 2 +- docs/man/man7/cdist-hacker.text | 2 +- docs/man/man7/cdist-manifest.text | 8 ++++---- docs/man/man7/cdist-type.text | 18 +++++++++--------- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 8d230028..d8c23a79 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -59,7 +59,7 @@ cat << eof PATHS ----- -$HOME/.cdist:: +\$HOME/.cdist:: The standard cdist configuration directory relative to your home directory This is usually the place you want to store your site specific configuration @@ -72,7 +72,7 @@ confdir:: a temporary confdir containing links to the real configuration directories. This way it is possible to merge configuration directories. - By default it consists of everything in $HOME/.cdist and cdist/conf/. + By default it consists of everything in \$HOME/.cdist and cdist/conf/. For more details see cdist(1) diff --git a/docs/man/man1/cdist.text b/docs/man/man1/cdist.text index c52e3696..113454a7 100644 --- a/docs/man/man1/cdist.text +++ b/docs/man/man1/cdist.text @@ -78,7 +78,7 @@ EXAMPLES # Configure ikq05.ethz.ch with debug enabled cdist config -d ikq05.ethz.ch -# Configure hosts in parallel and use a different home directory +# Configure hosts in parallel and use a different configuration directory cdist config -c ~/p/cdist-nutzung \ -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch diff --git a/docs/man/man7/cdist-hacker.text b/docs/man/man7/cdist-hacker.text index ee88ca29..d0f9a399 100644 --- a/docs/man/man7/cdist-hacker.text +++ b/docs/man/man7/cdist-hacker.text @@ -44,7 +44,7 @@ work nor kill the authors brain: - All files should contain the usual header (Author, Copying, etc.) - Code submission must be done via git -- Do not add conf/manifest/init - This file should only be touched in your +- Do not add cdist/conf/manifest/init - This file should only be touched in your private branch! - Code to be included should be branched of the upstream "master" branch - Exception: Bugfixes to a version branch diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index b9dfe655..19f6053e 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -16,8 +16,8 @@ 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***. -All available types can be found in the **conf/type/** directory, -use **ls conf/type** to get the list of available types. If you have +All available types can be found in the **cdist/conf/type/** directory, +use **ls cdist/conf/type** to get the list of available types. If you have setup the MANPATH correctly, you can use **man cdist-reference** to access the reference with pointers to the manpages. @@ -57,7 +57,7 @@ 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 **conf/manifest/init**. +Cdist searches for the initial manifest at **cdist/conf/manifest/init**. Within this initial manifest, you define, which objects should be created on which host. To distinguish between hosts, you can use the @@ -88,7 +88,7 @@ command. SPLITTING UP THE INITIAL MANIFEST --------------------------------- If you want to split up your initial manifest, you can create other shell -scripts in **conf/manifest/** and include them in **conf/manifest/init**. +scripts in **cdist/conf/manifest/** and include them in **cdist/conf/manifest/init**. Cdist provides the environment variable ***__manifest*** to reference to the directory containing the initial manifest (see cdist-reference(7)). diff --git a/docs/man/man7/cdist-type.text b/docs/man/man7/cdist-type.text index a5064f91..54b67be5 100644 --- a/docs/man/man7/cdist-type.text +++ b/docs/man/man7/cdist-type.text @@ -64,10 +64,10 @@ A type consists of - explorer (optional) - gencode (optional) -Types are stored below conf/type/. Their name should always be prefixed with +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 **conf/type/__NAME**. +To begin a new type, just create the directory **cdist/conf/type/__NAME**. DEFINING PARAMETERS @@ -84,10 +84,10 @@ or no parameters at all. Example: -------------------------------------------------------------------------------- -echo servername >> conf/type/__nginx_vhost/parameter/required -echo logdirectory >> conf/type/__nginx_vhost/parameter/optional -echo server_alias >> conf/type/__nginx_vhost/parameter/optional_multiple -echo use_ssl >> conf/type/__nginx_vhost/parameter/boolean +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 -------------------------------------------------------------------------------- @@ -98,7 +98,7 @@ The parameters given to a type can be accessed and used in all type scripts represented by file existence. File exists -> True, file does not exist -> False -Example: (e.g. in conf/type/__nginx_vhost/manifest) +Example: (e.g. in cdist/conf/type/__nginx_vhost/manifest) -------------------------------------------------------------------------------- # required parameter servername="$(cat "$__object/parameter/servername")" @@ -129,7 +129,7 @@ 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 conf/type/__archlinux_hostname) +Example use of a type: (e.g. in cdist/conf/type/__archlinux_hostname) -------------------------------------------------------------------------------- __file /etc/rc.conf --source - << eof ... @@ -186,7 +186,7 @@ mark it as a singleton: Just create the (empty) file "singleton" in your type directory: -------------------------------------------------------------------------------- -touch conf/type/__NAME/singleton +touch cdist/conf/type/__NAME/singleton -------------------------------------------------------------------------------- This will also change the way your type must be called: From d515f3dbe22d98bd9d41a735dc2067c9d2b06b11 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 9 Dec 2012 14:49:09 -0800 Subject: [PATCH 1907/4212] fix asciidoc formatting Signed-off-by: Nico Schottelius --- docs/man/cdist-reference.text.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index d8c23a79..006e5138 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -195,10 +195,8 @@ __object:: __object_id:: The type unique object id. Available for: type manifest, type explorer, type gencode - Note: The leading and the trailing "/" will always be stripped (caused by the filesystem database and ensured by the core). - Note: Double slashes ("//") will not be fixed and result in an error. __object_name:: The full qualified name of the current object. From 7abcd09fdd903c606fe2416931eaa74d1338e76e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 9 Dec 2012 14:55:38 -0800 Subject: [PATCH 1908/4212] -- lines Signed-off-by: Nico Schottelius --- docs/man/cdist-reference.text.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 006e5138..37b9d41b 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -71,9 +71,7 @@ confdir:: Cdist will use all available configuration directories and create a temporary confdir containing links to the real configuration directories. This way it is possible to merge configuration directories. - By default it consists of everything in \$HOME/.cdist and cdist/conf/. - For more details see cdist(1) confdir/manifest/init:: From 18a90eddeeedf163432886f349f4e08d4ca3b56d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 9 Dec 2012 14:56:25 -0800 Subject: [PATCH 1909/4212] and --more line Signed-off-by: Nico Schottelius --- docs/man/cdist-reference.text.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 37b9d41b..225d647f 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -96,7 +96,6 @@ confdir/type/:: confdir/type//:: Home of the type . - This directory is referenced by the variable __type (see below). confdir/type//man.text:: From 7d7ad2630c65a4bd0469807b688490fe57898174 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Tue, 11 Dec 2012 11:15:21 -0500 Subject: [PATCH 1910/4212] Fix issue #147 --state absent should imply --stopped. --- cdist/conf/type/__jail/gencode-remote | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/cdist/conf/type/__jail/gencode-remote b/cdist/conf/type/__jail/gencode-remote index 1f326bf1..7491754c 100755 --- a/cdist/conf/type/__jail/gencode-remote +++ b/cdist/conf/type/__jail/gencode-remote @@ -35,7 +35,8 @@ fi state="$(cat "$__object/parameter/state")" started="true" -[ -f "$__object/parameter/stopped" ] && started="false" +# If the user wants the jail gone, it implies it shouldn't be started. +[ -f "$__object/parameter/stopped" -o "$state" = "absent" ] && started="false" if [ -f "$__object/parameter/ip" ]; then ip="$(cat "$__object/parameter/ip")" @@ -92,14 +93,6 @@ fi present="$(cat "$__object/explorer/present")" status="$(cat "$__object/explorer/status")" -# Defining a jail as absent and started at the same time -# makes no sense. Treat this as an error. -if [ "$started" = "true" -a "$state" = "absent" ]; then - exec >&2 - echo "Can't have --state absent and --started true together\!" - exit 1 -fi - stopJail() { # Check $status before issuing command if [ "$status" = "STARTED" ]; then From 2e083db90ad0884392dbdce04442ff95022cf21d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Dec 2012 09:26:53 -0800 Subject: [PATCH 1911/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index a255f42b..319f7a38 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: + * Type __jail: State absent should implies stopped (Jake Guffey) + 2.1.0: 2012-12-09 * Core: Ensure global explorers are executable * Core: Ensure type explorers are executable (Steven Armstrong) From d289cc2d3e63ecd692f2f1e786bd9c58168df82e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Dec 2012 23:13:46 -0800 Subject: [PATCH 1912/4212] +solver that accepts __git behaviour :) Signed-off-by: Nico Schottelius --- docs/dev/logs/2012-12-11.dependencies | 72 +++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 docs/dev/logs/2012-12-11.dependencies diff --git a/docs/dev/logs/2012-12-11.dependencies b/docs/dev/logs/2012-12-11.dependencies new file mode 100644 index 00000000..e5506564 --- /dev/null +++ b/docs/dev/logs/2012-12-11.dependencies @@ -0,0 +1,72 @@ +2.1.0 behaviour: + + +__git foo + __package git --state present + +__git bar + __package git --state present + + +require="__git/foo" git bar: + + __git bar + __git foo + __package git --state present + __package git --state present + __git foo + __package git --state present + + -> detects circular dependency + + +-------------------------------------------------------------------------------- + +__package abc + __package_apt abc + +__sometype def + __package abc + __package_apt abc + + +-------------------------------------------------------------------------------- + +Change proposal: + +Each object only depends on the objects it directly requires, tree build to +ensure correct running behaviour: + + +__git bar + __git foo + __package git --state present + +__git foo + __package git --state present + +Order: + +1) + __package/git (leaf node!) + +2) + __git/foo (new leaf node!) + +3) + __git/bar (new leaf node!) + + +For __package: + +__sometype def + __package abc + +__package abc + __package_apt abc + +1) __package_apt/abc (leaf node) + +2) __package/abc (new leaf node) + +3) __sometype/def (new leaf node) From 2e81379c18a431aba1148e0e0e667e55ded6b03c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 13 Dec 2012 06:41:33 +0100 Subject: [PATCH 1913/4212] add very simple solver for dependencies Signed-off-by: Nico Schottelius --- cdist/config_install.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cdist/config_install.py b/cdist/config_install.py index 2c1edc44..8c99f8d9 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -139,6 +139,18 @@ class ConfigInstall(object): self.local.object_path, self.local.type_path) + all_resolved = False + while not all_resolved: + all_resolved = True + for cdist_object in objects: + if not cdist_object.state == cdist_object.STATE_DONE: + all_resolved = False + if cdist_object.satisfied_requirements: + self.object_run(cdist_object) + + + return + dependency_resolver = resolver.DependencyResolver(objects) self.log.debug(pprint.pformat(dependency_resolver.dependencies)) From 6b6037d9bbb68dad10d780e6a7d699734828d339 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 13 Dec 2012 06:44:55 +0100 Subject: [PATCH 1914/4212] todos for a simple resolver Signed-off-by: Nico Schottelius --- cdist/config_install.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cdist/config_install.py b/cdist/config_install.py index 8c99f8d9..cab09b91 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -139,6 +139,9 @@ class ConfigInstall(object): self.local.object_path, self.local.type_path) + # FIXME: + # - think about parallel execution (same for stage_prepare) + # - catch unresolvable trees all_resolved = False while not all_resolved: all_resolved = True From 16340b7d346b75ebde5feb9379c64553ae557d4e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Dec 2012 08:41:17 +0100 Subject: [PATCH 1915/4212] report on broken requirements, begin to satisfy requirements Signed-off-by: Nico Schottelius --- cdist/config_install.py | 18 ++++++++++++++++++ cdist/core/cdist_object.py | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/cdist/config_install.py b/cdist/config_install.py index cab09b91..6a0d5161 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -143,6 +143,7 @@ class ConfigInstall(object): # - think about parallel execution (same for stage_prepare) # - catch unresolvable trees all_resolved = False + objects_changed = False while not all_resolved: all_resolved = True for cdist_object in objects: @@ -150,6 +151,23 @@ class ConfigInstall(object): all_resolved = False if cdist_object.satisfied_requirements: self.object_run(cdist_object) + objects_changed = True + + # Reran, but no object was solved + if not objects_changed: + # Create list of unfinished objects + their requirements for print + + evil_objects = [] + for cdist_object in objects: + if not cdist_object.state == cdist_object.STATE_DONE: +# evil_objects.append({ name: cdist_object.name, +# requirements: cdist_object.requirements, +# autorequire: cdist_object.autorequire }) + evil_objects.append("%s (required: %s, autorequired: %s" % + (cdist_object.name, cdist_object.requirements, cdist_object.autorequire)) + + raise cdist.Error("Cannot solve requirements for the following objects: %s" % + (",".join(evil_objects))) return diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 90a21e59..cb34f521 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -209,3 +209,7 @@ class CdistObject(object): os.makedirs(absolute_parameter_path, exist_ok=False) except EnvironmentError as error: raise cdist.Error('Error creating directories for cdist object: %s: %s' % (self, error)) + + def satisfied_requirements(self): + + From 81c92e5cc43e551b6d22871aa2e6763b4e3904b2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Dec 2012 08:41:56 +0100 Subject: [PATCH 1916/4212] merge all resolver code into cdist_object (to gain the requirement searching code Signed-off-by: Nico Schottelius --- cdist/core/cdist_object.py | 169 +++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index cb34f521..1844aabf 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -213,3 +213,172 @@ class CdistObject(object): def satisfied_requirements(self): + +# -*- 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 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: + log.info("Resolving dependencies...") + self._dependencies = d = {} + self._preprocess_requirements() + for name,cdist_object in self.objects.items(): + resolved = [] + unresolved = [] + self._resolve_object_dependencies(cdist_object, resolved, unresolved) + d[name] = resolved + 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 cdist_object.requirements: + if requirement not in auto_requirement.requirements: + auto_requirement.requirements.append(requirement) + # 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: + raise CircularReferenceError(cdist_object, required_object) + 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 6a8778e59568947324a04b7449d2a4cb84178ef2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Dec 2012 08:43:52 +0100 Subject: [PATCH 1917/4212] remove most of the resolver boilerplate, keep the interesting functions Signed-off-by: Nico Schottelius --- cdist/core/cdist_object.py | 121 ++++++------------------------------- 1 file changed, 17 insertions(+), 104 deletions(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 1844aabf..fa358937 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -213,78 +213,6 @@ class CdistObject(object): def satisfied_requirements(self): - -# -*- 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 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. @@ -348,37 +276,22 @@ class DependencyResolver(object): # 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: - raise CircularReferenceError(cdist_object, required_object) - 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) +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 + + - 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 cd8b3cf68d3523bf4e732dc761481fcd110d077c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Dec 2012 12:47:13 +0100 Subject: [PATCH 1918/4212] finish rewrite of dependency resolver Signed-off-by: Nico Schottelius --- cdist/config_install.py | 3 -- cdist/core/cdist_object.py | 58 +++++++++++++------------------------- 2 files changed, 20 insertions(+), 41 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 6a0d5161..4d6c10f2 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -160,9 +160,6 @@ class ConfigInstall(object): evil_objects = [] for cdist_object in objects: if not cdist_object.state == cdist_object.STATE_DONE: -# evil_objects.append({ name: cdist_object.name, -# requirements: cdist_object.requirements, -# autorequire: cdist_object.autorequire }) evil_objects.append("%s (required: %s, autorequired: %s" % (cdist_object.name, cdist_object.requirements, cdist_object.autorequire)) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index fa358937..501c0fb3 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -211,25 +211,17 @@ class CdistObject(object): raise cdist.Error('Error creating directories for cdist object: %s: %s' % (self, error)) def satisfied_requirements(self): + """Return state whether all of our dependencies have been resolved already""" + satisfied = True - @property - def dependencies(self): - """Build the dependency graph. + for requirement in self.all_requirements(): + if not requirement.state == self.STATE_DONE: + satisfied = False + break + + return satisfied - 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: - log.info("Resolving dependencies...") - self._dependencies = d = {} - self._preprocess_requirements() - for name,cdist_object in self.objects.items(): - resolved = [] - unresolved = [] - self._resolve_object_dependencies(cdist_object, resolved, unresolved) - d[name] = resolved - return self._dependencies def find_requirements_by_name(self, requirements): """Takes a list of requirement patterns and returns a list of matching object instances. @@ -239,7 +231,8 @@ class CdistObject(object): find_requirements_by_name(['__type/object_id', '__other_type/*']) -> [, , ] """ - object_names = self.objects.keys() + + object_names = self.list_object_namess(self.base_path) for pattern in requirements: found = False for requirement in fnmatch.filter(object_names, pattern): @@ -253,28 +246,17 @@ class CdistObject(object): else: raise RequirementNotFoundError(pattern) - def _preprocess_requirements(self): - """Find all autorequire dependencies and merge them to be just requirements - for further processing. + def all_requirements(self): """ - 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 cdist_object.requirements: - if requirement not in auto_requirement.requirements: - auto_requirement.requirements.append(requirement) - # 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 = [] + Return resolved autorequirements and requirements so that + a complete list of requirements is returned + """ + + all_requirements = [] + all_requirements.extend(self.find_requirements_by_name(self.requirements)) + all_requirements.extend(self.find_requirements_by_name(self.autorequire)) + + return unique(all_requirements) class CircularReferenceError(cdist.Error): From 442dc767dd245631c0a09da9da775c232b378c1e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Dec 2012 12:55:36 +0100 Subject: [PATCH 1919/4212] merge resolver test into object test - because object requirement solving is implemented Signed-off-by: Nico Schottelius --- cdist/test/object/__init__.py | 91 +++++++++++++++++++++++++++++++++ cdist/test/resolver/__init__.py | 88 ------------------------------- 2 files changed, 91 insertions(+), 88 deletions(-) delete mode 100644 cdist/test/resolver/__init__.py diff --git a/cdist/test/object/__init__.py b/cdist/test/object/__init__.py index 3a91f709..2612f060 100644 --- a/cdist/test/object/__init__.py +++ b/cdist/test/object/__init__.py @@ -200,3 +200,94 @@ 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') + + +# -*- 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 + +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) + + # Create a test object with requirements + self.test_object = core.CdistObject(cdist_type, base_path, object_id=None) + + 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 diff --git a/cdist/test/resolver/__init__.py b/cdist/test/resolver/__init__.py deleted file mode 100644 index baae26de..00000000 --- a/cdist/test/resolver/__init__.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- 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 958d2d336f4fb17e3033e06473ca67ec847e3728 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Dec 2012 17:16:26 +0100 Subject: [PATCH 1920/4212] various cleanups Signed-off-by: Nico Schottelius --- cdist/core/cdist_object.py | 35 ++++++++++------------ cdist/core/cdist_type.py | 40 ++++++++++++------------- cdist/test/object/__init__.py | 56 ++++++----------------------------- 3 files changed, 45 insertions(+), 86 deletions(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 501c0fb3..7d757e67 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -56,6 +56,21 @@ class CdistObject(object): STATE_RUNNING = "running" STATE_DONE = "done" + def __init__(self, cdist_type, base_path, object_id=None): + self.cdist_type = cdist_type # instance of Type + self.base_path = base_path + self.object_id = object_id + + self.validate_object_id() + self.sanitise_object_id() + + self.name = self.join_name(self.cdist_type.name, self.object_id) + self.path = os.path.join(self.cdist_type.path, self.object_id, OBJECT_MARKER) + self.absolute_path = os.path.join(self.base_path, self.path) + self.code_local_path = os.path.join(self.path, "code-local") + self.code_remote_path = os.path.join(self.path, "code-remote") + self.parameter_path = os.path.join(self.path, "parameter") + @classmethod def list_objects(cls, object_base_path, type_base_path): """Return a list of object instances""" @@ -112,21 +127,6 @@ class CdistObject(object): raise IllegalObjectIdError(self.object_id, "Missing object_id and type is not a singleton.") - def __init__(self, cdist_type, base_path, object_id=None): - self.cdist_type = cdist_type # instance of Type - self.base_path = base_path - self.object_id = object_id - - self.validate_object_id() - self.sanitise_object_id() - - self.name = self.join_name(self.cdist_type.name, self.object_id) - self.path = os.path.join(self.cdist_type.path, self.object_id, OBJECT_MARKER) - self.absolute_path = os.path.join(self.base_path, self.path) - self.code_local_path = os.path.join(self.path, "code-local") - self.code_remote_path = os.path.join(self.path, "code-remote") - self.parameter_path = os.path.join(self.path, "parameter") - def object_from_name(self, object_name): """Convenience method for creating an object instance from an object name. @@ -232,7 +232,7 @@ class CdistObject(object): [, , ] """ - object_names = self.list_object_namess(self.base_path) + object_names = self.list_object_names(self.base_path) for pattern in requirements: found = False for requirement in fnmatch.filter(object_names, pattern): @@ -274,6 +274,3 @@ class RequirementNotFoundError(cdist.Error): def __str__(self): return 'Requirement could not be found: %s' % self.requirement - - - diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index 44e192fc..0efb10f4 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -42,6 +42,26 @@ class CdistType(object): """ + def __init__(self, base_path, name): + self.base_path = base_path + self.name = name + self.path = self.name + self.absolute_path = os.path.join(self.base_path, self.path) + if not os.path.isdir(self.absolute_path): + raise NoSuchTypeError(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") + self.gencode_remote_path = os.path.join(self.name, "gencode-remote") + self.manifest_path = os.path.join(self.name, "manifest") + + self.__explorers = None + self.__required_parameters = None + self.__required_multiple_parameters = None + self.__optional_parameters = None + self.__optional_multiple_parameters = None + self.__boolean_parameters = None + @classmethod def list_types(cls, base_path): """Return a list of type instances""" @@ -65,26 +85,6 @@ class CdistType(object): # return instance so __init__ is called return cls._instances[name] - def __init__(self, base_path, name): - self.base_path = base_path - self.name = name - self.path = self.name - self.absolute_path = os.path.join(self.base_path, self.path) - if not os.path.isdir(self.absolute_path): - raise NoSuchTypeError(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") - self.gencode_remote_path = os.path.join(self.name, "gencode-remote") - self.manifest_path = os.path.join(self.name, "manifest") - - self.__explorers = None - self.__required_parameters = None - self.__required_multiple_parameters = None - self.__optional_parameters = None - self.__optional_multiple_parameters = None - self.__boolean_parameters = None - def __repr__(self): return '' % self.name diff --git a/cdist/test/object/__init__.py b/cdist/test/object/__init__.py index 2612f060..531300a7 100644 --- a/cdist/test/object/__init__.py +++ b/cdist/test/object/__init__.py @@ -1,6 +1,7 @@ # -*- 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. # @@ -202,56 +203,24 @@ class ObjectTestCase(test.CdistTestCase): self.assertEqual(other_object.object_id, 'man') -# -*- 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 - -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): +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) - # Create a test object with requirements - self.test_object = core.CdistObject(cdist_type, base_path, object_id=None) + 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""" 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)) @@ -278,16 +247,9 @@ class ResolverTestCase(test.CdistTestCase): [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 + with self.assertRaises(core.cdist_object.RequirementNotFoundError): + first_man.find_requirements_by_name(first_man.requirements) + From 4faec434936ce21e6b7a4662fa3b3efa49d83a4f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Dec 2012 17:37:07 +0100 Subject: [PATCH 1921/4212] cleanup: remove call to old resolver Signed-off-by: Nico Schottelius --- cdist/config_install.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 4d6c10f2..d6628cc2 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -145,6 +145,10 @@ class ConfigInstall(object): all_resolved = False objects_changed = False while not all_resolved: + + object_state_list=' '.join('%s:%s:%s' % (o, o.state, o.all_requirements()) for o in objects) + self.log.debug("Object state (name:state:requirements): %s" % object_state_list) + all_resolved = True for cdist_object in objects: if not cdist_object.state == cdist_object.STATE_DONE: @@ -165,13 +169,3 @@ class ConfigInstall(object): raise cdist.Error("Cannot solve requirements for the following objects: %s" % (",".join(evil_objects))) - - - return - - 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 8031c7770041cff1be74655cec0745af5cdba480 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Dec 2012 18:21:51 +0100 Subject: [PATCH 1922/4212] fix some tests, break some others :-) Signed-off-by: Nico Schottelius --- cdist/core/cdist_object.py | 19 +++++-- cdist/test/object/__init__.py | 57 ++++++++++++------- .../object/__first/child/.cdist/.keep | 0 .../fixtures/object/__first/dog/.cdist/.keep | 0 .../object/__first/woman/.cdist/.keep | 0 .../object/__second/under-the/.cdist/.keep | 0 6 files changed, 52 insertions(+), 24 deletions(-) create mode 100644 cdist/test/object/fixtures/object/__first/child/.cdist/.keep create mode 100644 cdist/test/object/fixtures/object/__first/dog/.cdist/.keep create mode 100644 cdist/test/object/fixtures/object/__first/woman/.cdist/.keep create mode 100644 cdist/test/object/fixtures/object/__second/under-the/.cdist/.keep diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 7d757e67..3e5e33b7 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -20,6 +20,7 @@ # # +import fnmatch import logging import os import collections @@ -232,11 +233,19 @@ class CdistObject(object): [, , ] """ - object_names = self.list_object_names(self.base_path) + + # FIXME: think about where 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() + + print("a:%s" % self.objects) + print("b:%s" % object_names) + for pattern in requirements: found = False for requirement in fnmatch.filter(object_names, pattern): found = True + print("c:%s" % self.objects[requirement]) 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 @@ -252,11 +261,11 @@ class CdistObject(object): a complete list of requirements is returned """ - all_requirements = [] - all_requirements.extend(self.find_requirements_by_name(self.requirements)) - all_requirements.extend(self.find_requirements_by_name(self.autorequire)) + all_reqs= [] + all_reqs.extend(self.find_requirements_by_name(self.requirements)) + all_reqs.extend(self.find_requirements_by_name(self.autorequire)) - return unique(all_requirements) + return set(all_reqs) class CircularReferenceError(cdist.Error): diff --git a/cdist/test/object/__init__.py b/cdist/test/object/__init__.py index 531300a7..ec6e25c1 100644 --- a/cdist/test/object/__init__.py +++ b/cdist/test/object/__init__.py @@ -37,8 +37,16 @@ type_base_path = op.join(fixtures, 'type') class ObjectClassTestCase(test.CdistTestCase): def test_list_object_names(self): - object_names = list(core.CdistObject.list_object_names(object_base_path)) - self.assertEqual(object_names, ['__first/man', '__second/on-the', '__third/moon']) + found_object_names = sorted(list(core.CdistObject.list_object_names(object_base_path))) + expected_object_names = sorted([ + '__first/child', + '__first/dog', + '__first/man', + '__first/woman', + '__second/on-the', + '__second/under-the', + '__third/moon']) + self.assertEqual(found_object_names, expected_object_names) def test_list_type_names(self): type_names = list(cdist.core.CdistObject.list_type_names(object_base_path)) @@ -209,6 +217,9 @@ 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') @@ -218,23 +229,28 @@ class ObjectResolveRequirementsTestCase(test.CdistTestCase): o.requirements = [] def test_find_requirements_by_name_string(self): - """Check that resolving requirements by name works""" - requirements = ['__first/man', '__second/on-the', '__third/moon'] + """Check that resolving requirements by name works (require all objects)""" + requirements = self.object_names - 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.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'] - 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.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_dependency_resolution(self): first_man = self.object_index['__first/man'] @@ -242,10 +258,13 @@ class ObjectResolveRequirementsTestCase(test.CdistTestCase): 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] - ) + + # FIXME :-) + self.assertTrue(False) +# self.assertEqual( +# self.dependency_resolver.dependencies['__first/man'], +# [third_moon, second_on_the, first_man] +# ) def test_requirement_not_found(self): first_man = self.object_index['__first/man'] diff --git a/cdist/test/object/fixtures/object/__first/child/.cdist/.keep b/cdist/test/object/fixtures/object/__first/child/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/object/fixtures/object/__first/dog/.cdist/.keep b/cdist/test/object/fixtures/object/__first/dog/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/object/fixtures/object/__first/woman/.cdist/.keep b/cdist/test/object/fixtures/object/__first/woman/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/object/fixtures/object/__second/under-the/.cdist/.keep b/cdist/test/object/fixtures/object/__second/under-the/.cdist/.keep new file mode 100644 index 00000000..e69de29b From 369305f37643c1d26cf7b0551e83a99f033796ad Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Dec 2012 15:33:41 +0100 Subject: [PATCH 1923/4212] remove circularreferenceerror, because it is not being used anymore Signed-off-by: Nico Schottelius --- cdist/core/cdist_object.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 3e5e33b7..cc9aeaa5 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -234,18 +234,14 @@ class CdistObject(object): """ - # FIXME: think about where to store this - probably not here + # 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() - print("a:%s" % self.objects) - print("b:%s" % object_names) - for pattern in requirements: found = False for requirement in fnmatch.filter(object_names, pattern): found = True - print("c:%s" % self.objects[requirement]) 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 @@ -268,15 +264,6 @@ class CdistObject(object): return set(all_reqs) -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 From eb93d1bebd0a410970d6c161c0cd565e9ef2f29d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Dec 2012 15:33:50 +0100 Subject: [PATCH 1924/4212] begin tests for config_install Signed-off-by: Nico Schottelius --- cdist/test/config_install/__init__.py | 93 +++++++++++++++++++ .../fixtures/object/__first/.keep | 0 .../object/__first/child/.cdist/.keep | 0 .../fixtures/object/__first/dog/.cdist/.keep | 0 .../fixtures/object/__first/man/.cdist/.keep | 0 .../object/__first/woman/.cdist/.keep | 0 .../fixtures/object/__second/.keep | 0 .../object/__second/on-the/.cdist/.keep | 0 .../object/__second/under-the/.cdist/.keep | 0 .../fixtures/object/__third/.keep | 0 .../fixtures/object/__third/moon/.cdist/.keep | 0 .../object/__third/moon/.cdist/parameter/name | 1 + .../__third/moon/.cdist/parameter/planet | 1 + .../fixtures/type/__first/.keep | 0 .../fixtures/type/__second/.keep | 0 .../fixtures/type/__third/.keep | 0 16 files changed, 95 insertions(+) create mode 100644 cdist/test/config_install/__init__.py create mode 100644 cdist/test/config_install/fixtures/object/__first/.keep create mode 100644 cdist/test/config_install/fixtures/object/__first/child/.cdist/.keep create mode 100644 cdist/test/config_install/fixtures/object/__first/dog/.cdist/.keep create mode 100644 cdist/test/config_install/fixtures/object/__first/man/.cdist/.keep create mode 100644 cdist/test/config_install/fixtures/object/__first/woman/.cdist/.keep create mode 100644 cdist/test/config_install/fixtures/object/__second/.keep create mode 100644 cdist/test/config_install/fixtures/object/__second/on-the/.cdist/.keep create mode 100644 cdist/test/config_install/fixtures/object/__second/under-the/.cdist/.keep create mode 100644 cdist/test/config_install/fixtures/object/__third/.keep create mode 100644 cdist/test/config_install/fixtures/object/__third/moon/.cdist/.keep create mode 100644 cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/name create mode 100644 cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/planet create mode 100644 cdist/test/config_install/fixtures/type/__first/.keep create mode 100644 cdist/test/config_install/fixtures/type/__second/.keep create mode 100644 cdist/test/config_install/fixtures/type/__third/.keep diff --git a/cdist/test/config_install/__init__.py b/cdist/test/config_install/__init__.py new file mode 100644 index 00000000..326632b7 --- /dev/null +++ b/cdist/test/config_install/__init__.py @@ -0,0 +1,93 @@ +# -*- 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 + +from cdist import test +from cdist import core + +import cdist +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 ConfigInstallRunTestCase(test.CdistTestCase): + + def setUp(self): + + self.context = cdist.context.Context( + target_host=self.target_host, + remote_copy=self.remote_copy, + remote_exec=self.remote_exec, + initial_manifest=args.manifest, + add_conf_dirs=add_conf_dir, + exec_path=test.cdist_exec_path, + debug=False) + + self.config = config.Config(self.context) + + 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_dependency_resolution(self): + first = self.object_index['__first/man'] + second = self.object_index['__second/on-the'] + third = self.object_index['__third/moon'] + + first.requirements = [second.name] + second.requirements = [third.name] + + self.config.stage_run_prepare() + + # First run: + # solves first and maybe second (depending on the order in the set) + self.config.stage_run_iterate() + + # FIXME :-) + self.assertTrue(False) +# self.assertEqual( +# self.dependency_resolver.dependencies['__first/man'], +# [third_moon, second_on_the, first_man] +# ) + + def test_requirement_not_found(self): + first_man = self.object_index['__first/man'] + first_man.requirements = ['__does/not/exist'] + with self.assertRaises(core.cdist_object.RequirementNotFoundError): + first_man.find_requirements_by_name(first_man.requirements) diff --git a/cdist/test/config_install/fixtures/object/__first/.keep b/cdist/test/config_install/fixtures/object/__first/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config_install/fixtures/object/__first/child/.cdist/.keep b/cdist/test/config_install/fixtures/object/__first/child/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config_install/fixtures/object/__first/dog/.cdist/.keep b/cdist/test/config_install/fixtures/object/__first/dog/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config_install/fixtures/object/__first/man/.cdist/.keep b/cdist/test/config_install/fixtures/object/__first/man/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config_install/fixtures/object/__first/woman/.cdist/.keep b/cdist/test/config_install/fixtures/object/__first/woman/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config_install/fixtures/object/__second/.keep b/cdist/test/config_install/fixtures/object/__second/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config_install/fixtures/object/__second/on-the/.cdist/.keep b/cdist/test/config_install/fixtures/object/__second/on-the/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config_install/fixtures/object/__second/under-the/.cdist/.keep b/cdist/test/config_install/fixtures/object/__second/under-the/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config_install/fixtures/object/__third/.keep b/cdist/test/config_install/fixtures/object/__third/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config_install/fixtures/object/__third/moon/.cdist/.keep b/cdist/test/config_install/fixtures/object/__third/moon/.cdist/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/name b/cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/name new file mode 100644 index 00000000..4129a761 --- /dev/null +++ b/cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/name @@ -0,0 +1 @@ +Prometheus diff --git a/cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/planet b/cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/planet new file mode 100644 index 00000000..8e6ee422 --- /dev/null +++ b/cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/planet @@ -0,0 +1 @@ +Saturn diff --git a/cdist/test/config_install/fixtures/type/__first/.keep b/cdist/test/config_install/fixtures/type/__first/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config_install/fixtures/type/__second/.keep b/cdist/test/config_install/fixtures/type/__second/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config_install/fixtures/type/__third/.keep b/cdist/test/config_install/fixtures/type/__third/.keep new file mode 100644 index 00000000..e69de29b From c2705380727b0d341a680e6b510246622cb5b33a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Dec 2012 19:36:00 +0100 Subject: [PATCH 1925/4212] add dry_run option to object_run Signed-off-by: Nico Schottelius --- cdist/config_install.py | 90 +++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index d6628cc2..b7662ad8 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -104,11 +104,10 @@ class ConfigInstall(object): self.manifest.run_type_manifest(cdist_object) cdist_object.state = core.CdistObject.STATE_PREPARED - def object_run(self, cdist_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 cdist_object.state == core.CdistObject.STATE_DONE: - # TODO: remove once we are sure that this really never happens. raise cdist.Error("Attempting to run an already finished object: %s", cdist_object) cdist_type = cdist_object.cdist_type @@ -121,51 +120,74 @@ class ConfigInstall(object): cdist_object.changed = True # Execute - 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) + 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_prepare(self): + """Prepare the run stage""" + + self.objects = core.CdistObject.list_objects( + self.local.object_path, + self.local.type_path) + + self.all_resolved = False + self.objects_changed = False + + print("srp: %s - %s objects: %s" % (self.local.object_path, self.local.type_path, list(self.objects))) + def stage_run(self): """The final (and real) step of deployment""" self.log.info("Generating and executing code") - - objects = core.CdistObject.list_objects( - self.local.object_path, - self.local.type_path) + self.stage_run_prepare() # FIXME: # - think about parallel execution (same for stage_prepare) # - catch unresolvable trees - all_resolved = False - objects_changed = False - while not all_resolved: + while not self.all_resolved: + self.stage_run_iterate() - object_state_list=' '.join('%s:%s:%s' % (o, o.state, o.all_requirements()) for o in objects) - self.log.debug("Object state (name:state:requirements): %s" % object_state_list) + def stage_run_iterate(self): + logging.root.setLevel(logging.DEBUG) + """ + Run one iteration of the run - all_resolved = True - for cdist_object in objects: + To be repeated until all objects are done + """ + + object_state_list=' '.join('%s:%s:%s' % (o, o.state, o.all_requirements()) for o in self.objects) + self.log.debug("Object state (name:state:requirements): %s" % object_state_list) + print("Object state (name:state:requirements): %s" % object_state_list) + + self.all_resolved = True + for cdist_object in self.objects: + if not cdist_object.state == cdist_object.STATE_DONE: + self.all_resolved = False + if cdist_object.satisfied_requirements: + self.object_run(cdist_object) + self.objects_changed = True + + # Not all are resolved, but nothing has been changed => bad dependencies! + if not self.objects_changed and not self.all_resolved: + # Create list of unfinished objects + their requirements for print + + evil_objects = [] + good_objects = [] + for cdist_object in self.objects: if not cdist_object.state == cdist_object.STATE_DONE: - all_resolved = False - if cdist_object.satisfied_requirements: - self.object_run(cdist_object) - objects_changed = True + 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)) - # Reran, but no object was solved - if not objects_changed: - # Create list of unfinished objects + their requirements for print - - evil_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)) - - raise cdist.Error("Cannot solve requirements for the following objects: %s" % - (",".join(evil_objects))) + errormessage = "Cannot solve requirements for the following objects: %s - solved: %s" % (",".join(evil_objects), ",".join(good_objects)) + raise cdist.Error(errormessage) From 4fd27e76a7ca4aea212097e4bdb6a12bded8ce0a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Dec 2012 19:37:43 +0100 Subject: [PATCH 1926/4212] support dry_run in stage_run_iterate as well Signed-off-by: Nico Schottelius --- cdist/config_install.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index b7662ad8..9de5ecb8 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -56,6 +56,9 @@ class ConfigInstall(object): self.manifest = core.Manifest(self.context.target_host, self.local) self.code = core.Code(self.context.target_host, self.local, self.remote) + # Add switch to disable code execution + self.dry_run = False + def cleanup(self): # FIXME: move to local? destination = os.path.join(self.local.cache_path, self.context.target_host) @@ -171,7 +174,7 @@ class ConfigInstall(object): if not cdist_object.state == cdist_object.STATE_DONE: self.all_resolved = False if cdist_object.satisfied_requirements: - self.object_run(cdist_object) + self.object_run(cdist_object, self.dry_run) self.objects_changed = True # Not all are resolved, but nothing has been changed => bad dependencies! From 527ec0889bb64ce3977df908cf89d7319cadd4ab Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Dec 2012 20:53:38 +0100 Subject: [PATCH 1927/4212] remove unneeded fixtures Signed-off-by: Nico Schottelius --- .../config_install/fixtures/object/__first/child/.cdist/.keep | 0 .../test/config_install/fixtures/object/__first/dog/.cdist/.keep | 0 .../config_install/fixtures/object/__first/woman/.cdist/.keep | 0 .../fixtures/object/__second/under-the/.cdist/.keep | 0 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 cdist/test/config_install/fixtures/object/__first/child/.cdist/.keep delete mode 100644 cdist/test/config_install/fixtures/object/__first/dog/.cdist/.keep delete mode 100644 cdist/test/config_install/fixtures/object/__first/woman/.cdist/.keep delete mode 100644 cdist/test/config_install/fixtures/object/__second/under-the/.cdist/.keep diff --git a/cdist/test/config_install/fixtures/object/__first/child/.cdist/.keep b/cdist/test/config_install/fixtures/object/__first/child/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/config_install/fixtures/object/__first/dog/.cdist/.keep b/cdist/test/config_install/fixtures/object/__first/dog/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/config_install/fixtures/object/__first/woman/.cdist/.keep b/cdist/test/config_install/fixtures/object/__first/woman/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/config_install/fixtures/object/__second/under-the/.cdist/.keep b/cdist/test/config_install/fixtures/object/__second/under-the/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 From 2732a4ba5c3ea75fccb7aa833b6799d021255140 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Dec 2012 21:10:18 +0100 Subject: [PATCH 1928/4212] finally finish the dynamic resolver Signed-off-by: Nico Schottelius --- cdist/config_install.py | 64 ++++++++------------- cdist/core/cdist_object.py | 6 +- cdist/test/config_install/__init__.py | 82 ++++++++++++++++++++------- cdist/test/object/__init__.py | 25 ++++---- 4 files changed, 105 insertions(+), 72 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 9de5ecb8..f1529cc1 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -43,29 +43,25 @@ class ConfigInstall(object): self.context = context self.log = logging.getLogger(self.context.target_host) - # For easy access - self.local = context.local - self.remote = context.remote - # Initialise local directory structure - self.local.create_files_dirs() + self.context.local.create_files_dirs() # Initialise remote directory structure - self.remote.create_files_dirs() + self.context.remote.create_files_dirs() - self.explorer = core.Explorer(self.context.target_host, self.local, self.remote) - self.manifest = core.Manifest(self.context.target_host, self.local) - self.code = core.Code(self.context.target_host, self.local, self.remote) + 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 def cleanup(self): # FIXME: move to local? - destination = os.path.join(self.local.cache_path, self.context.target_host) - self.log.debug("Saving " + self.local.out_path + " to " + destination) + 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.local.out_path, destination) + shutil.move(self.context.local.out_path, destination) def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" @@ -82,7 +78,7 @@ class ConfigInstall(object): def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" - self.explorer.run_global_explorers(self.local.global_explorer_out_path) + 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") @@ -91,8 +87,8 @@ class ConfigInstall(object): new_objects_created = True while new_objects_created: new_objects_created = False - for cdist_object in core.CdistObject.list_objects(self.local.object_path, - self.local.type_path): + 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 @@ -134,56 +130,46 @@ class ConfigInstall(object): self.log.debug("Finishing run of " + cdist_object.name) cdist_object.state = core.CdistObject.STATE_DONE - def stage_run_prepare(self): - """Prepare the run stage""" - - self.objects = core.CdistObject.list_objects( - self.local.object_path, - self.local.type_path) - - self.all_resolved = False - self.objects_changed = False - - print("srp: %s - %s objects: %s" % (self.local.object_path, self.local.type_path, list(self.objects))) - def stage_run(self): """The final (and real) step of deployment""" self.log.info("Generating and executing code") - self.stage_run_prepare() - # FIXME: - # - think about parallel execution (same for stage_prepare) - # - catch unresolvable trees + # FIXME: think about parallel execution (same for stage_prepare) + self.all_resolved = False while not self.all_resolved: self.stage_run_iterate() def stage_run_iterate(self): - logging.root.setLevel(logging.DEBUG) """ Run one iteration of the run 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) - object_state_list=' '.join('%s:%s:%s' % (o, o.state, o.all_requirements()) for o in self.objects) - self.log.debug("Object state (name:state:requirements): %s" % object_state_list) - print("Object state (name:state:requirements): %s" % object_state_list) + self.log.debug("Object state (name:state:requirements:satisfied): %s" % object_state_list) + objects_changed = False self.all_resolved = True - for cdist_object in self.objects: + 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) - self.objects_changed = True + 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 self.objects_changed and not self.all_resolved: + 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 self.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)) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index cc9aeaa5..7beea130 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -211,15 +211,18 @@ class CdistObject(object): except EnvironmentError as error: raise cdist.Error('Error creating directories for cdist object: %s: %s' % (self, error)) + @property def satisfied_requirements(self): """Return state whether all of our dependencies have been resolved already""" satisfied = True - for requirement in self.all_requirements(): + 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 @@ -251,6 +254,7 @@ class CdistObject(object): else: raise RequirementNotFoundError(pattern) + @property def all_requirements(self): """ Return resolved autorequirements and requirements so that diff --git a/cdist/test/config_install/__init__.py b/cdist/test/config_install/__init__.py index 326632b7..2a05d4c5 100644 --- a/cdist/test/config_install/__init__.py +++ b/cdist/test/config_install/__init__.py @@ -28,6 +28,7 @@ from cdist import core import cdist import cdist.context +import cdist.config import os.path as op my_dir = op.abspath(op.dirname(__file__)) @@ -40,30 +41,40 @@ class ConfigInstallRunTestCase(test.CdistTestCase): def setUp(self): + # Change env for context + 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, - initial_manifest=args.manifest, - add_conf_dirs=add_conf_dir, exec_path=test.cdist_exec_path, - debug=False) + debug=True) - self.config = config.Config(self.context) + self.context.local.object_path = object_base_path + self.context.local.type_path = type_base_path + + self.config = cdist.config.Config(self.context) - 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 = [] + o.state = "" + + os.environ = self.orig_environ + shutil.rmtree(self.temp_dir) def test_dependency_resolution(self): first = self.object_index['__first/man'] @@ -73,21 +84,50 @@ class ConfigInstallRunTestCase(test.CdistTestCase): first.requirements = [second.name] second.requirements = [third.name] - self.config.stage_run_prepare() - # First run: # solves first and maybe second (depending on the order in the set) self.config.stage_run_iterate() + self.assertTrue(third.state == third.STATE_DONE) - # FIXME :-) - self.assertTrue(False) -# self.assertEqual( -# self.dependency_resolver.dependencies['__first/man'], -# [third_moon, second_on_the, first_man] -# ) + self.config.stage_run_iterate() + self.assertTrue(second.state == second.STATE_DONE) + + + try: + self.config.stage_run_iterate() + except cdist.Error: + # Allow failing, because the third run may or may not be unecessary already, + # depending on the order of the objects + pass + self.assertTrue(first.state == first.STATE_DONE) + + + def test_non_empty_object_list(self): + """Ensure the object list returned is not empty""" + pass def test_requirement_not_found(self): - first_man = self.object_index['__first/man'] - first_man.requirements = ['__does/not/exist'] + """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): - first_man.find_requirements_by_name(first_man.requirements) + # Use list, as generator does not (yet) raise the error + list(cdist_object.find_requirements_by_name(cdist_object.requirements)) + + def test_unresolvable_requirements(self): + """Ensure an exception is thrown for unresolvable depedencies""" + + # Create to objects depending on each other - no solution possible + first = self.object_index['__first/man'] + second = self.object_index['__second/on-the'] + + first.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() diff --git a/cdist/test/object/__init__.py b/cdist/test/object/__init__.py index ec6e25c1..f3a526aa 100644 --- a/cdist/test/object/__init__.py +++ b/cdist/test/object/__init__.py @@ -36,9 +36,8 @@ type_base_path = op.join(fixtures, 'type') class ObjectClassTestCase(test.CdistTestCase): - def test_list_object_names(self): - found_object_names = sorted(list(core.CdistObject.list_object_names(object_base_path))) - expected_object_names = sorted([ + def setUp(self): + self.expected_object_names = sorted([ '__first/child', '__first/dog', '__first/man', @@ -46,20 +45,24 @@ class ObjectClassTestCase(test.CdistTestCase): '__second/on-the', '__second/under-the', '__third/moon']) - self.assertEqual(found_object_names, expected_object_names) + + self.expected_objects = [] + for cdist_object_name in self.expected_object_names: + cdist_type, cdist_object_id = cdist_object_name.split("/", maxsplit=1) + cdist_object = core.CdistObject(core.CdistType(type_base_path, cdist_type), object_base_path, cdist_object_id) + self.expected_objects.append(cdist_object) + + def test_list_object_names(self): + found_object_names = sorted(list(core.CdistObject.list_object_names(object_base_path))) + self.assertEqual(found_object_names, self.expected_object_names) 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']) def test_list_objects(self): - objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) - objects_expected = [ - core.CdistObject(core.CdistType(type_base_path, '__first'), object_base_path, 'man'), - core.CdistObject(core.CdistType(type_base_path, '__second'), object_base_path, 'on-the'), - core.CdistObject(core.CdistType(type_base_path, '__third'), object_base_path, 'moon'), - ] - self.assertEqual(objects, objects_expected) + found_objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) + self.assertEqual(found_objects, self.expected_objects) class ObjectIdTestCase(test.CdistTestCase): From ef45cd5ce063ce4aace83bbba1091153dd6ef32e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Dec 2012 21:14:07 +0100 Subject: [PATCH 1929/4212] fix removal of context alias in config_install Signed-off-by: Nico Schottelius --- cdist/test/autorequire/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/test/autorequire/__init__.py b/cdist/test/autorequire/__init__.py index 2a647954..330680df 100644 --- a/cdist/test/autorequire/__init__.py +++ b/cdist/test/autorequire/__init__.py @@ -65,10 +65,10 @@ class AutorequireTestCase(test.CdistTestCase): shutil.rmtree(self.temp_dir) def test_implicit_dependencies(self): - self.context.initial_manifest = os.path.join(self.config.local.manifest_path, 'implicit_dependencies') + self.context.initial_manifest = os.path.join(self.context.local.manifest_path, 'implicit_dependencies') self.config.stage_prepare() - objects = core.CdistObject.list_objects(self.config.local.object_path, self.config.local.type_path) + 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'], @@ -79,7 +79,7 @@ class AutorequireTestCase(test.CdistTestCase): self.assertEqual(resolved_dependencies, expected_dependencies) def test_circular_dependency(self): - self.context.initial_manifest = os.path.join(self.config.local.manifest_path, 'circular_dependency') + self.context.initial_manifest = os.path.join(self.context.local.manifest_path, 'circular_dependency') self.config.stage_prepare() # raises CircularDependecyError self.config.stage_run() From e03f5d08dd616742d558f72545e9d9eedcf7a192 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Dec 2012 21:14:23 +0100 Subject: [PATCH 1930/4212] move / correct tests in object and config_install Signed-off-by: Nico Schottelius --- cdist/test/config_install/__init__.py | 14 -------------- cdist/test/object/__init__.py | 24 ++++++------------------ 2 files changed, 6 insertions(+), 32 deletions(-) diff --git a/cdist/test/config_install/__init__.py b/cdist/test/config_install/__init__.py index 2a05d4c5..2abf7614 100644 --- a/cdist/test/config_install/__init__.py +++ b/cdist/test/config_install/__init__.py @@ -101,20 +101,6 @@ class ConfigInstallRunTestCase(test.CdistTestCase): pass self.assertTrue(first.state == first.STATE_DONE) - - def test_non_empty_object_list(self): - """Ensure the object list returned is not empty""" - pass - - 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)) - def test_unresolvable_requirements(self): """Ensure an exception is thrown for unresolvable depedencies""" diff --git a/cdist/test/object/__init__.py b/cdist/test/object/__init__.py index f3a526aa..c4f46cd1 100644 --- a/cdist/test/object/__init__.py +++ b/cdist/test/object/__init__.py @@ -255,23 +255,11 @@ class ObjectResolveRequirementsTestCase(test.CdistTestCase): self.assertEqual(expected_requirements, found_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] - - # FIXME :-) - self.assertTrue(False) -# self.assertEqual( -# self.dependency_resolver.dependencies['__first/man'], -# [third_moon, second_on_the, first_man] -# ) - def test_requirement_not_found(self): - first_man = self.object_index['__first/man'] - first_man.requirements = ['__does/not/exist'] - with self.assertRaises(core.cdist_object.RequirementNotFoundError): - first_man.find_requirements_by_name(first_man.requirements) + """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)) From fbda50dfb0a5fef44be698187bf4f786ab4dd0f0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Dec 2012 21:16:22 +0100 Subject: [PATCH 1931/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 319f7a38..12baa1a2 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog next: * Type __jail: State absent should implies stopped (Jake Guffey) + * Core: Use dynamic dependency resolver to allow indirect self dependencies 2.1.0: 2012-12-09 * Core: Ensure global explorers are executable From acb31b2632778e1dc2eaf32fbf9d2bc5cf8d4da6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Dec 2012 22:41:20 +0100 Subject: [PATCH 1932/4212] do not push to ethz Signed-off-by: Nico Schottelius --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index 572fb768..1f408b94 100755 --- a/build +++ b/build @@ -349,7 +349,7 @@ eof ;; p|pu|pub) - for remote in "" github sf ethz; do + for remote in "" github sf; do echo "Pushing to $remote" git push --mirror $remote done From 7df1f26c9aa37b50d240a65fb49220de4f1c9426 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 3 Jan 2013 13:01:34 +0100 Subject: [PATCH 1933/4212] +deps issue description Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-01-03.dependency-issue | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/dev/logs/2013-01-03.dependency-issue diff --git a/docs/dev/logs/2013-01-03.dependency-issue b/docs/dev/logs/2013-01-03.dependency-issue new file mode 100644 index 00000000..91db9425 --- /dev/null +++ b/docs/dev/logs/2013-01-03.dependency-issue @@ -0,0 +1,27 @@ + +Problem shown by using __rbenv: + +__rbenv/nicotest + __git /home/nico/.rbenv + __package git + __directory /home/nico/.rbenv + + require="__git/home/nico/.rbenv" + __git /home/nico/.rbenv/plugins/ruby-build + __package git + __directory /home/nico/.rbenv/plugins/ruby-build + + +1) if children do NOT automatically depend on their parents requiremnts + + __directory /home/nico/.rbenv/plugins/ruby-build fails: + because __directory /home/nico/.rbenv/plugins is created by + __git /home/nico/.rbenv, but __directory /home/nico/.rbenv/plugins/ruby-build + does not depend on __git /home/nico/.rbenv + +2) if children DO automatically depend on their parents requiremnts + __package git from __git /home/nico/.rbenv/plugins/ruby-build depends on __git /home/nico/.rbenv. + + __git /home/nico/.rbenv depends on __package git (via autorequire) + + => circular dependency, they depend on each other From f41b029adedf98a01343ce19539111f71013911e Mon Sep 17 00:00:00 2001 From: contradict Date: Sat, 12 Jan 2013 19:22:23 -0800 Subject: [PATCH 1934/4212] 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 1935/4212] 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 1936/4212] 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 1937/4212] ++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 1938/4212] __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 1939/4212] 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 1940/4212] ++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 1941/4212] 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 1942/4212] 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 1943/4212] __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 1944/4212] 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 1945/4212] ++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 1946/4212] 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 1947/4212] 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 1948/4212] 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 1949/4212] 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 1950/4212] 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 1951/4212] 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 1952/4212] 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 1953/4212] 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 1954/4212] 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 1955/4212] 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 1956/4212] 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 1957/4212] ++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 1958/4212] 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 1959/4212] +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 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 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 1960/4212] +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 z15R&@mQ!aRO|H5MF8S7EqL)0#x#fc;=P)DNJ%?7dm)aJ8OgAJACfk!*pAPSFF8?-g z^g(y?6UZN)_w%LxWI%)N`~DG!tb@*20@A&C`;bO|tnZKe1t9O2^&yG_VAwuIK7vYj z4MaubUh6fhnZ#9g@nNg$Z*IZUtiqZ(wzQV|J7oV67>v6=H6^U<_-89~;KZZwBj=&WM;Re^?+~4<)?x_Mk z6;D6w`MhhVs5bjpPVoi=e7|$2Yibg@1{M>7{<8|18oIiU(s^T}v_e%XW+q5Vb`_Dk zeZpqFIXl_|CW*uoM;@u7it5feYX?Hp`o>eeqa#EHE*t?bG#0-;i{e9hV)YV*VVH>NIEel3-6Ej)7bFX<(ZU=(2m`-L02%b*kyI`~e0kn=aseNxeH^_!xow{*wP~ zD!Ue>U;@BzGVPN!JQxc53=J{dS>)%$cGBt}c73~OUTH&2_tz@vCssG5P|D9r6q z&zpQqH`URJHC1@iX2QwHG|r-Vj3v(FMzPEckO08BCe3K-B7d1l+BUc2M-uRn6GXyp zL0FYYl7uS^B_02GfRJymyu9cLttFp&_!)E|6zH*))-&WLXrIAC>h>po=puw}hp&|q z*)(qF4mZE#VxI1X?SuetM*MYYEc8{81%x0SdG zCQg${B6)JGH)!m6N36HqCT3aTJ!Xt2C9H?$<(8VUqvNCtJK2Sw9YJ_o7o~CXlB}rSjXe9;I66L$T!lI~8WOgm(`2g^Url8*? z6c?7t!gv_v7T_y>N=sc>8L67cz@IUfp$PCVDxBhnXuVl2hP->8y?f+k`#+lF&s*># zyU=KlUxS;YBrC!&YEaXsm9^HbNU*z=K&_PAC{ zK#qqs+>8>dt4m=$DN;%v$kQ}GsM-P~li6#QGbF3uUZIWHYSdGv7Pqi(0)ZGzbrSnX z!xLEU+G9xVNuj&^ZGV4v81y$C@|%)rB+?@c`GC0fT?sgDqp6brxHujxAf5els%={o zQAE8W>Q>^gCK3>qB?*yMl6IWcwL^Gmz!iCn)x!MBBAX5!4a=EWp zE#m?lNm)TkDPBh*XNaAuOJ>+V#W7v{ean^511ip-b0Qho2mRd~K&N4TqSrDXl2?Zw zVVvKTG|hC{z)83=0NF6aENQHbv)6)+F@zvq`|7mZ(id5F-+a&Uftl(0mtk_{h?(<{ zHkfTHkl1Kf_;j5PWD&TU>=m>dWh(VK5@O`H4c$E)^UCEG6vYiczY3CnCLSj#kHI8o zUR_UgGDSP7%1d<-EH0ofx(#d5WRWj!U`(Z&n0e%%B*@-NT}d>Z$z6#kR^=I%RzU9= zsFp~^abS?Ak}8ZR0gEfOEDI`nE8EAY;qGK*e(WWFYfcA{-@`8AYS-Lbf*DmBO3(v;IbkRh6JNVwPKR71weQCmWEdf!@rhDhnQ}$Wd5=`jm?l7xg6|tL^qNYl&`1 zQx8*agyX?yu4Ru}&%~5fHUE6vEGyCkXNUPfW&enVgsv1Sgnb9`Am_uzb(J^hF*Z*r z`&(|R(zGwV4D2v!7?fTH5sk|QEG2Zy`~d-z-d|lV;eu5(`f1J|j-4rVEX|YllI>AMd;4>gy0)U$n;+ze$Q^Nx=Rm_mK%)xvQcj_I3^*3#x?pAK; zp6BhG+iCfXmWVa*8l8dDJP6?(Fm)@9P>6Z;+O_UcIrbqQ9@v@NMfGd0%2y=fX@*8C z0ob@vuQ=kIVi)=><*Gj75YNkDi7Xmgq}MN~HGKw{Z3kubpllSHX;e^VGqP51Y~j0b zsN~fM9nI6&%Wkr&P*Z3TdtCKLl5ZC?{jS&@J3t3Jm!{1#N|GU1_E)er#_t?d0HXOB+2k%ljld zCI&gVKbzOy(*JevxOR%${XSzI`#{(YC39FGI`TZtWDMNzeuny|Dh{WU1fd@HhESm2i6N!Oij(W8)2J(1It)z z^J}j@JIQJy!4kW_B(-3>G{xhAoaq}|TTUzpc&(EZ=8UbAH=gCOLRV4i1iSa>$w3}@ znY)lZ7{$RRmmoD_udUb@juy!LrSA%Vg|6tlO3tqZTT%Joj=?I{fAMGGlsHt}r78P- z$8Cwm>i=?|Gid9zYPo)>FX1oF2WFgzVK%iX*xSQ6*6kt~-CcO3HZGfH4JMA9`^>7e zk!wT_+pn-Fb$=sp(T96jy9agp?)#BBqcS2yZWI6?o)?dYv)c8tKqrSxQisrP9v;>_ zWbOFyi8D-aeCyz=s6p(AX4;3`ly%+GLEGD52M&`_BIH9wLp*Oz53f1*M4># zt60o_0<6RoXbM3cnm{GHG{Uck=znVe-sAw3IoLL|pf`J`g3nvX>8Ww|JF}Jo);)qn z!xx2TrXxC}^`lwjKBwk0upRp1Bb57YpIUYgmn^`H8^Mi!$O|iKEX0l99aJ{M-vgbHo{op>U#lXTOcyUm@G&+_ zQ5GTBz@ik)>buwhJO+50HXK%PX|EwfA#W3Ljc-CDH4bK%h>EcjAle@b{0Zkd%>|}o zmU4DL@RRsFKZ?33r01LX#;J1OJM$jlX>ma8{o&1a3f;q%$+|n}v+Y5-HXCKk^vHYA zr=MoMtk%R#nn;V;=cc*qs-8opT7vIG=Tpir%Zi9!;zWHN`I{v{_j(LVcQ4|XP ztcaG8r(&w&X~q_kc=91xF@U+rq3)@cMz=HJ37;Mezm4pRRj;-D_# z0{}?mApheQ&wpL!3KVM`SHT7VRIn2xn1q1XxKg4*svcRF*>JjQgHOZHLdbGr6TQr% z=%|D2y>$ju~CkX3mHKp<3IqxsJK3jpk;~OZHD0%luPfVq&mDBN5JG8h$`x zT2xd32?seq*h&%*v=9e?E++v&Ru%yzE*dHWD66PkTk%1Yxm<0u6;vv&QV*i}eZ7eu z2I><3SNSkl!{r)1&TRS5(R6<{0-*Per zir!R#z&MLCF5mWahcSVwwERum!@#iDbzdRcZ_mq4;S9griLCk36Dm>A6q zMNDx3gF6Ig+X45V>H~fy_C0_k<7Y4%uca!j8N)!5GjFmo1nXD={w+y!0IFcfj>_si zexf{})h;Uw4+Yr9Y5E*rwGoQ@j({z&e|cj_HBOT_8uY%u;?E&1>u`T0XMW83wVt9` zhSK}mGH+?-cWdO0wEJ?q&&I}oen+DTroTrj-1 zxYcN6i~XBew1JHcU2f`jPaej%;^(DeU8lQ?1>oLUFv``G4@Q#n_NTYULT6Ky?D0Du zQu^&_fn)VVy%+?Z38^{5_uWnUxi16g(4>~>F|ez!m^Bth#DTE)E&sDc2ylUFvDOCx z3lHDa7y=FZ*aQ*in#b>_l)$)|cB~c{%c53(c&;PEcH6yjY_Pujyqc1`QA-$sfVbo* zDQISl#NU^)+9i@|@Xblq_IuOHhj)cf61tj5GIR0pvdQmJXZ}2MYLZ~H_57kmVA5{5 z6o_<+;pX|`T^>HIx7FHm-pe03^hqT8m4VD_v9*|%Y~9{u6ZhNU7%xzJ1^6y~+k`@7 zeDIIT5xlnGmxM(E32So`m3dp%{ zff9|FkCm7N|E>m1b|zxuu>2m@>6nVKR)>no3h{>K+SGj`_ok2V7nY_BY;A_A#E)KsLvBt#$n#R+o`R zkYhNjW}uPoScIV~?zhtU0OsQP?cDJ262ks|VUA~2+p>t~a!uNOy6u$tiL-xdQhTS(&}ngyXe5%Zc9k^p`=#&GA7-BAaP2$O1=LD4s~;DeXaieapGGh7o`b26>394e zCZodD(^dZ8$mr-UyZsOjV9c`8(*4+zVyypUl_A{7#^&ZZaJe=&BV(-QP(*SyUnJDe z4`7{c*udxggpQ7Wg2&=T;}Dma7+87o62NHC4bS7D>6hdn(SI0c_)n@un9ebJpG=18C6PF73}Qnxaq@uA<`rr9GL%F>yLP^b0d##5RwE<#NzW5 z&;Taz3GB*%;`;i8Jq-p3Q+$Pu;JCeV%vHn_Ac(qpdJyLlJwy*J{{*0iOBr1_Nt5)+ zEA#XiG&vv?oX>J&sz8(1P&aYl9nzs{)c_qD3F-OvR%m@u)HwnR9_6_KIwrK_R*1X? z-FOj<1^fB$jP3bGTVo%@TyX&SPFx<C9zF60zzQ zRlU&ys*49#NRcEU2I?w6Z02xq_BXU+wSa&CEjEHcYs5hI&QE`lfOu>&S&Tqy{|+@| zU66=rOlTGa1B4doBqsC?ybXc8C3s#UVkj=SwCb4r{jSR6MoWb{`aIiRYS=WyCy-vy zl?p@P1EVIj3zR2VKlTWS7o0~FA4n32bFC1e4}=4<3N<3v-#Rf%n`CMgbmy7HaiSY+ zA98wVrap zA@OeL;7m+I5(E6qAz_f4mPj`wT8{LINJVy_2EGtHGyu=3WmvGDb)#HMD)T#s8~_D& zEQhBFi1e=^x#ya(Lq$W=!bU?2?D_@SvN55dL|@3*pTU;G6Y}--W%Cpf%JgrXhOKGO z;>>h|tQTMqyIwY8bDhp=K-Xsq_2(3OtM$w71*;Mz5GSm9dK zm8sGfhvcc_2ha&i`r&PHSO<)+4;Fk5WUf}1n2WKo(yhUVO7xC8_UB#a%s*!f6) zuRHWi?_uWkiVkli=Flv3{HpG}3y(}a{D4nU!QepqGNxO{+Qi-+8Jr;ONg$2pq^qlN zRQ%ozs&9o*D63~CT&xnvOf1+2*^Q3WN+w@)&k1aXTAw%MHW=$J6IMho0oxfBAf~{W zRd+NnGJfIBUs&tkKd~QI&+P72mUc6_ep-q|>GJ+N5TT)=;r;_dQj^#8RKp>+(u|$M z?N}fYOZWqZm6es-Pq7TOz~jMv26JE{w~7j_*wpy!~hM$wQSOo@l2r_ z8{8uF4-36`qobonIqW)thBr=~5lDSM{waX3B$7Twb>N2cc_5Ep*hECRO-<~`vBvSnO+WqMn(N&BGX@{neY7K?VH zCy{@X5X8X54I4C^@dQGMxE-u!PwkH%#P6pV)YH>rMupva2D><;>mQ0|tjWhAqMPt{ zsjR}E3a}1Y)J6i?DxUOoE%mPrhq8EE@IHHj)Y@Gn8z4-~pPPH3GXx55F$(&rT@jz% z0NlqA>?jR5zing_+n;br0d7_I{G=@bYQM2=Hn_bWEQEyv@&!nt{rmZ{*vr%EkF=mWeV{zMH! za%DWSJ6J+u+6K}YPj94r-W&fDN>CDej*SI6BzO*VL{?CBweZRs8FLB|=CWk{l=3BqE zx{5UdbKq|1ot^Arp?TT_PqfGPSB=a%{^{4|{` zrm?0EjgJ^>)X)KXzEFL`ap_|IPrAdS85ouP{X`XY_2Y5iLI7^e2US(BZF8Xu45n9n zY*JCYtHtYf>mJPKJV~UjL91ua0ko`_vZ5ejD^Uko+vd|$zS!oDz>*Mf_BQ%rE?&K| z==Jw(!Spk>CVR`-c%z<9tvyEfL+xWmp&zsaNa*d@)L>jV9gw?CR3@N1=p=SZ?&rxCx2V=q&+|B3j4qwu$U#uN^v8@4Ovl_$ z-h@1OzWQHz%5&rfBMWM9&sm;ZJjGX#_Yx$PsN(@(tvEXN6rLtya`Pg?f9-#GA8srq zD~;VT=UW)DvK}NO?LB29DJ!2f!)sy218LC77gW-Y7JAfsbRYF9X>v0`DJkr~QzaU~ zu#lP`&ZyDJb?LIywgcWOciFDH&LbSukD1g-F_`>NK=dQ_)HH88jMKm0Uxv~0tMPv5 zbcgl#pPM(@ZzxXbGtpOE{fe2(J*ZTMVEyx3LRg(51tQA+d{P-Pz14TH_BeOy8@Ny?EpPyC-t~sjBh|>$)s|!>(c#OpfHC_T0U4r=XqqOZ!pl z3lqJ%He`B3by1C*PIbcHJRp%jYpK+}GG8kdE^?v@XLWa&^ZuCb+6}wyZ6|a9eN(FY zujhbw%k9&}kKtcVO6F?DTK%i;p+H`a0@DFbrtS2Y-AGJIvgK)_*-F<>8R<5` z*nW2N@*0ePha*E#BlG zVGSdaXTxx&JGS>2Rr2K8*POH`5hd@`&^=+&#sX-!9db};`}8y}7*q*Ckb@BZ=hkLj zWahH3d-t{PqzdrgHr)GBCBddXzUGt~sWb$P;K5Mw??oaHpV{g6Lha@-opv_ki+SMy zyI3z5qAt(9g_hvgw$Jz0!Pu`xBjR)BF;pw$}6fNZ}FumHyKv>(A zk_^d`kK&BV+0$yL(sc>*`S+I?7l%m%EZju?zI(9qZ=atzq{7MjpSv#rCJt_< zF=Kc~Tx=TwDlqtqn$#2cZJD@Y>5yv6^WfItD^4TGL_6;qq8V$c zRY8ObO6>w0Lt}4N$?MIpV@X z*X3ZUemx2$YH+s=3>-L)5zLYAv41fdl&F=E_1+Tz{#5+4_&ug{UmjKTXVCnOi*LPP z-32(o@O+SR%3|J5I~Gv8?1s}woh#Eq-_LYE#BklYpTRQRh$xhn?0uh~@ld?&|Ak3f zHYgDwTjR$7zA&1<&Un5n2V|u&B#ZRbg?qc?QW^Yc4lWUx8uN$k|McQT5m6` zEf-Le54K0(TaP^`m;dWf1B8GsH9nH`2b|jw&TRJER-_p%%Cl?l$Wv{ty7y5)4D*R zUC$6k+DoNS5mPRKs76wmNfwYDZ$SU`g*ud-4?dX7BX})sh`i)Um$A2thvkcgn zmXu*j6k;?=YbOZx(?}!P^tbf4Ss549C|7-Ee;P?EVuDU@qx4^q9vF7fQdyK>XoI@3 zRHyfvWi2bw^#XEYho2&`mev)xCO0}1S#l=W!H(LXdoEnvrT~7ZxhN_-A%740Qjz%9l+*hGGEwHdMfkwPQI*M5`|ORs`cq(@OBWB{|&C#5!q9 zS*a#KGoQd9kh{g1-5fD)BpXA=&}cbHq?(#wvW~Y){>cBmM`$Q}O&XSMthlL9Q#n{ zm;0WIyNwm}bkUurv!;h)%t~i=><>loO2QUj@Pf(@``%)~@W+lzRnr%%U^XTlnPUzI zJkjXlg(RVS%;G}xXeB|YXT$^T$fkYKQI})uyk@-E&xIUuMEuOe|MplHiy?5*Sde0V z&WOi88?)$Ps>z4(;&IiH5DKh}lPL5>A={6D=!44C#c`4<4p0jz%dHR6j@IjPST=%3 zj4;##;J&vd$!^42)hMmO44Jz$W^R$!eY$C5SX}3mQgFOpEC1w@f4s! zedkO!NH^0qcM#yCN|cc)qnuLt2FJ~1+l~{8h9z*IV_r3oJkMgAt*%OmkxHr`m(FO` zD9A6Fg@<@de^WyvyR%V1vSw|wFJqZO!q`QYCQE3LWwOl_ z##m|$AxyGIh(u)HNp>TIguZ;1Z+(A%{GRJv=REK8o^!v?^`8Ik>%MO4RE|}YP^w6R zW@@E-pgpO4Ng(^-vk3Ee4SXiaIY;cAK9$^~GO6`ZMmWdwrYqeH&_OOs-f|!0N@shT zG~Y$3&m2N_$q+NeC#GW+c3${tH1wK^F64x(q=4&VcN_@OY;MrwxunMo9t8}8eE3_} z$gJ1-+O4Z0c@`)q{UsF}IbW2J!>n^^Y&@-t&du8yJOyx`0`YBY?2_6-p7w(S^bo8# z6Es5Q?!eyNQHfOZ$kb%(QeiN9Hz)z>??58v?4-l?ub7);;Y@F*L;2zF)xP-Odtzzp zl110YP~0--YR$2bU1892ZHutp@awR~RQao5{KsU)dfr&DWiGb-6wci@WrC5!@qL@Q_v8EnaqD+z*PFaa-kfohNFCSn${wPqn?Gx-BshiFsUmQ3 zgB7us17yZwP0cOpy-%PUClLYB3W@l6%|eaLx9MUqH=%aA2~SozJV98H;QfQHqBj92 zG;1{5pO8!t3TB+~Ww#=|WBkZ`LBE3}S}%e@F@Gb-eYk&iqe7YQUT$;o#r3?Ks_k)N z7unLIDlbcDu~GN%ie?!3U90 z0-CgJi;ma16`k}Vph(L_$+<)k<}aY*PrWw6FM$et&Yc~JGLY7oSe-WAYxI%qRPZVS zzG3p+OFPiX&#RDxbfTjV=WMLZRbjJOqXE{TAp!72IbZnYt0oqsQ>LkFXTCAVQxi0d z`n}JZrGI~?63P>-sP4}#2T@{tHo?l~W1`Sr?8o+9P_KL!G+SA}u;P4Y_(^KdP>E=I z_~Pi>JmJVJ)Jae5OT(J&s4%Rao6?-OD}Ty!)MBU zpvFsw(}>rKZFU&Pxcym#C2z`fel+TheC-$$k(K2Ks;zk~XQ{EMp|dNeBS}?ZT$n6N zZ~pyzV*qCaDdmzC*i@XaO<|tTK;tNt<-2`(P?@BSefO(l%*nF9huaWwXI&op+}9O! zMSb50NCczr0BF23E=lv6Uo^syVp&J()7;>IaYWm|$arH$g2x9$!vdZ=;uUwp+jcDPPCqyi~A-X)oT#uS* zxcM!)M#Rn6cJbPygBlK&EV!cA%KB6$*?9j)wu$GdjB#4cIGZ}8CNxxcFsMl7bLeP` zxQf60d~L`8{?HQ_gow$YdyRzOFC>d^1x~iiT%(*?pwu&LUih|1sbbKn=hO64RK#L27u1rTgwrdgy*Hw>|ngGIG)MI%lC_tHrjp9U3 z@6W0m%Xr(#N+j^^*n#+P-R@eqRPp=nu~r^wW`Vy(!#m{DZ@ugP9gbw5R>NirvLP(P zu=&x{yzS5c6?4J#>v4I{o%m5Gxo&(j4bF&gaAcB<4}U0IDnrZV$&LSOZEbve#_|je zqt|6rX%DMZP)s;g-JBm<1g#tes3rcr*?+C>EdI}jb6RCl6u>D9*egRb#>n^v=s z0aH(hLK(5!?Ulnr&4!;zmKxkuyx{Ru70Xi@}v1bi_S8Ts*MVHy+Y@FA2eA?RRjPb&) zXg~lRNPvTa!Am}lajl7K@Njx?S{e%tA4CC+u-9DJCRgXo4U!FT++Z1IP4cq8x*xqG~1D_eBdjwRjVv6!q{K zZ@wr7mDqG;nSb-1^mT6#-E6PZw5&_^O!uqI%Zx*_sb2W*o$aV97O*^^$dB6QZWANA zpO|+<@9{^HbI-l;^o9GZmGzIli?Eme2u%t`N=AeA8wTiZvGH&}*4Z6?d9JF(00#-2 z{4t}V|8vV7*604=F2hQ5<67|cBDS|bU`J$ew_YVwhbnuS%q=`XYw}8K*y4J2$=%dR z-XVKl_VU&!lC0pe3oGa-MIGnvM(rRj{9o%*R#L#wuz4E|3qc*a*Z0??^r&aydg9^M zKhq>y9g6Jocn=9pnhM>^ec~Z}&mk^uojnlM$6v7D7b~JcE&tiJI}}kuV_X(FVBjXm zH`AkfWm+rANm)tlL6qAYX}XhY-Cmq8diwWKkyTEDWhwKpHKw(}S<@Ui!OO;zJ0(8; z>78CN*zH3(K#9_@&rsA!9L33iXeBniwo(5_V7nJhZqLwoO) zV3)$2o0qOTz)$ha%ulZdxs}R63WCz2x5L{?{k~f~@D*fq$qAJia~MiVjdADBPIVj$ib}IQOe$r!KojwVD`*V9t#*hA!S@qLweI2Xv_1t zvuN4TA#>JtMNu7~)Z12*I?Ze(cLCG@WJ zpV!PMLz2q#LM#^jDTn|uahGC@&qq`~Ms(XhMUrPEw>ZX+W#sf{KXS-RO5y6M`=(#U zl^~b$2J)-TEs$on;>}+KywAH`fz7*+*k)_ziA4^_^=oUH^)J!b4vyZuVWf`|w9`YG zoNicLK^myAIVI3JX~}U_nsEF)i|h4}r7+3=+R9^AfIg#_8C2-kk2AAMxx{*ZbJJAk z{07xVq~X$6PUByF3Ay@T$DRjpSzAdB{m{k4FB#a}1is-2anB`$&f7c9PlX7+V9a-X zn;~Ut-YMejQf^Sd*@ac^u72HN@kJdCH@!Uk23&)KOX>x+L$IA zso%#{buiL;V2q^gsoym}9n5XL{}1v=clt*Z>0q*tSfBcTAwJlGsOOGhxsC`OT9*Iq z40HUJR~G}+=ffDl{`u%}?WQiqA13y96In12b&M`1L|?F z9gP1HhTaI!cQO`WVPa;Xe|s}=e_`U{VPofEXXj)5AB2DC{%&k+WbX7f`00(D9sXh> zAkQrJg@s*~OX**Y{)6EEZD;6iXl3juz|QiA9C#a5|Iq)d;%{nGV;kc){cs?z{*X^D8TnGv+?|`=zntm#p18xzdaEwEbL#N2n0%Kfh7Qz95%U7z1J!~Dm+$c zYT_a`%gD&G7{gMM2X6SB4<}l|O^7A6#S@5j_!vW|LnHRgyIERXqM~c^6lq$x60yHr zxu3+>s`f&eTyd!0zM!$1hoQ^@NQ&m+%7zeLrRqqUA^5H}j8b@V?Nwzi=xP#xL}AihJ@^3wB4 zW881aiaDtW@gRVMf-*8Xvky#nQbNt8!c z%C}4jIb5?;So|3sT<^aDHZ}(2hE&Pt`Q{M564eB+569weww+rA$9uWMzns3A2f_jGN({Gr#g)Glp=2ktEy|HD3*{e#`=6ARL2J>O)JK$&8SG98KQkBY;g_qBSp-$u zDQ5y+Z^?ROrw-k(;x;Iojk+GjucVl#Dn|7SSQ}^!}sWgNJUvBKIPK zD3H5meth8d^b%5uc;_e{i(QKTBFw~#TdK%RKwUjRJA%Yppubj8L@oD$n#?_Oo|Ovs zfFHHCH-m|UDh-tVQGDs^xkaA*liL;P$!T?Jb{WyPJ5|ddv#Iu5 z(HH*WXB!b`a4u+G`UcEHw1J;2X$E)=*#J7(7aBe;LF=qX`zUZ!+Nxd>0ojHNS~!OH zI0LqkpM*YV!xQ;B#S6C9=0n}X*;~M3s?ulkObNPGNY70nw6YoZ>%a~bO1DYLLyt*g zg{;d)2Rxt5ke95QOf#tEIid!lef@e(nG}+!=mE2d(pN+t`bl?p~@w)@PCL>k3$UI&v;T(*n;#7U?7?bgPxQrW9u?KX|b zkW9|IGcMfrRNILeOBY$dxv+nNDGQ0-En9Zq%%kNQ04zPdL|GLa7SD?CDV;XY)R(>$* z^XoXKZY)PPGhI~4_NFdcJvFH`K={6yHAU7VO<8*W9IVo;%IkR-p&V6~vSx7qR9CiF zI!3v6od?%#E#T8BjrhS$>`@%V;^|(Rj6wo+=Ou%p&)Sl;>nliJ8U|KuQ*|vL8U!Mu z0=?z`?5_V=(-Qbm2mo!(gr$afpEX^-Us8%=Dj&~3geSO-Eq?Zj|G@jxgK{rJHnW5# z+@IX!qyL7nNn%L(Q-Jq;i1&i`3Q>}74bmB@A~{9;=7?Rt(?Sj8=G4B869Dq-R|Ps8 zt(*d$yGT!l!v+!F1!^bI(Yro7Tukq1+6dfV-V1t*tI!VjngY@W638y1W8^lluVmD} zp-s=HlM@DA$3xN7x>GH=xVR8TSvU1L>7A3tz55r#mHh22IT^-S_M}7Z7_2l>cIgw@ zu|_pbQZEaVJM5S0m_`v~MzM9{3WH9;(>2l7Tefg>>m~a#t()fu) z(m7uM^^%2XLF?iK(aWTp4bEcON%)U>XP} zukfX;uvxKgaoLxoK;QS$Y_FdoDc@V6Do8-GL*<)4aSapDS(d&$KDuJ>Li6@B)H?IA znl=lYHSvx?MjLY`fp3>9X!O+Mm4c6I;_(P52Wv!^DiL}1qOgLMr}2WBi4VEe!4bBu z22K{41GDv=S}G<`4%;*-tW1>4Q9-t^Y&32~J>lO^X((B*2g0jl+;#1$e5qy3vqmy} zOHK%qJIB0^!o^Nll0-*@y!Q0h@?sFvF?nfcUEWo^?fI~w?UOQP3J_e6ulvO(IW&o-WfT#UbMSPtNi*fe z%8#;h?~40hRvOs;5Kwr^M1OXux$2dQuVT@gu_B?l8O|^*J13`4mD}dqN4XJ2fGJ+r z!wPn9zj@Q@8h8X)*hGvF*%KAb-)-pfbcLe^}Acf?X#jpA>&bY#v z028)GB7{B1`U=~?H&Mid2Sc?_W6=1+WZJDotF?!Cu0Fq$>x_TnulBP{8;zgQ;F$oJoh^IhV!=oV8f`L{oge-6gQ{1E{K- zO|PmCQ+piRib9vCm0ym$!WDeCTR0u;=FHS9-B#F0?&A{EJCF$7+mOV)$ZaB~^ZA9m z^aEDlmdjzBlcML_Oq~wHG8!Y2^96rWFNdZTdPakCYkK#%rLxX09%7$fxTYb^ql@h( zKDUHqs$jNufTOgku@Njrf_XN%3h)L4QQpOY<)&@mMIO8~f(y=~h2F!0AwRW@xj$BZ zP>!+qOeAOk6F8e{D0=8hU+iwzSa4B7-7s_c*em(F7@I=pi-w1`J(sWKMtxEp3e4$< zo4WF%{OQ*{!+W?jzxQ5IsuD&aObCe9Ud8yH=5tIsZ@Xy(GICUVXV>Fc$7M;u4tR82xI0*N1GzxN;;(hE~8+Ht; z`#`ATI>{QjIF)=f?h|MepTbPq@*6Nj%nj^cML;N}4T-|$I_FF!q>bNd0?&!YX0P-< z51BnP%X)iizf>Q~BCYAM837o^G@kxN@*LuoAV8B%<0htv4G&unCEQ(=DP(7gQh=2Y z-OF8=bgg$EN!{S;o7@DHOBqyk^7(WmoyJ71$h(QBp_ZOuDHTF(C@=0f6CJfdnFMaK zD#XSU5^qk^t=4UON1d#^t?m;zkei}A!(RzVP@hM)dHJblXAPmQXj}B z9g>B#Gv+h8YN+VY)QaAPp$4h=Q@7Uj|0bO2-YC&o80G&Q6C}!C;nj3x&x@O^y&D!# z9`-)`QiUyv&_uI68Tq{SVk0_Rkye9t*-+B}^OIbfOF9=%@?Et4oU6#fk(d^Px0b5M z+;G~3dT@Sle`FI~vpTSNG%YcC<~?Wpb3A+XXv3vpyVw);+;WMj62_8&Q5t7sW9QK> zlYS#AAak@p0%YsOlMqe?S~yA>qWg)*lG!%9{c#smCVK1{A&|&4!t7V@F1k-^azDM} zF+u-OBp|9fA0K>c=Lbxj72F=1;#P=DVKRl?g&MTPQ0ul>krI%-IIEP*CD!@gZpND5 z-TC=3x=mGA7u@Vy1~g3(3zs!{aiSrH2jRZM%2uRKQZ7{e3h_1xhBj$6RB#2u5`l2z zZ*NZO`?g)w->ADJkW)5~%f|P{d#oUjW1LuPsIYRHt2;vNt5xHwbEJlM33Z`X_#xCj zAE))f1;c>;7%sr$WNT+T=JjPfQn>k(i*cOUv_H>Z(u`Lv6pvnSZCmehn&tq{a(!k@3W$Zz{e z;*zr{LK5F|vjIs2ik@4sy|m-;qP44B!pJ`!e-bcprb)AvJpcKFjg z(SUP+|41I7ehS0Al@!{jH4SHZ?Acgk?UR4ruzOa&C=$eAfEQ(+=?U7%yQ`CNmL^~j z#6SkX%K%<9>ln+`t+d;wU4F4T{tEa1%2l|d5LgLT8^^KCX3aupOTVWZbVz?5%tqvU zEkP}$Lw4?`uQtctO73g&#(db^e)1e9-~X{3%hcO|2^A`O+R^HUX`7EmaYqA}*E`v{ zsXE>AFy3h}0B62kcc-WCkcj3Jk#GgTzH;yu4d(4o_%VQMND?^E1Htx;+Zr#D8A}`u zHR6p)K2ch>uVY1{vm}@Q<&GP(fJ!rX(4wiDf;< z{X}HJ$dP$U8$pj6BEs6hmZv4dMLje6K&K!rwIhx-6-04Dv~3dRijhxqP)QGHQY57^ zQ`cE7N`MGM<$#mwiD3O25*O`2zV+nsppFgbx;3^3yy3*Fc%-jT&EN3ak6e_nJ~j(c z1idR2{4|jI?Tod#H-il%JVX$NZNxnA9_`q-V&e~ijxW!XT6ZNSzHgtBrPvD4@C9Jh(R^eipSqn#+ZPp}r z?5;IA++*&XXEIshj%WIzW^m^lDYm!{YNB^s>64c7#g_1nvUWKRI-EJ(CXs=D$vB6A zj_`C6t_1Pfck1nz&gZR$WXEH)?8Z!&ejTU#k--xgUpu(g)R>f{j(}pYQC@jdij| zZ{2C(+wyjzqDICqd!#nS&9QxpQAw1_-W$+`n;POT2vM==O!cC#9GpL75~3>e+rn(u zsbR*QbH5t8T!g}9Bo(9pyJsnbmfqj4m^u_%mXjy-yuLZub|~;3<6Bxi+?PV3`u>Q* z%$eJ^o>;|rzhAaEIX5YuAZ3)Nl)cADUjk{nWv*V04M68-2G_ zd^?5s##J@a>QZBdW(VJn6Bd?~qp3z-pLVV772JA| z{sDOZO6egW(T;zFgmMar~UI7 zg(_iau5}`^rQpMnC~?N(FfYD`66lUkgx<=ky6pJgzb3qXS@yI^FyVsgA_;tVa`l^q z?G=oi)SVQonE??<=vARJLFcnBGVB3gKuTW77vel>U_WN>)4}g(T(RY5p`>{`Ig?0eeF_p!GF5NdNpswuT74jiad} z0x9@F&I{%2-F7|YVbAQgt)GJ@0wRZ%N8k0d;dutO$!3-N)2iL~C5twH0fJqNHp;Mo z1}s5CA|QvquyM?AZW&95f)9=1=t<@)^yqd(ge}c`5#O&Iul@q81gFxy8keDK*~-vY zQ1X!y!8adnD+_VbepPn@*JIV=bo-6<7}Mz%w?4DdQhVYBb&c$&R9m^kp-^8$&RcqK z8v36r=eLRF#@4232*ONH8r{%9hVYjz5_m40SAfU~MPomcDAF^%<#zv%#!9$4dSWoC zO_`4ZN*q<%Raep0J=&(6sV2(q(7zWw#Sl8B!?8<*TVJ8BSRZ`iH(uI^$2wWGhI8li zk2BRkOe1~dfk~pL0k>c_a`DGtFZCR)hH4BjxTH9hZtLFXT1-Xk z)&Z#}-i~m)9{;)7Nw5UCca&#y%C%9k(!uzJw|PoDw5$q9WPx_(3}efBmw1l|KPogU zKcI_6RSboX$(yX4=*Jkv2D`m8<-qe#N?u=Q&61$kO3x zu~+Tn^6U=%T9+Q8yc`)}qAsWLy6lER_kI^z4PzxU7r%J>mmHDDD#cYMeqgZmfGO~; z41^Zr!+Ol$;kK7eS-QBaD;*;Q;ifO>oF<4g6PZ$yLGU7MV%vc&m7$ep8;(Zl{= z@b2L1ww%$8!r zCbg_TqQ0CzzLE~}f6qR@oKUOdB0%i3GQi`Y*ti@pYd5SerA>)9U_&Cb9TFS5?`=bV z{|!dh$6c|Mi)jRTuOd6ZaZYk?wbOANi%9ZRK;|@BK)(__tQki{t2#kC1>Q`sWJCTZSB?;;9C0SETMipMW||-PKSuU!8=YV za3gny5~7hy{KMZw@rz#}{^mMOW<8A39LvwdA|Lpd=9b#KUzz@Fg^4iU8?mCjf1N~G z7r`64lNmx+IaOI~CZKB@<^k!M*!2lU|=xJw*?*LkQ$hZ&BJ2 z9ViX1M&S#RmUF!kFN6nNt21<{IP*F!hJbFAT?q=;wNUPG zmPnZ|m^kFwSZ70$9$I5>U#PYSZs3f->eR~oT5du8)8zo$l_yds8}hT!eoR~{G-rZ` zt`;i6BKko_GA8$&El9G~Ykb;Ub!G13K*5MT&1EXRF$b&ohtJiDI)K*C&*1_bssae|zbt+0(Y{dR9QqklM&*=n7e7#{XW$37?>dWf zkLn2S?|xU^t&H25UW$#3C3G%WstBMju2!lBD^9)y!@N=8-_ZsYM}MiwU}2=bgpgO+ z5TAzuz?4>p5!zLyq~*y69O#0xQA+D!Nfr9(RhH zO~cTWHLKgq2O5G2jN_?=m#{V?tFco+gxseSpRKODB0$imzKj>Jh~&jDRW{SPD< z6k9soCcpNGv#4~~MR;^>ja?ad8c9EOLup3cjk?!S(FsqA+f zi)0^3auWFzjq4n4jt_uN}0 zbYt6hqC)m~k0fK5>eA?&Y4I30srgk!_VDzHdlego5E=`=vS?S+HT0Jn+Hxem`+Pc} z^%lW4MM?z1niz`d&r8{)N`K`;z$BjbDjGrAb0%%kDM~4kH(V8;5UYaj*dwJzmr}Ug zsSM$hl=|sh7Yeit1TN`pkiV>=u@j@23(X=?fypmYucJ^JBLx^`eiyl~sg87i)=+I` zVu{IyvgKjf`!v}yRJ%py7^U5U7H=qRvUTQlwy^-jNYFq<@x1utf0y{~8CNyG8fgN* zV+cchTdXkNyMDyvopb>WjE%eO@-yGLLy%9>EtUmzW0xX!EO)IR36Z8jsN*Z3nsVml zS2JRA=%O2;ma_p&34*kU6I-p{@Q~zFCe8ZJxzlMSVTw&B;IvWzP44JXeYHn-R%1nk zAt%6#`#Zjm??IY?ATqJt!OCs1?D*Q$p08go;v`>m+iXCA>IeD)SesZ#N63cHG5Jp+x9grRpP zo7A;FlqmjK`L&J9sq{J*pYDLkY0ADlVp#-$v-L0j{O<2YCgmvfK8XZclC;<7Hw)9 z6tvzaMJ@E_iz?z9(l43BK^gBd&CyfLr7}qrQZ4oLzZk0|Vi7u9Waf(rPqS0fSMgo~ zO{63*F~8`B!gCal1je6u=!wT>xCxcRi3<VRC#VS%~ z*!8#cdUW_9)h4#4PWm9eM(AeNP}g8eSdig-tZyz`R_*05I+eyT-TmUX(WH<=iw~z~ z9CRLlxSm7t{3SV_kjm<}lF=EmLssQF;Ps17(^v;9pHKDOu*%Ob<(ZCIb4<$f%*xOg z6EZ5@>`F1D@}5lJ?7s1nlpjdK>Ejp z^UazmqBRjxzs9*CQz}Ru>^}dgJ(Zu)FlXPpmKUrlO{QB^2%BPl>>hlzhU)Jgy`ZXB zot$?9oSWuMs+)5gIhV*U&|1AO0b(d6qS^$K;YZ>ECqynu;e?#9%tiWa)DwB6%wA@! zj;HM)^T6Ws`!B_JwYp^JJ_}8dY}Y@3DHDKbsFIuRAFXfK!M1I*q{rX}>WrRSYLe{X zH=95$#sc0`7FaxS1jv0JFN)_So6$ zCTm;_`lE{j^RnBb^b(U6Y+NmG+r_0Ai0~T^uv1v^cho$qqr6FB5@E2}`OatOaMfu0Bc^#acxn>LlpwmNat>o3` zVk416edX1iEz>tf+O2Yh$sr^Y$`lBtheN}~&nh9(cP%;+&()T=6SWZVSQ;>Ge8+3}8j@A7L z%e4eHrgM7m9?TS+i)bJI6wQtUCPR>!c6M#bw0(@TiC1aHUATPW9$3a)b@kLlou4v& z+Wme%RYXmo4wDlnV=%1AUm!`J%oxp?(!V^6<>#P(8*d!k6L;IvkY*H`o#sTO5HaXr zur=Z39mi=atrJ4*71KY|qwvrYuT0c-TIUf%7acXML-j3Ir}BzG;iJDu|B?Vqh)Byu z%wrhMhf*qNOz#OURlqhBe?nvd|EolG`3HY`)!nl2Qsr>!`6}`{sSv40f5D`2D0X@c zF0luw5?=6mh6xo}O_=8b9&UiJSsI^n0ODespqz9rU&Cm^jf)-mn)vs#+Y(so;5pvp zqg~t+fmEYwK7<`G^-0-4xVz-yR zLTFgJyI@D&k}L>D>*VwPl>7dhorHs9S-^KbF4>c6MLHv9w5nBETCu=CYAoByh-xoL zbk0J#twlb4S$M(?Q(~cA=tnL$5=Vdhavo6UmFW;!cnlnyw|Zvg;0(xMpzp^SM3Xf# z+@M7*Aq%Q~F~v|?=53F1(d0xEPan%GEhV1U^1C;Qlhd2g+OkHyy~U8h;BVs344WIJSB z4AoY`_0lA#GPBZrb^e&ObGkzh$r)janm23X3g|(+dOPpn?y}E+qaD8(gN9h0|0$jW zt8Rljwe&8n(>i$S)yy3SE8I(@Gi!NJFP1F9Dj4ciwt~a*(4Ucvs{j?Jh`O=Tqnfh?H7{@jkm{I{nan_yk3Z?Hk28|(ySI$;32T}n*&i(AI; zOav{AUrPfhu5V9-xPc*|K|x4~_E~<)_M(@S5yaInv7n&Q8De2He$^Uf`=Ob4okvl4 z{lZGu0~oXuT|XDO+-t(=hijy!`R3&%h5K(m9uwg9FTA~0ntzX7J|CM3vYL)%aJN1_ zWnE@u4sUs0?#lWTO8|YUN65sXNjV@?(ExBEL?n0+GaEIicjEsnh)MzNj=x29R{7MC z$qbcXNy!Yrg%ZU1-m{Ak+r9Qsj`a$ICP}zp{>3XC!M9)V6A_efhG;vQP?&jFJcYE$ z7>4}Z&F>``l=py^ii*o#rt6R!SJC;!MP8;p_PlHe3ejg7nYs?fag}D#P)_ij>+9=| zj^JqU<;Nbu=d0+@exgEAckMJB_ z6ES_K&gEF4)tc(5h^MC~H(r~S7Uz@YW~MALNlDR=Y`0CgAA!vG z_xEoPe(sHBrn6hB$jFRja667=@$)(#elZI?QBzYh<4EtW4Gs?eoX&xSOkQ1@?ejqM zMZj@)1Of%%tFri2GC25=!vpN%;zFfD%l&ZX`+I&5zSpPAgM$OUMp;_mybqhzWTd#P zED&Cv=%I@PJa=rfFJjH}v|T!xVdd>&2YY9x-RctL9pLZJpxZHmkknLq*4=2m1ij*U zH7U74CVdaS0t*F|bAN@M*kH55Q}uFud^|ED^8xVP8BQkR_qZyp>}YX2CmnCc3PC1>r@Y=ykVD4jpd%*_WV&fL9EcuG=M;QAuB~!DU2TVgf*NP8vsysM z8_~Pl{}yv|yZ|8?=uH7__=fFyJpiSvp-?83#e9mK3$hii3`?xueBQSRb)Sfry}o)VB7Pwp?dyZ*M2@0f~Y&!bpg6 z`n?7aQhm;VRe|LI8`dk+d&Xwa0)eps){9PS9p3i#_VPqt+%qt)vq?;9WjG8mSg!B-IKp>j+xFo=lcu$urU0zn@F3BUz&6B1a}LG?La zZhoh=OIz7CRUnOh=hwa9Nc;Hsc$q{41_n04)wG(HhBrT%TT%0hKtVwvY$kjy>UaOF z?Yh!eK}kimWSy^6^f_lEJRJU{=<~;qIm6aV4NxoLw|l3Zue%ivyn43?PK=4@zPslr zAf4qF)MI=CoL>^o&g^0%ZSa6M&&ll<|d z|2D~Tz(PCnT`>!h-o)diBj9m@-G;}4c9G-sYkzsV9B0!h!pvs_&n7hJTmxP+Z7fz= zuB#0P_U}Llv?^t44OXen2*mhAL_})7#37nvznWJVC)&@pQ9s6p07O1+yCbQnC{Oo$ z*-SwDUX~|u|GJ7VH&K&UD5+izY&FuIa|-1rbKFg=3B*B=Nq=Sg4PIh~AfRJVNnGd; zf_51n8uCx2aMgg*#~Eo32nY~{C@3gEz-9=156=PqC_*ickIQa>ah0(GY29%(C5>7n z>;{c6SE+0I7Of}&KE%4ZxpC?HQ>UC~bJ>G;5NT@HKSH%&2fqX1po;xQMGA=V+K!Vf zd!;}`MD%)nz9o6_QzJ64NtqN0OH3joCDmgfl?_MV>$T0V(*)@#e zhyJSH1xCAV%KUjKzX_%!!zQWI-TfMgPg(_jvMJb__BBNI@&VYKSzc;<$Jdbfxu3c*lc zE?#iAD;ygAX|)H4rxvN9bx0b8HHR6QCU%OlJce4Luhpp@u9SITyq(rYY8ZotP6s81^-TfoV#_) zr`FnNc%lM3XNu=I`H|oSf2P@vnqugSmV1!)N@6zW;m-0f*Bt^zJNP7l1=YnOe@uUWCLU@A9~$L*t(M|Ghvk5V_cV=qK=5aMr=t>@3@%P)8KalMehvA6uPe)?HyTc zNMr&pHyXBGC&W1jV0swjyy2_EBnZv`dy=XH&%F;BTnq*05xt3b{o=(Zj|oy=EV%r< z#3$$e8V%Q|CuQ@68S*QYX01VD&?sY)M47@`Iu{MMNegoB=V_B9w49p{O8xFB!e3ap z>$6ix=^%o1b9M-s#9LO^G>h55F?M%yKJwv5Z13{gUC=ty0brq4at5C4SQ4&4Lt6;5 zt1pL~SsB*iof;M|Vi>C>ADoGtLzu2WpaNmq9G0^7R%{+Vv6Z{3}iWT;w{i_%p*vIAum>v=o2^73ov*%uMFg498 zQPl>0uI=w;rC`_8%UZQ6`gEC1Pv25}k_LvthBM7f$(2W-X{|^iI<(mL_ZB~*B_=<9b z#sj*F)pvB&g~`duiJp@4c7rNVGr=&#PYB^UQrnxXdl=1lU${jv%mLi;HKobkjL^>v zArh$NLSSwfZk$!$azK3WDQ3CQ1mIAJl3Xgc9%f_2YyI2 zz|s%37gLSbh3)2D88F_kd-yAd<#X0{W;mK$b`&lQMGbvTId=)9A6l2y?6*w6w7L`U z%?}^Q@pfpyh+?Amp}wBp<_y&EVoQP%hkx@4HplWvps(h~c-yfWPd-Tqp67y~e5pfs zXU7eW+!6lX%kufj-n)Ox$|!bbyxSjmR)T~9!|+|Ib?*UMNpeS5$8^p{5Eyspwd*V& zXM4wJtd|CKOPe1$gR;fe&=OST^PP#bcUBr#GtQRjT-g6|D&qMaEAVvGpyb#i531UQ z4OV0aR3g~%Il+T z<=xH%;5Tc%l?sk{Nf)Xn?j5)P8~aa(Q!3BY4hxjAO>)?&%4W=5KX9OEA&W)s^TBHQEk7!3H!-Lb|5C*Sh#U^I*W1ZcbD^cJqDchx~L2@~+i@t#O(?%#&Rv{TM zbp^D29-ck{zIh&XrLD+IispPrr}W*NqBE^j@r4$71x z_WXjqy}TWFN2AT>Iy|#|W)0qRzu-3DtyFKuB%DkA6z(RO5)5(x_tgbwgi?;lC9{Qs zhI+kiZ{W{`6*xpONNH)&V7i{^FxLaVmkF4+y=1@pg^pizO*Q7Wpb~TyIqAPMJ8ti& z0GbGp4eb4KD+l}Wl8$5{(1|Q?*Abk^ES)I#(_r6Cjbkpn34Sg zCTic@k%$68!z){sVUyA!PH|N<6fwa7-|`}^VF5S+V%LCBPeV@8imA{dn>cOIPY2G> zCVsqKq3XvwA3hY{;=mzMzupW$n;Im>-*iue5fAoAOvYX#MjHC=Y$|6k4^r}X*4xB4 zgRuM_Er9*;OyBuVi@0%Mi%7%_!E#CY>ZhF>d-40Y+c?RSEGgN^u`MKK*eTdQ$47s; z;2zT|5(z&>P-8S9TCV~Vq{!RBQiwI92?b}sbU_%*EZ|)s-D&ME8a(iC=S^<=bMm^h zgLCRPNS_I66s)JW6y!mni_~%N$D33G4!QBGkIzAky@apm$_)HjR_dfH$o!_;F0F1t z+=(5yQ`iv?=1eQJ7AAjAuZITO zf<%eGPB>O*kp+OuLyYq0rHT6O63yaiax22Y3qf5OqLRAgaJs3V=Wm()kih_vQt{Q- zs-Ms9FqmVm1gE1{T2^)p0FObGjkW2RjBI5KfKm@M*6CxR?2=1e-0LAa_IotL`UfBHhw74h19yRu296ue?cC@CiEz#}1G}-U# z^tOv)&8FY=02M_g4Ru~rMkNnKWsHm0T)FdEr7?_oLt7?HbftFOsBEVxHiqv_q#v= z-1(PolfI+LQyra8d~QU7*H9rfo3g3=F{=B&f6H<$T)-wUv637x92_t!fZ$0dpNV)q zQcP|#Sxj|)Umua^k46*FK^+15s|JDq0JID_yE)HUs-F%zx>c#3z+|7?Wxrx^XXLSh z=|~`Q(5^=8TAi)c#TGUVX9z6iCLQRswRtQ9ID8zwx#T0U9HqR7!DI+IQ0M{%$;35&}3ShI^GRji1j>j2I8aEK9xml7ZN_CAP`W&r8Z zzxv~S)dQxGcGS+-3>!3GLBpo?Nny}g)>V!;h#vi;IL-Z0q;dTT-hJs*&3CEdf~WP) zkLeYSi@DdiXuc<;(W%0dF(w3cc<|(uuw))sUGypG?KU&&5}-5SsBx$bzfqDRLFp}E z?61Ww_XJLV>PvHR!@+g!o?ZralsqSSXo@;P{-8?2h=YAlC^uONQXIIzCSBsJn7Z8` zOLE1*^4*1tdhEZ!Dwd)Rk)U0&7G{eHBVPa7(I2 zdg}sRM`cD#->eKMT)+=?Qm|}giPcqr2Cc{58}7Hypj^@HBy#V8eyfh;Ja&K85b{C4cVXd3j%Op+xaNd+fVENer>Sw$)%d z$Wg?NZ#^f92%cn2fBNiw&@2W59O{_IuOa~^@z*tZ1*oh30gIxvHRJUte$37nAh z9--PMCt(hpfPO@)Nsi?zeEDpGiN*1WJMx;?7yL}dDTP@xkw5S$q}sFULLd<19ZNLx z3B$;2BODDyzGDFBhGm#H^})$GeHumr%#GNiX{uKkYK(N7Lgeptgv4EDgGHnU=TPRyf?PaeJZ+>Q0_;j?akhf)J2o76D{ddGH;bTK zAVbX@y=x;woWwkq?@Ah^hMwIIBP#+|0EGgJ%Ql(dRFQqk-Rw?Fqo4k)IAKVoeK3Y3 z&=QlDsctc4qF}`R;FVA!u@e8o)COk%M?upkYwPmP&Q9n1AO!5OY{9i$QJCx2z>hFc zT}63$2D4@A(n)mp4@Z@fkpND$gR)}A}exaeEy~X=l-7ifpcSlQ0O4c(uJkK}#A|oS-fG7L) zF2B>Z%g-Jj9tsKyMV~XLrl$5g-r`0@6jwr%lasnW_Y{p9-roGSl7L41*RN2gZxI~j zEomnrd5~9EewT;9Tkvmt+lVPsxl{!T64Ey+O@^{+u|m7`hlshkxsee$-PP}<+lgG! zw_qG0s|n%^B=h#(9u)<}TX0nFPv~PM<~{#nscPk~w~tmc`f97|X@~7v2N(o&mtPLM zhgg-5Jowwa)bT7}W@e_Xt?eyzad&suRX9JdHWAa<$Vms>ESOf2X*JiT3v zO08E~Fk4`LyrauSBISES`Z-&G5C>;#dtyaHjlNltNDN$5*w~nY>TYpr)qg#}AQMc@YutW7w|?@o(sD zJD;(p%%f+<&{ zt>C;RoBq!L`Tre4e-iBe-GGX_mskRNdr66Z7OOxL(ewZN_geq_@j-&0IB~+27{*_J ziI9LO&i!}dPid7VWP-Ig>OTc+e%uvk9I=%rrYO@(1^RP^s1)QdFdw`Ovn{-wp~0w-@|Zk$G#@( zq6?6x*1S)$x}UTe1&`oR$0!xRis&;4d$>C)Jw?(Xj@H89`XiWX5$h{z#}ucYDsecsD2jl(C3&)v@m z|DGgtg`Yu(pY!g8xO|f<11ThZRAK=K{>N~xiTZ5pFB8NiT0)8Sc! z0~|8u-Z%k;PYN1w1$w{7No)|2LWT9eh$51Si1ZeCEF23Pq-XfF)8Sjr4cCC1ctY73 z@*DQLD>G;8mKbmuXcG07hM#95XMd!4T$?V+)Y0!W*G=Sr`5LuSRh^QdVHJZqq*j1* zXJmSOSYm;EZ|mowB;C<%gIFzOGZ(+q1=Opqh7%T4hP1<9UHK97(yK>QJVlmMvjIby%vC0rJ?4CG5 z)yIBgmx`tlZ-&;tz6f@t?!Cp2P_ZS=B_XAdM9TCIF?JUOC>;~&1@Ll+kQfLURG=dm zwY3i3t!#nrHZVgrl$4ACV(&hNq&(rkLzK>=}qz&gZcMo7Jh& zLvdRGM@3o{_$ZC|*;n(DsaNu`tsmEI zW&Ju`KMlx{u*@1rV&WAB%Uykq9y|xWz%uD&?z9*vV=&{E8Da$aK44Tppix2TG=VFM zU{(BoZCqzmQ`-^_sB{RO&?FHJAQ1#1(tB^Y(u;^x1?f!zF@mVH2$x6~Fo@Iu5&}ps z(u+VKKtw{9CPj);g!ka-y_fgao3+>8d-j<#-|RWRW}R8z8Tnh~_Ky9J;xCK>3xYR- zam%VfFCbu1!Rg70S^Tp!b{un$l5gj%BCKNziFXT&yfaJ1l(Y3bSoW*POO`K;R~~aU zGr+P@XHD6)Gz#r2EV*S9i@>XL;gUY|eE2`D7HAVBZmClViW)p$;bP8S{BUP9tMpB? zKqqzc)HNJc)`K7;8nVW%mdE*$WvMB~3&LvGE4vCeDc|+vnSHXEI|9F7bODu10?+nH zTOt!KfZkE2_a=kb0*`)Lk6bF#0P6%D@;^HBubaSzaIjpb(hUwjSytZhb8cq$FT-Ap>%7C%$9j&zDfObA4Z@wHl4>t|a` zj@mSXeo~0COQOl})P36x5aO-F`ZJA;^?)ZzK(O1|-Kvu~9yvmx(2fd`a!iM`i-YmKY1q z{b%t$$-Bqx3JXT7+xTk{z48@9=Fe#+@-jw-KZ1Gcuc%)!6_T&CC$<;CaccX}+Kfva zDeD&!u4ovitbsS*K1@y!?|}>JO2our!Cs{W%l+7wkOdqKoltQrp2Aa29f^P8`kbU> znC}qVDjGY|llY2H=$x<&y9P#nZ>tr7cV$(cb{5edqb4)G@lS7;2#np50~GDm!i9J`lrOZSc0A zRa8#R*J0JQbyXo-fWUbE(DB+^i4}h_Tb1>_ZN;b_S>MXhIXt;p56L+oA@RESZT9rY zQ+iRs(PVTMH5QoSqdlC> zZ%8(*1}5#PUbnsi6-CnUEd%W)aeR-JRELI(riLrNfGW~KB3c#_W}|0B8jBG>rv2t* zS26Nvt7@yo-h{|VUbL=fR&+j472lqmQrc#CN64lJhm9Zva#S<4jO9WzK-&RR?OhG{ zCD4+Gd(*luyo+yaGC3u8a5e66N_>czS4?seRijaS#Jc($B>Jpd0;g}aKPmUxx@p{%ea65^J{NCQwxJ5o)@wWNr(YnP@LGaZKzT45uH*)X$ug%CLg2 zbVKDud+zYGw+`ujalp5DZe$!m+o+Ad()r#LCVDEjVd2#uYRaw=+0YwDJ6Vpb`C3(B z19Rr+jqQEp@Y5w5B4+bqoumJv3&Boq1hbZ~LALbl;7HhLzn|tbV#`CGGcw7q(f?4s z#+r5fP-@4VVQ1B4+V#`8Byl2dn)qcz!s{FVGYCUHP~G$yL`LR5|FeANZ}kxnx(?Oq zs~S7pTDt77&+s}`%E-WSKBlOgNzQr*CV;F#9527h!*!Y(maGY zxEvo$fOD%x=^Yo~%TyBOyse-37VPNDe6B~L$Uq0QCo^xOKx^&<7#^e? zX?47WQb%g81i3o6E_A3_J!+!&a9zipc{u8$Ft)KR28>fVm230N+kp%1-{ z0m8P!o{nqg|7TTtH$cs~-_(*0guT?DC)?j{g4GJY1~Pb4mdEo4-VY0-V_Cm=6}+}R zAOEQB!x5RHl&j!* zsVCqNrrSGrR#z#~-|JV!7JYMHEDlr5zuH$ughpfHK0;FW+(BLl=fGq`X$x*clXi3{ zQ+qVV)zq~Kh(MbyBB&2Ts16E6w~el!WlolU*& z-ywLtbeM|ns&fARnia4L2c#tFl@g=ZSiFRAsx&Lk;+fTovi8%^w7EBf27Qt`tt~C2 zsWqx{r|XK^V;C!HZ99I@>skGGSDZ?`& z;Ci(D$22v8q{Nb9F?fje%!;j#RWJ+e@c!a0NFiCHs=UHl0;~Hml0RubxXR>wLe1vg zbi_fqBO9l5_IwX}+dV2TO@zUaTU1*?X)#%hb9HBCn9Eok)mCwbkUXQICpb&M&@>_+ z6u4_*@pZmGqLR$L2uh(MZoy$BXjmvnX0@cZKGt7zLQ$_KFuBa`kEVt2k{cr>xh?@D z3q+P!VB#dNjNJ+wZa)I61X*!mUjDr;LUh)MsfDVUXT=j0AVp--$N?8$FtX-HUdYMh z#fl+ktsO4?nvhuy9LQkHR8oTJE;yQGvGzbjUTd={iE~hB?a>w+bS-M@EN%B6LG>G{ z)l^bTwAPmj485B=i!eG$qB_?oxQX6&OiT|FCNKM8w)Uvay3~Bd`sL-hKbPhes4S^Y z!sW%BxVdSEu!eQk2U~#m zZlTQAhlId{$N<6S=@k)H7!-&QZ0rShN)S&U@z_5MJ7UaKz? zFc;lb{qz1L)*Vt&5R1xoTZx7jzx-qhJ9=TBI!s!TSV&I4V-x5g-DOHd&78g7=f*Cj zKbXQrm`E5V`v+EDSB5O>*?;mLh4%DQ3$|0&yNbpbPlYTji2WAbfOaK4||G)Gl<-8XD6u;_K zwB_##w#(9l<*#!2Z=OK(6)O?z6B@zOR45E5h4$YfOb-C~Is2cmrTLw33I3r^LCFsI zhbrZC*WR(|DWPITzq8^7pSb_0e-8ivoiYIce8tgAR?uIuZdmhBW@@9wt%ZN-Hplvi zHkwCM5S?aC_m2&m4w^!X^SG*~Vfq!zU-v?vc+l5D$7!BNU$&w95A7eIqeg}G@i|C>~wD>OncQQ`=Q~m}yCY3oQcDiWq to6-s=$vFMp=uVjc0F}DOx%Lk_W|sSZnMO|^!&+FP4{r)l^;w;~_-|yS9drNy 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 1961/4212] 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 1962/4212] __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 1963/4212] 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 1964/4212] ++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 1965/4212] 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 1966/4212] 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 1967/4212] ++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 1968/4212] 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 1969/4212] +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 1970/4212] 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 1971/4212] 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 1972/4212] 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 1973/4212] 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 1974/4212] +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 1975/4212] 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 1976/4212] +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 1977/4212] 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 1978/4212] 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 1979/4212] 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 1980/4212] 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 1981/4212] 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 1982/4212] --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 1983/4212] 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 1984/4212] 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 1985/4212] 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 1986/4212] +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 1987/4212] 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 1988/4212] 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 1989/4212] 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 1990/4212] +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 1991/4212] +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 1992/4212] 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 1993/4212] ++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 1994/4212] 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 1995/4212] 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 1996/4212] 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 1997/4212] 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 1998/4212] 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 1999/4212] ++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 2000/4212] 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 2001/4212] +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 2002/4212] 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 2003/4212] ++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 2004/4212] ++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 2005/4212] 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 2006/4212] 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 2007/4212] 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 2008/4212] (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 2009/4212] 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 2010/4212] 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 2011/4212] 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 2012/4212] 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 2013/4212] 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 2014/4212] 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 2015/4212] 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 2016/4212] 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 2017/4212] 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 2018/4212] 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 2019/4212] ++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 2020/4212] 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 2021/4212] __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 2022/4212] ++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 2023/4212] __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 2024/4212] __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 2025/4212] __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 2026/4212] ++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 2027/4212] 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 2028/4212] __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 2029/4212] __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 2030/4212] ++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 2031/4212] 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 2032/4212] 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 2033/4212] 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 2034/4212] ++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 2035/4212] 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 2036/4212] 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 2037/4212] 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 2038/4212] 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 2039/4212] 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 2040/4212] 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 2041/4212] 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 2042/4212] 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 2043/4212] 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 2044/4212] 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 2045/4212] 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 2046/4212] 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 2047/4212] 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 2048/4212] 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 2049/4212] 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 2050/4212] 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 2051/4212] 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 2052/4212] 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 2053/4212] 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 2054/4212] 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 2055/4212] 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 2056/4212] 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 2057/4212] 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 2058/4212] 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 2059/4212] 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 2060/4212] ++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 2061/4212] 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 2062/4212] 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 2063/4212] 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 2064/4212] 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 2065/4212] 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 2066/4212] 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 2067/4212] 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 2068/4212] 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 2069/4212] ++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 2070/4212] 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 2071/4212] 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 2072/4212] 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 2073/4212] 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 2074/4212] 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 2075/4212] ++ && 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 2076/4212] 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 2077/4212] 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 2078/4212] 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 2079/4212] 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 2080/4212] 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 2081/4212] 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 2082/4212] 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 2083/4212] 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 2084/4212] 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 2085/4212] ++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 2086/4212] 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 2087/4212] ++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 2088/4212] 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 2089/4212] ++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 2090/4212] 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 2091/4212] 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 2092/4212] 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 2093/4212] 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 2094/4212] 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 2095/4212] 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 2096/4212] 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 2097/4212] 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 2098/4212] 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 2099/4212] 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 2100/4212] 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 2101/4212] 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 2102/4212] 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 2103/4212] +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 2104/4212] 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 2105/4212] 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 2106/4212] 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 2107/4212] 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 2108/4212] 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 2109/4212] 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 2110/4212] 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 2111/4212] 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 2112/4212] ++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 2113/4212] ++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 2114/4212] 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 2115/4212] 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 2116/4212] 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 2117/4212] ++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 2118/4212] 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 2119/4212] 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 2120/4212] 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 2121/4212] ++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 2122/4212] ++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 2123/4212] 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 2124/4212] 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 2125/4212] 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 2126/4212] 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 2127/4212] 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 2128/4212] ++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 2129/4212] 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 2130/4212] 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 2131/4212] 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 2132/4212] :%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 2133/4212] 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 2134/4212] 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 2135/4212] 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 2136/4212] 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 2137/4212] 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 2138/4212] 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 2139/4212] ++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 2140/4212] +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 2141/4212] 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 2142/4212] 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 2143/4212] ++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 2144/4212] ++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 2145/4212] 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 2146/4212] --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 2147/4212] 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 2148/4212] 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 2149/4212] 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 2150/4212] +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 2151/4212] 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 2152/4212] 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 2153/4212] ++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 2154/4212] 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 2155/4212] 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 2156/4212] 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 2157/4212] ++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 2158/4212] 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 2159/4212] 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 2160/4212] ++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 2161/4212] 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 2162/4212] 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 2163/4212] 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 2164/4212] 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 2165/4212] 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 2166/4212] 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 2167/4212] 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 2168/4212] 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 2169/4212] 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 2170/4212] 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 2171/4212] 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 2172/4212] 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 2173/4212] 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 2174/4212] 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 2175/4212] ++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 2176/4212] --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 2177/4212] 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 2178/4212] 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 2179/4212] 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 2180/4212] +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 2181/4212] 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 2182/4212] 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 2183/4212] 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 2184/4212] ++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 2185/4212] 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 2186/4212] +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 2187/4212] 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 2188/4212] 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 2189/4212] ++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 2190/4212] 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 2191/4212] 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 2192/4212] 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 2193/4212] 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 2194/4212] 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 2195/4212] 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 2196/4212] ++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 2197/4212] 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 2198/4212] 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 2199/4212] __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 2200/4212] 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 2201/4212] 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 2202/4212] 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 2203/4212] ++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 2204/4212] --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 2205/4212] 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 2206/4212] 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 2207/4212] 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 2208/4212] 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 2209/4212] ++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 2210/4212] 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 2211/4212] 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 2212/4212] ++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 2213/4212] +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 2214/4212] ++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 2215/4212] 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 2216/4212] 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 2217/4212] 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 2218/4212] ++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 2219/4212] 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 2220/4212] __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 2221/4212] 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 2222/4212] 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 z1P~#h01q>LpBb{Iw5=|-eBz3ZpG-T$d@v;Tru$C?Y@_poMkGh3KPNQ|TCED~@4md^ z3kk6EPmStakC%65lg7SMcM(+bUoKzU9Z!gUG_T@hCeYZ6@~6_=SB|PS>hY6VSU_2O zAYB8Eu+Rj%NZ4ylJz__?`i=en07?zi?O)EYlB5oP9)`b-<8valfdW+&0`j30qyEFs z5X>w+#z5lV{u3zWvVZRPtvk{;1!K$yL-&D>9}PI-RyRqey&w*?-t|47Q~v;PWcd)X zywi5yT*AO-9#&8XMFof9X5C>X1630%%`qCVBo6F46uL%2Qo2E480gr!HAjUBNLwHV z)v=DHXTDcst;1fhbkX5#812^i-DAu0RXjR?A_~+oO#rF%V2Xm=&_W>Dw_xjWHxo?t zct3@=E>O1?iiZshM5di?czl6G!qI$5)lMk+(}CvO)d4j5^>DQf;#jh7O`qo$o>}z) z3A`5FVu%4Fh(L5O7{nH-Pb}I#ML|7_1n#AAc8^Fk#bXx3}}oI0B%RsZ=Ut3vz#J;~J{>=6WTj2fgbIbRm(d*~*DR**HPhU3k=N=L!1k|o^!YJ;| zEYfUu7@-l*p114$=bY2mX1wb8^Zven{5kL9bou;e3f&CWWuaUHkS5(qlXpWNP^c$Q zVA0ch*6wO~0FE>T4fjZaE*9M*LZuMk(xHi{_5uEpu)3~OMR-BK6WaukP`3q1;{0Ow%V*#QgHe2aB@j7feVP633$|5-~a`LTtKd+P-t!d)Mt6tr2@!&?7u#< znqC`+xUF%87M5H8xE{lRyE@$jm=o53li*u4Zvs#jdraotjFzfT~1 z;Joq_eG9l#pS~Q1noUGh4{3PnU~$a4W(#|16j@gUmXv4}h%ALnbP|uiR>?-tgf=W- z2n|vR5(Q0Um*k~`#0p_{vw)Z&{JIVj^VS2cZJ{TRow&6V|J5PwSymE zgSGYCDq!{$R*Kq9%HUW~z72PGA1&?J7B1tn^mqRJKfX2SX|LGO80aq|2nnjbBO(BSX>zJEAIvdUg(OlnA|k z?(o43FU!$QGI#+ang~F|H0Ve$1nH;y6*sEUce0x^UVeS&-@MwA62d*@nSxvve^*1J zwv4CZuH`|6z6JfUB6cwe;z<)xt!=|?*Fmzyr+^L`#+P9ppoL*KFOYeGqU9`sUUjhA zTB0vAcdCrLRVYvh4I5!lLpV@p5B%>t3FahhGyE_>I#% zkBriu+Y?>7`PMIzmGRx$xR_oEw;(-Ncyt~F0E4J7Jz`6)-Wmc&n$LgF?tgf<(NZHj zub((0+jqSF@?ZTQ_mckr^8Wzu?Yuur5?3g@fjXdO&IEvw5QPaEe0OH>-kxd-fu?eV z$gf^fDCz<@u>hOX*gVS9Ym70iAm+~sR8%upSJIVzDtZWnvScq?VW<~i zQjzi4?%9q-;y&=K!TB*1fW>j70!#A)i=g%@Bl`eB7(f)zVKZ?pdZHE9P2222@Z;4^pH$<+ceWeCZHtGN$ zH(s%Cp>c?!KqM11HkK%91IBnL&2)kjK6 zvMucx!n_786o){XMAlpmL444<^1*zCi$vFujEE6YvnAm@K~{9x+G0x;ubppYoUrr)dX|HYbk@R=o!F)dsAjPuBvY+&2_6FMa?cCR#1U#?>71$d*jC9f= zBZ8sA;Ls>Q1sVi^Pn5tnzVdp|O>+f2AXE}v&bl-E{2oNtO=4d%B7Oe=^ASU6X!?9# zyiJvX)k)))b0E~R*CZ4)?a%M!K74J_f%@Nu5rBtj>tN6K`u1}_Y2)wD?+^H~MI?uO zU219uD1D-%ays)N$6ri&8>CvGH~#<+e_x-)^NZdf9{%F9tdk!_6XG-4pki~d2-hu5 zPTl-r?JUfhpu1i^G-6s|Y#2UTP+Fxhq)Z&?kGkw;skOi<1s>O4k`fDDZw;CPy;H^l z*a;lo627PdjnPqs%5utRY44-)gs+RU(cn}RAj`fQw@@O=4QQ_jFC%ir#`-G_yw`#9mJYppcG}W|7OYxI3K+zGk?>ym&E{8Z@pl`Sqj}C9XEr3+C<{oUAQDN+7;TxEdMpTnij(h(A zdcJ3e1)XezWe(kh752ae+%z}hN>iJX5f9Ig)v3wZ57PRpVK=v2^W2PTYhdo@vW2OF z6qAuPrAvJuFM?6wCw3k^#~2tnkm2Tv1_hCi877;27Z_>s^Pq@cF>&8Zxy>&|I}+!V zG(2rh4OLGV$Z-#8(SJHWe69w_D9&Iv1Z+S#hi7`O-GGx6qU(}8K_I;VDQ!Vnqlh7# zQ3EMAq?sh*=s^mr$1z4V(_av={7e+s}D$FctP}MgnH! zMyf#&x)Fi>@KoIkD6pnb^Z3KTYM@0X#nW($6VAG11OjRIntke)bl2lr{NSC0XgK)a z;{wpw(0JUQJUOF607p9$$!*7utK?Kkw%y_@oi!VRNKfY}W(g5%Q-?on0_^tFsfBd|C&s>*=0yO?ubu`svEwMc6P>F8Pb+!o>XMK~-k-*L_`my?z zvC%u8@C#kjz4>>iCJh&LUF-l$Hp))p8y$w=EmC(xPPo2$j9R*O{GZ?J*VFC)0L)Tm zP{>h4gR3%kI6@cnMgamY5C9Yx(W)pNVP1jIZyE52X+IY>n-O#YEzpUwy6S5PnupLr z7Ya$DTrYf$Ye@?QZju86Q+<_N>iPi4(?g1wtx>XZ)I6BJw2*#@>RVZ)6t z?bq(1!&$2rK^E}pd^ZwrRo>6e_s#zK$DaA`{=IyDwRK0t`#bT77>}c@hR{T5fU9I4 zVk)EzU{-1Yq)5}|T@QaBc$zn$(dO%in}n#&v1Mz+%lu_LO)m-HIma}lzdXA6qcd_x zbmjBkVk)he4J)a6D4$gyf{w6_tX>IDl5}R$*r4p zKR^L4L0Q-;9QrW5`eeCfc7IA*?r%QxP$EPosy3QBm`cG#NQy+#**OX(6fv(&gT&aQ zim`G#JG)@J(bJEQbK&%K+nzP+^*iJ9{asvDovJCB#_Q4Y&8~`HkvtockViZd;&<;I z!}rw4K>!Aa=&2qz-QcjgNGQF*#-uh!n>KOTI*Ds%4Dn0nG$fA1APq9r2tx=AAVkz@ z?*%Fg62P?S<$MXZw*Ji`nJ0|VTRVYBz$m8sFNi}=U0#9-I&oWG7iJW=H8rHh2ZTbp zxSxpvR9LVM{NCuM_i-MP1JON|6QVyj>%3voh2D?wWMQy?Qo_kk#hCM->XJuDAP!Vi~)gU`G2*#SiE%?bSAHhFXb0nO;O#y8rk>~|#>;lzr1z@Q%g z0H+5k688Lh9P;k#L^SwaE-`KN6WKEY08IvjS}>_zxIq}@o)h0V_^JD2e<+4{qGz;Y zJcX4qs|G#1xZY3-!BngzZ=M=+BG|~;a<4MTpWC)UwCR8Qmv~5G?gLb!-?ITWp)>)7X;7$1e10Rd zRXl@<`p^=(5`o^5BPO(|HcUsWx=*D_>HSYTp8Nd{45=)OBtM-BRzi~47~E1&iD}-d z>yd}cXWyLI+{Smr^jIbno;5F(#LRLW9Wg2tKIGSzF{TyI^TIG3>Ifh`ag%szK+`!5 zzNX&<#H(MtLUV6P`?LxYZX$WMXM}b}Ji#0VzZ~hILli2l*8{cVX=u9D#gieNkAk3{ zBtegk0{LYLxZ;RR4F+F2N3Lj3hZHA@wAHR_sRIognX619km^dvugfsjR~vtvPcV=iN>R8g*D{%~F?il-Q7D4NI!U0Cw=W8iNQ9!4Fs5L7%cKxK@z(=BBsCK! zUrPdM@Rz3Kl6aq?@7D0*1Q7V4lmM`$D8&cs2y#I&i-7k{c_|n`MBmS_o8ISL>0>|L zbh*ci%V{5O){_rogK`VR3j_3>$VzHMKw!dtF#7e-(LY!wG52(6=bi7)4g&=nOhiNh zaY-L!@6}2Q>^AqydmhPj6o423sR?yCs{>jNNSH!^NOr9_*m1yA zVY+PfWhNbAY~kMQEpd1gY6SLf&F>Nj6&3kb4|R+uywZY1m>z5&X{wW(zE4b9Tykwj8dpKc?nP$y#m(1m4}OR~*;>03T5B7dPOq zgZ{l>R)E84YTOu{uo*?u0k0k)9x!N->=Du+)aCqKZl&cQRHfp&z(Jk>0P{@PKfY3t z+#0ny3TQ!TrLF$}zf|-3d3`VKxA8mioC;fCFoc{}Z_kXI8xpYPyIV3sIR146^r(!6 zIAyXFPITNvwg)R#LM50ZZ<2X@n03!SO@#jdIO$lL&3g?AwAMS_^VAXJQ^fl+2G<;5 zLR{1-2`Lgi2;|WEdESx4sBNO+p2I*rAKaV<=*Q?#ypM+P0DE;pvX{9 zHjq1{M%DJ=2Y zax&p$;m5-`-l|LEUM)_WH09#H8pPRlbot6OtL5LrW!EuN4*F?nW1<;CBc&d4{fCSu zHx9lMPZ5R2B}y%9`o4FB>YpNh zwP7OI3*SZ@Y(nxVZPWF7+#k$>G3N^M~qhPYtTt|b*A-uZkZ-VTg=)SxB zWIEKGlnNjOCj$nOK_pFtk>LGT3&6mMJ33B`(?=2G+1zi+pb(ri_`LWEJ29@5QECK) z)oDzarEv2_2&m(CfB@kUby;NXOA+vDGK<(#OBrBT+2F`%LZ_I#Tbhk3Mb+eIHkqg= zc3^KsL^<(?4RxvznxOFRHwu&4#vbf?d|;%E7j#6p)JDWZ53u|H0ONgy^c5fnjqFayYef}TMJ`^Q>xYi|+B)VRsyy1-3UtfXJK5^ncPHub(l zPb#BRuQL~;A#@$Js%Mh@7VJ%4IH|1@qjOaud}O{Ob_fCc*IRPIq|# zjd|XUy$(zTLAJw7IUhL4heh*J1=GowF(^h>;(l2CA0h(XYM}jK$I!o28rxUbFlpn+ zRBV!d*m*?{FmCbHW&^?9?Qff>d&3iVUHR<%U-)cVw6G@!ev444v5naI@ z^leJkKjXI5t4AV*PXzSGg{&XCQT|>I*{) zQjS(IBua@0jhBNZQhgN4imFzkQ(9L~5g7jfEClolH`3>|o-y4sumZ=L2CCg-HNZu( zu+dTX;{dtr1#XV@e{8YfY$5e!T>0~tIK;+3C@I! zKb$J*$Elo9n$elE>ZHheD-22qY8nf$?0kTa?aZ4y5y!^YW!~TC6q2jqUz_*k!d~b^ z)v*}!RK+cz>Lk`+LYO?fI>K>IuMPa-*SE3ETd-mYYN?9M>4NZcb#tP+_TBeHql8iy zv6Vh*d&@=eRFs=a0cKpf9Ee?lxB<`rLDeBsUR#F6n1!ea(*SwFNqB329?4RC>nk8+ z;Vr=-9f8wXK*g9S1&AU-EH{UtvU9NlB|`IfVJTRkl@bBowVfwmc@HlyyioBUIz#uH z%Xp{E{{XULll;{G07gopqh}ZRHx3o$XZ-|CXGf#uYSo3tbzCL(H|)VkVFRcitD&_4 zesgP_u*Ur$32Dz1Z-3T6s3@^|Y1{B&Ld6a#y_v6B_WDIZ zQKU>hWD+1$(B}mhvO`x2+K(=_=zg9@v(ozYnnT}sUx^wCMi26vaFGJ&w5$}88bHFx zFssl4`Y0_Ljg2t);{O1c=O|*Kc`a{l(hO`A2*(5n(b@fLzwj%M5r@kloDnV(`dG(V zrdwr`V!p=z0L)}8gSuua(wjEAjximvv?oIr&g}yBB!tGk_Zk<7sGSl{fnoRJ3zfto z1!_C|qivQ7=ZGU3NtH*DEv?H3f@tu%7?DHgB80K3t=mMHmKCkfV}O3w1zC^?Y?bMc zdAaGTNIZe)aB~_whDug}Y8#rvva=_)lm) zGeI^&&2GZYr5Fwo$2r25d$yy4PLv49{9KyB%DJ4HSpq{BIGLTvLCK9mT_L*27^^PZjr^ ze0gZq**Ei?fv1meqQh7(NnPC4&T=BE%+zbC2U4iJSdGDhCD;(mEViM! zJ%X1^Kb`_*8p)MOGGRj11@2_Iw- zR%-5a?$x(`FlCze=k}*FOrxPR&hPP%dQ;OKeop5`l&B=T0!?O-Q8Ze<PD64Pqi7?n)?O5gSqUDu{9?_8u*hhE2BG|9 zUOkr6TlP2BK#OEAv&u>{G$jkj?XN@DP-)S+DPrAj8qbMWsvDXn;+?=@MJLSI#Gr}a zIQkH*BNWo{tRBmGX2(b0FjOl*Xl=ZK6W$KJzvWI*5v5ae0>F%9Ht4&RP}8H6acYnDVxVCPauLzTtJ zNyV(WMpB|7@liZwN-YkP(5NCH^^_=qssJFff#R*2y<8y%p)i&VjlLLUu|;+wXA*7z z?hVdZTwg;YeyMMmn!p>wJXA0Mk*1vy0VQ9w4TS~)70a>}DL!EUw;)X2ARn;dOlHfq zYyhG7PGb*nN2@!sin_I{AIb?%FNAim5v6b}8?0GLj>2Rq5wV0%N5n(`#KW$;m;tlE zwe2#|cHG7KNz`Jw*l`G3g@E8XrADeRg5^c3)a6JNg|7bq8R90@347mH))@kKC>}{i zj}D5GblDQI^<>pLw|gP{;0&`3jqQUON_U(4pz{9!!;=l}`TF=Xxd`5zp5yvPiBrD{ zz7uu0!V_T!s4O~oxj9yWepxFcno`Gh$Ha|3Gf*SF4eAqmnxDoEpF5iH%6>C+4sD)j zv%1i^ZM2AlZR<}M$e_l+uy!tt*FR!3>1DdX2<#jb8Kp>HIFXu|Q98F%KYWa|2>PM2 zn8EHa527)Eh}1S0xO)?x`%-%J>6n-!73EnE!b0j_k|T= z=>}1#k?}v*7qVW)VvQ!yJqImON(hF48N^amSMi0c3d5nYn_`7nmy;2%7jp3JQD!i$ z^nNC)B2*5W40mE{`QJTdPa17&v3|jgZChrm8_7N3e$bErOM+S=Q@^jIE&NX*Odou^ z$_9*nN4t?dGSXvMZQaMj3=gcB;RQ*o0f&SRWqgQZ$$-3Y6~o8?_4SA*e7lt^O1N=a zUqU)%o=bu(a{2o6&S6T>qG*Vxp9TrQBM{}?{{R@%o7kS~FsUW>`IYl_4jKo-+iVSZ z{{UtR*d5+3*-50otYDS5LD-tbt%h{+F86^@_RI(eqGP7uA-CtA`+=brD4utwkk&vO z*#61>6FMI;@%{SFPiYz9^B1^wb4Q0pu)2)buY3Nm0eJzwwZGox!g|~0oO$oYMWg0+ zjfEax&R&SV3cCeW>=!OeCrx|(k^3X0RR=M@V2X+j6ex!`TZ_ni9vv8AZ3h&71dzmu z;D9tKi0BhRpiP)cK^x?al#+Aba0yMmj@khyD-=y8+WYvrJU^gY@L%e5?Zt+1$1kP8 zQ1r2_s>pQx}H&3{mKc{{X;e?cHnS zsk~6jc)BPOZC4s5p%?*h5e03QU`>Dk(@Jb^qcBE?guaNzYLvZWa3)XOHGIW3HulE0 zZQIVqwrv~#*yhH$V%r_uE= zzT17TiW9Lsqf=+8^E0m0(Pyb_g2L|~$EA~QJ4RYV4KjsSzGo$X4I*uJI7~0VraBWw zg^82;PRko_Ds3f<`t1jmR(U4T`}(%xEt$(zs`1cOdZqmH>+97Zo7# zbouEAkkeT2<&6{TWk+JkI&6bB)WRx~e}*v005;Q{F}B(HMpoBg0X7d3kHvR#E4iE+ zszcs*De?gJC1`5Gaj5*Hnh1+jtEbD7J}HGPw;x>Uxg}NRh{;Kpm7}&>F}5=M51nDR zbWMP>mB;Jr<2&&k|0nm2uLPHy6T9T+Ee@9Bui7csUN>(1?u=qDtcBmlwE&#Ti-5~C zn8JH$#fOtg6}2n&FVEfF*yaI+Wg4Cyzx_-xTI+zV**?14(Wfv*d%87QaJptsPYN>$ zm;#bL$SU&o86iIk7|y=nFG_(1abmd=NJokClhgJ3ukwj+B38w?*WfFWW8Me%C*udf zt3M9S6m%E;edjmt38#kR;&Rx;!n1r$Tw!E!Ad4~z(^vue>fz*-vIPZ!R!tk+6(t5Q zV9Oj!Qr!cbvSy1NGp9~K`Op#+!zFTZ5$PW65~;HsN#qRQr`@uAOxE=j5 zaBvjM8ciEX6hp>J{R@~2ZTuh4x#8>kkNu@yKLe@|L8sQ1UlkSJX8=@j9M8cv94H8N zjr!Q92T54+kM(+8LLa59Tj1~^>h!({k2C_aBWjkzhSzo|SM2bvJ#c?1JjsTU43AXI zEDrF5g{dIyBh)UgeCc9SnKZepyAV5bqVA)xobrC79bR3N{cz=3+i@<*lxI58k?wW{bv#VR^lEFQI8ol2VhDs$b(=;1j%@Y;u~ z=;nd`MY0tXwy?gfL|<|{A+b`elYPh(#Q*ACUo!E#tS|urBE4;e&*mW0S{k~d8Cx>H zJf4_&`15R=-4n^|mK)#K?S@K+=yB&K1I~+8Llnj!b zVPEz-EEh)GC_mbP79%^u*m^UAPxSBwv(4UD`cj2-D z18XD&3obP%`+dv8(8@Kvvhwo>3bssN!(Q?!GZjDdujBSw1_^CKA??@y`nh@{1)lTK z4WLZ_QWRqf*|fH1kKp%uExt3wo2aoB=VDF%sf3m4W-2=u0|aBtgh1f<5S~*yLeqHi zw$n+0m&e2{!xuBo<;?Lv=VXE@(24!7U64n^Z0J!}w8p#28Cx~mYoF>#u62=qRpA-n z{0Y>GH%kgm_dQO1s2Rj9=@tkpG!1jC1^%QdB+~Kd&pz<0Je-PU0g4?j`>?h`S{fTf ziD?h@Nqex!T{k>;5+{+X&c8e-OBc8B-VxSoEmE-6SMc*Nlb!26SaT23!6`ePV#H~v zeSc%8S-gsgskh7a|JcK`2bWX?e`+O`YFPmzh>* zux@!l@8d&7qJUc~5G5S6v^Kfb7f53f5t7E^v135wWNk?K<2$4Tk727TWS&FX z)&1>`zi^28J&=hDn?4IO#KK^s750`*$X8gIiv#kSBBrdxzQ}a0C53KsmzCB{GS70V z1JU=(@p$3Fku>CCXQK_f6fTqY8AA=(stsFAnC3|A!bru;lsVV#%Ind`3uoJcl zo4~->#T_uk)P;*y7D^Zqg*1;;Q1Z73Gl-$vxy)oSofr3;0Zu6ih@-h8EM>wrXT*dv z=;+(?x(FvIrzm&?D2bv#uKN35zjDJ3X*5G}j0?OUDxE@`2U-OrkhY0!l zTgpNlSex-$axme2%5G21*58_tGtQZV1d}-f?7X}^TuN{%9)3;OY=-Q<4GH`^;_((p z{qnlPTs*&R2RpXv3{ooYWq(Cndx!Mi(d*rh;Kh7tG}=UPxcc!#V3XD2pB}*JdAb6f z$!|x+&+u!o^+*{mIZn$A&-*v_IqJMpt|(?HAhywCj~lK+^<;$d+l@m6S+5U+6OJ)M zP=Nub6FH(tOWCqV-X|?aN>!L7(f`Py1bi7jhW*14ayVMJSKTHW0LjfED6}*2@fE}O z__dXCC=nW!NMD0wAj1FF1Z4?VUELJ(M^jB?K&ac%vm$|#cNwrb0V)xDe)&Wxc;b4^ z(gJ_Bp9-7kO@lz&dZ17bGn)jkzo__C{X-I;zoBQ zNSxb3uF}d+S!}#qCgwGq&fmRl${S)>93##Y78oa3=~nVBp&=Q~9_1jsszAWa#Ui#iE{phF?O-nfa^!YR$^Skk%ONByeqpZS= z`qD2|wHwqQJ=pzrV^ybRGR9Koq$LSuS-yN>)i!?XHbzlSlMLDp8zd>6 zml;*85W?XL-V384@-ne*5X8SczkwboqR#GpKb~>kE4%xVygb_$uVric(vkZceyM!e zk0&|;jFRv2ND7mH7t)Hb3nf(%AEto`LnYrO%MJc@sREP_o5(MX!YD10(0(ZQcuRKX zO)F7!_tlWtV{LYw3J*o7WO!aTk&aRy82L2!AXMAq^Ys{+m>>jk{TN3yWE|0FaS3B$ z9MYHZ9En09kg@@LNeB8V6Dy)Y{W5M}73HQ<2ghN7f+O5)hRsXx9L4CQdWWt++!TX` zrs%lA%kCtSj)S^wilr02mTHL@ZDoZHXH^2ZXqpV)EtW!7X-hc@0PFF_fBj~jP-pPE zp$k!+T$m4pk*F$j1{Vu-M9eL$8e0ztCmp2lXAxqTMG6n1iEK0N$m6lA>2BukHshMZ z9Pg5uP!>sWjJxiB^K)PR0d#2J5SFF_2F+XS(5k+of(Y1`Uk7UeZf@MQ*`;i_UNWp= z=!Sto>37jc(>Bfa-zsC##M|gDE9_RXN_CAOM|z#v-*A$lkkQljbfi8=Qp%@sICo+2 zjGq~snc$+WMKFdCNZ}mH#8?6^GmpP#R37dhv(;PuyBa@dEaUg&jDf`|2U>W+IcDSf zbgPxc$a5G*xeGy<-1pgpj-UbwYMjeoz%XekjzJZrTt9!Iw{LHSpiPUyk3jGG3c9jj zXDO|iWm9kj)COk6)Wymxfh_CNcGP+s{ZBNX)eHk-OM*|-lq^Hcu zR-7{tClTmVbWgP}%{H#$xA*`=MXy&w?lKzuh93R1&1J+R?%yyZnhzyR@2c;WTJQAFcB(3eKQFvxKNE)^LKFFZnXgmN36G9ua zrc&K}jkA~}k@R{NCrF8bQp3U~oEzxk*2*Fdw3w99reJcYEJI2LlF z^Ysa7kz_H-&q4V?DAd|Yc;C|<&PWr(8jI0V#8%TL+w(Ij=8PiYHdmw0>D`_t-I=Ag zIqa*jr`JB~s0%ic>joi8%A6z`6N6o@|FopDk9m{cvcj>M`tDQWwM-X&Y!;2Z)WK9Io&pn2hem7jU7a4z^1PxQ>jXzXw9ThBkBN z(qTe6S|RO_*OX;%GnB#_ZIV2Lc}8OjqtzLo=|NvSXc@ybcu`zYC&>s0J^Vt2fDImC zx?;URcgz%X7E79PQ!8^`XKAJQ(_7QS?=nsjU0Axyq<)|Oi}zl+J?H=o1FZgzt4^X& z155-+0Ccw^2k&P;97uK&hF+afGryg66UC2x_O2kW(JO4_zlh0sW0S8Vjf$8{)nl7f z7ug*hB>L}=d^ooB=!5MaVEOEAJ0psiN=eB!^$srFC5|B5&iu(~f;YL!1pmom~p%!eheq zYVIBCSD<7LcwPu~;n-%fZTgZTUijTHc|&!3(n|z9dS8Sia@`rr&Bv{8LGdob>Vx^3 z0u>6wf#peHAWn;K5op09fXzj*AJo=g;yLX>A?$saUHkE?O6-@g?wSc}l>tAO*gUbe zN+X16x~YYi#ZUA!UA zX>r93tj=sMPO^eJ%;BxNuUF|f=QpVQ1NX7b*-wBcA`ZL~u2>rSizDw3RIyR^ADR~y zPP&xC6cK#ic9HlThaF=2niJx$V(Xn^-7~U6Xn~bSa!3%b1?R*(k;#N7rC}7B$ugSf z!%&B{L}oBycxj|d1t)4$A-tdvBEFJEiYPpF1Y5Rq`^$rl{U1zNectPwxUpsmx#NPrj4^Bw+a zUZ3uyho5y|EpFdt!S}p*@V^bx21B9T_kpN42Pm;p;-0`+FMiO++#HKYj(Z{7mERV< zFuXRvk-}>;-75xFn1poVCv>p9_ugrLW7~RC8cS8_aiP;B} z8E6XlJ!Xb<0$EWsj|@IpCQM(aiyEeGlcIcM>GLS zXCElIH1T{mKjBNjWZ%H+!CoUrW;)gdV`p2K_tm-8xw&Y^YhfWac#=z!YBK*E0#on6a$U=v9 z7y!U7imF5$XCQU?jbQgFG`d&YUb}w%iCR8*EIpd?1{SwIV2oX@Def7$Xeu_lql0KWi$btRm&!A67s-Mhm4#)z6dmv8Himr(vUvq|H8X^!39{nsv+#Zdl#!Itj z9|4kNAzbr*#-f>~ztP>13aVn;AvGQPsln@8o@Z5Tl{dv6k?e(V$?fM+fDJ?}!a6b| zg!C>EFH;Mmv~{e~S{h*XQmc(dUgcDF#og7bWEd%d&juZvw!yoB^PLZ9 zgw|(5`0_EFI|aOphTNb05;?skyWIWaZPB71*BwbV^9a9iw{L$9fE8jDhwpXs8;6QR zzr~#|5=`CJO!)h*0Ar=o*6Z=;PvqHG+T;WYQD3Lfxmp(p76qLOqt><+6L~ODMK(~- zmRCKa;e)&SLL%h>rG98oT{8KVOVhH=$}|gVV+4G51cjYs@A1{ICzO639cm2Vw$bah z$N>9Lg-XX_KEn96Ygxv=+=F29o;vzv7YeDe79)5uy;=6q;t=qV>=UT96poE^N7{dY z+&%PaL4$VP*;2jgUEem(vAFP3$@68-`_|#YA~0!WiTx?|*>ZA^Uza9(BGg9TG+0eTK|e7+4aB zFp2{RA<$+90H|#jvcnI1dVT&_FwnKD39kea$1S4KM)fC0bOi)}0uV(P%7ewN-iOav zMpP9Z zDvG|RtE=a$`;l~qhv@yru2||LGLk__g#bHvcw@8zA{HzWPG6~sHjOD|-HPHcPUPHO zX*qK2jKMHZ)bfH&s81Gp=P3hG&Qtl6LEp1^dMDT3;Y@d^)Hqt}QoRRYd^T`! zpK47n>6O&=R0Ovoj1rPmAprFIAE|i%ojmWU9x-5xpMuPkTO<0}{hvZ|{b$0-hiTE# z`d_V`rs~T%A?||cZ}wX%mnmWe)4t(X?-$o$FK^ahi3E)h$4Yw$0a>w$EbMNaX}}ON zpmTbT@d-j?NqS2!0-A4 zfgIHJ;5z3lWo)}!q2MC#mJ+1lriU8A7>XPbFD}7r8CM5y7XX>fcSt-%-aMA?NJS@} zuVDxp6?J@yKF!z?;&jm@?RHGmE+7|SO5=vbdo0MEx!ffix~+#qf_CVGn7!nL7j1Ei zBTP*^#UxuwsmeSUXibvqjDc4TIFv52XC-l z5^F>{7nVd;waXx+f*x0SxwPuq)*hh6|LV|(a zxYQ}MswLv?-I%HgH3)yt2eoA1yiY+ZT9UJ5*Sz_j@q09%kNkh9grP(sfWN0b%)c`y zHgat059x|YCh`fI_RX@Q#p8HZsD)UZFy}y*f4&kJV5y_k@ll1sImH0kXVxOjyh1K| z9%n?D!y)~P^)8jTnMT;7aVE%3&IZfcef{Ir>Mp_m0WMMI3O3pSXWhDlMHkq zf1CV)$XlXUf9&uJP?r*%7oF=r<+H;2axUJTF_N%zHI>pQ|9H@8EY|&5M8SnsB~?h6 zgo0x#@Ja);NGBX^nOJ0N^U)p!C*52Gmcjh#@Igv^2K>c| z%svd#hO6lPQ0{y24W|Tio2>cL)++(JW*rO^^jE6Y2;lhWD>?{?s_eq9KJ{C}@PP(#Y)yJcnmR+75DJkpUyqK{t^g?73vE`N?tZ!s%E+memJ|+duiqtOuP?u94u&~ znH2w7v6CH$^WCG>Nqd+%rCLTVlzF_x5D@CsSwiKz=6V#aj&H+AH{o8H0@q;V)>TJg zruZ%6nO%(eX0yydeAEOYVdQEd7~0jCnfF8TA!o%7xN5?NVA1 z>y#5sid?l8-k}}kF_gcBwP8^?NWjYSox0l2d;|+*K-n`x4#NRh$h*4)e9(mHDs|L} zV(9AG;4B!XNF_qE7_hTgxP!raMv+;(wd+~z(%+s(E6uy<#XCa4++;oyIF9*~Myv*o zx`2&Ad;`SQY=?Y_p)ANvbq|t48Bpp^y0!*FSeHWt+a+K#dt4S1<#YY8_0Jt>2CG(g zMEHCr#5%(8-Bqr`EY1w4ZXxK+d|i+UM)9l@XhT_2AzlStkdHf3F zw_%_|Sat+-!wL73lQGk(1`TsiT#Z@#+*YE(VYLA)67SnW9}nhVD7>K0Eb34sc)~zP zS7Un;&MR4om zE<)_{M@-MjkZu#iHOB~RU@w1Ep}_(N(IZ=!82oBNes5l9gj{gQqg<&?H>VFuvZJiA zHZPw~g;%%S=%!G-@r28lN3VUyU9Uxts+lEv%jZiIO6>scJC@Vk(%K- zFMXDlJh^7!-KG~=q%f%!sE=@@kt8yys%()nf*k?tCs}#VH(rpG`H+biiaI*bl4_L~ znn!ABAMYu0iSU3zk@hE{HIS}8j%2B_5rBLD0P>eyy)`o1J`HgSH-5mrz7>5_=`TZ> z(*OZefBLp^{%Z0&vngI>sZ_2r$-MFcUgRO#{%z8kmIm?W&kDonx{=r6NjC;M(rrh-nIY%J zdB8~QErpjcv@yzoVNkOAPx&fZ8rX91oqY|ca-Fr$eR1exgAGi@&B$W`zctw{ND>pP zC3jiDI3nv|c$uE53fODLXz*Cg+(5SyF*32j95|uhaI^A!dOQ3a0^fSFF6bMh&TE4DE%r2`q%W&)QwB1wbfOjwQ&$x> zZb|z9;?Y_Qxx#i-9jog|ul##0<^)IXvH#|ph$Nr>3_`~)y zmgBB(Bb8bv2^i~*zV`DM16~BTmr+b8NH~qHrKA2{<0tvFus$!*oPbKXKE4Q&O+O#5 z`#$dKsm^9!*|V&qo8FxJP0ti+$%5c6E~ERHR*Gc=>`tmIjxBAPR`dvt%=#pto!QFA z{+j`U3bDE#qM~r2&B~;}mlM3WDv^4SLQVZqqyS|n^MFPRiEe9uK<(WEjI=y_u^t}B z>A1?rUQ7eVE>vyDOt4=<3TtK1WLTsgZ9;9M`i!yIV5)O4tWj=Z7P-azKLDnwRW+It zNw|G*aSOOJwy+V1`iuG_` zz23O{S(Psh`P=@*EZ}-^nW)Con?r7QYGH6AlKT?w^Z>>~My$YpOE=B*hyc|80CzP- zYUb#3-(DU9k7vo^%L*`~jpA02A*pIUgFsl_-ko9isT}^Lu}~C)j`M<3r9|BSZ_#XO zPrmZK@#uuyUCi+ynyNm+dr7V;DGYx77`?A)w|(?+!28(x{DSlhb~ylKQdEj_h&`0b z{_^c6Ayl&*FURzu-^mQE>Rud1m3YCUbv#6^X?+Qh{PWf^ELB5CyX^Man!smRD9YKo z^cdt8M_x%U)?rIG5`@=UtQ1w&CAc;yo7@(z{=K{gKsFt(1|sB-T`7NI;Gn5L66o2l zK@?1vblZebo?h$^R|4zi@l|4h4`JJ4#>yuG~hbDj1WI$w7JXwc|YKl?u7mUPX7f;5Wl?&0k& zzB}q>TX$(POT$HgiLD2b;sCo!tQ}6P97033HlWYM=!8K=xx(<`AFmxjD2ugIRQxiVke-!zf zNjS^q4vC6}8pqVlhzlSAD-6SZ3+!uqEH}5+#ovB!Xor5KYxhJVzr+xD7qCt2Jt*SE zmf*KfWs>L$(hOJR1_*vS*n*hdnB#W^D-v;jBlq@QjeKoo*quk%#t0S1%;zIprjUk)c>Oz$NPub$}Z^wYf>6`qNMo>t>e=+8=mM zg8OL~Bap-ux8@kZXCDZn%yg{yG9#}L8@Os-VH4|jztq2vQeY|nENPIsSZty5?web& z-}2AB!{3DSGciJfiSPQ|taC}zWA9LacmHWRc=f1Uq%@KkM~Ha)^$aU!tfKwG-~78$ zVogm;(e@A)2>?Ld&Ff)WVZN9!BklxN9L_b&V^(y2N4jt&dJ%4pmm>$QKS2ZF;Md8* z&tc%CUGb3DMu%ufR<><&rZWWspyZ=y5KKmXs<+viSlim)Z>z8AAA|*0K#WW9Jb|$L zn@q?ih=|D9`2M(lMLWWAa3#pkhb7rPYPS+{nfp+#$^ODU4N=~{Q(|lP@>ijs9|hVS zvIdZz?Xf5;!OyxhmsXH{YQ^9d<0Wb`?E zp+7taPv>=H>(n@yvsVh_0*hrRUV5Gv;-L^)nSL|+^FuT?)X&xxE;oZMEXrxf7!IiAKMa9~PvdgspoA#e}EXDrQP@v$$>ph>*ea1O4 ze>diRA8xzzlWV`D-Ou}|7m8Qnk-(%$b_ZxS89OmGHXpeme6leaQVYBP$XuekQ30ay zFn>@dk0C59X)nQwDio8Uk{!+hE5(bU)t%@_q~+>^0(rQX@nV$W;$#Q@L$EI9ORr*6 zk<>dpnqwd(Y7f5Jgd!8PLxW~+7QarSM1*t@;q)fN5nV~1pUz#ae6hj|hODL+fFt*F z>mLehwPQJR2^Yi78rD2c>c2^*vBLoOEcMsAkQs~gT~i1egU52}r`1Pm1UrS!cGzP( z^HCV0EF%bI-(yJ^C0cI)i|^04*q2nWGxykpSf~86>^UgW&$ah`#iz0wfrww(H?|p=)AfJLu4eSO5@_P{})< zJQu<$F%c8?gMR^JPdt071mrSfzgfcibq(i(TDZme17hkpm_s)GkS_!W3T&>t8_i4- z#!^VVVe(aIp(rYq{L{IHBCxd>B)F%<0BocTu}|0u;=(mBe-~LbAo5U(ohvRw@$LaB zxPIx=iG*&j)&mGo_0MIS@Y6}JQE(}((4}`IB#g1F`juqlHEC*QYV}g$MGV&WVnIRM z^nm5IM}HwI%rxN5F?B}+tO+Lva~8F4_B%o4cJrIfoF&&Q!0=Kk{v?@C$q4YlZ5Be|*U1n<4pwv+`0K*v@}#_%#z75Z^B7=Em??A%i6SXK1Dqd!9gXnnrkL zartTsJ&y&!_{8Q3AZel-eb53^i>&k+Lj&$OHXN=6~H(UZ*QgyhmYpBp7*YiI>qRASjpjCixWPo&^X+bF}5p4{Me5s=4uZhLV zGZ>C<8Kl9=qfp)yl%wkt=%LYd)9CE=mpp+Rssv`(p*&m=D$EGVAwbgp^}+jyVhfOBH%pnP(-F&!1|U1oZH_^8Q~vb^Nri$AHbwvG)2sa;tK~s85F13f?!UBTnB*ngGW&eL+_`XuMHgj`# zF?VHRVgA1g3mfnn5(LkD4>3p;QYG*tt_uD@$cU^Q5T>wxD@bR!8u9mxB>tO82@vC z0kU&(zHh>~$tXy`Y(k?U@&f+(mLdQEP!TfXBI?>h*I6@i6jGS|HJdC;baL#hkp$UA zZLDl5lxlGK4S|Rwly~-xb^amOC-~js zPK3e2zCK6gK7!rm&PBGIP2%&Th^X-mxHvt%I+@z}pLIt7E5vHwXoJR!uM9jV!d5?` z`tm>nl+)IaVV(gT#dE85gKSukKByJ<@xy4}RUker{b+=zsyiSoz}Cq|LfQ%?L>UZzrvBrL#=*a14P1UnrlU#r(ZWd)e%ljJ&r%tiYyTy&`)F5 zP-QzfNTcz4X!Xs*;}P*=M4Ku_)`Z}-AveZ_8Io_S+eEW?ShdDPwNyjLY3w-Cthu)+AAP7Y(vLxS22e!}kmga7w zPZH=sQs&&h(vg^<|L-}(-?;_6U5}3x1=CwfAkxbX;VY&jpwRIz+l_Hf$MV0Y#sB`n z@LHU#l!+v2-bOR%COkmEw0X|{XJ+8K_x=Hw4mUi#mF;eS`{Tsoi_r;N=+!!4Z3owt z@_XxVX`_6zDqu3!eKdl-@n_({+^<;1jS$A$pNoG`DKqwMR#MLchlBcvd{AXyX$YQ#L~G=+{bejA8!+q*1+ z0StJ3@!UT__?%9Ak^Jod)6ZcH(9OQ`URUG1o;320{PM&di_79?@>{GGOFwlO3Sr^- zy&tiLNfYEZ`rMY@$fndWxncxoo&hRpmb5)5c*7%u-j7u2us4x*Oy!txYO|Dln2>_q z!2`Us0a%TMO5Xu7v#XyKB{+rIiNLIBruhVvb!0l{rrnwKV2c{Yn@pIq%#vlM$i)Q* zvcA1lO6ONEzz?K1Z{z~J+6o0v6p(Q|2(bEj!`fFL@5L;e?*@9X>3E#zP-2pF{pnj$ z+>-?}zJ1(h-4~ZF!6$y`219E{gVNzR`3^OChMcisN_6%``%izi8hur9b>=j9Q?W(YY#k-u{>{CoJ;gi)r0TR9p%4rB5cklTX57=qTOQcqW z=-QKk{#<Of z3*Pi`0paekPm@EAreII1fvB1f!g&8$J%yY{SPRIf5t859>7Mgp7;P4gL?ziAwf&!o z?Ut~Yd{D_x`z8COAg~@M^7fFeRxJniO(snaQITi~ye4>}_x6OpT*dZ`w;LueBbJlq zEn?rhSRQq zxyO(DwN>XESHb7^&w#o)I87}zl3r;~G!azOpAtF>kOQRQefErdLrQHuC_Q%wyXrb3 z*gOL7-_aj$7%A91%tw9Hu)h=QT#EJT2}lGKP8zD|n-!gm2CR=%Ae$U`-#ZJUt&=-wwW0s}EV^(<)49drtg77ZE>-u(T$Dl>o6 zCs&dXl5ZL7WN_kUNK0JlNpLE_wM`AAl{!(o+~}5?W<-*0nlqM94g4l;_;))0kN5aW zgBo6mopjT@-BOS3`Tp+CBH?KzWT!isfx}*{!RPG-z2~k>m<%s(XXe((3nda_?CKZ` zi-|w47S7H-9SaLXj;s3lqvwxkSE`25quYZk_aR|LkH+=N(-R`f)z1D|GTrYJ9Cms1J z(mzSERo~hU)5HU+=38wo9l>r5ixi(Z{?pRyqqHT&MOhhhFgoP>a&1g2`|IHC{s^XO zyhY6;#HBU=h0!G&b;#mxQt#0`Q2X>cie+ID;7w%s`A{hP1?`Jbt@=At=@?B4W$+S1w1=LGqMrcX7g?jFB195?a zkjoygcTN@RJ)oxJUL=n+>2u)yKO92{1>)j_r>8__Y%c|qzhv!@kUOj~z!U}@D}}DC zo@vca-^(XSWpT*w)JCZ1#k4RI&%TVf!;K58r$gM5?OAY^ww~swAlv+?h(yGu_k8?L z)o7*3VGzR1$Wf*=b4m?bP~1w90Um!NeGjPVW7K~np6U&1(3zHCZdJ-L;RCTWPax~5 z1P!7?RRmCe|X9Ua}Z!^ZkSqWN|^e`5Lky)!8a4o>vXP4mo_ZE z7n3oh=vWMk4DR@xuB+IdA!2D+QSj0Erzo2AY}Q*Gp=5;P4E5#hk!N^*UfK3Hgz{fm z!DgOYmD$aX4g_duj7(Z;E9=mu#d=0yOdt%WvXinWhjGp+F7SX{Wr!)4%5 z8&8yzNq&$UKzWhsb6Q(|DT<7&T-~WAIJmgtheyP7@1h zhWb?rnnt`nmI#*rdRfq2>UR**eMoF*ecJWhN!hlg*X zD!8|UIv=H?bQlUk4ur0@8kz>|8Wfdj#IVx0Q{KW_%KuuxJpPt&2<-gDpGqPxMo1k~ zprZp`KUt5vpAF;vTd;J{-$oHHEwQ8%j!!zI1Tg(xTb>zJsIqpj|d-9p72} z0GciIZ)o@r6cvGlTbbt2$mIm?EksLqbwg=jKTV1v(x2`{d?I6;M*q~)?N$$#`6WPJ zUS8;yxMV9VU$Q}kMbZiTmlE5-RF+a+@z3sixTtR&^{6k@r%^d4<6+C zugov?3J>Y&!CTG$$=W&B=fGhxMovZ+4=bvgA{yB^-xP3AbOoK8o4Y@)N<)^QrsLG9 zT#bKSQc|fE96YC}l;G*G)l$ z+ewgVmLEd%?d=I-X5_?y3mF+%2cOP zwiCo(de3%WSflMK_)H!19Sc_epqR=f4P5K<%u(xvC8TnqNfi_|ibZ_XKHF{ zg}|;V=%O9`EdrAaUsO&O@`;PmbR_l9%BfbbIYzM6c=u%*1OB0m%~e+~kuWU}NZ@v1 z|6(4Au{Az z4z67~5a}d|$WHNjZaOPz3hgyDDM=VOIZA$PZhp_Laj-LMj|1p000+dxUnunS{6wtI zr;y!G5*re#j4lXs1m zP*7lynWv0-w;F77CpvQW?^-}1Z(j8h#izVIKkxj+=W8H;I`N8U#qX9)>A?4-CGo7s zI|(OHN!Z^{;fh2y;u91^uFWofmqQT@QoT0BSKNAmFt@$jqQlmI%|Q93MJ!9$XVm#c zZVjys6s}+%I7E$?Tt&fpFT>8u*_VIJ*a;Z-j>zvvQckKpFqN9NTxs(bN?s@)Yb^?ZL&Ocosto&DB=-^fu_QxQoZ5c9da#}L8jYz?SszLk!2fvJ#v|Ro5 zQ}Klrpz0_YAM)h;7|Sz5!u_+5JmInO*@Gujv#@I;mi-4T+=M?y@Q`aaGu9l}U+1Oj z>MfS4r2>7!@0rSPOc<`5X}{=S?#>3|7-K$mOsMGkT@NeE?bvVSWy0$ceGfN9zkI|Y z&qv>UYT_!Fc4v0*ZQHHXD+U%gRDc=Vcb^ zt_%$_tuWPqVmny*o^gtEld$DzGVlyVcSo2E-I$%%33Ccqm#xF6jg>#G1m-}Vq*q;s zXy3xuHjRQw#a2$YD9 zN%U-KO2tw8{Eb&E>fP~W<1$w2rZoOPoSkELCT+B>W81cETOHd;$F_}*(Q(o-J9av@ zZQHi6QSE3EE(k|89F?g_nckS<-u&cd9 zKcMjZn9RI`lRKEaX9*x%|8LBqIGCem7Lj4zL}f|wY@&w5z2-?@17OOK2|hAMh&mZU zPTuY=B<42gxv8nQ<192d`a9Q%{5`m=hW11`LSk};1KMtT%MpphsMVYZgZs0**<-9w z@a9NP;1*^Mrb5|}Mjc2d1RFwj56r*gXtNRu7L7SFg|XM>5Al`#3-_b=Bi({N7BVY= z(&{3tq-|NKj!Hemd3QC{ukLTngxTQp2|(cDh=Z&H4BbITptp!_bPQ2msr3HtPG*AW zs-{yfImXS7C*=eeY-5AH#gtn=KUA5YVpG)7l9ufq1UAlY_e4Lps+#Nq3_SAQp>@ch zJ%0vi624)ajcL-`X*QY8+>U9}(cWf!+L}5Lw>Xmm4|l5CzM`f^NRrTbQ40xg&e=hmDqN?nGBj`rn9W4V5w`UWAAZ(Il^k^B$ zLqbG`r0_qA?0!V|^QfaM?`)9P?{Z{NwL|zdo8MfL%XewIe5@;WwIS)EeRNk)7awg zO|o$G##~oR8Z7z@%44J|TQLBV*BZHZFtT2%HIQDMe#}qy+H@+DL8(E;3Z_ccAGKb7 z-A`U^VMK7OjT9fJEg@O^Ev+7f2mLxOoY~4hTq;e0FTQr?oR|16C%R`7q}($PUJds< zQ5u}k;aez1M<@NroQ4LcnH~c`KKG-gVa;5YXREii(s+3_iH8LhKch*l%TyQQIWASg zftPT_Ns51V;1%0tzMg{VTTb!6PQpXL<kdTq z)I=Tds1M(5TAFaKh-tc-W25K@LeIk$<0EGb)9K7OO-cvZHTtx|m2bnHLp;T!n2bje zLuB8=Ir(|#?2sQsmrnoLi1BMOF^LThj?<+E{@gfqSz+o}ToD6DErLZj!2lw6b7_*1 zIA=3f!d>p95ktoJ!I&ue?5M%6$0w138Ik+$e`5=!P0)q$Lc;*i*)NmHZoBQGzXzWC!c z2F13w$2{OHz~rFH(vmBI6sQBuTIGM8ph^lMgl`wGYTc+FW+%+Y!VPS%8+i7GfSij6 zl_7IjziBkktE3dM8b={XO3XvPG%J%37jHoRd78%tL0fPsuL@(SY+_+SR1bIAqbMy6 zW0O}lN^{*rQQ#grht8-fX1%2sX{LF`ANpPi8Jx2lP7}_ksIJyXXN|B09NynPld9<5Q zr`Vpu{_E7uqmb|Yf`@ho72%_PWAGQweiRVDp$1?ziP2ACs_ab7ixaArL8Gg+_ApBO zS@rF*qhrJ*JQb$>W-{FtE|+F;1Q8KSx#5%nP7;@(e^_q)KihQxf`YA!`SF* zcYN^*ZRv`7mtoM*(8ShZ!jtiQV546hFZa$*b;k@tL~9`Kc7JmXK+5DQ!IpThwonBs*73Aw#p zaUtr9l7D_BShp%rYR6-+?(_IhsQ!J5IjMoc`bXTg&h_>DBSeX;mHne1hkzg()0uu2 zw3Eug9zj;|()GYTnF_)a3Tm&}_M_%xD>fEUm#U;x{cUsW#`@p-(WOJ* zd>v~Rc{N*jT`z>!-QE3)7WZh08CguKA%*5%a7bO1Vo;Z0m4{bc&?@w>@!^QFH^AjI z;ZEKot(BqtkL(sayRNg+*Y%{=hU(E$XxU1DXpLJ%V&42h*0JHJlckZA<3~bT>TsAD zW4!e9XZ5h%VuvFe@9Ksg{5+x9s!I8&0dU^SGBzU*o-fv$Ii2R-AFt zRFtJ>ycAn6s#1Dym|dIJUSQ#GV~i1n>kv2GoB}cP_5kQ+$+t_D z_;spqn@LVIfH>+N8QEmARs`jK5R96tLFtFCKm@Tkz6rHxGU3Lx<;oJ%Y(oaZAhu&o zLhPC&LF(ve8(iMp1h!O{J!}prONqo#wFu&7AQbt7pm#o2a#1X(9O)vo*eaCVXu@@9Z{dDXQmbM1qbU)RDPW+O~G0@#y&y) z3X+Gc%xnSAk3K(I#zUEZwSED1N&2Z6-Y!Y0* zMU*5{w%WwaAIq6?fp-e`N%ATX6`f6e0MUFj!Cpcs2=4L+9Y?Hp_-YwHHnbS|cqrC7LNCyLa}1x~*N{E(acrTWefos;c$*y~Cz_?FcKyMM4c@(#8y^r6 z5y7ImaKeSCWNzr=)ZBr32B>LEyj|cA>$jeIxYp;<-31?mDnE1V92^{uPn7(?f>#9M z0tzXWP`Q%(q~DzYX$J`6N`wvHk5QXHa;5e zcrm;7`t9%X2{-7^D>jb2N?_7%h!Czz7Dio!hgSm^%J~Ef+8QWjo(WWv5)xw0TvK%1 zMx4fe`-2G`MTi8&^YHR}YB;RRFT;>(iDpWD#&B^TWb3e(S?Ua7a`ZZR_NNr&2I7L6 zAwNEa!G8xb-qbE!qqrMS1Ae1@xFO`LS#I!;+58JLiH38m+5C|tL6G4=!!WUL4B_@S zhe2}p@LTjJ)F@Ynb;Ae_cCzM?N_8@2fvQ=zV-~pK#_sy}u(m_2vx`wg4z-x`qgQT% zGbKOk-5Dj&YE1Pnb1RBWjDs^z{vB-Svv}oQ1H_Qq3Ga-=FFjRNw9%8e%hp;K)~}v; zh~4m0TJkzp;sHfZRV81ExUR3yfRg0O?d(31ih<6eyRkK~S-_in$Z%@65So=7$@3;& zOVd@sk^IR}%~63L9?OUQ;-|agqKmF{@#kxZ%S@jJvT)Hik`Mxa+4I&XZ!J>ZT8Kbu zg&{qUK0GtTt_H(+k)AsMDclc0O-xsOn4$ITT6A5+*>SaX#gAuWVNZtQARn`V=u1JR zQwl}r?1c?d5wtWj3k`m3zQ&rAdVHdO)er0bFhkUE{0}EK5XYyH%28abxr&5+-GJ@| z64QSIQ@$Rw?|MqBK2ztF7z*&yZA7MpQVti*eitbiyhHy7A+;pdH0cOHKwJp_j}VfV z`~O2oF)1D%4mK7EPSO7$WK*Vwc8c-a)ep!}QFRmw$YMEJvBad51cG8UJlKe7Q3wi% zA_{D(v_AejA?F?2k7aiBn(`Wn@FHJ$Ky+5rcg99Me(*08oie&Ha>ctIcKrMOJ-Da|e}65A{UqMcnGC-( z0sdC6ZH1Sh{ugHo&@o2iulHUuh#QQZzP32^h}s*QgK@Fsi0wqs^ZHA!H`W{}A{OTCXLyDUSAaFgY2 ze}1mmUHell?!cdBTipIKZ0f+KUbyzD*$zyW4;C2>g|S5=K?!2AM2R#~ZS6rtxM14} z{3+Uq^0|VUk@?jgOj7b$OCNdG@HIpK+%j!+v!HjES$Gsd9#DafF-9$ zw6RK4>}Z8!s6$)dwMaZRF;Q6#-Qt&8O~SmBQ;pKbqj@o&xrl0AR9T3g_eP@ePq`&j zP+zF*h~RJ1)~2osOW^La)5^70v~<`(nU#JAWtNhP4c*7M^4ddcYU&Vilt7AB&FB;M zxyxpkFZR`S9HTW~0eR;y5=EaGp9{@*Kdo@7iZWBcTp}@`wmL*y0BfRTQnujl-y}gU zi%@heb#-}ZCFbpQO)ah3+wI0?;!0Erwq804yodPmT5cUIL{!Mq5f)P8FK})GT~$>!MaZlxIyl!+cm#VP-zY9a!9&D@>K7M{qb4=v{)#GcVbfnVE6AzjVZwlXzKZz$$`V^D&w)l&Z8Q$P?eR!F<3 zd&=4sRPTs`X?l9IDzP-TIbuSkKTf_=Ev}S+v9hKlby8a9g_MpCukr0)y$jMZvSjE! zmTUm+G0#0`v|^~q(Ovwn;-J4suCA`rcoacs#HmTCn%ccK8FM5|>t1u)X*CJK`t;2z`AW zP)q-DyE_D$)owkBbp0eZDwEv$Mn%LEot`y149w)aBz{OgZTY)DJQLhNn#XB8IE(^A zVr4cN?K~`?tS9>>-jZU;Hp!mkXfg=6oI+Dl9{&~W(YVHxWM;0<#uK9|{J^hRWrF7K zsJEQSePSpR^kUhZLzRh^utAz4Eon;p?(syU3y(Aj>+@Vr_!qn$q4ad?JGAh?(L-y;xfKKBFQo5jZ)YhUC(op(POM zuKqbZD&w}hKeba*IkK~vBq&cJJpNT;f(L55cLH|MXj$zuZ?2a+BPDbf@!b2VSZ8OQ zqT^|7tyVYN-7DSkz#;!|(gl4Iavim|^yG!5(!Q>*zhYpi?zuTOuD8iedIw``9sT1Q z=3E4vhi}@`mb=lDu8(Dw&QMZPJRTk%%JKu3Et{kxlgTU$Ss<<8Dw7iv%PTAHcR%^! zSB!xYCnY5{%E8Nh;~Xh4>t)2ZoWU_A6FRqoBBkb(sb4S{_Wv)lle-^=DmH?}-IpF|OoIeY=umMpyBA?xGP#fn>AgEaSjd(P$$0qbpm*xu$zST|&wnWZPca5(K}f;SyZww-N$pFw%S$Kr`4+>ioR z_2@DmF)=ZeuI|SW-&Y8uOCg(DCKv{HESS6+Lb23a#`!P%3#*-`&c9&A!!{>}MM$zH z*7j31T4+vwA~Fiq6oHw?5l|g{Gb_ElMz*GkoMd!xZ%>t-Gt+F0r(g5hSJemA28dK+ zt*dcu-MU)%heN;Py$ZC*v42>bVZ6#t9r-n5jg7^7E(zFoZ<%p*i7C}qB$9?{ z#Qa^bxm`QPz*4Lue(wD?>Rv=Y|CPRRMH2vYa3qUoI`VS#^70Y_ z7q2!1QF9x?V>$`5-!bX}mPBXqa=!QkDdsNrNsL@%X`Q=X`M7$cYc#fUlo~tA{LtKi z5z;KD?r=LpXE{DR zcu?^StYuc9EnpV8%U+5~3D*ddKwRL?E#8#x{@9cxwfVHOAVEvssosk)8W#9$$4p67^uSV$_G?Fla0Uqgm>#aD zv6qhzMU+}8=N$If$&&IbHi0V3 z#Ozya)HgFL%J9RPjdae@^NOz9k_uAoUEb4GV^%i{uqc_-6zr}=)~a}mj=kw#8S8ki z8>B##HbsrLwY`W}lrS@!&f?}kotx8Y`IE(wZpzu0`K7J|btpi`CcRkefJjF1^D;@O zn7}s_DCShL%N*dFTJs>>kdNDn+W`^`rWh}nHT35%ZhdB6-ih(!J3q>w%2bB8*Qbln z7zD&vx2UQvLFT+dK~XDk!dYlN?StiZt(JlTPGkN7n_wNV z?z5fm?$y^FLkAJ%9W9U2PW?x=}n$WkKkvbtFa$e@9X4Xy=wj^FDaTMkLMIx-c3D zx}jrWsPmRSJM}RzF-^md^JWPNILnRAvOEnzuBY0Z$aE`^qD+2o*@IVJsQjEGS=GAP zY!7oGqo7EsyD+Y%W6oRK(WlW@>=|)mt!;07yyqEM$M!7G8NtF@@A0QT-_&>;&g0=9 z*?d;aR#ya+On=MKKuT7F9VfmO4?V&yuXyFWZLDfnUt(&v&`kCb z$C=QaF;F^_xD&aFv`Lxxy{CQ8-$xEKM^g_R2~!21Yj7yevAAUO(<4|z4QH&bhVibM z*#N2|JifdZ^NWi)!$($sb1g61d*k8S?6bT{2wNFhGwR35{LDtz*{h+k~H;DtzZNJ{{?*nCff8P(}iHkeponJV*Ivswz z-$BQ)zD@GJ)c!J$=A?lfOW3vpBK_Irl+SjPsf*%KCjf;kRX7f2{WAfl4Wc>)c+|$mBSyH$gV(# z9gWs5D0>7cdHz$W^sw<{n*byVUO2f&M5~Fc7Q|AF_Tl;U+0IBKIe^FK&!3bO29wCq zynx@`%Xhw)7Qe+(g8!O$>*(kNP%vYsxv0QrMN03#{6=`ugC0{Ch}Q=LD{4K{AmHEG z9;*rdmB#3%HEKIc*HTvp-rTlroS-!B{@G8#vu@VaGEE0{aGmqbAHr#eg zPq10Q2HG<5;KgZY{-(3P(Up%=U+K|H`4EpsRWx&fQ2vpwx5LO)5$o#dnmp2)n@iwX z)wl{#S^v|*=vn!J*<(MsriaiF0%(|ao5ma{j&!70XkajSbXe&eFt{k-;45SB0_y?x zv_14@^c%jOLrJ#-G9{9c)mfE50xudm84C$1oSi9~km(onF$!B_x7Xh}j2|*5i-2I40ZB^-c2I-*%suO9)={$mXSC^LnABwo$AXT6G4E* z?!3H-sYwKgz@r9#QB)!X)Y2jwJ|@AO8xr^ZwBr1m>3Zc5EH!v6?-74m(w?H8t}Y`h zQ55%BWLF=3`woc_0r26Bx*uj?UbW>v1TQz;vM*R;x1X#1NcRmC#GvYYR@a)BHLJEW zvVlxfPZpW2uFHDATQ75TTm31W(E{*?c&jbD!+R7Ik+f8*WFl?&1X(d0{)DI|5$Q-I zK8VVd-?|bzxZTo6;^uC#2O}^!;=z=F2B~?@6$8%ftY)kz1O-1vVi2gV>12(uKc_Q# zTC*SMXJ;`nF;fWZ>+73ET4C?*_%3br@2;Bj!TohyPRRQQ#wf9lPcQ|wM(Rn@%?jDg zJKkQmMJ=vAi6+Ff{kgzrQc4tJ89&iGIwoF}#jh}kP7mv^ z7j(+$@=*f4*Ry2DR7+0LI-9GXEkjz_7E;5*p(>c13#SL*o~8dX>)+2rjSljr2}hAR z=)xc&uZ;FwX6_*;@sPD{_LElS6{zRTWOgSvlRTzVQw>SqC+Ig>_7$ODVDzqtBg*n` z*W$5zRKD)4s8x<}S@wac3jqQ@`Rnl{L`O zrHt?fgg>!*31`$!(8df6mb@)KDKVhgDjB$cTNiiv=^Q^haXZ@C#jK@#j$`url?2}w z5~9pnsbu|e2M<6}3-o;>vTC}FEjsBSEFDQ+=<+~9>Z)Uata}&LO*ILH&i6KMOd$+wr#v^3obp{?r#ZNc84_ceBJZhy?xqWrgQjT`tZeZ)8w{i6qI(rCsCnxlL`Hzr7RED zItXUVph@Ut%?XcSidbqbLcZ;rGk%M`2&j)EKwpYHB(e+OP$$?g$bQ ztvNYc=7@;e>RzOuP<`++9h@EjH8nWjcxQ^%3%GXG6Vj8Gwj{FOfSszPdE2o7NWx;s z)mvKR5EoR?2c@CzAK%!}TfNA`oh(-xb3+8+ilK0^KlrfYnefeeFsb!!XCxFJmbX+i zKGVEClC=CFjzjF5c!hiq-mHK?EcOf zViM~{`<(>N&qwjHay(zzrp3j^6g|JZVS_L_dyu0ZV8Kk`b38usv9U#tQxB}0+g#pJ zfKwC|@!G~loTqdem8Uc|?pXkBP+oFq$&g-HjO6(F&6g;IF7NNr$0IRFMf<8|^2~2D zkGlmh^dL#D+`%-^2fd^e6&)aMXE#>3g#>d@y}e)UsJ0#-IX*!!iKTyaBGB25Js~3c zu4F1M^_lV1{?=aKsDyxkP*znP|Nh-a6zzP3%)Fzx2h7YwjF0!R7^Gphif^mGTYb>u zdogmcB|Vk|c(Z(4ullgnmnW^tUwC)#8 z>Jl$aXJP%#J$XimgGD(Wi zqvLvCUvKxc%)l2U+M03ecM0V8x2zN%Z6R|9!F$_CtGkJg|%t3hoQX3x0g>5xDW+Y(uld866^_z@N7n(?`@0E>>wy#i7&*&`L&EFw} ziZ&AP##CVm={OOUmGp5fSm#7X;nmgEL!!(s|LP7;V*^;MQN9{l)6ZO>pe894R^E$< zgZw{NPQL&u!(ZL^fkNDUhA+f{Noew!jwbdw{7)FckVz;twy(S7jANJ{`zzeB7iig3 z=L33hZ1_q@1a%50D2&=V`*LYKAmsT;wYOB|MqyKWFbq|+O|XGqAC>F79a-?qSKF@( zmF|Rzq~a9`)*wYs4zClxx94muE08p!oh%eAu&`>r>(2|33cc;DJ>giAt`_XVszE_cLkh`VK`*7F`y9>?X>G?>riw5)i4e^{KJo*mp2FrF_m(*kw<9N zV`Hbz#$W%JYLIbr<{U)jv`R?F_2p%2Ur4EXTY&@#XctSt+vLAN@DLH163{oeV&RdI zgNu(xASDf8}gcqD_s^cPMV8kin5*jmGr^P|)hD-c=Z zzJzjH%Pp*qye7XFu_e$%CD2C^E;%k%T22kjnIW^FZQR+M1H|rjJy$cPo(4}QHrY*P zCMF~{@H=$Q8X(=9!||1M8!P}VD=W*EHM<&RjFw69hxF?#NGz6%A>l&lVQkTHPkU8I z2UmvYL<#$Y>ke)k+ep;w;dpd3w{gmR$>)Z;tgNg|v*+G1hLX$UH&R!5w4(tMG z^z;v1kp|;vM>tTr!scg*Ijv)%RUbNIY;0^+F^8}>j{$@i%{`={9pHQ9Z518PeU7cT zxR`LDLe=(9MHi}9b6XqjmH#(rNWVH2Q1=PHRo#bxNzRRnQv@oisLTmz`$?N_42H^_ z!E$si)0>>zzl+AHc^)^&i$d#d1d@ayBNwI5v$kGe)5`4ROg3b!L&N$#Lwfn=ahjmK zTcBfUvJ)G~O!wX-rp6>hjFWpRo5 znrZ)#u7=?9%6xci7k7$MVKb+9PDI?4@pA#+Zy&E7inwQLT2TV$O4SKJR?1g2-i3WF z@EO%Bg!c}OK6rstNieqmCkrR#(MQK9KLG*rwGV?Uk_IJ}s*I^34veWjAilAw>1YhC zA3&n`cb(IcGd%D0vSxczErh|tr?Fh6pj3vAlJd_Kx8b}O%0I3-W$o?@$a+ETvPx2c z3J}Wa*!1mHOLI%+h@VG`$q6Zomhr%yvwdmxyH5fys*Vduza$I0Hv&A{_XSiVb|Gr8 zGPb|ZdF)Jj1-EdFrzhGc#;*T2Y37eq{>!7e3C%^hWm)e<}m<9$K$cj~9m#sBK1uhZ#ox`X4-X_+CVHDKf9B<$TA4Ko*6#q)2z z5?35ODBg`h=T zzXXdvnSOmv-Ev=#InXNO=%J}my9jzeYRgxx|DAvfYiRuE3>mD+(v7f9bAuB7X|*s^ zCV9nYaMF!TB*WQYy@`=<%yJuKJA)jU1PMxMd%$Km{GPYnc?rUPoUs?r6*ls@(g%i7 zhN!MhD{nJr2h|VTRGqk3v`lb0sqyEJB-1e7@$s<|1EUUbdz+)`wX5kU+{B@;J!q$C zW@biD1~-p^qNv0Jq)s)|Ng~TU;JK@=PUpc*bNe4oo`I*t$hVfogx(DiGBaS(U^e!$ zN+LPCFHQ0B@lh<0`c!8+@XQXz2N|DCeiKcd2?^5IT6=TUQ%@tQhn0^|U*!K&Ul#kf zoTe0=C8=k=mtLL0-)VGVL=#n=hg6hd&YBqH-l#snT z@uMyA&4^Hngm?;mx~t7>&LZt4y+V`^s=b3*Sh`;XOoJ6MB3N6;fJ%A4ljak z%T0AP+yy5~c55roJ}qG(RGtJBRJi0QCaR`{goMMl{tdF>_#=+8&vw(OXUFy^R2P9e zC$~&2eH!vqa!Eo!-uWMXZDsbFdCKFN;^ExK_I%O@_!AQyoy|F|U09HI|7e5j$;00E zm$RU)t?kf%aFg@dN0TTJ4XCdX0wSfD4>*KnPAN~#%Y)!P;Bfsj65S_VO+WJ42P$;j z82Fi8em~2mv6x5#B~74}7UrXFSA=lrMVRU47!n+(2&t(8tSg6)_ACP*UBU`$xw_#7lI%)?Z;8MVdaA`hJvEZn8(=STWt5i)xiQd z5^3NoTeysFS9LX`vvqZ!Z*o_2jpD{g>9p9_(2(tKd{@F7IC%1?+<(f3me-(AB$g_N zW_I_w$iV^ud4fU{=5)}Zvsj@l8!?)Xu!y9fpcP02?O+W;g(MUVG5cX|3N37NB1#?} zua}v|O=MlZ}a(G^!a;vEaH*^dRo&}8tHsYgJ{0EQE^17+$!(C zbCciAa&<#rA4LDCk!sJ7$_Z7KW*ixIVMxwThC>7j)cNsoIJuC~v9Uz(Ka)?}*@4<5 zhhgP)VC*IEqU#o@u9m;rP6d42{(L(wfqCF3ewn>;busI}8}w3{mr@*DT>qO(hR;N= z+FKRWqqHpqSVtWuCMNa0!mR!|yda)Y8&|JaklcV1%DpxlvtQI=WV`wb#9rIWfc)~f zhzJ_qww!8v;Ok`zSS$kVbjv!UXBp}XKH%d9Gygla!@zTLPe&v6k=N-amnG5!Nu89M z92)uubKruCGK!g?gczS0?8w+~BM=$h^-0Xs(A2OMjIMSo=>3-={`-n`um1LE(k^XQ zbY0EU7jnwiO!qB?X;ToZnWgV%>wW;Sz7!38*#!1PCgcb6f5xBWxI39#au5&#s{fnu zhehIlcieFEaI6~&+x$2=n}A_oH_6Bj9l zR}H7?pT$McKFdeN{2`WB(kLQ=o0%_ts&S?YB?jBi-}&;gt#`BS4$!gPX;56V4BTmP zjBYAsg~m@s3?@NJ{td;IUmA=RZUhSG4u>K?)!v+pLCh~a0P2{|k?$HKww~fZh|;_} zhjcA7-GeE5)kTGo`enyPX@Gg7SYsiJUZPS#wKp4+R~`s0H}5#zJ~f@mnw_!Fvs)0! zU)i&1o^Zt{vA+E>vjkudqPHj=tp(>KY4qiC8RWU#{*xUYVa2heg8hJm^o+SC1_yOP zKqFIELeF~To!|HuOnx}`){o&r!six|D_DglRk@JAz|DEA@unWDbV}O#YM64+)^_+4 zarI^POIxZikbx5FBOdZP@G=nLgxJ%568qJxo%5L92^D) zhMBcwc@7Xi%29}K@@VOZt9p{>z|PS!f|#z$gEWZ>vFQ=u5^M}VG4VP)?1aTbFf|eZ zgNWEAZdmzDqy? z=c&pgDPE`(JgZ{NjgHs5crt9Im#_y^PC;oz-qk0w>j$WQxh?dsf zyNtozdaR@W&m;%|EG(^pf-XSXTMLt&o*qG>ZKT!;g{T|bU+$-(VkmkkWmjXT{H%e2 z_AVcA5My6eLxVEM&9;qFKKalXozvTk)X$a4mf9+e4tb$KndV55xHeB+X=;4hVyZ>H zepE2tkg(h%@3gXW4pMYoxTRHPF=a-N0Y}FYhK+@T;@OJ&Ud=CDmOeYlINHz8&t(gF z!LPBUrKKSKHUDMYlsWhhCe(M4yZJE3rHCFXYBYg4QYj&{vyl;_XydSqq>27rVI1wB z0M{4i`8M548(WfneRz5qbjF3Ki_u;V_pi51OZ}c_xdbM^JM7C@9F;ECHp~KE?ADW( zVP+bu-4kk4*O&VcYNd3^46u;kSuwEy(yI@3x?m#=GfYb7r*jP|p3drq1~u>vVP&&^ z|9uGbP~a`k0op&W*ZHFflP;yEKvWEjB9y0Ohw^Dh;`x6CObUfoRV7X8sug z$#envPOci3XLzqj@rk{DdM0ExHV3{u)8)4Ol3}QzN14y%KT!yXTW#w_Ap?7Ko5D_L zZ-O$7;PBinxC#Ml&HG77L}!Vg+d&i>3_+ByPB-!f0RdmPEcA_a?c)fH5S4=8)0d${ zS-H*Byzd5Do}#89{r-jmkkjss3yv}5EiF6GavM1D*yiG7zS~u@d7e2pQ;uqewvoPW z!*F_ye``y%;v7vg-T?MKRYGM0N<(RQ=+Hl!kPyv%jALsIvA;msbnm6>UX0k?Tlspn z_FbOntx8%}hU4tq(0}7+0V=fopno63t{hs9F;%H%|5x^mWO|NznI)T8> z^fH>NqN2gZ^ViKXKpAQsnjK~lv=iVX(=dB?rSe3l;-B|!}9!1#MD;pDTH98?|5W=wFAQT)(~Vc4;Xo ziOkK-A^7n!{OGGhEO{{pO@YFb%Nyvfo zNB-Ti!qcNp7l97x@+6JIiS7IOn-(9X)y&DbdRW*4Rb(Luci*ZQT5g zIXV5qQU%|DpJ7T`_r=OHm(EjGHo7#=kUw3Cqv1j{KnOZ=`h={qqF3BN)v@+yC_!kC|*-&GzVveI|L*cBv$S!rvA_%6FOv$v_PQT=7^DA~<$a{`-L zqNph08!%X!o239%kJeOT5fP6I_lz`^qaQOnrkea;2G-95-IqdsP3GA2On%#x?;&abg7&SiHnp0dfImpH1#z z1;>D@xqgp9rW}LkYr%aYvgL9~{QiWVn71C3-&=H|1r#@Pt2Mhs@ zLYqIrLqkPaZ??-hFPSlWs1j59o6w>Ep`)WyL}E3ISrFsncjP5MK*s{`BMD%NS()fs z@u`f$*?iQsHB*r$o&sp%z7nVgt5KL|Qs(Xox<2#}=|%lFBGb}Z$gxRZ22*m9A9$k< z`yE@Y7IcF6T z3b-%z!PK9urp!>PsR(po^Wkdn@IgCRCfh@B+PgU6?rL2f156%DjgpIsJlniv8=ZtP zsc6<>5bJ43HyUdsRPuh z`MeJAx@p5!P%v%7K|n+l_SVwNJ7WDY+A;0$MX5pM^2*_A)Rn*ZM^(0ICZRH3DJ{^= z&a<1Z1XrZhp>(!8-O6y185=?yJ$9h@+}t{(C$P)T-o7+arr*cI zqjSWMm+RQh$S7ZJ^#)G$>{luny7W)N>YS@-P5qrsJHnd#bSPe!t(#ZCzfx*aZY>b$ zxTY?D=qwmHZshA}zV8JamM>-B0ZwnfC7TYA456UC_h^i%r1kanOYO>{8F8sZRyPss zcvdglnWxWBPa{Q0o&$W9iupjSX{%~a(o#|=SX-NL5D}25Is^PYY%NFpPexkBud46f zt(ZZBuxkyPJlyI)$f`OTN=cqNB*Z#iPMQ*J%t|hsmbpEKfW*R@nFXj(g9n9B-_8>MV{aA5+l4u1ItQ|on*Y1bFwDO#%~JGZ~SN0+y=3GdVMpP z$RFw7kHYi{66ms&T%tsZCaE=i-u8qNj18u1P?Q@R9WCbSIs*C>RLePMzSA@IryFoR zk=;I6G`ZE`=?G;!ondxmUGmY@rh|0*;xoI^Mp_kk-Bw!b_`XoeLxL*1N>orfW)P}+ z;?ok|A*^qKg{{*t#V=twJON(vWW*;D0JGOB#K;GWmJz9)DsylfM{s~IdHH8F8bC&*f(cSo)m z*0w&14f9vSwxZau9m5vGKc(1M^Eyjs1bgfC98obk+)S+a2z@eM5|mFbHk}osYn~Ym zP%L(T@BaCDG!T+negEIdA>!&15Z|NQpQ|gDcD57bm`ZdZ*vZlpRyKUCd5IBl}9UA8vfhqoHB>fiqe2r)ruKf7C>O@+Q~OwtDetp`Yx z)S5gm;_`X|eKfI%7nAz^heaP>In(1yOBK~qj#r;~XdX-y0FChdJrClHfd)*kK+7SA zy}=@i%0wGI;$mR{kX(e)dgk0}2`pMs3N&bQgVNLwGtJL`g1os4_3ttlSM^Ec zee_R*H<0J=5wc^sKn6sFRgg3A=oiU@G)C4`%(Pl@ahXTr88%evS=s)9v*=58pBN5hO_l9slV}Mm{r2<)YQ&O zg;wt+78aPfAEndebh{?(_g}>i2WqfRKEX5StcC49tEE_E+W*qg`=t#_Fd_qFsC>vEFgd?$! z67yswW19bF2RIG%>)G)Y0{YDe0=H*?uI#flNXn5^5D;LZIRsY%A|!R7MhBjB;H90E zGT5yt;M2UTLCrlivQ%v-A|7GQYx%mu=g&ZL^D6wrxzl-*@l2>#jR9KW1{RgN)3R zCn8V8-Vu90``OSjhSa`~$QM~UI{HOe4WXC$^qNZV_0wO+2VyE# zbM$Meg9>ovpJ#g=dh3Wg;`)2%5buUD`iOfukgH%Yv_e9>NL~2tvpFioJzj}9I?b4X z-A|{_-9T3GjAFe2@~FA~qPot}N5mgNz38_@6mSzyY8qvJ#lJm{myQ06CMiaMb$lXJ zvRjo4k9669(x3jaVBfF_#8Y^DxNg<3l+k#@w2@;SP&)XgF1Y4AZP23F{8(cHjHi~^ z0aJgvq#g1lO18M`gALkFa~>o@nZ?DqIqCf^3&M79`H%1&Z^hI<$x(4tSe z-FcU?_TCwCiqjs=+zbWdTNu0P>G{W^Mz9IRB3M>wg5@QBUyk(*wzo6dKq`$16lUi= z*eO8tjnNTG6pO}MShyF@&&jhj${&rQs^(zdl4#hNW%BmmV}eV;t?Hp?fGt1>7Y$aV z-S4`8d&D^dejtsb^7ODS{yN`Xrmsj-ZgkY}8~K-%YypVhBGkC7k=AObs=s}$O;s^{ z>%`?`5zf}~x$Sms;a|$Bg`9=pC7moAOakS}t-o>1UknEhkB`UdKiJwHcs`N!PbHDN zxn6kx;*E$!4KfM)9T6FCvv14&CDBf8- zes>8t$(*p#Wa>?~F=B^?WuVyEpr2IBBR8&Atgy&5ti)ZM0o;O8Q?+9E>J6T|>beRG zi-TfN>$Y;lGDX9}qaO#1!&_#SHq~Uo<%HBPD(2(mq={yZ%T|fG2&?A6<@f=dtt?Bl z{MNP=_?AP7H+WSI zT+vhcpzIzgD5+t-Y9^?-VcvXfX2{V!7G?h~#Z}N%bs=Yj*_zy6M(dYoq(E-{E6+Zu z^cyyU*)F5m5?mCd-px_PbNjg8I%i~s5LJ?tdKDCDg>sjy-ae!mNi$#0suX!<(x|Bg z3RV(EAKn+-X5l*QqxU4kU?qBFik#6@ez5(t?MV{78?J6TIg)o*F+AvBb~R;hZgJI2 z0;_itn$@NKUGLV1cl2XC2iVy3*EM}irp&fVGrk`F(9e12WI zZL8`N`BnCvrV^9;2PYY}BNIVBg9P|fZ7nS|Cuv#y&P(E7jKHS0t~u$$!LNra9=47( zO6ek=)W#YL8k?KlO+8xhMcvdysqrAiBu&25c7fJWskUU3G^Sovj`g`^W9BAiU?!FQ z1T+#O1s-O zM8AcctSqFRmhvRS=5T5Mwku-rw;n=u(Y4#d<+QXkQ?#ytwUAxihcX}!dA;6_gQ_p$ z+}`@Il>mN1>LSdbR<1wp4MXjHB+=_!%EOT#N`;N3HOR|Ot~G-B+i3JE{55521sDE3 za28&{XM%3fd-zE+glII=#EmduYi2S$Jbdt1;c%gEl}6P|I$py`C5?$#}K4fm1v-l>Uo4>z!Utu7hFcD|&Jz7~1y1=VWiJzj9yL#|A%- zm;TY?liO+j_dkx2A*)N(20FP6sIbj}fSeR#U`^{+~F#bD&!1&l;SHQ$wm3T*AwaYhR;E1#?y;?!4iEd?k;{pi%4 z<{vlNZ=c^+NH<|$1ltXu?SIkUUZfHud4=|1LUU*SXv|;MmwCqcN3p||JgWP`0066? z?f*rwvv6|%2WzSbi^Mk;@o%DB|KjFGg}Z$CpWNI4Ef8s|4J?SE6+qa^1P3}m8-JG+ z1Av&q0iQXY#qpq$|DfYWF#-TkjKE3+i>*L~|EA*x!b8GQ@l+Om?*af|GykFE_Em(Ukt7Es)`i~ncnrq)~d9!^|F zh{d74DPf8P#4u1I1eua)Nnyi|iqr{7VaNS8{a4{AI9aPng*rWG1O)A66%`af&KE04 zDk`GhdGSLd;sX5q{3cS_VL%?_EbpB=@Uijn)VMei={Q(__}_t4@uAz>+p2VlkUhDg zf1E&pH;9OcrY1mX&>2d?3f^(~@tJwN(<;3+Xh{f}vWTL^aqk?R{Zytai z5VumB+Vsc!D;NNSN*483Y}Cu#)|MgoRwxE_o2sO+Fc_$TLPCJePH$>^AEF=oAUIwS zulIv(yPaG6dvUI=l@+Z|uz8R8Qotx9!%g_bKq;~uc7J`Dzmb(#-gF2od?f>9@Tgf zqluMO>F^tLA@y{d76bOe-@hOXJ|qa)4e(D&!sZ5Vb-yGA2vsjp2nY~=Pht?Zwx)Y~ zdmCU_uVzV~)a~&2(T>e$K7o6&-Wm^DVV!GVMBuS&>g!+3eo92gtEh9yoEHL=~AQR=yT2cZ)m95fl3c>%nfP2Xx`7d(QU0PmlvjkO8SXf(DRyNO;nwok}6%B&lrz9p0 z=H!rSxyi`DlkjvtSEdOJI_gMMQiL_gVTR$Nq6 z*VeY$Oz8j$I0SGxZV9DLnm3OH2M41A2nYyxfz$TQ?BBj6dv)qZ)lO&f9umZTvs)Dd zsFpAK-0X$wn4P=vV!=bX@?`2LefRQe^HJ$^K9t`~%1BP8{$l_I1!bS?_xivH=D0T! zYo9y`a!xVZfB*h{lkocI+Y_42-wH5529GQJe36`UdsJB&9iT_>^KI8{Wqn;YC^#4# z018#~K6igC+lz=mYOb2t9W&F)L5 z?-#dmV1~zYg}|!(+FCS#AqT#=dhx#nituLgnIqSprMT3GsH&pK%^C#BSVr zWq__0EngJLpWQlLss@h5V=z8bgRGD}$1Wn(OWu)&)$tYT4$P-AxK(_wJg;}et8`oA0G2GcPap5zWUcMAI#yOzkV5&hBXM!) zaRvR`G4a|vJ3B`%Jiqs<=8_K0S#Uq%=O6aRaX|D9Xn<%UUMfoW-{Z;5Dshx$s%6k$@KSNqn-E%!(YPdA~N#*d?E{p;43QNa5|fr@-qz7%@qrkl}c4VIKJ0YoSdAL z%paF1(ma7kP03o>i{vw9025PFZtb=@=11$T&cFAvm2`Dw0f=yL&&LR&JpIPCisg&S zxr!d^=)r!s8W!6iNe%%3`AC28QX@b41%8*1fYxQgdAI=5A29ju-JdS0(qJx}-rJk4 zd`j8bF)mtjs?jYnFQq-{e&6Wy{s#K4dWB{{PEHQfk_lUCjbSf%LsQdEPXNS@ur&d8 zI21@Gk%of$F(@w5rM&Cr#tD%`fKa;<8-!Fn+U)N3V2evmhG_>zEi5e9BS8Bb^#>b` zCD4NUGe~e39K}nsf#e!MQ&V$!H#Th4bO(g%@Zk+|<|14;cDcK~&7U-XrNFra-L8xA zc`zL3Ch#t+sH8;7x3GYE^4p_V_Igu6?m53GzqFGR8)(gE_%;2<>0idp&TA}e>@gH^ zZ$8yHO78T}x98g~ygrbi1Vu~TXUHN{swz^b{64$e;3~dUrFT1tW*{mG zl8WFn)dt;yZV|-_*&u#pWF;jfkgVP!+_l)xoFO(HO+RU%4e|IIKvfFMUbEHSc~epTE^6yS&( zY^fB)6Y=+{ zx@6@OTdx8+gsZ<8K`a>`77bS7&gDBHP^yiY^XuPmcq2go` zkmh%-B1G8AB{2$&k9q&`NHOh(hm7s7SG>q9&p5zpJqr|N#)me~>}LEfG0OJ_KLDF! zOJEYW2l-`|Zt#?I>aP}@#j@$~o8lxWQX2~CtrbLv$Hdv$V1G)3WTe&?-q~;C(D?%K z&s4il3lz-`1_01P{@)%w$iN10Hgj>YvbS*l=kWuz*PM2^P=9V#ODVn9=;*)&o3aJS zq_9Ckz@ai7pzAl87Wh-u?IrF3o?j9XO>tQeO?E3w_sJl2c#6L?wkv#F_f2izJ45;r zfYw})yeyfmj8QG4kTrqif$Is*& z?n!pinh}*P^4R2EzFSm1g>i?dDHzjndgs97Q$1_C!eoVFi~5zpvzx$cX`cA;{kdM? zy<#*)ZjL`9qCk|R^Ay#2$}A2aH?|qKm$QJ$S-&N}QEN@lRfUmmVRH6T{_pV7T3xTR z=akm0x)rj`bF7?Yer$t$qvvYg@I z!Dn&WJJrs@;Eq}0zL`C+y>fr`!2%_GUwE@UaDF(@d~?R}I7|`YkaSE(nCwHLPsx9a zWR9xEowRlwmnCbx2~rh)6{lL2SLF)ktX+*}^!URX2#~|l2cXd)cMakJH+EHWmc)|5 zr_IyMNILd>W$&<4a-g>`WW}8*UmS>35=aN*Z?Pf^2Nwqmq_t)FMZA;IPX}}caMXmz zg!?GjYoum88+Xh6F1S-%7Jo^^ab>XeG8GBsVN-+~uAQ6&a&YQts*d@vMU<4U?91$g zs2?i9AS6CCT?Ys)X^5La8Wg}E=No);pS86r1<>|Z8_Q)z8lb(^(jJqDa;DO%-MPnc z^-$5X_PNPLT%HkSlV+K=&E~!+6>gu4ahvJ#^P-VtFp<+0kd^c*!0TcJFmvF_Qh5Q{ z4eXplx30@059$!FHz*0IuV5exX>%|ZjK)Q_?>O`V$y4%>t6*;?ayAtdwH_r zwIt;r!!+g-O0jLdPg`;El=7)bD3|`>Z-lV<9w?EOoH!AA1i&U#@&Obf9qZr^_9fpxIs?)xSuu$WdE3*>P zR1SZiSd3HvHq~S8OPd+wR8dsh5=Pz;hgg})ZM%)gW4t1F?D4 z;M%+WELblLVbR{NBA1#%&rzuybs_!~W*rGNQ%ORXzxOAYL2>DrL^UYr+2TExZ z3>tlSl0JI#SoPZ#-TlKNI?)qkVZ7pVV27%uRhQEVVZ4uPrB&G!ig0Sh4h@U=>1aG3-CKb#JXT%x%yVosCE0|nMds#1jqt5G7kcnS$Ei%Q*um+Mu$R| ztLF>Gl45r~RkfiFVZcUcR@6y~Pfp6_{tD}cvf>1}fs_AjVk|tSBJ`NAx@?m+%iS7S z6Cl;JcTmXqY6uATkQ>E)KZW|Dcw$&fkomV*e)&u{kt5>CE47wJG^>kqeBPweOnuDH zqRNpWj4AHJZS?B>k<&%_o!)Nm1n674%=*HN)V`bAeN~=$-0Xd+Uv3lQ)(%s-?Y#mx zpUH)ow@tZq$hIlsJSlzDkc_-+<6bY-9CBXDNVfa|2Av%-Ta#3e^gKhavnc;*zERO3 zz>|!!AqDg%cH^V=PCQj}LeTt~5@_^#&7GbeApF^BmQ0cv(1>dmDp;oZ*<&>C2>p{} zgP{JUlNP^lrDE^vCLyQ0>hZLpS)7fJonTbC94mfQNd6Elfxe{uAE9I)qLm>Z6CZ5E zv;wpAX#R3dkVqG(xT^+{734A;Ai?)^EE@OS6LAdm2=Q0y}ldg&u4cn50#+T zYCvu%`aQR2QfrgTQleD}b}hgzVU>UFcjdUsf=NtKahh$6J&lFvyEt4`5%#9-yrn3* z>&kA$`hfaJLG3n7!CQcAGc?ryHw6Vsg$6Kjuy--Dclk#@o$Kj1@3z$X3U&t;$|I0 z%)(y*#~0ca&2RtVcMJS=2=7iAmf7RSE0V{79^wGQK5WoI^zP-&|5ai$^K&WPP{7^R z=_|rnqU4*YEsQUCHDGL1I6|YsHw2b~^)Y&k47=i;A9>jnXeakOX*f=Ov zyMCU$+EmgWUsKmNH^U$6aK*ym*yNo1j1hv*1DSNinex+CFm}+jHTi_e)AkyOr7No5 zl(e(H`0dL{FW}+R*V0wuOHe|imoQ;X*yCMW$=tX$A2H~;heM~F7h<_4u}kP;V|o77 zQ{BVM{#zesCi;pWAB{Q+f*~xAsO`BjhR-GC)KO5M=}so3DUd)4_tMG5xVa56B~hBi z`5u;By2ouw%8QUkt#3%%>s0BH5_`DjfDxqu22<9RVwri+pvdi|{Hd*6gbAnd>p!xi zN$k(QTvs5~&dc+;y>ZpPA+gmSwq)vnSrP>Oy~&))6SAV$qt5G_32EU8mBJO1o)x;i zkO0W^LP?AdIH#-OMovoO%-X7dhd&#^P_)RA9dbu*{WMptlW&KbUq_cMI$4WjA>Y70 zll3ovE2Le33pp8b6c6ufn);O}_UF^v!fn5wTl0+H3b z+Z_x&;!d|MT2TN+z&Ni9IsxYGx+iJ1P;Mh> zKHnD-F67?1SehSF3<<%+Do1tUA*(;G#EkzSvBq0Mb%|hTvAoNkQEo^JIPc6f{$)W$ zMCWN)74B;phcR*zJAFp!W$59g3 z#*W2eBH~3st_+!quVLQhKy$saQ0Jh}8I8LtQEbTRpm_p^d+ULj(wbTS0aOOKCgi}{ zbRd!+Hv4-SnT)$)Z!xS4SeO*C0f`uUHxxaQpJqMn-L{}-mm&0~Yf~j!>8G!cNA}L8 zUVaK+P@^HPwC4QY_r&J1Rz^dQ#Umj>+i~73zMvcbL7cHtg%OAyNPJak>g|UuL*h4~ z+_MFl#tF-~CjHk_nl>g2LtHpvdp;kH9({cyM6f>U1%=^#cSAbqu9;*;VO8kvn_)AY z3sH7M(?jWRw}zPY1rc7w$yFwBej^A#?X6BVd7=qwm_FSWCD)?5Dv6TdPAg?r^iYHB4sm^U(@4*NeFr*7%C%d6Ln&5Dvl6BNimuZ?vZV;-b?W7OM_)khlVly)YFmsPL=Q7>|aR#9*GHn z8xN~q^7F0WoI?CwMB^6R+f>@8XKPlsXOqtu03N3}xLRqceyLR0L@M8%%wiZSx1vv; zw6+WP6HkbpjsBF8JQ?jq5v}tOJaB&r)ZrA>RCQgiwodH2aZw}ie;u}E2TCPAMMwAw!3$HHlk^W}8kHeh;xT(u-dvkK;xn5F&+vm=P$LU% zB}_yw}qBKkR$*jKfU&h@g?l7#k13p@(E$1)4G+D8VI@10}i zWk(P{&ig3XyskAD`}*Aj@p~^Ow(P_?XVwYUPQTnWuZ8WbXcaO|j=Sx&$!C;a-5`UN zwS9wRYNfC*IxePP`Vtx=G3Pkqm*6XxKjd<{zc%alap{Nf&?5U)w(09n{dof1uJsCj z%K*Y(YO;n5htoYG>|+!2G!+~g?&9zK z!846TF-5q!=23&=qEf_&WRyD^p)qWvB17e3QbdSk40P4#WOgh;dm5q90)zt9stN?Z z$O<}?`R$NHW=YX}1ECp4kT-(d#R| zM)Txq2HtZXV}ju+(Dkm@zcteVc(JnQ+P9 z5j1ab#Cp)YJWQ$M$}j*K0-F(`QPnreEvL&idZ?_ioR3%)@JsC0?c?EQBb< zC}54(NNWq?em3E4Elm!6Toxxmrb&-J7`}klshQLzH<26cS5?-%m&{@ssYaf_QACKQ0es>dZ6itmc)KrUr_&Jf zTWh_h*(TrkpDrQ=_IsN(b*`F3ALA6YR5Omw!p7reh=ZCsI4t&aK<2_u3(g>fI5V* zt)B%YJozqAa7S*G0i}-AhCbJ#;teH$b9{}Ffd|o~7$<15vxrEfM}oa9bBKW~1dMfX z3zZ|M+{&BOqqL}7ZY80*@e$`B@rm099dg_)GE2Rb{hP;tR>_Y#T~C!wr*)ngUa4Y+ zG&S2;N;;nEDzn)wEOczN4Z;|D;C|pqB4)coQGMcZPcxG-k=oPL^u8?zt+Jec{FrAQ z57j(`h+R_AV2Es4Wr|8r#VA21!W+j1R2R@bzq+S=#@!nSN&WiGP5K$Bi0K-dm2ym2 zTX85cD=hal>7}&HT6eMcM^8)X$)M6av9D-4cA>jvU3U2d@^Ns~{rBS+ZBH<_qh9A} z!jf8c(PuL}9fS0ANgTBTjdaOH4~oL;xpCVBBe!o#+%2#cTh?Ws&%~p3FX$0`Fidp6 z)^gXvH7oDD7*0ZPe8m$u_6;4sEKc-v##Ff;clug&FgPZ%waC!77_JxMCx&7A%Jxke zpS-qfKy?%)(L%@Qn(CK~-H!+2ByZc1+@2TWF3$pqKR(Nqkeu)~-0Dk0g9FO1tkaqh z^k=XR1g>P3@H(gvYZ}}&#$Jm9ll9-_P$umreFM@t<-_F&qxE-i11P?YjhNhkvf)iT zy|JQJz;@1MjA!es`F{O^Fbor&!bd6hL%D;3>OD(8v)0so`Rg^9e%U$CT@$d3AU%Rz zI*23_C}bi;-S=$j-t%BV z0k{j_o>A)FpXzUkl6`)0Ya_}>HYq{v0LA*`UEz!a|>#Q#y&W^k% zr5CN*FgJSImGnz0XmSfJs>whv=MfnqJ>BZ6C_5q&XY?JctM{Wdv|8hyK(PiuS@my2 zrh!n-YzI_Ehd?5x^#Q1V3NgYr!RtPS&(@9vg;rDeNpbw&6>~z9zgNq*mrM zI6$K0RWSQ}oHO_ZK`PEJ`Y?%6Mu3lmb$w@H2~YNS5P?kB64ii(fMEeI8AnLy#O)@V zCDJ5Dh){SqKpo$m7D0!6butKBU-Z-e1(%>etXe~k*f@5t0V;aFCDztf-AA43da{; zJqPw@eboRg(YG(0m-W|yki^n?oZp4ASKDDp38Z5nBLL%f@rP*}pZF?amj`#<@Sh0B zhF1~^?4-L@lSt-M>tsr@8Za!TWpv_MP!wd|xVQN+=5JsEO6rhwDZ+7Ng=EK%3DET% znosRlDoo6K+2tTmkeZB*At!UNCzc00_b~14;sI4Wyi?BM^GbMcRBmY{K zCW-m2{-n3Tp=B!O3Vbp;<7N>s@FdMfy8bJQKRxamY7UGW_KKHOT9p2oJx1YCd6kl; zj>D-s+Yn6SpqmTh8*Ny7SB>w@NUB%Vo#=kB&)L=@vZ_+Ly0qm+N8Rjf(5%AWnmK&n z=IeMMmgD>Y-aX$OKmDA-6wffGY&Pn?W|nuD;JGx9xoP1m8d zBsRKkB010QB^wPx+9Fh^iQl5yb7vp(HxQTuKM`=bVn5M2EFIpdStR zTR&ghK3C^kK5r^JI(d9KKK#5DDjz?`;fpo_{@yi(T{s44%(xveC`ji@bP(qSh!1Me zFVc9HksCVgQhc3hCES7)5mOGKop;B-ocgBSDf3KD;;B|7uP=eK_G6qHmt}}yQk&#n?vKGvtnVKJY9-sB*zHw9XMWf$WVAD6z z)59~)Qa-J0`0{mj?TBazi>_nHjdioOgpRI;@}H1_=KoCW2l(%`X%GZ>{I(hiJyp+v zwe?BS+uQG}1mSI3ZKB5BQ51p-{IVAOMPChC=y_t#o}@G6Hbv0b=JxI=42%p7Vsb~k zuwxhn3&_sm4PvB3E%VZT$H`sj-o(M8FS+)$2m|~k$4h*`)3srG5qwC*_(Dz!rfd`1 zh%PoDjI&|~XgwNc(P-hSq_E^KnO0i7j(LF*YWnVlz3FbN6Mgf4$`G6;pl$}VwFzBN zP>y@@av*fvO%RD!mBG?E%4BdM(<`{k5h6tZ7E*q6;E4pgheVQxpbRNT=Ou zWd&LhrC~|8mDU$QMVc4jNgp#OvBzOa7rOP+R0zoVb1de(tHs__&T1V;@F7X3#+gOb z3D)N!*R5JspC=I&qc$hd9VDCpR6~jBf~q<3F?Kj{A&t+4 zc!TzS8YT7?jPR8i)~XRN%&~%pSrsAKkS)Gyx#WW>TS1f}p24M61o9V~OMOLs%Uuw* z@^3I9;wOmXbF@+2Xu0xl9^iDQn-`zTQvA!4XwI8}Deey^{hejg9U7nxk&iqjAT~M; zZSsuDY`jKsSC_p~pPl|5b2c+AXNaasQPWsJ57kglfc{!<)d_%g`+i`>tYF0){bO~U z{Y^hhPSRtclW(lD<7f4V6}!UjgP)t;pgF=8XYKNKv@r7zHf@{A@FHFAyxf~)4L)0B z7$=NQ^ZFXWaZdSc^=su6ZPrxR&d)gy@I|Is}rg3i&ju(B7=m{d(<1JAz#-a%vF6+2{4L;UAJO)EP zr|>&+k~Dgj9M$9FBe`@^cj$wYvUg%Hw`AoJTJqe2`tCcwz2_#DW_W!wAY3G?_*v&O1JT!hsj~u)w{KqrpC+pL zQjRq{j1~lt^~OYayyG@GqWXmxFRxO&-%Qt>ttF5-b79||eZ+W1(X=`3rng3h!k@ia z(N{^fz^?5fogkyPwR}0(UBo=`N9hVLSn^%%HM(0j3vP4SrBVLLjTlXY#B8Ns%m)(d z#2<{oV04M~`VqNg`#AN=gs>WxNO{eGwEE*&7dlIle63cO41;!i&5OOOJlJ3{^UgA6 zIJR5a`&O))B7e=Uc#FQ~n*@osirw8$)vG2`mtQ%a(Q2=}8TV8rE&|!E@X}0^=Q!SK z?)u?QA<|W;+w(dPm$_~4-i&Zg;urDP9OQqKM?JF_?)2DOA^EFQ&K<#lm=N8ix5 z3qY+YT@~{3ZFSLvLRERvI?IZNz=72-TZxRRqcyO(WS*eEcJ?q$j`kxG-4)J?vDu(| zENiAsL?e?1M|RU?T0kh#iS1M$kshFoXUg)x;6XA!oos$HD`7p_f%MJ(6#U0renq71 z@_-Eh(5?Qbxf}rU+Xv7~h?a_yC{lp}!T;HCLFRH*OIJH%dm}4bXJ(iGJpBhH`9A@Y zAonl;&;tt&+M7nxu>t^J&i@5-%s9`4F~l7F7`AY$PTrf7CIx{b0%pSfL9e@w@Gulr zAyl-OJR0z%oU0xfK5?N9(YH0U7$%~^@6MM|XqaUv%T<#@H#JM2ZA5H|zD z6P5}5E{>dA1l+;o@R=ou02W?o6-YRsbENR;0AU5W;Q#$(6pXAQ=8up}x`KG3POT!C zR8(1ApS9(?P$2l$IUH+z@ten%scu}WxyQoQw*y~}Qj*<`M89yaz0Q+ZI9;Y>S@qsc zJJgDmY>~rY;JzwraEn}9w<^mHh7w%1%J{rxYB6<%iB%3?u>kR9(>dh1DNn3S4 zT$YDbq8lI`jjnsfCk3KEUBO-aY?t3w)P-^K^a+hqiL1>Fed|(EQp$MxW%An=snvcr zK-Tzpp6O6a^n>g4LHqbUi_ocXrCJh7)l{b6I!y!%Dno6$@efyl=<;*&q(o|{%`HC* zt=6V5&v0|5HbJ1Ffx;ErA^MTT`nU7s?x$xVs@+Ya5uMXd?iEsc4|vl3D?k0zwj<3m zq*V8(aOZA=ueEq9VHxR3vd>qil^U0;dH9@}PseTWZ^U7`$GaoX(!$!{%W+l)m?exY zP<1aMu=FDbHxB$MQbYh2fC&IyIlZ90X+Ok{iEd%%~vIdh*FmXk*k&W2M|j*|{_v=Pdry$x7fhB&!~N>XRi#N` z^l=}fsq^Q{#JV=tdFTlibN0>@uDh!)+oUyfm%Te57Tt|(`(=A@Bc z9y9T4-Q193&~Hy7BviiQNFR%g*ndr9!|;2jE;Xx4&p`8fu2aZzSjo+P03}EMiY(vm zbku+SoocOX~0|k#vh>UVIO(EgkP=M$Eh7jTFc}g z?~Tcy$AdU&MLhR*FS2|!ZJWQW@(kY1`s)1knf=^v4_Tp_70%adgbn5Xa3=57`|sT< zHy@<-6!*`xdJEX9P{wDg%OA5=OzO&=|F~V6JafEF9jZ1R_QT=#9sf+-%=l)v05bTO zm{)GTzh4UCzpBnG3AKVoxqs~GDU)XR&)$AFtX5u;RHLz*&0+>-rZ4h$)!$P;y-0iK zI&p5w5om7H+MG@o5?vyTvbo~o_8A1QTZaaloe@cwBZD$Q z8@*UM6p<1DrJU#bG<3M} z=?@6%(Lr%>dV~~?u|=!pF$zBR73q*Q6#{v|dxr7^cjT{p}s(qGF!TJui877i>y>Z>Tg3U5=A8T!j6rs z*Fquo)DJBju>!WE?9qt+a=gBV0hNg^fH9SFP9vZPdv65Jx1ESd#stM#Hn>$+RS3s5 zT{Sz9#hr_p4C)QEyxu0B9qWhs##7V>sae7>9gBvaX6}W6o)t*q&ECrcz!cPH8`GBD zjM?8ZMV~Zcksyar@=ETPG`$(FX> zdx)T~s=N%!-kjzdPERXkdBQ*}xNWjp(hS!=;ye@vY4I zeWiu0H-<hF6Q}&c56h3moR8m~~9_Ob#`Fx`LFW>RMzBb0!Ck*OFPq z0A62exI&KUO#QcI50)J&Lx;Bz()Za=z=T^7w;`8t`W}7T5zKW^`(s8+poEeTA;9_k zW#q%C;%FwnfCk7I@>k9?rwBwIZVOw<8$2+_%L@b`JyKrZCpXWJo#rK|p9L{)+CXDE zjPCxu%>?NUvW2s|X1*L@2ismREXUX*0L{M8C03#L_IyKsxYKTz5gT((jD8mq zOby~gu+)?mwk}r8SE>Lm4Oj={s~%1$%ylN!(h8D)ZXdeg;2pou2EMimH)ixe5P?ARW~SA&)9B4h=Nc5%_jOV;57_9D0&_NqQxfHDry zxRCSk4Uh3%wf)|>EhTh{(7>5GksdZ>Allem9PA;?M}D5w0jSl14AqX2mAH6kld8zJ z#pvIk3-O2dS7!1OdQ|bWf1rUhSLYFpE4y=ygmuCPydX5Copb9Z38%_UXVK?`#F7V zNG>@RosvNEc0O3p-c7T7Y*r)NH*n)j0m3)1Gb0lBaVFt((1O$q502$wC_3_L2w7%4%QQ0S_*`R%M`7F&HYv zu8`Lc)cZY!h-I1!MGPCY9e{27POW+Q`K~-f`j1yvBRKxW_$*8z9R#=1-nQT3fU|U# zI>}bJdt5)A6%>(*Bq@H&kWJUISUBXjV3Jk;z}SPr(49ITh}>=X*`+~evxSrekB)K6 z1&O^L`^&%1j_WJwWd36m4K1j(b@3*@j?JAQnzTkEn|3(c%j#YHDvQ-SZQ=;>U$*?jD#| z)ZLDxurop{B6M54D2(hA9>48;3dSmzBIIawu>SuNbF>z_oQXwIeft}9> z>HY}vD$;MUOpOb`k}A6l)z{ctW7Pj}xk*Ay92IZ$xmSLT6kN@fu2i3SD!Xxxx7in8 z&)qSX=jn`dc`{d6FH*JKYO_>5ysI$m{F%B(Qcp{;ISa#~=3$KmJI1^zUTa0&nc8kG zhx&&e!=I2(s$Qrb37+qm0pn&vMZL|9^dI@t+thTOXQZv36y5v?irGqSZze;pL$~+z z@>nULq!7f8VYrE_DS961I@3=RBI zYZ?;tDwkN;4hgDFD@*CA!l(7-s+OHrQerl5pQ!~jem&T@zT@#P?WSIEF5iQj!a;dY|B$iiw$VuFT+*(M^dJ0LP$c%KPOGt zx2ucr@C?|lajIU~SzCVhnBt+gDI4C`ONIyG8FEDu1zz*`YuDsAq2-x&rEiGN!e3-4h~qNb_l%yh<*Ig)2YJ=| zwQ1D#W&iL;f-H~QzKk7wg@f#FYyiQ`$-o7LBn0>yC@v=ySe9|N4vJD?Z+2jv);6sW znG#9%*JV&;lPZRk!RvW8>Bo^-LHn2fd(=;u{D__3Z-q*h_}aNaCWF0K+`Q5n-prUj z9q9abNTzYh98w+Y>aU0c_stbNV#r0D(+?a0w_AsFd=6_%SS#1b<1l`2I7#GXc9A2@ zscWZ-HUpJQ((3h3!WJSDKZIm-JiH(0FZawv4Pho7SQp+M60}XJ=-w962Dk&cHNPol z9Y>i1K;jB{U7@pu5gA_%NnH=jzyLdE9@fmMRr$}mcWPYAK0_&uKQO>aIuY#Gnu1j4 z9Zc7zNwMJ9hp`?F!4@L#24M;breta=N>Eh7j&3ckFBiD=YpDgw9QfV@D{rOlYRg~W zRwd_7uscPFDe<;`-2x5V7LPgjfz}Zg_;!SwJ5PYjKI)FBh(fUt{?;{#0=bfe5HvB^ z5I+NK91|USaUCMw6@!UXcnlM1nfmQVsNZL>v*VBTd-m62#wVN|25J<$+b$;o4vvIf zu3lilblrp%hL+OUZ2ftf-G=9xXLl1B-$X6>9|Ys@Z)>rmQBJla+mt_hJdQC@6>LEF z?%8SQb-U1d%<&V0_K3TFp`;YwL2o-Jt~Mdj`!ejOSWZ5U{k}Qc;kxIM-xwR&Tt_Jh z%1kFF5kejLhkWob8CbN3d!*{k_Z*PKAgY~K^Pz&;a~ExuWZhC2fHEGvGPixt!p}*9 z=!Abc$_<3F{{7e!n*Cn$#M%3<8XjIxO}#E97jn8#`YSrQ%QL))QJdeS_S%3UO1d?j zG^wvWL-HH5A6Z@VXz7HTAiS+Jp!Oi((K`|tO*K!NqMW*?MKb0MKo7}J0+QT(1TBhFd65Q&T^`yZ~id>aBLGai+3H znf)Q5xl1#+Bb8tive1acUjM7Nua2u~+rr&|gwoOtlG5GXASo@~ zY--b8B1lU}OGpSvgLET}ba!`m$J^-jdXCp~-+lkQ!EdcKcZ_e%HP_nAF~^wm8|A7X zHauT<|O!rTSF35 zvFDN>!Z|TJ+m_+tlS1=Y>zluKI&^(!q)4+4JPQU25$lOn8H$4&ZRD3DeXH$JlyQ2PG3E)crg3qbZsBt3%+dUJ|u`?`#JCBq+vZJ<*s z8=`}hB>*%!P-!yD!$BYQIX|?T$7`O|Xyt{wv(*c^8d8{2+O@Hv*g~yHk7ANDp96SBkHea%08Yy zJtT5+;iN3)eoeq50C`vxO{);mu7>+ai5j)!Y1KIymJkW45H-6e#^GJ0kO-lEC1>Dn zq6)KKETj6L>56v`pLsUOYegcRk8aUhv2%qg*syF`MPAP zY2hsT=1Pb6Z)Acc-F%ISd;NHoiJRW~ zDAq?Eh^>oe%>>~@)FUH)I3dBy0I;P??XL%7mVm1A-hR8(s%)grJP2U&`~qdruSHKf zC-5yoh)0^B`dpKX7U1`YD(5D|DC9|*;abP!6}NT)($bAlJecI7_$jOO#%Etz6lPkV zKstuCEGEFG(g-H84uTc2Cb*y$#{(^eN6LFGQl@2b?=&0qnYE5md3`WiEp@|_L8XMGfEEjLLPZa_;AoIM!bc{N*X4i zt2qL9qr!_Tx{|wr@j$o5UPNYp`dKo@Cr9xzM&}xAnh4Gjhy9%Pfok~lLkL?15VU>$ zd_v^`E}2gi39O_ z0%~<;n^b+tj0OoK4x1aEB=toMq?=cXJ1cs5ZDh!nz;bXpi=)BF7HwXns@H?!s#=gO z$HZK)u0W}6G*@~ZkEaMhZ%SW$f6M}zvb%(`EHE#G3G^3q$`?M7q=dU?;x=B=uG(;JvHzLpV4F5K7xNcu@)FLqwQBI3ZOP zq|SWh8{tI?)Q$+9EqQbXy)~MY4g*@Zbb3m;0Od+J#d%c5Q{jlOzKzj&8w?0+ndd<| zZ_$OTfdVXf>Z^6@BG23*7eG+Oh(!i*wwbsewLg((7DF!aa^~TO(t8KB`U>^K`3C0P zqVf~=fJr3i>=0+J(t^;LH_JE_G|kTzRuJ@70+no%aD_erj5+I6zldU2QADz!)ZT5j z*98mLtxw}KY6u!tIJ|8KL`yF=1If2Pa&hMA`^Z>o~gVbGv8^INIP?BQ#)~BgLTgf#Wm~O#FVP9Ia zGq0pi@rQ62~^VI!M1@$ zY#k;Jcy&}z=MJ9}vwQgLVhaBtU-jb(_cxdw&1ACDNQWPL@Y!{b;;|tjZAUnVFi4?m z;aAkVGFUQcc~DZ>&&ZLVe!Q7fv#F1?g5olXx=f}O%oa;iCLCi+QSp4T>i@%uN)-jR zlpegP|KAHoMks}`=XDVc%wGXMj32!|j#GAwBj(@gF~4Tf)S|A>%6uyeE$F(WM|9VVmhwR??3-V*}0?|M-zLnx88kG$QDh3Mk$O1`AtEd{Oz?8}aFCG*a? zdJVG3nxuZEAwU$VK`3fTkPF>lcN#)g7vD}-o$0^nC#zPFxPaPlq;=KY#to+p z1EbbgUCE}pHoEK!xTypR%oV>~8yJY}CCWJEBMRkQeaG9i%Zn{E|hG#-ENkUd?d!c#Lr`t-6 z;W4+Yv>Ab|CL!qqxJRFm=s}LW6GwxioJ1ysjc7eLbML z)%9ZH&n+f(ET#8TyK2vB!=`VyqiVOsd08lzclmd6O2Fy6Z`isaKs!xS?4rG6$@_a7#rMAdPyIrUEs_EK5Ogr)^=50c- z*2r~Q%KfOB#{SvV2Zs}wer%MalI`=eLOX0wE zsSXA&uj9YyYab4~yR%nlLDJ1m*|aw>&+ygo)Up)%Fa`0N19XH_aozgND!%dU?nthE zC2r*5cB3vc&0W2*|2Gv@nh}ylkVE6_Mz4JwcjM^MWOKbZEv?o-EW5wg+h^Lh*DzSl zJ8KXh3JGv@D)X3@`^I3u(b?5s!^%BB@>d?gup+>R39hG-X{r)4olCwOc4?GK)w;PU z5;hK_@z}}2^grvXdpT1ymTuG6g4{#D#xZ;0hvcu|#y?J*D^&b4Hg)o~I7ZZ23r2|=EgQENj1!-E?)Y=BXyEwe%h1PtL9yYbwi6ShuaHy&Qy~c_ zyviea?!aAnujE237`d&2jeZ7iJKkR_v*#g7y%ikXNEOP@jGk%|U-Z%@Jgbr%rB^9S>Rxw=Lg*bO!QCwZ+DEkg7%@vp zcM=+HI|WU;1s5T1R4NQUCdYE7y`(gFFMF3_jq$=6zRmO9D~x#@?aSuL&M3&}I$QRn zWF0$M6X2D)daSq2&)*mw9Q&72HxLhCrd@N$rDnYk*G<)8Jcj+&yB`s^omeQ~;(B}E zknYPnFnS+o=$XzjRSLfvp}Pk)&U0pdH39jU2K;k(RfGqvM|oRv96lRO&R5V73#W6S z2oT3S&vW!7USIN7l0x=3yV#ovOxUl~j#I4M9k9wv&D$Dw-Qgt|*DO~%RDRr4I~bqp z6#9AVOAc?!yX}IhJeS-@f@#s1KcaF}@O6Bv;RM(22>4yor5fdG&D!)9u`!IUV9$u&YVZ&d2C5JEG!FS0y^DN_~T5=}VR=o9XHaX=MM)?ZnQj+xq zRmb1=^*8W1U+(banFc_=&0JB3^{UzEaGncyHSW%LOtmnt*c{vay5-Umijmhxf7!?Z z%LdUZV*&f^sRdhb)Ak2;D_llBpYCiX9d9vhLuvp>ZbOf6e=2FC z_ff^QAHllG;%?tZ@w#h#Cw#5(FYBy+bA{s;SFzaM9!OQ9N%C=v1eDOrYO9TYTPSjOaUMU) zGS7)e04KzK@c#KzR6BAb^@BN2Q-%%5uf4oii^Jpdn$`Lq+3gUhuB2Uku6{LzI~e20 z?QLw^(@KKE!f!FW>td0n#y9caRxaQY>tDOS*hBgpm&BHP+%D3{%i(eK`qbX~Q<5aY zMqgt1QtQOk;ZUUKV+JdI!u`re@ba%;;EbI>sUe>C1ys&ok=s1uU$l%dJb#^c`*tn4 zg*-dFYKW?H+3hQ$R{C%XnRO7{iKG*5pMw{uc*&?|JqUDqms8rXV-AY}aJidx?0@fF z>x3pCkL}8W4w4H~@*((o*e_k5SD%{ZTqhbwagvoav2JM$Fw&<-X{I1lmP7Qp{nIKKZR zh54A_4fltKX<$-fa-xO8dcHqsVt&pod-&w1;DQSxAZrt#siU2~0}y0w&&*&0vT?Mr zGPZUErzL@UgbpUk`!Of&r_RHX=nr~8D}7UAdj?^kgO$FG{eMyZ(@7mbAWIv4Yh%m* zM?HH7eFsN-1AV*yqKE&7%G%h0Ozn*A|1X*kQ}2Fno`;(L_w)Tp>!CgW-?dCELHZ8H zKd%iA4(|KpKyao0E#QUr|4~DILqlUrWAOb1*)bS8+S&bUojnwoE(rF47YOh$Iq*UL znLg+V_)~iaS4-pX3^Kdg8sW?APrc@K^{FK1$hHqYrEDVE>Ai-|GKEd(Yk(;go$irL z7wpnrNR_YjZ|q%Ke_AR=qIRy#1~!>kWNgO zhFX~Je0_JMcy+tFeSXw2rXO%rt zD!GJYv%0~oIfCqBKZ2z3<{(aH7 zvEinhwrZ1Q5$%k6AGWQIGD3EB4)(i=u`lT=Z8v>y`!l0%*DpmV)Fv#Zus-z)85?4= z5>jMiPLuk*R0Tp6?u2SYC?iRWXr{rq zbeJJ@zza_tP=yOxZD}7+n)1ytc;dAR*CB!c>6d{XA$BYlcaom{qMiC^W{dpI7)9m_ z@Q5VSkHAne7CF7{i009U{mdC_1qQgacf`e?9Cgve$qMVs5m_B2fiF+V(<80WT@tK~ z;mghl_>u7i4=@1;z?jui6Xa^jl`%g?)^uhY9WT5g?u0!KBeAebUi}ZFpR$eQwTVkp z>1pvgk&0&zHu-enhnFDkWfR<^`7_uk#2SfV5%~2prJza;$je0OE5nD7ReioX^Z3;% z;KKDI=^4FuG=`Y>Aw|@5;WXm?g{wfZA%C29?@gKvnbPFq42SV56j>IcCd0&xs$H>&+7MHA zTwD|7Hsa(2;}PvW_LxEBbr`?t0cye<ejDVw*OFgGl2?$IN!xd%pHrybcD z*t_9Af6w-+VraAo2NOwM-Gaku^{L!46GI6`{zp3UvO^G8lTm6LDp?_srw6wF2{ejk zr&#OMy>-@*H+kPOWR3MJLxv^?rdSyGlVXzaD8;5-H=?c+=XPa1{Se34?O>I`dgY2S z)F)6OZXX690^h%~E-rmq{H7cvVUgvsGik*95lf-v^*EY0T&Fz(?Gg*>T^a#7+sFhN zed11}*s`Ks34X6V3!Epc!nfe7#+~QUsB4rAv>cC~tGCLLd`u_KRMO(hk4}1*$2jE( zXSBq~ZASW~&yb9?4u&f$mn~JVmrD2|Mqwj^*uc1Om0^4=3LPR9W1y_j zen;%)w%9H`JucQIGPHuUe6y=~W>V!IMRdi0!u&qykU&JeO30Q~>6}Hh;!^xI2jPyi zC&cL8Mw5s_WR0tXood!EXq-(pH~HXMs~LM3ig=jGqN-bo9Jxw(b!+JZVd|n{(ZDMQ z1zclfmf^#P?(eSml^6U1;Fvq6Tn6H_E#%CHs#78$5b`iT8ZAm1U9%)K_iKj7%fEcz z_PlW~w0)k1E)Nd~kAFgHqj&w57Z%=62=ePKiIKzGi1yW+JrrEWz=0ilR9xq`5rv_9 zPt&AK;c%RT`pbAc_8gK^9N!LX$c+QPi1_WjbvEWk#3-MR9G^=Bvyx*(@`4T*LW_1REh#gSKA0xM1A%rr5N4a^UH{^p1~8epfsba$+DY zS@?9TAbEd?KbC0gWpoh3))&SXz=I6gK;Lkod?R6u@iiW-i(C>;GCjp+u~)ji63~xD zuw9zFmy}fEbr7`RFv*8~b-tN=3MG!MlX>Dl(UlVaIPw1Rju{kbDfeNZF>u2u0=(#5 z?->^UnqdY_Fnb|fan4R^6hIo+tl)9I%(e)FmJJOl1B@=*RC-s;ZnRDN)Xfu-&UZTU zPieXIR*b4MNV10!JX0+X4zPx!+wdIhF4Dm1tFb-R3 zH6egHr7y{9+Okk=1_j7X;C8(^Am4zMJrTvy0tmcCLKr@jAjkox9Z zS-O$ebanit6vrzo3K~7GICd^vA)*Yfp}d8W@-^&orO-ziA+#!SP|t~|BzfIq3r2Bk z(CBE?;AeBl+965PSI$ZT-I|_^U*KQ8a%kYOE%`QtCOxe}#s+8qfp*hKNcWmC`1Ux< zKC@B-$}4PGdM){kSsSQ)7%*BNVHv4QVXu3kkTEuka)<}hi z9zAwOEnzYEjHHHrrMm%oSw}gX&-jkTIBD19)#w^$yqZ&)ixK^l?mZV-xS0n5oNN&r zmTZwgbLwm^Ld<$P!7~xH_s~Nn2##?fPKM8susX#)%m52joF~nOd3wpV=<#~%UU<}e z6B{0}(8wv`z>yucw)niqk5|Cn7OD|axg3CZwR^qjfe?4rLQ{32dUNmQW7^wa=7M_BhC@HIZJF(#tY07%`ap2COJ`P6$iiJ@Fso^ zvP3wvkUdmAbe|x2q6+Wf{joLH^Ou3LHA0p*yTt6fFeP1;Zzl5bTC?Vn3`{rzdmA8H zzn<2y78M`cN1nJ`#8i}hY0*dKeg}_B=$*Nfa&xhqm^4J%&veCedYgQ8CwI%1VtC@b zb^WiGp5EDa-Qi5uJ586&&RdgB;nnQ}0K_zX@43NLXRTY;4mz&!ded3=v48D6>)}pQ z9QQTOf9y_s-N(rHj&@zzGfJ;}Io5E(pL9vY9fZ29-}jq-N#n}R95sI! zoc_7ng;(mydm6XW+zs)hVJCcKT#f#+LH~paXy16|L@yvQeRC^4ieGku6Ob6m&_KON zp6*oET~RYn^J%wvp=C{4{A3bk26J=?H{T--617j}Zl>+|sK|*z5q!|aS0PUBP3>o2 z*_O@gu-z>5&Y#HGTb6$|*jQEywLCGvuB2q1oHj`e3C()`ev=*+t!J3kJxf6zde46E;JMs`K{HzLo`Rs{pKc4Cee`zm{vQcs}aPAqaNl9b7;6{=x8 z+*Ch3O@v~mJ8qMeqt);Z@-^$8K>voOaPryU=#~fO(bEhp{dmvec&|VAC1k8@~O1i)~Ux210H=9-&2J{KL5Ng!oSpf&Tt2B|8}6CA!=a6KU&x zu#HTy2P#!bBf&*UQ4|cfpFl$2bcnR2O9iQ>M84KYH*^wQpMCOshk?pKRO-xK;r3M_M%cp)@KWr2nErRF4K9of|V!z3a;<0+1m zr})d%NC!5!pT!YVGHuK>e$vnVlIAIq${@?_`jT0^>F>Mo00ofcdArlUcDfwG^(Azf z_i9=7tr#g7;yZZib(tKjC1OAF5pz45?5RbqDCk<^;X6d zT8RiUfWD#TRXj*YE=f1k$3pAx(Q=uCR zYk-~=YS+iXG+>VYykU}<_JQ0#0T_$PH;%%b8|bLtTJ5vGtF9C?*i$9h&thz8X1bkl z0a&{*2;4vOGMRv%-8X1#5P;0j8ZEMoSW0Xf9;<&VEwO zbRovuo9l1@C3W{jVn(IQm&Z$V`T>Jgu{-EqkA;|863-(G=gPE?oFiyeH2PZ*S_}_H zcsi7ZF|}`*plV}u<`$Z9&zFpEA6GS8vN6==IueBV>Z`_}XjbT* z=*#O|$C`(ctxw+FU$!v2#p%(Y-~(=pd%jBTq)c>XXh+w-`qY;@*j<3jT{z)O7F#M& zpuO{0bq#WITcJ}nJw|B3+8EZ)X7d}N-4Oi8OHWb`9)lvD{d^!j{gwJ)k8j;TEi{*_ zVymV?E;CD(%Gam%3Ndg*ng=`vtodUx^&)-z$P)%5q{as5<)Uh38ml=H!Cm{lF=5>G zZ|$#akMsNFF!j<;YZSF;#52s%S(OIkg@$MM#=J20ES-5!j4}{Am2=zO6;r59*fHE~ zts6&iu%@<KZ%_5MZa!BY%zoANjwxj;JsMS;LyUwa%EUOSLo3O+zbbyv3wCey zb=8@*2_+m}eXT31jeF&>dgYfY*zAU!1xFKDRGxK2sS=SJF^2jeH2zznhjF$%|LGG( zWB`Dn;=hfvF~H+&SutfHIw?7EuxHB}Xku*tofNM;<^^bp5yfZ!7K6(9rgIuKts5%U zed7*L#59uE8e~vQecwRw`m4E^N?B{%VJpkAtVz`2)@6nj=Dxu|sZwO1PjU%=cYS3tJs;d9E@D6DrDQN!TJO_wTuY^r?PLcE zuvM@iV(t?oO`1ZCnAX3z>%9vxb>T3kH1rC00N%RkN#&vBHZVT0b2<3GqZ} zm`DJ?3-Ctw>+9f>3V2fh8agSr{*RGNB}b{@33ULQJCK-xG)Z-XLnCld9BUPoW*b@6g%KzeE3QYbHkVA7^3b0)w*)iL#3Q zsX_jl+4=9arj7nbXfBQ)(8A)JoUF`@qHIEcg8pk(wZB7?SN#+8KO~C&y+Qt(*X8ff zkJ|nTn(5C;+J1-rD~0*rp=W#k3Hl$>#QYBZSBmVv|IlQ|ApgyX{=3#+c}pMYvww-? z1mxeyw13z9>k{qX`6*~L6u!Ow8O zLoDH!uo3=e8~;OO;pbEN6ZEgP&qE~PmxO{rf5jDk*ZXS^`d}ITk`p?pKif$PFQCDF 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 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 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 2223/4212] 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 zcmeFY^OvVF6EE1dZQHhOo6~lG8{f7)J?);hJ#E{Vwr$(CcHZ~yy=V8FyZZ<1*_>3R zQYXm|$@8RAseDxA!67g}Kwv;Xpm^QI*{Lc^nL$86{zLy%APzPT7CKleT`I6l17BXgZtMRQC3Dm z4Fm*~=bu~x3jU7+%R#IE6`-za(qbUhQv|2~Do`p48j|1N-~U9-{(1j@1+0^dt}6%# zJoaG5qKPa%!bTd~eMPcP5G z7D14a-^|9|9D<_jg5ew{`CESD6CMrbAk9JWaA^c;jSCtz4lR5r#8Xc!HcDYHoa>L^ zv8B=x&J**A6Ymq z_>Eo!jfK7%NT&_#zr1}oN~hMVh8ZyT2KP<4j~~Xnu7WY4$p?eHWu5+^{&r5bng@q% z(p0i|1qH@KRq_7tJXuxy6sz)mnegTAMY3B|-wA}sIsOEb_+Ti_*lWZjpWfG z3`D05q2%l1xTd_c%VRtp>PHguet!Vm?&{UMn)f7JrdihH*#=c3#dG$Z)KO-Pb4 z{=KwjHDz}F{j{3(1Iusj?vDr`gF4iSawY_?HCex0SRnW}I!&|+{;E}&4tM|R08_L^;ObVGV#g?;d~c{c1kmR@0Re`r;$cY;{aJo-#{>xSNXQX7h4R z<}bmFx_8CA;)@+O2wc~A>)FE2dg1Q6x;+-KK-4u(%T|VjwsCW)P?DB zy{5fc>yhekCnG5CHC_H%9oYtiQ?MaJ-w7L4!&!hiiL^v?r4uwVViY+d+% znoIwN=CeFnDi)2?x{hSji@gJfZuXc;H#2nIdH;Y-hW$ISk>TcWjeTVK#pHw~{A%OB zvW4qPm7w)9zgDtd=06tYHWbcLOBt{?Z9ZirtXjmA41vS3{<6cd{*>Zg)GVHI7ARQG zwPE%Qb$UjPHpkj&v%53)SmO_o8S43Rka3wehv#K-fEdUhD2EJAgOClCq}W<4U<*EC zcauiYhYn{Tk+m3z&*iieAzQhreo)6Y?8Y5%wfzWjJw8*W1v3JO^6Qq?l2Qp z=ZH=4k(Eb%y;=Cq&n<0;y`#=vy$0Gv8)*V4U7I=eU#5cxyOXW0eOEn|p>ua)sso}k zd>*d!vtA6*{$XxWPh$fBQ_v^102Hk|5xnmv4`Js)wp{WF_=L9>`sW;ICfnHqF)4O{ zj^8t}{XEvZHwyW2uT-xzIOgMM_70NuvQ^)%$(YGL3L+hW=O}OF&W^~JtN6~3&6=_E z@P+sp%cysb*7aRiBiSufV)8EaFEGdaUPkB%#21`X!`S`CPEul5S>X%Ve!ob?0vC>D z_)@C_v-sxaJ}#DoR#b+zwOG_$09VhP*0@&s#r(2`Z%Y~Z@Y zc0OZ#p{q@rTqk9t(J`}GiRdo)=+0t_r9Z61rZVI8v*Uk%vpx$Me1oMBls2_{PB#AA zq(NjQl_aXgegvz?L&G#0(J;b8{oCOG(f_lR`LF4+0Gcp)I@rhj?u*T2K?%S1gFCod z#K9Nq1Jf!mFOR6wvr#W=`MI*Sz_>EPCI9xsiK14IUq$vBeEe?pg^N7+S?3UJWm36N z4#5*GLV_`GP%aMZZ!bK6u%Ueo_xV7Po@da|jXBn*)yj9HW^qbDCknt=Y)VckZ^umG zlX9b8Aj`MQPzpQBG$UWkMf-56E`&iGKtXaYodn$#n4ZNjRGFGGSkAO8;1MrCHG_DeCa|02OI>=i_fDDwPpkY*BRBKWHPf6tS%oQ$#kT3* zebn8SW>aPEW0#TOclh>$2T(2e>zROD_;GFVM)%jQV5?3@OULB&X3o-&CQk^B@syZp zRm}N97IG@U3^oR4Bumhj#4FdBb$x!OVo{Xn{Jq2gbN!fBKQT=1f}kn<4G$ z(VyWowM4rbf+7~Q91h6p4!qQ^`2zjV$~zAtjQj-!0il8Te_MHkf8UF%1rTWCXyy8! z)!)?9cirQ{@V~AZVezy6BhC_PZe}SyjN&*>`2%0v^Av_b1Yg(1f*0xaF&UwV0Vk!& z+3Jr#=nwgAk60kk@#$E2o51%GENRy5C?w6U zQ-3<)L9(lh?7|f8scp)4D|fz*jGLQ)21#@$2f;H#f2$kW9&i6A*Ww~%2Urwi;J_r0OUxEr|M2U_jfr4-sn_;YT|70mh#5-S!lXUm zE}7nute^exLhZq;!4^e0K&(+m>X-3IKzo}o zw(vO!chpbB?YypO$dHpsxMLU}vkF&=aMAHC^!a@S9kCLIOEO{rB_6^mBcOrE=SE$Q z6@o%N2mGRs;>AsB^b5}ztm_aLqLnI{fwup-56m4@pJcCigzVcLCCJ7_K(VJEw}#!B z)h$H`bNHl`E$g*T_ig1lBX9-B8xN_MPVzmunf}Ym{D;ZUhVZy+CEqYx9NwQGNbeXm z{hH@L;SGKRRby!bDrlUWcn{uUS2@CQ;f;6c0W_i-%k|ZP#fP zhzUwS>=H8PLoD#f$C(F@(oEq0;e@IQvfh$Cb3U}O%?OOU3t4f7HNb@~BTnxfQh@#b z))ZHu=k2gn**_lBgiC{tlQV8*9BNDr=u;laf$3s$Sym6G78jy*^R-T|4Ht{^DR{C9 zR8JurCa2&~=qb=eTW}&KnEnnTnm#?5z3WfXo?G}iu`*YBO5qKc{uruu94S!*Z57(} zGpeI1$gG8XGyDXU=-~J{c?sJWEBun!hQ+2jN?RPcUb?sMaNiHoIlq)v(WKNPmP6S8 za}pcuqnmWZD-*^4a@IybD`Aj@BvDYSIM&{OY$=!M?+O=GS z&;_p!{c`8u4Ew^+ZKg96^W-q{^9Z)%?A?6m^S7i~0UnP%s3whHA4@jV1CuD^gprz! z_mxxD#UE-a)INc1qrZ6BK_Yq@dUMOD!pY&3+9d6J-4voYwnb>Cz-dZp4gS4gI)PUL zV()W!w2{Tr;ztZ}a~9O_Q@q4TwFKjESyV=|_xsjHj1@izE=o_~_f`#k?WAV)5ec@V zz!4>piM3{Cmv%_-tGOFO>M9zHtCwDAoZHVs**Pc#6H>cK4yo=w60{^F9YXIvm(^x? z=904FbyBOeml!^Vt!fZRB*eUe^o7e+9(6MThX1by(&BA#Z(Eo7LqqV>LK<;-`nz_ewcSX zPwM&bmDf-~UMS-|_FOtEr^hmE`)dSG6&|@&h^n}G*Qm34%+-Q*)TwkBLtpAP94ii? z3t;YtA~2&%4>yPOC@CB|SowlRd$$5?FHO4C@G&&D9d!m(o`U#2iB>&zdOgtRFO`Pc z7ev{mT7m?Z6j_bE`n6c>bm;S2@)y1R)Grz|we3S(fOE!5+*)% zkaW08^wB9C?cokK{d|KBXqKc^DJ4B!a-kB|J%AYJ;crxeO0 z?!5blDFfZIC$=DVHzLa?GCDQf4_8OZ*P>6x7l63}Fa~JZFf<~+R3=x2KB3=hk?+~= zo2`0Gx89WBS*>1;5CTvep9;ngPVb{6PYmBI44Yj@aNmZnvYsPM=D*qn+P*n{-X$7 z@V$@RZoV}0EX=(YW`un~M3`HEksr!T5tEI)P z6UtO!p-;Yt#;3#4FF;gvJ|%1492U1U8FIjQWQNu(6@!~eSq?=SnFptk%4XRSd*=Z6 z(UjGERDIY8HMul_pns2BVPK9q>Nri8m<{0P-q%I+dz|(09P#h!S-a8X0q|p0>5C*| z@`;|?P&M6O`fX2(6eA`MPW56!iV{(7yEXwlw0aP;(?Z+MmZr{9PW5nyKD{vK@`#8; z5n~x>$E~7%l983$ki;eq>mH6&U%tg%*Hl;Gre|i3DY;rq-4?7oaHT~a#ja<-skDUK zC{EiSx473wiz;My1<-lskf`ITC>`_nqB^j2oO61j8MBT(%d|kF`**3p&bT z)Bh@J{pHC`EcJjZ{m5>e2Q11mBs1#N!6%KJiImdqgNR0TG}Q}jh&+^H?p8{Y)rwBM z#<)7hUj8BrEm-bWoQcbiV@CP;;by2KQ*n%KoDoFq*QCix+bPo44Nl!G!lInTZ)zOP zhZtqlR`OW(xFh?RBic&kYIV`!?nAT0hy-!qVayna8pTUAEEdAZ0|Km}+72lKAV|+nnRjmXcU!aNc+Y4QxkPk6FB{OQ} z4_C}!oj==RuRpfs4`?2I21x$LmDb*@#3;9MUsCMA5^|G^coksmD8r^&?#bZf6?gW9IAwe4H=Czq| zYZ0oOh68&edq%P1-GM1g=Q*v$pZ%?BEHHZUT))NHHHv*==prSqn!5(zU;opi!8CbGoB^93}g3Tyaf#Hf>-GTh?3Od5R zn#GYn(8kA-izhJtRqj2=OUusEvypLSvmHTzoAQ<9$7#89(>D5R0`*HG%U644-?{EluSob zs>%$TSJ)5w)?NOIGqKHk_KMpChA8kl%enxoD9&3MsL3E5eEEl-`@yvYgfj3t_oLVv zPpPNOg-sB&=@EZ*FY#+@(8y!6o}fnt89nTqkh>IH|9SUejIH>{HYYPCchl614C&D> zwa{3Sl$8$hpR=YLFcwXEISO(-P~UJKp*?@M33s1A(j?wNjmb?D{XXhHE3Hji%91^M z09U7ML4rCJ2VKBW;%JlQTbQd_5SAmvy5ECDN!-xN?O=SY31d-me?BAfI=wvc$bf3< zqF&cGLd7#e)=aCn!_p1?^m5c%-*uI-6Eo)E76X=)`rzt5b`GXN9&Nmk{X`h&_2f7Y zjC1$!s=IC>U+Q($GQk*s340kUO1}COq4Q9aN?_*R zU;U~fv@!7~lYyoOf-jxL8r}rnVX=2|Q%m`Ea>59FX|CpOH{74_-!ypvlPnIksk7_I zJ@9M8LIJElwA?fGymE-A6kBo>?y%Am-Oq>Jsg2~?GLm}WL?zFC;uL(BP(-*ZouWYct0#&OhVzjo$k+d&PrHnulg$o!ITczh zrIxY7g4i`R2CH)Dw6EQtJ1_nDbXR|(=d*isU?^#UKc7)~ z=E(%Fm@$Ehp!u++?}RXg#_w!*@PY3<9?@%}wElX7kz(mCYN$_ZI*#@=Z(8I*YL#Y9$a zDySm1Ar*9F^nPGXM&DzpzRj7Aq>lNVVLL|!cQQD}n*KtXFFmf&4(QLB!A7s<4d+^I zV{e+YJmWQ$IYSgr!zQK(KOkZ)5|%-r?J|)$IE0QQZQ@3dMMe|W3wZI$bJ4p-6u$#c zo|lTl@lJEe@IDmGmwD}kaJzEGchwW<<~4LMyGptmN+*33q5lAUTM@&{@ggJG9NUIP zby%c+wcV*SVRj=UXUBY(n{8bLn;=!7d zRLQNujlDglEazX_oh!SznFeu#)>|LQd9FPcyzt5`Z2HHMeYXCWqOI;T-61N;;ZoJX z^W>p#rA2!+^`m$S+ZdaymP*w?cjna8dg-rY?qAYw&)Y7u*ORr3S7!wSD^yY>L*A`D zBtLv5g%>h7ojsN#iQ98k!)xYlOKe>mnUw=MJ8wwL?)@mYA0e9VeMyoHN@n1ajd2ty z_Fs3WS`4cnsYT6p)gOazNt@&JzU20t`Jr;66UrXHlS#AGy(8`ka;UqTe!ASIoeYpT zX|s%uqq(g|3yX6x)eUAk+@ zD5u@emCXIRL~B?<9;{=L;%x1Wn#~(SKTcPCZ!T|f zv8@`rrO?TU_SYafso!Fsc+m1;q?0arrXhB`Rw`};UJZ#K=WihCQa*J@W*0J)S{+tV zKecfBMIiQ1ikgoPs2qJRhDYGyyj~3AlGp-xIx5<|I+dDU(^DQwUF)N4HQ4ww)f6zn zKQohvfhvQlc*g3ES4Z8O{g!VmHRXlF?450}Sn8MA1blF(qI1~tD&~v5C{3s72qrxl zWK0;F6vM#EAp-?E&RX3bB#Lin*oH8}>1af1`GcHab9l$aFFP!_Ia) zL&ogyHFF`Vr}mN1>PZ~ix2U~il_Kui*ppD(b58ei;Y1pfvqG_RA!z-*vfXRcVu1bX;oN}#yF$PeKd#Bf|HHZ z`3V(1Xi#$J2ZTh?WO=W$X)Oor4Ad$Q-Moh(`Hu;e3a&x9Cfdg;uE9))v+S5P`;zxB zTlLKlQaT6&4p)#&JPEXiERqv#pzK?1=8JS{#VFxI4Y(@=Qfha9rZxP^|Z)nK*eQ z`D7QJD}5w+?m4c6DJhhSrt-G1n{tdJ)@=w^QZ4CiMTLC}ykvBkbHwRN$Jy|liOxm0qgzwfk3-0qg0zpj_PHX&L!C+aob8m8)LR>*t809}L*;ZwD~t390UDOV@z zD(4?yj9XralWIuR7rO9ek(lW`eK^FyVwzp-I8T*5(_zTd{#q~XC=I(}p_a+YGc0IP zf|-Gcsyo-App9;# zWo&b!3wUvi9joZtQs=F2tWIE<>}-Cc!<60F*E{HiVAEN<%4k4Y5n^${_iG-LCDHrR-taYr}LZHKi9KC8c(>~L)SENwdS47&#oan~SK>|!>>bNAr%+J3I?|0e`-Zfn5Yu81og+QaCJyky zJk}lQf)b|PS|YKz#-}42TaI-yU~<)%D*~|6{(>>X3bu8B zU7eC}KPSPLP1t@jn4>KASgOAOU(EIpbOVa%B&B>KRi;Vct}tL+gttH zK)^;Ih!=WHA^^SndJ<~2E7?9(;nL9X1umnQM3F&MbVR}lUB)XjIWMD#?hS2&;s}ZT z%&W>9#L{d<>9=^PP%qW z@haqO@ccR$eJETLGVshZ?pCR+`OI#{)CCJRNGhr3M(O?C|Lo^z7zM7Tn=8ZfH0k7X z&?wu8^JhO(>qL4M%FOvu<3dsfPyqv0ok2kVb5*h(VCY^9@FNcuWZmZh4n?K;PJ04R zC8k!Kvpt&}Pyd85btDdunDiOq$alMKq=iDVB$YZ(n7h+b8L29K^ufx!#fLwRP3N%f zXC!q9gAHTIts4iPzfaBSZWYgmcK|=Pi}mf|Ntu2?$~XR$b9-wI)EsJ9A~C2;+`Ea8c9G|HBOjIp!;dQc%Rjt)B7A_W|eeIs+X z-~H851oB~@)K2e%@Lnl(FC*UB330%C9J7$WLiAP~hv}g3*HiAu?VGgvodDM`?#m=B zNnZN7eu@09w>KBbwlMeZ>YWI4n11Q{5wf7%{ zrSYb)&hkm8jj>=YHY_*L+kW3q5#y5}sY!T5hyna=pLM5XF4(R9GX2%I$MN}Ps0Y0( zb`>x&mS0)X*1d<;2fQi5du2+Y#M5bU0Z&pQ6R3krqV5Z%DDV3{DD+bxvGJ#?KOL_( z;lJ2ARcY8jN(DqC6`k{B>yYhx6xCfoJz+Ke>eT|UMjFjxzJnyXJBkVq;`A1VHh4Ef zuT!xACT}i#OF9(5^8Ppe)f*l$3ZQ{5NC4e7b=71 zpG0PR1rtr|?FvTb7=dZfErGIVvPg&y{Cbd4l<3TUaIQstuSKnJb$@asN6K7(?rQt| zH9=6GW(6UMHFE5&d2=H<8b5S{Q(!(~<{5rZvB0h}1OAlN^zqp#CtInBpnA z1W&KG2BD;M)lfF6ik?BH+P!{PO9Vg|Ghmo))Vp2ZJy_=>U?L)tPBLu){F=;Wc@TFz zikM;+s$}B+4gWeUpTWJg=KsR0rq7_#p$n?5rhmXm-Xj>=qFvDs|I3@DE3QcnIsbLR za0cBc7F+t%nGYv8XI{Y{mWI~MxRyy?PcL31A*FWP2G%DdX+{e3Ur4s=I0IWJzO@=% zf)nAT;}NHL8>D0{_||tC91D87G5EYuuX^1XWCv-UeEKcCMvJHJAqi1ElCm1jh5|-+ zb;V89KHM41*2sl&5TCDZVv*MLLeY&?JFTXYYM}2f4Lp>uA1#m*U9ysaR}mHB>9%0P zvYx>N0<#_>DKmNp7wX+`OwELro4D1wD{0WT-mUT`oQb$I<jyJ(si5548>~g3zFQB9P-z$SFJb_NP4o6(w8OALCR*`aMB7 zFITe}%)E+p_1VO-*Q34(XA>BHw4((>LYn%tA~d=S`Z~1Fk*#D~5Ju)x-%5WmXULD? z)^$7z+7Bo+msf}7I%#|VmOB!xwx16_W5t;E%3=~<`4Y=#WG_W-4bFRO=S=nG9>@y) z9L@h_4>WZt{*_K!@hi(}faa)oIF?$I58&IOlj`9d-munrcc&))rEa z)o9o!s(G)gN#R|0p4wUlgy50_H~zuh5=#PWas!I*wvkqXco5Onb{`?d>^h}TKqvOt ziq~Hsczmr38hB1mTn-}Fh|G&M5M z&AVkVHcU@<{^$%^kyNiP(|pH}s$un*#(!XLo5?-4K3MG&m}L$B%^dt(`qF zM4q9a@(Nr#6`t~)@cqK>(ku-7FwvzDZ(gCDtZ6$0q7&{fq_p(sjr$ygmOqk2g$8Kf&Z;Z$+Q@qi6lK~F%* zgpu4YTNA}f&J-V70I2z)+NPrrQTVbHX+!1xWkc8GO9i(iP;Z6VnQfx%w%-jzg8(XY_lbeBYhDdLJ^cIXBx)`av~ zU$VxV?mOMxlF<@zxWB9XYIi;k_*hY<84MA*5>D9@-67ylGo@GBLT+C;*jk}D2G?uzze}3LG+-=I9HJZNedPf$$Gr|(QomVD4?rl@rN&Lf`q}9yy{6xB`F0H)O zaUSvTH1=$0>dlY$8?`$_>-5Rbjr7(6$+4she^e)REja6L@; zyF``SULgW299PoO2IIcbS+>=&wJBHRru1F_<(_Eh&FL|$1>|>OtnDT>H zf*gRBO>GBh2{TqRWP|S;gw!okQ^pT%O!5dBUYT=z2LHjui{*utBl1eN-sS@a4aw7_&CjCz9>sR57aCXD#z&C?}4dnY#6Eci#H} zPjE03k=;JHP3FjPIj4nk+D5M zY+7-?x2*1(JVJ^KVpiH7BkfpA#H|@rr2{jnC_~1Nl9NtbAQTF}9p#V*cIn z+zxA9%GF&t_ucOl^#+95J~h^bSP#rqr{L2faw`X@*%#szB=>$+{`{Gp|A(MbBA2xt=7ro z`!v!ZR1Murw5qS)Ct=jE6uI38l%LI1NDT_U!#VKQWCdyfzLJG0BVF_`T)N8wG2Dj< z{G@$rX*o$s+X4?)V5?|s^I#gYX^#%YsgGb*4Y7ToMLlz%wd+|t*f)-FwUu%o21Ofx zCgHz#5_nVpyE_S+R_rIA7`Bv>*sV;CQ`yZ%j&nK|TD&dtwHG=EqZ25HFSrxxhfm2P z;)6)8gYt{S_2~@Mb9C6@Zd}K>EUx_5=fqn@`iH`kJ(|_8qNpykcUGA+6epSq03r5A zB^Zv}0*@tI2L^f#4b|5U1cjdrGSz{VusQmLU7;Baz%x1~7Cnqx;22#2c^~Gu;~F6J z;ZzB(Y{h^TE+ajR0xw=v$iDIAE1vTA5!^ODk60%W#LDZ=Vdkwt?k!fgg|B>Jor{27 z+YsXg>Bq0PK&^Jx;qXoBAr+Ljr+zYEF0A0~aSl32lw)uSustaa98ypk5a@Mm7Y)32 z-1k8A!1h_76JLoZx5g~vvmeRRyn4Q%mw^^GK(sAt3~K$Q;B)19k~`bNy`7(nm2WmV zgRY7KRKj4{5`URz(EPcb&CkVkrLN+%d$Rw$NKR0-qKtTwGfXM$NU4PPZ-S22=%WsjfrWZy9^A))Md<3E!ag{F7E&e!NO^`n@dPqhnSY-RDF%9XF zrnb()WfjiK$qytie9nIP5QByqF=)ZWDD6x*3B*8Qk4BfdS4hQB-h|v;p(oUF#I3(n zbYncldU2};A(091vnnXJl~k&+nM-ThBzk5tZfmcXE8_sS37)bP8T;5&m^mBk=pE!Z$qLY$Rg936+tNYt z(#1liBIvSv^+I<@^<2~E!?ZwF3V#13Wh7vtvY+`AUqi@(q6|YtFBxafHOwoW(*Eyn zr1-$v@Yz%yj7HqFpKPB+TClW;A+4$0tI5bHYK-ZdG%P;%&bKKO)nj4slq5|^!jTuV z;^lp6L@!-p_{U9P`XFORPrl_bt`w;0zrmxIBG+T^98+D!aCSuaq6POcK$+ddSuD}g z#4soRZAEj43=h2*jF%e>!t+bZ0}O_!_u)xBfd#ka1%wk zqH;ECj-ZbuMkffU;&F9{?gc;d2U7Hx8C$HC8sLcR=Bo~$K(L~QWbWGmZK8q2ADklK z(a8fbs6HQF`kQ{Z@vSlqN1gl*2r?NP4Nm+9a#hbJH4i2$aguMQ?RL~7kk8Ru{X<^z zR$cb=h=c|Xn(r3XbAs$ZJrBfIpQy2e%P`80F>Mlpxv02&PEi zi3(25vl&vIq^(x0k;ttkn`ELgWNnItnNMP|c7(NBiZ@E1(Ws{Pj~bg>x8Y57kHQ8eU6mbgeF zy4=T**}|nl=t{XlB;oQ(7zfma$^NQfE69=%nkM%zmlM_oKixX16HZ|Q7CDBPm8WyPt=*nN|e#wn85 z?Rvh~MRV=Q%E-_f)|wDA?`1As`M;JCV#_}iDhclMiYbv?)g4T2%=|XoUkn9qNhrSK zX-{zy14fd7;fVo`dL&PvFXx6{@HeC95%%Nj{)_RbB}HdcBF!!k~7xCh2Oi&ai#NhCGJpVpxWalR`& z^OI*zjZp0mHVROJ@^w(Lx_r{Q*ieYt{;6+2=J`#TJ(?($0VVIH zikB_m;5`&|APDnk`O6pS1DG;yhFk{>)&-8GLtV13RAB$b^bUfy2}niI#%MB#NCH*d2Q|PhEQah9w;;QRf1H!5Xm4&8jk&RE6^qPb_&n z#~5)_0v*u)HVQI$fLoy%c7s2FYY|yrGWdh{CqE>hkZubslh*W1;1y!+BVBRBsu|tS zlndk?g|`PqE7H#lt1m0Ct;sa(RC;Y8L{dqAwx==k!Dr-bmbsGgU2=Q2ZtpOwFp1XJ zl5@$}dRRf>!O`j=Xo%d?+(mh)#1}2D5-c)XLFx5EpkBxlNJOMd%+9MGS2-+sN2rM) z?K6zdkI@o@uW0!?3J#Cc+N%#+O17z#T}1>#uJX#<6mc3MoYN{6_jE~RMMm4BLu0>8_mTvLYE}d(p-Qq-s2Zf3aQpR zpMFu>O~@UWXwsNJDj$WoNj>d^APTMgm(BXsisoHgr3q*$JIJVcA^ewz=d39s<@2JI z3Ewmxq6vSU9yg4}+)U}uk(QFlG(b||LI|PQ9bNur*uDM+MWb@5)Q$f7GQM%%L@yZa z?{+Ks8&#Rk8#zkUM(LyIr@}sToy}r|vaHA`lLjq%tr&<~8>_}}nS8l>5Xm~N^NFy^ z5SQnFfNs%1Q17$p;a*eWvCK^D;m+K){1F(Zpp-=ezw@KSomKrb<7*D#R~KaL6eIURN?$9K z_kxxm`(zocnJ>d(@-5MQWU-^}KjyM6FAJN!4oQg*S%ItZad!xAtMv14p#&^OR=~^v zPzOS0y0@MXIkTUw>FKOskUz*?8gK25L9%?~`| z&!#W$d*9&yc^I4>D?PMB4+3I?2KIk~l>R5acBA~0Vf7z6=|A)z0IG(yn}eyNiH*H0 zGw^?k|3SU}Zve0VT7&e$fc@jPR zXSzBa21fnn#*|IIfMVa7g$XZM2g7Q;swE%7Evv&UUf0CmzpopJ;^07A$EK#ZhBLp{ zv?`n*Izuu4)o&(yBTb=hOK!|z=c16hp>C%KjU62Cw3U}EpB>$lIzZ25kUGT7( z_2pR}6)zY+>ek)=*a@V(o`SocD~@`NarCd5CcYE%UaF>Y9-nI`Mv&Jd+%Wlh@3>ln z%r$(Hub&Mt<}PjGlXSM>GB;O7gy3TD;+1w-nO8>fCyjG;DU+ z+PzFyMShHVCn5vUKC&7Y@}i_?rWT}P;k0vp=W|{AZhT2?zV_LsrGMh?RO_;|GFy@y zX1uCl5@casey?*HH+EDIN+i~8oC9bMhF1+Sb5ogjHgGJ|SMEJ!z4cA;`)qkBk~_)` z^^;>429N!j(Ba~>mCBv`BMq$&HRv$Gn{aeT5sU4%I_3pEKoa;J2x746uh^2}-@QNi zq^c^ocBG6)$Z~pqzX>lt;VcuMn>kohd60O|C?4{$!FW0On;2U|Uv+wYm~VzS)$xPnFX4`6X;Bp^UEw@`dUlF$FHL_TqJ|QuJT|ZJV>GNLy zFsd@_X#VWUxj-K#y@1I}><}VQ?rs4rZ)#tnAJ4MBzV9X&6DxXbS-j@#H}}lZRROnF z^N(Mm3-<}7H=hY{Une`a{Br)jsvQ!R`&;s$fE1zr|M`E+KyQnN_x-PqX)}*p<_^Ez zLdA8mH$>l;xKKb42;D}v?@EW`y0D)&MVa3@H`b+0^z~Ui$=+z-h%tabu-nz^7Ls`z zs`&8m>7H6hfpeG&)ofyRvckw5Sh>jObe`dt56;(dq2lsc^vC%3M(`e$KanO=t)SEw z>2;uc)RqD>-Syl0%byAMp2(9d9zWSAr7A)@$DGXuR#(5V4r4{@r@_P0(x&rsdwF6F z@AHFUUHm;OqEFLnumL^WvLh2l=DHZIiv1Mf5(`Cn1a^QxE9GTSm-Dt2gi2q9622?J z#ivA~NwnO_QssWmE$nT>5tU+QcEkCnZny~{`Z|-Tm`oIrj~rejQ-dCOa7T=_>Kdn) zg!zFEa+HOiT$lLwi+z9nYI9fRprEN(G|oD3VM9_eQxYy464VzTPx0;C3o8_m|r! zH_Q5JfBxpQww63f`HlKdaR8UcVyX2yqoYwwz=i*jr(^S_CgW8sD?9uAX$q`~$?^m~ z@gV+(p#%u#uWEnC*p}cADmRW2VwMzu&>4W02^aJ##|mNnn(NQfV!$d(v$@0c>uXe8 zrq!LRaNEOg6xSeLz-I5Yr;+2#eFA06bVh`gqXFCS&YS=6bO5IH|53?TfJL?SUk@k@ z%8-H#DUA{m(g@NaB?1ysLr60)Ff^#NbV!#pl9Cb<(jg!rHFS54pa{r+@V#*IT!BF3vWSQGZ z2d1~v6(@8pEJ1NQ3Gd1a(ujr94czUegD71gVPWSron@ZpqNz8^?&SOT9}jigweN5= zcYIA2FhBMo_~w`^uv;BwhG{Z@bc>fdw`C*%XJ_?}U+u#vNo%S8_N&vqkc zN6v!`wITtvd17t~hy5@SvFBp9h1$YxQSKse_P=ty&xcXxn6u@L-{8!xA*LvQ5pi<| zYlyA=KY)LCQU@s1$`)c{V)Z}b>`~q)aC<`t>>qFxzp1P(3~GvUL;3$8&qj;CHqTj2 z|M`5sL!Gtf|BiZM1%)`6oL}4TtX)u9aDS^I#K_3R$^>;kp)htMI1KimB)ChcVKMM5 zNgr@Fo;`~{=klMKzSujsSeg9D=ib!S3Y+I8^qkg*+?1W7U*AhhS;d7JJjcj31;+Q* zW0p!Hx@6O-J2$sny6%nodyJmGZ7_BT;DT$HE@lWTJj+zP-a6NwXIP?{K6Uz)@N0%C zJ`)van?X?}ivWvq#dUT~@7u}h_MXnS-C5}NENoR^rq{QZ5ddLkTFu9cB(R`hbSmG| z8*iDVEWgHHjlBt=cY19Pq{Avc1MCIzdV%RKZe4)=Di#Z&syw zyH+>=sv2IrtZusMs>jo~QLtH6mP9a@o(r~dQsLC8w>HRG_d84uyP?8x*f;N=tkWts zQqN(H#>{k(-rJlx1DPNjZS`(pPwg?-5{`L&2q?l@DSgAL5Zc>=twD)AG9Va z;V=$X>6jr6au?ZZL<)tG_48uApma@6YcD5O3E})2LYEY5g#Vtu2TjY7uO^p7n2&Uw zdnZv5v&bYfe-v&hMpS#N4%s z|C9x+%)U*dtsGl<$(V%Sb8jbQyy=~@YKudt<44Rht_j7z|5k=-M1 zt3V;I&RRkmwwKZqWpwQDa9u4|_QvS8x*E!p4McBjZ?fv%bFHr+bSRp~TOpEy)`(#D z&t9#Jq#l*c#-G!wzo2W`$M!jH5L9pR9nUYHG={F~;PN2-x!z~P8mqUvx`24qye)d+ z)z%BIBsB&(vtl)k%w{e)B2{Taq!l?D+XuJ3h5%%w(& z4v$s>)n+TyD*0|H(2{TS3X_Q5w>at_e_|k$_)(5ea<`+b-`H8qhZ3kAb|4|D*U~8M z#@N!ZoLPV=lxP;j2<$MMkoRQG32FklreVJ^_5ISYa4U|WR9SD_6CL&@Jk?9oSH&x* z%0*K^fJ(!pJn?deS@TL$p@LvvxWYWnO^#0mhgg>45zhJqzBbagZXq{qD@rtSv3xQc z#c&^xWyqbL*e`Z+!B{un6wnBf9a~9DxOIs33PRxeBL$4>A?n9_CF4wvg&sSlIU`AV zmDBGWH>2Hp^S|$^jQ2bcBOe{w$rF37^pM;osDx!-1DsB*X7thi)wW5#Mz-YRzE;HD zPggSQYNV{u=7=}BkbZ%oiI3JP>5HB3DEXF)KJ%&05-2LP4CWEKAy!rtMaDY8`;gZK z$7q|SMTF;}2GlqEd!J&YYqtiicf{sgKvZx!W?A~`wGSYTl4s_Dd=7B9h-S7iU@>s? zabY!?AetqDAyKIhUV?7x%f(fDMRqZkmaMgFWV~yDRrnp#bH-`;z@-X$iM#P(2N@y^ zF(l;Ez}0|9bFgxw@D*ikhWW2eb)OqfzYCG@Z_y-uh~Rxr(p6t4%5$ir+z)6|#0((C zWkjU*gFHQP!jI_ToJvx)MoRTe+QYm9RQxM4Gor&dE@&|vm>?g7Ls5cqD__aJ!ws zkq~H%H}uAp*Q3<7Mr6se?OjxFd!G0Rvkwx6r|T94^VZS4SRRtrI%pLyeQv6DlHpfi zqPh|OY1`HktK|XU@P4|WmbKji#Z9)$lTBP>wy>H@)Ex+3uW(iF=I|(PK*R{2M8Bvw zJ?L`(cy_vWe+Kv~mF92&gL_d_m!OwItJ7L9#_NO2IWu$0GntRsrMdw)IH@rorO; zO@%VKx4tJr9da90v+g>FYlam+^Tlw`S8kK8y%fhbqiXEvRu3{2=;e;du(o7>+l zSp0l5#ld{j#}YI8H6J9)auRKYX#n(WmaStE|K`@4G1Lr|>VDfIzIB7P&WD5!?^xPN z`%qsNfMe;4utyndF;?Lr8k7A`t!w>!&}`=7NTsA5uDP05TCNMCx!(A6%p*UhIocbm z9z5vWy|c%DIjM^;EvteclTKQk57w!2X)V&tu0AQC3;=E-q5zJ+QsNh`SzGZ7GPBj? z*3^*V{+esXfe~KZ^3>D2e+HA|*Oz4oZ=_8IO^5b~oXrXL_ zYsQprvn0pl#M^SQ`N8uF=JtyYCBu?9>s`GvVG6lN>-YTWB@~M;rHxfE4y|sQV7;V$H(0TF4HdyOtB+G%7S}X4<}Y>wm#!K zx$4XlWL6DIoNopQ2^Sq--V0d_)L8;Vf{x=x@&#YL=OF@y)bpF6%DGn&l9*Eui6neD zB(ctmA`%*cCVU#ue+p+LO>jb$50;o(PU{0!_g!D!ekSDD1R>gs40OUL4Bb2AII`RT zJ36#0B2CmXU)==iQU6gEhfJRi0{7+GT{L|A@}xz$`Yc!I)Jch%S3(%R42(-(H}ih) zrZ+hY!jno4H^DviY)y=cH-9r7Pcx!s!WCaCesEA#z+4kCx#mKFN2V>!jcihQ`CODL zGh3f5K%PSd6MdI^dMYwu;*L0QuE_dG4-eJUNq!U z+@6SYniIQ&Uz!7W^mJf~>P>v2V^0;CvfmW>XdU_>h%=`8vQrPsp_pz9O>cNZ1}KdNi7E>Jet6R?T$v z2F+aYtvTRA_>OP%oz6)fzp>jMXhtN<>J;w90(1F$Tu<2Ruio#v9o_B}w=Z1#e{C-&v^tx?oyj7qW{GRyj$;RN*F{gEs z>ri^cp>`p7xWJ(0AgpE=HWq{`Ws~zxI!j*U5%wc}qt^886mfPkA5XjiuiI=_R+lU0KrD))`Pekbm-OAK z$=jgfuJKIe=bs0pGMD;k)yBnDn0N?#@*|`Yp))$l^j81!=bo$;54<@$dL!nGpPIB1-NSA$zG2A;HIJ&sATFf2= z5#21H$z@C#5P_w&ZH`V8B)-?}o2T?^pLvZJnv=~^GlemDcRdTQz!j>Av{8Cq;CV~# zQ%;u;W5}?Wd{mSYOHp~)9dB1xJ8NK!{3@A_g*j3ehQg>9Sq z)eQ*ypH%fWLp+t279d+|Hs$6>i*nauOcvWEFg?vZbgk{-uZAsDKsx0I{6&%1-2vD zSyIGof#);*&R+wp7Ld(lKAADXKGe)En2@G9=webD-pnySX(tg+LMf{Vg|{8uj=3DJ z=iY~UX+N=&MaB2Z$EPb^9Ud^~S>x}k;_ptkD`8v1xvYxYqJCK&Q*0FfeRR+>7B5zr z+wbSs$daJ4)rHGj-02Q0je)x5=AgY1yGZ}PrnpMMx=B8G0Km(-fBJSOMt!?0N~wvl z$tg**TSIKjpP1PHaKR~5Q-n5gfa;Jec@v2R)HG@;_=px4;K8NRA-0IUtQN7I?N~>2 zK}G7k2>Fds&+XRGQk@$WUAQye<=M0t9yFw2h^6^>p!-(kp;v)MRMwI-FaDdmFS8a=b zi>1ltxlS0*P~@^R>;b`6QlyvBeIp=h`j>-pEwfib)-6?H6wG$xp@G7u0%y_!!^*Fm zyvVV2chz@L)1mkSzec-Yvhcy7QE~$;8Dm{%A~Qe>_sNcf0R+d9(vx?~=Ei>P>_ZGc zQ>0Q*))L#B+aiIBJqgm4{a^6t6i7+XiRedM8PmUffgao|0_xibWJif+WEuu=z`i>_ z+*$b?yV2M8<{RdjVxl76#d8Pcfv5Jv0}liw1aXT!c9TF?LEu0@$9p?rmZ*fai$`q@( z%yj7@WKa+4PZmt)z;iY6*Gbt6pn=ezr)Ym=xj+E`XR_i&Kqdb!jQy-^{`Y;n!2P9d zUTo+5hUafe=by>`yHX3kA^TbR{I@(5Qh&d=pOw%*^PFj+7oqkWp8r-x|IBoza$ZE} zZ5<@DdOeESW{g_8Og%lWH#b_M5h=$V#!5ggKgZ{t5GtLIPUIqA>+ w^qG=+5&kIB3tjbB+|NDDSucJO5|94Sr$3O#K)u%h00HV3f$E^DHO{vF4=Z5z9RL6T 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 2224/4212] 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 2225/4212] 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 2226/4212] 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 2227/4212] 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 2228/4212] 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 2229/4212] 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 2230/4212] 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 2231/4212] 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 2232/4212] 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 2233/4212] 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 2234/4212] 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 2235/4212] 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 2236/4212] 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 2237/4212] 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 2238/4212] 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 2239/4212] ++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 2240/4212] 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 2241/4212] 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 2242/4212] 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 2243/4212] 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 2244/4212] 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 2245/4212] 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 2246/4212] 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 2247/4212] ++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 2248/4212] 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 321b39ee893c012341c988b151f1f186332a72de Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 28 Nov 2013 14:11:23 +0100 Subject: [PATCH 2249/4212] use new docs/ (from 2012 or so) Signed-off-by: Nico Schottelius --- {doc => docs}/dev/logs/2012-05-24.preos | 0 docs/dev/logs/2013-11-28.preos | 2 ++ 2 files changed, 2 insertions(+) rename {doc => docs}/dev/logs/2012-05-24.preos (100%) create mode 100644 docs/dev/logs/2013-11-28.preos 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 diff --git a/docs/dev/logs/2013-11-28.preos b/docs/dev/logs/2013-11-28.preos new file mode 100644 index 00000000..aa34f377 --- /dev/null +++ b/docs/dev/logs/2013-11-28.preos @@ -0,0 +1,2 @@ +- debootstrap for the moment +- From 65cab0d0e8adf4fac88ee0f3e909131273d4d45f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 28 Nov 2013 14:18:24 +0100 Subject: [PATCH 2250/4212] add "preos" subcommand to generate preos Signed-off-by: Nico Schottelius --- cdist/preos.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ scripts/cdist | 10 +++++++++ 2 files changed, 71 insertions(+) create mode 100644 cdist/preos.py diff --git a/cdist/preos.py b/cdist/preos.py new file mode 100644 index 00000000..29181057 --- /dev/null +++ b/cdist/preos.py @@ -0,0 +1,61 @@ +# -*- 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 os +import subprocess + +# initialise cdist +import cdist.exec.local + +import cdist.config + +log = logging.getLogger(__name__) + +class PreOS(object): + + def __init__(self, target_dir, arch="amd64"): + + self.target_dir = target_dir + self.arch = arch + + self.command = "debootstrap" + self.suite = "wheezy" + self.options = [ "--include=openssh-server", + "--arch=%s" % self.arch ] + + def run(self): + cmd = [ self.command ] + cmd.extend(self.options) + cmd.append(self.suite) + cmd.append(self.target_dir) + + log.debug("Bootstrap: %s" % cmd) + + subprocess.call(cmd) + + + @classmethod + def commandline(cls, args): + print(args) + self = cls(target_dir=args.target_dir[0], + arch=args.arch) + self.run() diff --git a/scripts/cdist b/scripts/cdist index 39449666..f4d4ce93 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -26,6 +26,7 @@ def commandline(): import cdist.banner import cdist.config + import cdist.preos import cdist.shell # Construct parser others can reuse @@ -83,6 +84,15 @@ def commandline(): default=cdist.REMOTE_EXEC) parser['config'].set_defaults(func=cdist.config.Config.commandline) + # PreOS + parser['preos'] = parser['sub'].add_parser('preos', + parents=[parser['loglevel']]) + parser['preos'].add_argument('-a', '--arch', + help='Select architecture for preos', default="amd64") + parser['preos'].add_argument('target_dir', nargs=1, + help='Select target directory') + parser['preos'].set_defaults(func=cdist.preos.PreOS.commandline) + # Shell parser['shell'] = parser['sub'].add_parser('shell', parents=[parser['loglevel']]) From adab98799485adb826fff7b8ded384668c1df606 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 29 Nov 2013 16:02:00 +0100 Subject: [PATCH 2251/4212] minor updates for preos Signed-off-by: Nico Schottelius --- cdist/preos.py | 4 +++- docs/dev/logs/2013-11-28.preos | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cdist/preos.py b/cdist/preos.py index 29181057..77d6d6dc 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -42,7 +42,7 @@ class PreOS(object): self.options = [ "--include=openssh-server", "--arch=%s" % self.arch ] - def run(self): + def bootstrap(self): cmd = [ self.command ] cmd.extend(self.options) cmd.append(self.suite) @@ -52,6 +52,8 @@ class PreOS(object): subprocess.call(cmd) + def run(self): + self.bootstrap() @classmethod def commandline(cls, args): diff --git a/docs/dev/logs/2013-11-28.preos b/docs/dev/logs/2013-11-28.preos index aa34f377..f8561135 100644 --- a/docs/dev/logs/2013-11-28.preos +++ b/docs/dev/logs/2013-11-28.preos @@ -1,2 +1,2 @@ - debootstrap for the moment -- +- add triggers: https://github.com/telmich/cdist/issues/214 From 8998ea929890e918eab76d84c6e2825a7a25d223 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 29 Nov 2013 16:02:17 +0100 Subject: [PATCH 2252/4212] ++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 2253/4212] 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 2254/4212] 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 2255/4212] ++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 a6e2cf853e55e7123c9923b7e86ce31b0cc618fd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 1 Dec 2013 22:33:13 +0100 Subject: [PATCH 2256/4212] mkdiropt needs to be unquoted => empty if not existing Otherwise this happens: root@lilly ~ # cat /var/lib/cdist/object/__directory/vm/.cdist/code-remote rm -f "/vm" mkdir "" "/vm" which results into mkdir: cannot create directory `': No such file or directory Signed-off-by: Nico Schottelius --- cdist/conf/type/__directory/gencode-remote | 2 +- docs/changelog | 1 + 2 files changed, 2 insertions(+), 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 diff --git a/docs/changelog b/docs/changelog index 67eaca1a..b9056fa6 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 __directory: Fix newly introduced quoting issue * Core: Fix backtrace when cache cannot be deleted 2.3.6: 2013-11-25 From d074713b94f026e4de78bb3c07b777a3066e7d85 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 2 Dec 2013 13:27:42 +0100 Subject: [PATCH 2257/4212] 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 2258/4212] ++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 2259/4212] 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 2260/4212] 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 2261/4212] 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 2262/4212] 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 2263/4212] 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 2264/4212] 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 2265/4212] =?UTF-8?q?aus=20versehen=20eine=20.direcotry=20?= =?UTF-8?q?datei=20vom=20dolphin=20eingecheckt,=20nun=20wieder=20gel=C3=B6?= =?UTF-8?q?scht=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 2266/4212] 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 2267/4212] 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 2268/4212] 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 2269/4212] 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 2270/4212] ++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 2271/4212] 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 2272/4212] 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 2273/4212] 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 2274/4212] 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 2275/4212] 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 2276/4212] 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 2277/4212] 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 2278/4212] 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 2279/4212] 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 2280/4212] 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 2281/4212] 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 2282/4212] 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 2283/4212] 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 2284/4212] ++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 2285/4212] 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 2286/4212] 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 2287/4212] 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 2288/4212] 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 2289/4212] ++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 2290/4212] 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 2291/4212] ++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 2292/4212] 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 2293/4212] =?UTF-8?q?Verbesserungen=20am=20=5F=5Fcron=20ty?= =?UTF-8?q?pe=201.=20Filter=20messages=20from=20crontab=20-l=20welche=20da?= =?UTF-8?q?s=20ganze=20file=20f=C3=BCllen=202.=20neuer=20parameter=20raw?= =?UTF-8?q?=5Fcommand,=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 2294/4212] =?UTF-8?q?revert=20vom=20chmod=20der=20aus=20ve?= =?UTF-8?q?rsehen=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 2295/4212] 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 2296/4212] ++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 2297/4212] 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 2298/4212] 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 2299/4212] 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 2300/4212] ++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 2301/4212] ++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 2302/4212] 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 2303/4212] 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 2304/4212] ++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 2305/4212] 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 2306/4212] ++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 2307/4212] =?UTF-8?q?vorbereitung=20um=20mit=20zypper=20au?= =?UTF-8?q?ch=20spezifische=20versionen=20zu=20unterst=C3=BCtzen=20paramet?= =?UTF-8?q?er=20ptype=20auch=20beim=20package=20type=20zulassen,=20analog?= =?UTF-8?q?=20anderer=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 2308/4212] ++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 2309/4212] 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 2310/4212] __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 2311/4212] 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 2312/4212] 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 2313/4212] 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 2314/4212] +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 2315/4212] ++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 2316/4212] ++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 2317/4212] 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 2318/4212] 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 2319/4212] 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 2320/4212] 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 2321/4212] 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 2322/4212] ++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 2323/4212] 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 2324/4212] 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 2325/4212] 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 2326/4212] 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 2327/4212] 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 2328/4212] __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 2329/4212] 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 2330/4212] 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 2331/4212] ++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 2332/4212] 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 2333/4212] ++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 2334/4212] ++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 2335/4212] ++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 2336/4212] ++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 2337/4212] 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 2338/4212] 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 2339/4212] ++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 2340/4212] 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 2341/4212] 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 2342/4212] 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 2343/4212] 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 2344/4212] 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 2345/4212] 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 2346/4212] 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 2347/4212] 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 2348/4212] 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 2349/4212] 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 2350/4212] ++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 2351/4212] 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 2352/4212] ++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 2353/4212] 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 2354/4212] ++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 2355/4212] 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 zcmV)CK*GNtiwFP!000001Ejsn(k{tuB)Hd8lyN_YagRWo)cqQ>WlJ?JT2m|;SsF>3 zdG<+%I}lmjvl-^*{N^X~i;N2bK;RaC|KI-OU;gyd|NZk{{`$vX{`?QWt3S%`e){XL zfB5r1{ozl){Q2j9_}!m>`Q3l}uYdRV|MAPe{pHVpc)eJDj34`V&y!#O`0Jm3{;&V1 zp8wM?|M+kJ^7Eg6{ptVs>90Tk{L?@G`s=^`m*4;XU;gmxKmYibKmPjT=YRUQ-~T^< z__x3O@^Am~`@jD3fBpLJfB4JKzgOG8|NGywt-t&GfBnP%`1z-Q|KmUX`p^IHyJ_=B z+rRtipMU=2|M=%$|KWFM)E~$2<^TSNfBc{S<7w*8|Mb(Z|M{;^U;p~cpZ@qyzx(MQ zfBDldfBA>s{rf-v@zac5^SOG~k1>DR^+!8D0rU+}mV?!P+U1AUe3GD5 z|4n&;`3Bn(v>&a%z#a~2|7rIhZM}ds2j%I`_%ZOC`NKAV4F{+EwC9hp9PFoW&&zzW z2EaHD=K5*xA7#J57%#AUg7c%aZ2J7DB|o}K=jl{=fpRBg z{8*E~0NS12{$sQ0IbO4aRmgeU2cWa*XI`GUK6q{asCO0iLtD8%`^T)ga?j`&z(RMP z(HDR@9P|z_ii5RYzz#si;0&wzfHobB{Q`>(YzOD$N9~8L=#CXk5<0paU=FG;@B=Uh z&)|-O*#S;-uxd<*dFL@zY;8M*l=TAh{p4KmY`O6Q>m(o{J>Z#35K?`C&DSv38xwW` zh{7tU<^gLt=>Ej!Pk;CKzvou`|Gy{gp+t)vVGkuHX*>Yb(D5(8GgS|m(*a0OVEs5g zVb~Go8{>kq6Fj?UzCa%@P;LW5Gww}~AARNYKNIg;_h2TT|Eswc9s6|q%K#6-itZoK zTI`4iJa0eXS?mB>ivZq({-fUM?>_7e(g6U~Jv4r@JDY3%&_RnGZvHv!@SVdJSRnET zbj~Pt>jTUIHk-gvYYq%QjRp)`liz8j;05xSR;n+FcN72w{VdFUK*QT4Gytr&GZ%n9 z#XRnlhiuURsLq)o0O-JH6ac+;o{1i8fAa8i?~X4?9S*qk#vz<068qaJwbg<>xt>k` z4E_PnBtM{_Q_rUFKTQL_0eC3r0jCp`*K5x%QUecodi?<7YtLe?XP}stgJoU~Bna@3 z)9M`j2C1)SpPPecs+P0aRu-0dZSW3&`ZR5zpjM`DdgogJlzEd+s&m`f92D*dJQ>c! z2Ad9W?h_YG@f$7X1j~zMo-Sw?HV(it5p;BCV_$ejiLh9Lm0F<-kIH2^Y)xqrAL;*+!0xnhpEU?sQ zfLmWpJ5%^Fkb|{)HiV&52Nd=IAJsvxAMnUwe`4A^=a*|A6QJ9#DpZXRDl!DFS$Q)M?JvnhUW9fO)kA+C0_wJiyaH z0k0L<&S5U7J$^%OuGU1z{EoICd!SwVfazQI*-+}J*yjVzlHQ^5JTx(;j}(%IOasHN zK}Q4+qdD~jO1`#yjslQ5B`7T>@!?^8Ie0X=A_WDgf#ap-iczt( z2YeV+Uzj%P$pED$n4o(q%>ndjg6_L40SI0VkgU7Q!Uyc;V6>qAP7&kkSnCuqt}J~S zh&k1gxI2aV`ncrdc-LI-Y-3}sG|&gMB?TFvv;@ngtX|`(*Oh93+JdK#DJ>Rq{sFD) zMA61@m5I|foUcKPC8&O)==hE6RGPyFJmTO1Ajb#Hs#79BpVDsupy*LTj4sIx2JnEA zl39QPJV9^yn*&Z3-#M;rsXKm#Lq~DQGgrMd9x~2nq+{o6oDk<0A698LXk*eoXLZuz zl09HFohSh62`)Q}s8(P$ok9TG$t5$WH?c~lB?D7=09iY9<_FY~)6a7(wXp{rUkl@t z-E+px4<1yE)EdFlgFIdUtkjZbockaJA7B_8+EfodEGC7^T&~_MU(@MIP6Gos08BDK{b_Ee zaq{`;A{F4#qv!ESe!$b~=Rg4BebkeOG;{`lu2Mtoe?WCXQt+FK?eTmXLtK8GlBWNF z?konfP{3ScU2fN+i6ej;rvfxTH}E$+4XJ6Z1v+9euPcsiwME~!%wOiUUaJQHrAj&Z z>4vq8uL*QF+$2~tfv-}4DJ2DhV)+mVK6DrMoiP0Y)G!wUlp5+f^q&z=mLCG8EInYQ zYQ1>wptN2tD8#K7k0*oFa(uV@86Mz-SPI~>@&YF}{)Ss}#bM{0(v6c(i5|lAXThnq zt833djG*SIHsuL54TuN}qQiJnZ-H1zX$`(MV(?^{I`?m~c9P=`5dwV>?F2bq0D9JI zeroduENl|6)s*0S;3_+x%rLlY4#8qxHB!#_rhw&IfEQXw!R@CIZK4N^A_K*T>3@y_ zb%$#990kq{ZR`Q7#3p*c7%}4y=sC#`pj~aVflFbBteulAFrzhs)ABcD0Eg0v@RIYnsuase;_nZzzW!uu=}=;8#L*dcdeTgz0863V&G6 zPlDycrX~Pe_Y4~g%-by&Yq?p4d*wJ;QW5_^K}OTl_H&;dKc#G!Xb&iEEPD25vyG7g zJpHhR!7aBe0nGCPZN5Nt83d6CE31V-5;#r`dd-jJ0M9CbQ}H(si7mH>p$FZWY3UA5 z8ZDlVroRT`DJ>-017^5eI*ffqn*g9qEhfOIn(+&^fNA~WiJus}wG(^AObiL;#s`eF zJwAP-i4yb(BX;V}Fs#l{Tr3VF4u&*22d+v4aO1`WwIm1$JwH*yqxzm5+QoK-0XCE` z2GP2Gu^)1E|5XLS2k=vuz%zp9YXO{@62O?-O9JO70=0rT11$UzXcfwP0Jj+mbhn-a zSYXfsqe3wa;A)+~qrdK!V7ak}02)~K4TrdF0A8qU8geK5_RN80-=04u`}Qnp$-cpT z5e;{yfD=WtF2W_2EvNH2A17Ks85Pi&ORsm6@|)n5_%oYZEx6uK;Vk0DOAGodp1#=;z$= zfIb{N((?gr<$5G|7*M>%Wm5z0?1}Gibraai?vMzK&>#XEd3t8+KHKCiYGwKQlXqjZXWV{H@Y-pm-fY_3w|svS@%Gc z;m$uS{As}qUj!p!I>}G*yGk;sY-NxOgKi#l$|V>Er@+3p9f@ELS8Udc7MZl(T;yG9 z#aVKaq~?s%3NPe~l+E`Og+PV3u}7~zP+I4{#MXa41rxXBYzG?7y1R!>__~-Qmnfu| z2RYXo)Cm?uZO~75SsPsOLG@fTd`d2AmUPg2h!1bGQ!tQTyVi`9-L*_l@D#W&4xUCj~2B9`?c4D%x6n@0LUm!eJ5PkfJS_Mml=etP4)m^X%A zTe6r=wk4+0xoM`K&wVDya0X{-_KT*|2#mp;Yjh%>aaGvL2O5FMwB#xeS|jIvFbqmm zF-p*ZPi*m!B5|=%xFbmp-BOm6Hv*pxMAE!y^xKNIO<~iA8%%vUWD@Ep*Cocl-2?T2 zD^aK{*h~R3{EROJ?aQnU>bK-aa4wMYHn+{yt#T??FupZ%^n)>4)X#ilQpddVI>aYP zoSK}Z@2oLTA4V~yV7m4UQnH#H0Ys;v4NAb3906oKa`%GS)#M06T5qD-E;>%@+UHn2 zyVR9vzuqM0ilr2@v6!yIFHEjPJ;{c_1Ge|Nv|JZ#zms#XZ6sv{K8-uuvyiN)ti-%f zS$XEHu!GVQHmPgv+vbUlDwV%T6Jh78L;|O-e>tbsIZ20Fr5U@|S8#E8$T_EnR_0o7 zc7wb3L1(07m?sWcAUSv{YLf9ZN@Z93>ngGGV1&;Zxp1vP{;P&8z<(|&V9fdh&Z$>K_;W@;!Ujz zwTGA&`{vuKFvpGDXAf#6X=IW7ML#R`O`-KdMg`u{m)=MkaEypj>oIR1T5a6-^a<5! zPSy;Y0|M;f#gBPF+fr@?rrt@L2KqrH12JU??Jr;`a+{r0pJxxzc**ioa-T$XF5VR z8ac)$=`{CXIh9mLU~rojCB$%%642pBCbnrcK|mFrxxobpWDF<6A_C=gSN9MVR2_k@ zHW~)#F$2P9>4*n{h}h(^jfM}nkIWIsfAcig{XAXiR|CStZkNkn=J5ETa`RZ%D6Z)b z%+b4>@-=!K6=S>}poN}7Iw;d1##DLwpgCZ>0Xh5a)~Gl)Xip+2jQiDiPJy7~?)`F} z<5@ad&Z^pR|NuWJKUH zv&B5Qrqz5|HHWj4`|5i=B=({XSh#}N0}t}Grlg-VV=ZpPi_loSIYX~3mNH~ArDajf zJgDPYf#lh0c@C1cqEpzCDUR+7I(hvNIWBE^-~^~5 zROIc*cn00nNH)=!mkuU5x{M%+rsYXi+-IOGGcmUV{p(({eX1-#Yx&J7bcSqOZ29E za=kKbF6NXObs_nfMfXCQZ$~`*UUXj1xWO*6bCGAiIbu>+8M(g9SQEefk_k2`mC2Eq zq7~fOX6VMA)s_e!Mt12+Zl&LeO3`LXY0hLQ^mMQlvs`_nbxkvBi(HOWYAJg>-HRqg zh6{M+R7sjOkChMFvqSnyw23@t&q!_hod;j*3(8*7*Og~gBR7XqgDU}aPK-fGSkmf% zS`B)3l>0T2pBdZ_pLzw*NG(#iT;c)B#R3}q!Y;95Uy@{G7BB_^v^W)2_D1I?V`kYt zA(dZfo5$v!5PTlr-v@ zGci8q@Wt4f@a1#O^skw;^(9@&lb!P$Ggc50+m%P=_#*96THWV7yvG|2d!xE@htwW2 z+gs_bw!{~DoI?;eUp>A|d=sej(DGi-5Fr-7^J7f3skyHsPLf!c2d$OsStn^kZ>~5m zc`GaSpnqXU&pc~v#|a6mR5y2)pKAS?1%J;sNommv_h(J%HZmv62?+DN2 zd>X~Ex8ey72w}3CvwJ*|7s&JB2NTXXgU3m_)#m)~ERK)5#bF5egYb2P#Z-@HI?O_! zM362FB=K0Mc2RMu#H{q7$#b~w9)s+;?As~ZGwAufLes(7(hf(Y0FztPMW)$-z zft-s_uR4S2rZife&J@$b;s~4x_@B|w#(k_dTkJrH>ElE3+}7f=yH+Gz0;$(-qi~C7 zjA;9TD)u8XGfHG&0!_Z@RtfhFVa{AaZmvUhReig!1ju!){V`;&QNS;ECk6Vd4O6d1RG7Qh&Sz$ZshMhr6N`h-o~^SDY?v_;Z2%x#O-_M34(H=Qw`>ssCCar z)j2DX2W91(oB3dBWi$7x(>A!7NY#9umdCp(1+FsfDaWvwe?_e$PzkG^kj^OHN^#0l zSSnM~qG!zCi#cl+r$e*I`U_sz4!Ib)3RB-gW-!4pBo7l2L$WhRQM&I7S-o$%PM2+x z<22gHX+4Ra?a3@kIs+8W&P+pDRxn!UP5$P$Ji1LeczR^J{jZ1`&_&?rf&A$CLP+Zj zL=JnAy`H%a>miragq3TzcSymy3nPwHc5N_+8`*obyli-2l(A^?L1CS_Kj`54M>&uR`zS#B5>&w2dAd6^S zu2QZ2@R~0nqnY&=67(XZ5X76Le8!2%Zip|ml4lfsJ@N%TK_u3mxrnhVG$JK$A?TuA zba=-9N+r|d?A?{PJ&@N;Hy#EB)DD{=|MJghcZu2Hciifv->;GMaVYk z7MJccb#kQ!HaE{iq?mcQO4J+Y2@TVe^u%!!iL!-GyT3D94XAIf5~m61T#Lal`Z|`Q ztdQXggRoYWYQ zx?`!YoF4XN@V_&{qXj*H$u}`iOsfg*bdrACj>MXfOozLbUMr-@xSmJ4KdeVZYYx!K z)41o*l;moMj#){xBf8f!8kwUN?E-y)u72&TBY94$L~*Ebdu>4n&|Hs&*9NP5jQ$9X zJ$DFJ*SIINm#ieOXpUA-N<)dJoo8I5(@Fap;m<33W|h2{`^9Mb(ufd{J#w_xUVbnn zq{t73c`?>QQi>Gn9rfft53-%}Vk3Pj=IC`YM`5CoI|9X(F0ZgbuE{fPAj-Xq=6oaQ z%z;Re7tK%m!;F@1XMD;p3LV-kxZ$&fl{zFk2a*op2^{rxzDI7ywdDY?EbqR z-)nq!di1525gM*1E)D7quKm7H@NeM^xU(c|Umr z^Pz$_Fd<6c1FAK712fKY1rK?HX7_}bs%4f}=rKa#wt7=sQ*BCzWkOhR3bU}=74~zT zpmQaN)tezU(lh+GQw-+*Fzl&um0bI)T-`+HT+}d_L~d|NG$79sxxXio8#3~Hn@Mkz zCnTS3pq6JoAZZ{r9qk(2sFy_>kk28|}R}D+n0Kc zdmvFSA=!K#>Kl#UJQH_Eo3N(#`1*%E(CHf%|LNk4)erA zGn|Ig)(NCj6==EFmwg&YUTe@+ubg{lUqI{9d9Puu2EBIj<%{I+0QJI}vG4CvPkRI& zP#+8DX6}LVMzg+Adm*huqEAtveK0zVr}91+ z8z4{DK{4hpr1`J*5Pq7fwnE^(^K$qtQxnBpy^;94ub{m&^gb20#`T;mdn>6lYiIzVrkQ64P};2FhXIG1jVCkmk;$Yz zt?q+n#;!U_Pb|<{vFAUm;ADIjtusLV>Qs~AIm^W;ke{RSnIo^s^g{dfrWc0GR@}zp zUtr8mn~p|C)Bw5e;1(Ysqi#L$rXt5E+vbVbqRD4H&lN!9a{I~D7Rd#nnBPMm>c=eB zPQ@~Mv+`sCUWG|GxkDDEo6ZX;6>!fBC|jgBw(V%%orP&G_X{=T5_a~gp^1V@R?2H| z3o6bbTjLpb$f|LQ1jQ~{Qn*7_4T~jq2;DP5_p8xMlW1A$U#rI+^foyYl68y84y5}p zv%MpB3~LBgol)X_I_ivthO`6eP}8sHBDZAc@BDDr*;r8Ql0B$9Us;Pfvkk6oI)8OwcciLgJtj;;8d)aaRGaiGR19UlX;`WSTvbTYc<%Ss&D|EYzX6H=@9H(I|zJ~PQ@2A{3hJRR;4SI>b? zM#T1`6E=6~$@6w2s%Z^#l(uUiS(&gyVH;~HwH`Dr&mqU+9CAL6+`8NX-guj|G#;*2Cq#Hu$eL!vmgM5I`g?(ZgDpx$#A znBp?Ig2oyi(lks_n(FllOSX^b#3>rQ(G;Odeb6kt;%7RN?dbXJD9V!Y4*|*MH2G|$ z`P|I`V3t@FDGbTk_wY==w z`2|s-z5F#mt%v@FUhnZnZQeH-Nkv^0sIUBbQC?Bb;LQ#Il5SS`tfU+mWrlsvTbXgv zD15d^X?tAc+$Z1kXaOK&#OrAHdmcs@t4TjFdOetT(#u`3M2G(4Qhi>=iB`TzR%Hc3 zzdg$R@Yn&MMyb#!J*y-}P3gJZtnh)-+hWFpR|f^E7FykCl0$x)0oo;WyhN^zy%1I{ zke5VEHwoj5_Eon83>H?2RdA} zXJDf-a*fe1K#Qw=KJkurZD94zp~b9)CGEVCk7>RvMBYk9U47_HPu}$?a6roL!G7v# z@4$}jBeRK~6@^u?ztI?R?i#(tZU!&uE%JcCb-J=hIHumh#)#1iY1MiQ?_D3+iuQI_ zgs5ALfYwQA(8nt-D8?ZE-xoaqLdsvH+~_w;uQ;;w%#3cqOR&>N$r$zHNV2bgu?LP( zL#G9|95w8_*js}ced6(>gr1B!93{^9;GIuT6?^??+Ze^VT(&c-BGyHciMmW@Oe)XH zn6*(ZRb>1xD6fymf0&;lW123XsVvf;2!7n=Of;V{-i6f%UkI^355l>?oR=gTyhcE8 zdKf#})V(u)LjdzHjJ1ogw>r})iWl#LN5T~2#|R!{iAt8X2eJ}39aI*%`Z5QCsi4KdUpYFy{g>mO%A4^TdRp-rwlF=8$(y#1}}3JrjE>`>9K& z5RKFQW)`Q*>ge#uOB;oFcLxZ#A^X!kDwGp;chy244ivKBZ>IJebJ0o9C@LU zL~caPR!)@b_wRX%q>A@@${xQyPf`qQ|1)WlmHmS%COz54>r^J=#mGCp%#2r+4tkn} zJB>S=7aatDQn?iH0CRM9B2+3WZ?s>}G+v=bp6A*+kX;U_2upKIP{dRQl5BF98R8~= z_jJx7V!+1ce55ojMcavL%pz%8v6G?5~lK*<$NMq za-?Jg(p(otZuSw}8EB;r24w9bSE62Ml;G8lEO<50%3Tj6Nij;s1V+yWWte(B$-C&= zP)s2A4^ThBog+e!s|n;|pAk#Aa=&`?pxxP>l)Utb7Z$$YMFBvbj_-OMBFsvn50*Ja z@M(mKs3R>${dA+J|0R6|65j*7Ry-t3QbdJo| zJU;N@r~<0>0BjmL&Ejoxw{Jh8k)B&DadwunsiRM`_Ttc~H7 zK%OvNJdU9FmAgP5Ny!w&>ZT)5{ZI-jV{MTp2I4ERla%1A9hkqHan0yj5zXt@k)A}w z9jA#7<9B%%W$|0myv@SvQfGdzEM9)WzLd#0?v*73rX!yh-G8w;XZ>4EvtFegl8asB z5w7;qX@Lgm4s%hNOA&k3;_73k`a_$MsEN^0JdXmc9klhK->t=|8vSmJF%aFi8oUBN z|BFEBt%g+$oZ~?{c|4N|w0IJD*r%hCe5BRj9Q`-wyxyeziZA%7+IwcnnNjPmB|m74 zceu#zK5NVfzG#g%I0O80L?2)+u#Yw&-=Yi@*hgpHe;9jh*q45Y&crvub}3( z-W;dx;O9QOjK-2=Z9D8Bpr6KQEM6u8Y3h^XP?%9SJaZNJfZJ)@q{Q(wTG_TOj^fw(e( zs4wVyk|^pKrOh`E(O8!Nc?ylWe8-JpUm`tc7Wq z5x+qD%T=Ng(P%ZI9qY&)HCcPlJcOc8R?UlNi9FVFg|)z=Bojdg3qW-e*Nie< zpx!mZmIjG-Q7`vR%EdL~Gzxl&?~yx2UtGuh7Ly72!X_xiVLQ>7qcBHdb(l#ruJ*FtU^v1kpy{mvOeacb4Q0^#?i{lYUrLJt&5; zKH4pd70|U?V2NpWC3qcycFSVKP|y#fg0!Byggpl{u}hrVF``|=W&GG< zqt)F#Xc=?1nNcAb0(ZY`Hrvs>qus2#Ej?h*u#IBnxA-zoYk^237lD2P>Fe{ok1v8o zv{?~c^Rj37e|+rp$7^40*4EP=*!16Wmwkya;l(*ICRWFl#(PS5#tzZG`mf?`X= zS5IY_ z)<}&^5w_+=XY|bZR*8O=dY>`6IDW?nV(pg0yak;Z4sTh~nR7EbE2xQaK+-t3y}YnM z{qp*FlN!iol$C52rvxu7jBOq(=^%PWZhNGqyNZetb^fk#=39ESB1)Kc(wtp>{meMS zAEJF_AXw5p2OQoxqy7J&k=Ase-7nf9p@e#Qqj@#>!>k2aeW-%Q9#^DsAlAE$zOZJy zTCoyZBj(yt>S6t?1+`)(tkX)M$lD%vP^_OxUNuIavg)0y8?clRib%y5k&!uqbcr}qx}$RQkj``++{mdUkzuJ>FA^#^xHQ^dV_#;jz#>;eTFzs zSe9n&WPHD*4HIbWkV>P9Vttx9f2tp^YHSUANjIM)W+G`mW^EbWcb|`0j<__DA&u5}(7pb2+EZcKj9LDw zLfTJ&X4*HuMCH}+x_b0kjU9qW=+0Wwff!FmNd$D#4~Mw8*)AI44{*dn>d^}0;&`fx zxH!r|kBj5{mg&f21`JFK(Prh+a;J2ofB*FiG18rp!N-#wf!d4;f%u-^&AJ(TMlI)f znJn~EduNx7LDWuC++Tc86%dW_d(F8jtr9?$IsjtV@9bi?^cviup8JfHt%yXewIUM9 zo8t?Vd_X%-`VpT<`I+nBvNa+nsqguS%0)A5?m~x>)}O-p zQ}t4hKyVUPPhs>Zyy6Ja1s8dBL?I80e4%~cY_41Zq2N<25D|W8YVCGSN=E!UL4KAJY;uo@>Z#I&O+SIJ!>zXGbd^To= z&fC_a&R;EW)W;ivvZED`Bg7Xx0&jaTLURif5JF_4XDk!b3aS3E45P+yxa2NtfZ&;_ z#wvp>V$5rGfHW`tH>mP=F@yC!V;oep;^heP3!7Cj4?QzlqeH6K`mxuswj5D)BetR@ zz0B>mXuuX%mZ>=Et4rb!&|HYb70BN}6^hbL3|>TX6Kp5#BM z>o9XY8HS>QSMU@Ihj9(qOj|U5PRxfp-_`hsZzC2P4>m>R<-cfte zxhA6z`%bRO%7`!I-1bD}$3Bu14+bH|*U2Ib6_talik zBT!-7UZR?n5rYE+I*gg@Sx)*~#NDdz;n0#b8&MV-1fVgn5Oj>My85lkk6tc&&EwVv7`(Aw^uvk?_8e-I$wM{9&=ZHZdA{5a^5QA_?(_u|9eSF`Xy&gR|LeHC-#Wf=uEkY zU9nWkoVwwn{FeR~h#?j0gjQE(wjxQt4tW5VOMPkXxm3Ji=nEP{^HU|zUWqhX$*f(- z)u{6@-Vg}$8;EPT3yVg#h(&ZnJ{D+1WlwL@4@Qb;R3eI^9bF}Dx1VmXkGbw8X5vtd zpF3xQ1*h8DOg^AEWSX)kCLo@YB;MVr1JtP?dK~7Y(voPEH&S{7crl|;y?A$jqcSdP zq|aT8RLUM;uU$WoUe-(BaVe8$B;?6H*9GLUE zyR`Yu0Do!ojAf1eu~Q$iei0c_yh+`Rr6%GGq_0bx--8D~YV4ckvYR_@5P@39-2>EX z;@M)tlYY0}I^Fglqx?EqdGw6BOZ1x2Q{u4ugtl2eX~{68)|47Y@|$}3xsrZIUE1JV z7kL%e{+4cmC>ewrvm*kz%Ow$Ymy7oO-a~oylg&VZ^y-_9;IOLBx<<-jqcS47&pNIz zRLey*^iTg?jq|5}!7~Ix?pvW;;91IkBQsfj)=y-tDckOeUg;wjExV{uD(QEPr)IKp z^9oXpm#5|!sMT4cF3kO6R4wnDLRO<{ZJZx28kVypEz(%Ro|69CDq+zJGl=M3gy!gT zxVW3@M`;e9$G+<{DZhD!xTp|~%Y)#_ILW(gh22MJUX9E)^-)@gY=bN{72>k-w1DM3iIE3ME2(fqTzun3mAjyb5gc zS;bN3vl_ZwyOF-!&zK3x6?n#3u~jk^sHc_4Ba72k`DO0CZl6v+K=lNF?sdn>-mBMg zJJR}sH^uin&iT+X?7i_w*tBXOBCfU2A%Ki~6rOTMhU&bdSWrnkpm{=XSM;ZB9Ek92 zJYT_&jUzlIC1$4euxBkk+wHd5!wxn0rtRQ5hy^XVM-(+0v)#sP_rB2FZ)E)4rHU`> zQfcj;Q4e^MBOCJo{1ogd>#7`_NP8)fkA8g1@PTLBPud>#)Rlt8V0xg+J&7nAYoro) z*8w>v=P0a^%d>A*DSy4#IZ)>)CZG9!br-t(|Vpq() z!_rxDCdd)2hSf+&x{gN}H0~^8^)Rgwqq&SmAnxQZRN?h(p*48btVF)@|DVs8rNA0m zK%37xvlP4@)Zxx9@w-BM6QW6M(~i;@dm-eTxGVWtJ0zZoLQhykJA2m2NxYI8`$8=t z`lo;xBJfJG8kO`AAW2F1oLNyz{75yXB(s1HY0|4Yb<&UT9iY2+ zfR@GhfbK3EWl%eIS_W#lSAk}Uu>!WtC5ib$@Kwi~ zhtSWa&pFzsva3+KMF#+2E8GbQxqh(za|GcnV9s_I^nm_Q@Ff_ae`UGb@c+~k%BfV{98JyjZ?1)ntjPJSzo8sasN7mYkw zD4I&1I7Cd#n`IgKCOo)h}e;f z+Na8Gy+kB{_uFEAjkU~b>VB$v7Ie@gOEn4_4Fm1qlQZL~vdtYAtu{tbop#X)4&bwv z$a|Iu(ku`;K%m14XhJS|qAx8Yy><_qWAueyL7>V4P^f#=RtA3@N1c~0j;yf;`*LM` z+F)qLB&t0wl|)>divEC>+lWF!;On@@(H9i;rKy8Iy zteaJInZ52(NhHrfqWK$SJJBq05xmg;4RXFMR6}E5-}0GB^;E&po3aCa$^PXlY(^)tOE_>@@$x2!J znavvenfa?>yIUvDWo1UjY9gcWM47He@1JXI$P1m9gWIzBJ6$wc zJMUAG-I8BlCoEKh^SRSbk@HCp+Fb|FuwD`K?Y~>Wfy;g)NUeC27VBt*Hfnu=-s||f zd?o6cqzJQ$74f8e;E*?)o<7D#VU|jX-~H`$cl-jq#+=W?(B0!luEPV(@g(2l8Gi_Y zcsBH*S^an-$MJiC0G`pD#=CIc8=`WT$JN}!quOzw)#1hR$5rLym*_R#@`6m%;owmf z&tRN~3*W=KI!ui{GwP}}2i_f@iQ|b+08f9QZi(1m-u@A*ks2V`K>1Q|&DSj2=E>WCzHhA5%&p0w-Yux@Ez$Z+vnJdFa zJ< zZSD=yB*J4eW3J8F{NKK^wX%SuxyL=waTPC70TF%pM%knbmd-}GDi&Bo;#Kh+dPh2F3Dg1v|s$VT=|0Waz`SiL#=R424DiwNSvSZuy6hTO2kAu2u{M@YPH^z)b>2y5ec z-a5Zt{F{kiy_ln4){V z2B7&xC#{_Yn-9yxca}Xp{wbizZy>3;&$!whz3HCu@4;%s?*bAOh@kY`WOpv$7p#eX{RqobP$MZ9jJ09gjiNeh>|bb zJS?)J8Ps)Wn!&?Mtu<$qzcEY4@7w_LfKMhTclt;!n&rOftRPw$^or;UgO{5h7P=cH z`Z@XLAQd8YcN9`63zr7+6s`E3WG5gq43l}j|p`lAn<#tNqF<{8K`$q z$BwyA9SXEOm<$xi?}kf6-@`>st)SQaH(!tn%VN5N-Ud)wb99xlI#h(WcoOwcx!&UZ zE)e(sMc`ZUJFPX_jJ4+XR9<5+Maw+ZD*CBn8-wWt;8d6B)IakkZp_^ZCaa4EkCiCT}{ zzF6aRa)Z3E^LiFq4veJ{H3nlzEg++8o{A-R5SH*>=z_ZDpvl6z~0!dQ8!;NU7v zKHD=T9WP}HIj|OYxh}I?!7KbySMgBS)qsxOnV=_IduJuT+q`OMtUI5ZdsXvEzqV+3 zk@IVhFG>Z;vL*RZ;!4gjlCl@GwXMdrM~ggr@Y@Kcl)uAOS6yUGhY5Ba+;N?Z(19_x+#Ix-;@2~V_j%~i=c+)RgwYcNx9!%p5a zg6;i+=E*YLLd-bV>h8sJ2`PJfdE0!`t9WFazu~Bx`Pt&A_f5a5OJ_)~{AR&!?bV%p z(yv=%KV!5S!{H@^8Xx6ej6Knu?^)`0zaakV>YA>o3`*Obq4pXdBl0BWFS2?O^?{3Y zIid4H?j&Ax3FMb3QkIFMs%NAozp!p6f7OV@8#XieFPi-#&Kc1Mnmmkq6W!4?0^|kg z7$J8yi{!KjpVym`kcH3sN%?hJ069R$zwC18Kk)@p=wU*d=Ke4_PV)Kmkk;7qv;f7r zoDp)*%bhZo?!LJ%)gP}flHVJY&(wxaXPOSF;?QF&x;ymIiqc{xNLw)zlo6-WK%{4t z$v$d@{_yx-jUD0RtJJz#cnmif@8nd0D1!s39EyI&lgp{p%qTGqGwQ|p)iX&2_1ah_ z<}hns@V()hjkMkJIQm@i~4olIzB*CHgSo@PjopOG6>?Nxgd76JB&Ebw&+w-=$xCivT zMfzceJt`imlq1h0z2DLDnqMfcl;kRw)b9#frL|{#%R2NTNR*MfIH}0M`6=JOuo{R4 zSIG0YM^rvt=M@yCb#r2(wlDGiZ3t@j+!?{8(KN2%c%WPPc%P3`7SU=()+!T zo^+*;HG-q6&|zkEFFXS!8vBi0VlyMV7oG;`D7eTgu?VStj1bMfffURoG$SCP(PG=` z{W={e(KAwLuc37uhLW{B1w_>(B?ok7@r#;NUrE%|8}}fosWV%V+NXzo%{U`s^LVf4ro~JmtJUDVZL_H-J|i&o_i_A#IR-FGAO>SJNTrt zBOq?28T<=9`He!^(~~C%V@)0l{S)ZwBtSZqpc_3;`<@8DL%KVa?2ztyHp*>fhowdJ zh{_Iq1$B(fLKY>WYa`xl@w=XLv_(^^yu;x3F4alc~hVL{*V;M=^6xcx@63YmwiKR(SH@KI6@3 zK?keGsmm*1As@j{!Eg&TOX%K79ECVwu9QLPuA(}8A>(^FK1;d#lC z($M)#dtkNuj8u=B^D|}L+#&hSzF&9iNmP@e-z?Uadfc}g)LNdNqTa}1D8Fi-+-E}P z)+y1922u@-6Y0jj*5p({6^YjC858C&Qtgv*_w_~NH)xOSnYfW^ibzWF#RfkIIW{LO$AE0C$I!p|51$%(TGMX zNnk0X&ZqmvO;RdH=n_nZc#UGDYxDf10Hdh*aTu|oV_M7%MadcA_Vk@ChXpHM#4}z; zDRYytrc!)i^TgnVa=z>|){#4`ORCy0N5^1ZtEdywAvx-VbQtS<7@l=lV~)?h+*!o( zG@CaFHAbM4E))6D0jOn!grgGi3qY>(73TU^+Syozzp?fU!?3!FsqpmHRmO{_Hz2or zv!Z+;-oFxv)${|o0+6jZ=g#jL?|oulsGY?acq)nULAvr;6ucR6tClyQK-VX2jiD$gsr)^qrbf=m2lkNlCJe~WMkh+medY10>(kK#H+~g&MJ0A2q z%BENbfcLnwX{DLZipb_ZC`-f3MLWs=l<)L$D6Lh1J4u@nYF2 z%}bZ%(7OvHp@68^u8Uo{Cwk{;#*H3dZZxx?U*utQ3u_A~y|W5T^!vn`dA}KX8~r{J z&43u>eyB63rzbRsI^Sr1x`}O6+E94&-6%XuDq}=!nKx_^WEc|G}(&fnH2Xv^$}+ZAjQ1x8aFmcod!BJc)*wWJ&b_n9X}W0 zcBMeP{c@{Bpk|b+{(UCoH)08C&2~hE)%8Z$k%1`BH|s))SMKxjpGIG_vv}XQ&Xb8W zGu+qIW`JgT^nezXYgE(P85!xB0Vnvs+BAOs@CGIAYe-(+pcGtuTSTb&%8UP;xKHU^ zxu_$MsOhMjn{Gmq)}xz{$N@y>hqXs|_QCB+h3kN7N2k()!#!{+Z3X(BiZk*aFW$+Y(yt*1-gSuCt@JY{L0&$f zcPVz9oRk;Mg=T3h=+t| zH18c%E0V;#2`ePAdPe_d=M}0Umo-|-Ld=AGnDdKdj5<#A|3!@_a&E8xRDvG^)fN&C zsEptWiI}Aw$mbU|r7UfKFLY`mu5}`3KhX+JFVPqB(@hHmq_!yZMb*thViAp6( z-8pJnF;W9)?K_GQKCi(_Rq|(4B1;O2+Ela-MKvnwhhC2ac@P1B+Brp ziNxIt6keI;Xl0Zz(5~;_o%B}emNn_$K%q@lM>D1GU}1}(N~9*HZa!ErCf2Mnax~CN zi(bt-M=`#4bZFE$;(A7%Bl5AK%P9h#paY@V?(ZyQs(-=aMB#m5Y`iEfO7|At0!DMX zsdfsh_HmzmxkWAu7aQyHw7b^G7pXaijWzW&3RS<+x~RSmHJ_+=BW?l9Mfw~3?zD2z z3NM@gZiQdJS=`4KbKjDSdlj1*-um_%G{+lx^`sfzx%wM4T7FMd&pY1aA&Oqdn>)<3 zy5nv4J7vt_~ZW}wa(^v=XT-8US4?I_ld%RghR?bgU z(N|iOSWTqSo`pJAosnwWLk7NlgQplue%&<|9HA?&%e7^%cvIq}pnJ$?z0|e9RFQL zMthsQ4ny2yGJ;z>U2`T5F~=+J$k9o@HtDPpkDc=st@T1a6Ei4w^O>v@jlT=a#U`>i zPXdh@bNzu1mRvW~78iqqv}UO9FylO%$Zd2lwD`MghXaz`4|)JlTHb(0%RM2aIlO4E zi#YdcMRcIAYfs=#8@s56jSe@AuKKdG0_h?EXthhR$)vQ^;tYZPxmsui&`DNH4@Pk` zF9%pHY?nS0i5j2nyMjylwvghEG@r6yk&mq#2hL|Z{U>9Mx8AWvL^*h`N9Y~kDr-c9 z8}z?5gR;S6)(l6h&+dv{hN@F*MJ5L5eC^O8p+m2<+MpsH;zTmO4d`a9jb#zThAL^x zLT@a5rc9GZ%#B^*Gy^)@B`6zpyEcRMbSBzz+mqkKGgjc+j8pz!QA7{OA0+pxFj0s68U6VuG6y;V5r78CXE5Z5AHy23U|c&x5=)fh4o_mEXAUQ34PBlh9&H#10 z^lNl06;gtb=w5~18rPm}jz(IOE3Pwtv#^|+hwXkD;buF9d8b5uFlUpfxy#^7MrEfX z*egvbuP^o?^Xy*8UeD;93$(lxTKBSW%6E*l*mSfY@Egw#_nHT3R~7*2EK*Pp%Z=$7 zGr0VB7Fk-+CbP8s>m@SjoL^+lR`3hv+<`+Fv%8!__+^XA1M9qK7hgYo)3e@KP>~11 z?C12HG!{6?XNTY8rS5wNN7~HGT88OQ3bvkB;{F=(ktjozqGA>4mY_e(=-v+cC>GGnU&w&b=^I4 zzk6d=81uV3jV8*|2I|bW#*DW4%?f~goF&OoJXfa@eX7EQRvSYXJRiulO`!fQ!_;e7 zqYU0&PK%fi2oWN<-KNh+(CK{!UF`l2vTOQFB^LL7G33Z(d=bUf53R%4cBBAdC_maeX6nbS2Q8x&g6@)CeRkQPh3lKXyX$5M*p z0>n>sGvJLm-nYZ6!w5nSz$veudR2aZhDO<9#*7&EgDu|pO!3%!Kqa@Pj)6R{^2GcG~f zlLh)81fDo~l|8cuu?xI}rQ4XWg4Nz=?~9z8UI!xOdw!iX89md1ymXc-WMG*_ z8;J7~zjG^3w#g70(oZWYSjl9jLM|UYQ;AB3l$RY}7wYZ4xjoDv#;}84H__%Uul$`; zHdC7l0}@o`<02TG%Lyv@>OG^6<$I6k0c_qD6sD8#!xH5R_C=-I~#5`oRScJ$OYF@qLgk z!hsCGsJ-4CEF{X%$2!O>bXndY#k9C4rd&#^eiLe}Qgs&|kV^WN8hk_-SYVZOy$sF~ zT0wZa_8Zx{zti}7T(N?%k)^9kG%r1_Le!3ktIc{+cHP_`J+6IUY|}3R5*ktP`;g!1 z$`Nb9@4N&kdD^F1vR+u4d)_bAV=&5MsBrU~^H`TC5Xz)t#8U6vON}8d+C7b73mSbO zuFFNbYF!AUkME7RsIQMeUq*W1EuS+Z z*+WXd$S)ffYH|Io(5$yj%}fiv;sxb9B?{@HNoJ{xx1=xwYnvoAsj^9eC0gZ;?DeMK z)c!)Fy^%B-|H9&qyk*h(reC+q%fvW_FB!X&YtPgTUYgNm(C*^?#Z9NZ$GYh1YA=PG z$oGLzZ31Q>pp^W32l3$vvY^UGbXad@3;&4 zAWbs)x$`8n=rrs-%JTYkB|hmyYso71ZT<(TN+7B2#1vCQVG zR;O|v&o;}XHwBC8Vt2N=S)xPVQ`VIFvKdySerhJ#;k+)3Upzxn-;D26vgO|2aO* zL=QbtND@=1N`mZ*^gXXvBPsl41uafC*sa6jWCL0o7W@ZtX&mlP@{w_Z8$p7MLoG6q zxDjN{V90&6DJ`Hf7k=}sM&3W9J>=YLmD=kWuM>;kF%^1jayXVxL#+LB&Vi7`!BhKU zSbdC$1$73)_k^aTH#yFf4#10MCsQM&ea=Qnz`jgLR`zptQZ~mhN32pInk~mZM{sHX z`s7K*oJQv4ndf-O!gSXF&Mw&V(;1|na*m_Tg8OjbO>&OOVn%cEq5wZICgMeTfr@j+ ziw4{DLjC329SDB;*Pz8@un7Bfdztf8k0j{4d8)A*EbO25t^P%)KVipJQd7RHlJYFj za87a&0%rrc=lg}+OCZF6YT8Cs$0E_D1=1O|Dpz2+K~Y6P97&mEzw^6|)#ev& z$X&1WB%#idbVAKJ!Z(?@OW4{~<0IDTK5Ilaa(zeViqdsHc+R8k8xlr#>iNau3GUU> zj~9GS^gL;yqP-jZ(LG{`<{cA!d^PE7y89{HEMX_d>0HuB^o9H;`eiqt`3^PC{(0HS zfsTcpJQ2&n#hXk|P%E^P1FatR?%@BllcQ&2gqJkNFjxbAR{B%*j59$SdZU@@vke_J zI5Y~(C~KrT*I~7cMQ-Ue6nI7gC4M>+vf2YyZ7{iC{KLZvdiXjDllw=1zuD4XM*aeMWPLAQ}EH zQoiUN>*bC1>rG?ewOS#?oXJF9i&WB?WAdOJuDl1C&hVpslLu#$1MdjIT$it%9Uf~T zNzr;!q%P{O-_7u#w%3?;q`+FswLgQqPUX0GosTH?bnY`_&||0E;A$T)4J5ynDk%6| z?0j?7xD>|79XksPR0|Ke7l$~>IgipXdAY-xypoPVkB8Tn$1|U-{N0J&s+(2L$enyF zR`65iiU*aoq%Nz$Ifp{qSFWHH`g(V!v){S568p|n0%6?QHfma;Lta)d4Mv3&V%APv zZ5N@(BVu$s*p5*^jZ|@X-I~>;kztWox~YL1=N`5R>G8blCj23y3IwlMuC=b_qKP8> zA&1v9%@x&Vpp#9dJW-m{o9HQS=l#rmg!-M|NhL3&m)_u6q%%>j@G3G7t)>K>BZ_M} zQm<)6ohoP~RHOW1sd+MqFBH<2^fM#psElM{qPs>kXf-+1U4{xJ^q6`3RuzX=am6(Z zc`}$xTb`F2+6=ne=c2ytZJh2lJ)KQ6(0?=u3Qg|U81B&0`rdYslJw2&AIyxa? zfGpSIh5C4-^+Fm&BTr}MWNADV@@BC@%NP3%BweQQcQ!(ML5gM{p|1cb`VL31GI;GL z-4A6(yayD@2W<;J+RNe>^yZFpinnrjZ6r5NN!=JKc}cCn`$>(L(zRD=yqcxTUC3Gb zQnh8osco=oOq@zTV3d;f&!%C^rc}ryV>I0qE7CT~ePaRP;Mknn= zo*)X;M(pi;=6YAQ$;K*W19vQtp9Z)V>NR6_fLey{Zc@z&#AtEIVhBp;=ytMdk-a0)4Uo zf#JLMLDR^fR)&<85$qpmoi{Ry2G@|unlJL>Vxq=3H{)(MZ&Ka${e{g~LEX-()8^!x zir5-NBV&vF=GN5Yb&qTCquuejyb2vjCYbVaVF;89h@}7+U(_GNzF=Z^xDCZb2(U%%Fi)X48 zfna;Z30?Q7M!$LgYK)0@%DO%1xYFfPEzufppw zIor$rlgKrpe3Q~Q+N6XrJN-F#GNjpvb5!y*D+ za&)#QzfkcNNmSOq3Ell7uRxQ?E|Mm%R0=hV)mPABxBBXy_=d0iiM{I-lW4yXxx+*;7OMRs z4MnwIM1`vM60==9>CTh(RNqC`0ie#Zp~yoxC$7praZ^6(v=p91 z+IHmSc|9Z$XftnREJw!EDzc}m3a?JqTk(7QfQot57O_!@bA-B;1zm|OUCkj+$Rr9sp#+xX5B9AVnUoUNYtxXyuHC)tRx< zVdrHOd01f?SqHQ;0|S;;%HawYA79y#1pszl6k|wtMOl$6 zhJF?ncV(n2Q0aHBXGA>v?9zm|C}hiw_-CgPArel!=~1cK3N2QJChFxGjrnzcR-OUo z(4g1FA~rEc#9-sX_yk5+V(&pq-Bkk}`_{>2)+m{-Pm3WG(Z6K#>U z($LW}!_LhfnRVa>lAi0*sZ%p5)e}HZu3*&k61HuXc~Ptg&aX%rFP}D{6V5M`6R>xlx^2H^W?*;$ zv_IuNkd`s&36wrExotEPvr|fOmgKDGDv`k`alB@7l11aKwB(Cy-Zy*v?pShaePLzltz_+1Qq$c%^4y4zYDC&~ zJSN5NiP=?J$c$XaP1dt`ws?6mBwr+eCC}t55wBR1Hl&HQ!(}66Cn;o|(8~P?bs~SM zFzrRzjlS+D&Unr~jhS2`6bpXq2~U#J@7kloYLZo%QeGInzGPuY}6 zgtJTMn@WsyE_q`D(NlBLOP>$Ky>rp5_jjDNy+i9*Cp|ornfX1^NFd7Li_YtJ)V-t4 z_3bA6@H$Ke^93sOawG!D9r9+l>`PSEe<9z=bc-DNhocoC2LA_YwAZVZ79JjB%p&&0 z;pGX86I9LraBj;NG#8UBc@e-QQOn079-~71;sCt2AWjAH3`u*CXGnCfBK@MnK-`h? z@JRBV8r!tB{GRkG^-L?MF-W7l&t0ryPD3iiLtC?F2v>JR&s5$Nuj<5nhx}TqTkHS|(N=J!e$j33 zm&#&_we<#BYXDBPc9(T$w62 zcV6AZfYxvQ!(<`Fswvk^Z6y<_fPpQmSbNnH#1#o;iD7}^wWJ7ckPN*v}NaxLALCCb!A#~YTVA@^3FJG%Uzvp%P67bm$AvVIr7u~p{}t1 zRHhcG`^xTd+KALrs0xGYM(Z(=gCh3?7l@oL(~0xFOheNtCF&~Z95V0IR13LSCuP`L zM#4DJ8ZJFMD`|E*<-vca*xT94e7ibZI}3M=FFN%hr7rj_&I>blwB_NkEJf+OOSZGT zOExla`N-~(n>4yca2XfAs&Y3Rjr+sJ;-%IbkTB zn!9Ox$(M+h@+Wjcez6%;kv6)w$wTIK+6p}!6>+k4<1?|9@a-9HdEGq2hd^6_M0fFb znp3>f_L0=H#i`v^gMd zY<~7PId@&rhb?yd6w#%4$58^2sXOL(Vhd<+xl5XjDpA7wI+STGv=c-sjNYhMyA(9>%O<7O638L_P#EDe{33B%ykE>9tNY z^vmD;GFNV%ql@F$wui1KUPbMX!fdFKDZP>=Rudgc&vKhZbAX$+PSabOPWjcd>Xg^{ zMK&nw&6E7lZ@sFW2Y1*m1*qSoyn8}7$3kCKP&SQTCs5|Iy5HX|5rnk(tD26c*lTNN zhS9n``;(c4mQz;&4r>!Y;!d-DpPl>uPLlZAnp3&)__}-JsfMJv+EuQBDgDaJ=u;5u zq7&kbz!=#L-RUO@9yxllb0eEiM-!QTN9%;HPR;_9JdX@PaetsugD!wtTADyLEpTQX zp5WUbbldx-x={R~C0T#(8`=3yQ$`-(NIMD0njN}slqvr2*{j{McplIiL0v$$VM>X9 zbf#bQqjT!_7HajauWl#l+_`g|=@4kOHx_w0f3*yliI-L>v-IqkY|)dAF2xo7+FXCl zz1&>I4QR|SYW}4%4X>P!w?ywaa;uV=hT=%>GH0vsgV@>4Nb3}Troeza$R+DhvBLtXqI9eS!V`p?xnC7F~q9lyLqbDxp=O*EpR=qfqR zTa@*v8Oe7Sd86`JMOLTehWq1hcevSMu9)kn$!~DSEdgoH`OwhckvnE{;NFur zZw66*xv@fv%IzQ-LQ=y^-;rTkMWvL-FZ++N<)y|m#U)UuT5RsHjjCEl4u|^(QCCV4 zn#riR?|g+H<;_H(zgYpHf_0@|83>j7EAKJP!-OuN zztaYUjsletIUw{bsMHkZp>gh>HbCfOQdwbn9u}ajl^wT$Q2oEshMi~W3$!k$>TUN2WF;Bl^_A~ z9MA_LkY`J3&y_Hu7zP?!>#1jd0z3CX-@9}e#mFuLFqqN7t}wt4^rvLa%QARamp^g@ zx|`@va?Cq4BYF>jZX^0z)_HjsyNZma3MBwxeh>MXcMN-U)svyp9}R>`^p*O|yy_Ma zV_|V0pgV|8f1_R+r}pTonJ_@;9?^KqU>+7z2bz~?Z=wrC=WlJ)CxGrC z!rIGZKzFEKl3p7%0np?T+M>InU*4IN))?;$+G^ApKtELor|dF%&MzFU8v0>0`oFQ- zIGrBZ<*h`Hy8g>5MWg17R;gMShG$n{Nn)(TpDnVAIwdtu8fbf!@Rp(Pv5+bdx(qe? zRDhP=@<*sZKXw1AD*qDab6oAGc-r6<37ll~Xc=s82ZU7{v@n3sFJRF10E9jzgJscy zKx;$PeAq~>;tqUEUNP8n`h#kD$owu*-|sDSeCPMZm*WhIz#O$Xv3T|nmo|4Fte+1w z^~_Yk?^RKSXk=8;Ph$_7_$8g6`4(1x09vA-GWhj!i9qLrGCF8$nB&la07M=`RV-#3 zztp2iAJ#S>nDs&PBeoLUJz8(O8SeQ#Ppbe4(l zc?HdzbjpVL7E4eB73fMIP!XN|)RP|lwAM{&HoIi-;@VH1kg1Yki54kaUAaQePHr7# zo1U$kbT@fE<3t!)SMV<{Z~equF2kewOk7222(f3A93XaAUBE1rep!nqt){En6z`M; zUCgFklf-<#G&29|CD-tF^%nEkIE!D#wzV4S$TO3Mz&qxV*1_V&zjOrZ(%iKEN^1I` zsq;HG5%jpr+eAR0`7a(^AW)5JB4VdNUyJr!oY+OX1#^NPw}vP~`orSot9gIC-Cb2+ zIJnT-(k`gJ0$rU_bag^*)%v3IdB!-<2i=-z7il_dWd(HfJ@%Wb(rv^Mch%PmNU!R+ws`k0G(c4CJgGZ}VOr5M=GPwe+j5xY_tMMiYo-;C_4S(h0>WgwsvC{Zk~~eQ&^%P%W+u*?np# zTUZf!syrdk*xz4L6PfBNM7Niv3{aI7IMh|>p3tA%e+V=?g-(mJ70-0)<1Nxe_`MqZ zIYuVl6{Eho8CQlliP~uwx^yjb(AUS-0PfzEDT*TRA`;F1)^$SNiF{^&>W%Z%in)j9 z#6H?UsIpnA^l_d_{+$r}_4u7eU1!b6>r~Zm$#Y^CPIM=tRBJ!hCaqOEjczao;$by{ zUjJJ?(As2y@I(XoWU^}wZzh^&5Q&4Z+f9=lJk_J8iFea=i5@*|hvagP9!oW#Jwn%X zzaZ-^=(W?{9@eFOV#5@7-U&*qEZ$@Z`%4cQ);%Ugt252LN#E+A6JracaknZCO}igx z-r&25R0%!Mj@~y!tSa$AsCFBO^%;y{?~V2l9rHw$XtwC>vsB>By>@_>y7HV!)U%rp z-g(u{XLfzz5>fY1W#Kv9 zljPTV;R|TY@3Xa|t4UIirLSkS!ulE~y6{*d=QvC7%3r9LW$$vNSA3jj!ZqoE&SKs9 zzH^4U0&lwwb?4X2mFXk2KF~p5AI*;40Mdij`U$@#sG^_rfS?Bc75}9j9M7bo0gaWi zsIv!KB3{JHUruS6e#?+v!YjM2r_?IhEhxD0n_tiVIk_$@uo9FO>%x+=uGJ4T=NH`@ z9R{pv0a-Vn`n&t+ytlBo*zKT+Q_#bMan==@kGmb%XZA~-^(E~}v!5$8AIPa`I+V0~ zXqJb>Q|FSmRJ0v$5x<*D){f3@d{47iZ;g-(56vFEJnWN9>LmN|TcI zu!`(XX;Qd})AQ`;(yZ+upuWFo)i1i^y(KjgexbpXuvZ1hdIsqHp*0?o2K3OFUxe8P z8mi0R!WV>HSxt5(Z~o-Sq}9b(=5Jl3(HCH+B@HxI@}GESG-dZ`?R612`1>-ikdC() zh7A6`wkXCcv!%yqKi3IukZX9Q?Q4B^i5LOS)vkI=Rki&pN~`KEP^HHd)vd4L(VF_Z zI+Jg0vdiF;yGVY~--EA*_waCJwt!JvdmV8jww`Ee1!VP2ZE;+g19H&iuC4FYSF-acNm=4?(u=XCK`6PT3B-iC(EN{Ziki%6ic5sq*B*uJ@WO?g$LBqqYhM` zObn#1H}T8tsWEhxhJHyMKxZk&a3|rkX{vSxtIm7&Dnv_OE?xhu)|vgzqg~T4TM=F8E%2oDke|JESr#gH)P^LH ziYc@a)>&7HxweCcv&38vK8;__^tb^PNmFFRBa&U>g!I-T0>NiZx}dJwwk8@?;$k!1 zdn{F4RO`}oTBS385XtjY*5&8WMYou{+HS^djg~A6rMa~& z{Ze)P+lj0bBuh8zth(XbuIQIK4$*m|zS0P^?=5v*?#cK4H+o=wT7D4O;(FjBf4OJCsNiIx0lyvBXL;0EJ{&2z_l<`p#3DSK$-JwR)sKh`RdWz%=uTCiL!t5kl8px9zmnLsdml67BW=PN!hbPuzfCPig9U z?Q!bnk~iKpWR@(&85K^pc4_pu+ZP;QZpmcPR{T;`(Bmzlt!c@pMs6x5V4W^j!ju*> z5^YWMNzt9!D1DIq`$v^%tiP|HB+s;^s*Aq!hCkuB$eQ)uDHA! zh)b+F1IHDuoq_W~{w0x`*xk(1YM)=KSgn!#Gl@h$fh13^GHYcub7VEC_kJ@vfric! zF2dgtI`gVg``TX6-zuVyjGg(OPw;!)GP17k+ewbi=A3feEn^WJTgs51>vCf+zyq#M z;bF3)t90i+87cK0%DZ!yPgL7>)Vhnz;@s)pO~{aY;%xQykn{!row>Nb7khZa9!5;D&3Z@L#dYL;y{+lGplr)r@Kn`=h^!FU6t+TcRJcSl=kk-C{=t`4Q=y3rrl@U z$#t@=YvX21UBNqmYysk)LRqrmscZW#%jcObdj6erR{hScv+VC>wDmM4-LH^*Ou82p zj`KxlK14Q=Z}GY~E0!n3H)-r&^er26u0;Iv95vJZ^6wZ6_~iypiJix|Ymv;xvjs#`@%+2~ER&9^*K^s57{jFY%Z_!P^;$V@Y%M$K?rNI8bal{Q|WWywcUhoe`bSj`qdta#TJ2$g@rNU9OTU?BgDQJOf@qdkuPfYj$;~X@?J? zw>S42>#}CZzF+pUDHmsn@|v{YrTb6qb9>_Rtloe5{9V<}tnqoKJi_=pYsTxhN-@aR zM)p7@lLSKcKvkZd^16YLzoxuyAZK|alU$qUEbn~F!FsQzOg`lW1MLx+z^i3m@ShqC zH0Kwc@enKE<=?g6?q(qybz&A|V$Mwk+R9Y@6DCW<;|$xSD-h1UU2=#d((IL|iy0zU zQ8~OoYez0@%=e+yzUc47Bx=9K+Axcyy+CeXAQo89**hSac)CmeY^*taJ=ATl#R%&Wvnnpm8Ew8tA7=CU{Tn$+_{3$GMfK8~kDOzy(rXcW}9w zg-*8jI?jmK!pLiw2%PNy|LmWC$9&@WLadW+-6)eg_AFM$b6}PN(P6ImUJvoYwb2i2 zh^j7!bb(tco45XhJ8nxqw*Rb%?};ZMKYSl?9fm)ET6>6hT|Q{{_jfen^9#Jt&#z-n z^o9gSLR|UgF6|}$p^t%?ryy~e~@jHQi~%bN?5=!lC; zqU{@J5Vwr>)tT4#P7&wOSQO^NIB|dCRLxd%I5lJlc0Lek#B;8@uP7n7iE#V$SYyzQ)`!5=PU;Vkyn#f&4}tp|S@u1&O1@KT_{;1y z-+1c;0fvUAq;&GiN<{wTu}%DwJ7YQJSunU2=T(k?rPe+5SWZbtI85>ij*DoncC`ND zE2(#c#st24c?V~ybu&;MNtc%;h=aN>FHsT|BG6tS{`m(T{avl^nbt7=PP)cz!F8ZH z-==de3Rb8hC;`UPO?~1HY1KOQcLbNg-9nZB1g+tY*PY_Ol0}#IM}TmXTjuvtIyF)G zzQqVM3YSGoX&29=58fHvA2M1F>)64&BsKhOOGEMBZD}atlyEriHzUhaal9+-LE~(N zW-AbHEEG|iIs%m{+Ty7Ln*EFRd5HOIUKeNg=NITd<4Wu=>OvkTqRzSp;28m}6Z{sp z0!mUg&`25i%Wa0Ob4E=AsFc`i+%A~)t;Lcg@_eUcUm{v;p8b?oOYY=*7dd<0(D1%| z(E0q*v!7aRo>m~sZ$#P4(rPDaD}MRQS{%3@a%@NECDG6`Q%%rcnb<$`sv??8;%-{Gp-{v*3tNQ*UAE+1$PkLRaGQB&K$O62e>wndKk{~gECb%97-54m zhkwZSsJg!}WS3CB{IF-ed}JulN=*Q0&XA!%J+)(?lD0c?|2=!7af3Sp)%~6^cPie} zZ0)FjT05aF@>Ya-HMKCHT0=tvD(SaLL`leB-jI?&)+Bey?@2$5vB<}PaneFmcCTmT zXI;|3Z}BSm3!Rxv)`FbTZx4X;^lj+@?bKeJwQpMhdHS~NuhB`au8e-K=P!FbLsEes z_bKVl8{{;v6k#*9^4Lbiyv?p^Ht zkR*(JRzUOSdFj^vy}q_tL_giujaQVV#X>gdMo4fD-4+S{(^+CEebz<1S!Mk+#5U%RiM*b z2y`B|9W8i2WbI(-^qAjhS{F9Q03uClMx$$8bocWQb@>#KQ~HO7>=0z^#V;9X#9K(` ziMl)t9_N)c^OJt6X-%-(voBhqtmS#u#+D0U-el7xUSn%^$!o581k{AM5>?fhmR6~#j*_Z$jiS0#GuFC~s9iMFqAS7KuoA!+O#bs=&DfmhY%3$s+rSN60xgZ zL}O%QbX8Gl6iA~F?dRbR_Nn?$jE{`2x(|&4X>__1fe<`YH*?pp8WNnYZxtspkf~yc zOE+5os&qp#>0Wr*>iuhAP`E&2Y%;pU+t5#(zf_FwoRUS@mYdd137nR^J$EVFI*u&RCa)^+Z0X z^@qAnL87(3sDFOhf)_W{;~9F^N5o%vLKe}`TNra-Tcn(k<@Hdc#I!sVYqQ+dnkml6 z9V}n8+Cxk6yF{~m(aFk0l(Z`%NUD!b;-6wy?+r`-e`y$`Fq|!kBr%SIcipQ1A-6w50Ptnex@vz#Q|D7R^pe) z0S^i#mSPn|RLX#Gk~^E)0xd~8oZa`#zl^usFG6fM5S5KYyxaps`85>_>eQoTpeACS zU7#X<*H0qro`GnxC2EQU=`B8G{<_bq=U@u;{06%KIZgxAd&Gr?iV6aamUOP@Qk?iR z!>+(-QB;aD@e-|(C-6+|d{Z21iQhG?*MZbi1{!n?$XIt}Q`Z3XcbKhZ| zFrKsHj1T?Y)Ve?_9O)Q7)yFblr}`o27=d`P=YzV?8F{J|6$(xJNW+n){Yz9xsfdHu zNUM|oMp4vcXg>?r_x8|+aON)!+Yf?l3)EzTu-^z!Z%JE<3Q=}%qR_MtQL~mYi0VlW z?o>R}K_IPY{E~%qfJV<1y;bL$4o{55nlIKjMm80*@u;N-dq(lgE}reT^pMYt=P)J} zRIeyo(6U;~#raS)DX8L3abi)-U1>irB3o*sMKtOEMMLqbC0RBUKU(6;qAkUp;*=qI zw7yaAn9)x?cO6}_Hssn--s`4ftV1oono90quSZ6#s9zSMcUlqKvb1JAhxr)Z`9woe zsYLtp%lT`3#j>X=62u5r&M8qdy5DD0Gi<7kWgCwXvo7tr(N|SQ=+m6zu*oT&K7Nr5ht~Z+BH|%)I!6rqRv4e$UqWzJ+s`aaz6d zwrh%Nn>Fd4TjM;^6S+#v8yT}`EYck&ujXSVptnsP8dqc+b7`%4NQcVRw94usV_wCD zMUzTU1ogsOx){iIJb5hF!;>Fyb=CjVX<4e6p{VUxsti$B8909_dt|9bhGM_?0?(DK zljSOclNKeed!0n{#;GP^a!~x8+Tq0)<`jpc(;q8=Xhz{J@iF_ao@>S_W0zW$J~Tgd z-Ruuy)Kc~)BT`+|OLA~DFp*`Qf4O8!OjUAwlE|L&5;64-#UpB?< z{FbKrY&%cciP~mC%gvHjv>fB43FBBRf2kRT9(>+x8|%NQK3j0<#_X0Hb*`D$vq{q4 z`&M@;hG?{-qF$9fbbgXws!C=}#_=g@2#92@)Sw+z3x3c?a4Od6vhAx=uF71oYQ2Xa zsi}rn8@W#1cAVeYD=52B#{k8S&EG2c7%=?kINE#QoSC&6Uo8W_=@L zhpe1~pINdp?HMaUdS&k;*L9bRq!r-!TS$4R1v9mS!2m40iQspG z^^stIf$Ftbu+)~~VK@y#=~G4zDU++EV||B*pP$MF|W}W#&C3OG?wvk zbPNc36WDVlDnH5DvE*~Pn!TmOWi69oxuDe^mJ5ld`~Xh16ZQ2)>weMw{IZIE`1M~Z*O_zC zcjF3e^aQH1+j-|2x2RWg*oWqRXh$78qjMiRQDyF~JRwH2s9GE=Jq}GRMyA5%t`=w6 z0|XkKBSsBgtc&DChZ1bfX4iyCQbobin%AU{D6FnHM_r6=|+va=N)pzJA1!?Zd&)K zjn{k1p)Kh$hAN~<50-WBT70&IfmZr5fbL2fQ5Ccg8uPuSX?KTe_%%_XMi%d+7Xrv$ z^Ya;*XhbywKd7dk1M@rMi)`bNwr*&9cqi^fl+>_P`!DQ%)h~?MsuE!E%(X*fWo<(v zot=k}O|rJmoVet&%s;9DX*>A*md$}$b(rsTt-}$Ky5FjusyZIM+^XW|Sb9?(y()bZ z6uj*Rm6Z5H5lcEzsV}s#y`?ou)~H@v(!~ic(;iVt&h-0BUAw~3Od7~QpoPgoLO|d; zlPN_X)b>Lq>fv=sFjiOdTO`kp8s3@Xs&ZbOW>ts_4)KR(N!fm?q9oE*j%^_EX0#LB z|Ki95D#T53YUGfeE)J-jP`$X=i8JIO)=r$6zTHD)-!AK!&B&rKI_;q)&qkuLzv!HY z{-IZ#lp4?-RA(-B{@n12E>-w?eo$Bc3Ocw|cB44_ZOW6N=hIc+9MfwmV)Q|4fB$Yj zAAxGe<@XY8RVlkQNBs~^_Cx3MOUaOjmY-#`>VtZZI(9#w^ImirT`LN-a+i8BKU9Cz zQslcKM*`|S=m)4J5Bea~lL(|v!2Y|*i;3|CoQRTNmlg-~G?L$Dcx3mC@n%RbFwk_) z)A~L`g_2S;Qt(rCjj|QDplkv%?V-9+S?PmsM2=ArO;K>7oiWu!^hO{to>Tv4TIe`ujWXJ-$HiQKJ5NrcpoCOfz1W`bDih#B>I8Z6H(LPd%ql zbFa0~D^VTL+6C$a)frLvDfB$ssN84m0=2U0hcrSRsKq39?s7%#be_O;;}Int$kw>n$O@bGu+b6dB9yQF!+C4k{i?t zfGjCk337#2fEt-?ie@~+8MNkSBQrjL>V03Z$4~r7*T!@9D)u7p3eZY>Dxaw;*N*;S^Y_%v=_thduwC&FL9q3i#YKZN>{j{NtmXX%_4 zpqa7R4`SWT8(G7s{v}i8ixdN7rOgw02jlaMRz2QQeOf->6V?BbO6|EXv&8IKi?K>7 zO0N;21|ON}mqAsy*|hf3Yo@esp9nY;XVT67mfPfDOv8bI;3-WWKvl|3Xd+YWl=3w z6(o}^|Bc^aWjYOgAVw1AmjmeV1$XFF8$M`=12C&>{8-m{@6f&3)O|%n8#>os5k~ZCGcB~r_m|FdVEgx%K|P3O=86Day%T$ZY764;*zJA8e+8ZLl!)-anmI*r zFj}%eJF|=Wsb6jIRPh|0ms2BO3o_$0c@(6{9MP|>2~?Ta$=Z5$rMtjdJnduQ1C9Gd z&ohAUSqA_YMOFKf+Cq#|JoS{Y_n}vu5*!wM`Z%*(dg@mGz3gZp=YWFy?)%kM_KCX} z;Ki}>w77xVO5V72vXpm;{j)`cQw~4VHD6N zHT1~TmovY&uqvi4W#(!C zottOiTIUd*-x@wQR*Y;xlf6XU%b?!dKbe-Udl}l0>U9Ra-Vxk>wWxv_6ndw4zbI5K zpMnbSljT|2GpO*6kN4GeOoQ%jj|>4&+Ra-&MYTI?`Y<{7lk{_o#wjTrt1CJjXO^gM&?^6>qO;6%LrFA zG_QBmR*$vTQr%W`tP$V5lFQPJw2u)mDz=kK&;@lLI0d`~+qivXxPns!)C zac9IFsE?dqwPmQe*P(dBQO(N{XAWytduaAY)f;UUgRW~2n~EdzT_idAYRbnoqXwk; zP5vD<)?X@8DqDTFm|?Y5K1KERb&3jk=EiS*H}RgPFJA4F*R80^=W>ST6?N&3S{EN- zRzK4Nf8ka7zRifvE9(aN~J(>)w%1)3Ri2Dgh~TYWX^>aO|BL` zq1wM_I>A;u!Q@-NQ#%pg)A?BaV^09}l_v>R{nIYU88Pw))Kdcl@~MUxh;@dEOeXg>^x~}yF`{0*YHLLoRKX_qh236(kFD1*9lJ{{t0A?@h?p=H!M(?9 zi{^kEE#>hs#a{ep?l==yOmX%{>2jBvnwPHXn0^;K&&1hXDl@Q@=Wph+R3l*x@g|nu z;lbQQRmZLBL(IFM;^8c2#KR}f97j=T^)Kpri{-*S?=4%$Mwg1G3h&3ERjx1&tx(Z4 zhvd+Gqn>Os<9h`_W=iwEU+VgNyi+SNS%_z-VF{OY#=U}^AN#E0pQ2j^yy~D;ij}YO zeX_I=uR-X}!SXc-xcGoDX_Jr`}@fVf)dfEGY>= zbyE6$#%KF2lWrW{x;EcD$}&+L3h1`vo2RG3Bs6Mr(bGeD1F7Jq>PRknMw~fN@3D`> zXv)_q4tr+g7~*Be_tuGin4ue0SO>W+{CJ>Wwb2Pn_EyQBL@yQtRQ5w9ZiHhiZ;{6C zcb3S^#LKRz%X0Tzsje~{9-99^po>7_oADMMzW9Qy$N0Kr>n)N5TEm-iiF2>g)U->t zg)bfZd3AHj`+2RM`0qx<)3Hl;#P^0!MC*Ry)7SUSJi|ns{RmqY!@t%nByHRp!jkCf zMwG4I7`Jyq_tavSJVWni56|z9vv793^s(zqf9YztpPE?^AN0>>+|d=@WsWovC@7F5 z_Cx3McPGBko<}8+WZgrvzOQ?KEtgCQTU$4;OW>{NPKS3MJI^>O9Y_3#i)b2UIWQ5@RP2WHR*kWs# zcZz|!T>^#3)wR%SsycHq(K-3c>b!NmrTVUszEJZv6K64`SE=P#HIJwFe%2ND)zPX9 z#R%ogM_amj;%Zea{^!5`H~x?R{XhQKzyJ4t{kQ+} 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 2356/4212] 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 2357/4212] +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 2358/4212] 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 2359/4212] 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 2360/4212] 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 2361/4212] 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 2362/4212] ++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 2363/4212] 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 2364/4212] ++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 2365/4212] 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 8af1add2a6059bf6a6c525f15a712a8a25464fa6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 10 Jan 2014 00:04:46 +0100 Subject: [PATCH 2366/4212] preos: seperate parameters, create remote_exec, remote_copy and manifest on the fly Signed-off-by: Nico Schottelius --- cdist/preos.py | 98 +++++++++++++++++++++++++++++++--- docs/dev/logs/2014-01-09.preos | 20 +++++++ scripts/cdist | 9 ++++ 3 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 docs/dev/logs/2014-01-09.preos diff --git a/cdist/preos.py b/cdist/preos.py index 77d6d6dc..2f53791f 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -22,16 +22,26 @@ import logging import os import subprocess +import stat +import tempfile -# initialise cdist -import cdist.exec.local import cdist.config +import cdist.exec.local +import cdist.exec.remote log = logging.getLogger(__name__) +class PreOSExistsError(cdist.Error): + def __init__(self, path): + self.path = path + + def __str__(self): + return 'Path %s already exists' % self.path + + class PreOS(object): - + def __init__(self, target_dir, arch="amd64"): self.target_dir = target_dir @@ -42,7 +52,53 @@ class PreOS(object): self.options = [ "--include=openssh-server", "--arch=%s" % self.arch ] + self._init_helper() + + def _init_helper(self): + self.helper = {} + self.helper["manifest"] = """ +for pkg in linux-image-amd64 openssh-server; do + __package $pkg --state present +done +""" + self.helper["remote_exec"] = """#!/bin/sh +# echo $@ +# set -x +chroot="$1"; shift + +script=$(mktemp "${chroot}/tmp/chroot-${0##*/}.XXXXXXXXXX") +trap cleanup INT TERM EXIT +cleanup() { + [ $__cdist_debug ] || rm "$script" +} + +echo "#!/bin/sh -l" > "$script" +echo "$@" >> "$script" +chmod +x "$script" + +relative_script="${script#$chroot}" + +# run in chroot +chroot "$chroot" "$relative_script" +""" + + self.helper["remote_copy"] = """#!/bin/sh + echo $@ + set -x +src=$1; shift +dst=$1; shift +real_dst=$(echo $dst | sed 's,:,,') +cp -L "$src" "$real_dst" +""" + + @property + def exists(self): + return os.path.exists(self.target_dir) + def bootstrap(self): + if self.exists: + raise PreOSExistsError(self.target_dir) + cmd = [ self.command ] cmd.extend(self.options) cmd.append(self.suite) @@ -52,12 +108,40 @@ class PreOS(object): subprocess.call(cmd) - def run(self): - self.bootstrap() + def create_helper_files(self, base_dir): + for key, val in self.helper.items(): + filename = os.path.join(base_dir, key) + with open(filename, "w") as fd: + fd.write(val) + os.chmod(filename, stat.S_IRUSR | stat.S_IXUSR) + + def config(self): + handle, path = tempfile.mkstemp(prefix='cdist.stdin.') + with tempfile.TemporaryDirectory() as tempdir: + host = self.target_dir + + self.create_helper_files(tempdir) + + local = cdist.exec.local.Local( + target_host=host, + initial_manifest=os.path.join(tempdir, "manifest") + ) + + remote = cdist.exec.remote.Remote( + target_host=host, + remote_exec=os.path.join(tempdir, "remote_exec"), + remote_copy=os.path.join(tempdir, "remote_copy"), + ) + + config = cdist.config.Config(local, remote) + config.run() @classmethod def commandline(cls, args): - print(args) self = cls(target_dir=args.target_dir[0], arch=args.arch) - self.run() + + if args.bootstrap: + self.bootstrap() + if args.config: + self.config() diff --git a/docs/dev/logs/2014-01-09.preos b/docs/dev/logs/2014-01-09.preos new file mode 100644 index 00000000..b802825d --- /dev/null +++ b/docs/dev/logs/2014-01-09.preos @@ -0,0 +1,20 @@ +- debootstrap + x setup arch + + - include trigger + - replace with cdist config later? + + - get kernel + - create initramfs + - later: + - configure chroot using cdist + + + packages: + linux-image-amd64 + + - temporary manifest + + - bugs with sudo + [22:50:04] bento:~# ln -s ~nico/.cdist/ ~ + diff --git a/scripts/cdist b/scripts/cdist index f4d4ce93..872d00ff 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -89,6 +89,15 @@ def commandline(): parents=[parser['loglevel']]) parser['preos'].add_argument('-a', '--arch', help='Select architecture for preos', default="amd64") + parser['preos'].add_argument('-b', '--bootstrap', + help='Bootstrap directory with OS', action="store_true") + parser['preos'].add_argument('-c', '--configure', + help='Configure previously bootstrapped directory', action="store_true", + dest="config") + parser['preos'].add_argument('-i', '--initramfs', + help='Create Linux initramfs', action="store_true") + parser['preos'].add_argument('-k', '--kernel', + help='Create Linux kernel', action="store_true") parser['preos'].add_argument('target_dir', nargs=1, help='Select target directory') parser['preos'].set_defaults(func=cdist.preos.PreOS.commandline) From b535e848ada9720d01861292c8df79b1cbe51677 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 10 Jan 2014 00:38:29 +0100 Subject: [PATCH 2367/4212] run apt-get update after deboostrap Signed-off-by: Nico Schottelius --- cdist/preos.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/preos.py b/cdist/preos.py index 2f53791f..98fd7f35 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -108,6 +108,8 @@ cp -L "$src" "$real_dst" subprocess.call(cmd) + cmd = [ "chroot", self.target_dir, "/usr/bin/apt-get update" ] + def create_helper_files(self, base_dir): for key, val in self.helper.items(): filename = os.path.join(base_dir, key) From c130bdf5341769539bfa0daa15de80e34fb94413 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 10 Jan 2014 00:41:17 +0100 Subject: [PATCH 2368/4212] 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 2369/4212] ++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 4fb55b8d92065690d383c21e6015f550c70122bc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 10 Jan 2014 10:46:09 +0100 Subject: [PATCH 2370/4212] various updates for preos Signed-off-by: Nico Schottelius --- cdist/preos.py | 51 +++++++++++++++++--- docs/dev/logs/2014-01-09.preos | 85 +++++++++++++++++++++++++++++----- scripts/cdist | 21 ++++++--- 3 files changed, 133 insertions(+), 24 deletions(-) diff --git a/cdist/preos.py b/cdist/preos.py index 98fd7f35..c24dbbe3 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2013-2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -39,6 +39,9 @@ class PreOSExistsError(cdist.Error): def __str__(self): return 'Path %s already exists' % self.path +class PreOSBootstrapError(cdist.Error): + pass + class PreOS(object): @@ -52,14 +55,39 @@ class PreOS(object): self.options = [ "--include=openssh-server", "--arch=%s" % self.arch ] + self.pxelinux = "/usr/lib/syslinux/pxelinux.0" + self.pxelinux-cfg = """ +DEFAULT linux +LABEL linux +KERNEL linux +INITRD initramfs +APPEND ro root=/dev/sda1 initrd=initrd.img + self._init_helper() def _init_helper(self): self.helper = {} self.helper["manifest"] = """ -for pkg in linux-image-amd64 openssh-server; do +for pkg in \ + file \ + linux-image-amd64 + openssh-server + syslinux \ + gdisk util-linux \ + btrfs-tools e2fsprogs jfsutils reiser4progs xfsprogs; do __package $pkg --state present done + +__file /etc/network/interfaces --source - --mode 0644 << eof +# The loopback network interface +auto lo +iface lo inet loopback + +# The primary network interface +auto eth0 +allow-hotplug eth0 +iface eth0 init dhcp +eof """ self.helper["remote_exec"] = """#!/bin/sh # echo $@ @@ -78,13 +106,16 @@ chmod +x "$script" relative_script="${script#$chroot}" +# ensure PATH is setup +export PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin + # run in chroot chroot "$chroot" "$relative_script" """ self.helper["remote_copy"] = """#!/bin/sh - echo $@ - set -x +# echo $@ +# set -x src=$1; shift dst=$1; shift real_dst=$(echo $dst | sed 's,:,,') @@ -106,9 +137,14 @@ cp -L "$src" "$real_dst" log.debug("Bootstrap: %s" % cmd) - subprocess.call(cmd) +# try: + subprocess.check_call(cmd) +# except subprocess.CalledProcessError: +# raise - cmd = [ "chroot", self.target_dir, "/usr/bin/apt-get update" ] + # Required to run this - otherwise apt-get install fails + cmd = [ "chroot", self.target_dir, "/usr/bin/apt-get", "update" ] + subprocess.check_call(cmd) def create_helper_files(self, base_dir): for key, val in self.helper.items(): @@ -117,6 +153,9 @@ cp -L "$src" "$real_dst" fd.write(val) os.chmod(filename, stat.S_IRUSR | stat.S_IXUSR) + def create_pxe(self, base_dir): + pass + def config(self): handle, path = tempfile.mkstemp(prefix='cdist.stdin.') with tempfile.TemporaryDirectory() as tempdir: diff --git a/docs/dev/logs/2014-01-09.preos b/docs/dev/logs/2014-01-09.preos index b802825d..c0b840ee 100644 --- a/docs/dev/logs/2014-01-09.preos +++ b/docs/dev/logs/2014-01-09.preos @@ -1,20 +1,83 @@ - debootstrap x setup arch + x allow cdist to configure debootstrapped directory using cdist + x include sshd + x configure network (eth0, dhcp) + x various mkfs variants + - various fdisk tools - - include trigger - - replace with cdist config later? + - add option for different initial manifest + - allow -, stdin usage - - get kernel - - create initramfs - - later: - - configure chroot using cdist + - add option for additional manifest + - allow -, stdin usage + - trigger + - can be handled in the manifest of the user - packages: - linux-image-amd64 + - remove /var/cache/apt/archives/* ? - - temporary manifest + - fix linux-image name (amd64) - - bugs with sudo - [22:50:04] bento:~# ln -s ~nico/.cdist/ ~ + - blog! + - self configuring + + - pxe + /pxe/ + - pxelinux.0 + - linux + - initramfs + - pxelinux.cfg/ + - default + + - iso + + - add unit tests + +-------------------------------------------------------------------------------- + +[1:16] bento:~% sudo cdist preos -vc ~nico/preos-tests/preos03 +INFO: cdist: version 3.0.0-38-gea286c6 +INFO: /home/users/nico/preos-tests/preos03: Running global explorers +INFO: /home/users/nico/preos-tests/preos03: Running initial manifest /tmp/tmpxbquwe/manifest +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __file/etc/network/interfaces +INFO: /home/users/nico/preos-tests/preos03: Generating code for __file/etc/network/interfaces +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package/xfsprogs +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package/reiser4progs +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package/jfsutils +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package/e2fsprogs +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package/btrfs-tools +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package/file +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package/syslinux +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package/openssh-server +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package/linux-image-amd64 +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package_apt/linux-image-amd64 +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package_apt/linux-image-amd64 +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package_apt/openssh-server +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package_apt/openssh-server +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package_apt/syslinux +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package_apt/syslinux +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package_apt/file +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package_apt/file +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package_apt/btrfs-tools +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package_apt/btrfs-tools +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package_apt/e2fsprogs +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package_apt/e2fsprogs +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package_apt/jfsutils +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package_apt/jfsutils +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package_apt/reiser4progs +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package_apt/reiser4progs +INFO: /home/users/nico/preos-tests/preos03: Running manifest and explorers for __package_apt/xfsprogs +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package_apt/xfsprogs +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package/xfsprogs +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package/reiser4progs +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package/jfsutils +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package/e2fsprogs +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package/btrfs-tools +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package/file +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package/syslinux +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package/openssh-server +INFO: /home/users/nico/preos-tests/preos03: Generating code for __package/linux-image-amd64 +INFO: /home/users/nico/preos-tests/preos03: Finished successful run in 2.546635866165161 seconds +[1:16] bento:~% diff --git a/scripts/cdist b/scripts/cdist index 872d00ff..c1e1cd94 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -89,15 +89,22 @@ def commandline(): parents=[parser['loglevel']]) parser['preos'].add_argument('-a', '--arch', help='Select architecture for preos', default="amd64") + parser['preos'].add_argument('-A', '--additional-manifest', + help='Add stuff to configuration manifest', default="amd64") parser['preos'].add_argument('-b', '--bootstrap', - help='Bootstrap directory with OS', action="store_true") + help='Bootstrap directory with PreOS', action="store_true") parser['preos'].add_argument('-c', '--configure', - help='Configure previously bootstrapped directory', action="store_true", - dest="config") - parser['preos'].add_argument('-i', '--initramfs', - help='Create Linux initramfs', action="store_true") - parser['preos'].add_argument('-k', '--kernel', - help='Create Linux kernel', action="store_true") + help='Configure previously bootstrapped directory', + action="store_true", dest="config") + parser['preos'].add_argument('-i', '--initial-manifest', + help='Initial manifest for configuration (added to built in)') + parser['preos'].add_argument('-r', '--replace-manifest', + help='Instead of appending to the built in manifest, replace the internal manifest', + action="store_true") + parser['preos'].add_argument('-I', '--iso-boot', + help='Create ISO for booting in given location') + parser['preos'].add_argument('-p', '--pxe-boot', + help='Create PXE files for booting in given location') parser['preos'].add_argument('target_dir', nargs=1, help='Select target directory') parser['preos'].set_defaults(func=cdist.preos.PreOS.commandline) From 5cb5c3bfdffa74d51ee34c959b92a48a9b3678c4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 10 Jan 2014 11:26:23 +0100 Subject: [PATCH 2371/4212] 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 995e33afc9f62959fabc1888ec02952d6a68242a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 10 Jan 2014 17:21:42 +0100 Subject: [PATCH 2372/4212] add command line handling for pxe generating Signed-off-by: Nico Schottelius --- cdist/preos.py | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/cdist/preos.py b/cdist/preos.py index c24dbbe3..78b88f94 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -56,12 +56,13 @@ class PreOS(object): "--arch=%s" % self.arch ] self.pxelinux = "/usr/lib/syslinux/pxelinux.0" - self.pxelinux-cfg = """ + self.pxelinux_cfg = """ DEFAULT linux LABEL linux KERNEL linux INITRD initramfs APPEND ro root=/dev/sda1 initrd=initrd.img +""" self._init_helper() @@ -153,9 +154,29 @@ cp -L "$src" "$real_dst" fd.write(val) os.chmod(filename, stat.S_IRUSR | stat.S_IXUSR) - def create_pxe(self, base_dir): + def create_kernel(self): + cmd=[ "cp", '"$(ls boot/vmlinuz-* | tail -n1)"' ] + cmd.append + pass + def create_initramfs(self): + base_cmd="find . -print0 | sudo cpio --null -ov --format=newc | gzip -9" + + pass + + def create_iso(self, out_dir): + self.out_dir = out_dir + + raise cdist.Error("Generating ISO is not yet supported") + + def create_pxe(self, out_dir): + self.out_dir = out_dir + + self.create_kernel() + self.create_initramfs() + self.create_pxeconfig() + def config(self): handle, path = tempfile.mkstemp(prefix='cdist.stdin.') with tempfile.TemporaryDirectory() as tempdir: @@ -186,3 +207,7 @@ cp -L "$src" "$real_dst" self.bootstrap() if args.config: self.config() + if args.pxe_boot: + self.create_pxe(args.pxe_boot) + if args.iso_boot: + self.create_iso(args.pxe_boot) From c585e4876e46306afd56b9490e36e00d379b3fbd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 11 Jan 2014 21:05:14 +0100 Subject: [PATCH 2373/4212] create kernel, pxeconfig and pxelinux.0 Signed-off-by: Nico Schottelius --- cdist/preos.py | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/cdist/preos.py b/cdist/preos.py index 78b88f94..1fb73ad7 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -20,9 +20,11 @@ # import logging +import glob import os import subprocess import stat +import shutil import tempfile @@ -57,11 +59,10 @@ class PreOS(object): self.pxelinux = "/usr/lib/syslinux/pxelinux.0" self.pxelinux_cfg = """ -DEFAULT linux -LABEL linux -KERNEL linux +DEFAULT preos +LABEL preos +KERNEL kernel INITRD initramfs -APPEND ro root=/dev/sda1 initrd=initrd.img """ self._init_helper() @@ -155,13 +156,29 @@ cp -L "$src" "$real_dst" os.chmod(filename, stat.S_IRUSR | stat.S_IXUSR) def create_kernel(self): - cmd=[ "cp", '"$(ls boot/vmlinuz-* | tail -n1)"' ] - cmd.append + dst = os.path.join(self.out_dir, "kernel") + srcglob = glob.glob("%s/boot/vmlinuz-*" % self.target_dir) + src = srcglob[0] - pass + shutil.copyfile(src, dst, follow_symlinks=True) + + def create_pxelinux(self): + dst = os.path.join(self.out_dir, "pxelinux.0") + src = "%s/usr/lib/syslinux/pxelinux.0" % self.target_dir + + shutil.copyfile(src, dst, follow_symlinks=True) + + def create_pxeconfig(self): + configdir = os.path.join(self.out_dir, "pxelinux.cfg") + configfile = os.path.join(configdir, "default") + if not os.path.isdir(configdir): + os.mkdir(configdir) + + with open(configfile, "w") as fd: + fd.write(self.pxelinux_cfg) def create_initramfs(self): - base_cmd="find . -print0 | sudo cpio --null -ov --format=newc | gzip -9" + base_cmd="find . -print0 | cpio --null -ov --format=newc | gzip -9" pass @@ -174,8 +191,9 @@ cp -L "$src" "$real_dst" self.out_dir = out_dir self.create_kernel() - self.create_initramfs() +# self.create_initramfs() self.create_pxeconfig() + self.create_pxelinux() def config(self): handle, path = tempfile.mkstemp(prefix='cdist.stdin.') @@ -210,4 +228,4 @@ cp -L "$src" "$real_dst" if args.pxe_boot: self.create_pxe(args.pxe_boot) if args.iso_boot: - self.create_iso(args.pxe_boot) + self.create_iso(args.iso_boot) From 0d78ab313ffcb81a0daf9b650f982cd3e1d1b90b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 11 Jan 2014 21:14:04 +0100 Subject: [PATCH 2374/4212] create initramfs Signed-off-by: Nico Schottelius --- cdist/preos.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cdist/preos.py b/cdist/preos.py index 1fb73ad7..6d473ddf 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -160,17 +160,20 @@ cp -L "$src" "$real_dst" srcglob = glob.glob("%s/boot/vmlinuz-*" % self.target_dir) src = srcglob[0] + log.info("Creating kernel ...") shutil.copyfile(src, dst, follow_symlinks=True) def create_pxelinux(self): dst = os.path.join(self.out_dir, "pxelinux.0") src = "%s/usr/lib/syslinux/pxelinux.0" % self.target_dir + log.info("Creating pxelinux.0 ...") shutil.copyfile(src, dst, follow_symlinks=True) def create_pxeconfig(self): configdir = os.path.join(self.out_dir, "pxelinux.cfg") configfile = os.path.join(configdir, "default") + log.info("Creating pxe configuration ...") if not os.path.isdir(configdir): os.mkdir(configdir) @@ -178,9 +181,11 @@ cp -L "$src" "$real_dst" fd.write(self.pxelinux_cfg) def create_initramfs(self): - base_cmd="find . -print0 | cpio --null -ov --format=newc | gzip -9" + out_file = os.path.join(self.out_dir, "initramfs") + cmd="cd {target_dir}; find . -print0 | cpio --null -o --format=newc | gzip -9 > {out_file}".format(target_dir = self.target_dir, out_file = out_file) - pass + log.info("Creating initramfs ...") + subprocess.check_call(cmd, shell=True) def create_iso(self, out_dir): self.out_dir = out_dir @@ -191,7 +196,7 @@ cp -L "$src" "$real_dst" self.out_dir = out_dir self.create_kernel() -# self.create_initramfs() + self.create_initramfs() self.create_pxeconfig() self.create_pxelinux() From 11ba4640b4c7d2e0018fcaafa0fab66f147a169f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 11 Jan 2014 22:34:44 +0100 Subject: [PATCH 2375/4212] disable unsupported iso - create /init - include support for another initial manifest Signed-off-by: Nico Schottelius --- cdist/preos.py | 89 +++++++++++++++++++++++----------- docs/dev/logs/2014-01-09.preos | 29 +++++++++-- scripts/cdist | 6 +-- 3 files changed, 87 insertions(+), 37 deletions(-) diff --git a/cdist/preos.py b/cdist/preos.py index 6d473ddf..cbb9f23c 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -24,16 +24,42 @@ import glob import os import subprocess import stat +import sys import shutil import tempfile - import cdist.config import cdist.exec.local import cdist.exec.remote log = logging.getLogger(__name__) +DEFAULT_MANIFEST = """ +for pkg in \ + file \ + linux-image-amd64 \ + openssh-server \ + syslinux \ + gdisk util-linux \ + btrfs-tools e2fsprogs jfsutils reiser4progs xfsprogs; do + __package $pkg --state present +done + +# initramfs requires /init +__link /init --source /sbin/init --type symbolic + +__file /etc/network/interfaces --source - --mode 0644 << eof +# The loopback network interface +auto lo +iface lo inet loopback + +# The primary network interface +auto eth0 +allow-hotplug eth0 +iface eth0 init dhcp +eof +""" + class PreOSExistsError(cdist.Error): def __init__(self, path): self.path = path @@ -65,32 +91,9 @@ KERNEL kernel INITRD initramfs """ - self._init_helper() - def _init_helper(self): self.helper = {} - self.helper["manifest"] = """ -for pkg in \ - file \ - linux-image-amd64 - openssh-server - syslinux \ - gdisk util-linux \ - btrfs-tools e2fsprogs jfsutils reiser4progs xfsprogs; do - __package $pkg --state present -done - -__file /etc/network/interfaces --source - --mode 0644 << eof -# The loopback network interface -auto lo -iface lo inet loopback - -# The primary network interface -auto eth0 -allow-hotplug eth0 -iface eth0 init dhcp -eof -""" + self.helper["manifest"] = self.initial_manifest self.helper["remote_exec"] = """#!/bin/sh # echo $@ # set -x @@ -200,7 +203,25 @@ cp -L "$src" "$real_dst" self.create_pxeconfig() self.create_pxelinux() + + def setup_initial_manifest(self, user_initial_manifest, replace_manifest): + if user_initial_manifest: + if user_initial_manifest == '-': + user_initial_manifest_content = sys.stdin.read() + else: + with open(user_initial_manifest, "r") as fd: + user_initial_manifest_content = fd.read() + else: + user_initial_manifest_content = "" + + if replace_manifest: + self.initial_manifest = user_initial_manifest_content + else: + self.initial_manifest = "{default}\n# User supplied manifest\n{user}".format(default=DEFAULT_MANIFEST, user=user_initial_manifest_content) + def config(self): + self._init_helper() + handle, path = tempfile.mkstemp(prefix='cdist.stdin.') with tempfile.TemporaryDirectory() as tempdir: host = self.target_dir @@ -226,11 +247,21 @@ cp -L "$src" "$real_dst" self = cls(target_dir=args.target_dir[0], arch=args.arch) + # read initial manifest first - it may come from stdin + if args.config: + self.setup_initial_manifest(args.initial_manifest, args.replace_manifest) + + # Bootstrap: creates base directory if args.bootstrap: self.bootstrap() + + # Configure the OS if args.config: self.config() - if args.pxe_boot: - self.create_pxe(args.pxe_boot) - if args.iso_boot: - self.create_iso(args.iso_boot) + + # Output pxe files + if args.pxe_boot_dir: + self.create_pxe(args.pxe_boot_dir) + + #if args.iso_boot_dir: + # self.create_iso(args.iso_boot) diff --git a/docs/dev/logs/2014-01-09.preos b/docs/dev/logs/2014-01-09.preos index c0b840ee..0f0b0384 100644 --- a/docs/dev/logs/2014-01-09.preos +++ b/docs/dev/logs/2014-01-09.preos @@ -8,21 +8,25 @@ - add option for different initial manifest - allow -, stdin usage + - allow to replace current manifest (later) - - add option for additional manifest - - allow -, stdin usage - - - trigger + x trigger - can be handled in the manifest of the user - remove /var/cache/apt/archives/* ? + - later, optimisation level + + + - bug: cdist config als root! - fix linux-image name (amd64) + - ln -s /sbin/init /init + - blog! - self configuring - - pxe + x pxe /pxe/ - pxelinux.0 - linux @@ -31,6 +35,9 @@ - default - iso + - later + - usb stick (+efi version) + - later - add unit tests @@ -81,3 +88,15 @@ INFO: /home/users/nico/preos-tests/preos03: Generating code for __package/linux- INFO: /home/users/nico/preos-tests/preos03: Finished successful run in 2.546635866165161 seconds [1:16] bento:~% +-------------------------------------------------------------------------------- +[21:14] bento:vm-tests% qemu-system-x86_64 -m 2G -boot order=cn -drive file=testhd1,if=virtio -net nic -net user,tftp=$(pwd -P)/tftp,bootfile=/pxelinux.0 + +-------------------------------------------------------------------------------- +[21:16] bento:preos-tests% sudo cdist preos -vp /home/users/nico/vm-tests/tftp /home/users/nico/preos-tests/preos03/ +INFO: cdist: version 3.0.0-42-g0d78ab3 +INFO: cdist.preos: Creating kernel ... +INFO: cdist.preos: Creating initramfs ... +760780 blocks +INFO: cdist.preos: Creating pxe configuration ... +INFO: cdist.preos: Creating pxelinux.0 ... + diff --git a/scripts/cdist b/scripts/cdist index c1e1cd94..ed9d2eda 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -101,9 +101,9 @@ def commandline(): parser['preos'].add_argument('-r', '--replace-manifest', help='Instead of appending to the built in manifest, replace the internal manifest', action="store_true") - parser['preos'].add_argument('-I', '--iso-boot', - help='Create ISO for booting in given location') - parser['preos'].add_argument('-p', '--pxe-boot', +# parser['preos'].add_argument('-I', '--iso-boot-dir', +# help='Create ISO for booting in given location') + parser['preos'].add_argument('-p', '--pxe-boot-dir', help='Create PXE files for booting in given location') parser['preos'].add_argument('target_dir', nargs=1, help='Select target directory') From e7ad8f929804e02337c4c09b4045ade2859d2b85 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 11 Jan 2014 22:45:38 +0100 Subject: [PATCH 2376/4212] inet not init Signed-off-by: Nico Schottelius --- cdist/preos.py | 2 +- docs/dev/logs/2014-01-09.preos | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cdist/preos.py b/cdist/preos.py index cbb9f23c..8b4a9a09 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -56,7 +56,7 @@ iface lo inet loopback # The primary network interface auto eth0 allow-hotplug eth0 -iface eth0 init dhcp +iface eth0 inet dhcp eof """ diff --git a/docs/dev/logs/2014-01-09.preos b/docs/dev/logs/2014-01-09.preos index 0f0b0384..8d5a59b6 100644 --- a/docs/dev/logs/2014-01-09.preos +++ b/docs/dev/logs/2014-01-09.preos @@ -41,6 +41,10 @@ - add unit tests +- testing with qemu + [22:43] bento:vm-tests% qemu-system-x86_64 -m 2G -boot order=cn -drive file=testhd1,if=virtio -net nic -net user,tftp=$(pwd -P)/tftp,bootfile=/pxelinux.0,hostfwd=tcp::7777-:22 -enable-kvm + + -------------------------------------------------------------------------------- [1:16] bento:~% sudo cdist preos -vc ~nico/preos-tests/preos03 From 07545f4f7f9ddc806037a61babccefa6d3fa83a5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 11 Jan 2014 22:47:34 +0100 Subject: [PATCH 2377/4212] update preos notes Signed-off-by: Nico Schottelius --- docs/dev/logs/2014-01-09.preos | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/dev/logs/2014-01-09.preos b/docs/dev/logs/2014-01-09.preos index 8d5a59b6..1a3f2ddc 100644 --- a/docs/dev/logs/2014-01-09.preos +++ b/docs/dev/logs/2014-01-09.preos @@ -6,9 +6,9 @@ x various mkfs variants - various fdisk tools - - add option for different initial manifest - - allow -, stdin usage - - allow to replace current manifest (later) + x add option for different initial manifest + x allow -, stdin usage + x allow to replace current manifest (later) x trigger - can be handled in the manifest of the user @@ -44,6 +44,9 @@ - testing with qemu [22:43] bento:vm-tests% qemu-system-x86_64 -m 2G -boot order=cn -drive file=testhd1,if=virtio -net nic -net user,tftp=$(pwd -P)/tftp,bootfile=/pxelinux.0,hostfwd=tcp::7777-:22 -enable-kvm +- create preos + [22:43] bento:preos-tests% echo __panter_root_ssh_keys | sudo cdist preos -vp /home/users/nico/vm-tests/tftp -c /home/users/nico/preos-tests/preos03/ -i - + -------------------------------------------------------------------------------- From 3daa74e81dc225a9004ba276b20e25f1ad3d80be Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 11 Jan 2014 22:48:47 +0100 Subject: [PATCH 2378/4212] fix 'stdin: is not a tty' problem (thanks, steven) Signed-off-by: Nico Schottelius --- cdist/preos.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cdist/preos.py b/cdist/preos.py index 8b4a9a09..433cf871 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -58,6 +58,10 @@ auto eth0 allow-hotplug eth0 iface eth0 inet dhcp eof + +# Steven found this out - coyping it 1:1 +# fix the bloody 'stdin: is not a tty' problem +__line /root/.profile --line 'mesg n' --state absent """ class PreOSExistsError(cdist.Error): From ef1394f4d1cc6b042057d4f071f6765d09f18c2a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 13 Jan 2014 22:07:05 +0100 Subject: [PATCH 2379/4212] 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 2380/4212] 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 2381/4212] ++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 2382/4212] __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 2383/4212] __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 2384/4212] ++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 2385/4212] 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 2386/4212] 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 2387/4212] 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 2388/4212] ++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 2389/4212] 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 54815e2b29ae2642f17c600a3c7afa1e24262d7d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 29 Aug 2013 22:32:26 +0200 Subject: [PATCH 2390/4212] implement cdist install Signed-off-by: Steven Armstrong --- cdist/config.py | 1 - cdist/core/cdist_type.py | 5 ++ cdist/emulator.py | 2 +- cdist/install.py | 37 ++++++++++ cdist/test/cdist_type/__init__.py | 10 +++ docs/dev/todo/steven | 118 ------------------------------ scripts/cdist | 5 ++ 7 files changed, 58 insertions(+), 120 deletions(-) create mode 100644 cdist/install.py delete mode 100644 docs/dev/todo/steven diff --git a/cdist/config.py b/cdist/config.py index 3f8a7fc6..59cf339a 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -158,7 +158,6 @@ class Config(object): 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, 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""" diff --git a/cdist/emulator.py b/cdist/emulator.py index b70ef956..b8f7b10b 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) -# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012-2013 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # diff --git a/cdist/install.py b/cdist/install.py new file mode 100644 index 00000000..4530029a --- /dev/null +++ b/cdist/install.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 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 . +# +# + +import cdist.config +import cdist.core + + +class Install(cdist.config.Config): + def object_list(self): + """Short name for object list retrieval. + In install mode, we only care about install objects. + """ + for cdist_object in cdist.core.CdistObject.list_objects(self.local.object_path, + self.local.type_path): + if cdist_object.cdist_type.is_install: + yield cdist_object + else: + self.log.debug("Running in install mode, ignoring non install object: {0}".format(cdist_object)) diff --git a/cdist/test/cdist_type/__init__.py b/cdist/test/cdist_type/__init__.py index 79f824d3..8cc1f2e4 100644 --- a/cdist/test/cdist_type/__init__.py +++ b/cdist/test/cdist_type/__init__.py @@ -106,6 +106,16 @@ 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/docs/dev/todo/steven b/docs/dev/todo/steven deleted file mode 100644 index 2aacaa42..00000000 --- a/docs/dev/todo/steven +++ /dev/null @@ -1,118 +0,0 @@ -autorequire: - - objects defined in type manifests should be automatically prerequisites of the current object - - __foo/some-id - __other other-id --state present - => require="__other/other-id" __foo/some-id - - -metaparameters: - - steal the metaparameters from puppet: - - # I have to be there before the other one - __directory /etc/ssh \ - --before __file/etc/ssh/sshd_config - - # the other one has to be there before me - __file /etc/ssh/sshd_config \ - --after __directory/etc/ssh - - # if I change, tell the other one about it - __file /etc/ssh/sshd_config \ - --notify __init_script/etc/rc.d/sshd - - # whenever the other one changes, I want to know - __init_script /etc/rc.d/sshd \ - --subscribe __file/etc/ssh/sshd_config - - - how does a type react to a received 'event'? - - maybe something like: - __some_type/ - manifest - ... - gencode-refresh - ... - - gencode-refresh -> code-refresh -> ssh $target sh -e code-refresh - - - - -logging: - - logging from type emulator without clobbering stdout - maybe implement logging server as described here [1] - [1] http://docs.python.org/py3k/howto/logging-cookbook.html#configuration-server-example - - - use different logger to limit output to current area of interest, - e.g. - explorer.$target_host: explorer related messages for the run for $target_host - manifest.$target_host: manifest related messages for the run for $target_host - ... - then one could filter e.g. on explorer.* - - - more granular debug output, - [2] http://blog.ooz.ie/2011/03/python-logging-extending-standard.html - - - -tests: - - __init__(): - - sets up env: __target_host - - run_initial_manifest(): - - parameter is actually used (from __init__) - - ensure changing the manifest actually runs a different manifest - -> give ConfigInstall Constructor different manifest - -> different manifest is executed. - - test all submitted (from core to type manifest) variables: - - ENVIRONMENT - - they are set - - they contain the correct values - - run_type_manifest(): - - test all submitted (from core to type manifest) variables: - - ENVIRONMENT - - they are set - - they contain the correct values - - same tests as for test_initial_manifest_*? - - run_manifest(): - - test all submitted variables: - - ENVIRONMENT - - including __debug, if debug - - they are set - - they contain the correct values - - does $require work? - - check that exception raised, if manifest is not existent - - object_run(): - - ensure no object is run twice - - ensure requirements are taken into account? - - and order of run is adjusted - - check (from extern?) that all needed variables are setup - - ensure no code-{local, remote} is created, - if gencode is not producing code - - ensure THAT code-{local, remote} contains what gencode created - - abort if gencode-* fails - - abort if code-* fails - - abort == raise(FooException) - - gencode-*: ensure ENVIRONMENT is setup correctly - - run_type_explorer() - - ensure ALL type explores have been run - - ensure output is saved to correct path - - ensure a type with {0,1,2} explorers works ? - - none, one, multiple - - ensure ENVIRONMENT is setup correctly - - fails if ANY of the given explorer fails - - run_global_explorers(): - - ensure ALL type explores have been run - - ensure output is saved to correct path - - ensure a type with {0,1,2} explorers works ? - - none, one, multiple - - ensure ENVIRONMENT is setup correctly - - fails if ANY of the given explorer fails - -Code fixes needed: - - - shutil, os.mkdir, etc. everywhere: catch/reraise exceptions correctly diff --git a/scripts/cdist b/scripts/cdist index 39449666..31bd7373 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -26,6 +26,7 @@ def commandline(): import cdist.banner import cdist.config + import cdist.install import cdist.shell # Construct parser others can reuse @@ -90,6 +91,10 @@ def commandline(): help='Select shell to use, defaults to current shell') parser['shell'].set_defaults(func=cdist.shell.Shell.commandline) + # Install + parser['install'] = parser['sub'].add_parser('install', + parents=[parser['loglevel'], parser['config']]) + parser['install'].set_defaults(func=cdist.install.Install.commandline) for p in parser: parser[p].epilog = "Get cdist at http://www.nico.schottelius.org/software/cdist/" From 02476073aac96ce59d25e71ace119489616d4551 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 29 Aug 2013 22:33:43 +0200 Subject: [PATCH 2391/4212] add install types Signed-off-by: Steven Armstrong --- .../__install_bootloader_grub/gencode-remote | 73 ++++++++ .../type/__install_bootloader_grub/install | 0 .../type/__install_bootloader_grub/man.text | 47 +++++ .../type/__install_bootloader_grub/manifest | 25 +++ .../parameter/optional | 2 + .../__install_chroot_mount/gencode-remote | 1 + .../conf/type/__install_chroot_mount/install | 0 .../conf/type/__install_chroot_mount/man.text | 1 + .../__install_chroot_umount/gencode-remote | 1 + .../conf/type/__install_chroot_umount/install | 0 .../type/__install_chroot_umount/man.text | 1 + .../type/__install_config/files/remote/copy | 48 +++++ .../type/__install_config/files/remote/exec | 73 ++++++++ .../conf/type/__install_config/gencode-local | 50 +++++ cdist/conf/type/__install_config/install | 0 cdist/conf/type/__install_config/man.text | 47 +++++ cdist/conf/type/__install_config/manifest | 23 +++ .../type/__install_config/parameter/optional | 1 + cdist/conf/type/__install_config/singleton | 0 cdist/conf/type/__install_file/explorer | 1 + cdist/conf/type/__install_file/gencode-local | 1 + cdist/conf/type/__install_file/gencode-remote | 1 + cdist/conf/type/__install_file/install | 0 cdist/conf/type/__install_file/man.text | 1 + cdist/conf/type/__install_file/parameter | 1 + cdist/conf/type/__install_fstab/install | 0 cdist/conf/type/__install_fstab/man.text | 48 +++++ cdist/conf/type/__install_fstab/manifest | 29 +++ .../type/__install_fstab/parameter/optional | 1 + cdist/conf/type/__install_fstab/singleton | 0 .../files/fstab.header | 1 + .../__install_generate_fstab/gencode-local | 59 ++++++ .../type/__install_generate_fstab/install | 0 .../type/__install_generate_fstab/man.text | 52 ++++++ .../parameter/boolean | 1 + .../parameter/required | 1 + .../type/__install_generate_fstab/singleton | 0 cdist/conf/type/__install_mkfs/gencode-remote | 71 +++++++ cdist/conf/type/__install_mkfs/install | 0 cdist/conf/type/__install_mkfs/man.text | 57 ++++++ cdist/conf/type/__install_mkfs/manifest | 31 ++++ .../type/__install_mkfs/parameter/optional | 3 + .../type/__install_mkfs/parameter/required | 1 + .../conf/type/__install_mount/gencode-remote | 78 ++++++++ cdist/conf/type/__install_mount/install | 0 cdist/conf/type/__install_mount/man.text | 61 ++++++ cdist/conf/type/__install_mount/manifest | 29 +++ .../type/__install_mount/parameter/optional | 3 + .../type/__install_mount/parameter/required | 1 + .../type/__install_partition_msdos/install | 0 .../type/__install_partition_msdos/man.text | 62 +++++++ .../type/__install_partition_msdos/manifest | 41 ++++ .../parameter/optional | 3 + .../parameter/required | 1 + .../explorer/partitions | 3 + .../files/lib.sh | 68 +++++++ .../gencode-remote | 175 ++++++++++++++++++ .../__install_partition_msdos_apply/install | 0 .../__install_partition_msdos_apply/man.text | 42 +++++ .../__install_partition_msdos_apply/singleton | 0 .../conf/type/__install_reboot/gencode-remote | 23 +++ cdist/conf/type/__install_reboot/install | 0 cdist/conf/type/__install_reboot/man.text | 43 +++++ cdist/conf/type/__install_reboot/manifest | 23 +++ cdist/conf/type/__install_reboot/singleton | 0 .../type/__install_reset_disk/gencode-remote | 65 +++++++ cdist/conf/type/__install_reset_disk/install | 0 cdist/conf/type/__install_reset_disk/man.text | 43 +++++ .../conf/type/__install_stage/gencode-remote | 65 +++++++ cdist/conf/type/__install_stage/install | 0 cdist/conf/type/__install_stage/man.text | 58 ++++++ cdist/conf/type/__install_stage/manifest | 33 ++++ .../type/__install_stage/parameter/optional | 2 + .../type/__install_stage/parameter/required | 1 + cdist/conf/type/__install_stage/singleton | 0 .../conf/type/__install_umount/gencode-remote | 25 +++ cdist/conf/type/__install_umount/install | 0 cdist/conf/type/__install_umount/man.text | 43 +++++ cdist/conf/type/__install_umount/manifest | 23 +++ 79 files changed, 1767 insertions(+) create mode 100755 cdist/conf/type/__install_bootloader_grub/gencode-remote create mode 100644 cdist/conf/type/__install_bootloader_grub/install create mode 100644 cdist/conf/type/__install_bootloader_grub/man.text create mode 100755 cdist/conf/type/__install_bootloader_grub/manifest create mode 100644 cdist/conf/type/__install_bootloader_grub/parameter/optional create mode 120000 cdist/conf/type/__install_chroot_mount/gencode-remote create mode 100644 cdist/conf/type/__install_chroot_mount/install create mode 120000 cdist/conf/type/__install_chroot_mount/man.text create mode 120000 cdist/conf/type/__install_chroot_umount/gencode-remote create mode 100644 cdist/conf/type/__install_chroot_umount/install create mode 120000 cdist/conf/type/__install_chroot_umount/man.text create mode 100755 cdist/conf/type/__install_config/files/remote/copy create mode 100755 cdist/conf/type/__install_config/files/remote/exec create mode 100755 cdist/conf/type/__install_config/gencode-local create mode 100644 cdist/conf/type/__install_config/install create mode 100644 cdist/conf/type/__install_config/man.text create mode 100755 cdist/conf/type/__install_config/manifest create mode 100644 cdist/conf/type/__install_config/parameter/optional create mode 100644 cdist/conf/type/__install_config/singleton create mode 120000 cdist/conf/type/__install_file/explorer create mode 120000 cdist/conf/type/__install_file/gencode-local create mode 120000 cdist/conf/type/__install_file/gencode-remote create mode 100644 cdist/conf/type/__install_file/install create mode 120000 cdist/conf/type/__install_file/man.text create mode 120000 cdist/conf/type/__install_file/parameter create mode 100644 cdist/conf/type/__install_fstab/install create mode 100644 cdist/conf/type/__install_fstab/man.text create mode 100755 cdist/conf/type/__install_fstab/manifest create mode 100644 cdist/conf/type/__install_fstab/parameter/optional create mode 100644 cdist/conf/type/__install_fstab/singleton create mode 100644 cdist/conf/type/__install_generate_fstab/files/fstab.header create mode 100755 cdist/conf/type/__install_generate_fstab/gencode-local create mode 100644 cdist/conf/type/__install_generate_fstab/install create mode 100644 cdist/conf/type/__install_generate_fstab/man.text create mode 100644 cdist/conf/type/__install_generate_fstab/parameter/boolean create mode 100644 cdist/conf/type/__install_generate_fstab/parameter/required create mode 100644 cdist/conf/type/__install_generate_fstab/singleton create mode 100755 cdist/conf/type/__install_mkfs/gencode-remote create mode 100644 cdist/conf/type/__install_mkfs/install create mode 100644 cdist/conf/type/__install_mkfs/man.text create mode 100755 cdist/conf/type/__install_mkfs/manifest create mode 100644 cdist/conf/type/__install_mkfs/parameter/optional create mode 100644 cdist/conf/type/__install_mkfs/parameter/required create mode 100755 cdist/conf/type/__install_mount/gencode-remote create mode 100644 cdist/conf/type/__install_mount/install create mode 100644 cdist/conf/type/__install_mount/man.text create mode 100755 cdist/conf/type/__install_mount/manifest create mode 100644 cdist/conf/type/__install_mount/parameter/optional create mode 100644 cdist/conf/type/__install_mount/parameter/required create mode 100644 cdist/conf/type/__install_partition_msdos/install create mode 100644 cdist/conf/type/__install_partition_msdos/man.text create mode 100755 cdist/conf/type/__install_partition_msdos/manifest create mode 100644 cdist/conf/type/__install_partition_msdos/parameter/optional create mode 100644 cdist/conf/type/__install_partition_msdos/parameter/required create mode 100755 cdist/conf/type/__install_partition_msdos_apply/explorer/partitions create mode 100644 cdist/conf/type/__install_partition_msdos_apply/files/lib.sh create mode 100755 cdist/conf/type/__install_partition_msdos_apply/gencode-remote create mode 100644 cdist/conf/type/__install_partition_msdos_apply/install create mode 100644 cdist/conf/type/__install_partition_msdos_apply/man.text create mode 100644 cdist/conf/type/__install_partition_msdos_apply/singleton create mode 100755 cdist/conf/type/__install_reboot/gencode-remote create mode 100644 cdist/conf/type/__install_reboot/install create mode 100644 cdist/conf/type/__install_reboot/man.text create mode 100755 cdist/conf/type/__install_reboot/manifest create mode 100644 cdist/conf/type/__install_reboot/singleton create mode 100755 cdist/conf/type/__install_reset_disk/gencode-remote create mode 100644 cdist/conf/type/__install_reset_disk/install create mode 100644 cdist/conf/type/__install_reset_disk/man.text create mode 100755 cdist/conf/type/__install_stage/gencode-remote create mode 100644 cdist/conf/type/__install_stage/install create mode 100644 cdist/conf/type/__install_stage/man.text create mode 100755 cdist/conf/type/__install_stage/manifest create mode 100644 cdist/conf/type/__install_stage/parameter/optional create mode 100644 cdist/conf/type/__install_stage/parameter/required create mode 100644 cdist/conf/type/__install_stage/singleton create mode 100755 cdist/conf/type/__install_umount/gencode-remote create mode 100644 cdist/conf/type/__install_umount/install create mode 100644 cdist/conf/type/__install_umount/man.text create mode 100755 cdist/conf/type/__install_umount/manifest diff --git a/cdist/conf/type/__install_bootloader_grub/gencode-remote b/cdist/conf/type/__install_bootloader_grub/gencode-remote new file mode 100755 index 00000000..ed57331a --- /dev/null +++ b/cdist/conf/type/__install_bootloader_grub/gencode-remote @@ -0,0 +1,73 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +device="$(cat "$__object/parameter/device")" +chroot="$(cat "$__object/parameter/chroot")" + + +cat << DONE +os=\$( +if grep -q ^DISTRIB_ID=Ubuntu ${chroot}/etc/lsb-release 2>/dev/null; then + echo ubuntu + exit 0 +fi + +if [ -f ${chroot}/etc/arch-release ]; then + echo archlinux + exit 0 +fi + +if [ -f ${chroot}/etc/debian_version ]; then + echo debian + exit 0 +fi +) + +# Ensure /tmp exists +[ -d "${chroot}/tmp" ] || mkdir -m 1777 "${chroot}/tmp" +# Generate script to run in chroot +script=\$(mktemp "${chroot}/tmp/__install_bootloader_grub.XXXXXXXXXX") +# Link file descriptor #6 with stdout +exec 6>&1 +# Link stdout with \$script +exec > \$script + +echo "#!/bin/sh -l" +echo "grub-install $device" +case \$os in + archlinux) + # bugfix/workarround: rebuild initramfs + # FIXME: doesn't belong here + echo "mkinitcpio -p linux" + echo "grub-mkconfig -o /boot/grub/grub.cfg" + ;; + ubuntu|debian) echo "update-grub" ;; +esac + +# Restore stdout and close file descriptor #6. +exec 1>&6 6>&- + +# Make script executable +chmod +x "\$script" + +# Run script in chroot +relative_script="\${script#$chroot}" +chroot "$chroot" "\$relative_script" +DONE diff --git a/cdist/conf/type/__install_bootloader_grub/install b/cdist/conf/type/__install_bootloader_grub/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_bootloader_grub/man.text b/cdist/conf/type/__install_bootloader_grub/man.text new file mode 100644 index 00000000..858e6a67 --- /dev/null +++ b/cdist/conf/type/__install_bootloader_grub/man.text @@ -0,0 +1,47 @@ +cdist-type__install_bootloader_grub(7) +====================================== +Steven Armstrong + + +NAME +---- +cdist-type__install_bootloader_grub - install grub2 bootloader on given disk + + +DESCRIPTION +----------- +This cdist type allows you to install grub2 bootloader on given disk. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +device:: + The device to install grub to. Defaults to object_id + +chroot:: + where to chroot before running grub-install. Defaults to /target. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__install_bootloader_grub /dev/sda +__install_bootloader_grub /dev/sda --chroot /mnt/foobar +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__install_bootloader_grub/manifest b/cdist/conf/type/__install_bootloader_grub/manifest new file mode 100755 index 00000000..4c7c4955 --- /dev/null +++ b/cdist/conf/type/__install_bootloader_grub/manifest @@ -0,0 +1,25 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# set defaults +device="$(cat "$__object/parameter/device" 2>/dev/null \ + || echo "/$__object_id" | tee "$__object/parameter/device")" +chroot="$(cat "$__object/parameter/chroot" 2>/dev/null \ + || echo "/target" | tee "$__object/parameter/chroot")" diff --git a/cdist/conf/type/__install_bootloader_grub/parameter/optional b/cdist/conf/type/__install_bootloader_grub/parameter/optional new file mode 100644 index 00000000..0bd1ce46 --- /dev/null +++ b/cdist/conf/type/__install_bootloader_grub/parameter/optional @@ -0,0 +1,2 @@ +device +chroot diff --git a/cdist/conf/type/__install_chroot_mount/gencode-remote b/cdist/conf/type/__install_chroot_mount/gencode-remote new file mode 120000 index 00000000..b1a5485e --- /dev/null +++ b/cdist/conf/type/__install_chroot_mount/gencode-remote @@ -0,0 +1 @@ +../__chroot_mount/gencode-remote \ No newline at end of file diff --git a/cdist/conf/type/__install_chroot_mount/install b/cdist/conf/type/__install_chroot_mount/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_chroot_mount/man.text b/cdist/conf/type/__install_chroot_mount/man.text new file mode 120000 index 00000000..e131fceb --- /dev/null +++ b/cdist/conf/type/__install_chroot_mount/man.text @@ -0,0 +1 @@ +../__chroot_mount/man.text \ No newline at end of file diff --git a/cdist/conf/type/__install_chroot_umount/gencode-remote b/cdist/conf/type/__install_chroot_umount/gencode-remote new file mode 120000 index 00000000..f2bd2681 --- /dev/null +++ b/cdist/conf/type/__install_chroot_umount/gencode-remote @@ -0,0 +1 @@ +../__chroot_umount/gencode-remote \ No newline at end of file diff --git a/cdist/conf/type/__install_chroot_umount/install b/cdist/conf/type/__install_chroot_umount/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_chroot_umount/man.text b/cdist/conf/type/__install_chroot_umount/man.text new file mode 120000 index 00000000..f615c734 --- /dev/null +++ b/cdist/conf/type/__install_chroot_umount/man.text @@ -0,0 +1 @@ +../__chroot_umount/man.text \ No newline at end of file diff --git a/cdist/conf/type/__install_config/files/remote/copy b/cdist/conf/type/__install_config/files/remote/copy new file mode 100755 index 00000000..5b6f555c --- /dev/null +++ b/cdist/conf/type/__install_config/files/remote/copy @@ -0,0 +1,48 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# __remote_copy script to run cdist against a chroot on a remote host via ssh. +# +# Usage: +# __remote_copy="/path/to/this/script /path/to/your/chroot" cdist config target-id +# + +log() { + echo "$@" | logger -t "__install_config copy" + : +} + +chroot="$1"; shift +target_host="$__target_host" + +scp="scp -o User=root -q" + +# postfix target_host with chroot location +code="$(echo "$@" | sed "s|$target_host:|$target_host:$chroot|g")" + +log "target_host: $target_host" +log "chroot: $chroot" +log "@: $@" +log "code: $code" + +# copy files into chroot +$scp $code + +log "-----" diff --git a/cdist/conf/type/__install_config/files/remote/exec b/cdist/conf/type/__install_config/files/remote/exec new file mode 100755 index 00000000..4822bcf3 --- /dev/null +++ b/cdist/conf/type/__install_config/files/remote/exec @@ -0,0 +1,73 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# +# __remote_exec script to run cdist against a chroot on a remote host via ssh. +# +# Usage: +# __remote_exec="/path/to/this/script /path/to/your/chroot" cdist config target-id +# + +log() { + echo "$@" | logger -t "__install_config exec" + : +} + +chroot="$1"; shift +target_host="$__target_host" +# In exec mode the first argument is the __target_host which we already got from env. Get rid of it. +shift + +ssh="ssh -o User=root -q $target_host" +scp="scp -o User=root -q" + +local_script=$(mktemp "/tmp/chroot-${0##*/}.XXXXXXXXXX") +remote_script=$($ssh mktemp "${chroot}/tmp/chroot-${0##*/}.XXXXXXXXXX") +relative_script="${remote_script#$chroot}" +trap cleanup INT TERM EXIT +cleanup() { + [ $__cdist_debug ] || { + rm "$local_script" + $ssh "rm $remote_script"; + } +} + +log "chroot: $chroot" +log "target_host: $target_host" +log "local_script: $local_script" +log "remote_script: $remote_script" +log "relative_script: $relative_script" +log "@: $@" +cat > "$local_script" << DONE +#!/bin/sh -l +# FIXME: fix the dependency bug, then test if the below is required or not +#if [ -f /etc/environment ]; then +# . /etc/environment +#fi +$@ +DONE + +# Upload script to target +$scp $local_script $target_host:$remote_script +$ssh "chmod +x $remote_script" + +# run in chroot +$ssh "chroot $chroot $relative_script" + +log "-----" diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local new file mode 100755 index 00000000..da87a4ac --- /dev/null +++ b/cdist/conf/type/__install_config/gencode-local @@ -0,0 +1,50 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +chroot="$(cat "$__object/parameter/chroot")" +remote_exec="$__type/files/remote/exec" +remote_copy="$__type/files/remote/copy" + +cdist_args="-v" +[ "$__debug" = "yes" ] && cdist_args="$cdist_args -d" + +cat << DONE +echo "__apt_noautostart --state present" \ + | cdist $cdist_args \ + config \ + --initial-manifest - \ + --remote-exec="$remote_exec $chroot" \ + --remote-copy="$remote_copy $chroot" \ + $__target_host + +cdist $cdist_args \ + config \ + --remote-exec="$remote_exec $chroot" \ + --remote-copy="$remote_copy $chroot" \ + $__target_host + +echo "__apt_noautostart --state absent" \ + | cdist $cdist_args \ + config \ + --initial-manifest - \ + --remote-exec="$remote_exec $chroot" \ + --remote-copy="$remote_copy $chroot" \ + $__target_host +DONE diff --git a/cdist/conf/type/__install_config/install b/cdist/conf/type/__install_config/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_config/man.text b/cdist/conf/type/__install_config/man.text new file mode 100644 index 00000000..def0439b --- /dev/null +++ b/cdist/conf/type/__install_config/man.text @@ -0,0 +1,47 @@ +cdist-type__install_config(7) +============================= +Steven Armstrong + + +NAME +---- +cdist-type__install_config - run cdist config as part of the installation + + +DESCRIPTION +----------- +This cdist type allows you to run cdist config as part of the installation. +It does this by using a custom __remote_{copy,exec} prefix which runs +cdist config against the /target chroot on the remote host. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +chroot:: + where to chroot before running grub-install. Defaults to /target. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__install_config + +__install_config --chroot /mnt/somewhere +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__install_config/manifest b/cdist/conf/type/__install_config/manifest new file mode 100755 index 00000000..f26297b4 --- /dev/null +++ b/cdist/conf/type/__install_config/manifest @@ -0,0 +1,23 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# set defaults +chroot="$(cat "$__object/parameter/chroot" 2>/dev/null \ + || echo "/target" | tee "$__object/parameter/chroot")" diff --git a/cdist/conf/type/__install_config/parameter/optional b/cdist/conf/type/__install_config/parameter/optional new file mode 100644 index 00000000..fa32393d --- /dev/null +++ b/cdist/conf/type/__install_config/parameter/optional @@ -0,0 +1 @@ +chroot diff --git a/cdist/conf/type/__install_config/singleton b/cdist/conf/type/__install_config/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_file/explorer b/cdist/conf/type/__install_file/explorer new file mode 120000 index 00000000..8479ee44 --- /dev/null +++ b/cdist/conf/type/__install_file/explorer @@ -0,0 +1 @@ +../__file/explorer \ No newline at end of file diff --git a/cdist/conf/type/__install_file/gencode-local b/cdist/conf/type/__install_file/gencode-local new file mode 120000 index 00000000..9ce4e805 --- /dev/null +++ b/cdist/conf/type/__install_file/gencode-local @@ -0,0 +1 @@ +../__file/gencode-local \ No newline at end of file diff --git a/cdist/conf/type/__install_file/gencode-remote b/cdist/conf/type/__install_file/gencode-remote new file mode 120000 index 00000000..f390bba4 --- /dev/null +++ b/cdist/conf/type/__install_file/gencode-remote @@ -0,0 +1 @@ +../__file/gencode-remote \ No newline at end of file diff --git a/cdist/conf/type/__install_file/install b/cdist/conf/type/__install_file/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_file/man.text b/cdist/conf/type/__install_file/man.text new file mode 120000 index 00000000..ba483161 --- /dev/null +++ b/cdist/conf/type/__install_file/man.text @@ -0,0 +1 @@ +../__file/man.text \ No newline at end of file diff --git a/cdist/conf/type/__install_file/parameter b/cdist/conf/type/__install_file/parameter new file mode 120000 index 00000000..e5099e86 --- /dev/null +++ b/cdist/conf/type/__install_file/parameter @@ -0,0 +1 @@ +../__file/parameter \ No newline at end of file diff --git a/cdist/conf/type/__install_fstab/install b/cdist/conf/type/__install_fstab/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_fstab/man.text b/cdist/conf/type/__install_fstab/man.text new file mode 100644 index 00000000..7c509427 --- /dev/null +++ b/cdist/conf/type/__install_fstab/man.text @@ -0,0 +1,48 @@ +cdist-type__install_fstab(7) +============================ +Steven Armstrong + + +NAME +---- +cdist-type__install_fstab - generate /etc/fstab during installation + + +DESCRIPTION +----------- +Uses __install_generate_fstab to generate a /etc/fstab file and uploads it +to the target machine at ${prefix}/etc/fstab. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +prefix:: + The prefix under which to generate the /etc/fstab file. + Defaults to /target. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__install_fstab +__install_fstab --prefix /mnt/target +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__install_mount(7) +- cdist-type__install_generate_fstab(7) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__install_fstab/manifest b/cdist/conf/type/__install_fstab/manifest new file mode 100755 index 00000000..74af53c0 --- /dev/null +++ b/cdist/conf/type/__install_fstab/manifest @@ -0,0 +1,29 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +prefix="$(cat "$__object/parameter/prefix" 2>/dev/null || echo "/target")" + +[ -d "$__object/files" ] || mkdir "$__object/files" +__install_generate_fstab --uuid --destination "$__object/files/fstab" +require="__install_generate_fstab" \ + __install_file "${prefix}/etc/fstab" --source "$__object/files/fstab" \ + --mode 644 \ + --owner root \ + --group root diff --git a/cdist/conf/type/__install_fstab/parameter/optional b/cdist/conf/type/__install_fstab/parameter/optional new file mode 100644 index 00000000..f73f3093 --- /dev/null +++ b/cdist/conf/type/__install_fstab/parameter/optional @@ -0,0 +1 @@ +file diff --git a/cdist/conf/type/__install_fstab/singleton b/cdist/conf/type/__install_fstab/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_generate_fstab/files/fstab.header b/cdist/conf/type/__install_generate_fstab/files/fstab.header new file mode 100644 index 00000000..7653cc78 --- /dev/null +++ b/cdist/conf/type/__install_generate_fstab/files/fstab.header @@ -0,0 +1 @@ +# Generated by cdist __install_generate_fstab diff --git a/cdist/conf/type/__install_generate_fstab/gencode-local b/cdist/conf/type/__install_generate_fstab/gencode-local new file mode 100755 index 00000000..d10e5b92 --- /dev/null +++ b/cdist/conf/type/__install_generate_fstab/gencode-local @@ -0,0 +1,59 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +destination="$(cat "$__object/parameter/destination")" +cat "$__type/files/fstab.header" > "$destination" + +mkdir "$__object/files" +# get current UUID's from target_host +$__remote_exec $__target_host blkid > "$__object/files/blkid" + +for object in $(find "$__global/object/__install_mount" -path "*.cdist"); do + device="$(cat "$object/parameter/device")" + dir="$(cat "$object/parameter/dir")" + prefix="$(cat "$object/parameter/prefix")" + type="$(cat "$object/parameter/type")" + if [ -f "$object/parameter/options" ]; then + options="$(cat "$object/parameter/options")" + else + options="defaults" + fi + dump=0 + case "$type" in + swap) + pass=0 + dir="$type" + ;; + tmpfs) + pass=0 + ;; + *) + pass=1 + ;; + esac + if [ -f "$__object/parameter/uuid" ]; then + uuid="$(grep -w $device "$__object/files/blkid" | awk '{print $2}')" + if [ -n "$uuid" ]; then + echo "# $dir was on $device during installation" >> "$destination" + device="$uuid" + fi + fi + echo "$device $dir $type $options $dump $pass" >> "$destination" +done diff --git a/cdist/conf/type/__install_generate_fstab/install b/cdist/conf/type/__install_generate_fstab/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_generate_fstab/man.text b/cdist/conf/type/__install_generate_fstab/man.text new file mode 100644 index 00000000..d7d747a0 --- /dev/null +++ b/cdist/conf/type/__install_generate_fstab/man.text @@ -0,0 +1,52 @@ +cdist-type__install_generate_fstab(7) +===================================== +Steven Armstrong + + +NAME +---- +cdist-type__install_generate_fstab - generate /etc/fstab during installation + + +DESCRIPTION +----------- +Generates a /etc/fstab file from information retreived from +__install_mount definitions. + + +REQUIRED PARAMETERS +------------------- +destination:: + The path where to store the generated fstab file. + Note that this is a path on the server, where cdist is running, not the target host. + + +OPTIONAL PARAMETERS +------------------- +None. + + +BOOLEAN PARAMETERS +------------------- +uuid:: + use UUID instead of device in fstab + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__install_generate_fstab --destination /path/where/you/want/fstab +__install_generate_fstab --uuid --destination /path/where/you/want/fstab +-------------------------------------------------------------------------------- + + +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/__install_generate_fstab/parameter/boolean b/cdist/conf/type/__install_generate_fstab/parameter/boolean new file mode 100644 index 00000000..43ab6159 --- /dev/null +++ b/cdist/conf/type/__install_generate_fstab/parameter/boolean @@ -0,0 +1 @@ +uuid diff --git a/cdist/conf/type/__install_generate_fstab/parameter/required b/cdist/conf/type/__install_generate_fstab/parameter/required new file mode 100644 index 00000000..ac459b09 --- /dev/null +++ b/cdist/conf/type/__install_generate_fstab/parameter/required @@ -0,0 +1 @@ +destination diff --git a/cdist/conf/type/__install_generate_fstab/singleton b/cdist/conf/type/__install_generate_fstab/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_mkfs/gencode-remote b/cdist/conf/type/__install_mkfs/gencode-remote new file mode 100755 index 00000000..6a71b8ed --- /dev/null +++ b/cdist/conf/type/__install_mkfs/gencode-remote @@ -0,0 +1,71 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +device="$(cat "$__object/parameter/device")" +type="$(cat "$__object/parameter/type")" + +# show command output in debug mode +cat << DONE +__debug=$__cdist_debug +if [ "\$__debug" != "yes" ]; then + # Link file descriptor #6 with stdout + exec 6>&1 + # redirect all output to /dev/null + exec > /dev/null +fi +DONE + +case "$type" in + swap) + echo "mkswap $device" + ;; + xfs) + command="mkfs.xfs -f -q" + if [ -f "$__object/parameter/options" ]; then + options="$(cat "$__object/parameter/options")" + command="$command $options" + fi + command="$command $device" + if [ -f "$__object/parameter/blocks" ]; then + blocks="$(cat "$__object/parameter/blocks")" + command="$command $blocks" + fi + echo "$command" + ;; + *) + command="mkfs -t $type -q" + if [ -f "$__object/parameter/options" ]; then + options="$(cat "$__object/parameter/options")" + command="$command $options" + fi + command="$command $device" + if [ -f "$__object/parameter/blocks" ]; then + blocks="$(cat "$__object/parameter/blocks")" + command="$command $blocks" + fi + echo "$command" +esac + +cat << DONE +if [ "\$__debug" != "yes" ]; then + # Restore stdout and close file descriptor #6. + exec 1>&6 6>&- +fi +DONE diff --git a/cdist/conf/type/__install_mkfs/install b/cdist/conf/type/__install_mkfs/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_mkfs/man.text b/cdist/conf/type/__install_mkfs/man.text new file mode 100644 index 00000000..3a9a325d --- /dev/null +++ b/cdist/conf/type/__install_mkfs/man.text @@ -0,0 +1,57 @@ +cdist-type__install_mkfs(7) +=========================== +Steven Armstrong + + +NAME +---- +cdist-type__install_mkfs - build a linux file system + + +DESCRIPTION +----------- +This cdist type is a wrapper for the mkfs command. + + +REQUIRED PARAMETERS +------------------- +type:: + The filesystem type to use. Same as used with mkfs -t. + + +OPTIONAL PARAMETERS +------------------- +device:: + defaults to object_id + +options:: + file system-specific options to be passed to the mkfs command + +blocks:: + the number of blocks to be used for the file system + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# reiserfs /dev/sda5 +__install_mkfs /dev/sda5 --type reiserfs +# same thing with explicit device +__install_mkfs whatever --device /dev/sda5 --type reiserfs + +# jfs with journal on /dev/sda2 +__install_mkfs /dev/sda1 --type jfs --options "-j /dev/sda2" +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- mkfs(8) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__install_mkfs/manifest b/cdist/conf/type/__install_mkfs/manifest new file mode 100755 index 00000000..e9d275a4 --- /dev/null +++ b/cdist/conf/type/__install_mkfs/manifest @@ -0,0 +1,31 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# set defaults +if [ -f "$__object/parameter/device" ]; then + device="(cat "$__object/parameter/device")" +else + device="/$__object_id" + echo "$device" > "$__object/parameter/device" +fi + +type="(cat "$__object/parameter/type")" + +options="(cat "$__object/parameter/options")" diff --git a/cdist/conf/type/__install_mkfs/parameter/optional b/cdist/conf/type/__install_mkfs/parameter/optional new file mode 100644 index 00000000..86aeae30 --- /dev/null +++ b/cdist/conf/type/__install_mkfs/parameter/optional @@ -0,0 +1,3 @@ +device +options +blocks diff --git a/cdist/conf/type/__install_mkfs/parameter/required b/cdist/conf/type/__install_mkfs/parameter/required new file mode 100644 index 00000000..aa80e646 --- /dev/null +++ b/cdist/conf/type/__install_mkfs/parameter/required @@ -0,0 +1 @@ +type diff --git a/cdist/conf/type/__install_mount/gencode-remote b/cdist/conf/type/__install_mount/gencode-remote new file mode 100755 index 00000000..0ab5c069 --- /dev/null +++ b/cdist/conf/type/__install_mount/gencode-remote @@ -0,0 +1,78 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# show command output in debug mode +cat << DONE +__debug=$__cdist_debug +if [ "\$__debug" != "yes" ]; then + # Link file descriptor #6 with stdout + exec 6>&1 + # redirect all output to /dev/null + exec > /dev/null +fi +DONE + + +get_type_from_mkfs() { + _device="$1" + for mkfs_object in $(find "$__global/object/__install_mkfs" -path "*.cdist"); do + mkfs_device="$(cat "$mkfs_object/parameter/device")" + if [ "$_device" = "$mkfs_device" ]; then + cat "$mkfs_object/parameter/type" + break + fi + done + unset _device + unset mkfs_device + unset mkfs_object +} + +device="$(cat "$__object/parameter/device")" +dir="$(cat "$__object/parameter/dir")" +prefix="$(cat "$__object/parameter/prefix")" +if [ -f "$__object/parameter/type" ]; then + type="$(cat "$__object/parameter/type")" +else + type="$(get_type_from_mkfs "$device")" + # store for later use by others + echo "$type" > "$__object/parameter/type" +fi +[ -n "$type" ] || die "Can't determine type for $__object" +if [ "$type" = "swap" ]; then + echo "swapon \"$device\"" +else + if [ -f "$__object/parameter/options" ]; then + options="$(cat "$__object/parameter/options")" + else + options="" + fi + [ -n "$options" ] && options="-o $options" + mount_point="${prefix}${dir}" + + echo "[ -d \"$mount_point\" ] || mkdir -p \"$mount_point\"" + echo "mount -t \"$type\" $options \"$device\" \"$mount_point\"" +fi + +cat << DONE +if [ "\$__debug" != "yes" ]; then + # Restore stdout and close file descriptor #6. + exec 1>&6 6>&- +fi +DONE diff --git a/cdist/conf/type/__install_mount/install b/cdist/conf/type/__install_mount/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_mount/man.text b/cdist/conf/type/__install_mount/man.text new file mode 100644 index 00000000..b55cb83e --- /dev/null +++ b/cdist/conf/type/__install_mount/man.text @@ -0,0 +1,61 @@ +cdist-type__install_mount(7) +============================ +Steven Armstrong + + +NAME +---- +cdist-type__install_mount - mount filesystems in the installer + + +DESCRIPTION +----------- +Mounts filesystems in the installer. Collects data to generate /etc/fstab. + + +REQUIRED PARAMETERS +------------------- +device:: + the device to mount + + +OPTIONAL PARAMETERS +------------------- +dir:: + where to mount device. Defaults to object_id. + +options:: + mount options passed to mount(8) and used in /etc/fstab + +type:: + filesystem type passed to mount(8) and used in /etc/fstab. + If type is swap, 'dir' is ignored. + Defaults to the filesystem used in __install_mkfs for the same 'device'. + +prefix:: + the prefix to prepend to 'dir' when mounting in the installer. + Defaults to /target. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__install_mount slash --dir / --device /dev/sda5 --options noatime +require="__install_mount/slash" __install_mount /boot --device /dev/sda1 +__install_mount swap --device /dev/sda2 --type swap +require="__install_mount/slash" __install_mount /tmp --device tmpfs --type tmpfs +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__install_mount_apply(7) +- cdist-type__install_mkfs(7) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__install_mount/manifest b/cdist/conf/type/__install_mount/manifest new file mode 100755 index 00000000..5afae7fc --- /dev/null +++ b/cdist/conf/type/__install_mount/manifest @@ -0,0 +1,29 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# set defaults +if [ ! -f "$__object/parameter/dir" ]; then + dir="/$__object_id" + echo "$dir" > "$__object/parameter/dir" +fi +if [ ! -f "$__object/parameter/prefix" ]; then + prefix="/target" + echo "$prefix" > "$__object/parameter/prefix" +fi diff --git a/cdist/conf/type/__install_mount/parameter/optional b/cdist/conf/type/__install_mount/parameter/optional new file mode 100644 index 00000000..08b6ad04 --- /dev/null +++ b/cdist/conf/type/__install_mount/parameter/optional @@ -0,0 +1,3 @@ +dir +type +options diff --git a/cdist/conf/type/__install_mount/parameter/required b/cdist/conf/type/__install_mount/parameter/required new file mode 100644 index 00000000..f89ee6a8 --- /dev/null +++ b/cdist/conf/type/__install_mount/parameter/required @@ -0,0 +1 @@ +device diff --git a/cdist/conf/type/__install_partition_msdos/install b/cdist/conf/type/__install_partition_msdos/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_partition_msdos/man.text b/cdist/conf/type/__install_partition_msdos/man.text new file mode 100644 index 00000000..8d403b67 --- /dev/null +++ b/cdist/conf/type/__install_partition_msdos/man.text @@ -0,0 +1,62 @@ +cdist-type__install_partition_msdos(7) +============================== +Steven Armstrong + + +NAME +---- +cdist-type__install_partition_msdos - creates msdos partitions + + +DESCRIPTION +----------- +This cdist type allows you to create msdos paritions. + + +REQUIRED PARAMETERS +------------------- +type:: + the partition type used in fdisk (such as 82 or 83) or "extended" + + +OPTIONAL PARAMETERS +------------------- +partition:: + defaults to object_id +bootable:: + mark partition as bootable, true or false, defaults to false +size:: + the size of the partition (such as 32M or 15G, whole numbers + only), '+' for remaining space, or 'n%' for percentage of remaining + (these should only be used after all specific partition sizes are + specified). Defaults to +. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# 128MB, linux, bootable +__install_partition_msdos /dev/sda1 --type 83 --size 128M --bootable true +# 512MB, swap +__install_partition_msdos /dev/sda2 --type 82 --size 512M +# 100GB, extended +__install_partition_msdos /dev/sda3 --type extended --size 100G +# 10GB, linux +__install_partition_msdos /dev/sda5 --type 83 --size 10G +# 50% of the free space of the extended partition, linux +__install_partition_msdos /dev/sda6 --type 83 --size 50% +# rest of the extended partition, linux +__install_partition_msdos /dev/sda7 --type 83 --size + +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__install_partition_msdos/manifest b/cdist/conf/type/__install_partition_msdos/manifest new file mode 100755 index 00000000..e55d3f24 --- /dev/null +++ b/cdist/conf/type/__install_partition_msdos/manifest @@ -0,0 +1,41 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# set defaults +if [ -f "$__object/parameter/partition" ]; then + partition="(cat "$__object/parameter/partition")" +else + partition="/$__object_id" + echo "$partition" > "$__object/parameter/partition" +fi +device="$(echo "$partition" | sed 's/[0-9]//g')" +echo "$device" > "$__object/parameter/device" +minor="$(echo "$partition" | sed 's/[^0-9]//g')" +echo "$minor" > "$__object/parameter/minor" + +if [ ! -f "$__object/parameter/bootable" ]; then + echo "false" > "$__object/parameter/bootable" +fi +if [ ! -f "$__object/parameter/size" ]; then + echo "+" > "$__object/parameter/size" +fi + +# pull in the type that actually does something with the above parameters +require="$__object_name" __install_partition_msdos_apply diff --git a/cdist/conf/type/__install_partition_msdos/parameter/optional b/cdist/conf/type/__install_partition_msdos/parameter/optional new file mode 100644 index 00000000..b2b0a4c2 --- /dev/null +++ b/cdist/conf/type/__install_partition_msdos/parameter/optional @@ -0,0 +1,3 @@ +partition +bootable +size diff --git a/cdist/conf/type/__install_partition_msdos/parameter/required b/cdist/conf/type/__install_partition_msdos/parameter/required new file mode 100644 index 00000000..aa80e646 --- /dev/null +++ b/cdist/conf/type/__install_partition_msdos/parameter/required @@ -0,0 +1 @@ +type diff --git a/cdist/conf/type/__install_partition_msdos_apply/explorer/partitions b/cdist/conf/type/__install_partition_msdos_apply/explorer/partitions new file mode 100755 index 00000000..6be61af4 --- /dev/null +++ b/cdist/conf/type/__install_partition_msdos_apply/explorer/partitions @@ -0,0 +1,3 @@ +#!/bin/sh + +cat /proc/partitions diff --git a/cdist/conf/type/__install_partition_msdos_apply/files/lib.sh b/cdist/conf/type/__install_partition_msdos_apply/files/lib.sh new file mode 100644 index 00000000..cddc575d --- /dev/null +++ b/cdist/conf/type/__install_partition_msdos_apply/files/lib.sh @@ -0,0 +1,68 @@ +die() { + echo "[__install_partition_msdos_apply] $@" >&2 + exit 1 +} +debug() { + #echo "[__install_partition_msdos_apply] $@" >&2 + : +} + +fdisk_command() { + local device="$1" + local cmd="$2" + + debug fdisk_command "running fdisk command '${cmd}' on device ${device}" + printf "${cmd}\nw\n" | fdisk -c -u "$device" + ret=$? + # give disk some time + sleep 1 + return $ret +} + +create_disklabel() { + local device=$1 + + debug create_disklabel "creating new msdos disklabel" + fdisk_command ${device} "o" + return $? +} + +toggle_bootable() { + local device="$1" + local minor="$2" + fdisk_command ${device} "a\n${minor}\n" + return $? +} + +create_partition() { + local device="$1" + local minor="$2" + local size="$3" + local type="$4" + local primary_count="$5" + + if [ "$type" = "extended" -o "$type" = "5" ]; then + # Extended partition + primary_extended="e\n" + first_minor="${minor}\n" + [ "${minor}" = "4" ] && first_minor="" + type_minor="${minor}\n" + [ "${minor}" = "1" ] && type_minor="" + type="5" + elif [ "${minor}" -lt "5" ]; then + primary_extended="p\n" + first_minor="${minor}\n" + [ "${minor}" = "4" ] && first_minor="" + type_minor="${minor}\n" + [ "${minor}" = "1" ] && type_minor="" + else + # Logical partitions + first_minor="${minor}\n" + type_minor="${minor}\n" + primary_extended="l\n" + [ "$primary_count" -gt "3" ] && primary_extended="" + fi + [ -n "${size}" ] && size="+${size}M" + fdisk_command ${device} "n\n${primary_extended}${first_minor}\n${size}\nt\n${type_minor}${type}\n" + return $? +} diff --git a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote new file mode 100755 index 00000000..c683673d --- /dev/null +++ b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote @@ -0,0 +1,175 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +die() { + echo "[__install_partition_msdos_apply] $@" >&2 + exit 1 +} +debug() { + #echo "[__install_partition_msdos_apply] $@" >&2 + : +} + +# Convert a size specifier 1G 100M or 50% into the corresponding numeric MB. +size_to_mb() { + local size=$1 + local available_size="$2" + + local number_suffix="$(echo ${size} | sed -e 's:\.[0-9]\+::' -e 's:\([0-9]\+\)\([KkMmGg%]\)[Bb]\?:\1|\2:')" + local number="$(echo ${number_suffix} | cut -d '|' -f1)" + local suffix="$(echo ${number_suffix} | cut -d '|' -f2)" + + case "$suffix" in + K|k) + size="$(( $number / 1024 ))" + ;; + M|m) + size="$number" + ;; + G|g) + size="$(( $number * 1024 ))" + ;; + %) + size="$(( $available_size * $number / 100 ))" + ;; + *) + size="-1" + esac + echo "$size" +} + +get_objects() { + objects_file=$(mktemp) + for object in $(find "$__global/object/__install_partition_msdos" -path "*.cdist"); do + object_device="$(cat "$object/parameter/device")" + object_minor="$(cat "$object/parameter/minor")" + echo "$object_device $object_minor $object" >> $objects_file + done + sort -k 1,2 $objects_file | cut -d' ' -f 3 + rm $objects_file + unset objects_file + unset object + unset object_device + unset object_minor +} + +# include function library for use on target +cat << DONE +__debug=$__cdist_debug +if [ "\$__debug" != "yes" ]; then + # Link file descriptor #6 with stdout + exec 6>&1 + # redirect all output to /dev/null + exec > /dev/null +fi +DONE +cat "$__type/files/lib.sh" + +partitions="$__object/explorer/partitions" +objects=$(get_objects) +current_device="" +available_device_size= +available_extended_size= +available_size= +primary_count=0 +for object in $objects; do + device="$(cat "$object/parameter/device")" + if [ "$current_device" != "$device" ]; then + echo "create_disklabel \"$device\" || die 'Failed to create disklabel for $device'" + current_device="$device" + device_name=$(echo ${device} | sed -e 's:^/dev/::;s:/:\\/:g') + available_device_size=$(( $(awk "/${device_name}\$/ { print \$3; }" "$partitions") / 1024)) + # make sure we don't go past the end of the drive + available_device_size=$((available_device_size - 2)) + available_extended_size=0 + primary_count=0 + debug "----- $device" + debug "current_device=$current_device" + debug "available_device_size=$available_device_size" + fi + + type="$(cat "$object/parameter/type")" + partition="$(cat "$object/parameter/partition")" + minor="$(cat "$object/parameter/minor")" + + bootable="$(cat "$object/parameter/bootable")" + size="$(cat "$object/parameter/size")" + + + if [ "${minor}" -lt "5" ]; then + # Primary partitions + primary_count=$(( $primary_count + 1 )) + available_size=$available_device_size + else + # Logical partitions + available_size=$available_extended_size + fi + + if [ "$size" = "+" ]; then + # use rest of device + partition_size="" + available_size=0 + else + partition_size=$(size_to_mb "$size" "$available_size") + available_size="$(( $available_size - $partition_size ))" + fi + + if [ "${minor}" -lt "5" ]; then + # Primary partitions + available_device_size=$available_size + if [ "$type" = "extended" -o "$type" = "5" ]; then + # Extended partition + available_extended_size=$partition_size + fi + else + # Logical paritions + available_extended_size=$available_size + fi + + [ "$partition_size" = "-1" ] && die "could not translate size '$size' to a usable value" + debug "----- $partition" + debug "primary_count=$primary_count" + debug "current_device=$current_device" + debug "device=$device" + debug "type=$type" + debug "partition=$partition" + debug "minor=$minor" + debug "bootable=$bootable" + debug "size=$size" + debug "partition_size=$partition_size" + debug "available_size=$available_size" + debug "available_device_size=$available_device_size" + debug "available_extended_size=$available_extended_size" + debug "----------" + + echo "create_partition '$device' '$minor' '$partition_size' '$type' '$primary_count' \ + || die 'Failed to create partition: $partition'" + + if [ "$bootable" = "true" ]; then + echo "toggle_bootable '$device' '$minor' || die 'Failed to toogle bootable flag for partition: $partition'" + fi +done + +cat << DONE +if [ "\$__debug" != "yes" ]; then + # Restore stdout and close file descriptor #6. + exec 1>&6 6>&- +fi +DONE diff --git a/cdist/conf/type/__install_partition_msdos_apply/install b/cdist/conf/type/__install_partition_msdos_apply/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_partition_msdos_apply/man.text b/cdist/conf/type/__install_partition_msdos_apply/man.text new file mode 100644 index 00000000..5399afb7 --- /dev/null +++ b/cdist/conf/type/__install_partition_msdos_apply/man.text @@ -0,0 +1,42 @@ +cdist-type__install_partition_msdos_apply(7) +============================================ +Steven Armstrong + + +NAME +---- +cdist-type__install_partition_msdos_apply - Apply dos partition settings + + +DESCRIPTION +----------- +Create the partitions defined with __install_partition_msdos + + +REQUIRED PARAMETERS +------------------- +None + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__install_partition_msdos_apply +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__install_partition_msdos_apply(7) + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__install_partition_msdos_apply/singleton b/cdist/conf/type/__install_partition_msdos_apply/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_reboot/gencode-remote b/cdist/conf/type/__install_reboot/gencode-remote new file mode 100755 index 00000000..4358347d --- /dev/null +++ b/cdist/conf/type/__install_reboot/gencode-remote @@ -0,0 +1,23 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +options="$(cat "$__object/parameter/options")" + +echo "reboot $options" diff --git a/cdist/conf/type/__install_reboot/install b/cdist/conf/type/__install_reboot/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_reboot/man.text b/cdist/conf/type/__install_reboot/man.text new file mode 100644 index 00000000..91aec19a --- /dev/null +++ b/cdist/conf/type/__install_reboot/man.text @@ -0,0 +1,43 @@ +cdist-type__install_reboot(7) +============================= +Steven Armstrong + + +NAME +---- +cdist-type__install_reboot - run reboot + + +DESCRIPTION +----------- +This cdist type allows you to reboot a machine. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +options:: + options to pass to the reboot command. e.g. -f + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__install_reboot +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__install_reboot/manifest b/cdist/conf/type/__install_reboot/manifest new file mode 100755 index 00000000..fab80a1e --- /dev/null +++ b/cdist/conf/type/__install_reboot/manifest @@ -0,0 +1,23 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# set defaults +options="$(cat "$__object/parameter/options" 2>/dev/null \ + || echo "" | tee "$__object/parameter/options")" diff --git a/cdist/conf/type/__install_reboot/singleton b/cdist/conf/type/__install_reboot/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_reset_disk/gencode-remote b/cdist/conf/type/__install_reset_disk/gencode-remote new file mode 100755 index 00000000..e9278a7e --- /dev/null +++ b/cdist/conf/type/__install_reset_disk/gencode-remote @@ -0,0 +1,65 @@ +#!/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 . +# + +disk="/$__object_id" +disk_name="${disk##*/}" + +cat << DONE +# stop mdadm raids if any +if [ -r /proc/mdstat ]; then + md_name="\$(awk "/$disk_name/ {print \$1}" /proc/mdstat)" + if [ -n "\$md_name" ]; then + if command -v mdadm >/dev/null; then + mdadm --stop "/dev/\$md_name" + else + echo "WARNING: mdadm command not found" >&2 + echo "WARNING: could not stop active mdadm raid for disk $disk" >&2 + fi + fi +fi + +# stop lvm's if any +if find /sys/class/block/$disk_name*/holders/ -mindepth 1 | grep -q holders/dm; then + if command -v vgchange >/dev/null; then + vgchange -a n + else + echo "WARNING: vgchange command not found" >&2 + fi +fi + +# clean disks from any legacy signatures +if command -v wipefs >/dev/null; then + wipefs -a "$disk" || true +fi +if command -v mdadm >/dev/null; then + mdadm --zero-superblock --force "$disk" || true +else + echo "WARNING: mdadm command not found" >&2 +fi +if command -v pvremove >/dev/null; then + pvremove --force --force --yes "$disk" || true +else + echo "WARNING: pvremove command not found" >&2 +fi + +# erase partition table +dd if=/dev/zero of=$disk bs=512 count=1 +printf 'w\n' | fdisk -u -c $disk || true +DONE diff --git a/cdist/conf/type/__install_reset_disk/install b/cdist/conf/type/__install_reset_disk/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_reset_disk/man.text b/cdist/conf/type/__install_reset_disk/man.text new file mode 100644 index 00000000..542d68ba --- /dev/null +++ b/cdist/conf/type/__install_reset_disk/man.text @@ -0,0 +1,43 @@ +cdist-type__install_reset_disk(7) +================================= +Steven Armstrong + + +NAME +---- +cdist-type__install_reset_disk - reset a disk + + +DESCRIPTION +----------- +Remove partition table. +Remove all lvm labels. +Remove mdadm superblock. + + +REQUIRED PARAMETERS +------------------- +None. + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__install_reset_disk /dev/sdb +-------------------------------------------------------------------------------- + + +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/__install_stage/gencode-remote b/cdist/conf/type/__install_stage/gencode-remote new file mode 100755 index 00000000..17eeda0d --- /dev/null +++ b/cdist/conf/type/__install_stage/gencode-remote @@ -0,0 +1,65 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# show command output in debug mode +cat << DONE +__debug=$__cdist_debug +if [ "\$__debug" != "yes" ]; then + # Link file descriptor #6 with stdout + exec 6>&1 + # redirect all output to /dev/null + exec > /dev/null +fi +DONE + +uri="$(cat "$__object/parameter/uri")" +target="$(cat "$__object/parameter/target")" +post_install="$(cat "$__object/parameter/post_install" 2>/dev/null || true)" + + +[ "$__debug" = "yes" ] && curl="curl" || curl="curl -s" +[ "$__debug" = "yes" ] && tar="tar -xvzp" || tar="tar -xzp" + +echo "$curl '$uri' | $tar -C '$target'" +if [ -n "$post_install" ]; then + post_install_script="$(cat "$__object/parameter/post_install_script")" + cat << DONE +[ -d "${target}/proc" ] || mkdir "${target}/proc" +mount -t proc none "${target}/proc" +[ -d "${target}/sys" ] || mkdir "${target}/sys" +mount -t sysfs none "${target}/sys" +[ -d "${target}/dev" ] || mkdir "${target}/dev" +mount --rbind /dev "${target}/dev" +[ -d "${target}/tmp" ] || mkdir -m 1777 "${target}/tmp" +mount -t tmpfs none "${target}/tmp" +cp "$post_install_script" "${target}/tmp/post_install" +chmod +x "${target}/tmp/post_install" +cp /etc/resolv.conf "${target}/etc/" +chroot "$target" /tmp/post_install +umount -l "${target}/tmp" "${target}/dev" "${target}/sys" "${target}/proc" +DONE +fi + +cat << DONE +if [ "\$__debug" != "yes" ]; then + # Restore stdout and close file descriptor #6. + exec 1>&6 6>&- +fi +DONE diff --git a/cdist/conf/type/__install_stage/install b/cdist/conf/type/__install_stage/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_stage/man.text b/cdist/conf/type/__install_stage/man.text new file mode 100644 index 00000000..0e657fdc --- /dev/null +++ b/cdist/conf/type/__install_stage/man.text @@ -0,0 +1,58 @@ +cdist-type__install_stage(7) +============================ +Steven Armstrong + + +NAME +---- +cdist-type__install_stage - download and unpack a stage file + + +DESCRIPTION +----------- +Downloads a operating system stage using curl and unpacks it to /target +using tar. The stage tarball is expected to be gzip compressed. + + +REQUIRED PARAMETERS +------------------- +uri:: + The uri from which to fetch the tarball. + Can be anything understood by curl, e.g: + http://path/to/stage.tgz + tftp:///path/to/stage.tgz + file:///local/path/stage.tgz + + +OPTIONAL PARAMETERS +------------------- +target:: + where to unpack the tarball to. Defaults to /target. + +post_install:: + path to an optional local script. The script is uploaded to the target and + executed inside (chroot) the target after the stage has been unpacked. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__install_stage --uri tftp:///path/to/stage.tgz +__install_stage --uri http://path/to/stage.tgz --target /mnt/foobar +__install_stage --uri file:///path/to/stage.tgz --target /target +__install_stage --uri file:///path/to/stage.tgz \ + --target /target \ + --post_install /path/to/file/on/server +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__install_stage/manifest b/cdist/conf/type/__install_stage/manifest new file mode 100755 index 00000000..ab5f4d79 --- /dev/null +++ b/cdist/conf/type/__install_stage/manifest @@ -0,0 +1,33 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# set defaults +uri="$(cat "$__object/parameter/uri" 2>/dev/null \ + || echo "$__object_id" | tee "$__object/parameter/uri")" +target="$(cat "$__object/parameter/target" 2>/dev/null \ + || echo "/target" | tee "$__object/parameter/target")" + +if [ -f "$__object/parameter/post_install" ]; then + post_install="$(cat "$__object/parameter/post_install")" + post_install_script="/tmp/post_install" + __install_file $post_install_script --source $post_install + echo "$post_install_script" > "$__object/parameter/post_install_script" +fi + diff --git a/cdist/conf/type/__install_stage/parameter/optional b/cdist/conf/type/__install_stage/parameter/optional new file mode 100644 index 00000000..8e1a11b5 --- /dev/null +++ b/cdist/conf/type/__install_stage/parameter/optional @@ -0,0 +1,2 @@ +target +post_install diff --git a/cdist/conf/type/__install_stage/parameter/required b/cdist/conf/type/__install_stage/parameter/required new file mode 100644 index 00000000..c7954952 --- /dev/null +++ b/cdist/conf/type/__install_stage/parameter/required @@ -0,0 +1 @@ +uri diff --git a/cdist/conf/type/__install_stage/singleton b/cdist/conf/type/__install_stage/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_umount/gencode-remote b/cdist/conf/type/__install_umount/gencode-remote new file mode 100755 index 00000000..c275fe5d --- /dev/null +++ b/cdist/conf/type/__install_umount/gencode-remote @@ -0,0 +1,25 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +target="$(cat "$__object/parameter/target")" + +echo "swapoff -a" +echo "umount -l ${target}/* || true" +echo "umount -l ${target}" diff --git a/cdist/conf/type/__install_umount/install b/cdist/conf/type/__install_umount/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_umount/man.text b/cdist/conf/type/__install_umount/man.text new file mode 100644 index 00000000..8d9d1f55 --- /dev/null +++ b/cdist/conf/type/__install_umount/man.text @@ -0,0 +1,43 @@ +cdist-type__install_umount(7) +============================= +Steven Armstrong + + +NAME +---- +cdist-type__install_umount - umount target directory + + +DESCRIPTION +----------- +This cdist type allows you to recursively umount the given target directory. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +target:: + the mount point to umount. Defaults to object_id + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__install_umount /target +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__install_umount/manifest b/cdist/conf/type/__install_umount/manifest new file mode 100755 index 00000000..c547e167 --- /dev/null +++ b/cdist/conf/type/__install_umount/manifest @@ -0,0 +1,23 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# set defaults +target="$(cat "$__object/parameter/target" 2>/dev/null \ + || echo "/target" | tee "$__object/parameter/target")" From f5aad522cc7328243c8338f29602838d789b094d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 29 Aug 2013 23:28:15 +0200 Subject: [PATCH 2392/4212] dont add help to 2 parsers Signed-off-by: Steven Armstrong --- scripts/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/cdist b/scripts/cdist index 31bd7373..dfdef691 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -92,7 +92,7 @@ def commandline(): parser['shell'].set_defaults(func=cdist.shell.Shell.commandline) # Install - parser['install'] = parser['sub'].add_parser('install', + parser['install'] = parser['sub'].add_parser('install', add_help=False, parents=[parser['loglevel'], parser['config']]) parser['install'].set_defaults(func=cdist.install.Install.commandline) From 82612bc312eb8c367fdac4d46f88306beee87429 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 29 Aug 2013 23:29:54 +0200 Subject: [PATCH 2393/4212] config already inherits from loglevel parser Signed-off-by: Steven Armstrong --- scripts/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/cdist b/scripts/cdist index dfdef691..24a955ae 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -93,7 +93,7 @@ def commandline(): # Install parser['install'] = parser['sub'].add_parser('install', add_help=False, - parents=[parser['loglevel'], parser['config']]) + parents=[parser['config']]) parser['install'].set_defaults(func=cdist.install.Install.commandline) for p in parser: From 4ace4348a7386d3750eaf6ed67873a48f11f4fc4 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 30 Aug 2013 12:56:12 +0200 Subject: [PATCH 2394/4212] filter out install objects when running config Signed-off-by: Steven Armstrong --- cdist/config.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cdist/config.py b/cdist/config.py index 59cf339a..988695ed 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -162,7 +162,10 @@ 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): """ From a9109c94a480ef74937ac6680aa86f2682a17b4c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 6 Sep 2013 12:22:57 +0200 Subject: [PATCH 2395/4212] add missing types from private repo Signed-off-by: Steven Armstrong --- cdist/conf/type/__chroot_mount/gencode-remote | 36 ++++++++++++++++ cdist/conf/type/__chroot_mount/man.text | 42 +++++++++++++++++++ .../conf/type/__chroot_umount/gencode-remote | 33 +++++++++++++++ cdist/conf/type/__chroot_umount/man.text | 42 +++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100755 cdist/conf/type/__chroot_mount/gencode-remote create mode 100644 cdist/conf/type/__chroot_mount/man.text create mode 100755 cdist/conf/type/__chroot_umount/gencode-remote create mode 100644 cdist/conf/type/__chroot_umount/man.text diff --git a/cdist/conf/type/__chroot_mount/gencode-remote b/cdist/conf/type/__chroot_mount/gencode-remote new file mode 100755 index 00000000..ec0b83ae --- /dev/null +++ b/cdist/conf/type/__chroot_mount/gencode-remote @@ -0,0 +1,36 @@ +#!/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 . +# + +chroot="/$__object_id" + +cat << DONE +# Prepare chroot +[ -d "${chroot}/proc" ] || mkdir "${chroot}/proc" +mount -t proc none "${chroot}/proc" +[ -d "${chroot}/sys" ] || mkdir "${chroot}/sys" +mount -t sysfs none "${chroot}/sys" +[ -d "${chroot}/dev" ] || mkdir "${chroot}/dev" +mount --rbind /dev "${chroot}/dev" +[ -d "${chroot}/tmp" ] || mkdir -m 1777 "${chroot}/tmp" +mount -t tmpfs none "${chroot}/tmp" +if [ ! -f "${chroot}/etc/resolv.conf" ]; then + cp /etc/resolv.conf "${chroot}/etc/" +fi +DONE diff --git a/cdist/conf/type/__chroot_mount/man.text b/cdist/conf/type/__chroot_mount/man.text new file mode 100644 index 00000000..adce80d9 --- /dev/null +++ b/cdist/conf/type/__chroot_mount/man.text @@ -0,0 +1,42 @@ +cdist-type__install_chroot_mount(7) +=================================== +Steven Armstrong + + +NAME +---- +cdist-type__install_chroot_mount - mount a chroot + + +DESCRIPTION +----------- +Mount and prepare a chroot for running commands within it. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__install_chroot_mount /path/to/chroot +-------------------------------------------------------------------------------- + + +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/__chroot_umount/gencode-remote b/cdist/conf/type/__chroot_umount/gencode-remote new file mode 100755 index 00000000..aad9ac76 --- /dev/null +++ b/cdist/conf/type/__chroot_umount/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 . +# + +chroot="/$__object_id" + +cat << DONE +umount -l "${chroot}/tmp" +umount -l "${chroot}/dev" +umount -l "${chroot}/sys" +umount -l "${chroot}/proc" +rm -f "${chroot}/etc/resolv.conf" +# ensure /etc/resolvconf/resolv.conf.d/tail is not linked to \ +# e.g. /etc/resolvconf/resolv.conf.d/original +rm -f "${chroot}/etc/resolvconf/resolv.conf.d/tail" +touch "${chroot}/etc/resolvconf/resolv.conf.d/tail" +DONE diff --git a/cdist/conf/type/__chroot_umount/man.text b/cdist/conf/type/__chroot_umount/man.text new file mode 100644 index 00000000..a5ca1ef0 --- /dev/null +++ b/cdist/conf/type/__chroot_umount/man.text @@ -0,0 +1,42 @@ +cdist-type__install_chroot_umount(7) +==================================== +Steven Armstrong + + +NAME +---- +cdist-type__install_chroot_umount - unmount a chroot mounted by __chroot_mount + + +DESCRIPTION +----------- +Undo what __chroot_mount did. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__install_chroot_umount /path/to/chroot +-------------------------------------------------------------------------------- + + +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). From a035b52a0dfd88b0383e22edcfc9f0c42d8129b2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 14 Sep 2013 21:55:51 +0200 Subject: [PATCH 2396/4212] better mounting of virtual filesystems in chroot Signed-off-by: Steven Armstrong --- cdist/conf/type/__chroot_mount/gencode-remote | 20 +++++++++++++++---- .../conf/type/__chroot_umount/gencode-remote | 11 ++++++---- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/cdist/conf/type/__chroot_mount/gencode-remote b/cdist/conf/type/__chroot_mount/gencode-remote index ec0b83ae..6d855f41 100755 --- a/cdist/conf/type/__chroot_mount/gencode-remote +++ b/cdist/conf/type/__chroot_mount/gencode-remote @@ -23,13 +23,25 @@ chroot="/$__object_id" cat << DONE # Prepare chroot [ -d "${chroot}/proc" ] || mkdir "${chroot}/proc" -mount -t proc none "${chroot}/proc" +mountpoint -q "${chroot}/proc" \ + || mount -t proc -o nosuid,noexec,nodev proc "${chroot}/proc" + [ -d "${chroot}/sys" ] || mkdir "${chroot}/sys" -mount -t sysfs none "${chroot}/sys" +mountpoint -q "${chroot}/sys" \ + || mount -t sysfs -o nosuid,noexec,nodev sys "${chroot}/sys" + [ -d "${chroot}/dev" ] || mkdir "${chroot}/dev" -mount --rbind /dev "${chroot}/dev" +mountpoint -q "${chroot}/dev" \ + || mount -t devtmpfs -o mode=0755,nosuid udev "${chroot}/dev" + +[ -d "${chroot}/dev/pts" ] || mkdir "${chroot}/dev/pts" +mountpoint -q "${chroot}/dev/pts" \ + || mount -t devpts -o mode=0620,gid=5,nosuid,noexec devpts "${chroot}/dev/pts" + [ -d "${chroot}/tmp" ] || mkdir -m 1777 "${chroot}/tmp" -mount -t tmpfs none "${chroot}/tmp" +mountpoint -q "${chroot}/tmp" \ + || mount -t tmpfs -o mode=1777,strictatime,nodev,nosuid tmpfs "${chroot}/tmp" + if [ ! -f "${chroot}/etc/resolv.conf" ]; then cp /etc/resolv.conf "${chroot}/etc/" fi diff --git a/cdist/conf/type/__chroot_umount/gencode-remote b/cdist/conf/type/__chroot_umount/gencode-remote index aad9ac76..caf2c40c 100755 --- a/cdist/conf/type/__chroot_umount/gencode-remote +++ b/cdist/conf/type/__chroot_umount/gencode-remote @@ -22,12 +22,15 @@ chroot="/$__object_id" cat << DONE umount -l "${chroot}/tmp" +umount -l "${chroot}/dev/pts" umount -l "${chroot}/dev" umount -l "${chroot}/sys" umount -l "${chroot}/proc" rm -f "${chroot}/etc/resolv.conf" -# ensure /etc/resolvconf/resolv.conf.d/tail is not linked to \ -# e.g. /etc/resolvconf/resolv.conf.d/original -rm -f "${chroot}/etc/resolvconf/resolv.conf.d/tail" -touch "${chroot}/etc/resolvconf/resolv.conf.d/tail" +if [ -d "${chroot}/etc/resolvconf/resolv.conf.d" ]; then + # ensure /etc/resolvconf/resolv.conf.d/tail is not linked to \ + # e.g. /etc/resolvconf/resolv.conf.d/original + rm -f "${chroot}/etc/resolvconf/resolv.conf.d/tail" + touch "${chroot}/etc/resolvconf/resolv.conf.d/tail" +fi DONE From f67cdc8afa0f898986ddd628dccbf0255f0b9a85 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 17 Sep 2013 21:35:00 +0200 Subject: [PATCH 2397/4212] cleanup, remove unused/useless post_install parameter Signed-off-by: Steven Armstrong --- .../conf/type/__install_stage/gencode-remote | 24 ++------------ cdist/conf/type/__install_stage/man.text | 7 ---- cdist/conf/type/__install_stage/manifest | 33 ------------------- .../__install_stage/parameter/default/target | 1 + .../type/__install_stage/parameter/optional | 1 - 5 files changed, 4 insertions(+), 62 deletions(-) delete mode 100755 cdist/conf/type/__install_stage/manifest create mode 100644 cdist/conf/type/__install_stage/parameter/default/target diff --git a/cdist/conf/type/__install_stage/gencode-remote b/cdist/conf/type/__install_stage/gencode-remote index 17eeda0d..12b9f1ed 100755 --- a/cdist/conf/type/__install_stage/gencode-remote +++ b/cdist/conf/type/__install_stage/gencode-remote @@ -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. # @@ -29,33 +29,15 @@ if [ "\$__debug" != "yes" ]; then fi DONE -uri="$(cat "$__object/parameter/uri")" +uri="$(cat "$__object/parameter/uri" 2>/dev/null \ + || echo "$__object_id")" target="$(cat "$__object/parameter/target")" -post_install="$(cat "$__object/parameter/post_install" 2>/dev/null || true)" [ "$__debug" = "yes" ] && curl="curl" || curl="curl -s" [ "$__debug" = "yes" ] && tar="tar -xvzp" || tar="tar -xzp" echo "$curl '$uri' | $tar -C '$target'" -if [ -n "$post_install" ]; then - post_install_script="$(cat "$__object/parameter/post_install_script")" - cat << DONE -[ -d "${target}/proc" ] || mkdir "${target}/proc" -mount -t proc none "${target}/proc" -[ -d "${target}/sys" ] || mkdir "${target}/sys" -mount -t sysfs none "${target}/sys" -[ -d "${target}/dev" ] || mkdir "${target}/dev" -mount --rbind /dev "${target}/dev" -[ -d "${target}/tmp" ] || mkdir -m 1777 "${target}/tmp" -mount -t tmpfs none "${target}/tmp" -cp "$post_install_script" "${target}/tmp/post_install" -chmod +x "${target}/tmp/post_install" -cp /etc/resolv.conf "${target}/etc/" -chroot "$target" /tmp/post_install -umount -l "${target}/tmp" "${target}/dev" "${target}/sys" "${target}/proc" -DONE -fi cat << DONE if [ "\$__debug" != "yes" ]; then diff --git a/cdist/conf/type/__install_stage/man.text b/cdist/conf/type/__install_stage/man.text index 0e657fdc..7abc77e8 100644 --- a/cdist/conf/type/__install_stage/man.text +++ b/cdist/conf/type/__install_stage/man.text @@ -29,10 +29,6 @@ OPTIONAL PARAMETERS target:: where to unpack the tarball to. Defaults to /target. -post_install:: - path to an optional local script. The script is uploaded to the target and - executed inside (chroot) the target after the stage has been unpacked. - EXAMPLES -------- @@ -41,9 +37,6 @@ EXAMPLES __install_stage --uri tftp:///path/to/stage.tgz __install_stage --uri http://path/to/stage.tgz --target /mnt/foobar __install_stage --uri file:///path/to/stage.tgz --target /target -__install_stage --uri file:///path/to/stage.tgz \ - --target /target \ - --post_install /path/to/file/on/server -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__install_stage/manifest b/cdist/conf/type/__install_stage/manifest deleted file mode 100755 index ab5f4d79..00000000 --- a/cdist/conf/type/__install_stage/manifest +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh -# -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# - -# set defaults -uri="$(cat "$__object/parameter/uri" 2>/dev/null \ - || echo "$__object_id" | tee "$__object/parameter/uri")" -target="$(cat "$__object/parameter/target" 2>/dev/null \ - || echo "/target" | tee "$__object/parameter/target")" - -if [ -f "$__object/parameter/post_install" ]; then - post_install="$(cat "$__object/parameter/post_install")" - post_install_script="/tmp/post_install" - __install_file $post_install_script --source $post_install - echo "$post_install_script" > "$__object/parameter/post_install_script" -fi - diff --git a/cdist/conf/type/__install_stage/parameter/default/target b/cdist/conf/type/__install_stage/parameter/default/target new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/cdist/conf/type/__install_stage/parameter/default/target @@ -0,0 +1 @@ +/target diff --git a/cdist/conf/type/__install_stage/parameter/optional b/cdist/conf/type/__install_stage/parameter/optional index 8e1a11b5..eb5a316c 100644 --- a/cdist/conf/type/__install_stage/parameter/optional +++ b/cdist/conf/type/__install_stage/parameter/optional @@ -1,2 +1 @@ target -post_install From bfae291cf797da1bb9ce653398aea826bc2f3535 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 17 Sep 2013 22:41:10 +0200 Subject: [PATCH 2398/4212] remove pseudo debug output redirection Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_mkfs/gencode-remote | 20 +----------------- .../conf/type/__install_mount/gencode-remote | 21 +------------------ .../gencode-remote | 18 +--------------- .../conf/type/__install_stage/gencode-remote | 18 ---------------- 4 files changed, 3 insertions(+), 74 deletions(-) diff --git a/cdist/conf/type/__install_mkfs/gencode-remote b/cdist/conf/type/__install_mkfs/gencode-remote index 6a71b8ed..2fe680e5 100755 --- a/cdist/conf/type/__install_mkfs/gencode-remote +++ b/cdist/conf/type/__install_mkfs/gencode-remote @@ -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,17 +21,6 @@ device="$(cat "$__object/parameter/device")" type="$(cat "$__object/parameter/type")" -# show command output in debug mode -cat << DONE -__debug=$__cdist_debug -if [ "\$__debug" != "yes" ]; then - # Link file descriptor #6 with stdout - exec 6>&1 - # redirect all output to /dev/null - exec > /dev/null -fi -DONE - case "$type" in swap) echo "mkswap $device" @@ -62,10 +51,3 @@ case "$type" in fi echo "$command" esac - -cat << DONE -if [ "\$__debug" != "yes" ]; then - # Restore stdout and close file descriptor #6. - exec 1>&6 6>&- -fi -DONE diff --git a/cdist/conf/type/__install_mount/gencode-remote b/cdist/conf/type/__install_mount/gencode-remote index 0ab5c069..3a35c139 100755 --- a/cdist/conf/type/__install_mount/gencode-remote +++ b/cdist/conf/type/__install_mount/gencode-remote @@ -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. # @@ -18,18 +18,6 @@ # along with cdist. If not, see . # -# show command output in debug mode -cat << DONE -__debug=$__cdist_debug -if [ "\$__debug" != "yes" ]; then - # Link file descriptor #6 with stdout - exec 6>&1 - # redirect all output to /dev/null - exec > /dev/null -fi -DONE - - get_type_from_mkfs() { _device="$1" for mkfs_object in $(find "$__global/object/__install_mkfs" -path "*.cdist"); do @@ -69,10 +57,3 @@ else echo "[ -d \"$mount_point\" ] || mkdir -p \"$mount_point\"" echo "mount -t \"$type\" $options \"$device\" \"$mount_point\"" fi - -cat << DONE -if [ "\$__debug" != "yes" ]; then - # Restore stdout and close file descriptor #6. - exec 1>&6 6>&- -fi -DONE diff --git a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote index c683673d..a1547296 100755 --- a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote +++ b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote @@ -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. # @@ -71,15 +71,6 @@ get_objects() { } # include function library for use on target -cat << DONE -__debug=$__cdist_debug -if [ "\$__debug" != "yes" ]; then - # Link file descriptor #6 with stdout - exec 6>&1 - # redirect all output to /dev/null - exec > /dev/null -fi -DONE cat "$__type/files/lib.sh" partitions="$__object/explorer/partitions" @@ -166,10 +157,3 @@ for object in $objects; do echo "toggle_bootable '$device' '$minor' || die 'Failed to toogle bootable flag for partition: $partition'" fi done - -cat << DONE -if [ "\$__debug" != "yes" ]; then - # Restore stdout and close file descriptor #6. - exec 1>&6 6>&- -fi -DONE diff --git a/cdist/conf/type/__install_stage/gencode-remote b/cdist/conf/type/__install_stage/gencode-remote index 12b9f1ed..bbc27679 100755 --- a/cdist/conf/type/__install_stage/gencode-remote +++ b/cdist/conf/type/__install_stage/gencode-remote @@ -18,17 +18,6 @@ # along with cdist. If not, see . # -# show command output in debug mode -cat << DONE -__debug=$__cdist_debug -if [ "\$__debug" != "yes" ]; then - # Link file descriptor #6 with stdout - exec 6>&1 - # redirect all output to /dev/null - exec > /dev/null -fi -DONE - uri="$(cat "$__object/parameter/uri" 2>/dev/null \ || echo "$__object_id")" target="$(cat "$__object/parameter/target")" @@ -38,10 +27,3 @@ target="$(cat "$__object/parameter/target")" [ "$__debug" = "yes" ] && tar="tar -xvzp" || tar="tar -xzp" echo "$curl '$uri' | $tar -C '$target'" - -cat << DONE -if [ "\$__debug" != "yes" ]; then - # Restore stdout and close file descriptor #6. - exec 1>&6 6>&- -fi -DONE From 2f70a0d70e5c4aae07bf93d61752e34df4f2c2eb Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 17 Sep 2013 23:33:30 +0200 Subject: [PATCH 2399/4212] need a way to set remote.base_path from the command line Signed-off-by: Steven Armstrong --- cdist/config.py | 3 ++- cdist/exec/remote.py | 7 ++----- scripts/cdist | 2 ++ 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 988695ed..dcaac740 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -124,7 +124,8 @@ class Config(object): remote = cdist.exec.remote.Remote( target_host=host, remote_exec=args.remote_exec, - remote_copy=args.remote_copy) + remote_copy=args.remote_copy, + base_path=args.remote_out_path) c = cls(local, remote, dry_run=args.dry_run) c.run() diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 7c807092..3ffda12f 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -48,15 +48,12 @@ class Remote(object): target_host, remote_exec, remote_copy, - base_path=None): + base_path="/var/lib/cdist"): self.target_host = target_host self._exec = remote_exec self._copy = remote_copy - if base_path: - self.base_path = base_path - else: - self.base_path = "/var/lib/cdist" + self.base_path = base_path self.conf_path = os.path.join(self.base_path, "conf") self.object_path = os.path.join(self.base_path, "object") diff --git a/scripts/cdist b/scripts/cdist index 24a955ae..7bd58e58 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -68,6 +68,8 @@ def commandline(): help='Do not execute code', action='store_true') parser['config'].add_argument('-o', '--out-dir', help='Directory to save cdist output in', dest="out_path") + parser['config'].add_argument('-r', '--remote-out-dir', + help='Directory to save cdist output in on the target host', dest="remote_out_path") parser['config'].add_argument('-p', '--parallel', help='Operate on multiple hosts in parallel', action='store_true', dest='parallel') From fc988a5c228e0f778aa04840b18c8f2ea8bdddd7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 17 Sep 2013 23:48:45 +0200 Subject: [PATCH 2400/4212] oh my, never mind Signed-off-by: Steven Armstrong --- cdist/exec/remote.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 3ffda12f..7c807092 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -48,12 +48,15 @@ class Remote(object): target_host, remote_exec, remote_copy, - base_path="/var/lib/cdist"): + base_path=None): self.target_host = target_host self._exec = remote_exec self._copy = remote_copy - self.base_path = base_path + 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") From a2318983970e580492f1940d39dd7e3ab3548316 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 15 Oct 2013 22:29:58 +0200 Subject: [PATCH 2401/4212] get rid of unnecessary tmp files Signed-off-by: Steven Armstrong --- .../type/__install_config/files/remote/exec | 37 +++---------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/cdist/conf/type/__install_config/files/remote/exec b/cdist/conf/type/__install_config/files/remote/exec index 4822bcf3..58e6b162 100755 --- a/cdist/conf/type/__install_config/files/remote/exec +++ b/cdist/conf/type/__install_config/files/remote/exec @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -35,39 +35,14 @@ target_host="$__target_host" shift ssh="ssh -o User=root -q $target_host" -scp="scp -o User=root -q" +code="$ssh chroot $chroot sh -c '$@'" -local_script=$(mktemp "/tmp/chroot-${0##*/}.XXXXXXXXXX") -remote_script=$($ssh mktemp "${chroot}/tmp/chroot-${0##*/}.XXXXXXXXXX") -relative_script="${remote_script#$chroot}" -trap cleanup INT TERM EXIT -cleanup() { - [ $__cdist_debug ] || { - rm "$local_script" - $ssh "rm $remote_script"; - } -} - -log "chroot: $chroot" log "target_host: $target_host" -log "local_script: $local_script" -log "remote_script: $remote_script" -log "relative_script: $relative_script" +log "chroot: $chroot" log "@: $@" -cat > "$local_script" << DONE -#!/bin/sh -l -# FIXME: fix the dependency bug, then test if the below is required or not -#if [ -f /etc/environment ]; then -# . /etc/environment -#fi -$@ -DONE +log "code: $code" -# Upload script to target -$scp $local_script $target_host:$remote_script -$ssh "chmod +x $remote_script" - -# run in chroot -$ssh "chroot $chroot $relative_script" +# Run the code +$code log "-----" From f9cac131c9c4e125b85cc6b152839bb97b461383 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 10 Dec 2013 11:13:25 +0100 Subject: [PATCH 2402/4212] add parameter to run curl in insecure mode: thanks Thorsten! Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_stage/gencode-remote | 5 ++++- cdist/conf/type/__install_stage/man.text | 9 ++++++++- cdist/conf/type/__install_stage/parameter/boolean | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 cdist/conf/type/__install_stage/parameter/boolean diff --git a/cdist/conf/type/__install_stage/gencode-remote b/cdist/conf/type/__install_stage/gencode-remote index bbc27679..3b83ea61 100755 --- a/cdist/conf/type/__install_stage/gencode-remote +++ b/cdist/conf/type/__install_stage/gencode-remote @@ -22,8 +22,11 @@ uri="$(cat "$__object/parameter/uri" 2>/dev/null \ || echo "$__object_id")" target="$(cat "$__object/parameter/target")" - [ "$__debug" = "yes" ] && curl="curl" || curl="curl -s" [ "$__debug" = "yes" ] && tar="tar -xvzp" || tar="tar -xzp" +if [ -f "$__object/parameter/insecure" ] ; then + curl="$curl -k" +fi + echo "$curl '$uri' | $tar -C '$target'" diff --git a/cdist/conf/type/__install_stage/man.text b/cdist/conf/type/__install_stage/man.text index 7abc77e8..289c8621 100644 --- a/cdist/conf/type/__install_stage/man.text +++ b/cdist/conf/type/__install_stage/man.text @@ -30,6 +30,12 @@ target:: where to unpack the tarball to. Defaults to /target. +BOOLEAN PARAMETERS +------------------ +insecure:: + run curl in insecure mode so it does not check the servers ssl certificate + + EXAMPLES -------- @@ -37,6 +43,7 @@ EXAMPLES __install_stage --uri tftp:///path/to/stage.tgz __install_stage --uri http://path/to/stage.tgz --target /mnt/foobar __install_stage --uri file:///path/to/stage.tgz --target /target +__install_stage --uri https://path/to/stage.tgz --target /mnt/foobar --insecure -------------------------------------------------------------------------------- @@ -47,5 +54,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/__install_stage/parameter/boolean b/cdist/conf/type/__install_stage/parameter/boolean new file mode 100644 index 00000000..e86bf3fc --- /dev/null +++ b/cdist/conf/type/__install_stage/parameter/boolean @@ -0,0 +1 @@ +insecure From be8df7999be8c45206004e024eb8621ab32e0b52 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 17 Dec 2013 14:56:20 +0100 Subject: [PATCH 2403/4212] first stop lvm, then mdadm Signed-off-by: Steven Armstrong --- .../type/__install_reset_disk/gencode-remote | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/cdist/conf/type/__install_reset_disk/gencode-remote b/cdist/conf/type/__install_reset_disk/gencode-remote index e9278a7e..e8e9cf8c 100755 --- a/cdist/conf/type/__install_reset_disk/gencode-remote +++ b/cdist/conf/type/__install_reset_disk/gencode-remote @@ -22,6 +22,15 @@ disk="/$__object_id" disk_name="${disk##*/}" cat << DONE +# stop lvm's if any +if find /sys/class/block/$disk_name*/holders/ -mindepth 1 | grep -q holders/dm; then + if command -v vgchange >/dev/null; then + vgchange -a n + else + echo "WARNING: vgchange command not found" >&2 + fi +fi + # stop mdadm raids if any if [ -r /proc/mdstat ]; then md_name="\$(awk "/$disk_name/ {print \$1}" /proc/mdstat)" @@ -35,28 +44,19 @@ if [ -r /proc/mdstat ]; then fi fi -# stop lvm's if any -if find /sys/class/block/$disk_name*/holders/ -mindepth 1 | grep -q holders/dm; then - if command -v vgchange >/dev/null; then - vgchange -a n - else - echo "WARNING: vgchange command not found" >&2 - fi -fi - -# clean disks from any legacy signatures -if command -v wipefs >/dev/null; then - wipefs -a "$disk" || true +if command -v pvremove >/dev/null; then + pvremove --force --force --yes "$disk" || true +else + echo "WARNING: pvremove command not found" >&2 fi if command -v mdadm >/dev/null; then mdadm --zero-superblock --force "$disk" || true else echo "WARNING: mdadm command not found" >&2 fi -if command -v pvremove >/dev/null; then - pvremove --force --force --yes "$disk" || true -else - echo "WARNING: pvremove command not found" >&2 +# clean disks from any legacy signatures +if command -v wipefs >/dev/null; then + wipefs -a "$disk" || true fi # erase partition table From 095c5335c69a732bc54879a6a42e7162c59311bc Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 16 Jan 2014 11:05:29 +0100 Subject: [PATCH 2404/4212] 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 2405/4212] 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 2406/4212] 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 2407/4212] 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 2408/4212] 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 4ca13d59a66e49a90148166f8b623772615a7a5f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jan 2014 10:40:42 +0100 Subject: [PATCH 2409/4212] comment out __apt_noautostart for the moment Signed-off-by: Nico Schottelius --- .../conf/type/__install_config/gencode-local | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index da87a4ac..674dec25 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -26,13 +26,13 @@ cdist_args="-v" [ "$__debug" = "yes" ] && cdist_args="$cdist_args -d" cat << DONE -echo "__apt_noautostart --state present" \ - | cdist $cdist_args \ - config \ - --initial-manifest - \ - --remote-exec="$remote_exec $chroot" \ - --remote-copy="$remote_copy $chroot" \ - $__target_host +#echo "__apt_noautostart --state present" \ +# | cdist $cdist_args \ +# config \ +# --initial-manifest - \ +# --remote-exec="$remote_exec $chroot" \ +# --remote-copy="$remote_copy $chroot" \ +# $__target_host cdist $cdist_args \ config \ @@ -40,11 +40,11 @@ cdist $cdist_args \ --remote-copy="$remote_copy $chroot" \ $__target_host -echo "__apt_noautostart --state absent" \ - | cdist $cdist_args \ - config \ - --initial-manifest - \ - --remote-exec="$remote_exec $chroot" \ - --remote-copy="$remote_copy $chroot" \ - $__target_host +#echo "__apt_noautostart --state absent" \ +# | cdist $cdist_args \ +# config \ +# --initial-manifest - \ +# --remote-exec="$remote_exec $chroot" \ +# --remote-copy="$remote_copy $chroot" \ +# $__target_host DONE From f23999c8d378f81bcb5e97604a220ce6d1b19cd1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jan 2014 10:41:23 +0100 Subject: [PATCH 2410/4212] ++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 2411/4212] 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 2412/4212] ++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 2413/4212] 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 2414/4212] 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 2415/4212] 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 2416/4212] 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 2417/4212] ++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 c3f79277b226ef5c97360566c868660e1ed1fbad Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 08:50:41 +0100 Subject: [PATCH 2418/4212] add some more packages for preos - fixes #267 Signed-off-by: Nico Schottelius --- cdist/preos.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/preos.py b/cdist/preos.py index 433cf871..f573566d 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -39,8 +39,8 @@ for pkg in \ file \ linux-image-amd64 \ openssh-server \ - syslinux \ - gdisk util-linux \ + syslinux grub 2 \ + gdisk util-linux lvm2 mdadm \ btrfs-tools e2fsprogs jfsutils reiser4progs xfsprogs; do __package $pkg --state present done From 79cfdf578d1d93241648262b64c2243ffed49559 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 09:01:04 +0100 Subject: [PATCH 2419/4212] remove obsolete '--additional-manifest' parameter Signed-off-by: Nico Schottelius --- scripts/cdist | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index ed9d2eda..7b7569ee 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -89,8 +89,6 @@ def commandline(): parents=[parser['loglevel']]) parser['preos'].add_argument('-a', '--arch', help='Select architecture for preos', default="amd64") - parser['preos'].add_argument('-A', '--additional-manifest', - help='Add stuff to configuration manifest', default="amd64") parser['preos'].add_argument('-b', '--bootstrap', help='Bootstrap directory with PreOS', action="store_true") parser['preos'].add_argument('-c', '--configure', From 55f26cbe25d8c87279a8221a9ef611fc2c90b8f1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 09:06:02 +0100 Subject: [PATCH 2420/4212] - ' ' Signed-off-by: Nico Schottelius --- cdist/preos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/preos.py b/cdist/preos.py index f573566d..b76d2178 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -39,7 +39,7 @@ for pkg in \ file \ linux-image-amd64 \ openssh-server \ - syslinux grub 2 \ + syslinux grub2 \ gdisk util-linux lvm2 mdadm \ btrfs-tools e2fsprogs jfsutils reiser4progs xfsprogs; do __package $pkg --state present From b125c0a4f273acaf33a082f8179b69e3b765b7d0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 09:21:50 +0100 Subject: [PATCH 2421/4212] create output directory, if it does not exist Signed-off-by: Nico Schottelius --- cdist/preos.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cdist/preos.py b/cdist/preos.py index b76d2178..f3d34c21 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -194,14 +194,21 @@ cp -L "$src" "$real_dst" log.info("Creating initramfs ...") subprocess.check_call(cmd, shell=True) + def ensure_out_dir_exists(self): + os.makedirs(self.out_dir, exist_ok=True) + + def create_iso(self, out_dir): self.out_dir = out_dir + self.ensure_out_dir_exists() + raise cdist.Error("Generating ISO is not yet supported") def create_pxe(self, out_dir): self.out_dir = out_dir + self.ensure_out_dir_exists() self.create_kernel() self.create_initramfs() self.create_pxeconfig() From 4cfedb1787abe7af68aa3cb51bbfc84714c26f4b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 09:42:53 +0100 Subject: [PATCH 2422/4212] +curl Signed-off-by: Nico Schottelius --- cdist/preos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/preos.py b/cdist/preos.py index f3d34c21..347b0cba 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -38,7 +38,7 @@ DEFAULT_MANIFEST = """ for pkg in \ file \ linux-image-amd64 \ - openssh-server \ + openssh-server curl \ syslinux grub2 \ gdisk util-linux lvm2 mdadm \ btrfs-tools e2fsprogs jfsutils reiser4progs xfsprogs; do From e463f84333204605d948f81de7ada5683bb0ce64 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 10:04:42 +0100 Subject: [PATCH 2423/4212] add changelog for 4.x cdist series Signed-off-by: Nico Schottelius --- cdist/conf/explorer/disks | 2 ++ docs/changelog.4 | 10 ++++++++++ 2 files changed, 12 insertions(+) create mode 100644 cdist/conf/explorer/disks create mode 100644 docs/changelog.4 diff --git a/cdist/conf/explorer/disks b/cdist/conf/explorer/disks new file mode 100644 index 00000000..52fef81e --- /dev/null +++ b/cdist/conf/explorer/disks @@ -0,0 +1,2 @@ +cd /dev +echo sd? hd? vd? diff --git a/docs/changelog.4 b/docs/changelog.4 new file mode 100644 index 00000000..79478c86 --- /dev/null +++ b/docs/changelog.4 @@ -0,0 +1,10 @@ +Changelog +--------- + + * Changes are always commented with their author in (braces) + * Exception: No braces means author == Nico Schottelius + +4.0.0pre1: + * Core: Integrate initial install support + * Core: Integrate initial preos support + From b4644c9c2eae1fdabb2b5a33f69ae92a774c1bc0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 10:08:46 +0100 Subject: [PATCH 2424/4212] add readme / warning for 4.x series Signed-off-by: Nico Schottelius --- README.4 | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 README.4 diff --git a/README.4 b/README.4 new file mode 100644 index 00000000..04258873 --- /dev/null +++ b/README.4 @@ -0,0 +1,24 @@ +This branch contains experimental features for cdist 4.x: + + - install support + - preos support + +They are not yet stable: + + - use them at your own risk + - all __install types may change at any time (syntax, parameter, etc.) + - explorers for install may be broken + + - core code is based on the master branch, but + contains changes for install and preos feature + + +In short: + + _ _ _ + _ _ ___ ___ __ _| |_ _ _ ___ _ _ _ __ _____ ___ __ _ __(_)___| | __ +| | | / __|/ _ \ / _` | __| | | | |/ _ \| | | | '__| / _ \ \ /\ / / '_ \ | '__| / __| |/ / +| |_| \__ \ __/ | (_| | |_ | |_| | (_) | |_| | | | (_) \ V V /| | | | | | | \__ \ < + \__,_|___/\___| \__,_|\__| \__, |\___/ \__,_|_| \___/ \_/\_/ |_| |_| |_| |_|___/_|\_\ + |___/ + From c790014cd59d65181d83a42d5f7b45ef2d2264c8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 10:11:23 +0100 Subject: [PATCH 2425/4212] 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 2426/4212] 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 2427/4212] 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 2428/4212] 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 2429/4212] 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 2430/4212] 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 2431/4212] 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 2432/4212] 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 2433/4212] 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 2434/4212] ++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 3ca911dbc641ed22596c18293d5f4c9271133eec Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 14:37:50 +0100 Subject: [PATCH 2435/4212] integrate install and preos support Signed-off-by: Nico Schottelius --- docs/changelog | 4 ++++ docs/changelog.4 | 10 ---------- 2 files changed, 4 insertions(+), 10 deletions(-) delete mode 100644 docs/changelog.4 diff --git a/docs/changelog b/docs/changelog index f43131a1..98260564 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 +4.0.0pre1: 2014-01-20 + * Core: Integrate initial install support + * Core: Integrate initial preos support + 3.0.3: * Core: Enhance error message when requirement is missing object id * Explorer hostname: Return host name by using uname -n diff --git a/docs/changelog.4 b/docs/changelog.4 deleted file mode 100644 index 79478c86..00000000 --- a/docs/changelog.4 +++ /dev/null @@ -1,10 +0,0 @@ -Changelog ---------- - - * Changes are always commented with their author in (braces) - * Exception: No braces means author == Nico Schottelius - -4.0.0pre1: - * Core: Integrate initial install support - * Core: Integrate initial preos support - From e40fde92fc95bed5e97e0715413b6a21f5780a42 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 14:40:54 +0100 Subject: [PATCH 2436/4212] 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 2437/4212] 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 a3c5d32a5453b25057acd238377fe002f98f9e74 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 14:45:42 +0100 Subject: [PATCH 2438/4212] fix building manpage of __install_partition_msdos Signed-off-by: Nico Schottelius --- cdist/conf/type/__install_partition_msdos/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__install_partition_msdos/man.text b/cdist/conf/type/__install_partition_msdos/man.text index 8d403b67..82d81ac5 100644 --- a/cdist/conf/type/__install_partition_msdos/man.text +++ b/cdist/conf/type/__install_partition_msdos/man.text @@ -1,5 +1,5 @@ cdist-type__install_partition_msdos(7) -============================== +====================================== Steven Armstrong From 5a0a3971b0c2769bf3b1c0202b0d48be6db71bb9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 14:48:05 +0100 Subject: [PATCH 2439/4212] 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 8ed5f85f9d5559f55ea41357d61217d3405c0610 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 14:48:05 +0100 Subject: [PATCH 2440/4212] 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 2441/4212] 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 2442/4212] 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 2443/4212] 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 2444/4212] ++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 2445/4212] 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 2446/4212] ++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 2447/4212] 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 2448/4212] 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 2449/4212] 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 2450/4212] 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 2451/4212] 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 2452/4212] ++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 2453/4212] 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 2454/4212] 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 2455/4212] ++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 2456/4212] 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 2457/4212] 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 2458/4212] ++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 2459/4212] 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 2460/4212] 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 2461/4212] ++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 2462/4212] 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 2463/4212] 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 2464/4212] 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 2465/4212] ++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 2466/4212] 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 2467/4212] 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 2468/4212] 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 2469/4212] 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 2470/4212] ++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 2471/4212] 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 2472/4212] 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 ca47ea00382a8f5da655540d6032c1338b51c8e5 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 3 Feb 2014 15:29:48 +0100 Subject: [PATCH 2473/4212] cleanup apt cache before packing initramfs Signed-off-by: Steven Armstrong --- cdist/preos.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cdist/preos.py b/cdist/preos.py index 347b0cba..dc400ba9 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -253,6 +253,12 @@ cp -L "$src" "$real_dst" config = cdist.config.Config(local, remote) config.run() + def cleanup(self): + # Remove cruft from chroot + for action in 'autoclean clean autoremove'.split(): + cmd = [ 'chroot', self.target_dir, '/usr/bin/apt-get', action] + subprocess.check_call(cmd) + @classmethod def commandline(cls, args): self = cls(target_dir=args.target_dir[0], @@ -270,6 +276,9 @@ cp -L "$src" "$real_dst" if args.config: self.config() + # Cleanup chroot + self.cleanup() + # Output pxe files if args.pxe_boot_dir: self.create_pxe(args.pxe_boot_dir) From 3c52710763a3f8537f732e716e53439d1b6af494 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 3 Feb 2014 21:43:39 +0100 Subject: [PATCH 2474/4212] 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 2475/4212] 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 2476/4212] ++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 2477/4212] 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 2478/4212] 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 2479/4212] 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 2480/4212] 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 2481/4212] /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 2482/4212] 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 2483/4212] 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 2484/4212] 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 2485/4212] ++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 ee5731fc960fa7849daa32f8ee4df130adc7aa66 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Feb 2014 00:08:02 +0100 Subject: [PATCH 2486/4212] add __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 294285c164fdb212ea2fc6277c97fc877e889cb2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Feb 2014 00:08:40 +0100 Subject: [PATCH 2487/4212] 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 2488/4212] ++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 2489/4212] 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 2490/4212] 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 2491/4212] 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 2492/4212] ++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 2493/4212] 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 2494/4212] 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 2495/4212] 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 2496/4212] 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 2497/4212] 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 2498/4212] 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 2499/4212] 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 2500/4212] 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 2501/4212] 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 2502/4212] 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 2503/4212] 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 2504/4212] 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 2505/4212] 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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�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 lpALS{q< Date: Mon, 10 Feb 2014 07:32:58 +0100 Subject: [PATCH 2506/4212] ++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 4efe8553da4ccf4ec58197bb1422eefa9713e908 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 10 Feb 2014 21:40:11 +0100 Subject: [PATCH 2507/4212] run apt-get clean before creating preos Signed-off-by: Nico Schottelius --- cdist/preos.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cdist/preos.py b/cdist/preos.py index 347b0cba..ff157f5b 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -162,6 +162,10 @@ cp -L "$src" "$real_dst" fd.write(val) os.chmod(filename, stat.S_IRUSR | stat.S_IXUSR) + def remove_archives(self, base_dir): + cmd = [ "chroot", self.target_dir, "/usr/bin/apt-get", "clean" ] + subprocess.check_call(cmd) + def create_kernel(self): dst = os.path.join(self.out_dir, "kernel") srcglob = glob.glob("%s/boot/vmlinuz-*" % self.target_dir) @@ -270,6 +274,9 @@ cp -L "$src" "$real_dst" if args.config: self.config() + # Cleanup archives before creating any image + self.remove_archives() + # Output pxe files if args.pxe_boot_dir: self.create_pxe(args.pxe_boot_dir) From e29255b9f250c15197406bed3b2d5869cc8751b7 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 11 Feb 2014 15:20:26 +0100 Subject: [PATCH 2508/4212] 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 2509/4212] 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 2510/4212] ++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 2511/4212] 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 2512/4212] 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 2513/4212] 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 2514/4212] ++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 2515/4212] ++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 2516/4212] ++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 2517/4212] 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 e8f5d4c34039acc0df7d9feb357c2634df0088f2 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 13 Feb 2014 15:38:35 +0100 Subject: [PATCH 2518/4212] some new explorers wich are handy if you must tune for example sap or oracle to the systemtype, cpu cores and/or physical memory --- cdist/conf/explorer/cpu_cores | 31 ++++++++++++++++++ cdist/conf/explorer/cpu_sockets | 31 ++++++++++++++++++ cdist/conf/explorer/machine_type | 54 ++++++++++++++++++++++++++++++++ cdist/conf/explorer/memory | 27 ++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100755 cdist/conf/explorer/cpu_cores create mode 100755 cdist/conf/explorer/cpu_sockets create mode 100755 cdist/conf/explorer/machine_type create mode 100755 cdist/conf/explorer/memory diff --git a/cdist/conf/explorer/cpu_cores b/cdist/conf/explorer/cpu_cores new file mode 100755 index 00000000..efabc848 --- /dev/null +++ b/cdist/conf/explorer/cpu_cores @@ -0,0 +1,31 @@ +#!/bin/sh +# +# 2014 Daniel Heule (hda at sfs.biz) +# 2014 Thomas Oettli (otho at sfs.biz) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +# FIXME: other system types (not linux ...) + +if [ -r /proc/cpuinfo ]; then + cores="$(cat /proc/cpuinfo | grep "core id" | sort | uniq | wc -l)" + if [ ${cores} -eq 0 ]; then + cores="1" + fi + echo "${cores}" +fi diff --git a/cdist/conf/explorer/cpu_sockets b/cdist/conf/explorer/cpu_sockets new file mode 100755 index 00000000..98836cec --- /dev/null +++ b/cdist/conf/explorer/cpu_sockets @@ -0,0 +1,31 @@ +#!/bin/sh +# +# 2014 Daniel Heule (hda at sfs.biz) +# 2014 Thomas Oettli (otho at sfs.biz) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +# FIXME: other system types (not linux ...) + +if [ -r /proc/cpuinfo ]; then + sockets="$(cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l)" + if [ ${sockets} -eq 0 ]; then + sockets="$(cat /proc/cpuinfo | grep "processor" | wc -l)" + fi + echo "${sockets}" +fi diff --git a/cdist/conf/explorer/machine_type b/cdist/conf/explorer/machine_type new file mode 100755 index 00000000..60b7f5e2 --- /dev/null +++ b/cdist/conf/explorer/machine_type @@ -0,0 +1,54 @@ +#!/bin/sh +# +# 2014 Daniel Heule (hda at sfs.biz) +# 2014 Thomas Oettli (otho at sfs.biz) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +# FIXME: other system types (not linux ...) + +if [ -r /proc/cpuinfo ]; then + # this should only exist on virtual guest machines, + # tested on vmware, xen, kvm + if grep -q "hypervisor" /proc/cpuinfo; then + # this file is aviable in xen guest systems + if [ -r /sys/hypervisor/type ]; then + if grep -q -i "xen" /sys/hypervisor/type; then + echo virtual by xen + exit + fi + else + if [ -r /sys/class/dmi/id/product_name ]; then + if grep -q -i 'vmware' /sys/class/dmi/id/product_name; then + echo "virtual by vmware" + exit + else + if grep -q -i 'bochs' /sys/class/dmi/id/product_name; then + echo "virtual by kvm" + exit + fi + fi + fi + fi + echo "virtual by unknown" + else + echo "physical" + fi +else + echo "unknown" +fi diff --git a/cdist/conf/explorer/memory b/cdist/conf/explorer/memory new file mode 100755 index 00000000..982b5dfa --- /dev/null +++ b/cdist/conf/explorer/memory @@ -0,0 +1,27 @@ +#!/bin/sh +# +# 2014 Daniel Heule (hda at sfs.biz) +# 2014 Thomas Oettli (otho at sfs.biz) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +# FIXME: other system types (not linux ...) + +if [ -r /proc/meminfo ]; then + echo "$(cat /proc/meminfo | grep "MemTotal:" | awk '{print $2}')" +fi From 46459053f463789f01a4afc159d1ab02a1940a11 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Feb 2014 21:02:18 +0100 Subject: [PATCH 2519/4212] 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 2520/4212] 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 2521/4212] ++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 2522/4212] ++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 2523/4212] 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? + From 95b1ac0706d0e6f127b78235dd89236053a92efe Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Feb 2014 20:34:24 +0100 Subject: [PATCH 2524/4212] update rbenv type to cdist 3.0 style Signed-off-by: Nico Schottelius --- cdist/conf/type/__rbenv/explorer/homedir | 25 ------------------- cdist/conf/type/__rbenv/man.text | 12 ++++++--- cdist/conf/type/__rbenv/manifest | 14 +++++------ .../conf/type/__rbenv/parameter/default/state | 1 + cdist/conf/type/__rbenv/parameter/required | 1 + 5 files changed, 18 insertions(+), 35 deletions(-) delete mode 100755 cdist/conf/type/__rbenv/explorer/homedir create mode 100644 cdist/conf/type/__rbenv/parameter/default/state create mode 100644 cdist/conf/type/__rbenv/parameter/required diff --git a/cdist/conf/type/__rbenv/explorer/homedir b/cdist/conf/type/__rbenv/explorer/homedir deleted file mode 100755 index 8dc25535..00000000 --- a/cdist/conf/type/__rbenv/explorer/homedir +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -# -# 2012 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Check whether repository exists -# - -user="$__object_id" -su - "$user" -c "pwd -P" diff --git a/cdist/conf/type/__rbenv/man.text b/cdist/conf/type/__rbenv/man.text index bee57f76..c6ed5de2 100644 --- a/cdist/conf/type/__rbenv/man.text +++ b/cdist/conf/type/__rbenv/man.text @@ -19,16 +19,22 @@ OPTIONAL PARAMETERS state:: Either "present" or "absent", defaults to "present" +owner:: + Which user should own the rbenv installation, defaults to root + EXAMPLES -------- -------------------------------------------------------------------------------- # Install rbenv including ruby-build for nico -__rbenv nico +__rbenv /home/nico + +# Install rbenv including ruby-build for nico +__rbenv /home/nico --owner nico # Bastian does not need rbenv anymore, he began to code C99 -__rbenv bastian --state absent +__rbenv /home/bastian --state absent -------------------------------------------------------------------------------- @@ -39,5 +45,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2012 Nico Schottelius. Free use of this software is +Copyright \(C) 2012-2014 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__rbenv/manifest b/cdist/conf/type/__rbenv/manifest index 8f912861..767abdba 100644 --- a/cdist/conf/type/__rbenv/manifest +++ b/cdist/conf/type/__rbenv/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -19,20 +19,20 @@ # # -homedir="$(cat "$__object/explorer/homedir")" -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" +homedir="$__object_id" + +state_should="$(cat "$__object/parameter/state")" +owner="$(cat "$__object/parameter/owner")" rbenvdir="$homedir/.rbenv" rubybuilddir="$rbenvdir/plugins/ruby-build" __git "$rbenvdir" \ --source git://github.com/sstephenson/rbenv.git \ - --owner "$__object_id" \ + --owner "$owner" \ --state "$state_should" -#__git "$rubybuilddir" \ require="__git/$rbenvdir" __git "$rubybuilddir" \ --source git://github.com/sstephenson/ruby-build.git \ - --owner "$__object_id" \ + --owner "$owner" \ --state "$state_should" diff --git a/cdist/conf/type/__rbenv/parameter/default/state b/cdist/conf/type/__rbenv/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__rbenv/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__rbenv/parameter/required b/cdist/conf/type/__rbenv/parameter/required new file mode 100644 index 00000000..7ee3bde8 --- /dev/null +++ b/cdist/conf/type/__rbenv/parameter/required @@ -0,0 +1 @@ +owner From f461a5073cd60168a0ea2688ca6df5dd0b5fb0fb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Feb 2014 20:44:51 +0100 Subject: [PATCH 2525/4212] pass owner/group/mode to __directory as well Signed-off-by: Nico Schottelius --- cdist/conf/type/__git/manifest | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__git/manifest b/cdist/conf/type/__git/manifest index 7f6fee84..b2b0feb0 100644 --- a/cdist/conf/type/__git/manifest +++ b/cdist/conf/type/__git/manifest @@ -24,6 +24,9 @@ __package git --state present state_should="$(cat "$__object/parameter/state")" +owner="$(cat "$__object/parameter/owner")" +group="$(cat "$__object/parameter/group")" +mode="$(cat "$__object/parameter/mode")" # Let __directory handle removal of git repos @@ -33,7 +36,10 @@ case "$state_should" in ;; absent) - __directory "$__object_id" --state absent + __directory "$__object_id" --state absent \ + --owner "$owner" \ + --group "$group" \ + --mode "$mode" ;; *) From 1cdcb12ebd535175639f71705b4b2704cf879069 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Feb 2014 20:51:20 +0100 Subject: [PATCH 2526/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index e8f98c01..49a0a3c3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius +3.0.10: + * Type __git: Pass onwer/group/mode values to __directory + 3.0.9: 2014-02-14 * Core: Ignore order dependencies if override is set (Daniel Heule) * Core: Improve Mac OS X support for unit tests (Steven Armstrong) From ac23fa3e1018d80f52bf05686bc6a9e70b23eeeb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Feb 2014 20:53:43 +0100 Subject: [PATCH 2527/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 00d2734e..4f6b1064 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 +4.0.0pre2: 2014-02-14 + * Core: Remove archives from generated preos (Steven Armstrong) + 4.0.0pre1: 2014-01-20 * Core: Integrate initial install support * Core: Integrate initial preos support From 3a2bd673c97f5276d781f14e51c2f55dcaf17ce3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Feb 2014 20:58:12 +0100 Subject: [PATCH 2528/4212] enhance build scripts for releasing from non-master branch Signed-off-by: Nico Schottelius --- Makefile | 5 +++-- bin/build-helper | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 1962c96e..9502c989 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-fix-link: web-pub +man-latest-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" @@ -146,7 +146,8 @@ web-dist: web-blog web-doc web-pub: web-dist man-dist speeches-dist cd "${WEBDIR}" && make pub -web-release-all: man-fix-link +web-release-all: man-latest-link +web-release-all-no-latest: web-pub ################################################################################ # Release: Mailinglist diff --git a/bin/build-helper b/bin/build-helper index bfd7d31c..1de2eb94 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -256,7 +256,11 @@ eof make pub # publish man, speeches, website - make web-release-all + if [ "$masterbranch" = yes ]; then + make web-release-all + else + make web-release-all-no-latest + fi # Ensure that pypi release has the right version "$0" version From 478ebd190cf0f69a02dc5212389a8cebb43d7f76 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Fri, 14 Feb 2014 22:06:43 +0100 Subject: [PATCH 2529/4212] transfert idea into the file in git tree, so we can close issue 286 --- docs/dev/fancy-ideas | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/dev/fancy-ideas b/docs/dev/fancy-ideas index f125a884..8ee290cd 100644 --- a/docs/dev/fancy-ideas +++ b/docs/dev/fancy-ideas @@ -4,4 +4,14 @@ implemented as a proof of concept at: https://github.com/asteven/cdist/tree/type-namespaces + + +Execute all global explorers only when needed #286 +My intention is to create a brunch of global explorer which are of use in some cases and makes cdist more userfriendly. But now, all global explorers are allways executed, even the return value of the explorers is never used. + +I think a possible approach can be to replace the result files with pipes, and on first read of the pipe, the explorer is executed by the core, all following read calls from the pipe are answered from the core with the result of the first real execute of the explorer. + +So cdist can have an unlimited number of global explorers and only used explorers are executed on the target host, all other explorers laying around are simply ignored. + +Also a possible approach would be to create a new explorer type (dynamic explorers) which are sitting in a different directory to (for example dynexploer) and only this ones are executed with the conditional approach explained above. So the overhead to create pipes and monitor it is only in place on explorers which are not interesting for everyone ... From 4ce52c5a9d65fa5af4d492e56a1101a2ce7316a5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 15 Feb 2014 11:31:39 +0100 Subject: [PATCH 2530/4212] -ws Signed-off-by: Nico Schottelius --- docs/changelog | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 49a0a3c3..1dbc0787 100644 --- a/docs/changelog +++ b/docs/changelog @@ -21,7 +21,6 @@ Changelog * 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) * Core: Add unit tests for dependencies based on execution order (Daniel Heule) From 9c6defe17c934796d3cb0d443be1cf4f1031181f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Feb 2014 20:17:08 +0100 Subject: [PATCH 2531/4212] unauthenticated problem Signed-off-by: Nico Schottelius --- .../logs/2014-02-18.unauthenticated-packages | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 docs/dev/logs/2014-02-18.unauthenticated-packages diff --git a/docs/dev/logs/2014-02-18.unauthenticated-packages b/docs/dev/logs/2014-02-18.unauthenticated-packages new file mode 100644 index 00000000..5fc6357b --- /dev/null +++ b/docs/dev/logs/2014-02-18.unauthenticated-packages @@ -0,0 +1,18 @@ +- we cannot install packages, which are not authenticated: + +INFO: voicerepublic-staging.sky.ungleich.ch: Executing code for __package_apt/deb-multimedia-keyring +Reading package lists... +Building dependency tree... +Reading state information... +The following NEW packages will be installed: + deb-multimedia-keyring + 0 upgraded, 1 newly installed, 0 to remove and 13 not upgraded. + Need to get 14.4 kB of archives. + After this operation, 46.1 kB of additional disk space will be used. + WARNING: The following packages cannot be authenticated! + deb-multimedia-keyring + E: There are problems and -y was used without --force-yes + ERROR: voicerepublic-staging.sky.ungleich.ch: Command failed: ssh -o User=root -q voicerepublic-staging.sky.ungleich.ch /bin/sh -e /var/lib/cdist/object/__package_apt/deb-multimedia-keyring/.cdist/code-remote + INFO: cdist: Total processing time for 1 host(s): 72.07943892478943 + ERROR: cdist: Failed to configure the following hosts: voicerepublic-staging.sky.ungleich.ch + From 68c1bf6633d3e6219211e11c25435dffb4b6e9d5 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 22 Feb 2014 00:51:26 +0100 Subject: [PATCH 2532/4212] preserve ownership and permissions of existing file Signed-off-by: Steven Armstrong --- cdist/conf/type/__line/gencode-remote | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote index 1fadf454..1ac1ad13 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -74,8 +75,13 @@ case "$state_should" in fi cat << eof -tmp=\$(mktemp) -grep -v $greparg '$regex' '$file' > \$tmp && cat "\$tmp" > '$file' && rm -f "\$tmp" +tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) +# preserve ownership and permissions of existing file +if [ -f "$file" ]; then + cp -p "$file" "\$tmpfile" +fi +grep -v $greparg '$regex' '$file' > \$tmpfile +mv -f "\$tmpfile" "$file" eof ;; *) From 2fdff153d6f1c78693f7e49a9baa2b43cc668061 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 22 Feb 2014 00:51:54 +0100 Subject: [PATCH 2533/4212] dont fail if result is empty file Signed-off-by: Steven Armstrong --- 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 1ac1ad13..f73444e3 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -80,7 +80,7 @@ tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) if [ -f "$file" ]; then cp -p "$file" "\$tmpfile" fi -grep -v $greparg '$regex' '$file' > \$tmpfile +grep -v $greparg '$regex' '$file' > \$tmpfile || true mv -f "\$tmpfile" "$file" eof ;; From 16a829d3eb14cfdc338f1bba1a1dfcfb0be6841d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 22 Feb 2014 01:09:42 +0100 Subject: [PATCH 2534/4212] manage individual keys instead of block of text also fixes #251 Signed-off-by: Steven Armstrong --- .../type/__ssh_authorized_keys/explorer/group | 22 +++++++++++ .../conf/type/__ssh_authorized_keys/man.text | 2 +- .../conf/type/__ssh_authorized_keys/manifest | 37 +++++++++++++------ 3 files changed, 49 insertions(+), 12 deletions(-) create mode 100755 cdist/conf/type/__ssh_authorized_keys/explorer/group diff --git a/cdist/conf/type/__ssh_authorized_keys/explorer/group b/cdist/conf/type/__ssh_authorized_keys/explorer/group new file mode 100755 index 00000000..cdea6fe7 --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_keys/explorer/group @@ -0,0 +1,22 @@ +#!/bin/sh +# +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +gid="$("$__type_explorer/passwd" | cut -d':' -f 4)" +getent group "$gid" || true diff --git a/cdist/conf/type/__ssh_authorized_keys/man.text b/cdist/conf/type/__ssh_authorized_keys/man.text index 7177f26e..259d4152 100644 --- a/cdist/conf/type/__ssh_authorized_keys/man.text +++ b/cdist/conf/type/__ssh_authorized_keys/man.text @@ -97,5 +97,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2012 Steven Armstrong. Free use of this software is +Copyright \(C) 2012-2014 Steven Armstrong. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 5a9cfbb3..01a29c37 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -32,7 +32,7 @@ else fi if [ ! -f "$__object/parameter/noparent" -o ! -f "$__object/parameter/nofile" ]; then - group="$(cut -d':' -f 4 "$__object/explorer/passwd")" + group="$(cut -d':' -f 1 "$__object/explorer/group")" if [ -z "$group" ]; then echo "Failed to get owners group from explorer." >&2 exit 1 @@ -56,16 +56,31 @@ if [ ! -f "$__object/parameter/noparent" -o ! -f "$__object/parameter/nofile" ]; fi fi -# Generate entry for inclusion in authorized_keys file -( -if [ -f "$__object/parameter/comment" ]; then - echo "# $(cat "$__object/parameter/comment")" -fi -cat "$__object/parameter/key" -) | \ +# Remove legacy blocks created by old versions of this type __block "$__object_name" \ --file "$file" \ --prefix "#cdist:$__object_name" \ --suffix "#/cdist:$__object_name" \ - --state "$state" \ - --text - + --state 'absent' \ + --text - << DONE +remove legacy block +DONE + +_cksum() { + echo "$1" | cksum | cut -d' ' -f 1 +} + +# Add each key +IFS=$'\n' +for key in $(cat "$__object/parameter/key"); do + unset IFS + raw_key="$(echo "$key" | tr ' ' '\n' | awk '/^ssh-(rsa|dsa)/ {printf $1" ";getline;printf $1}')" + set -- "$(_cksum "$raw_key")" + set -- "$@" --file "$file" + set -- "$@" --regex ".*$raw_key.*" + if [ "$state" = 'present' ]; then + set -- "$@" --line "$key" + fi + set -- "$@" --state "$state" + require="__block/$__object_name" __line "$@" +done From 95f38d9d443fbceb7ed89f590df1932d16f21162 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 22 Feb 2014 01:12:41 +0100 Subject: [PATCH 2535/4212] remove no longer supported parameter --comment Signed-off-by: Steven Armstrong --- cdist/conf/type/__ssh_authorized_keys/man.text | 8 ++------ cdist/conf/type/__ssh_authorized_keys/parameter/optional | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/cdist/conf/type/__ssh_authorized_keys/man.text b/cdist/conf/type/__ssh_authorized_keys/man.text index 259d4152..9fd683fd 100644 --- a/cdist/conf/type/__ssh_authorized_keys/man.text +++ b/cdist/conf/type/__ssh_authorized_keys/man.text @@ -40,9 +40,6 @@ state:: file:: an alternative destination file, defaults to ~$owner/.ssh/authorized_keys -comment:: - an optional comment - BOOLEAN PARAMETERS ------------------ @@ -67,12 +64,11 @@ __ssh_authorized_keys root \ __ssh_authorized_keys user-name \ --key "ssh-rsa AXYZAAB3NzaC1yc2..." -# same as above, but with explicit owner, two keys and a comment +# same as above, but with explicit owner and two keys __ssh_authorized_keys some-fancy-id \ --owner user-name \ --key "ssh-rsa AXYZAAB3NzaC1yc2..." \ - --key "ssh-rsa AZXYAAB3NzaC1yc2..." \ - --comment "allow the members of project foo to login" + --key "ssh-rsa AZXYAAB3NzaC1yc2..." # same as above, but authorized_keys file in non standard location __ssh_authorized_keys some-fancy-id \ diff --git a/cdist/conf/type/__ssh_authorized_keys/parameter/optional b/cdist/conf/type/__ssh_authorized_keys/parameter/optional index bfbd72ab..989750b3 100644 --- a/cdist/conf/type/__ssh_authorized_keys/parameter/optional +++ b/cdist/conf/type/__ssh_authorized_keys/parameter/optional @@ -1,4 +1,3 @@ owner state file -comment From d6b7033f2bb79e6243eb866f83cce43add1fba56 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 22 Feb 2014 10:13:51 +0100 Subject: [PATCH 2536/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 1dbc0787..66a83b31 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,8 +5,10 @@ Changelog * Exception: No braces means author == Nico Schottelius -3.0.10: +next: * Type __git: Pass onwer/group/mode values to __directory + * Type __ssh_authorized_keys: Allow managing existing keys (Steven Armstrong) + 3.0.9: 2014-02-14 * Core: Ignore order dependencies if override is set (Daniel Heule) From 4e535b6b8bc1ceef209b63f24bcbc3067f29c6c5 Mon Sep 17 00:00:00 2001 From: Antoine Catton Date: Sun, 23 Feb 2014 20:22:06 -0700 Subject: [PATCH 2537/4212] Docfix: ssh service listen on port 22 --- cdist/conf/type/__iptables_rule/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__iptables_rule/man.text b/cdist/conf/type/__iptables_rule/man.text index eb230093..2f5b9785 100644 --- a/cdist/conf/type/__iptables_rule/man.text +++ b/cdist/conf/type/__iptables_rule/man.text @@ -41,7 +41,7 @@ __iptables_rule established --rule "-A INPUT -m state --state RELATED,ESTABLISH # 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 ssh --rule "-A INPUT -p tcp --dport 22 -j ACCEPT" __iptables_rule https --rule "-A INPUT -p tcp --dport 443 -j ACCEPT" # Ensure some rules are not present anymore From ce0f779664e5808382134f12904553b30db65c22 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 24 Feb 2014 16:00:12 +0100 Subject: [PATCH 2538/4212] include the owner into the object_id for line Signed-off-by: Nico Schottelius --- cdist/conf/type/__ssh_authorized_keys/manifest | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 01a29c37..313e3b23 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -1,6 +1,7 @@ #!/bin/sh # # 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -75,7 +76,11 @@ IFS=$'\n' for key in $(cat "$__object/parameter/key"); do unset IFS raw_key="$(echo "$key" | tr ' ' '\n' | awk '/^ssh-(rsa|dsa)/ {printf $1" ";getline;printf $1}')" - set -- "$(_cksum "$raw_key")" + + cksum_key="$(_cksum "$raw_key")" + line_id="${owner}-${cksum_key}" + + set -- "$line_id" set -- "$@" --file "$file" set -- "$@" --regex ".*$raw_key.*" if [ "$state" = 'present' ]; then From a126bd955ff2aafc2e715a9fb9b7a5c515bcc0d2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 24 Feb 2014 18:06:15 +0100 Subject: [PATCH 2539/4212] use while read -> avoids ifs problem Signed-off-by: Nico Schottelius --- cdist/conf/type/__ssh_authorized_keys/manifest | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 313e3b23..efcd2d7a 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -71,21 +71,17 @@ _cksum() { echo "$1" | cksum | cut -d' ' -f 1 } -# Add each key -IFS=$'\n' -for key in $(cat "$__object/parameter/key"); do - unset IFS - raw_key="$(echo "$key" | tr ' ' '\n' | awk '/^ssh-(rsa|dsa)/ {printf $1" ";getline;printf $1}')" - - cksum_key="$(_cksum "$raw_key")" +while read key; do + cksum_key="$(_cksum "$key")" line_id="${owner}-${cksum_key}" set -- "$line_id" set -- "$@" --file "$file" - set -- "$@" --regex ".*$raw_key.*" + set -- "$@" --regex ".*$key.*" if [ "$state" = 'present' ]; then set -- "$@" --line "$key" fi set -- "$@" --state "$state" - require="__block/$__object_name" __line "$@" -done + # Ensure __line does not read stdin + require="__block/$__object_name" __line "$@" < /dev/null +done < "$__object/parameter/key" From 205e256ef646d272bd8854eaed3d1761e8af3126 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 24 Feb 2014 21:42:45 +0100 Subject: [PATCH 2540/4212] rewrite of __key_value, now support nerarly every value --- cdist/conf/type/__key_value/explorer/state | 70 +++++++++------- cdist/conf/type/__key_value/gencode-remote | 93 +++++++++++++++------- 2 files changed, 108 insertions(+), 55 deletions(-) diff --git a/cdist/conf/type/__key_value/explorer/state b/cdist/conf/type/__key_value/explorer/state index 94a5ea7f..071bc862 100755 --- a/cdist/conf/type/__key_value/explorer/state +++ b/cdist/conf/type/__key_value/explorer/state @@ -1,6 +1,7 @@ #!/bin/sh # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -18,36 +19,49 @@ # along with cdist. If not, see . # -key="$(cat "$__object/parameter/key" 2>/dev/null \ +export key="$(cat "$__object/parameter/key" 2>/dev/null \ || echo "$__object_id")" -state="$(cat "$__object/parameter/state" 2>/dev/null \ +export state="$(cat "$__object/parameter/state" 2>/dev/null \ || echo "present")" file="$(cat "$__object/parameter/file")" -delimiter="$(cat "$__object/parameter/delimiter")" -value="$(cat "$__object/parameter/value" 2>/dev/null \ +export delimiter="$(cat "$__object/parameter/delimiter")" +export value="$(cat "$__object/parameter/value" 2>/dev/null \ || echo "__CDIST_NOTSET__")" -case "$state" in - absent) - if grep -q -E "^$key$delimiter+" "$file"; then - # if the key exists, with whatever value, we will have to remove it - # so report it as present - echo present - else - # key does not exist - echo absent - fi - ;; - present) - if grep -q -E "^$key$delimiter+$value$" "$file"; then - # key exists and value is same - echo present - elif grep -q -E "^$key$delimiter+" "$file"; then - # key exists, but value is empty or different - echo wrongvalue - else - # key does not exist - echo absent - fi - ;; -esac +awk -f - "$file" <<"AWK_EOF" +BEGIN { + state=ENVIRON["state"] + key=ENVIRON["key"] + delimiter=ENVIRON["delimiter"] + value=ENVIRON["value"] + keydel=key delimiter + line=keydel value + found=0 +} +# enter the main loop +{ + i = index($0,keydel) + if(i == 1) { + found=1 + if(state == "absent") { + # on state absent, only the ocurance is relevant, so exit here + print "present" + exit + } + # Key with separator found + if($0 == line) { + # exact match found, so state is present + print "present" + } + else { + # not value is wrong ... + print "wrongvalue" + } + exit + } +} +END { + if(found == 0) + print "absent" +} +AWK_EOF diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index b79d9688..0e963b7c 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -2,6 +2,7 @@ # # 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. # @@ -18,6 +19,7 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # +#set -x key="$__object_id" [ -f "$__object/parameter/key" ] && key="$(cat "$__object/parameter/key")" @@ -25,39 +27,15 @@ key="$__object_id" state_should="$(cat "$__object/parameter/state")" file="$(cat "$__object/parameter/file")" -delimiter="$(cat "$__object/parameter/delimiter")" -# 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 +# here we check only if the states are valid, let awk do the work ... case "$state_should" in - absent) - # remove lines starting with key - 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) + absent|present) case "$state_is" in - absent) - # add new key and value - printf 'echo "%s%s%s" >> "%s"' "$key" "$delimiter" "$value_escaped" "$file" - ;; - wrongvalue) - # change exisiting value - 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 + absent|wrongvalue|present) ;; *) echo "Unknown explorer state: $state_is" >&2 @@ -68,3 +46,64 @@ DONE echo "Unknown state: $state_should" >&2 exit 1 esac + +cat <"\$tmpfile" <<"AWK_EOF" +BEGIN { + # import variables in a secure way .. + state=ENVIRON["state"] + key=ENVIRON["key"] + delimiter=ENVIRON["delimiter"] + value=ENVIRON["value"] + keydel=key delimiter + line=keydel value + inserted=0 +} +# enter the main loop +{ + # I dont use regex, this is by design, so we can match against every value without special meanings of chars ... + i = index(\$0,keydel) + if(i == 1) { + if(state == "absent") { + # if absent, simple yump over this line + next + } + else { + inserted=1 + # state is present, so insert correct line here + print line + next + } + } + else { + print \$0 + } +} +END { + if(inserted == 0 && state == "present" ) { + print line + } +} +AWK_EOF +mv -f "\$tmpfile" "$file" +CDIST_HEREDOC_END_HERE_MARKER From 820ed5ae0c8cccc203db2c642af05c763eda0e87 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 24 Feb 2014 23:27:42 +0100 Subject: [PATCH 2541/4212] added option comment_line to prefix key value with a comment line --- cdist/conf/type/__key_value/gencode-remote | 52 +++++++++++++++---- .../parameter/default/comment_line | 1 + .../conf/type/__key_value/parameter/optional | 1 + 3 files changed, 43 insertions(+), 11 deletions(-) create mode 100644 cdist/conf/type/__key_value/parameter/default/comment_line diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index 0e963b7c..2fa07f5c 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -47,22 +47,26 @@ case "$state_should" in exit 1 esac -cat < Date: Tue, 25 Feb 2014 11:35:14 +0100 Subject: [PATCH 2542/4212] updated the man page .... --- cdist/conf/type/__key_value/man.text | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__key_value/man.text b/cdist/conf/type/__key_value/man.text index 1423fc7d..82bb2fdf 100644 --- a/cdist/conf/type/__key_value/man.text +++ b/cdist/conf/type/__key_value/man.text @@ -25,12 +25,15 @@ delimiter:: OPTIONAL PARAMETERS ------------------- state:: - present or absent, defaults to present. If present, sets the key to value, - if absent, removes the key from the file. + present or absent, defaults to present. If present, sets the key to value, + if absent, removes the key from the file. key:: - The key to change. Defaults to object_id. + The key to change. Defaults to object_id. value:: - The value for the key. Optional if state=absent, required otherwise. + The value for the key. Optional if state=absent, required otherwise. +comment_line:: + If supplied, the comment line is inserted before the line with key and value, + but only if key or value is about to be changed. EXAMPLES @@ -46,13 +49,24 @@ __key_value my-fancy-id --file /etc/login.defs --key SYS_UID_MAX --value 666 \ # Enable packet forwarding __key_value net.ipv4.ip_forward --file /etc/sysctl.conf --value 1 \ - --delimiter '=' + --delimiter ' = ' --comment_line '# my linux kernel should act as a router' # Remove existing key/value __key_value LEGACY_KEY --file /etc/somefile --state absent --delimiter '=' -------------------------------------------------------------------------------- +MORE INFORMATION +---------------- +This type does not use regex to avoid quoting problems. +So you need to specify the key and delimiteri exactly. +Delimiter can be one or more characters. +Due to shell limitations, we have some values which can not be used. +These values are: +__CDIST_HEREDOC_END_HERE_MARKER +__CDIST_INPUT_END_HERE_MARKER + + SEE ALSO -------- - cdist-type(7) From 8d80e52de957c1a12cd48ff4cfe564b86dd21862 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 27 Feb 2014 14:45:19 +0100 Subject: [PATCH 2543/4212] implemented some suggestions from steven --- cdist/conf/type/__key_value/explorer/state | 36 +++++++-- cdist/conf/type/__key_value/gencode-remote | 81 +++++++++++++++---- cdist/conf/type/__key_value/man.text | 33 ++++++-- cdist/conf/type/__key_value/parameter/boolean | 1 + .../__key_value/parameter/default/comment | 1 + .../conf/type/__key_value/parameter/optional | 2 +- 6 files changed, 124 insertions(+), 30 deletions(-) create mode 100644 cdist/conf/type/__key_value/parameter/boolean create mode 100644 cdist/conf/type/__key_value/parameter/default/comment diff --git a/cdist/conf/type/__key_value/explorer/state b/cdist/conf/type/__key_value/explorer/state index 071bc862..cb7578a5 100755 --- a/cdist/conf/type/__key_value/explorer/state +++ b/cdist/conf/type/__key_value/explorer/state @@ -27,6 +27,11 @@ file="$(cat "$__object/parameter/file")" export delimiter="$(cat "$__object/parameter/delimiter")" export value="$(cat "$__object/parameter/value" 2>/dev/null \ || echo "__CDIST_NOTSET__")" +if [ -f "$__object/parameter/exact_delimiter" ]; then + export exact_delimiter=1 +else + export exact_delimiter=0 +fi awk -f - "$file" <<"AWK_EOF" BEGIN { @@ -34,27 +39,48 @@ BEGIN { key=ENVIRON["key"] delimiter=ENVIRON["delimiter"] value=ENVIRON["value"] - keydel=key delimiter - line=keydel value + exact_delimiter=ENVIRON["exact_delimiter"] found=0 } # enter the main loop { - i = index($0,keydel) + i = index($0,key) if(i == 1) { + delval = substr($0,length(key)+1) + delpos = index(delval,delimiter) + if(delpos > 1) { + spaces = substr(delval,1,delpos-1) + sub(/[ \t]*/,"",spaces) + if( length(spaces) > 0 ) { + # if there are not only spaces between key and delimiter, + # continue since we we are on the wrong line + next + } + if( exact_delimiter == 1) { + # we have key and delimiter, but since additional spaces are not alowed + # return wrongformat + found=1 + print "wrongformat" + exit + } + } found=1 if(state == "absent") { # on state absent, only the ocurance is relevant, so exit here print "present" exit } + linevalue=substr(delval,delpos + length(delimiter)) + if(exact_delimiter == 0){ + #ok, now strip tabs and whitespaces at the beginning of the value + sub(/[ \t]*/,"",linevalue) + } # Key with separator found - if($0 == line) { + if(linevalue == value) { # exact match found, so state is present print "present" } else { - # not value is wrong ... print "wrongvalue" } exit diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index 2fa07f5c..dc01b645 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -21,21 +21,49 @@ # #set -x -key="$__object_id" -[ -f "$__object/parameter/key" ] && key="$(cat "$__object/parameter/key")" state_should="$(cat "$__object/parameter/state")" - -file="$(cat "$__object/parameter/file")" state_is="$(cat "$__object/explorer/state")" -[ "$state_is" = "$state_should" ] && exit 0 +if [ "$state_is" = "$state_should" ]; then + exit 0 +fi -# here we check only if the states are valid, let awk do the work ... +file="$(cat "$__object/parameter/file")" +key="$__object_id" +[ -f "$__object/parameter/key" ] && key="$(cat "$__object/parameter/key")" +if [ -f "$__object/parameter/exact_delimiter" ]; then + export exact_delimiter=1 +else + export exact_delimiter=0 +fi + +# here we check only if the states are valid, +# emmit messages and +# let awk do the work ... case "$state_should" in - absent|present) + absent) case "$state_is" in - absent|wrongvalue|present) + absent) + # nothing to do + ;; + wrongformat|wrongvalue|present) + echo removed >> "$__messages_out" + ;; + *) + echo "Unknown explorer state: $state_is" >&2 + exit 1 + esac + present) + case "$state_is" in + absent) + echo inserted >> "$__messages_out" + ;; + wrongformated|wrongvalue) + echo changed >> "$__messages_out" + ;; + present) + # nothing to do ;; *) echo "Unknown explorer state: $state_is" >&2 @@ -56,16 +84,20 @@ export key="\$(cat <<"__CDIST_INPUT_END_HERE_MARKER" $key __CDIST_INPUT_END_HERE_MARKER )" -export delimiter="\$(cat <<"__CDIST_INPUT_END_HERE_MARKER" -$(cat "$__object/parameter/delimiter") -__CDIST_INPUT_END_HERE_MARKER -)" export value="\$(cat <<"__CDIST_INPUT_END_HERE_MARKER" $(cat "$__object/parameter/value") __CDIST_INPUT_END_HERE_MARKER )" +export delimiter="\$(cat <<"__CDIST_INPUT_END_HERE_MARKER" +$(cat "$__object/parameter/delimiter") +__CDIST_INPUT_END_HERE_MARKER +)" +export exact_delimiter="\$(cat <<"__CDIST_INPUT_END_HERE_MARKER" +$exact_delimiter +__CDIST_INPUT_END_HERE_MARKER +)" export comment="\$(cat <<"__CDIST_INPUT_END_HERE_MARKER" -$(cat "$__object/parameter/comment_line") +$(cat "$__object/parameter/comment") __CDIST_INPUT_END_HERE_MARKER )" @@ -80,17 +112,33 @@ BEGIN { delimiter=ENVIRON["delimiter"] value=ENVIRON["value"] comment=ENVIRON["comment"] - keydel=key delimiter - line=keydel value + exact_delimiter=ENVIRON["exact_delimiter"] inserted=0 ll="" llpopulated=0 + line=key delimiter value } # enter the main loop { # I dont use regex, this is by design, so we can match against every value without special meanings of chars ... - i = index(\$0,keydel) + i = index(\$0,key) if(i == 1) { + delval = substr(\$0,length(key)+1) + delpos = index(delval,delimiter) + if(delpos > 1) { + spaces = substr(delval,1,delpos-1) + sub(/[ \t]*/,"",spaces) + if( length(spaces) > 0 ) { + # if there are not only spaces between key and delimiter, + # continue since we we are on the wrong line + if(llpopulated == 1) { + print ll + } + ll=\$0 + llpopulated=1 + next + } + } if(state == "absent") { if(ll == comment) { # if comment is present, clear llpopulated flag @@ -136,4 +184,5 @@ END { } AWK_EOF mv -f "\$tmpfile" "$file" +exit 1 __CDIST_HEREDOC_END_HERE_MARKER diff --git a/cdist/conf/type/__key_value/man.text b/cdist/conf/type/__key_value/man.text index 82bb2fdf..95e00ce9 100644 --- a/cdist/conf/type/__key_value/man.text +++ b/cdist/conf/type/__key_value/man.text @@ -31,9 +31,28 @@ key:: The key to change. Defaults to object_id. value:: The value for the key. Optional if state=absent, required otherwise. -comment_line:: - If supplied, the comment line is inserted before the line with key and value, - but only if key or value is about to be changed. +comment:: + If supplied, the value will be inserted before the line with the key, + but only if the key or value must be changed. + You need to ensure yourself that the line is prefixed with the correct + comment sign. (for example # or ; or wathever ..) + + +BOOLEAN PARAMETERS +------------------ +exact_delimiter:: + If supplied, thread additional whitespaces between key, delimiter and value + as wrong value. + + +MESSAGES +-------- +removed:: + Line with key was removed +inserted:: + A new line was inserted +changed:: + An existing line was changed EXAMPLES @@ -58,11 +77,9 @@ __key_value LEGACY_KEY --file /etc/somefile --state absent --delimiter '=' MORE INFORMATION ---------------- -This type does not use regex to avoid quoting problems. -So you need to specify the key and delimiteri exactly. -Delimiter can be one or more characters. -Due to shell limitations, we have some values which can not be used. -These values are: +This type try to handle as many values as possible, so it doen't use regexes. +So you need to exatly specify the key and delimiter. Delimiter can be of any lenght. +Due to shell limitations, we have some values which you can't use, this values are: __CDIST_HEREDOC_END_HERE_MARKER __CDIST_INPUT_END_HERE_MARKER diff --git a/cdist/conf/type/__key_value/parameter/boolean b/cdist/conf/type/__key_value/parameter/boolean new file mode 100644 index 00000000..190831c1 --- /dev/null +++ b/cdist/conf/type/__key_value/parameter/boolean @@ -0,0 +1 @@ +exact_delimiter diff --git a/cdist/conf/type/__key_value/parameter/default/comment b/cdist/conf/type/__key_value/parameter/default/comment new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__key_value/parameter/default/comment @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__key_value/parameter/optional b/cdist/conf/type/__key_value/parameter/optional index 8eeebd0c..666be2ae 100644 --- a/cdist/conf/type/__key_value/parameter/optional +++ b/cdist/conf/type/__key_value/parameter/optional @@ -1,4 +1,4 @@ key value state -comment_line +comment From 0198b99eb53819111ebb4362900a761f9c2bb091 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 27 Feb 2014 15:47:19 +0100 Subject: [PATCH 2544/4212] corrected some debug codesnips --- cdist/conf/type/__key_value/explorer/state | 4 ++++ cdist/conf/type/__key_value/gencode-remote | 5 ++++- cdist/conf/type/__key_value/parameter/default/comment_line | 1 - 3 files changed, 8 insertions(+), 2 deletions(-) delete mode 100644 cdist/conf/type/__key_value/parameter/default/comment_line diff --git a/cdist/conf/type/__key_value/explorer/state b/cdist/conf/type/__key_value/explorer/state index cb7578a5..8bdd3a1d 100755 --- a/cdist/conf/type/__key_value/explorer/state +++ b/cdist/conf/type/__key_value/explorer/state @@ -48,6 +48,10 @@ BEGIN { if(i == 1) { delval = substr($0,length(key)+1) delpos = index(delval,delimiter) + if(delpos == 0) { + # in this case, the delimiter was not found + next + } if(delpos > 1) { spaces = substr(delval,1,delpos-1) sub(/[ \t]*/,"",spaces) diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index dc01b645..1e1d7c92 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -53,7 +53,9 @@ case "$state_should" in *) echo "Unknown explorer state: $state_is" >&2 exit 1 + ;; esac + ;; present) case "$state_is" in absent) @@ -68,11 +70,13 @@ case "$state_should" in *) echo "Unknown explorer state: $state_is" >&2 exit 1 + ;; esac ;; *) echo "Unknown state: $state_should" >&2 exit 1 + ;; esac cat <<__CDIST_HEREDOC_END_HERE_MARKER @@ -184,5 +188,4 @@ END { } AWK_EOF mv -f "\$tmpfile" "$file" -exit 1 __CDIST_HEREDOC_END_HERE_MARKER diff --git a/cdist/conf/type/__key_value/parameter/default/comment_line b/cdist/conf/type/__key_value/parameter/default/comment_line deleted file mode 100644 index 8b137891..00000000 --- a/cdist/conf/type/__key_value/parameter/default/comment_line +++ /dev/null @@ -1 +0,0 @@ - From 727c918f671620d5beb59da0cf7110a0b77b1e48 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 27 Feb 2014 17:04:23 +0100 Subject: [PATCH 2545/4212] work around a bug in bash3, now tested with dash, bash, busybox --- cdist/conf/type/__key_value/gencode-remote | 25 ++++++++++------------ 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index 1e1d7c92..62cc745d 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -80,30 +80,27 @@ case "$state_should" in esac cat <<__CDIST_HEREDOC_END_HERE_MARKER -export state="\$(cat <<"__CDIST_INPUT_END_HERE_MARKER" +IFS='\n' read -r state <<'__CDIST_INPUT_END_HERE_MARKER' $state_should __CDIST_INPUT_END_HERE_MARKER -)" -export key="\$(cat <<"__CDIST_INPUT_END_HERE_MARKER" +export state +IFS='\n' read -r key <<'__CDIST_INPUT_END_HERE_MARKER' $key __CDIST_INPUT_END_HERE_MARKER -)" -export value="\$(cat <<"__CDIST_INPUT_END_HERE_MARKER" +export key +IFS='\n' read -r value <<'__CDIST_INPUT_END_HERE_MARKER' $(cat "$__object/parameter/value") __CDIST_INPUT_END_HERE_MARKER -)" -export delimiter="\$(cat <<"__CDIST_INPUT_END_HERE_MARKER" +export value +IFS='\n' read -r delimiter <<'__CDIST_INPUT_END_HERE_MARKER' $(cat "$__object/parameter/delimiter") __CDIST_INPUT_END_HERE_MARKER -)" -export exact_delimiter="\$(cat <<"__CDIST_INPUT_END_HERE_MARKER" -$exact_delimiter -__CDIST_INPUT_END_HERE_MARKER -)" -export comment="\$(cat <<"__CDIST_INPUT_END_HERE_MARKER" +export delimiter +IFS='\n' read -r comment <<'__CDIST_INPUT_END_HERE_MARKER' $(cat "$__object/parameter/comment") __CDIST_INPUT_END_HERE_MARKER -)" +export comment +export exact_delimiter="$exact_delimiter" tmpfile=\$(mktemp "${file}.cdist.XXXXXXXXXX") # preserve ownership and permissions by copying existing file over tmpfile From fa55cd7d3bd391e16903f9ba930aa7842f8fea65 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 27 Feb 2014 21:08:45 +0100 Subject: [PATCH 2546/4212] ups, typo ... thx to steven --- cdist/conf/type/__key_value/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__key_value/man.text b/cdist/conf/type/__key_value/man.text index 95e00ce9..dabfe928 100644 --- a/cdist/conf/type/__key_value/man.text +++ b/cdist/conf/type/__key_value/man.text @@ -41,7 +41,7 @@ comment:: BOOLEAN PARAMETERS ------------------ exact_delimiter:: - If supplied, thread additional whitespaces between key, delimiter and value + If supplied, treat additional whitespaces between key, delimiter and value as wrong value. From 1c0d74f7db1163b5f673d58ad0481f58c28ec74e Mon Sep 17 00:00:00 2001 From: og Date: Sun, 2 Mar 2014 17:18:25 -0700 Subject: [PATCH 2547/4212] openbsd stat works the same way that freebsd's does --- cdist/conf/type/__file/explorer/stat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__file/explorer/stat b/cdist/conf/type/__file/explorer/stat index 298221b7..52570379 100755 --- a/cdist/conf/type/__file/explorer/stat +++ b/cdist/conf/type/__file/explorer/stat @@ -25,7 +25,7 @@ destination="/$__object_id" os=$("$__explorer/os") case "$os" in - "freebsd") + "freebsd"|"openbsd") # FIXME: should be something like this based on man page, but can not test stat -f "type: %ST owner: %Du %Su From 5cbdf981c0003ba1b958ef7ba937404cc7cf71ed Mon Sep 17 00:00:00 2001 From: og Date: Sun, 2 Mar 2014 17:32:14 -0700 Subject: [PATCH 2548/4212] adding pkg_path parameter to be explicitly set, this is important for using -current, as os_version always parses to a release version (e.g. 5.5) but the path that mirrors have is /snapshots/ --- cdist/conf/type/__package_pkg_openbsd/gencode-remote | 8 ++++++-- cdist/conf/type/__package_pkg_openbsd/parameter/optional | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index 1df87997..9d760655 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -50,8 +50,11 @@ fi pkg_version="$(cat "$__object/explorer/pkg_version")" -# TODO: Shouldn't be hardcoded -echo export PKG_PATH=ftp://ftp.openbsd.org/pub/OpenBSD/$os_version/packages/$machine/ +if [ -f "$__object/parameter/pkg_path" ]; then + pkg_path="$(cat "$__object/parameter/pkg_path")" +else + pkg_path="ftp://ftp.openbsd.org/pub/OpenBSD/$os_version/packages/$machine/" +fi if [ "$pkg_version" ]; then state_is="present" @@ -65,6 +68,7 @@ case "$state_should" in present) # use this because pkg_add doesn't properly handle errors cat << eof +export PKG_PATH="$pkg_path" status=\$(pkg_add "$pkgopts" "$name--$flavor") # no error diff --git a/cdist/conf/type/__package_pkg_openbsd/parameter/optional b/cdist/conf/type/__package_pkg_openbsd/parameter/optional index 77fd22b3..43278d16 100644 --- a/cdist/conf/type/__package_pkg_openbsd/parameter/optional +++ b/cdist/conf/type/__package_pkg_openbsd/parameter/optional @@ -1,3 +1,4 @@ name flavor state +pkg_path From 6a455be63a874b7b63bdde34499f86222e749166 Mon Sep 17 00:00:00 2001 From: og Date: Sun, 2 Mar 2014 17:34:36 -0700 Subject: [PATCH 2549/4212] openbsd and freebsd both use the 'passwd' database --- cdist/conf/type/__user/explorer/shadow | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__user/explorer/shadow b/cdist/conf/type/__user/explorer/shadow index a949ec51..59abaa8a 100755 --- a/cdist/conf/type/__user/explorer/shadow +++ b/cdist/conf/type/__user/explorer/shadow @@ -26,9 +26,10 @@ os="$($__explorer/os)" # Default to using shadow passwords database="shadow" -if [ "$os" = "freebsd" ]; then - database="passwd" -fi +case "$os" in + "freebsd"|"openbsd") database="passwd";; +esac + getent "$database" "$name" || true From ef1f9bf6331add3878fc3c4836e7cf49cb59c95a Mon Sep 17 00:00:00 2001 From: og Date: Sun, 2 Mar 2014 17:44:22 -0700 Subject: [PATCH 2550/4212] updated documentation to reflect new parameter --- cdist/conf/type/__package_pkg_openbsd/man.text | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cdist/conf/type/__package_pkg_openbsd/man.text b/cdist/conf/type/__package_pkg_openbsd/man.text index f523a892..c7de2652 100644 --- a/cdist/conf/type/__package_pkg_openbsd/man.text +++ b/cdist/conf/type/__package_pkg_openbsd/man.text @@ -29,6 +29,8 @@ flavor:: state:: Either "present" or "absent", defaults to "present" +pkg_path:: + Manually specify a PKG_PATH to add packages from. EXAMPLES -------- @@ -45,6 +47,10 @@ __package_pkg_openbsd python --state present --name python2 # Remove obsolete package __package_pkg_openbsd puppet --state absent + +# Add a package using a particular mirror +__package_pkg_openbsd bash \ + --pkg_path http://openbsd.mirrorcatalogs.com/snapshots/packages/amd64 -------------------------------------------------------------------------------- From 19f6126a0f6895a2b28ee58037d24d5b64f6809c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 3 Mar 2014 07:42:27 +0100 Subject: [PATCH 2551/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index 66a83b31..e7ac935d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,10 @@ Changelog next: * Type __git: Pass onwer/group/mode values to __directory * Type __ssh_authorized_keys: Allow managing existing keys (Steven Armstrong) + * Type __iptable_rule: Fix example documentation (Antoine Catton) + * Type __file: Enhance OpenBSD Support (og) + * Type __package_pkg_openbsd: Allow to change PKG_PATH (og) + * Type __user: Enhance OpenBSD Support (og) 3.0.9: 2014-02-14 From 3fffb93150a57786b6db1c1406b93a17bf727e64 Mon Sep 17 00:00:00 2001 From: og Date: Mon, 3 Mar 2014 14:59:50 -0700 Subject: [PATCH 2552/4212] OpenBSD pkg utils does not return properly, so we have to verify success by looking at the list of installed packages after the present/absent actions --- .../type/__package_pkg_openbsd/gencode-remote | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index 9d760655..7583167e 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -69,12 +69,17 @@ case "$state_should" in # use this because pkg_add doesn't properly handle errors cat << eof export PKG_PATH="$pkg_path" -status=\$(pkg_add "$pkgopts" "$name--$flavor") +status=\$(pkg_add "$pkgopts" "$name--$flavor" 2>&1) +pkg_info | grep "^${name}.*${flavor}" > /dev/null 2>&1 -# no error -if [ -n "\$status" ]; then +# We didn't find the package in the list of 'installed packages', so it failed +# This is necessary because pkg_add doesn't return properly +if [ $? -ne 0 ]; then + if [ -z "${status}" ]; then + status="Failed to add package, uncaught exception." + fi echo "Error: \$status" - exit 1 + exit 1 fi eof ;; @@ -83,9 +88,14 @@ eof # use this because pkg_add doesn't properly handle errors cat << eof status=\$(pkg_delete "$pkgopts" "$name--$flavor") +pkg_info | grep "^${name}.*${flavor}" > /dev/null 2>&1 -# no error -if [ -n "\$status" ]; then +# We found the package in the list of 'installed packages' +# This would indicate that pkg_delete failed, send the output of pkg_delete +if [ $? -eq 0 ]; then + if [ -z "${status}" ]; then + status="Failed to remove package, uncaught exception." + fi echo "Error: \$status" exit 1 fi From 074938c697f2671d384f774ecf80d4ee5e2d2c32 Mon Sep 17 00:00:00 2001 From: og Date: Mon, 3 Mar 2014 15:13:57 -0700 Subject: [PATCH 2553/4212] . --- cdist/conf/type/__package_pkg_openbsd/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index 7583167e..e7f40a4d 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -79,7 +79,7 @@ if [ $? -ne 0 ]; then status="Failed to add package, uncaught exception." fi echo "Error: \$status" - exit 1 + exit 1 fi eof ;; From 3d5706d3cc30e556ea6fbf2e6addf8a925362020 Mon Sep 17 00:00:00 2001 From: og Date: Sat, 8 Mar 2014 17:18:19 -0700 Subject: [PATCH 2554/4212] escaped some variables in the gencode-remote output --- cdist/conf/type/__package_pkg_openbsd/gencode-remote | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index e7f40a4d..08e15e89 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -74,8 +74,8 @@ pkg_info | grep "^${name}.*${flavor}" > /dev/null 2>&1 # We didn't find the package in the list of 'installed packages', so it failed # This is necessary because pkg_add doesn't return properly -if [ $? -ne 0 ]; then - if [ -z "${status}" ]; then +if [ \$? -ne 0 ]; then + if [ -z "\${status}" ]; then status="Failed to add package, uncaught exception." fi echo "Error: \$status" @@ -92,8 +92,8 @@ pkg_info | grep "^${name}.*${flavor}" > /dev/null 2>&1 # We found the package in the list of 'installed packages' # This would indicate that pkg_delete failed, send the output of pkg_delete -if [ $? -eq 0 ]; then - if [ -z "${status}" ]; then +if [ \$? -eq 0 ]; then + if [ -z "\${status}" ]; then status="Failed to remove package, uncaught exception." fi echo "Error: \$status" From 0a98abbffadbc8a0c2bdbe087fdbef025cfd4f0a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Mar 2014 15:39:08 +0100 Subject: [PATCH 2555/4212] add messaging support for __key_value Signed-off-by: Nico Schottelius --- cdist/conf/type/__key_value/gencode-remote | 5 ++++- cdist/conf/type/__key_value/man.text | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index b79d9688..e1041a02 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -1,7 +1,7 @@ #!/bin/sh # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -42,12 +42,14 @@ cp -p "$file" "\$tmpfile" sed '/^$key\($delimiter\+\)/d' "$file" > "\$tmpfile" mv -f "\$tmpfile" "$file" DONE + echo "remove" >> "$__messages_out" ;; present) case "$state_is" in absent) # add new key and value printf 'echo "%s%s%s" >> "%s"' "$key" "$delimiter" "$value_escaped" "$file" + echo "add" >> "$__messages_out" ;; wrongvalue) # change exisiting value @@ -58,6 +60,7 @@ cp -p "$file" "\$tmpfile" sed "s|^$key\($delimiter\+\).*|$key\\1$value_escaped|" "$file" > "\$tmpfile" mv -f "\$tmpfile" "$file" DONE + echo "changevalue" >> "$__messages_out" ;; *) echo "Unknown explorer state: $state_is" >&2 diff --git a/cdist/conf/type/__key_value/man.text b/cdist/conf/type/__key_value/man.text index 1423fc7d..7def7139 100644 --- a/cdist/conf/type/__key_value/man.text +++ b/cdist/conf/type/__key_value/man.text @@ -32,6 +32,15 @@ key:: value:: The value for the key. Optional if state=absent, required otherwise. +MESSAGES +-------- +create:: + Added key and value +change:: + Changed value of existing key +remove:: + Removed existing key and value + EXAMPLES -------- From d288ee1cde8dcc5c2d6886e1f6690e0a32152183 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Mar 2014 15:40:44 +0100 Subject: [PATCH 2556/4212] ++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 e7ac935d..9477d8d0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,11 +6,12 @@ Changelog next: - * Type __git: Pass onwer/group/mode values to __directory - * Type __ssh_authorized_keys: Allow managing existing keys (Steven Armstrong) - * Type __iptable_rule: Fix example documentation (Antoine Catton) * Type __file: Enhance OpenBSD Support (og) + * Type __git: Pass onwer/group/mode values to __directory + * Type __iptable_rule: Fix example documentation (Antoine Catton) + * Type __key_value: Add messaging support * Type __package_pkg_openbsd: Allow to change PKG_PATH (og) + * Type __ssh_authorized_keys: Allow managing existing keys (Steven Armstrong) * Type __user: Enhance OpenBSD Support (og) From 75c203a1f05748ff877e986148f43e8e792edb16 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Mar 2014 20:48:47 +0100 Subject: [PATCH 2557/4212] handle existing symlink but wrong source Signed-off-by: Steven Armstrong --- cdist/conf/type/__link/explorer/state | 10 +++++++--- cdist/conf/type/__link/gencode-remote | 9 +++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/cdist/conf/type/__link/explorer/state b/cdist/conf/type/__link/explorer/state index a9220a3c..48278d9e 100755 --- a/cdist/conf/type/__link/explorer/state +++ b/cdist/conf/type/__link/explorer/state @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -34,8 +34,12 @@ case "$type" in symbolic) cd "$destination_dir" source_is=$(ls -l "$destination" | sed 's/.*-> //g') - if [ -h "$destination" -a "$source_is" = "$source" ]; then - echo present + if [ -h "$destination" ]; then + if [ "$source_is" = "$source" ]; then + echo present + else + echo wrongsource + fi else echo absent fi diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote index cbdfd30f..7582863f 100755 --- a/cdist/conf/type/__link/gencode-remote +++ b/cdist/conf/type/__link/gencode-remote @@ -1,7 +1,7 @@ #!/bin/sh # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) -# 2013 Steven Armstrong (steven-cdist at armstrong.cc) +# 2013-2014 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -18,9 +18,6 @@ # 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" @@ -55,6 +52,10 @@ rm -rf "$destination" DONE fi + if [ "$state_is" = "wrongsource" ]; then + printf 'rm -f "%s"\n' "$destination" + fi + # create our link cat << DONE ln ${lnopt} -f "$source" "$destination" From 38c3d551baa512b0d6d56356f6ddd1920908ef5b Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 11 Mar 2014 21:05:31 +0100 Subject: [PATCH 2558/4212] bugfix, if file was absent and type is now tested on openwrt --- cdist/conf/type/__key_value/explorer/state | 6 ++++++ cdist/conf/type/__key_value/gencode-remote | 11 +++++++++-- cdist/conf/type/__key_value/man.text | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__key_value/explorer/state b/cdist/conf/type/__key_value/explorer/state index 8bdd3a1d..6dfb2031 100755 --- a/cdist/conf/type/__key_value/explorer/state +++ b/cdist/conf/type/__key_value/explorer/state @@ -24,6 +24,12 @@ export key="$(cat "$__object/parameter/key" 2>/dev/null \ export state="$(cat "$__object/parameter/state" 2>/dev/null \ || echo "present")" file="$(cat "$__object/parameter/file")" + +if [ ! -f "$file" ]; then + echo "nosuchfile" + exit +fi + export delimiter="$(cat "$__object/parameter/delimiter")" export value="$(cat "$__object/parameter/value" 2>/dev/null \ || echo "__CDIST_NOTSET__")" diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index 62cc745d..ad216f51 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -44,7 +44,7 @@ fi case "$state_should" in absent) case "$state_is" in - absent) + absent|nosuchfile) # nothing to do ;; wrongformat|wrongvalue|present) @@ -58,6 +58,9 @@ case "$state_should" in ;; present) case "$state_is" in + nosuchfile) + echo created >> "$__messages_out" + ;; absent) echo inserted >> "$__messages_out" ;; @@ -104,7 +107,11 @@ export exact_delimiter="$exact_delimiter" tmpfile=\$(mktemp "${file}.cdist.XXXXXXXXXX") # preserve ownership and permissions by copying existing file over tmpfile -cp -p "$file" "\$tmpfile" +if [ -f "$file" ]; then + cp -p "$file" "\$tmpfile" +else + touch "$file" +fi awk -f - "$file" >"\$tmpfile" <<"AWK_EOF" BEGIN { # import variables in a secure way .. diff --git a/cdist/conf/type/__key_value/man.text b/cdist/conf/type/__key_value/man.text index dabfe928..de2d7d65 100644 --- a/cdist/conf/type/__key_value/man.text +++ b/cdist/conf/type/__key_value/man.text @@ -53,6 +53,8 @@ inserted:: A new line was inserted changed:: An existing line was changed +created:: + A new line was inserted in a new file EXAMPLES From 301b4e18ff8fc87f2a10d0c471c93df55fe0abc4 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Mar 2014 21:07:20 +0100 Subject: [PATCH 2559/4212] either to it all, or fail; echo and cat suck, printf ftw! Signed-off-by: Steven Armstrong --- cdist/conf/type/__link/gencode-remote | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote index 7582863f..9e7831c7 100755 --- a/cdist/conf/type/__link/gencode-remote +++ b/cdist/conf/type/__link/gencode-remote @@ -47,24 +47,22 @@ case "$state_should" in present) if [ "$file_type" = "directory" ]; then # our destination is currently a directory, delete it - cat << DONE -rm -rf "$destination" -DONE - fi - - if [ "$state_is" = "wrongsource" ]; then - printf 'rm -f "%s"\n' "$destination" + printf 'rm -rf "%s" &&\n' "$destination" + else + if [ "$state_is" = "wrongsource" ]; then + # our destination is a symlink but points to the wrong source, + # delete it + printf 'rm -f "%s" &&\n' "$destination" + fi fi # create our link - cat << DONE -ln ${lnopt} -f "$source" "$destination" -DONE + printf 'ln %s -f "%s" "%s"\n' "$lnopt" "$source" "$destination" ;; absent) # only delete if it is a sym/hard link if [ "$file_type" = "symlink" -o "$file_type" = "hardlink" ]; then - echo rm -f \"$destination\" + printf 'rm -f "%s"\n' "$destination" fi ;; *) From 5ec617fa3e4dba53a85cad90d75590fea0abf591 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Mar 2014 22:16:08 +0100 Subject: [PATCH 2560/4212] ignore trailing slashes for comparison of source Signed-off-by: Steven Armstrong --- cdist/conf/type/__link/explorer/state | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__link/explorer/state b/cdist/conf/type/__link/explorer/state index 48278d9e..b8d8fc2b 100755 --- a/cdist/conf/type/__link/explorer/state +++ b/cdist/conf/type/__link/explorer/state @@ -35,7 +35,8 @@ case "$type" in cd "$destination_dir" source_is=$(ls -l "$destination" | sed 's/.*-> //g') if [ -h "$destination" ]; then - if [ "$source_is" = "$source" ]; then + # ignore trailing slashes for comparison + if [ "${source_is%/}" = "${source%/}" ]; then echo present else echo wrongsource From 619076bd2da618d51c7a95afd8adcd5a009a0f5a Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 12 Mar 2014 20:16:33 +0100 Subject: [PATCH 2561/4212] corrected a small relict in example --- cdist/conf/type/__key_value/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__key_value/man.text b/cdist/conf/type/__key_value/man.text index bbfd4d48..cf779037 100644 --- a/cdist/conf/type/__key_value/man.text +++ b/cdist/conf/type/__key_value/man.text @@ -70,7 +70,7 @@ __key_value my-fancy-id --file /etc/login.defs --key SYS_UID_MAX --value 666 \ # Enable packet forwarding __key_value net.ipv4.ip_forward --file /etc/sysctl.conf --value 1 \ - --delimiter ' = ' --comment_line '# my linux kernel should act as a router' + --delimiter ' = ' --comment '# my linux kernel should act as a router' # Remove existing key/value __key_value LEGACY_KEY --file /etc/somefile --state absent --delimiter '=' From 2b03ccd776a37bd0bfe0a3ccd7e9ef42ea6b9756 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Mar 2014 18:57:11 +0100 Subject: [PATCH 2562/4212] changes for 3.1.0 Signed-off-by: Nico Schottelius --- cdist/conf/type/__ssh_authorized_keys/manifest | 1 + docs/changelog | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index efcd2d7a..1c9df208 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -58,6 +58,7 @@ if [ ! -f "$__object/parameter/noparent" -o ! -f "$__object/parameter/nofile" ]; fi # Remove legacy blocks created by old versions of this type +# FIXME: remove me in 3.2+ __block "$__object_name" \ --file "$file" \ --prefix "#cdist:$__object_name" \ diff --git a/docs/changelog b/docs/changelog index 9477d8d0..df23d39f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,7 +5,8 @@ Changelog * Exception: No braces means author == Nico Schottelius -next: +3.1.0: 2014-03-19 + * New Type: __rbenv * Type __file: Enhance OpenBSD Support (og) * Type __git: Pass onwer/group/mode values to __directory * Type __iptable_rule: Fix example documentation (Antoine Catton) @@ -14,7 +15,6 @@ next: * Type __ssh_authorized_keys: Allow managing existing keys (Steven Armstrong) * Type __user: Enhance OpenBSD Support (og) - 3.0.9: 2014-02-14 * Core: Ignore order dependencies if override is set (Daniel Heule) * Core: Improve Mac OS X support for unit tests (Steven Armstrong) From 9a79cec140ce76230e078e3c47abcad83950145c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Mar 2014 18:58:54 +0100 Subject: [PATCH 2563/4212] remove useless error in build script 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 1de2eb94..93401d3b 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -175,7 +175,7 @@ eof release-git-tag) target_version=$($0 changelog-version) - if git rev-parse --verify refs/tags/$target_version; then + if git rev-parse --verify refs/tags/$target_version 2>/dev/null; then echo "Tag for $target_version exists, aborting" exit 1 fi From 10a71eb35a8aa9cfa356e6bc79f42ff12ddfa34a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Mar 2014 19:00:39 +0100 Subject: [PATCH 2564/4212] notes for 3.0 -> 3.1 update 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 2e3e9b92..28f41da7 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 3.0 to 3.1 + +The type **\_\_ssh_authorized_keys** now also manages existing keys, +not only the ones added by cdist. + ### Updating from 2.3 to 3.0 The **changed** attribute of objects has been removed. From 5ef27191fca6b60f6a02664cb7799e45de052674 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 20 Mar 2014 13:52:12 +0100 Subject: [PATCH 2565/4212] implementing the $__object and $__object_id on the local and remote execution call, to allow read access to parameter files --- cdist/core/code.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/cdist/core/code.py b/cdist/core/code.py index f128697f..6abfb393 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -123,15 +123,27 @@ class Code(object): self.remote.mkdir(destination) self.remote.transfer(source, destination) - def _run_code(self, cdist_object, which): + def _run_code(self, cdist_object, which, env=None): which_exec = getattr(self, which) script = os.path.join(which_exec.object_path, getattr(cdist_object, 'code_%s_path' % which)) - return which_exec.run_script(script) + return which_exec.run_script(script, env=env) def run_code_local(self, cdist_object): """Run the code-local script for the given cdist object.""" - return self._run_code(cdist_object, 'local') + # Put some env vars, to allow read only access to the parameters over $__object + env = os.environ.copy() + env.update(self.env) + env.update({ + '__object': cdist_object.absolute_path, + '__object_id': cdist_object.object_id, + }) + return self._run_code(cdist_object, 'local', env=env) def run_code_remote(self, cdist_object): """Run the code-remote script for the given cdist object on the remote side.""" - return self._run_code(cdist_object, 'remote') + # Put some env vars, to allow read only access to the parameters over $__object which is already on the remote side + env = { + '__object': os.path.join(self.remote.object_path, cdist_object.path), + '__object_id': cdist_object.object_id, + } + return self._run_code(cdist_object, 'remote', env=env) From b87b5eab31d38c1685e3c30056c7c18fd55531ff Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 20 Mar 2014 16:23:28 +0100 Subject: [PATCH 2566/4212] documentation to __object in execution run --- docs/man/cdist-reference.text.sh | 14 ++++++++------ docs/man/man7/cdist-type.text | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 62614c55..6552bf82 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -157,13 +157,13 @@ TYPES The following types are available: eof - -for type in man7/cdist-type__*.text; do +set -x +for type in man7/cdist-type__*.html; do no_dir="${type#man7/}"; no_type="${no_dir#cdist-type}"; - name="${no_type%.text}"; + name="${no_type%.html}"; name_no_underline="$(echo $name | sed 's/^__/\\__/g')" - man="${no_dir%.text}(7)" + man="${no_dir%.html}(7)" echo "- $name_no_underline" "($man)" done @@ -209,10 +209,12 @@ __messages_out:: Available for: initial manifest, type manifest, type gencode __object:: Directory that contains the current object. - Available for: type manifest, type explorer, type gencode + Available for: type manifest, type explorer, type gencode and + at the execution of the gencode scripts __object_id:: The type unique object id. - Available for: type manifest, type explorer, type gencode + Available for: type manifest, type explorer, type gencode and + at the execution of the gencode scripts Note: The leading and the trailing "/" will always be stripped (caused by the filesystem database and ensured by the core). Note: Double slashes ("//") will not be fixed and result in an error. diff --git a/docs/man/man7/cdist-type.text b/docs/man/man7/cdist-type.text index 8415f991..06026542 100644 --- a/docs/man/man7/cdist-type.text +++ b/docs/man/man7/cdist-type.text @@ -252,6 +252,27 @@ echo "touch /etc/cdist-configured" -------------------------------------------------------------------------------- +VARIABLE ACCESS FROM THE GENERATED SCRIPTS +------------------------------------------ +In the generated scripts, you have access to the following cdist variables + +- __object +- __object_id + +but only for read operations, means there is no back copy of this +files after the script execution. + +So when you generate a script with the following content, it will work: + +-------------------------------------------------------------------------------- +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi +-------------------------------------------------------------------------------- + + HINTS FOR TYPEWRITERS ---------------------- It must be assumed that the target is pretty dumb and thus does not have high From f36dc1160153558f1d83d8490fc091186e193619 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 20 Mar 2014 17:22:07 +0100 Subject: [PATCH 2567/4212] forgot myself to the headers .. --- cdist/core/code.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/core/code.py b/cdist/core/code.py index 6abfb393..5374bcdf 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.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. # From b5b1a25e4ff00b6a8dd9531f567447ffeb096aac Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 20 Mar 2014 18:53:19 +0100 Subject: [PATCH 2568/4212] fixed some formulations and removed a debug statement --- docs/man/cdist-reference.text.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 6552bf82..28c46fa6 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -1,6 +1,7 @@ #!/bin/sh # # 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -157,7 +158,7 @@ TYPES The following types are available: eof -set -x + for type in man7/cdist-type__*.html; do no_dir="${type#man7/}"; no_type="${no_dir#cdist-type}"; @@ -209,12 +210,10 @@ __messages_out:: Available for: initial manifest, type manifest, type gencode __object:: Directory that contains the current object. - Available for: type manifest, type explorer, type gencode and - at the execution of the gencode scripts + Available for: type manifest, type explorer, type gencode and code scripts __object_id:: The type unique object id. - Available for: type manifest, type explorer, type gencode and - at the execution of the gencode scripts + Available for: type manifest, type explorer, type gencode and code scripts Note: The leading and the trailing "/" will always be stripped (caused by the filesystem database and ensured by the core). Note: Double slashes ("//") will not be fixed and result in an error. From e1766aa070de2c7de99b52428758be60d0137a10 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 20 Mar 2014 19:04:09 +0100 Subject: [PATCH 2569/4212] reverted the change to .html in generating the reference, since I have fooled myself ... --- docs/man/cdist-reference.text.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 28c46fa6..cff0f9c7 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -159,12 +159,12 @@ The following types are available: eof -for type in man7/cdist-type__*.html; do +for type in man7/cdist-type__*.text; do no_dir="${type#man7/}"; no_type="${no_dir#cdist-type}"; - name="${no_type%.html}"; + name="${no_type%.text}"; name_no_underline="$(echo $name | sed 's/^__/\\__/g')" - man="${no_dir%.html}(7)" + man="${no_dir%.text}(7)" echo "- $name_no_underline" "($man)" done From 6e4533cb145165a88f8bec1ffbf347fb0f20a774 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Mar 2014 20:40:04 +0100 Subject: [PATCH 2570/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index df23d39f..7db43304 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius +3.1.1: + * Core: Make __object and __object available to code (Daniel Heule) + 3.1.0: 2014-03-19 * New Type: __rbenv * Type __file: Enhance OpenBSD Support (og) From b7fb973fa5de1e2fc2bdc8f1fdb46572b6416d10 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Fri, 21 Mar 2014 09:35:47 +0100 Subject: [PATCH 2571/4212] bugfix for whitespace stripping, its no more simple --- cdist/conf/type/__key_value/explorer/state | 4 +- .../type/__key_value/files/remote_script.sh | 104 +++++++++++++++ cdist/conf/type/__key_value/gencode-remote | 121 +----------------- 3 files changed, 107 insertions(+), 122 deletions(-) create mode 100644 cdist/conf/type/__key_value/files/remote_script.sh diff --git a/cdist/conf/type/__key_value/explorer/state b/cdist/conf/type/__key_value/explorer/state index 6dfb2031..b990733d 100755 --- a/cdist/conf/type/__key_value/explorer/state +++ b/cdist/conf/type/__key_value/explorer/state @@ -21,8 +21,8 @@ export key="$(cat "$__object/parameter/key" 2>/dev/null \ || echo "$__object_id")" -export state="$(cat "$__object/parameter/state" 2>/dev/null \ - || echo "present")" +export state="$(cat "$__object/parameter/state")" + file="$(cat "$__object/parameter/file")" if [ ! -f "$file" ]; then diff --git a/cdist/conf/type/__key_value/files/remote_script.sh b/cdist/conf/type/__key_value/files/remote_script.sh new file mode 100644 index 00000000..2ed43366 --- /dev/null +++ b/cdist/conf/type/__key_value/files/remote_script.sh @@ -0,0 +1,104 @@ +#!/bin/sh + +export key="$(cat "$__object/parameter/key" 2>/dev/null \ + || echo "$__object_id")" +export state="$(cat "$__object/parameter/state")" + +file="$(cat "$__object/parameter/file")" + +export delimiter="$(cat "$__object/parameter/delimiter")" +export value="$(cat "$__object/parameter/value" 2>/dev/null \ + || echo "__CDIST_NOTSET__")" +if [ -f "$__object/parameter/exact_delimiter" ]; then + export exact_delimiter=1 +else + export exact_delimiter=0 +fi + +tmpfile=$(mktemp "${file}.cdist.XXXXXXXXXX") +# preserve ownership and permissions by copying existing file over tmpfile +if [ -f "$file" ]; then + cp -p "$file" "$tmpfile" +else + touch "$file" +fi +awk -f - "$file" >"$tmpfile" <<"AWK_EOF" +BEGIN { + # import variables in a secure way .. + state=ENVIRON["state"] + key=ENVIRON["key"] + delimiter=ENVIRON["delimiter"] + value=ENVIRON["value"] + comment=ENVIRON["comment"] + exact_delimiter=ENVIRON["exact_delimiter"] + inserted=0 + ll="" + llpopulated=0 + line=key delimiter value +} +# enter the main loop +{ + # I dont use regex, this is by design, so we can match against every value without special meanings of chars ... + i = index($0,key) + if(i == 1) { + delval = substr($0,length(key)+1) + delpos = index(delval,delimiter) + if(delpos > 1) { + spaces = substr(delval,1,delpos-1) + sub(/[ \t]*/,"",spaces) + if( length(spaces) > 0 ) { + # if there are not only spaces between key and delimiter, + # continue since we we are on the wrong line + if(llpopulated == 1) { + print ll + } + ll=$0 + llpopulated=1 + next + } + } + if(state == "absent") { + if(ll == comment) { + # if comment is present, clear llpopulated flag + llpopulated=0 + } + # if absent, simple yump over this line + next + } + else { + # if comment is present and not present in last line + if (llpopulated == 1) { + print ll + if( comment != "" && ll != comment) { + print comment + } + llpopulated=0 + } + inserted=1 + # state is present, so insert correct line here + print line + ll=line + next + } + } + else { + if(llpopulated == 1) { + print ll + } + ll=$0 + llpopulated=1 + } +} +END { + if(llpopulated == 1) { + print ll + } + if(inserted == 0 && state == "present" ) { + if(comment != "" && ll != comment){ + print comment + } + print line + } +} +AWK_EOF +mv -f "$tmpfile" "$file" diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index f1744ac1..e6815cb6 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -28,15 +28,6 @@ if [ "$state_is" = "$state_should" ]; then exit 0 fi -file="$(cat "$__object/parameter/file")" -key="$__object_id" -[ -f "$__object/parameter/key" ] && key="$(cat "$__object/parameter/key")" -if [ -f "$__object/parameter/exact_delimiter" ]; then - export exact_delimiter=1 -else - export exact_delimiter=0 -fi - # here we check only if the states are valid, # emmit messages and # let awk do the work ... @@ -81,114 +72,4 @@ case "$state_should" in ;; esac -cat <<__CDIST_HEREDOC_END_HERE_MARKER -IFS='\n' read -r state <<'__CDIST_INPUT_END_HERE_MARKER' -$state_should -__CDIST_INPUT_END_HERE_MARKER -export state -IFS='\n' read -r key <<'__CDIST_INPUT_END_HERE_MARKER' -$key -__CDIST_INPUT_END_HERE_MARKER -export key -IFS='\n' read -r value <<'__CDIST_INPUT_END_HERE_MARKER' -$(cat "$__object/parameter/value") -__CDIST_INPUT_END_HERE_MARKER -export value -IFS='\n' read -r delimiter <<'__CDIST_INPUT_END_HERE_MARKER' -$(cat "$__object/parameter/delimiter") -__CDIST_INPUT_END_HERE_MARKER -export delimiter -IFS='\n' read -r comment <<'__CDIST_INPUT_END_HERE_MARKER' -$(cat "$__object/parameter/comment") -__CDIST_INPUT_END_HERE_MARKER -export comment -export exact_delimiter="$exact_delimiter" - -tmpfile=\$(mktemp "${file}.cdist.XXXXXXXXXX") -# preserve ownership and permissions by copying existing file over tmpfile -if [ -f "$file" ]; then - cp -p "$file" "\$tmpfile" -else - touch "$file" -fi -awk -f - "$file" >"\$tmpfile" <<"AWK_EOF" -BEGIN { - # import variables in a secure way .. - state=ENVIRON["state"] - key=ENVIRON["key"] - delimiter=ENVIRON["delimiter"] - value=ENVIRON["value"] - comment=ENVIRON["comment"] - exact_delimiter=ENVIRON["exact_delimiter"] - inserted=0 - ll="" - llpopulated=0 - line=key delimiter value -} -# enter the main loop -{ - # I dont use regex, this is by design, so we can match against every value without special meanings of chars ... - i = index(\$0,key) - if(i == 1) { - delval = substr(\$0,length(key)+1) - delpos = index(delval,delimiter) - if(delpos > 1) { - spaces = substr(delval,1,delpos-1) - sub(/[ \t]*/,"",spaces) - if( length(spaces) > 0 ) { - # if there are not only spaces between key and delimiter, - # continue since we we are on the wrong line - if(llpopulated == 1) { - print ll - } - ll=\$0 - llpopulated=1 - next - } - } - if(state == "absent") { - if(ll == comment) { - # if comment is present, clear llpopulated flag - llpopulated=0 - } - # if absent, simple yump over this line - next - } - else { - # if comment is present and not present in last line - if (llpopulated == 1) { - print ll - if( comment != "" && ll != comment) { - print comment - } - llpopulated=0 - } - inserted=1 - # state is present, so insert correct line here - print line - ll=line - next - } - } - else { - if(llpopulated == 1) { - print ll - } - ll=\$0 - llpopulated=1 - } -} -END { - if(llpopulated == 1) { - print ll - } - if(inserted == 0 && state == "present" ) { - if(comment != "" && ll != comment){ - print comment - } - print line - } -} -AWK_EOF -mv -f "\$tmpfile" "$file" -__CDIST_HEREDOC_END_HERE_MARKER +cat "$__type/files/remote_script.sh" From c31278bcd09e4da521b9b72566a2fe3b8bd218c9 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Tue, 25 Mar 2014 12:50:27 -0400 Subject: [PATCH 2572/4212] Fix __jail explorers Only fixed gencode*, manifest in PR #279, fixed explorers here --- cdist/conf/type/__jail/explorer/basepresent | 2 +- cdist/conf/type/__jail/explorer/present | 2 +- cdist/conf/type/__jail/explorer/status | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__jail/explorer/basepresent b/cdist/conf/type/__jail/explorer/basepresent index f167a19c..034128d5 100755 --- a/cdist/conf/type/__jail/explorer/basepresent +++ b/cdist/conf/type/__jail/explorer/basepresent @@ -26,7 +26,7 @@ #set -x 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/explorer/present b/cdist/conf/type/__jail/explorer/present index 2ba3b2af..ddfb805c 100755 --- a/cdist/conf/type/__jail/explorer/present +++ b/cdist/conf/type/__jail/explorer/present @@ -32,7 +32,7 @@ else 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/explorer/status b/cdist/conf/type/__jail/explorer/status index fe81eaf7..06f7d063 100755 --- a/cdist/conf/type/__jail/explorer/status +++ b/cdist/conf/type/__jail/explorer/status @@ -32,7 +32,7 @@ else fi if [ -f "$__object/parameter/jaildir" ]; then - jaildir="$(cat "$__object/parameter/name")" + jaildir="$(cat "$__object/parameter/jaildir")" else jaildir="/usr/jail" fi From bae472eb33095dcad9cd032cc3a19345155565bd Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 26 Mar 2014 10:41:00 +0100 Subject: [PATCH 2573/4212] fixed some typos in the man page --- cdist/conf/type/__key_value/man.text | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__key_value/man.text b/cdist/conf/type/__key_value/man.text index cf779037..d4c8e2cc 100644 --- a/cdist/conf/type/__key_value/man.text +++ b/cdist/conf/type/__key_value/man.text @@ -79,11 +79,8 @@ __key_value LEGACY_KEY --file /etc/somefile --state absent --delimiter '=' MORE INFORMATION ---------------- -This type try to handle as many values as possible, so it doen't use regexes. -So you need to exatly specify the key and delimiter. Delimiter can be of any lenght. -Due to shell limitations, we have some values which you can't use, this values are: -__CDIST_HEREDOC_END_HERE_MARKER -__CDIST_INPUT_END_HERE_MARKER +This type try to handle as many values as possible, so it doesn't use regexes. +So you need to exactly specify the key and delimiter. Delimiter can be of any lenght. SEE ALSO From dfdd77eff4ecba79cd7d09337fba3c621ae00b24 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 26 Mar 2014 11:00:38 +0100 Subject: [PATCH 2574/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 7db43304..54c5cf8c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 3.1.1: * Core: Make __object and __object available to code (Daniel Heule) + * Type __line: Ensure permissions are kept (Steven Armstrong) 3.1.0: 2014-03-19 * New Type: __rbenv From 653012ee5fc153cf555113b03a79c94f04c6efe2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 26 Mar 2014 11:17:16 +0100 Subject: [PATCH 2575/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 54c5cf8c..5cafc436 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ Changelog 3.1.1: * Core: Make __object and __object available to code (Daniel Heule) * Type __line: Ensure permissions are kept (Steven Armstrong) + * Type __link: Do not create link in directory, if link exists (Steven Armstrong) 3.1.0: 2014-03-19 * New Type: __rbenv From ae477d69c8975a13033444cdbab2cb669b113241 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 26 Mar 2014 11:18:35 +0100 Subject: [PATCH 2576/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 5cafc436..2dce48e4 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ Changelog * Core: Make __object and __object available to code (Daniel Heule) * Type __line: Ensure permissions are kept (Steven Armstrong) * Type __link: Do not create link in directory, if link exists (Steven Armstrong) + * Type __package_pkg_openbsd: Improve error handling (og) 3.1.0: 2014-03-19 * New Type: __rbenv From 94c7d4cacfa24f5bc1b24a743c95b713f0dbd675 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 26 Mar 2014 11:20:54 +0100 Subject: [PATCH 2577/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 2dce48e4..3194b5ee 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 3.1.1: * Core: Make __object and __object available to code (Daniel Heule) + * Type __jail: Fix parameter names in explorer (Jake Guffey) * Type __line: Ensure permissions are kept (Steven Armstrong) * Type __link: Do not create link in directory, if link exists (Steven Armstrong) * Type __package_pkg_openbsd: Improve error handling (og) From 7b6102750e6511243217622bd8291880918b4c6a Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 26 Mar 2014 11:57:15 +0100 Subject: [PATCH 2578/4212] as requested, replace space with _ --- cdist/conf/explorer/machine_type | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/conf/explorer/machine_type b/cdist/conf/explorer/machine_type index 60b7f5e2..74789f5a 100755 --- a/cdist/conf/explorer/machine_type +++ b/cdist/conf/explorer/machine_type @@ -29,23 +29,23 @@ if [ -r /proc/cpuinfo ]; then # this file is aviable in xen guest systems if [ -r /sys/hypervisor/type ]; then if grep -q -i "xen" /sys/hypervisor/type; then - echo virtual by xen + echo virtual_by_xen exit fi else if [ -r /sys/class/dmi/id/product_name ]; then if grep -q -i 'vmware' /sys/class/dmi/id/product_name; then - echo "virtual by vmware" + echo "virtual_by_vmware" exit else if grep -q -i 'bochs' /sys/class/dmi/id/product_name; then - echo "virtual by kvm" + echo "virtual_by_kvm" exit fi fi fi fi - echo "virtual by unknown" + echo "virtual_by_unknown" else echo "physical" fi From c3de952d559fa4d71e6c161179d2584a56310d38 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 26 Mar 2014 13:09:48 +0100 Subject: [PATCH 2579/4212] release date for 3.1.1 Signed-off-by: Nico Schottelius --- docs/changelog | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 3194b5ee..78c856aa 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,8 +5,12 @@ Changelog * Exception: No braces means author == Nico Schottelius -3.1.1: +3.1.1: 2014-03-26 * Core: Make __object and __object available to code (Daniel Heule) + * New explorer: cpu_cores (Daniel Heule/Thomas Oettli) + * New explorer: cpu_sockets (Daniel Heule/Thomas Oettli) + * New explorer: machine_type (Daniel Heule/Thomas Oettli) + * New explorer: memory (Daniel Heule/Thomas Oettli) * Type __jail: Fix parameter names in explorer (Jake Guffey) * Type __line: Ensure permissions are kept (Steven Armstrong) * Type __link: Do not create link in directory, if link exists (Steven Armstrong) From 63347497ad2a8ee00f7b032ba4abfe72f826190f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 26 Mar 2014 13:14:26 +0100 Subject: [PATCH 2580/4212] --typo before 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 78c856aa..8b66e95b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,7 +6,7 @@ Changelog 3.1.1: 2014-03-26 - * Core: Make __object and __object available to code (Daniel Heule) + * Core: Make __object and __object_id available to code (Daniel Heule) * New explorer: cpu_cores (Daniel Heule/Thomas Oettli) * New explorer: cpu_sockets (Daniel Heule/Thomas Oettli) * New explorer: machine_type (Daniel Heule/Thomas Oettli) From 50316902e3d7fecbd39b4fa31b7aa5b3f5f4eaf2 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 26 Mar 2014 13:58:29 +0100 Subject: [PATCH 2581/4212] renamed ll to lastline, hope its now clear what the var is for .. --- .../type/__key_value/files/remote_script.sh | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/cdist/conf/type/__key_value/files/remote_script.sh b/cdist/conf/type/__key_value/files/remote_script.sh index 2ed43366..282ba531 100644 --- a/cdist/conf/type/__key_value/files/remote_script.sh +++ b/cdist/conf/type/__key_value/files/remote_script.sh @@ -1,5 +1,3 @@ -#!/bin/sh - export key="$(cat "$__object/parameter/key" 2>/dev/null \ || echo "$__object_id")" export state="$(cat "$__object/parameter/state")" @@ -32,8 +30,8 @@ BEGIN { comment=ENVIRON["comment"] exact_delimiter=ENVIRON["exact_delimiter"] inserted=0 - ll="" - llpopulated=0 + lastline="" + lastlinepopulated=0 line=key delimiter value } # enter the main loop @@ -49,52 +47,52 @@ BEGIN { if( length(spaces) > 0 ) { # if there are not only spaces between key and delimiter, # continue since we we are on the wrong line - if(llpopulated == 1) { - print ll + if(lastlinepopulated == 1) { + print lastline } - ll=$0 - llpopulated=1 + lastline=$0 + lastlinepopulated=1 next } } if(state == "absent") { - if(ll == comment) { - # if comment is present, clear llpopulated flag - llpopulated=0 + if(lastline == comment) { + # if comment is present, clear lastlinepopulated flag + lastlinepopulated=0 } # if absent, simple yump over this line next } else { # if comment is present and not present in last line - if (llpopulated == 1) { - print ll - if( comment != "" && ll != comment) { + if (lastlinepopulated == 1) { + print lastline + if( comment != "" && lastline != comment) { print comment } - llpopulated=0 + lastlinepopulated=0 } inserted=1 # state is present, so insert correct line here print line - ll=line + lastline=line next } } else { - if(llpopulated == 1) { - print ll + if(lastlinepopulated == 1) { + print lastline } - ll=$0 - llpopulated=1 + lastline=$0 + lastlinepopulated=1 } } END { - if(llpopulated == 1) { - print ll + if(lastlinepopulated == 1) { + print lastline } if(inserted == 0 && state == "present" ) { - if(comment != "" && ll != comment){ + if(comment != "" && lastline != comment){ print comment } print line From ff8f7ac2878fff4bec02ba7dcd7333b498a4d52c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 30 Mar 2014 13:09:38 +0200 Subject: [PATCH 2582/4212] add copied version __dog_vdi from __qemu_img Signed-off-by: Nico Schottelius --- cdist/conf/type/__dog_vdi/explorer/list | 23 +++++++++ cdist/conf/type/__dog_vdi/gencode-remote | 19 +++++++ cdist/conf/type/__dog_vdi/man.text | 50 +++++++++++++++++++ .../type/__dog_vdi/parameter/default/format | 1 + .../type/__dog_vdi/parameter/default/state | 1 + cdist/conf/type/__dog_vdi/parameter/optional | 2 + cdist/conf/type/__dog_vdi/parameter/required | 1 + 7 files changed, 97 insertions(+) create mode 100755 cdist/conf/type/__dog_vdi/explorer/list create mode 100644 cdist/conf/type/__dog_vdi/gencode-remote create mode 100644 cdist/conf/type/__dog_vdi/man.text create mode 100644 cdist/conf/type/__dog_vdi/parameter/default/format create mode 100644 cdist/conf/type/__dog_vdi/parameter/default/state create mode 100644 cdist/conf/type/__dog_vdi/parameter/optional create mode 100644 cdist/conf/type/__dog_vdi/parameter/required diff --git a/cdist/conf/type/__dog_vdi/explorer/list b/cdist/conf/type/__dog_vdi/explorer/list new file mode 100755 index 00000000..856c86fc --- /dev/null +++ b/cdist/conf/type/__dog_vdi/explorer/list @@ -0,0 +1,23 @@ +#!/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" + +dog vdi list -r "$name" diff --git a/cdist/conf/type/__dog_vdi/gencode-remote b/cdist/conf/type/__dog_vdi/gencode-remote new file mode 100644 index 00000000..6e4bb4d0 --- /dev/null +++ b/cdist/conf/type/__dog_vdi/gencode-remote @@ -0,0 +1,19 @@ +################################################################################ +# State: absent is handled by manifest - we need only to do stuff if image is +# not existing and state != absent +# +state="$(cat "$__object/parameter/state")" +[ "$state" = "absent" ] && exit 0 + +exists="$(cat "$__object/explorer/exists")" +[ "$exists" ] && exit 0 + +################################################################################ +# Still there? Create image +# + +format="$(cat "$__object/parameter/format")" +size="$(cat "$__object/parameter/size")" +diskimage="/$__object_id" + +echo qemu-img create -f \"$format\" \"$diskimage\" \"$size\" diff --git a/cdist/conf/type/__dog_vdi/man.text b/cdist/conf/type/__dog_vdi/man.text new file mode 100644 index 00000000..444ab15d --- /dev/null +++ b/cdist/conf/type/__dog_vdi/man.text @@ -0,0 +1,50 @@ +cdist-type__dog_vdi(7) +====================== +Nico Schottelius + + +NAME +---- +cdist-type__dog_vdi - Manage Sheepdog VM images + + +DESCRIPTION +----------- +The dog program is used to create qemu images for +qemu and (qemu-)kvm. + + +REQUIRED PARAMETERS +------------------- +size:: + Size of the image in dog vdi compatible units. + + +OPTIONAL PARAMETERS +------------------- +state:: + Either "present" or "absent", defaults to "present" + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Create a 50G size image +__dog_vdi nico-privat.sky.ungleich.ch --size 50G + +# Remove image +__dog_vdi nico-privat.sky.ungleich.ch --state absent +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- dog(8) + + +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/__dog_vdi/parameter/default/format b/cdist/conf/type/__dog_vdi/parameter/default/format new file mode 100644 index 00000000..e0a90ab9 --- /dev/null +++ b/cdist/conf/type/__dog_vdi/parameter/default/format @@ -0,0 +1 @@ +qcow2 diff --git a/cdist/conf/type/__dog_vdi/parameter/default/state b/cdist/conf/type/__dog_vdi/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__dog_vdi/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__dog_vdi/parameter/optional b/cdist/conf/type/__dog_vdi/parameter/optional new file mode 100644 index 00000000..71b9a32b --- /dev/null +++ b/cdist/conf/type/__dog_vdi/parameter/optional @@ -0,0 +1,2 @@ +format +state diff --git a/cdist/conf/type/__dog_vdi/parameter/required b/cdist/conf/type/__dog_vdi/parameter/required new file mode 100644 index 00000000..2a613ba5 --- /dev/null +++ b/cdist/conf/type/__dog_vdi/parameter/required @@ -0,0 +1 @@ +size From b22b581b671fa9816f82efda3dc1d60f246f499e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 31 Mar 2014 14:26:14 +0200 Subject: [PATCH 2583/4212] first version of __dog_vdi Signed-off-by: Nico Schottelius --- cdist/conf/type/__dog_vdi/gencode-remote | 53 +++++++++++++------ cdist/conf/type/__dog_vdi/man.text | 22 +++++--- cdist/conf/type/__dog_vdi/manifest | 28 ++++++++++ .../type/__dog_vdi/parameter/default/format | 1 - cdist/conf/type/__dog_vdi/parameter/optional | 2 +- cdist/conf/type/__dog_vdi/parameter/required | 1 - 6 files changed, 81 insertions(+), 26 deletions(-) create mode 100644 cdist/conf/type/__dog_vdi/manifest delete mode 100644 cdist/conf/type/__dog_vdi/parameter/default/format delete mode 100644 cdist/conf/type/__dog_vdi/parameter/required diff --git a/cdist/conf/type/__dog_vdi/gencode-remote b/cdist/conf/type/__dog_vdi/gencode-remote index 6e4bb4d0..56e4108a 100644 --- a/cdist/conf/type/__dog_vdi/gencode-remote +++ b/cdist/conf/type/__dog_vdi/gencode-remote @@ -1,19 +1,42 @@ -################################################################################ -# State: absent is handled by manifest - we need only to do stuff if image is -# not existing and state != absent +#!/bin/sh # -state="$(cat "$__object/parameter/state")" -[ "$state" = "absent" ] && exit 0 - -exists="$(cat "$__object/explorer/exists")" -[ "$exists" ] && exit 0 - -################################################################################ -# Still there? Create image +# 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 . # -format="$(cat "$__object/parameter/format")" -size="$(cat "$__object/parameter/size")" -diskimage="/$__object_id" +state_should="$(cat "$__object/parameter/state")" +num_vdi_lines=$(wc -l < "$__object/explorer/list") +name="$__object_id" -echo qemu-img create -f \"$format\" \"$diskimage\" \"$size\" + +if [ "$num_vdi_lines" = 1 ]; then + state_is=present +else + state_is=absent +fi + +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + size="$(cat "$__object/parameter/size")" + echo "dog vdi create '$name' '$size'" + ;; + absent) + echo "dog vdi delete '$name'" + ;; +esac diff --git a/cdist/conf/type/__dog_vdi/man.text b/cdist/conf/type/__dog_vdi/man.text index 444ab15d..d7cc6f88 100644 --- a/cdist/conf/type/__dog_vdi/man.text +++ b/cdist/conf/type/__dog_vdi/man.text @@ -10,20 +10,19 @@ cdist-type__dog_vdi - Manage Sheepdog VM images DESCRIPTION ----------- -The dog program is used to create qemu images for -qemu and (qemu-)kvm. - - -REQUIRED PARAMETERS -------------------- -size:: - Size of the image in dog vdi compatible units. +The dog program is used to create images for sheepdog +to be used in qemu. OPTIONAL PARAMETERS ------------------- state:: Either "present" or "absent", defaults to "present" +size:: + Size of the image in dog vdi compatible units. + + Required if state == present. + EXAMPLES @@ -33,8 +32,14 @@ EXAMPLES # Create a 50G size image __dog_vdi nico-privat.sky.ungleich.ch --size 50G +# Create a 50G size image (more explicit) +__dog_vdi nico-privat.sky.ungleich.ch --size 50G --state present + # Remove image __dog_vdi nico-privat.sky.ungleich.ch --state absent + +# Remove image - keeping --size is ok +__dog_vdi nico-privat.sky.ungleich.ch --size 50G --state absent -------------------------------------------------------------------------------- @@ -42,6 +47,7 @@ SEE ALSO -------- - cdist-type(7) - dog(8) +- qemu(1) COPYING diff --git a/cdist/conf/type/__dog_vdi/manifest b/cdist/conf/type/__dog_vdi/manifest new file mode 100644 index 00000000..cd022f28 --- /dev/null +++ b/cdist/conf/type/__dog_vdi/manifest @@ -0,0 +1,28 @@ +#!/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 . +# + +state_should="$(cat "$__object/parameter/state")" + +if [ "$state_should" = "present" ]; then + if [ ! -f "$__object/parameter/size" ]; then + echo "Size is required when state is present" >&2 + exit 1 + fi +fi diff --git a/cdist/conf/type/__dog_vdi/parameter/default/format b/cdist/conf/type/__dog_vdi/parameter/default/format deleted file mode 100644 index e0a90ab9..00000000 --- a/cdist/conf/type/__dog_vdi/parameter/default/format +++ /dev/null @@ -1 +0,0 @@ -qcow2 diff --git a/cdist/conf/type/__dog_vdi/parameter/optional b/cdist/conf/type/__dog_vdi/parameter/optional index 71b9a32b..c3ac4490 100644 --- a/cdist/conf/type/__dog_vdi/parameter/optional +++ b/cdist/conf/type/__dog_vdi/parameter/optional @@ -1,2 +1,2 @@ -format state +size diff --git a/cdist/conf/type/__dog_vdi/parameter/required b/cdist/conf/type/__dog_vdi/parameter/required deleted file mode 100644 index 2a613ba5..00000000 --- a/cdist/conf/type/__dog_vdi/parameter/required +++ /dev/null @@ -1 +0,0 @@ -size From b7f8b5e33951f931cb6be12ac892d914dd0a4cba Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 31 Mar 2014 21:22:15 +0200 Subject: [PATCH 2584/4212] catch unsupported state cases in __dog_vdi und __qemu_img Signed-off-by: Nico Schottelius --- cdist/conf/type/__dog_vdi/manifest | 18 ++++++++++----- cdist/conf/type/__qemu_img/manifest | 22 ++++++++++++++----- cdist/conf/type/__qemu_img/parameter/required | 1 - 3 files changed, 30 insertions(+), 11 deletions(-) delete mode 100644 cdist/conf/type/__qemu_img/parameter/required diff --git a/cdist/conf/type/__dog_vdi/manifest b/cdist/conf/type/__dog_vdi/manifest index cd022f28..ab533c4b 100644 --- a/cdist/conf/type/__dog_vdi/manifest +++ b/cdist/conf/type/__dog_vdi/manifest @@ -20,9 +20,17 @@ state_should="$(cat "$__object/parameter/state")" -if [ "$state_should" = "present" ]; then - if [ ! -f "$__object/parameter/size" ]; then - echo "Size is required when state is present" >&2 +case "$state_should" in + present) + if [ ! -f "$__object/parameter/size" ]; then + echo "Size is required when state is present" >&2 + exit 1 + fi + absent) + : + ;; + *) + echo "Unsupported state: $state_should" >&2 exit 1 - fi -fi + ;; +esac diff --git a/cdist/conf/type/__qemu_img/manifest b/cdist/conf/type/__qemu_img/manifest index 6d50037f..bb2c9366 100644 --- a/cdist/conf/type/__qemu_img/manifest +++ b/cdist/conf/type/__qemu_img/manifest @@ -3,11 +3,23 @@ # format="$(cat "$__object/parameter/format")" -state="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" diskimage="/$__object_id" -# Absent is ensured by __file, present by gencode-remote -if [ "$state" = "absent" ]; then - __file "$diskimage" --state absent -fi +case "$state_should" in + present) + if [ ! -f "$__object/parameter/size" ]; then + echo "Size is required when state is present" >&2 + exit 1 + fi + ;; + absent) + # Absent is ensured by __file, present by gencode-remote + __file "$diskimage" --state absent + ;; + *) + echo "Unsupported state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__qemu_img/parameter/required b/cdist/conf/type/__qemu_img/parameter/required deleted file mode 100644 index 2a613ba5..00000000 --- a/cdist/conf/type/__qemu_img/parameter/required +++ /dev/null @@ -1 +0,0 @@ -size From 2955ef4344c864a1276c333ab027b029fb80f74a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 31 Mar 2014 21:22:29 +0200 Subject: [PATCH 2585/4212] cleanups Signed-off-by: Nico Schottelius --- cdist/conf/type/__dog_vdi/man.text | 4 ++-- cdist/conf/type/__qemu_img/man.text | 13 ++++++------- cdist/conf/type/__qemu_img/parameter/optional | 1 + 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cdist/conf/type/__dog_vdi/man.text b/cdist/conf/type/__dog_vdi/man.text index d7cc6f88..e3453ba7 100644 --- a/cdist/conf/type/__dog_vdi/man.text +++ b/cdist/conf/type/__dog_vdi/man.text @@ -19,9 +19,9 @@ OPTIONAL PARAMETERS state:: Either "present" or "absent", defaults to "present" size:: - Size of the image in dog vdi compatible units. + Size of the image in "dog vdi" compatible units. - Required if state == present. + Required if state is "present". diff --git a/cdist/conf/type/__qemu_img/man.text b/cdist/conf/type/__qemu_img/man.text index 39188ab0..0fe2bbec 100644 --- a/cdist/conf/type/__qemu_img/man.text +++ b/cdist/conf/type/__qemu_img/man.text @@ -14,17 +14,15 @@ The qemu-img program is used to create qemu images for qemu and (qemu-)kvm. -REQUIRED PARAMETERS -------------------- -size:: - Size of the image in qemu-img compatible units. - See qemu-img(1). - OPTIONAL PARAMETERS ------------------- state:: Either "present" or "absent", defaults to "present" +size:: + Size of the image in qemu-img compatible units. + + Required if state is "present". EXAMPLES @@ -42,9 +40,10 @@ __qemu_img /home/services/kvm/vm/myoldvm/system-disk --state absent SEE ALSO -------- - cdist-type(7) +- qemu-img(1) COPYING ------- -Copyright \(C) 2012 Nico Schottelius. Free use of this software is +Copyright \(C) 2012-2014 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__qemu_img/parameter/optional b/cdist/conf/type/__qemu_img/parameter/optional index 71b9a32b..21aa421b 100644 --- a/cdist/conf/type/__qemu_img/parameter/optional +++ b/cdist/conf/type/__qemu_img/parameter/optional @@ -1,2 +1,3 @@ format state +size From 47b6149803b89a09d88522404191a345cd2278db Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 31 Mar 2014 21:23:40 +0200 Subject: [PATCH 2586/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index 8b66e95b..8d0cb31a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,10 @@ Changelog * Exception: No braces means author == Nico Schottelius +3.1.2: + * Type __qemu_img: size is optional, if state is not present + * New Type: __dog_vdi + 3.1.1: 2014-03-26 * Core: Make __object and __object_id available to code (Daniel Heule) * New explorer: cpu_cores (Daniel Heule/Thomas Oettli) From 9ad7e055024c067d6dbb35eab53b49b33a48344c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 31 Mar 2014 23:58:45 +0200 Subject: [PATCH 2587/4212] ++;; Signed-off-by: Nico Schottelius --- cdist/conf/type/__dog_vdi/manifest | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__dog_vdi/manifest b/cdist/conf/type/__dog_vdi/manifest index ab533c4b..be327a3a 100644 --- a/cdist/conf/type/__dog_vdi/manifest +++ b/cdist/conf/type/__dog_vdi/manifest @@ -26,6 +26,7 @@ case "$state_should" in echo "Size is required when state is present" >&2 exit 1 fi + ;; absent) : ;; From ad7977e51b877b80320989301ef2233121961473 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 31 Mar 2014 23:58:45 +0200 Subject: [PATCH 2588/4212] ++;; Signed-off-by: Nico Schottelius --- cdist/conf/type/__dog_vdi/manifest | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__dog_vdi/manifest b/cdist/conf/type/__dog_vdi/manifest index ab533c4b..be327a3a 100644 --- a/cdist/conf/type/__dog_vdi/manifest +++ b/cdist/conf/type/__dog_vdi/manifest @@ -26,6 +26,7 @@ case "$state_should" in echo "Size is required when state is present" >&2 exit 1 fi + ;; absent) : ;; From 203708e5da676a2d97545773da4246893a25091a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 6 Apr 2014 20:33:29 +0200 Subject: [PATCH 2589/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 8d0cb31a..0a6a4986 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 3.1.2: * Type __qemu_img: size is optional, if state is not present + * Type __key_value: Rewrite using awk (Daniel Heule) * New Type: __dog_vdi 3.1.1: 2014-03-26 From d12daf10c4dd943bb007402914957ab8f47dcac3 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Fri, 4 Apr 2014 14:00:51 -0400 Subject: [PATCH 2590/4212] Added messaging support for __jail type prints start/stop/create/delete/onboot to $__messages_out --- cdist/conf/type/__jail/explorer/status | 2 +- cdist/conf/type/__jail/gencode-remote | 7 ++++++- cdist/conf/type/__jail/manifest | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__jail/explorer/status b/cdist/conf/type/__jail/explorer/status index 06f7d063..1ceba212 100755 --- a/cdist/conf/type/__jail/explorer/status +++ b/cdist/conf/type/__jail/explorer/status @@ -39,7 +39,7 @@ fi # backslash-escaped $jaildir sjaildir="$(echo ${jaildir} | sed 's#/#\\/#g')" -jls_output="$(jls | grep "[ ^I]${sjaildir}\/${name}\$")" || true +jls_output="$(jls | grep "[ ]${sjaildir}\/${name}\$")" || true if [ -n "${jls_output}" ]; then echo "STARTED" diff --git a/cdist/conf/type/__jail/gencode-remote b/cdist/conf/type/__jail/gencode-remote index 141c8150..c88f3361 100755 --- a/cdist/conf/type/__jail/gencode-remote +++ b/cdist/conf/type/__jail/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012 Jake Guffey (jake.guffey at eprotex.com) +# 2012,2014 Jake Guffey (jake.guffey at eprotex.com) # # This file is part of cdist. # @@ -104,6 +104,7 @@ stopJail() { # Check $status before issuing command if [ "$status" = "STARTED" ]; then echo "/etc/rc.d/jail stop ${name}" + echo "stop" >> "$__messages_out" fi } @@ -111,6 +112,7 @@ startJail() { # Check $status before issuing command if [ "$status" = "NOTSTART" ]; then echo "/etc/rc.d/jail start ${name}" + echo "start" >> "$__messages_out" fi } @@ -162,6 +164,7 @@ EOF rm -f /etc/rc.conf.bak fi EOF + echo "delete" >> "$__messages_out" } createJail() { @@ -215,6 +218,7 @@ cat <> "$__messages_out" # Create the ro+rw mountpoint entries in fstab cat <> "$__messages_out" fi # Add the normal entries into the jail's rc.conf diff --git a/cdist/conf/type/__jail/manifest b/cdist/conf/type/__jail/manifest index 6a953241..2d29e263 100755 --- a/cdist/conf/type/__jail/manifest +++ b/cdist/conf/type/__jail/manifest @@ -29,8 +29,8 @@ # Can only be used on FreeBSD os="$(cat "$__global/explorer/os")" if [ ! "$os" = "freebsd" ]; then - echo "__jail can only be used on FreeBSD targets!" >&2 - exit 1 + echo "__jail can only be used on FreeBSD targets!" >&2 + exit 1 fi jaildir="$(cat "$__object/parameter/jaildir")" From f7a6377b74f7b1809a096a9a7cb9b9daf96b1d90 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Mon, 7 Apr 2014 09:44:28 -0400 Subject: [PATCH 2591/4212] Updated man page Included MESSAGES section --- cdist/conf/type/__jail/man.text | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cdist/conf/type/__jail/man.text b/cdist/conf/type/__jail/man.text index 9c968d84..be27e909 100644 --- a/cdist/conf/type/__jail/man.text +++ b/cdist/conf/type/__jail/man.text @@ -67,6 +67,19 @@ be removed then re-added with the correct IP address/netmask or the appropriate line (jail__ip="...") modified within rc.conf through some alternate means. +MESSAGES +-------- +start:: + The jail was started +stop:: + The jail was stopped +create: + The jail was created +delete:: + The jail was deleted +onboot:: + The jail was configured to start on boot + EXAMPLES -------- From c818442ef2d3363175f8ba960eaf43b121264165 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 12 Apr 2014 19:40:41 +0200 Subject: [PATCH 2592/4212] also linke "files" subdir Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 2f75ffd4..6b0ad9b5 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -33,6 +33,8 @@ import cdist import cdist.message from cdist import core +CONF_SUBDIRS_LINKED = [ "explorer", "files", "manifest", "type" ]: + class Local(object): """Execute commands locally. @@ -216,14 +218,14 @@ class Local(object): pass def _create_conf_path_and_link_conf_dirs(self): - # Link destination directories - for sub_dir in [ "explorer", "manifest", "type" ]: + # Create destination directories + for sub_dir in CONF_SUBDIRS_LINKED: self.mkdir(os.path.join(self.conf_path, sub_dir)) # Iterate over all directories and link the to the output dir for conf_dir in self.conf_dirs: self.log.debug("Checking conf_dir %s ..." % (conf_dir)) - for sub_dir in [ "explorer", "manifest", "type" ]: + for sub_dir in CONF_SUBDIRS_LINKED: current_dir = os.path.join(conf_dir, sub_dir) # Allow conf dirs to contain only partial content From 432e65b218e6db786c61345170cd140d198ed3c4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 12 Apr 2014 19:41:39 +0200 Subject: [PATCH 2593/4212] document CDIST_LOCAL_SHELL 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 cff0f9c7..644d12f4 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -237,6 +237,9 @@ The following environment variables influence the behaviour of cdist: require:: Setup dependencies between objects (see cdist-manifest(7)) +CDIST_LOCAL_SHELL:: + Use this shell instead of /bin/sh to execute scripts + CDIST_OVERRIDE:: Allow overwriting type parameters (see cdist-manifest(7)) From 152f02bb62ae240fe32ab47d1817e79b4715c250 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 12 Apr 2014 19:42:37 +0200 Subject: [PATCH 2594/4212] document CDIST_REMOTE_SHELL Signed-off-by: Nico Schottelius --- docs/man/cdist-reference.text.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 644d12f4..7081e762 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2014 Nico Schottelius (nico-cdist at schottelius.org) # 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. @@ -238,7 +238,10 @@ require:: Setup dependencies between objects (see cdist-manifest(7)) CDIST_LOCAL_SHELL:: - Use this shell instead of /bin/sh to execute scripts + Use this shell locally instead of /bin/sh to execute scripts + +CDIST_REMOTE_SHELL:: + Use this shell remotely instead of /bin/sh to execute scripts CDIST_OVERRIDE:: Allow overwriting type parameters (see cdist-manifest(7)) From a568d5da0fcad260ee953758e12968b78ce2487f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 12 Apr 2014 19:43:52 +0200 Subject: [PATCH 2595/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 0a6a4986..68e040e4 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog 3.1.2: + * Documentation: Add missing environment variables to reference * Type __qemu_img: size is optional, if state is not present * Type __key_value: Rewrite using awk (Daniel Heule) * New Type: __dog_vdi From 702a07b2d12b5ef7acb5b830dd2a44d1b99c223b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 12 Apr 2014 19:45:37 +0200 Subject: [PATCH 2596/4212] relese 3.1.2 = today Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 68e040e4..84462764 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,7 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius -3.1.2: +3.1.2: 2014-04-12 * Documentation: Add missing environment variables to reference * Type __qemu_img: size is optional, if state is not present * Type __key_value: Rewrite using awk (Daniel Heule) From aa8c5555b78591a48bccdd696389105bdac03e9a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 14 Apr 2014 09:46:52 +0200 Subject: [PATCH 2597/4212] document __files Signed-off-by: Nico Schottelius --- docs/man/cdist-reference.text.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 7081e762..c6e5053f 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -75,6 +75,10 @@ confdir:: By default it consists of everything in \$HOME/.cdist and cdist/conf/. For more details see cdist(1) +confdir/files/:: + Cdist does not care about this directory besides providing access to it. + It is thought to be a general file storage area. + confdir/manifest/init:: This is the central entry point. It is an executable (+x bit set) shell script that can use @@ -196,6 +200,10 @@ The following environment variables are exported by cdist: __explorer:: Directory that contains all global explorers. Available for: initial manifest, explorer, type explorer, shell +__files:: + Directory that contains content from the "files" subdirectories + from the configuration directories. + Available for: initial manifest, type manifest, type gencode, shell __manifest:: Directory that contains the initial manifest. Available for: initial manifest, type manifest, shell From 40e517f50c41ee2e223eb3a26747572f8063039e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 14 Apr 2014 12:46:17 +0200 Subject: [PATCH 2598/4212] new type __yum_repo to manage yum repositories Signed-off-by: Steven Armstrong --- .../conf/type/__yum_repo/files/repo.template | 60 ++++++++++++ cdist/conf/type/__yum_repo/man.text | 91 +++++++++++++++++++ cdist/conf/type/__yum_repo/manifest | 40 ++++++++ cdist/conf/type/__yum_repo/notes | 3 + cdist/conf/type/__yum_repo/parameter/boolean | 6 ++ .../type/__yum_repo/parameter/default/state | 1 + cdist/conf/type/__yum_repo/parameter/optional | 26 ++++++ .../__yum_repo/parameter/optional_multiple | 2 + 8 files changed, 229 insertions(+) create mode 100755 cdist/conf/type/__yum_repo/files/repo.template create mode 100644 cdist/conf/type/__yum_repo/man.text create mode 100755 cdist/conf/type/__yum_repo/manifest create mode 100644 cdist/conf/type/__yum_repo/notes create mode 100644 cdist/conf/type/__yum_repo/parameter/boolean create mode 100644 cdist/conf/type/__yum_repo/parameter/default/state create mode 100644 cdist/conf/type/__yum_repo/parameter/optional create mode 100644 cdist/conf/type/__yum_repo/parameter/optional_multiple diff --git a/cdist/conf/type/__yum_repo/files/repo.template b/cdist/conf/type/__yum_repo/files/repo.template new file mode 100755 index 00000000..73ef00f2 --- /dev/null +++ b/cdist/conf/type/__yum_repo/files/repo.template @@ -0,0 +1,60 @@ +#!/bin/sh +set -u +cat << DONE +# Created by cdist ${__type##*/} +# Do not change. Changes will be overwritten. +# +[$repo_name] +DONE +# single value properties +single_value='name +metalink +mirrorlist +gpgcakey +exclude +includepkgs +failovermethod +timeout +http_caching +retries +throttle +bandwidth +sslcacert +sslverify +sslclientcert +sslclientkey +ssl_check_cert_permissions +metadata_expire +mirrorlist_expire +proxy +proxy_username +proxy_password +username +password +cost' +for key in $single_value; do + if [ -f "$__object/parameter/$key" ]; then + printf '%s=%s\n' "$key" "$(cat "$__object/parameter/$key")" + fi +done +# multi value properties +for key in baseurl gpgkey; do + if [ -f "$__object/parameter/$key" ]; then + printf '%s=' "$key" + prefix='' + while read line; do + printf '%s%s\n' "$prefix" "$line" + prefix=' ' + done < "$__object/parameter/$key" + fi +done +# boolean properties +for key in enabled gpgcheck repo_gpgcheck keepalive skip_if_unavailable; do + if [ -f "$__object/parameter/$key" ]; then + printf '%s=1\n' "$key" + fi +done +# special cases +if [ -f "$__object/parameter/disablegroups" ]; then + printf 'enablegroups=0\n' +fi diff --git a/cdist/conf/type/__yum_repo/man.text b/cdist/conf/type/__yum_repo/man.text new file mode 100644 index 00000000..7af95f6a --- /dev/null +++ b/cdist/conf/type/__yum_repo/man.text @@ -0,0 +1,91 @@ +cdist-type__yum_repo(7) +======================= +Steven Armstrong + + +NAME +---- +cdist-type__yum_repo - manage yum repositories + + +DESCRIPTION +----------- +For all undocumented parameters see yum.conf(5). + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent'. Defaults to 'present' +repositoryid:: + Defaults to __object_id. +name:: +baseurl:: + Can be specified multiple times. +metalink:: +mirrorlist:: +gpgkey:: + Can be specified multiple times. +gpgcakey:: +exclude:: +includepkgs:: +failovermethod:: +timeout:: +http_caching:: +retries:: +throttle:: +bandwidth:: +sslcacert:: +sslverify:: +sslclientcert:: +sslclientkey:: +ssl_check_cert_permissions:: +metadata_expire:: +mirrorlist_expire:: +proxy:: +proxy_username:: +proxy_password:: +username:: +password:: +cost:: + + +BOOLEAN PARAMETERS +------------------ +enabled:: +gpgcheck:: +repo_gpgcheck:: +disablegroups:: + ! enablegroups +keepalive:: +skip_if_unavailable:: + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__yum_repo epel \ + --name 'Extra Packages for Enterprise Linux 6 - $basearch' \ + --mirrorlist 'https://mirrors.fedoraproject.org/metalink?repo=epel-$releasever&arch=$basearch' \ + --failovermethod priority \ + --enabled \ + --gpgcheck \ + --gpgkey https://fedoraproject.org/static/0608B895.txt +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2014 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__yum_repo/manifest b/cdist/conf/type/__yum_repo/manifest new file mode 100755 index 00000000..9bb63c3c --- /dev/null +++ b/cdist/conf/type/__yum_repo/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") +state="$(cat "$__object/parameter/state")" + +case "$os" in + centos) + repo_name="$__object_id" + export repo_name + repo_file="/etc/yum.repos.d/${repo_name}.repo" + "$__type/files/repo.template" | \ + __file "$repo_file" \ + --owner root --group root --mode 644 \ + --state "$state" \ + --source - + ;; + *) + 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/__yum_repo/notes b/cdist/conf/type/__yum_repo/notes new file mode 100644 index 00000000..67fa617b --- /dev/null +++ b/cdist/conf/type/__yum_repo/notes @@ -0,0 +1,3 @@ +https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/sec-Configuring_Yum_and_Yum_Repositories.html +https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux_OpenStack_Platform/2/html/Getting_Started_Guide/sect-Configuring_Software_Repositories.html +http://docs.puppetlabs.com/references/latest/type.html#yumrepo diff --git a/cdist/conf/type/__yum_repo/parameter/boolean b/cdist/conf/type/__yum_repo/parameter/boolean new file mode 100644 index 00000000..8fccfa7c --- /dev/null +++ b/cdist/conf/type/__yum_repo/parameter/boolean @@ -0,0 +1,6 @@ +enabled +gpgcheck +repo_gpgcheck +disablegroups +keepalive +skip_if_unavailable diff --git a/cdist/conf/type/__yum_repo/parameter/default/state b/cdist/conf/type/__yum_repo/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__yum_repo/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__yum_repo/parameter/optional b/cdist/conf/type/__yum_repo/parameter/optional new file mode 100644 index 00000000..dc432f28 --- /dev/null +++ b/cdist/conf/type/__yum_repo/parameter/optional @@ -0,0 +1,26 @@ +bandwidth +cost +exclude +failovermethod +gpgcakey +http_caching +includepkgs +metadata_expire +mirrorlist +mirrorlist_expire +name +password +proxy +proxy_password +proxy_username +repositoryid +retries +sslcacert +ssl_check_cert_permissions +sslclientcert +sslclientkey +sslverify +state +throttle +timeout +username diff --git a/cdist/conf/type/__yum_repo/parameter/optional_multiple b/cdist/conf/type/__yum_repo/parameter/optional_multiple new file mode 100644 index 00000000..6467915b --- /dev/null +++ b/cdist/conf/type/__yum_repo/parameter/optional_multiple @@ -0,0 +1,2 @@ +baseurl +gpgkey From 0d36c9487a05254db2d4ae4b2426baa6c336dba5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 14 Apr 2014 13:47:56 +0200 Subject: [PATCH 2599/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 84462764..bea0859c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius +3.1.3: + * New Type: __yum_repo (Steven Armstrong) + 3.1.2: 2014-04-12 * Documentation: Add missing environment variables to reference * Type __qemu_img: size is optional, if state is not present From 831acd16c65747ddd8c7ca63e276f078c169dfc1 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 14 Apr 2014 19:14:29 +0200 Subject: [PATCH 2600/4212] rename parameter repo_uri to uri as requested by nico --- cdist/conf/type/__zypper_repo/explorer/repo_id | 6 +++--- cdist/conf/type/__zypper_repo/gencode-remote | 6 +++--- cdist/conf/type/__zypper_repo/man.text | 12 ++++++------ cdist/conf/type/__zypper_repo/parameter/optional | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cdist/conf/type/__zypper_repo/explorer/repo_id b/cdist/conf/type/__zypper_repo/explorer/repo_id index 83a698b7..be0b9771 100644 --- a/cdist/conf/type/__zypper_repo/explorer/repo_id +++ b/cdist/conf/type/__zypper_repo/explorer/repo_id @@ -18,11 +18,11 @@ # along with cdist. If not, see . # # -# Retrieve the id from the repo with the uri from parameter repo_uri - parsed zypper output +# Retrieve the id from the repo with the uri from parameter uri - parsed zypper output # # -if [ -f "$__object/parameter/repo_uri" ]; then - uri="$(cat "$__object/parameter/repo_uri")" +if [ -f "$__object/parameter/uri" ]; then + uri="$(cat "$__object/parameter/uri")" else uri="$__object_id" fi diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote index f678552b..005166c9 100644 --- a/cdist/conf/type/__zypper_repo/gencode-remote +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -33,8 +33,8 @@ else desc="$__object_id" fi -if [ -f "$__object/parameter/repo_uri" ]; then - uri="$(cat "$__object/parameter/repo_uri")" +if [ -f "$__object/parameter/uri" ]; then + uri="$(cat "$__object/parameter/uri")" else uri="$__object_id" fi @@ -65,7 +65,7 @@ fi case "$state" in present) if [ -z "$desc" ] || [ -z "$uri" ]; then - echo "parameter repo_desc and repo_uri for $state needed" >&2 + echo "parameter repo_desc and uri for $state needed" >&2 exit 4 fi if [ -z "$repo_id" ]; then diff --git a/cdist/conf/type/__zypper_repo/man.text b/cdist/conf/type/__zypper_repo/man.text index 6ea88f16..e8024ce5 100644 --- a/cdist/conf/type/__zypper_repo/man.text +++ b/cdist/conf/type/__zypper_repo/man.text @@ -22,13 +22,13 @@ OPTIONAL PARAMETERS ------------------- state:: 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 + + #present# - make sure that the repo is aviable, needs uri and repo_desc + + for all following states, the repo can be searched via repo_id or uri + #absent# - drop the repo if found + #enabled# - a repo can have state disabled if installed via zypper service (ris), in this case, you can enable the repo + #disabled# - instead of absent (drop), a repo can also set to disabled, wich makes it inaccessible + -repo_uri:: +uri:: If supplied, use the uri and not the object id as repo uri. repo_desc:: @@ -43,10 +43,10 @@ EXAMPLES -------------------------------------------------------------------------------- # Ensure testrepo in installed -__zypper_repo testrepo --state present --repo_uri http://url.to.your.repo/with/path +__zypper_repo testrepo --state present --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 +__zypper_repo testrepo --state absent --uri http://url.to.your.repo/with/path # Drop repo by id number (attention: repos are always numbered from 1 to max) __zypper_repo testrepo --state absent --repo_id 1 @@ -55,7 +55,7 @@ __zypper_repo testrepo --state absent --repo_id 1 __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 +__zypper_repo testrepo3 --state enabled --uri http://url.to.your.repo/with/path # disable a repo works like enabling it __zypper_repo testrepo4 --state disabled --repo_id 4 diff --git a/cdist/conf/type/__zypper_repo/parameter/optional b/cdist/conf/type/__zypper_repo/parameter/optional index 6f5a8325..fe40e350 100644 --- a/cdist/conf/type/__zypper_repo/parameter/optional +++ b/cdist/conf/type/__zypper_repo/parameter/optional @@ -1,4 +1,4 @@ state -repo_uri +uri repo_desc repo_id From c5152b75f2b2713fc73dcb0d3aa76e70e0978254 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 14 Apr 2014 19:18:16 +0200 Subject: [PATCH 2601/4212] rename parameter service_uri to uri as requested --- cdist/conf/type/__zypper_service/explorer/service_id | 4 ++-- cdist/conf/type/__zypper_service/explorer/service_uri | 4 ++-- cdist/conf/type/__zypper_service/gencode-remote | 4 ++-- cdist/conf/type/__zypper_service/man.text | 8 ++++---- cdist/conf/type/__zypper_service/manifest | 4 ++-- cdist/conf/type/__zypper_service/parameter/required | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cdist/conf/type/__zypper_service/explorer/service_id b/cdist/conf/type/__zypper_service/explorer/service_id index 9c3d3a2d..bf5f0260 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_id +++ b/cdist/conf/type/__zypper_service/explorer/service_id @@ -20,8 +20,8 @@ # # Manage services with Zypper (mostly suse) # -if [ -f "$__object/parameter/service_uri" ]; then - uri="$(cat "$__object/parameter/service_uri")" +if [ -f "$__object/parameter/uri" ]; then + uri="$(cat "$__object/parameter/uri")" else uri="/$__object_id" fi diff --git a/cdist/conf/type/__zypper_service/explorer/service_uri b/cdist/conf/type/__zypper_service/explorer/service_uri index 2f4f8960..bcad4ec8 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_uri +++ b/cdist/conf/type/__zypper_service/explorer/service_uri @@ -20,8 +20,8 @@ # # Manage services with Zypper (mostly suse) # -if [ -f "$__object/parameter/service_uri" ]; then - uri="$(cat "$__object/parameter/service_uri")" +if [ -f "$__object/parameter/uri" ]; then + uri="$(cat "$__object/parameter/uri")" else uri="/$__object_id" fi diff --git a/cdist/conf/type/__zypper_service/gencode-remote b/cdist/conf/type/__zypper_service/gencode-remote index df8d1660..ebd5fc5c 100644 --- a/cdist/conf/type/__zypper_service/gencode-remote +++ b/cdist/conf/type/__zypper_service/gencode-remote @@ -33,8 +33,8 @@ else desc="$__object_id" fi -if [ -f "$__object/parameter/service_uri" ]; then - uri="$(cat "$__object/parameter/service_uri")" +if [ -f "$__object/parameter/uri" ]; then + uri="$(cat "$__object/parameter/uri")" else uri="$__object_id" fi diff --git a/cdist/conf/type/__zypper_service/man.text b/cdist/conf/type/__zypper_service/man.text index 31543d93..b6bba660 100644 --- a/cdist/conf/type/__zypper_service/man.text +++ b/cdist/conf/type/__zypper_service/man.text @@ -15,7 +15,7 @@ zypper is usually used on SuSE systems to manage services. REQUIRED PARAMETERS ------------------- -service_uri:: +uri:: Uri of the service @@ -45,13 +45,13 @@ 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-services --remove-all-repos +__zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --uri "http://path/to/your/ris/dir" --remove-all-other-services --remove-all-repos # Ensure that internal SLES11 SP3 RIS is in installed, no changes to ohter services or repos -__zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --service_uri "http://path/to/your/ris/dir" +__zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --uri "http://path/to/your/ris/dir" # Drop service by uri, no changes to ohter services or repos -__zypper_service INTERNAL_SLES11_SP3 --state absent --service_uri "http://path/to/your/ris/dir" +__zypper_service INTERNAL_SLES11_SP3 --state absent --uri "http://path/to/your/ris/dir" -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__zypper_service/manifest b/cdist/conf/type/__zypper_service/manifest index aa4a39a3..b21f3f98 100644 --- a/cdist/conf/type/__zypper_service/manifest +++ b/cdist/conf/type/__zypper_service/manifest @@ -27,8 +27,8 @@ zypper_def_opts=" -q " -if [ -f "$__object/parameter/service_uri" ]; then - uri="$(cat "$__object/parameter/service_uri")" +if [ -f "$__object/parameter/uri" ]; then + uri="$(cat "$__object/parameter/uri")" else uri="$__object_id" fi diff --git a/cdist/conf/type/__zypper_service/parameter/required b/cdist/conf/type/__zypper_service/parameter/required index 2b4645ee..c7954952 100644 --- a/cdist/conf/type/__zypper_service/parameter/required +++ b/cdist/conf/type/__zypper_service/parameter/required @@ -1 +1 @@ -service_uri +uri From 8a4cc56266d234b9a8cd2ef3ec999fb00374e480 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 22 Apr 2014 11:04:02 +0200 Subject: [PATCH 2602/4212] ensure all files we create end with a single newline Signed-off-by: Steven Armstrong --- cdist/util/fsproperty.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cdist/util/fsproperty.py b/cdist/util/fsproperty.py index 49d4a32d..98de09f8 100644 --- a/cdist/util/fsproperty.py +++ b/cdist/util/fsproperty.py @@ -143,6 +143,9 @@ class DirectoryDict(collections.MutableMapping): fd.write(str(v) + '\n') else: fd.write(str(value)) + # ensure file ends with a single newline + if value and value[-1] != '\n': + fd.write('\n') except EnvironmentError as e: raise cdist.Error(str(e)) @@ -281,7 +284,7 @@ class FileStringProperty(FileBasedProperty): value = "" try: with open(path, "r") as fd: - value = fd.read() + value = fd.read().rstrip('\n') except EnvironmentError: pass return value @@ -292,6 +295,9 @@ class FileStringProperty(FileBasedProperty): try: with open(path, "w") as fd: fd.write(str(value)) + # ensure file ends with a single newline + if value[-1] != '\n': + fd.write('\n') except EnvironmentError as e: raise cdist.Error(str(e)) else: From 9127e0610932b52abaa52cf2e28afd41d03eec3b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 25 Apr 2014 01:48:58 +0200 Subject: [PATCH 2603/4212] CentOS support for __hostname Signed-off-by: Nico Schottelius --- .../__hostname/explorer/hostname_sysconfig | 26 ++++++++++++++++++ cdist/conf/type/__hostname/gencode-remote | 27 +++++++++++++++---- cdist/conf/type/__hostname/manifest | 27 ++++++++++++++----- docs/changelog | 1 + 4 files changed, 69 insertions(+), 12 deletions(-) create mode 100755 cdist/conf/type/__hostname/explorer/hostname_sysconfig diff --git a/cdist/conf/type/__hostname/explorer/hostname_sysconfig b/cdist/conf/type/__hostname/explorer/hostname_sysconfig new file mode 100755 index 00000000..d0d7b4e7 --- /dev/null +++ b/cdist/conf/type/__hostname/explorer/hostname_sysconfig @@ -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/sysconfig/network ]; then + awk -F= '/^HOSTNAME=/ { print $2 }' /etc/sysconfig/network +fi diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index 3d208cbe..eec3bc9f 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -28,14 +28,24 @@ fi os=$(cat "$__global/explorer/os") name_running=$(cat "$__global/explorer/hostname") name_config=$(cat "$__object/explorer/hostname_file") +name_sysconfig=$(cat "$__object/explorer/hostname_file") has_hostnamectl=$(cat "$__object/explorer/has_hostnamectl") ################################################################################ # If everything is ok -> exit # -if [ "$name_config" = "$name_should" -a "$name_running" = "$name_should" ]; then - exit 0 -fi +case "$os" in + archlinux|debian|ubuntu) + if [ "$name_config" = "$name_should" -a "$name_running" = "$name_should" ]; then + exit 0 + fi + ;; + centos) + if [ "$name_sysconfig" = "$name_should" -a "$name_running" = "$name_should" ]; then + exit 0 + fi + ;; +esac ################################################################################ # Setup hostname @@ -45,6 +55,13 @@ 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" + case "$os" in + archlinux|debian|ubuntu) + echo "hostname '$name_should'" + echo "printf '%s\n' '$name_should' > /etc/hostname" + ;; + centos) + echo "hostname '$name_should'" + ;; + esac fi diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest index 0544a6f9..b6985c1c 100755 --- a/cdist/conf/type/__hostname/manifest +++ b/cdist/conf/type/__hostname/manifest @@ -20,6 +20,12 @@ # os=$(cat "$__global/explorer/os") +if [ -f "$__object/parameter/name" ]; then + name_should="$(cat "$__object/parameter/name")" +else + name_should="$(echo "${__target_host%%.*}")" +fi + not_supported() { echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 @@ -28,11 +34,18 @@ not_supported() { } case "$os" in - archlinux|debian|ubuntu) - # handled in gencode-remote - : - ;; - *) - not_supported - ;; + archlinux|debian|ubuntu) + # handled in gencode-remote + : + ;; + centos) + __key_value sysconfig-hostname \ + --file /etc/sysconfig/network \ + --delimiter '=' \ + --key HOSTNAME \ + --value "$name_should" --exact_delimiter + ;; + *) + not_supported + ;; esac diff --git a/docs/changelog b/docs/changelog index bea0859c..6e69251f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 3.1.3: * New Type: __yum_repo (Steven Armstrong) + * Type __hostname: Add support for CentOS 3.1.2: 2014-04-12 * Documentation: Add missing environment variables to reference From 5a647ec763b5465be09b6fcc36b6afec78a3d12a Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 29 Apr 2014 11:49:43 +0200 Subject: [PATCH 2604/4212] Bugfix to auto import pgp keys for new repos, so we can add repos with new keys --- cdist/conf/type/__zypper_repo/gencode-remote | 2 +- cdist/conf/type/__zypper_service/gencode-remote | 4 +++- cdist/conf/type/__zypper_service/manifest | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote index f678552b..b80727b2 100644 --- a/cdist/conf/type/__zypper_repo/gencode-remote +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -25,7 +25,7 @@ #exec >&2 #set -x -zypper_def_opts=" -q " +zypper_def_opts=" -q --non-interactive --gpg-auto-import-keys " if [ -f "$__object/parameter/repo_desc" ]; then desc="$(cat "$__object/parameter/repo_desc")" diff --git a/cdist/conf/type/__zypper_service/gencode-remote b/cdist/conf/type/__zypper_service/gencode-remote index df8d1660..ef025752 100644 --- a/cdist/conf/type/__zypper_service/gencode-remote +++ b/cdist/conf/type/__zypper_service/gencode-remote @@ -25,7 +25,7 @@ #exec >&2 #set -x -zypper_def_opts=" -q " +zypper_def_opts=" -q --non-interactive --gpg-auto-import-keys " if [ -f "$__object/parameter/service_desc" ]; then desc="$(cat "$__object/parameter/service_desc")" @@ -73,10 +73,12 @@ case "$state_should" in present) echo zypper $zypper_def_opts addservice -t "$stype" "$uri" \"$desc\" echo zypper $zypper_def_opts refs + echo zypper $zypper_def_opts ref ;; absent) echo zypper $zypper_def_opts removeservice "$service_id" echo zypper $zypper_def_opts refs + echo zypper $zypper_def_opts ref ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__zypper_service/manifest b/cdist/conf/type/__zypper_service/manifest index aa4a39a3..cea6a7c8 100644 --- a/cdist/conf/type/__zypper_service/manifest +++ b/cdist/conf/type/__zypper_service/manifest @@ -25,7 +25,6 @@ #exec >&2 #set -x -zypper_def_opts=" -q " if [ -f "$__object/parameter/service_uri" ]; then uri="$(cat "$__object/parameter/service_uri")" From 3710557c629d25ad91d8efe378b91493c64c958a Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 29 Apr 2014 12:57:46 +0200 Subject: [PATCH 2605/4212] bugfix the list of interfaces --- cdist/conf/explorer/interfaces | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/explorer/interfaces b/cdist/conf/explorer/interfaces index 6804f2db..c1f2a57a 100755 --- a/cdist/conf/explorer/interfaces +++ b/cdist/conf/explorer/interfaces @@ -24,12 +24,12 @@ # # Use ip, if available -if command -v ip; then +if command -v ip >/dev/null; then ip -o link show | sed -n 's/^[0-9]\+: \(.\+\): <.*/\1/p' exit 0 fi -if ! command -v ifconfig; then +if ! command -v ifconfig >/dev/null; then # no ifconfig, nothing we could do exit 0 fi From bfbc6210105ac0f40a65b161f09155f0291c1e35 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 29 Apr 2014 18:10:50 +0200 Subject: [PATCH 2606/4212] ++releasedate Signed-off-by: Nico Schottelius --- cdist/conf/type/__yum_repo/files/repo.template | 3 ++- cdist/conf/type/__yum_repo/man.text | 4 ++-- cdist/conf/type/__yum_repo/parameter/boolean | 1 - cdist/conf/type/__yum_repo/parameter/optional | 1 + docs/changelog | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__yum_repo/files/repo.template b/cdist/conf/type/__yum_repo/files/repo.template index 73ef00f2..3e14c8b6 100755 --- a/cdist/conf/type/__yum_repo/files/repo.template +++ b/cdist/conf/type/__yum_repo/files/repo.template @@ -11,6 +11,7 @@ single_value='name metalink mirrorlist gpgcakey +gpgcheck exclude includepkgs failovermethod @@ -49,7 +50,7 @@ for key in baseurl gpgkey; do fi done # boolean properties -for key in enabled gpgcheck repo_gpgcheck keepalive skip_if_unavailable; do +for key in enabled repo_gpgcheck keepalive skip_if_unavailable; do if [ -f "$__object/parameter/$key" ]; then printf '%s=1\n' "$key" fi diff --git a/cdist/conf/type/__yum_repo/man.text b/cdist/conf/type/__yum_repo/man.text index 7af95f6a..549cf336 100644 --- a/cdist/conf/type/__yum_repo/man.text +++ b/cdist/conf/type/__yum_repo/man.text @@ -32,6 +32,7 @@ mirrorlist:: gpgkey:: Can be specified multiple times. gpgcakey:: +gpgcheck:: exclude:: includepkgs:: failovermethod:: @@ -58,7 +59,6 @@ cost:: BOOLEAN PARAMETERS ------------------ enabled:: -gpgcheck:: repo_gpgcheck:: disablegroups:: ! enablegroups @@ -75,7 +75,7 @@ __yum_repo epel \ --mirrorlist 'https://mirrors.fedoraproject.org/metalink?repo=epel-$releasever&arch=$basearch' \ --failovermethod priority \ --enabled \ - --gpgcheck \ + --gpgcheck 1 \ --gpgkey https://fedoraproject.org/static/0608B895.txt -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__yum_repo/parameter/boolean b/cdist/conf/type/__yum_repo/parameter/boolean index 8fccfa7c..2eb49a93 100644 --- a/cdist/conf/type/__yum_repo/parameter/boolean +++ b/cdist/conf/type/__yum_repo/parameter/boolean @@ -1,5 +1,4 @@ enabled -gpgcheck repo_gpgcheck disablegroups keepalive diff --git a/cdist/conf/type/__yum_repo/parameter/optional b/cdist/conf/type/__yum_repo/parameter/optional index dc432f28..7e185701 100644 --- a/cdist/conf/type/__yum_repo/parameter/optional +++ b/cdist/conf/type/__yum_repo/parameter/optional @@ -3,6 +3,7 @@ cost exclude failovermethod gpgcakey +gpgcheck http_caching includepkgs metadata_expire diff --git a/docs/changelog b/docs/changelog index 6e69251f..d7a5af9c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,7 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius -3.1.3: +3.1.3: 2014-04-29 * New Type: __yum_repo (Steven Armstrong) * Type __hostname: Add support for CentOS From 7b7f17cae5d04970f92c96a7d3d134fe34617e19 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Tue, 29 Apr 2014 21:33:18 +0200 Subject: [PATCH 2607/4212] english --- docs/man/man1/cdist.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/man/man1/cdist.text b/docs/man/man1/cdist.text index e8c12991..fa91af40 100644 --- a/docs/man/man1/cdist.text +++ b/docs/man/man1/cdist.text @@ -26,7 +26,7 @@ cdist supports different subcommands as explained below. GENERAL ------- -All commands except the following options: +All commands accept the following options: -d, --debug:: Set log level to debug From ba0d6e83b2563fba27f348820f30614675053d72 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Tue, 29 Apr 2014 21:34:03 +0200 Subject: [PATCH 2608/4212] fix asciidoc --- docs/man/man1/cdist.text | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/man/man1/cdist.text b/docs/man/man1/cdist.text index fa91af40..c09d8f41 100644 --- a/docs/man/man1/cdist.text +++ b/docs/man/man1/cdist.text @@ -34,7 +34,7 @@ All commands accept the following options: -h, --help:: Show the help screen --v, --verbose: +-v, --verbose:: Set log level to info, be more verbose -V, --version:: @@ -72,10 +72,10 @@ Configure one or more hosts -s, --sequential:: Operate on multiple hosts sequentially ---remote-copy REMOTE_COPY: +--remote-copy REMOTE_COPY:: Command to use for remote copy (should behave like scp) ---remote-exec REMOTE_EXEC: +--remote-exec REMOTE_EXEC:: Command to use for remote execution (should behave like ssh) SHELL From 28a734fcc0d2b8f4513cfe2ec4a414fe3224a4ca Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Wed, 30 Apr 2014 11:17:09 +0200 Subject: [PATCH 2609/4212] asciidoc syntax fix --- docs/man/man7/cdist-manifest.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 057905ea..369752e6 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -13,7 +13,7 @@ DESCRIPTION Manifests are used to define which objects to create. Objects are instances of **types**, like in object oriented programming languages. An object is represented by the combination of -**type + slash + object name**: **__file/etc/cdist-configured** is an +**type + slash + object name**: **\__file/etc/cdist-configured** is an object of the type ***__file*** with the name ***etc/cdist-configured***. All available types can be found in the **cdist/conf/type/** directory, From 8ae9bcfec91251728dce5dd55d547b6825ba5873 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Wed, 30 Apr 2014 11:28:13 +0200 Subject: [PATCH 2610/4212] whitespace --- docs/man/man7/cdist-manifest.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 369752e6..d9cae7cf 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -29,7 +29,7 @@ at an example: __package apache2 --state absent # Same with the __directory type - __directory /tmp/cdist --state present +__directory /tmp/cdist --state present -------------------------------------------------------------------------------- These two lines create objects, which will later be used to realise the From 9ffdde3646813e3c5891e7a29d89933023c727dd Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Wed, 30 Apr 2014 11:45:13 +0200 Subject: [PATCH 2611/4212] wording --- docs/man/man7/cdist-manifest.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index d9cae7cf..77b19c4c 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -89,7 +89,7 @@ SPLITTING UP THE INITIAL MANIFEST --------------------------------- If you want to split up your initial manifest, you can create other shell scripts in **cdist/conf/manifest/** and include them in **cdist/conf/manifest/init**. -Cdist provides the environment variable ***__manifest*** to reference to +Cdist provides the environment variable ***__manifest*** to reference the directory containing the initial manifest (see cdist-reference(7)). The following example would include every file with a **.sh** suffix: From cdb5b9c82a3e4cd3a7537b58e23097dfe071600f Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Wed, 30 Apr 2014 11:53:04 +0200 Subject: [PATCH 2612/4212] wording --- docs/man/man7/cdist-manifest.text | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 77b19c4c..7c6b820d 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -149,8 +149,8 @@ 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 -cdist encounter the affected objects, otherwhise this results -into an undefined situation. +cdist encounters the affected objects, otherwhise this results +in 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 From dc7f5ab62899b7c4b2877f4386be4dd5957c46e8 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Wed, 30 Apr 2014 11:57:10 +0200 Subject: [PATCH 2613/4212] typo --- docs/man/man7/cdist-manifest.text | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 7c6b820d..cc4c0428 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -152,7 +152,7 @@ ATTENTION: Only use this feature if you are 100% sure in which order cdist encounters the affected objects, otherwhise this results in an undefined situation. -If CDIST_OVERRIDE and CDIST_ORDER_DEPENDENCY is set for an object, +If CDIST_OVERRIDE and CDIST_ORDER_DEPENDENCY are 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. @@ -198,7 +198,7 @@ How to override objects: -------------------------------------------------------------------------------- # for example in the inital manifest -# reate user account foobar with some hash for password +# create user account foobar with some hash for password __user foobar --password 'some_fancy_hash' --home /home/foobarexample # ... many statements and includes in the manifest later ... From 779374ad948fd00713af275447f30380fadf82c7 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Wed, 30 Apr 2014 11:59:07 +0200 Subject: [PATCH 2614/4212] wording --- docs/man/man7/cdist-manifest.text | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index cc4c0428..a6143ab7 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -210,8 +210,8 @@ __user foobar --password 'some_other_hash' # this tells cdist, that you know that this is an override and should be accepted CDIST_OVERRIDE=yes __user foobar --password 'some_other_hash' -# its only an override, means the parameter --home is not touched -# and stay at the original value of /home/foobarexample +# it's only an override, means the parameter --home is not touched +# and stays at the original value of /home/foobarexample -------------------------------------------------------------------------------- Dependencies defined by execution order work as following: From 5b8ab385f2c3a6ebfed781e53766f3f39d3ae089 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Wed, 30 Apr 2014 15:50:14 +0200 Subject: [PATCH 2615/4212] clarify docu --- 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 06026542..323fc130 100644 --- a/docs/man/man7/cdist-type.text +++ b/docs/man/man7/cdist-type.text @@ -25,7 +25,7 @@ to use. HOW TO USE A TYPE ----------------- You can use types from the initial manifest or the type manifest like a -normal command: +normal shell command: -------------------------------------------------------------------------------- # Creates empty file /etc/cdist-configured From e5a12803ffd33ac3e08e2ffa56d9bdaeacdc3b7b Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Wed, 30 Apr 2014 15:57:44 +0200 Subject: [PATCH 2616/4212] expand "Dependencies" paragraph --- docs/man/man7/cdist-manifest.text | 35 ++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index a6143ab7..b28fe94f 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -110,24 +110,39 @@ setup the variable "require" to contain the requirements. Multiple requirements can be added white space separated. -------------------------------------------------------------------------------- -# No dependency -__file /etc/cdist-configured - -# Require above object -require="__file/etc/cdist-configured" __link /tmp/cdist-testfile \ - --source /etc/cdist-configured --type symbolic - -# Require two objects -require="__file/etc/cdist-configured __link/tmp/cdist-testfile" \ - __file /tmp/cdist-another-testfile + 1 # No dependency + 2 __file /etc/cdist-configured + 3 + 4 # Require above object + 5 require="__file/etc/cdist-configured" __link /tmp/cdist-testfile \ + 6 --source /etc/cdist-configured --type symbolic + 7 + 8 # Require two objects + 9 require="__file/etc/cdist-configured __link/tmp/cdist-testfile" \ +10 __file /tmp/cdist-another-testfile -------------------------------------------------------------------------------- +Above the "require" variable is only set for the command that is +immediately following it. Dependencies should allways be declared that way. + +On line 4 you can see that the instantion of a type "__link" object needs +the object "__file/etc/cdist-configured" to be present, before it can proceed. + +This also means that the "__link" command must make sure, that either +"__file/etc/cdist-configured" allready is present, or, if it's not, it needs +to be created. The task of cdist is to make sure, that the dependency will be +resolved appropriately and thus "__file/etc/cdist-configured" be created +if necessary before "__link" proceeds (or to abort execution with an error). + All objects that are created in a type manifest are automatically required from the type that is calling them. This is called "autorequirement" in cdist jargon. +You can find an more in depth description of the flow execution of manifests +in cdist-stages(7) and of how types work in cdist-type(7). + CREATE DEPENDENCIES FROM EXECUTION ORDER ----------------------------------------- You can tell cdist to execute all types in the order in which they are created From e6b26829f4cb9a6fc887eb7d0614dc0e3fb9f248 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Wed, 30 Apr 2014 16:38:40 +0200 Subject: [PATCH 2617/4212] crosslink html man pages This is using sed --in-place, which might not be available in all sed versions. If that's a concern, then please replace with awk script or move to build-helper and use temporary files. Also the regex is a heuristic. It works for our man pages here but it might have false positive matches in the future. --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile b/Makefile index 9502c989..82a774a5 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,11 @@ A2XM=a2x -f manpage --no-xmllint -a encoding=UTF-8 A2XH=a2x -f xhtml --no-xmllint -a encoding=UTF-8 +# Create cross-links in html man pages +# We look for something like "cdist-type(7)" and make a href out of it +# The first matching group is the man page name and the second group +# is the man page section (1 or 7) +CROSSLINK=sed --in-place 's/\([[:alnum:]_-]*\)(\([17]\))/&<\/a>/' helper=./bin/build-helper MANDIR=docs/man @@ -86,6 +91,7 @@ MANSTATICALL=$(MANSTATICMAN) $(MANSTATICHTML) # Creating the type html page %.html: %.text $(A2XH) $^ + $(CROSSLINK) $^ man: $(MANTYPEALL) $(MANREFALL) $(MANSTATICALL) From 2ff61d19656f21c794c54633c01afcea1573c53b Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Wed, 30 Apr 2014 16:42:35 +0200 Subject: [PATCH 2618/4212] wording --- docs/man/man7/cdist-bootstrap.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/man/man7/cdist-bootstrap.text b/docs/man/man7/cdist-bootstrap.text index 985d0f53..5852bad0 100644 --- a/docs/man/man7/cdist-bootstrap.text +++ b/docs/man/man7/cdist-bootstrap.text @@ -25,7 +25,7 @@ location. For starters, having cdist (which includes the configuration database) on your notebook should be fine. Additionally an external copy of the git repository the configuration -relies in is recommended, for use as backup as well to allow easy collaboration +relies on is recommended, for use as backup as well as to allow easy collaboration with others. For more sophisticated setups developing cdist configurations with multiple From 454f955d25221e34c9b13515487c56adc4010d59 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Wed, 30 Apr 2014 16:53:32 +0200 Subject: [PATCH 2619/4212] fix error --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 82a774a5..18e2e67a 100644 --- a/Makefile +++ b/Makefile @@ -91,7 +91,7 @@ MANSTATICALL=$(MANSTATICMAN) $(MANSTATICHTML) # Creating the type html page %.html: %.text $(A2XH) $^ - $(CROSSLINK) $^ + $(CROSSLINK) $@ man: $(MANTYPEALL) $(MANREFALL) $(MANSTATICALL) From 5f147dd845bbfabbd14a6e7bdda7cc6a8828d42c Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Wed, 30 Apr 2014 20:45:05 +0200 Subject: [PATCH 2620/4212] fix sed pattern * don't add a href to the title tag (3rd line in the html document) * replace multiple instances on a line --- Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 18e2e67a..112b1411 100644 --- a/Makefile +++ b/Makefile @@ -23,8 +23,10 @@ A2XH=a2x -f xhtml --no-xmllint -a encoding=UTF-8 # Create cross-links in html man pages # We look for something like "cdist-type(7)" and make a href out of it # The first matching group is the man page name and the second group -# is the man page section (1 or 7) -CROSSLINK=sed --in-place 's/\([[:alnum:]_-]*\)(\([17]\))/&<\/a>/' +# is the man page section (1 or 7). The first three lines of the input +# (xml, DOCTYPE, head tags) are ignored, since the head tags contains +# the title of the page and should not contain a href. +CROSSLINK=sed --in-place '1,3!s/\([[:alnum:]_-]*\)(\([17]\))/&<\/a>/g' helper=./bin/build-helper MANDIR=docs/man From 2d3e5439a7e5165b98b9d8a251ef13ad5e099c90 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 4 May 2014 08:39:57 +0200 Subject: [PATCH 2621/4212] ++changes Signed-off-by: Nico Schottelius --- bin/build-helper | 25 +++---------------------- docs/changelog | 3 +++ 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 93401d3b..a4160418 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -142,8 +142,6 @@ eof freecode-release) version=$1; shift - api_token=$(awk '/machine freecode login/ { print $8 }' ~/.netrc) - printf "Enter tag list for freecode release %s> " "$version" read taglist @@ -151,26 +149,9 @@ eof read changelog echo "Submit preview" - cat << eof -tag_list = $taglist -changelog = $changelog -version = $version -eof - printf "Press enter to submit to freecode> " - read dummy - - cat << eof | cfreecode-api release-add cdist - { - "auth_code": "$api_token", - "release": { - "tag_list": "$taglist", - "version": "$version", - "changelog": "$changelog", - "hidden_from_frontpage": false - } - } -eof - + python2 $(which freecode-submit) -P cdist \ + -v "$version" -c "$changelog" \ + -t "$taglist" ;; release-git-tag) diff --git a/docs/changelog b/docs/changelog index d7a5af9c..e1a4220d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius +3.1.4: + * Documentation: Cleanup up, added HTML links (Tomas Pospisek) + 3.1.3: 2014-04-29 * New Type: __yum_repo (Steven Armstrong) * Type __hostname: Add support for CentOS From 99ce837d42e0411bd084f30f2b2db3265104d1d7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 4 May 2014 08:43:53 +0200 Subject: [PATCH 2622/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index e1a4220d..4d2083ac 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 3.1.4: * Documentation: Cleanup up, added HTML links (Tomas Pospisek) + * Explorer interfaces: Remove test output (Daniel Heule) 3.1.3: 2014-04-29 * New Type: __yum_repo (Steven Armstrong) From 6482b5df3fc83a2ab9738a726186119beec8f071 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 4 May 2014 08:52:06 +0200 Subject: [PATCH 2623/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 4d2083ac..943be9d1 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog 3.1.4: + * Core: Ensure all created files end in \n (Steven Armstrong) * Documentation: Cleanup up, added HTML links (Tomas Pospisek) * Explorer interfaces: Remove test output (Daniel Heule) From beab2888fa9c231f952d28a86619c1b192e26403 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 4 May 2014 08:53:10 +0200 Subject: [PATCH 2624/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 943be9d1..5d851c54 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ Changelog * Core: Ensure all created files end in \n (Steven Armstrong) * Documentation: Cleanup up, added HTML links (Tomas Pospisek) * Explorer interfaces: Remove test output (Daniel Heule) + * Type __jail: Add messaging support (Jake Guffey) 3.1.3: 2014-04-29 * New Type: __yum_repo (Steven Armstrong) From f2459df682a020cd6fc92e5fdf25f5cf68afe74b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 4 May 2014 09:25:17 +0200 Subject: [PATCH 2625/4212] prepare release 3.1.4 Signed-off-by: Nico Schottelius --- bin/build-helper | 2 +- docs/changelog | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index a4160418..ec98c68f 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -148,7 +148,7 @@ eof printf "Enter changelog for freecode release %s> " "$version" read changelog - echo "Submit preview" + echo "Submitting to freecode ..." python2 $(which freecode-submit) -P cdist \ -v "$version" -c "$changelog" \ -t "$taglist" diff --git a/docs/changelog b/docs/changelog index 5d851c54..d94ad297 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,7 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius -3.1.4: +3.1.4: 2014-05-04 * Core: Ensure all created files end in \n (Steven Armstrong) * Documentation: Cleanup up, added HTML links (Tomas Pospisek) * Explorer interfaces: Remove test output (Daniel Heule) From d28c374de97d29cf9e4e1f6531e0dea3099549c4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 4 May 2014 10:37:32 +0200 Subject: [PATCH 2626/4212] prevent ml releases without version and use custom freecode submit (archlinux is outdated) Signed-off-by: Nico Schottelius --- bin/build-helper | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/build-helper b/bin/build-helper index ec98c68f..0d61c7d6 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -104,6 +104,11 @@ eof ;; ml-release) + if [ $# -ne 1 ]; then + echo "$0 ml-release version" >&2 + exit 1 + fi + version=$1; shift to_a=cdist @@ -149,7 +154,7 @@ eof read changelog echo "Submitting to freecode ..." - python2 $(which freecode-submit) -P cdist \ + python2 ~/p/foreign/freecode-submit-2.7/freecode-submit -P cdist \ -v "$version" -c "$changelog" \ -t "$taglist" ;; From d86e50172a12f66f3247114baae13e2b97d2990d Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 5 May 2014 19:08:06 +0200 Subject: [PATCH 2627/4212] remove the "BETA FEATURE" flags from CDIST_ORDER_DEPENDENCY and CDIST_OVERRIDE. --- docs/man/man7/cdist-manifest.text | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index b28fe94f..96346c08 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -153,8 +153,6 @@ 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 --------- @@ -171,8 +169,6 @@ If CDIST_OVERRIDE and CDIST_ORDER_DEPENDENCY are 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 ffe24c612c6a8fc2b4870e8285de0599ed791079 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 5 May 2014 22:46:04 +0200 Subject: [PATCH 2628/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index d94ad297..e40dd5c0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,10 @@ Changelog * Exception: No braces means author == Nico Schottelius +3.1.5: 2014-05-05 + * Type __zypper_repo: Automatically import gpg keys (Daniel Heule) + * Type __zypper_service: Automatically import gpg keys (Daniel Heule) + 3.1.4: 2014-05-04 * Core: Ensure all created files end in \n (Steven Armstrong) * Documentation: Cleanup up, added HTML links (Tomas Pospisek) From 78c3c09163fbcaebb913b4944f5ccf9dfc6ab824 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 5 May 2014 23:12:18 +0200 Subject: [PATCH 2629/4212] do not wait for input from stdin Signed-off-by: Nico Schottelius --- bin/build-helper | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/build-helper b/bin/build-helper index 0d61c7d6..d28c0616 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -156,7 +156,8 @@ eof echo "Submitting to freecode ..." python2 ~/p/foreign/freecode-submit-2.7/freecode-submit -P cdist \ -v "$version" -c "$changelog" \ - -t "$taglist" + -t "$taglist" \ + -n ;; release-git-tag) From c363fc24deb63b9ffc029af2a434bd701e045ec1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 May 2014 00:28:18 +0200 Subject: [PATCH 2630/4212] begin to make OBJECT_MARKER dynamic Signed-off-by: Nico Schottelius --- cdist/config.py | 2 +- cdist/core/__init__.py | 2 +- cdist/core/cdist_object.py | 15 +++++++-------- docs/dev/logs/2014-05-06.object-marker | 14 ++++++++++++++ 4 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 docs/dev/logs/2014-05-06.object-marker diff --git a/cdist/config.py b/cdist/config.py index 73ba4710..2fd80db0 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # diff --git a/cdist/core/__init__.py b/cdist/core/__init__.py index 66ee00a5..5dafd061 100644 --- a/cdist/core/__init__.py +++ b/cdist/core/__init__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -23,7 +24,6 @@ from cdist.core.cdist_type import CdistType from cdist.core.cdist_type import NoSuchTypeError from cdist.core.cdist_object import CdistObject from cdist.core.cdist_object import IllegalObjectIdError -from cdist.core.cdist_object import OBJECT_MARKER from cdist.core.explorer import Explorer from cdist.core.manifest import Manifest from cdist.core.code import Code diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index e8c58a67..d13c33dd 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -32,9 +32,6 @@ from cdist.util import fsproperty log = logging.getLogger(__name__) -OBJECT_MARKER = '.cdist' - - class IllegalObjectIdError(cdist.Error): def __init__(self, object_id, message=None): self.object_id = object_id @@ -66,16 +63,18 @@ class CdistObject(object): STATE_RUNNING = "running" STATE_DONE = "done" - def __init__(self, cdist_type, base_path, object_id=''): + def __init__(self, cdist_type, base_path, object_marker=".cdist", object_id=''): self.cdist_type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id + self.object_marker = object_marker + self.validate_object_id() self.sanitise_object_id() self.name = self.join_name(self.cdist_type.name, self.object_id) - self.path = os.path.join(self.cdist_type.path, self.object_id, OBJECT_MARKER) + self.path = os.path.join(self.cdist_type.path, self.object_id, self.object_marker) self.absolute_path = os.path.join(self.base_path, self.path) self.code_local_path = os.path.join(self.path, "code-local") self.code_remote_path = os.path.join(self.path, "code-remote") @@ -97,7 +96,7 @@ class CdistObject(object): def list_object_names(cls, object_base_path): """Return a list of object names""" for path, dirs, files in os.walk(object_base_path): - if OBJECT_MARKER in dirs: + if self.object_marker in dirs: yield os.path.relpath(path, object_base_path) @staticmethod @@ -127,8 +126,8 @@ class CdistObject(object): """Validate the given object_id and raise IllegalObjectIdError if it's not valid. """ if self.object_id: - if OBJECT_MARKER in self.object_id.split(os.sep): - raise IllegalObjectIdError(self.object_id, 'object_id may not contain \'%s\'' % OBJECT_MARKER) + if self.object_marker in self.object_id.split(os.sep): + raise IllegalObjectIdError(self.object_id, 'object_id may not contain \'%s\'' % self.object_marker) if '//' in self.object_id: raise IllegalObjectIdError(self.object_id, 'object_id may not contain //') if self.object_id == '.': diff --git a/docs/dev/logs/2014-05-06.object-marker b/docs/dev/logs/2014-05-06.object-marker new file mode 100644 index 00000000..4878a2f5 --- /dev/null +++ b/docs/dev/logs/2014-05-06.object-marker @@ -0,0 +1,14 @@ +Change object marker from .cdist to .cdist-TEMPNAME to allow using +object ids that contain / are .cdist. + +Changes required: + + cdist/emulator.py: + needs to know suffix/name + tests: + allow object id named /.cdist + tests: + many + cdist/config.py: + have suffix + From 658e759fa48ecfe70b79556ef7d66bfb97012088 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 9 May 2014 00:26:34 +0200 Subject: [PATCH 2631/4212] add speech from berlin, linuxtag Signed-off-by: Nico Schottelius --- docs/speeches/2014-05-08_linuxtag_berlin.odp | Bin 0 -> 495911 bytes docs/speeches/2014-05-08_linuxtag_berlin.pdf | Bin 0 -> 755096 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/speeches/2014-05-08_linuxtag_berlin.odp create mode 100644 docs/speeches/2014-05-08_linuxtag_berlin.pdf diff --git a/docs/speeches/2014-05-08_linuxtag_berlin.odp b/docs/speeches/2014-05-08_linuxtag_berlin.odp new file mode 100644 index 0000000000000000000000000000000000000000..0cf6374c0cce2f1f3f7d00124d0e87f29189f894 GIT binary patch literal 495911 zcmeFYRZtv%*flryKOm|OrKXRUP&QD1e8iEZ1!Gl0HUgcjteW)&H0f9jOy?{S~?5*w1-MpR5 zjh&qAtWAyGtQ{R#JRHoJ9gSVBU6~!7%pJ@eP2KIy9o(3mT+Cg8-~aO&rT@!8)7olR z@!3J3|9JriRkL!pH*qkwwsU21`(JOFog6HqloTXU5D5{1kDy3PeNh2{z`$EjFFX{m zHB0!&1_H6IOMekj^U6NW@$S-?dmFiD!xqOVuqsZ1jS_XwOr4iDmns&Ck~Nnab3!SI zVQv?f3aygLEDnlRu~v~zc2OHe|7c!5|JWVyeC@mF_~$u$pT7(>r>wgt;AF}F&fxm# zYtO)6+w=X%*jVJLsO0ir7;v3ng=}IuXNVJ~_5ZOM3kQXc($mxPA{cUcHcjTvBV38f zPSkt}7uYiCJ)~jP`-9%QgN$wbfvWFBI)|L4d9Y`9n#>StBUVW7k1hzO!E%a}Ww>kr zmCx>ct(*A%bj9;wGr|=aU7+%e+C7E==53# z)lWgKg3jl0!u@nmBytFD7sf0NYDC0kl+u=i*8EQEx+I9E*PM_cV<1}};P*(xTV^KrUhB!6&JaI%8**|gW2Js)_SyXaVGI8d}u zH;z+KKq+yQ4yx^iZN+jEpans^3uxN$Aw;|8a6-?03?=DRY4#qfhk}Nq!9UAjo$i+m z118g13=2fV+-M{{Hum!Z1oyt1HoChve*2b#EewKaP+Sk#Q6dIy!$({xtDm8tjkasPP2ay*ym*XS*syVbb(E%gC|2OO?AlUhN(p z9-9A3dEAU3%jC4x`04K_6?taZ?qc5VvMUiss9vqb#{70ULgviT(JdJMlqVD*sNFxN z^atDIAtROA2HY&1BxOSDtz|;DmcuFG&hjWLzY*(Dvk>4Scy#A<5h==V$CC)mO5zP<#mAmZ(A%7t9{)>~lWmD*}jpfar!E=Q| zT%)C0{jqT{-$@f0KfMnXxTqq}B1nk!$zt(S_c2ZVM^Ey}G+C!W^KTdt#%o>PShNau zOSL&E4S22!E;`&_p6*s0o%QiieizKK{Co)}YwqXzXKB+~Ox)aO+A zO*g|){IV<-Ba^FHf%H|0%$I>^-{{)-o!Br62wq;reirPeG3nl&{88=lx+LVZ$+um2 zebo&fJl1M;Ac0mXmcp=hOJSo6)eI_Bdjp~mwT&P{CiPjL5e>|+tH zHgGYmRVm5{iKkvEQ;PC05+w3!>Tm3IQK!%Be;m6mhl{0?JZ1AfJg$%$-PaJXe;WU66dRpR6c2<_#1IXwU9d=qe^CI>H9SpZ*-Npqars9?ZFK zjppOQS>Y%|gr>~2U+!2%kn(SYGr;o>pwU1)wN?lH;V+7^11)*Z!vy4*PFYqfYLoTNR#RwuK`&3*0L!(s+3Z3*W>^ z@6*36b8~Z-w}(<*sk3(3Q7jQ}&!8)5r6aA)I3ljX7Z6zJ`Tl&p$IthM0d~pCK`xY> zu8Yu<>~vR~8U0fPlJSZa1}sO{?V>K4z)fPsQVO}?vU9Kka@YipIz`!fGxdoYwIGy? zUcNAxSI};mwLY@5|8kt=XSGhtN2L(h{T$ES2^~rrS(0k4hG15s>%B>2l0PGHM4s1^ zToGB8p6h3k*j?7S(h?0@FZm)NP`JGs5*Hcx`EnWT+4&^o!ubXt=$1@CEL_M>A{g{I zus30N241HvOTt2kV%sir@?3s*e=PBp1Og$%dS8z!%A^t`2hmv!dtQXzAJMd|fgBo% zClMf<`$9cQWkxEx~=>9=EK-& z59TLZ4J}?K|a`1s*oqxZ9P}Yu|0^Th|Iyx#S{ojla%5u&jI27oXxs! zAjfu*97XoYA~u7xB%94NTr{{swJi8sRb5Y}9vwdH(WM}RBxnOA6RiEP;+Ptq< zkr-5T7jue2VfsoAlbM|VUD&TwhLsjuJmCd@Ix2Ip{kq>h2}coFy;2P<(fZGWi2H+! zA5ivKdLB%+Q(^d%SxcqG$g0$Vb~MyrYm z5oDtmg=;mxyj3BGH!x%{G2$kfR{$1#ZGkMHeK z31*vu8mrHZRW@@55(P5T!>lZe2e*Nz*kohC4mTaWRNWkMR9{;m&3Gd@+>pFJF%gvl3&PTQ0nq9i9 z<>a#;qAx!;9$AmAu+i-d@tmNm1eC&3Ajs+Z9t4`baHz~1&{%CVbk?!ZbQE8%MRhTD zsgf}5*w{4noWu6vU_p307~Wza_2TX~v2f%*XP?^z%>p{yfol|O+Hx*oVF??%xl$BJ zKB7`pq5uQJ1}E#Q3qs_E2x&Z7m}zw&YH6v-P;_rR!!jL@9i2NY7~X`K{q``fgR@>? z(00~&AROfePZtggzv^mt+*DXW=+&(n>+8lSPn;PgzGarCmGN+5%mmbRFbkZf(Blr4 z1v*t=I3-xFRG>sA)kT-$O_O8GGRGbFBOKcIjL&yD7}eTMA7nZJXyw97gG_J~!E76( z-H|AA|I#k`%Ba%}Pm&Pl57ZC4cl9V96PjX;mfRX1Vb`K_c_zv=0M#irgSc+=aEIy^ za4@rCKZagetLJ-u#*Jfc8PHU6+L( zKO|X^ccD(Pr|Z!1zddXdC^ZYVskKSK^8vNep~Y$@I0mRcCU3(DWa}O7wgROs47-R2 z#!wd<>QH#}HTEk%Wb%i|_TGZvNb?hc_UnSN8}YpJ=tkpqX95uxJ0|uVsvUx)7@TZ2 z*CvvpTV;hr+214*jUd0HWEUV^Y*^EBhp=+s{Mg2JR#=AK1)+aLdo~(oWfP! zF>vGL!x`R&dy7^#{ZxqCk@seTzH<)#)H3qiBxx!28^iUNB8R{Sq?@@bcJp6Kj5LwZ zDZ{b7a?OGNU8yZ<{!is12|A+w55u09TSE`DUf3n7$Mbdb;wEk1~m!*elqT0scb9- zrGX_qSNZq1*UjPX`?c{dOgi75ZkyG%hKkWZXtmST_UkOi9x(a@*8v!X92y3p2OO~( zuHY8t63DlP_aR9STj3Kvu`476pBQn;;W;pPDe2_P2Rgh!a0dM!ewZezrPyU&_Mxri z4Gra@YJ%wSuI3*=$8XlqJv$8UCisn6McnzZvtnjfL01mtI ze~N-^ULLj+4*!-b7jZ+8j}D0A$Jaa`Rn-|W{;{UD`=V~>y_-63BBNwUpDnsrXUL+N zCFs%(w8LiAs&3de6=48dHZI0A;54U|&eB8q=`b7zEe2Zu{U@9SRR6Lt_Q(Q1$p@bL zu;tjRF{o(@p26+x4!Q`~IhUj#K!Y`#n5;qnk)EwbxjSOD#g2JYpqkP3jYhW6e?nF3 zr0oOpx~2@$Dzr%~eGxLe60IDjXIwZmN2v2(RO@EOc6jv)(G{KixIO&yFzcqgZy#mz z1pV>}nj-&NEP@5N$x(7~YG4cwtOYpVP5I5L&U1+V)IA@LAm_VFp%ywX2 z;HK;Ylg6vy%Y~R6K~Q3DWg&bo0mPue1g6&{3fIHg5(3JzZ%Ii(2nQ}t;uN!j^`nd&&Soz&+Q`2*`a+_9E7Ku6=J2|I zm(l5T+U$3o5=igQKovzAMqDVprRm79trDhx^Jw^@vd77$Kz+KDrYIq=dGm?prg~-r zIWiD5wPd`fE^t1joP&FQ(pAnD8;Ivi+Y-u>ElUBDDcPWfqr{8@P1|x-fbzNA(pP=0 zx;3z?KrF)Ja293+Ie-wk;H`neYng7tW%pMfF_d0y1ROQh9SL5|d!cigVqQE3IXA4d zY#Jlj3~1yCUqMOSqDp@qJ}bcE7`HV?Weyjmio645{1VpkcXkv^({bS>IwsN3?M#tm zjMQJ0k3>UmN__On;0JL%HnK8h3S=n&A%eMRoCc3_J=eUOlQ(SsG@1{xvIcRu5x@1K z{BEF#{^rUAJ1X^e(kVC0nnFv4jphe5M^|i(p2~v7yQmRU|6qCsvk!b}5a!8I7e2Qf z;T(TwMTdism^x$3Pmzb9kM`?50@+{=P|_oA>n1h4n7PfdZvHUxaU82cAQJkB+eU7X z!UHJ3K~xVe9viCuG^yRNKloKq6H8f$)4`sd+_G3gX%r==7x@-Fa3Ep4l-h)MG%{T21{u}vPN z3S?5aQpCT%Ng-^C_V4Gm5I6%sR!1dWj@(F=1q(c03Cxr78mm(W1xV}Qsi(_V4s{7 zSjqDrLItrMlLKyn+6v_mZ=Bg1P0(ew0xkkAmjBllkc;1kHBRJ&Bv3m4=C zOi8!-^VcN!>|4P_GJPmI-oH}l0sOxxVf#y3UY_K$9sW{52ClBtzLPRC?#z~z8>@^m zdf-7A)(u{ zS43LWgBPZuLZJ^@fB2RX55mezgRx5FY#1hmI&-r1-~s{bWSSX(sz@=cN>BsB6U7ve z9)w@B6sNu42Dl;nq|`Y8qL0C2fweqvk%9>vRZupAi}b>K{3;T*tyl066+6@S_gV}J zTS&+lH6^)E#NJj2=F6;Ze03~B>#L~+SC z^uv~fp}y%Ny#0tqbqMAj^6%|ayt z)*T@p1=Sm`r*er=CL@4ID>Um!)!3@O#^5qRXFPsmb|a`f-K}9Cxrwhvgx?L5O~Tv0H`n@Gn7C1H&m1mIT(Ip z=wZrT6vkf#DQu2klw7LTG9bu#Za>j=5~|mInCo|?cpUh?c@mbfkv#H}wn%gxL64oqlKYP&>>PBXGLNE`~$VM;AR}dw?9TCZ+14 z=hNjPX1Y}H3^7|k(VFbl-Fp$QOzV4!!$OpibLkHVTQ@`ex z>PbrwO6iuck5Sn9A{n(Cslx(!n)V~ewc_ahl`@CI44;!r;vdOuGeC|hPpEEF1=18vNytu1PP{8x| z7L%FASn!|AYc*y7%Lgu^Z6c5LkYjN1FdVZMJC^yB@_6$JU?EE|Ze@KZ3Qa3-Il7UVz) zxrojS`H{fy| z0n0a)7r*7r&VZHH$ASH*^b1W6&J{@en-KI9f{gG5(Dm; zf7}&JvVF%_zb^?hOdYm>zM~!|874O-vwki9b>oi;SVU)#; zb^SyT7oc5y^>kPfui-Pv2auWBB zw_$}RG6j&N@Hke$}e@Oh{C zelf-mdg{5!n}-}}gE}E{9$ys|_p)imo1npdnI0j4gJ$4eD%N{Q8LbAYuBk#xm3$v@ zz)rvhuGC;cXy!vU>wkQyM99zQGrsa*dQe@PoX!=OuXPJG49=|qSQA?c63xyMRv}u4XWfu;91GGw@cp_rgh4h71zFx2V)z@^AcS)9|In1x0wv7HdJ?^H%RW1rn zrW^PmsODQPe~$#n@vZ4?L1o4zB%F^BCj_D9X5s2;A!61Y?2$;H{fP`QB@uV}H-D9W z(3TycTx`5YV9?WBg`i4K!cEnp4tg`k5#fcqR`4fBL>op{&c8* z540nG$__D!9Tp90I)2>M;=K%dJj}jd6`&-r(P03Z!^J#4f&5@L5E9gKwRP zP9F zYS!q8XKe=NemppJ$1k6XP{wHK4Fy=oKDw~ctG81eCl!E(%o#?v2Klk&4RX7v$>Y8- z+yp-^xBQ!bfIj{&-00BFgRM(54&j`vY(Ze3={aFU4rmPKBUgvqcV)G1(L{`uJ_&^F z;kab1A)X#|aLMZsw4T#fgbn!0d`M=Np7E4H0o22sW)LuU$1#ZRATD0UoTP7weCmS@ zf~&=*pIkYvPxsh*2Q(h@e;w|jw_l*;c&Y-v86FI(Z1&m^Vz`>sDet6lNh}%xk+FgY9`Eb&K(4pQvNXiu|H2J0X z2zkC|JW_@GdK*x> z47GvODRMyvj;}1L5+`JR#pl*#tE7A`@HhIcMi?h0P4(#~UyyvXBR1V%EfHk+)p?3M<8oP zkjxzedVo`gL;~qQfII~RLj(WE-91HUD7HYsSQvqNAs-y9{an}$LHX~j1pwFa^nqG_ zmr}kYsThN3tlSG4NtnnfC_fs(8ycX}e+epmC`D5_Tp)LHl%zX}H#&7Q;hkoNzg3rkBS+T?gs`qFACXctLd;RUI_w{^Y zOX9ok*L>A-s9xop5O|bcfci1~EOa}sdh1ix1d8af^0*}L)A!$4l{!4GND zU3qrps90KSk70x$UnA2Z=6ba=MtA<74p7^9c2ynF6kDV*$u6{K0x(w( zJj8sSXR&kUZ=Rg18@Ktc5Yi+@WbgCIanTZ~G;mGb17>xz69M-d6=XkpiwoGT+Ju8Ff8@ON=dV1~fWHSb z#Pn+0@TZ1%{FFeze}uJs+E5F>jgaEGD!bP$DAmdmaFr!{e+712HJR&`6@4LbbB1tZ z4{rMZ9Kz_8F8=>F{~x*s?9vhv5;8J~lD~P_H19fvB|)^_`jE?R-+LE-fL=y=HGqE# zCmJ=5AhAfM2Kqnun3xHJR}NC&^W7=*+#OTAo-*^<$CBx(C_frOIAU=24i1}<_#dRR z{?}XqUtoB+e>$#v2b6e#{-YED*vZcTJ8LoV{XdgQo+Pm|gudjV{pz^xCoZ$zaw3I) zNjym5DlJgwk!KoYM)aRJ`4y0k(LsXE4*z_B5|rx*L5~EBrP#f_JOU+$6wv1puJ)(S z83U8eFe_dFh8=}~9kQ|Jv0@KkMQeb|`HvfV(*0rA4(J06bzLsN7Y777+vR$Sr~i}! zDMiHyXu#1yx76u=Jlr4>0!!Tk2)Oj*Z2YH{(dK%YBvFbF16&XQ zh|I^+f=+65TS+}vomI;eNC4tKGncX6N$Wb1cy-zo#m%ig9$J&+O7Az0^;z~ z?J<}0)*#S!KJGFba%%%P4lp~c0f;m&;EmveaNtMv%4)-(J(g3sz_8PER9Q9QqNI_^ z3p`(R%RD~~U~;7tkN)pL0hp-$ z}R6c>|Uo>*E)pDL_(o0x5xTuG8x958&JYFdauK0B}W5l!32p z^W_ry*q`Kmkw@gl07s1l5PX0dUS?*N&F|f~>hL60g$#k7Gn>lC3u(#e1)lUuro}P+ zb1mM0pGK2~?sN6te4-G8ml@4}7jX$xk&IYC2;ZN|6JlbD!>t3{5!O}!<4~j10{R0- z_Ek6lkfSBj0Qvp3=lN_q+rO|J$Z(74isb(x4+o%R|^PtWH+Rp;48h@r(i&esGy&sKqSdmBI#DqfpY;G66n z4>UcRuK<`lyV+vtg-Z4R#BGrL8ZiDU6JAGTmW2Wqgy*j7-@46KGdZ4X(iw4I3%p~O zh2Aa`R7zyL1>J_@Njia%2NF%g5SJ= zGw1;yMX7;$1pxg$-~y4FU#?K4g_V?zi{+vW%CCz{WHQNW=PV6+ypRiZ6>3|7>Z5+Ui)NC}<+A>BGqf+hwvSEVm=Q%Y? z86DkF!W;S9VtdT|uXW!IsC;gTZ-NgSAt|`wk{T`-2%u4rMg%H}@bZe|PyKQwia_7j z+ok)HKi7uuPk2-hfZqx#2|&u;y@B8zs5vt;bR1f5wpPUxI593j1O@IP@*vcmu}dU@7aKE}*^wvLLM4{d$0q8l!3{GClnra1X(X|5YOLe27!X zQHe^t%_9&Lxd34f1WWSwG0 zzXHP&VVw6#!w7)d!&|R=q0y#UJ4(BmfqqipA(L+ixI%)ffc?*x>c~bJlnV!K>$)Y* zeQpjer^V1nfX?9ebW>mqkaLAJYHq+`RDJ{X9AG15o&aZ#@n(NmN|WgbYVCkQyvkz& z{}ucKTexHQ?IN&e--DjpjJOr?=!6?9=M8G*09M%e5r+KhVObsr26=8qFsS(vnEwHp zJV9iqHwb!c9QzabGy9={Oeza8k|5K8)^3Z}oOEKX2K)dV1HXDjK(J6L zfxiKsZB`7Y_U3$j{UOOf4yOQtyRWn;8egei)|xik392&eQDOmy#UNYz%VWWcFwqh5 zj&r&-IUk4VH=uXR^SnTU0X|F|rRW=h2&)J#NVCn!xN`WqPq?794W?f39tLH;&3PMW zuk5<$u^C2{JA+8XZqe-EzRvR=-(dnvB_t-1h|A~+FTk+zsX{oLjR(j;5h5E! z6x&UtXgw@s!RZuyHlGNUVhK51ZVS-vPiLq~VWOx8J38g3u$q;6V==(w^xq(RB#Jdh zrS>6Kr_n6xE&~YeYQSFM1Y!!jGtOs~l*4ijMJSX88%FN25f%sW#6HrOWsAz0M2o=CB_sN~sYDvqzunbq0j%BvEH_pIunnx6C^a*?@dN*V z5~j5kthJI9pKHm1dbGD|L$Xh?^2hb8s0%$ct2Y69&}=NG z<_*@gFe!-3YMQ)-cqC*n7A-7)dlU9RvS!vF6ek)ags+a}m|q~mWIrHu2{fmUA&{to z1)L!aQ;a`nP;``xd|9(o)HEya!$DEP>_@0#fMGtn6{ni2H=?b`={&Gg<6G!+bzvK& zUNo{XP%_@n^*saXBP!Ntxj|7E9TR_9Fdwa)yvD_-8mb`pJO9HZ0(EHtzH=!$5kR%h z03tGV5QviJ$n@9q?Okg;(DYAgjhdp?!e2(yV<^x37(>34op~2VZ_4hRK!rhw` zEW&UVN!S0TG=PNYl`qN4b(B!*4U*o$wJ+V>*$tH>KN0vBmY3c zIl{QjH$y!dLOJrUFzLW?FRW+4pk6^$nLtfOnY!(`wv)s5E?cFJ^wlJ2;35+GXNWXt z5}Y`z7_P;efb}7@^MFN&nGBxB$dRG$@BQK@e;%*L1Mp<&`&YMoPykfJ=cEN>$1uqlq2xQnAUt&mBKRY zT5d!TM5||IXo8R0o%mi-+!q4Jz>?^*o2ohCQVAA0q~@Gwf9n*t94!o1MFhLWDR!Z^^B?QlQF%~kE#du;H|re@!k%6sb`DzsENf@P;KIkKmC79h2Z9 zJ`tiabx%C;RF@+-sg1EVg7 zg!4tz{1```%JggI;)dw#4s{Ls{jrDQbh#i4g%Lh^{bLuV*p;Z?lti(6q^%e{0G(tl zzS+S(`Q7@-F6LKr6T)YzInjx)StGp$fUP;-_|F~PYLXmZ>S?T*j;RKoJ^OdsPJ>u? z1COlbEloVj%>Hi?dil^8pOS`Uf7Frrm^|UE(I$V<|Ez`9`+9!TPaz7TRk%|GCdMy1 z|1WOd;NW3PclPNp%KlsUAuX=(rB>7^_wk%`+{JewKYYx0RC`b7+npgqgbj z-Svqy9c`o*CAa;v=osP`3RrNu8XE-~&O^g1#PveyC&R*Aa(*_ectpG`5}!j>uXG88 zYdKU%+80gv5+c`d^BCx4JMkC3OhL`2YX!nrej-{n1{R-60>|vi5?gq9!T}7`&Rzp z?mH;j*6VcP&yT0cFDa+Lsg&=n5xK#5lWfz4pA8J*?o&@nrKKJqa@q1=E!MD^h1@kf z>E1XKmE<)|rk^}Z-$%En%>HcNEsg(n0~3HaaT6qawj;BYU{d#}xeg;Uz%AFmbEZ7H z+4h{_=#j;t1@1JcTF=%=8EzZ!B!it{|DJvHqNvR-leVWC`6=?+-c8X-)Wp-!`$zlw z27J0zpM~sxgiUE2hsJboUe&AGtoh0APQW~-Q27lEM5N#fPXqGE?eB_e(QBo%Fp$>x)8B%()pOB6HJNdP{Vt7 zjWl*(9kVf-G4Rzb1Hq_SFKcXEYiU{p#O^RVZT?K~pVPbh;Z_XSD0krwMQZoF3SQ#! zyolLTV&jC)6Z37$!-_zTTp|h*YKtEpX40M#JWr_M=wT?{Vk?=7AQcQE_ZAG4-Y8N( zvl803)8_vDnXo`RKl3Pz454BRQLivLiv}${=2~X@EQ`j+uYy>s|4?u7cQ6qndpG9b zg{B_mY*pDs=2Vpzi-e}iQvC62K2+o3;^)paA5T18dvJJS2&T%$$*;`c7EhYK{4)Rt zuc{i)FL$fg)$ls_z75<>8vD5<=~cGfM$`~tpL1n3y`@V)b^MZK{+yl~hej{0?Iq@P zxhYUl@4Y^CNKyM)*b@EwysW)rbSkYQC8f&HN>%6cgy4jt2-oJ9P~$RJPc9w18$p*r zM&!4nBW7PBq8`*4H(VQkX5XruE*@(;G;%>q)n*?D1zB(O|7J z3vOJDyGs-HX;hf(?JWHh^amgHa+cQi*dzh2 zO%*i~H&(Qfs8O(pH|!`jp_~54?7Y&LBxr9U_7LWNv`tP~k^!^DnT?+7kL+MCvZi?eDy_Z#dZa3dKTX?eG0`BgL=AMlva@%(~Pw9L9u10P% z9P-}BIX?u1b|uyJU~>+%WmA=FvIi zAOVZqDG?I$@*-Ds`XaG*&1-(3-@)6vpU~t^esU0GjLW$qBqrg;{91X6rTZXhJFG?H zG!6Qw%saxGL3(2uj9I@Q)yyyCOnh28@*!!AKSN`XFefPNs=T1_ke8^DPtItm% zn0%pJoO+H=li2uQ@Q+D1;d=jaA(`vjeK_<0 z(SGgqqN)Gxe4d5Tv^VMA71H#1ck5)O&(sK}qnX7&lCa&}nTJKnEzZLWItYO=yhpwpoLu6dr|j>K;FB0cG_I~F!vr>Zuc z&_{B-b;qYB$l|8@sBy7wSGUw+{^OiV%MwF3e)peZ%YPh`-u^}kWR(8qOE8Z0t#9Bd z271$9$?z*=>-M3?G4h?8vK&t1uEpiajWe7D$D348=lg%vM6&3c?rlpa3f4Pu-eLah zO(*)10Vc4(N>tkar{07F^d?hB2eOg3+> zr;x$FzWJkOS=d|)^j9pk8o6Hg9>0(1R`f5Xf4HGw}sDbFp?DlGis>f!v(EqvQv z1+zCy=fF7E$mWvQ402O-MgKeJvRmER}=F=^~K6hBxGC&*lo zx%5(VwuP&B1yw!^Q1fLcG-zgU=;ZHOEZo+kiElU~m}=P4>C+Av##o!5>Bz~BR!?!% zvFFY7YinS{9#vD~A9lDheNUaJjDhThZ*{Q~Wly z7!3}kaoNDGwg$1px@t*XEAG#`36O8a*3;rvhs7bnP>wgoOg=GJC?<3lIb$9?21Tf$ zN)VYuYjS^&^4}Y>^`7==ORw4*q^wRPG`STt4qthK00*5^OYpBW)*6efRPCUY$*6eA z?*%Dav(p2$+c0Ag`AQ=2L71Wy2hyHKJ0g{*rg&MdF*a`4CcK!EWxgCN5|-in9;0c_ zk57A6A#4?u>*`^+GAqF~INTmmzo?HOTJH93UDhVLvRxQ_Z zNQZwKvti|j@3b*yW5k`S|;v-?)zBw&NwSFhDht0%AbxE3<0M33;3Cvmy3 z)6Sknl?Kt$$-;Nm0>6J{wQ*LYFCWMgFxbqLN_ZUD>4#iQ8WkRT85#Y%B70|UR2(zM z_M_eQck|c`CDrrU!^iKwCq6?C!qHBJ`J*Su`>f(h@}3nJJTvqu#b$*Qn#ApOu&ZzQ zPrXL#K}E@-W-4Dov?qTk5JeANkTz)?;+&OP47(JD1MZJP-%W_rFalAgGHgAv z3WgZ(gPKFuc&KhH@H|VSNu2_d{SA!p5Lqp$OCX=nKG)NtK$cv>7)jo0oa z(R_I_M^~rpsVnf7V7GKmy>U|xehAvv6Mj@f)WvXuQjhX+2VwNiom0+r zN0hTtu>pPqV_+*3?7bN6V;REdsZ=iT$?1e5wr5AL@KlDI zOAu=+E;yB-A8!oc;cM6OJ;7Sp8xGM#Sc7$A-Y2g!~qHw3&cN9AWzr-ss?8a{t-g3X6Sz$@N~*GAgN9=i8H@qdcc#5edz|51OBOKR7vu zp*PsiA8`+}>u=*GJx>x#X(s{lwTuu<5NxQ&T^(RkPQCK-7cugir=5$fgGh+VyP9w`i zL$hTLeiFWMCBeyqHtsZI_uemwMjX%O%qd94xwgy{`MoR2a1NKz%AaP-?|l22(r`~i zpXAz=wb?ggM9){5_bXxk2kba>3;oqhU;is-B)ggz+nAO0&=!5l^>P01)%J^A75HQs zOjKfjPIm~bf(R9-hqv&aS=uQUFASoOHSYC~1pNfiUDCU`2#-eDU$vOo-MqvW!VM={;1N{(Z|uDVSRGBXF1m1c4Hh(5aCdi?V8JE0yE_4bySpYh1cC*3 zcb5bwXwV?x3?$$GXP^Dw{p@}2x##TXx!=I7d8bxQ_jFfRbx(KI8ZNZLwMmJ!OGY-L zMBDQcCBij|;^02FuWl&^i*aG5lE*QLE;9HcnZ`27+C3t?;_z^pN})#A@dYvSB*D|b zVftCHn>eo&{6MCXB&XC3)yl+<=tbS)v*2!wnW=naYNs@hv@%gAQPMpd>iy|M8oRVL zfsD^A1>dS&qCa|;d9z~f|3WK9heVdoIf6aPbkHmj-gYjg<2rtDc~1CD>2=;o+k+_v zBn2T%aDtK8mphl0!qrzqG~!?6+;+_l^!j+G3E|s}2Jf*IKY8U*)$$NjWKf0dBfpK7 zkKz|vg|Z0zd{X6-SP~CJ5q%0Z zo2;dp$UK_IaK!6f+fGC36m_tAvlzkO{2^6Wz-?i8N7O5=%G;+mIFn`69&so z1}Q56HmF;YtXh!tYwiRqMd+Ir{%m(QaGi7y)XpFjF7}IPjOpDj3{5v0fiGEYn7DIU zSv{`;3uTb~(l-4@_R|E&C`nJfA|hufkkV$ssrKe=2}U$V($o792uGpeYVlGbX=x{u z?ue$bU*&bY%!sxgsSAH$*P!nJ&Js5>V*XV_Ty=Ar7mksxR1;hXtB0II@C6K(`pa@w zUv(32+63mTPq$&1A?lx&G0F|w%AJuY3tuszl2)j(-n~L?5~irp@iW-=WvvdjKG&|T z9N#>vBx070$QqF($}vnWpFfi6W6sr~%gDjG#H@PDFY<7A>zg-zrgMB&xrwfwYFLFA zS=Yrlw)6p=9xF(>za2*yI@hwlUC*XwX+kh$C1R0)xqpd7n_O^^WABD~UtqAbp9Rs6F<+h^7V$Z=tn^oD}Sko1w8@$I`ZMF}csmR#6jM<7zLwux#tbV|)MF0$C-na`Aw6CruH|*dZQ$ zDSfRs`Ko8x;hE#msc?1URx@jZgo&!agOMzA^S4@%_fIVTJj?R;M;0~>LAM4C@NNwR z4zJdc6TgU=Bu6FVrmCw9lYoUL47!npiRgAUe%OCWHJ0BNm(#MY$Lm@8o%gKP6V>#~ zWimdV;ah>>4Bwyk4>wdP=Iif5hHPoW4V|66Te#JBh5H7JwK zx@K+MUXy&UWVH)#sosudxH&lUUBcBF7d<`9C`Z8Q52@q2LH5k{rM54oslOm1Xz**Y zB-dVBzlz%V@}bMa%rLhQqq*Lxv#<(IDXLdYMOv&T;I&GLU;O%dB&!{bygNiLB+QOZ zPjIJgI!k4h50-Lc?}qx9vVx)b2Ewm!3~xVbx)oa*Vi%qGg!_X}`GLG39T9O6-hv@t zR)81Yf?Y;qnAIC*!PBxI&ecyBS-vJ9b6hG>F}ME!A`mVT%ZJacI{p5;fb0dT~y?YPjJT|@9rjER9 z{~dZ*$9SkN1j6z6d}55>?!Rj6^r~|kY%ERN-$LLnteF;gMIz)Ut2ln2H0y%paCH1E zUajvF&Rdfd$>&-z>#!eRF1Cm@Kb}-x(Ubg{$Mc=(s_2wy61Myz$`8_0@%Uc<7dMDY ze%^P)b;T$XUe0KCJf!yDz;HBoX|nRI6P7UO<2<#U3_rmljW-{A*iB;+w03+}SdR&2 zi}uS2+Zk43?8>3J7iakW0DaOjez&zhgQxVeK2XryK)rSwR^f$)ZGhNr zI7j&Ao0t zYcLGvb$lwpDpf(%QX?*vTB&@7wzf|>EAX?1{u0Q-*B__og6Zb_ zgu^+lBmVH=#5VL|g2c>v(Q?-a0i=hx2AX?H+1VYU9Sq;PX4LKbm3m6v+A7n)qVF-{ zaZvjBu?X`vVY9j^?EXHxDxn9A*N`LJpg|CQGlpL}@k6$jE86i?yS)MgdgJp9weRxS z(Ou@A-R7Xr4>`~Ji)1X>k1Vd-slyt=L-Yee-5!c{OE1#j{|Ui%PCN%H&0@NMQ=j5G z8!?H$2`ySppHrOsog)9ShAUgin^#7iU6 z!Mhk>#;eCE+L>Qa@24Kpm|Q(8-tFkFt5Rr4_I|Zyr-!}*>o##}K!9?$AhLN|`{J-5 zsYPFszpl2qJYuhMe&X1AXHk5NVKrug9hb^|t#O0muvM7cB3jbn4gIWvK&*%(-Ti~; zdiH$I8PWmRxJ_G7KGZx>e681J{4+S;A@+eTj}Pj8QMRjoAPh5zBQUg$q;i2C^)zc3 zR=G{gPv*$;!>)XC*X^@wezjjLydpYy=yF9aGME{n2`I(;;bF;^n z>K{nXRMli2R(u{20iVF(=&21X_YRmscMO|7EM|{Pen!rVe@md5FOrCh?7-x4Byf|t zaRX*=1f17PHM>c(;uo%64Mzi>p)Pd!^E(nwAwwq!?k9l{0nzz#X)rd!`L(u`;5RO$ zozaj21F3Kxqeg1UknWFtA#4 zeI<4k&OOc*ZP!^EJURt>eWh|a222yx)?rC}gpbuSkTjS*J|-)Z#LozZ-i0KI=k=3M zYH9c{m7PGn`+O;P+tGk=ebUbMHe=A|V&+o(dPH2mZr9R3J~)>Y;rr!a=Nl6Qg@A`2 zhd~lc-@?)_!28M-&ysKlFzRzwuU3 zoxU8z`nFD<1A~K8DP13R4qvZc)f#Y!b>OX7#Y|hwS~eK^epFnai zA885n(=b@}O@&dmIc>mU`S)~1AIbJ2c9!f~QCF}P?fzQ|1OgTcV{Bgv1 zz}W9W{!;01TZb6eUqgiMwP8E$n# z2xYU91#(3brRC=y5nbzLc7crLgPHmdLQS#c(J$fGj$FV4-b+?Z8J|!FKr)0NaS&;qi)+ztpl?t{cz(3K(5eUB8NI(}W&_MI3Nm#qA$Hk+*)9%L=E%Zp`@Oi*x*~a=_~3!Ob|N(wBwduqdI9SH@pE zi!cazM|2!J$Yr)5a%D+|#idQ5f_H^mhzr4fI~kj>XK3`U3Yf#sdOhb^@%3I2pC{MB zGfQ%7X1h?9#q6GAaUj8JYu7_zd1RTJBT~Y&sM>=f@qX6lhW(QB>`*}jW8a0($Z_h7 zz?RXG_beV_(uBf;#M=`LZ)TdqcC}|=o29mODGO(meT*vqya}y=x*WYr+Tq)e)#QZw z)U#5oI6@tL*L$~SEGMDMQ?WJ;Or3l^&R3WT*TSsf*YNj*dbzIov<1o?vqR3`O81{( zcPE)N`M^Q^tlB5L!VjTV*XQl4_wVU|V_0u;*rZFSokfxW7PTxtYdN6VCCtk9?0gER z6v7fUN5Z%lJPR-@F(1Lw(H+BJO+f9{z}Zp3nF`)2;X#dVU=+r(2S>E*JKyHfF{NVAi7^$+s9%()QTbvH3Qqq6|$%^>w z(faz_z-ZO3V3aG?VhC3c`%OXyrqu%2$~SSm?4V1mRFaW!<$iB?Z)^U(OH2j*Uhwnw zE7M(ghWoeu2z@e;bytG2cX5%|w;s+knOFmM5BulDmGX|5r_lbz3;gaio3bvciftpG zv&|ZsIk@nW=FB3;5bY5gR>x$znyVddT9-p(dz3z~h}=(P{WKd3BRniEs->}NT+`F~ zhOPC%<>(u@uSFgF-fpo7x0=GX_A>cA8@izWw=&`CZ>dQWwB!gJiuyyuvp7dxE?lJ& zb6kqo9$9=-7xaky!5}NR<6oX@`An#b6nO2jf{s_@i`i0&;h4Z$MqPMXqD+Zggd4x;m z4D4uk2KYmDUC!$=GtR-K#MGq-tJD#ntg`|;?X(*=VpeT?v&6{dJ|BIX)^AdwU!rcv zSBW~@l{N4{^m0MGi(;DQvYS6(6;$sWl0szIM&zx&$&Wapk$y2sHxv;iqh(BEEfGv^zY+g*5POB!6CBFP6UCyDhzD|OPis(e+vm!a8LF|o zf$V|c5RS(6NZJY~3f2uxV$sz|DWKLYohg~IlcmHd3W{N%setk~jp_om+v&!kgSQW%?Q{|PYRQsZqRmHKVZ3zhrqHutPPIwzW0U7_!i~@)}G^7*h%0O7>B&r8)ndYx1{`+pm2~DJ1jh5;#96HXnWyY7bG!izH86Q;!-Y ziWWgnT&dI!b`o(Z-Tk0LL!s&No*t3c(JC9YGj&?Cn`*vCvAQjwXCs^~S0RsVU)`(C zKBZWEW(JP6>GLIO`DYI|WE!($S{h1&u9?-49VS7QcP&jbr3J zt9>(Bj>FEkY#&qSK{=ih=+x&RjN;9O^m$=sZM^H8%}B~)f1hy2<(tWk<@3Yz4{bkE z$es~WQ4@Ke3eJI_Z|R9pUT?pPex5IwL`@^wlXpw!G962_F@lHh?admw3y+8Bl@^bH zG@h(>g7ia()BhC`55*TZQswvqEWK_-RL+q4yJQ!-212bvsn@mkqE*pMC}K;{8)Jb& zccCgMMm$9?zg)c>Q=ez@xaohdpqC(_c5D}#f3FGanQg~Ow=}Ezk?(plKf0U_iZ$^Q zNj09Yq^pH@)9k^XY&s;X;%34dz3_UYT=!kq5JcK2`>i>?2==&1GvENJ?5z%h#q&i3DO%Xvh0O->y&;46v%V}ii3y961@n1B4@P9G-USq5nq*6 z`D;mg2EB~PX^yDt8=Ye2x0gIhiI%hpS2&*wxDYLQEv;YTEqT4}gNd+~cl)rwX^7h< zuHV2E8iZ^8R*{v^GyIhPkg3=6u#b~KWd^TTm-GD~EcfPqUgJF8o=^ApfC9Uhl;LGm zbtp~@Gw@CfOr%4O@E@X#rS!SNET`qs-8!kT&_mSMASIzO`f*mJ*-BqO60@H-|cM> zTrWA%-MtDg2>y6h?j1T;F%dXJ*d6vEki6d&ehJlj0PG4ki~@@LA^&3(e}Ar=tt^H60BF_EB0 z*@%Tjqp;d>n)YzT0xenUn&#h**Nl>(ChU*#2PhZCX8CnVsmAV7H|3N*Uzzqd8Qn+6 z5wGzW5z?!?v+i%#cw2NjamLn*)Th^jaMr;3JiROB5Z#;8m?>8@-ebzx#1g z6^Bj%7OoRxj0E44mZOM|acWx~`(7W>VuWe@$LY4&x?Ef-7(PY{`zsm3VMR;kk8r|8 zYHJgo=#0$@Wa)kBOm>nkOLgFtW638AkU>#dvFrlDD+du;*+F8+3ls&x7)?gI5dD;z z(Ty%&N04WC^g5aES{XLAGuG4&@VKt}Orj4z9U$0=CwD}&5Cs9 zI#I2AN&AjMt6m{AeNMj(MF=JD++B+$s$j+N7#faHKNci3hZpv#cnsVzTnl;!+7A59AC6}wGYl9$$(|>%k|t#U0*ksD4+az zS(M$5AS-pSZS#}C@81^@!O=<1_103G9KncCygm+B32jz3=m)nGXuXM_YFbOxAL!lL z{doKq7i{I6*6f21&sfF}0#EJ*au2j7z_Dbv<0b6!*_V@>n>08n?C0Z&5&TQyWrN>H zUHgrbdBnX3-?fl<{rI8I;6iK0%1b~|VQZqT=SK9Ul_~U~a~d`DLM%Z0=v zJ47Y>MpA`FxqR`4FY!g(T_e?R(0Y7P5)DtT2zL9cK*_?07yoWyYV4 z>YoNGf5Q>>YDw6gkP6qmvL#B+oexSBziGFVIg%aiKDQ9Yn35lEi;!~^J_B-IutI$K zQXDQ%UYIM(!EONQw1Jf{-mlP@SWKJiK;GculsJC+gR2sq*lh{@YKza$uV4A8167cB z-8=_#qI=!cufkd#DmJuLQ!%qv%9_>Mtqb>hkLGo&cSb*2bEQ>F^-KpCNR2#~i+njS ztv5-IwNhv~TloXO#aA>$pWzj7 zBK`T14_(u5!voC|JGaTLR;ghGTlmuF-jcU`U_XZOaBFQ24cbD$(T1{rF1EA7E=DF6 zhwnh7f;yR6M$VWX$)?p zmh$|k7bOM{$tMankz|U6ZddgIg8(l5ywK)~dI8K%4m!aqI&*ZUd zbPefXTV-{dL_Sr*vuLGnIUhhK$}JtCDT+$H1Ba0|a8h0Ub~~P(Tb&dcIX7?qUVH_9 zB8@gS*~pCxzg&}(W|2QX_fi;LwzE#Dhs8uf#?mAc<|n7-53Gn~E%0DA8NkoiSVMp@ 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

    i4k4pZwSy~}@Yz=yIBPBO;)D<}p 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 literal 0 HcmV?d00001 diff --git a/docs/speeches/2014-05-08_linuxtag_berlin.pdf b/docs/speeches/2014-05-08_linuxtag_berlin.pdf new file mode 100644 index 0000000000000000000000000000000000000000..88fbeb6e36d380d2d5eae4d690ba735ffb51e3d2 GIT binary patch literal 755096 zcmd43cUV(d`z}lgB{T`WPk_)ngbofRfdrBWp(7w2LX#4z&PX>@Aps0Nhr z&Mu0hJ~Fjl0{_0lGEzymrDWKXj8%`k+Bdl)3U197ysSS>F%Ppj8n8Zd>hB{u<=1{8 zRu-(e(mFItXl$9oK_#rsZMT(5o(giG;`560Dmxa&9e?B~SY~IYq<4+YcB&t*+p`(6 zkY?E2nZ2^w?DOWsO{G@V9mj^wzLT~bmxUwy8JX8UOfPudK7MSW{nF)6Hn!63XX3KB zn?D3yi2iKpl5J%E7b~BqeHm9!RN(jd0kuO&xDJsxtmx|K9rk`}gZ~FF=j7-hE%#&o zVL<^zEvI;Y;^8$q(k~=P%Z(6th@_6L7AlAk5=w;X7#L_-5r}aPL9x~+Bco471w{dk zKOi?egq-UK=GN9|XJ;F~q<>)7`sdBTFE%m`P?9}VLr2Rh!Y?2k9j5~&#>NL}S)YuE zkBo{t91hUY;pNF#r)a-`AmF13gn%I1SifYh?~ggI1J(BC`j09PHljmo>^{qLYZFQv ze94?T1fk;UL6LX@WYPDIiscG1M!JxMN0&Ca;|DASvGA|(@rv#_ENA!h5CW0>XeJ>s zhBV|2i72<3A=*df{*exHc#+F(xh?Xw4!$V6*AX&j5p}0Uj=0i-1QngI z&8pg-oWd-?&H0LsnG_Tx>)>FYj5>30W=Em;!NJ|HFfytz$Lh;*a6OqK(p}*Q0ZM4V z)MOllbj_6LEt=PL10oG^A7*eutkXF)py|`lTq#IqSsIISw2iRVSH`W`dzb#~o);(j z@ja+x%sGF%uVw%w%18r=kX^ssCwlNzYc|MJ{?ft0-<+ZkRn=>59UQy^!_v98TNSy3 zV5+~a5b7x_;n=L5?s){V1|pJ)tPvx<>++h_5zDuc+urrj5w(F>X^A0-cpG_G@HS>8YyZoa0~OJOj^k_{-a3SO8ZbR<=7Ww%cm);^!xI2m zgm!q!L?Ha-%o-61{)ZDp71Wx*^KIlIL_YyQ-H3~!E1G#D@(|LXd@cD933*7~006v2 zt`xtePqB1z_aVH8S8``T{BG6XYkp800R*wgGW4*Sv*z0;(vsPW4q^EpxB(a1w+^N) z3EDp2z?udC+tH@k9~=yFb7}!Ip+hpc8FR-;q(k(MKc7R+WHplZ;B!_wl85uq-*+Z{ zdn)uQ;gDnBp@&|bwrKn&(ur!)&QH3M=gc?we~{t>r|3ZgFyg_%&Y6SUGl!K+2OE6+ zCk_r?9ef#JIXEaWI#lQ1xLY4Y4+?)h_}jkq%wOl-8AU)VaCvZmt-n#O-s#aX&01(!0@qe;vt*L#V@%oP#>zwI%?*$eAOC`^`-_wg`6LfscKA-oe=w2fI)6}i@G1WDiG$DR zGoLZl2j!SXKw@+~O@tP1$20ueUjx1<2hcNTpC1b^@4#Ai&tdUDxH&*?NCA zKEI#D6FVI7pECEO^6mX^TVv}?(eF*W&9}ZN|8fxIa&RydbJ(^AUj(2Hr4h=l2=xHa z`s@G5_YYA^8`MOv^p;SwOyPaG_ilarV62k=1%=!g~EMGg6Dj~>DU_|j|IB+{T}j?oa{XTOE0 z@0JPv&Lep+%MYL+)+PM^lZqhGYKt@&zvqAG$`3f5g9E@%0)IdVJos`b*t{fGpB*sb z=MT>KPYpPK z`3o@K!;m_<1zat=oB>WY@*i47KcgWtnzs&Kr@uM$f$+&%LR&p8SW(by z+75a5&+83Dx}HYb`9Z2fPXJ^Y-y@)9)PH=%_a-PBGW(Ox{t1RaQu0GEkW=%CgKvTR z;O{9tz&Dal{Cxqy@>>CbJq$aatTSyLfn|>u#TDy%3lNk4kc{^0p4H& zXwI}nd}0T(0PXSmZyxlwpZpvkzn|0RA4mh4+)s0Z`s_d+)RrB>_*Ien;4f&0#Vw#( zqN9DH?f?S7_Xdz9OdbN6B^*j)!{Z65{>h<=kiS36Qs@Qxhe>dOFCC)O;G1>^cY}68*#E{xG5c zzAiKRcY*NJqU@(sKBy-7`(}C?rC-ttH351J$6}CnVm@6+9zgSAZ zcc~n^P?osbPrRNtLYnTytSyN$Q}mzH74AJXCp5m><|Pl@Ad|XcMuj+{s7qq8r%qT^ zmfgLT)p&v>z@$_$qJ$jL7NaU>)9U%rSx7-5?c%GInm33nLz}F&ErTZ5GR8gPt*`tG zeFnp1IueD>aC&FDm>cS9kb2y(Z}9yW+goog?@9O`@6D;9qr+{^6+Y+)Cbps)26@EP z@crp<_V`Az?9=JFeU_899vPTEdnwDtkmR#obJNxe-5;|$7llUU(Z8+@un^O?U^`tvu(5(~x`ONytg ziuQjMSRVKkV=AfDLHpz8InE=0`1MHnXHFU}#sA7oYm~nIU%2&+A%_+MH`e`^NIJkW z^T)Qr&&%Zh-&%;yPx~PMuO_1N(+0o~8##0b|2G@)b~Hc6s>8GTPR-2inwQkwPervn z-EN@c!)P87I8;2Px-9M1If{i^4Qi_EYsAJ4v4YoaIA34w6)P0OJlcO?%kX_~`jIS$ z`=6>Yk+*AARp6&H3m@*jIf-Vw@umGk%awkaGI(I|BOFSKMzwO$Grj17_gD~pl3SIX;`_U+Gua{E4>f=I2Zr%-e zDA2AKIOfdmm)Ab*vsS25w)M#e+qIITJpxT>F^X*k7g2&Op2laMM;0V}Zi+K2AE+P6;54X{P(dtp( z%sZm_@5HUoEFW1ljO_kz-1^~Yb${m8Pu}cjZvE?gf8K)8)z;RA{<{gIr>777Keu6w zp#SHd$)N}Sz6FM`cK*H-^IhL?Z9PLHeSbgPoIyi-(7si<_I5Pk^7755mXI%`d_a5fl;@7Unr3DkdT% zCLkm%bodZvR^T%rHZU6-ScsRKSLpw9IT&PuaIzV4OtUh}F|k0HSs}~^Lrl_uoNUZM zISd)!3M&&c3y6)KgA)vNOENRD9`^pH8|Ve5z|L{7!oFMXGx zafh1*nXY=ER}ftGpXVxeb*MQPF;SMzEJrP;&u+T?6TowJew8Y z>dw4w(&j5F%fPI5QPdLkxfx0Q7LhY`bPZL7^aI<@1VK>W(v9rXF%=g-P zAEzm01jqJKk4Z%-h)qW?OfDLVAUm$S=T?6guoZ5tWviji_9-+Wg?~b#;Q2?r9yTF2 ze=IxFQvCY8JS>yH1D-Mfe_FoeE`oQSbbb)=48c5HH-LSmU+eV&TV+u5)>_Bzob zE-e$ep+K?H99h^5mNT6ZJ13XmtfXaX8lrVN<05|AMG(xs9{W0kbsptLwGl{I+i`g$(l4NW`u<dRhz)jF><*b&!`3}0E^P&RS{5-l9+76-D33at*-Wu=gB>%{NYD@h z<Yh27f%7XU2S=6>YphKGBOdQ-cRswQSmnVVYAd}f zNju4WMvscd5F<0pfy9Nd!4Ib+dk zHc)rGG@vA>nKE_0bUHbtH!jSvR7n&sMcsmNgOwC90--2zJsn>5dgnXRZ?7{XAAJG0 z9!+$oh?PiS*>7ym-mmM|P|VIPF%)Vl9AYymzwJM(5U2Ujlicj{TOLPlY${`B^DT`q z{LBs&ai2fLSKpt=w~#x+6{8(w7ad(Y=Ic=pMx=Gq8&$MU!S|u}$`;2?2Hp;qkx;iVaVm(WBAWEI!9l zkvx_VMj%?YvY6&aW8t^wF6La=LG`qP=(BNBEou8I&qHD_3&w5NDP`9fRr{+)x;0eu zh8P60ci3JE<>pqLx_qaF-fH(DC~fD0$z##LG)31Zs=~@Em%7uc+KU5A)Uz^&as|me zAooNi-%9rKC*Wm5q}}`A#tdvXZA&mKV;=6(#HE9X5tE7&V53K$vRWEjoT5#d%S3v` zRbDoGlnIeU7+jzv(6G|S7R`4|T((BL zdz$ppL8NX{^1MP}nyH;8rpkT9y$3vq#qo`1Tz5!!gfD0mK65M$ul#(aDKXBy?`)vq zF{@WHA2yf+YVM)Zeq*9O92a2ect*>wWnruF+FJ435uH~LicX#iV?^;b#K1O$Wi7|Y zNWK$IS#+xmm8mdZBR;*7*-UQcL8lli4oTvjKvChYJ%5WmTCS>+FWO;o$D$WvStO_57WA&OHN<5`aofD?otX+0T zoWK%Afe!bDKVQSjK5A)&J2^Kb^R~K@wZ?1KTRY_Fvo1YCMy2f0-NSKoN#8ypdlAxl z>aGz_0e5otJ*;s64%_Kh79P}Das%QV+{ULlI)9C7Gq4GwRk?X37Iof@(+f4vO%P97 zD9DAXs|lT}SMZ`}PWvU?J3u1Tx?i(7*S zOt$W0OAe=BV%E78Y7xg%W@&0HZMc#~s;M0Rz#nES!}pdGW3G2H$Ih7HIkV3yUlVd> zJPHBJT4XQ{3^S1E9qlde`gK72OLZY?vQ}>pRwNOoEVT(p zgMWwWi>iXZ6S3y#+m#Q8P1y6F2w&8BWcJiu%RkRg)f4YePL_SFSsDC}9ZwEO^M#<{ zuPd31SCS-MrwZ=3br(WsFd2Rs{FzKmX#QXfjHj-z z{4&OG$^(Ry>+zXz6o0H*k6Vy_H`&9vCm~p8_WbE0%+VKBZzQF!&j{(}_h$7N*SK;r z+E6afpv(Xsr-XAAV0w#Tm4UY`DdfZl1q-}jd55oUH&+#Ywb0jMP}9m0$39A|AL`1c zZQbsnM}QPY)>L|JK!WUY_UMa}@%nipx^JHSilleZ%cB0=Q7OEp{$R3j`GuKQP@Uop z@#OBF@K@zoEfyZH6{hlExZjGq;J%vthKQ&wxhm!&KbZ$Fsq*r)2Ag@1rD~ykOE1Go zclugH_&$YG%>LZAt*kGnQo`{CeIfBmu}sh7a@)^&H@S7};j`9O>gX-@5gjI)#2b}g zOQ%j%zx{&dylXCX#Gs`N?wP;O$PN-(U0*ZIrw}Iu)nS#(WI-j)?(8Au#il~xzxF!) z&Dz5`cQ?zUT!Ui7G%Ojnrx-^J$a0J|VYp6Hbv`3q2g(phq$fSU)Ezk6mkh6Gyul=9 z7#oL`x=>TeV>dAiLWO86n=`wca=4RY>T)EK>cY8e98c_i9mE%vZ#>G2d&ZF+aNvjbzpY;nzI|(+L zE#mF6M$pR2+4Ui=*p!(%U+T*Ra>zsOA+XMDn2NC#hM%A>+hmljl3jGsR1|)v$)*f( z;rK;VlNRo&Se#b1s?)*@s6ck6tTeR8@Y z0#aaY0lbRzwfrDq*i`wXvbOWfJ7`A0WW8Kf0@t;CbsC*@qk=kkZtI zT4sC#h+I@@0HP;d57*3r84GnaURKQS4R@Oj;{z>nxr-91gQe4%N3v>7J|A4LV8f*4uaFGGVIo`H+==N%hLGh(m{m^WckL z)GD;&nn2bonrr9INb2wzN0;-=%bRp}t1tB3ugO<=+PVVP9ks6D@DRb#H9xO4du+k#i$%xa#{b9}D2g0Y|QfNrJwIh44cB7=;v){gS1HFf3ooY&5< zVVx|kAwcMfL9VI)0i2nB9uu zY{*d|B!hHx#HUB4+_mOhV?sWSO=ibWtPv+=F@dBO()$|EXX}|!D2r?A<_X+E&G3D_ z#t1fVh!b~wssxoMy00@$TQ}dyycu+!;q{_80XCaUCh$TeQ2pcpf}RAX=xK>KL_mYn zh8J~Lc7CKOd_E1+BUezvmPB32Yh;Zv|Mjfi!nG3>AN&$ez}*usM47@^R^8(=#@o-tYYO>#yAV^sX1e*871$Aijxtx+PV%pTGrk(_uTyC6Z^r znJD3nT1n_Sj!3v1N;H1B;hrTeztn#Ec&Bzkvlqo#$x~ zqCb}MMktBo$!OA~6iv%0HpRYgan+i4(QQExt}u^jq<vFxq%9 zc9dJy$NaKjQWrexH>hNrX6vLjD_zN5binC?%DJRYJ6G9 zzp{dy4V(IH;`xf?Q-+)}L4@04qI=NvJyyz zSfyY~^{dLc=?`0sZU}B2&%LTxm1u0Kq?it(>X=x}(3poZLWNo#dr4j?)`KXl@(`Cn zblB$G`jiv;8!}Pn=l;;0pTN2(6Obe1Y0@0iS#Z+`hwV*r>7&F=-uA&emm1s!Ih)>Q zKR05e+;9A=U^Vn+r-l~?Td2bZ+b+UGY}$| zTf8nkNL35xD~o?264ZzJ-Mbk#5%eGyNkUvgMS)+4YX0kijc4GB@Tx#8j2`QBZNum4$QOW9)a z_Uh(hXqfopZmXqC#Wo9cft}wU2K{Q_!9u$BUFo*p6pLR8s9DR!SgyJ?e_!~~XE(To?w2)K6Sri?1Ton=Mldoz#vpjE%ifEoLmzTxurQrYtExT1 z`gHcgIo_cRZj<|bp=?Zu0$vWJ^Es z&iTH1e&dJ7AyY4G-fbiceS98yLH@*Xt=VUn>sQP^XU}g;Ho9k@Fa7;py`lU@^@aiG z2)x-|V&UpNi=>5*_oK3OUP#2WOmCg6(f#z*5xPeAREV7vuYG4NzUG7r$S#g0o`Z+h zm(g$}i(20*_4yX7s-h=Wi(J`*@{Uv7k%2XE_&rb)Z2bMSXV?zAlz2miw&{qaZvGqs zia)}SIHJ12?J545y4q>^X7LyY3nmVCQd|xBuNWux6D#x3Jod{Bq`(8MBBzU%v))&(;Tp zkNSOa_S;0GEnAO!=Uey`C$A-(`lI%p_lYQZ8#`MSRCF?9q&`cO2sW*U+xogUGA)WX zzwTjgk?&C!0CU9j&!v`X`fp!D(N@l58py1Y+PEHR_0@OAm6u%>NU7{$AC;Z5DSDvU z4N?3H_S*(o!3x=K=~FrUU3d-Gy5ub78mC@ffB8z{G00-mOsQN$pmwgD!}wxpu0e7) zRLNPrLi}aIqUCybfOjo}Q_@|QBS5V|(&-pff_Uw6=I+Y*%Fp#v?^++8jzH%4=O~rA zN`2W^5w#%aW{j(JO9*Sh_IlBfkj2x)iH~Xv~Z2T!vfHR_@w3e@5 zl_Mq6Uoyet4~@8B%*X@ec&k|O=3_{AUC#K}Kozg44XoI<*T6o`vrUo`}Rw`;21y}cq^FnhuVG~c@JbO{>n5WAfwI zKT@usBk2^2rAJWr z!c6sy(`S92_qYzUAssxi!j;D(n0U*%vdm3Zjopl1>Na;9`&ZU36b)}YppRwgbqr3+ z!iH-lsdJg{-&`*ct6v!7^}kYgs&k(4=eC%DhR#edsSM$q@Wk1oh#Z$!lY`?mTBS+Z zOIY~Z)ZfI7gy3|0kY2k-BOm{UlIQaZ@if8qzYwQczQXsicd*9oda%SG6Y_iWezlEw zCBcYZ{4!U0UA37N;TV*S$Eo6SP(fG~6aS_N7j1FG0+(CU3%Z|yYti&{g}k^`mI#S% znMyjTULeHxI$C}ZMH#VpOK3*s4=DPUcnm=DGdy_vcP7EZ?i#UJ^z!X&NIhe>t~dF@ zh4$b6*!zv5h z+jpcKXFdM7F=vF>Ho}D0e-_;Qwf4Qi-2kW4$1N1V1F(_j`bzr#!!p(-&hy^Jjf~CO zHAM`V!U}854;~t3Ok~*c>Jsp{JafYyDy66tXB(!Ho;!UjIFOJg;;wwnguwPI5i_ZCoa=t70m? zyt0+KVq<|qlwX{^JIYkDI=7dbnMtQl`o+wD9zgiFMcWtOnc zhNMP#?cJp7ct;}oqU?x53^+gAu!2hf1D~}LJ{AAc+bmtPXq5ui(>o?Kk*_3qUYU=U zOO|S+KJpE=fQEh4mDHc~OtJpMgq*g2zQmOni#O{-u+*K_LG^gX<#h?%F_GdmaVZ|p zJr`){S#hpG$UINb{r&!jj>U_icchhRv4TpCB9D7Yp7}|rpv|tNd6W#CcGDlI@oC_i zys|xpk~>dm@ni~#5ICfmf%eDrK;6 zv+~qUaXX!G0b8l`u|f!o(db|~vM5VDXrj1sA>D0_vX}IVhoR;6dMZ>dsgr{qt2mR7 z^q=H5UdWAO5fXx96^&K6H~DDdino>f)KO$u!a%2>0ztpw z{44sgti%eLEN79f-(HTsj1LA+!p2sO`iqc^bS`|L^Wj$)%4lr?tV%sDU0zKamDBvX z(}ec4^MSt1?Iyls2HEe@;}n8<1vZza_O$Ex?9>Gvg6-7zP_^)R`n% zc#2Y>umoFVI>O%3b=YY-NMoO{vbE?;w8{ltl`M@w+(UQSsWMLXOsERb|BGnHDMy|gkFUe{NB3abv2b2jn_WJmZ0?v9rd zS?iNO3rEe$9V;trsgcls@o2mCVo$Bz;61F=XPSlDbaE(2P}c6fYUS=j;x%2)Q6-)H z@)+EjxDtZ?jAVzG3R09blOm&VE}87Ce4Ma7D0L{A6B(oWkqWSh1{J8p-yve1;%?kt55{$uOCSeldh`=4 z6ite2U~|{3m7>$hoJ0B3w*EpbLq)x5a=R{L5;VWwhg;rlozMhzuffz*t2>djTlABr zmwlph+vGH$!r0>xyW@}E&KWE}wj4btGT>S_4wAYKy5z4iUo!7bVi^ghKGf#ucv;B+ zE5?hQH!`DvB6tfFNoXao@(@^CTp+Nn|E_HD+`YhEFl=aNdK?u)fJzF}ByrH)x13f( zNFNb-6z9`W!fI(&vh$(>)gB~YVCSY3Q>Sv@l%Sv~2Q3G_s7cwf>mR-nkhuh%vlx#` zGkXS+$Kpd$P4z$&xxkBZR5UAm5RLX3Kq@PvuU=R`>ZkSM1hq3-FqjhTb_$A1DY;)T zSXip#QLo4_hIb#q)FQZs87V0)F*V)7Ws0I09ayACocCaj>l9I9Avc+rqna;$Jie!x zFJ?xA=kGj$Da}PU$;S6%k8eC*K?1yc4B-P2u^N1I9Svr%h#(Hz!GZxp!wH>$% ze@)8aFD%VuO-C!9H6V-%WmFd%mWZiOb#LZRqi7k0$H1UD69SBn%$`4OxdA~hkI+zT ztV1r3nu};e3C-WIk$Supsv7j!s4Ba&td6msRt*eQq)gwUaPxlVkZ<5Si}~dvIv6nP zfP=5Qu4a)g4!i-k3F*$&PuOAi)9yEx=~*+|L&YWiF;y+-N^`UDx;v>I>hE^d+D1dw zK_LY!R*!sqn`IPAZE0b4oKkfalGmW&Br>vmQnaPRE=jR%s?9IAj`yS#oumHZRM32} zqb$@?x4F(YJLJrE|1Y&sUpczAOt3X3Npf=*#%LY-s!@|R63waT{tSHMnrbDywxP%(+aPA+3yMdDsu zJ;WpW&Sf;!l3bhg4@&xY2|i&?SDg4>qY9iBreZ{8q#uC|43Si5gmQ>T%gaxx zGWJZ^ZIc_V2F0XCtt!TJ`qu@LknGV#agIdTsDkoD#H=p?2A&%oo95$hAyn8{)kMz0 z#<1|6(ayi(uz=kkn(MMEty;3@TayA3r5lpg=m z!iPFXkts9N`Q3#mljVoh?1mcpeapwsdcqQ;o*rN8%~14K^S`(CMt4BFIxasajVwMtAm%5%K|3LNQ_qMa&Z*)GWF)SrLXx$7Cs`OEn5b zx_4B0X0G!mQlN9bxyhM6QE7Xeb&=9FRzZllNZbC7syliuu3d+JKj|_P^I-4}^p&7O`30RS#e1m&p z01B3o<}@D4a+SRi@(1d&5%8tX$Y4w&ae0{~vs{i*+09+ax>Nc)&DJJy3cmvpkO_8{&2hHUJucsCoip%@R1xQbi z%>n_l5>weCoGq1_<7^a02w9za2+g|NiU^W)ki0EkVs#8G`xwH?&LiMBt`=(KRe8y_ zY2)bc7v`!?J~MLoyW-Oq1?vuO(ddpEr}L@>G9)uu5IRp=AU}=1zcDWeYH$cIGircN zfv>`<*)5adl}ZC;qASYw7GkDyEn?1=5vwS80_KHe^VH0ylexrS?_0v5eda151EwXK z<|>4s_08*2W9}})dqGF03sMA<%s=+N`vd=>p`M(mxw~_{3s8)-Ud@~w<4rVi3arFV zEE<~=XQZoQAc+=qBV>K*NhLs8dDqx+Y1AcoaXt3Au=4&{=n%;YhUIhe#phFSV@E`T zxfBbOaky+J;;a*N(n3mENpsqVX9~d zVYny+YlGvz6eyYoqu{3ac6S&>N`YLOnNz!9dfG+U2%*Cgn`u;rX;I^0$*F}Jd#1@D zoGN9!<`oSqgEXj1f^e%);>r!2=u#ValT^Jem%%zHAG#1MQsCxnzR}BAwfglnAMrKOvcgm4y|ZFUvA9x%8sFTc|XhC5tqd`vfx(R~)4x6vZv5rNiuxw)aF5m+) zOrgXnIGH19h_eRj7#tRZWA*Q{PV=4jW(rl3y~HY_?wea$5>B!7WUaT1`btXX;&V2Heq-TorWQ^9vRB zoLWD?UICxYv>1)G?(~fpx{FCaCTd;p3z&-|=9rK`XbqN{Ht#_WwX8+xh2bXHC;|jJ zY=kpwRHJn1rExV`NbpMYP(rD(zOOc^4GD4Jn}sNO&vj12dR=-YJfPDe)Qvd0lFF5Y zZ1MRKt9H{DWvZuc+K+$wI|P|3nw#k#ovFbtr77|lN7uGR#!`Lx>VizJs1-#SiK)R% z$r#Pbs%71Hgs%f*YOYdb?Y5p--!A)AwV5{hY30rE&G!;z)&cb8qO_^77tgGz51UG) zLr$9Hy>}j&sSDm$@oijicy$C~mlw}pta17{8FynPmdm$nbR}7F>RL*PM(i)h7$lq?4oC!Dj5V+tEp%6^#$8qILjZA8e zP4#$FyVw$k8L1dDIpXD-D3R1X%_)LJk%<*1MBN0?6jj0?bG|?cr-~A16pKw##e`Gw z2?QlFOD;`vaxRn3OGC-MTob7PL4(68Tah*W<#P88($!EZOO*q4N@Y{c^F0f znvOI2V8c*ujL91;d4$A?s-@c}#AzTUgtJK_h()B%n670leJ0C3uVBwkGp#bSOw##D z9=}kzZKzy~6!p}_`&yMRX8AvRC3X;zT{e4~{_OmXw;Zdaa~&89+2D_`;mMO>R&yKL zYO)FZG51`I#-{HmyFcTZTcF!ZZDJ<)$o`?-A>3p87pU=n4gXs6Rd4dEk_{bZf)c>- zOs%mghJlyR%Y$e}g=z14eLCMR7v{;1iMWZRlEtK=ps6BS7jaQcH#$$>ATKA|#<$p` zxY7&ei1R==GK~uKC{ZSrh?zUQz|AlS-ePQ87bR%Qf_p+Y(j{9fS&&hHZ6MfD0-3vS zVWZM|88$?*cBKGQC^-bQ%WzEax5H#W(&$EdfaO+WfECH%!83K6VuUpFJSGa(CF+@p z>nu?09tG#<>7KOc)#+?(2ND$O9{%({*CaK+ZW(w6QC?TVfDMiASzLunzmqSk+LElY_WPoXs@b zxF}3vUNcdG+*Av7P86!%EnYjRbm4rCC#~^{Sv;3v* zE8nS$fre;BdXWiVbk74dcT@eb=X!qWfwM&AYZh-a&%&lM$v_I05OWQ{l63?nH)oZ{ zFuGm?N1bJZv&7a|LU`0&LnGWc&FIWF!H6Onfu5##7><-POT46Ez+PSB5He|$uskq} zhZVt!6chYe@>~VAH>=aJA}q2bRL@=~nhYeY^fbK=*o2CmrXeP64w{&k!C+watYK+N zzG!V-9Dkx!V6|Y07#K1Wl)IsZD1xQy@t2&OLe@i}BYgYK0$~fZ zgy1%T%bTr>r9%2XlBc}(KOH?e==J%RbIvkR)(!!U9RdqVXQ7QNLqC|zO)P0_8bLu5vTW??Nv8Mp6zJleliZ{i~pk;>;4+ozqz84xprQyJ7Vlq zaH)){#^Z2nkm#rOYlY{hAa}Rx1hi`u6YOx$Zy|ApE2!%23XaL*)#OXX zob-J07l!FysS@kh-x)V9S-tCj^VPcR?XmWAi&Zz$IuqF`MoJ-8XkI&A5c%6d$uO}X z0~W(x;(*rWzziq|2_!*jc^RG2Xl+Fb$QvaGWYRDQ@yR$!j*$*gw>0rRCL{=Kyiq|k zW!Q`)hp$su#2C0l96rU`U>d1{RJ6^gJ=DzY-D!vfxalya0XL7l0<+dz?EYgZjC7T0 z8#Z4adyy>XoY6MrOd6j+ez`($pPJ~-m=Z&y+StPZRT^%YH$^qsfJ`5tKD^3O<_fa-}UhNT8rIVns z@-f+6mQ4%m{!e>!0yjtAF&Ro7*2*Sx)Rh55x%pW$Jfy+*4K0lyg=uNKO6T$QIiedu}N zbjSsJog##lV!iJhwFT8z&9gyWHkphZIpXiRO2_YkZU*9%N>&oOU!7Q(-Za+CE7*MX zz6nK_k}BPs3X*0sb)l_0Tw88G`|xkCebTKUYvoy#^s?-n(dtuR#eg=_C4zyKG-xV~ z(xIDpm{gO2|J-1S1<9b~m3vLQfP9v6P22?VTR>80!j8K=v6D~c2#E%6W89{$!$d2j zGUOua_%YiOP1!R_iU_DXe3rm^-6V=S07Q^k3#Fvl#9Z){VA+l=V_RH_onU0SnvSkQ zP%`wGNeL7yu>UkP39f_@jH#B-Rqt3M3h0pZ1I*Re!qHPkiD9!NaRJV6e8j^kV@pjU z0gZOv<8CS;4pI$_p7jg7YMal&)C?noOzH~o!vG^GmEkHZ=E`wyDMVxWsK_sv#7~VZ z*T4-0-2Mv8^D|LF9mW1GlNYxsm8*AzrJbTyt?VWe zrrT!p$2r4Lr7L5-~sdRX1O()O#){#pJ{g-(lVaUaX3 za5o?I{w=!g!DY_AnRT4D>zgN&W!87b_QT(hmyS(%3px}xbvCJY6~;#$fThh^kfQ^) z4|R~HR~-Z+U9SeN7-^L1e6l}U*3?7*_5HwrVI#ouHO4jHsqMW)5g2gj1KaX)RYMwEhkb2u0}$zKMYXn74X%>WRK-Ee|^9Bapo7 zqi9p6!31B~2rM(2OYWLBi>_~F7w{WXF$P}AUF!*AUq)+k{c&{KF$GQ~MnSN+XJOuk zN5yzM^G>P+Yk})dMRy%jW^H&mBiWb!)ht{TzY!Ip8Zg7TFhkI7_KHehvoLFaqkM<0 z%=g#8k(*5%R-%|ytnWF++s#Un@Rs9hrmk5lo#9soIFQin@mlp4gyp8NPVSWb!l?EbfBiCX>upH&Uw1FM1v!? z3mf`Wxm4CYxGdb|V(u58^Y^oMeXe_YoC@hVGx1sA8Z&_;kT1B^p8Qea9OCP_yXK$Y zT{FH(-C9_zJ@%^x&GOh|Gw$W5KEqGmK6_IHBTFl>Cs-%uWm16n&5?jtq_6-9T%`a? zkikP|0rqq(#+GwnL%R$j5OsbWx|q8OL`5Q45kwC39SU?V;wgqAjZy=J)6Bg2G%FqP zmSQLjS&F7!y>s2o&$E=kH`uS0!*+6GZ)mBu?><0L)O^BfSk39A$cBAMElBIgK&3m zo~N76Np1E|1qQQN3}!d6pxRvn^EH3h^0ERx-_FtXH@Z#1J)MLNpR8z+mN?h{1*$+* zznyj@ED>yC_p;q{d#F)_`kFGmUjR5=`h$&JL0qNdk63B^L*H zx)Mo=*#o>?4w(a{a8Ae_GDEUJl0cG7Ni!tO=yb>(B!rR#k_66yB!MJ>B!Qzbu}Vl8 zItaRSMy!uXJ4|s-kj*9rN-StJ8YEzvoLP|ul4(hh-Ps}LISh#;;xa%(jH6PSsYUe(!k71ch7up1eh^LdCS3{RZaS>v{G^28(GACW_=|j%koOtdu9;-?*9;sf$2`2>378bE!#WJ!4RDmW-LyB|}jN;`=2xX9-T;kAV zf)cq6k`Myqh}34ns{=u)&M7w_rW0mLnkk&9toF1ahvxGAN6mQ*Y${mROHZAn)!{Rn ztwXI z8qKnhCVN!w(w!P{sk_Trk*Q;1fQ~KDq|Zv(E8E4?i7Qb%bu2(9(Rgg;%!YAAZr};Q zp^_JZR5}iKHYGK@DM2Pc%wUryl$6;M0&qN@G7eEC3`UZtvJDJNCVdVSTQ2<@s`j&G zylDoqlFUbTP%=8KI=T>?I|xcQRF=`M`Oc-GK@cEYMP{_fs;w<-y%1Y&i$6ddYu3(q zdo0(T<#v47n;twY*P~wc zkffPZ9XY%m5>Y`U$ZqW5oumoUL#VjqnFO9F9oYk>h)JO^cVrT0K?tadMF|F3h?3pY zq7Wn)$ss3a229}WkUKj9XK;)fvo1Tb9W#QXc8f=|7fmFA+0ZDcGAxr)ijdR|5DaV~ zR#s3}Yb+IGWNiiJnFLgUq!4J>BOxgy+D{;i4#*OkV4z3|ndBj{YA}PN=cx4jZYP+^ zyH7B|&x2NtSrkscoTOKwaC({y=QH17Ec*STG!vuz!WcG`cUO}_9D{SgswlT(yx-6Z_ z_7bI3&8QnujH?zYS;ROYTncE!D@9LswkX=%nqXf zcbl>*Nj6ArG@@iPq&7(j(;!Uf8cg8HIMQ?sodYQ_G-iM?u*|O;6`ZQpCKV1x0Yt0= zcT9Q0NFzl8l5vk4TjvEH{{WBk9wJ{?5ucWCo!$*c}M9HT$P@h z;{#KqY_#P#?_|NOyngRUJDy`}UjaKjcI7s+E!Q>8>J!S%5@(@HPbgH{*Qh6G7bX_Z zYaqFoX^sMD&9);rFl)H)^XSyh6h`$6EzZ0|!oY4wtJ$HcV6_aBkZ&W2nU8xkvZOKy zEP^COvKAc0cYrCh1iBFvQy?Oa$q1sRtc0>yt6{TsB4Fz+HX|o;T}LJJyHl~w>fX#J zA)#DBg8g2TpQX>%*Uj`$>+59bMshn^8gzAh+G-k=5t&l{XGFY!cBN*sNh+2lyDNfF z?*zfjFyT{Y`V65jQ#W`x5yvFo7idj*k2UmmJTDhsgU?O#)b@g&9e&54PtSVKN9x<+ zJNI^-odZT`m7{7jt0G0rT4)BQ!4@Qj2-tvx?*7a5RM^8=n1#=lzaDIag`!YG-u#Jq9-WEw;7hZO5@dZ0@D4UT?9io)K#>*BEzRcr#M!Gv0Z7 z7@eF0$lRYg<6`madKi0}?yw8Ljgt&*NR$bMwgs`JnMxAP7=o0tILMrmiX`xmNz;r$ooj+d zDwNqW2`IXx(?}4kiJ>)yV5ICRye6qL%mE89YP%Jh3U+CsA++&kVo^kxwTPyl{G z1m&JXGNm?@j_N~AC<08tpn}p&sZGY{BaUN`i3B-aAtZr2AWb9FbAb_b&73xMRk zU!J_V-fLopx%tIT)}Hv~2L23`Eb2+B>o->wkxKq=OwM)fSlhz0$yXyrIq7Cp3I)!) z3sqT%sC)E3I!KhW+WK|D2ibOLeUh z=6>HfROM1YJ7c%St-Rf8^3%r7ZgQHEqnn`)Y%AVn$>VQLGl)jbPVoFeS0(JAW{^ru<&3ouFZ9;ZKto=_qm@ zi=^&3zRQQFD%U4<*Ip3lVO12cHPYB>Sz7IF@_O0n=o%bOgx6!wC>5MN5(g{MvcK@NLFi=k&4%h0V< zEkX&lEmxyO!(*AkHHgr2b@O&ba2DJi4MBA&=yM=d)DBNH4<4x+yu+ml8kJYKR0i-R zCxH@hYavQ;EC+Pdi^DoX9I>Jp6QFE`xbU{yQM75Fl)I%0TtK&}*qPnCOCy}sHywXf zZdAjWD)cq!Jb7-HQq_(i6j8Y2OzT8m9EG@(*QXJmyjBRd;o4x-IU z{OEVueD6RqGqP5ZF?c&9@RAf~Oh%r4rd^dOD!Rc) zG-Du&c>rNyfC%Z8-0mT{WSFxyU>-}u{U0YjDt}?(k@Ii1_;0)N^m@!o4y>BBKbzG1 zCxP)9^F3AW3Q)RxJjCScxD(ge0(Pz@)i-eY-A7xyEU@(%aa-M9evTbn{*8TY5H&%I zodZ74M*1pfTT!ihGo0x=wIrUn>X0qYo#}OnGssYMmo&@G`zkq*?DCzTJ6UQ6FK;T~ zdCyPs-kx4=#cLfr^bcnqB$-58z{)O;U2}_9o#S)*R5q8kJMsu+oX`jcqNUn5Z9NO+ zmz+!4^hxfPU2DK>i&;PG6HYG}h|&yz?iWmsBnJs(Jn?CUrh{06kvzo0 zO1p)rQ*`bKEYV{a1-lu=PTU4Si@>6Q?NkAUfpT1X)oE%>az%tCH8KXuag^CPp0$Z& zOqEGRfRP-+aAYW{CPm%>AU%OHNja1=OpZ51ouU&_kVX?=W>I2zNs}O6Nhe@T@dd-<*H8^t0#R5_T2JU$n1xcrH$5P=2Npm_Rhs?0Ljk$ zbD`*%Z;{Y~o!vTabg;#G=3&+8^jlhrs@TDgvuotHC-nbdOI_EzP4 zE+(D5F~gcF+Mruetask2T(MP}P755Wt#g-FhTue`7*d!f8zL#kR*4;~RvT#2u#+M2 zF<905R-8nzO3g!{^sJ|K_F;1;a)XPIg_=j`%^+DFJdovc``Q*0gL=)mHh{uy1}98lpFGLdRHadeVHLQz0YP8SL zIU>V=Otvaa(Sj&k#p>Nf^$1J1AQoz5s8sLDyyB!#$Sk-eH8{k9B^LzG5R`@{j{w*L z#0&*MkXUfZGfXo~k!Xab839@-8K(e@BvC?aG0hD%VWkw~=1a;me1>hRoE{!fUMK2CK&{5y<<4yved|(y(}_C^!hy3sC8O=ZuFb^w(KK{&F#5E9J`h& zysP<7ws9I|=jQ}^IIn{;!g1;GZqbXIx0OR;Z{ujL*v#DJ%vS>Z>n7=`^PdmKkG6~LZQ(&`uZe(@zYVFKn+20#`!>`UGZzis~TxPyT z_O72#&Rd1Bx&4y4Uaz0*nz;@`dlP3J`QQNP-soHTI+*ewt>z1n*Ivl04`PmS(Xm*% z1NRgWeWx|4Q;=SIHV0~AWX`}z9#x!n$wZRwPMH(9N`{I%iPM`i1m+oqgH@EflA|Q; zz(_2Tp_3R*n{rTyR~BJem|;M5Gl-!|%hhnU^@yD30R@3q4I>N@sXD0uCH{8o*3|K= zhP0?ORk&aUuF}sTwVi6u7W~!stzuc+Q&lI(2yVsc3g`DD+%zXQs}%V;>i_ z^!HWH85d8LJWO!t+u7u0_M^>k=Dk;9t=zL)+#f9peucZ^`Z>Q>t>=BWGU#W=UzP8< zlA-q;y4Eo@N;SZd79~xQY82qj1wn&Cd4xupGK!wf%zK&L$PG)A4K!&60c_dCPVnFW zJgFwHzG@8^(U@4QR20QxrjqdtC^P~xZ9OTn>1oY7g9K3Z+NGmap@nnOAD!1uH?p-e zqFZ@qY$o5ms$AmOCL zfa*;s+D@u1aT0aN2XQiX7#0(9f+1!!c*ea19KVIh^dFS@21YNpoqjT%dC1XC1d8cx9)1FYi0)*&NZ%k zd>N(2h5}^z)uxhjYzSTU>SIzObY~{eLj7R(5I=GBWh5hAfdOO{=v?6eCv4 zYh7}dsdje!?6F>qelKD#qLxyZrC&OgPSJUK%g2S7FZvmsMk&(wCyK;u^K^@@aMh$Fi6)uW{Pv+iCgFLp8gj$;TV&BcEh-_|3j& zY=Jvjl{$2cjz=S=8of3*;&&1ej|$V?CaD8=Mm1k9#fsmC#%KGX0)fXEed5tXkUk6_4th0^EE0r?Blub29;^j?p|OqbBMJW}d^ zMfCpwIQG*02a@Y>8|HK6NHM(kzv7JW`<@%ABd_cE>k4dO7Y6as#(F~M>`*=Pj~_!m zph1+nQXr)2F3|}Rz0BupOE?~OnmG2dbVRXAdgrbv*Tv{%9*)&g5*Kn}1fqQb-{o0{ zHj=E;U8kG1UJEgWG13#7dX*63?hoKJ0Qk@QbCL(Xe*v>Qu1F)f~pkeK%QE#Z$F zUwUD~^PQefwMNDsj_a(!bI%&;HhhLze1jEbpIr>J`x~Gd&u{ryWm!HT!(JR?)OL~q>QMYfNiaWheKkISV zuviApwJYS~(&?LuYF#%qlbx=23!ht9>PgBNVf{;bn^AE zb!*mMU`gu znYX}ZnJjimS;;UsTEd%Yjl??)iD4g(WS4g z#MxKqHTd4XwFZzuI!>zc^y`5hv*A49cR_;!~0$GNq~@=+bP6OnrPY08al zb91&U&d4WLq2i;ncd<0{;W%hm)uVR`AXr(WRUjouI^8cN)?=;o5k+6- z_98A?-uUfhbDNx&nf0RLuF=}%F=B#A<2BRPz|Lz+2}5kjVxa*YuV+HM(#KHKJu89T zS^CD^?m8jR*T$G^imgGSf_g=Y)?%G`w1pLN#9m2&L^u*+S6OU_^&Ft$D&fBok z!&`98a(enuhpFtIKkB&eufla41B@Q)$-2ET?Dsj{0mH@p!^*|T6K0L@X4UJUx(<`-xF&qXST9>{$2$2Yn!>uuffNe8}(dT0eYF2XKuWeqfC1$2f0^AH>CY*;Z>!DE($0M-5I5U!Xj{#AyKR$TTA;-UwxN!xXxFUGJ4SR^ zwVxSxX@Tl(0uTgIm@EiVnzqn+qn|kN>etlI)&kOolNKyk?FUNLNgX&G?G^=ev03^E z66|M8)K$50q349qxgl#FDDi;;%8=e` zCr+J?ZH+KDUp=ViQRmaHk17v0qiyqR=Xa=Mn|QlxB*<$ua>sImPR0phm5{-u!c8hy z$D=-LvfEf(HK&mp_cQ|yF5ta)9oF&o^SSrODxSDCA2k~dnJUFrT_fz)xz5#9LLItt zZIuWTze=!5bIM++t85zFv~qJ876$Kg=l$dF2(C(c^8u?$u7zurggc_VEB>G6zJzVN z;{O0hc>Uw&;lEy39>f?c*1Ht>o{O}eRgtNkp^fo;FROWoa@`r}-dzLa_6D5qD^Ho~ z@^9tWuK7qaEt}t>WlTUjb|QF+DbFm0qCR-p6&d1$8vt`orI>eB2{O>x43EU9O3bmMEq9hlRk8wcyoLLaKK&tItSt@N$moHWi|*PL`_ zzP4-&v0N_)^beFc;x1sFS5N3(Rk+`|ONi_l_h0)qa}A#{u4R`i{I? zI_)n*z^0_CUK6U@-=S@@5HXszI_3!;q>y^nYv&Jcm8_8L#2oQZr3YK3THrby&Ns}n zI;Vseb#*#=5S5-i7|}}gbls*Cs$mv17Im%StHQx)QVqKF0N@?I>Wx6~K|n~QXxDVJ zIeVE}Xw65W8_|zcmS*klCSOfg3aV7&d_Y7>_y-N)Helyg(cBQps@Tfh!kVJl?b3lN zfK2UECXAa!tztwo)lP6zVJ%f`+K8T{wcOwlk`$g!&Dgg}#&j7l#d*zpEqS6ydgP|_ zmeQ;i9w3z|%qC9LMY6IgunQHBKywhIwodVOuinXQHPx#~h$M#!R%c#lc*Jb3NXM6A zRiJFIISujB?K9CcM}>+AL5~};pFHrnih6rVg();PJ?VK7-p?F|Uv3O|boAlo^tP<= z-732L%sjmsw>zeKSX;O>6`!4LD$~!mG*2z@EKe%sCE*u|th-Z`4E>&Sc}J&nd5(65 zeHEi=`Yy1n*0-T+E?Fx&Ai2tfNISlhu;9Ce*lb;FS?{HqY^9-%RN7>1j$I?Mk3V*F z-^IwHD;gO(7OYkzYE8AwX=S%x=-y4!%k?ftZx0iv=WkF-I@uisyze{hyhnaa?5zsj zUR8QJ6zPS7X3$Sq$SD=P%JX10VV(^bPZ$Q$xs+9}q70RC)?0=JhXI28(Vb!<5#r2; zJy&h3+NVOdQvET&;8bWukb1>z;<=y;EUME$V{F#T4Hd^Y&9)X*+QWR7ja#N2d27^@ zI^7=5XO`*sWmRKJw>_;5q3lx1 zvTkK-Z1S|TH5BzPowLU4MAXr;8-2HvW%acJhvsoayJ~1n=r`yEIr>u+UMC zbe;@GM!=^H##2iK+PL1k%H@${h&8!QP$3sNs@KsD+olIgpkE$pCF{-b;3_)(~9I zY_7+xPFJ&7SL?T0mPCh%t8k#^@6By(gB)p}B;`hOlM8_yEGw)9 zli6{W9TrA?eJYamIvz8p%Wp}y&Thm9UjunpGh0L&PFI|ESbZL6FC8qMaE>mWODNt3 zsIy0}p9!s1IM7}#&I(kMG*LShtn=qOy#`Jyp!IF-c%sp!qEi&^vje$kS#a2nXE^#< zTAf2txy@DT?B!U%gf&jlye#N+eNIQ2AG@9_n7_AInNT{e1VPiKiI=OHtFcmJvEgc< zbOxY!Svb8B-kG2!O;PO9+LKCo^szQ6p56oSUZ z9gKMftgPy&ZGwV8ppnNpv86ju>y~OM$x^7S);rn>;SeZdQN)Cl48$&VnoFRh8uwa( zOja|f157bhr6d&U+@aB&24Icd5J4GBb5_)$mWnPgG3m3Lf|$9q9aWjndR5^(Zp{a; zq7L;dxbD{LSIN-Yj#-`js*togO3zHvE{?`;AiA~jyz^LgQPI$NqBR@bqeniK8#QyS zGfOsS(5;Wva$OUyeCq{{nW$2y*K+&(FQ(^pGC8~Sdmb~d<;#)7+U5O@W@{nWDBI00 zOInPpMGVz!b}Isqn}NY@BxV5Sr)zHBVf^zv4Yyq1|_)vXbOVzz{3pJrM*nbO{?k&@O`%^~bvm(T2ISj??gRM|W+ zZ`rHlEO*es^AC7VajR%i*)Z-`waiiIF+0r-UU#wMn)Ld+95u&Z>7O~rv!N_iC%-sU zYih!bL`;sd=5Xt5tvxi(zlq+;bxa1UWsr~pew&nQeVsmUYnj*5#3qPW@%o`_WAAD6 zzC(V7!Z0+fk&aLOP-icBd6p}^57oz(HvZU?A7dq+vIOEzOlmIoZ03Eq&WGA01ss5nzD zdUlZCT+MefX<4f^&#+}q_dbEMLOeYhIcPg$776v3lU}rxs~(*f4W52}of@PLQ$g+8 zxXH`tjYehYDY?_JOF+){SzBwH+s)}vm0ouEZA+s&&RQWe=NY5v4e9j<;g)RkRr7d@ZZ18U-9*4Z@V^g04J zfK9{HXV|+(9P#V5?4HcV@m967<}QbC67a5X^ILdcXFJyNFQ3o(KVRp&`8?|W?LB7= z;aHnP(yhsz=>w$Vj&Dkh_OFveZjMFYx!n17jw{jgIaZUZy;B`K z8Jo9K^5b+IZ(H9DEA;Y7cpV149g#xP=ewJoFU^UsfzAV`;r&%AHalKN%FwyCLuV%U z@~=O!v-VrwzdiHMMf1-?ibFf=m|iZ@L=X%{4v2xU$;C`)vu`EF`7ZQ1-xkg=>oFt+=X2X(7eHfrv1G^V#Pp3DbT#au;q>P=6nW@v`I=uF| zNhRrM%;br#<%1YSm~&GO!hfwk9NJ`8!Bbn0kehbgrhCbjjI?jd(;oy%=v?Z&52 z`pHR?J!a?_x=7?pbcIsYY9Sjiv@vNxI>wRnAq^_B=#0xi1Uy{2Qic-^=BDQ+b)Lt^ z&rR-2JUHJ$(eVAdDq70b*C}P%!>JktPCo|4PpXns|7;9 z+^J$!k&5mLwY!Gd;D%cDrgi@BhidmD>Rg;p8`U1?1X!+ka;pkMmtp{9T&8nfVPW;$ zr$eVY$KTL4&JK?+F5}QQJ_F0rr_dH%9UgeASX8%t75+}{O0cX{>UJyu`Nu3x`yHEc zjnv^>XOWGwO4Vsp;d1EmFLu%A(ew84@b9QfMc-WlR?%-DJIR>Wu91#-4qPZ&sVQ2c zqbf(NNp`#ZKSzzUIPUY0o7c~YaAF>8?kwYVLY`iFw%D@Ajl%RC>dSx!X18^71_RQ{u=`9KP4zZ#2QQ=5p>@tlh+SP^Qs-UGuw`3ZJn)OEn8eyIMxacqGhkM zkog3KI8)KBqO;ucyBxZ0!yfi0Ekmj1d!?JA=d_-inCr7S4tJ{J?e$LXOtf<-^jPDg zvGcy#S=X7}w7W{~)!|w-4GEbQ;hMDCZ4aK_$+M=CrD=3lefqkamnyz`pG4|)HurvY znrdEbSUx?SYTSo=tyQU|PNO$Qq}#k~qK`ndbT-U2EUa|T&?U@DgwnZ7oFw{PZ-TQ! zST{k`)z19PTGnE1V{acfW6pYyGTBkl&eP7Xb-cE(Hr+)`x{EuUp3ghkHLcURbJ1wf zo*EZ-4_YTbGeahwf`zKAP&RZxjZBY9r>|!;P0YQ_D#h2w&U&C=%RH1R((g+rc6vrz zmb>XS3wLV{Ye#7LygMBUu{jC$HZ!gkecRypy4}!P!fiSF70qd*%I$f(WaE6}>gDB~ zV3wuD+10dxildCi%R6_p@k))%4WLuy^K|h0eN7z<>p1XUK1i{{Vuf7*(3D{nP&)dR zeASTc!I59Jv7LGL&enpA-0iciGxECy$Z}d6Zr(19sN}~e*M)jnuIB#$JAQqaz=wYe z+wFU_@46vGDZ5V?Fd`ChdIGR3QLHT8tx6t&I&bb}YexGuY~M$aZEf(d`kbD~^E}T- zI&f9Y>$5ALh{W{HKDn|n`ii;Z%8OC3&n;_83cQbXPe$44GKRrY-cS-^MMMDlhq@?ga7aN6dm z?cwy(tE8ZWCsWNlJ)&!+&c2-;D?Zkp7P`DFZK#_MtDBM-$7QnEwVfeJV(u5s*w8(m z!(h}th53DvT)|`#qRI677`gEK8FKc#``ZR&hN)j$&R0QCPjZIWIJvax8v*$Ztjw&w z!%s(#)6rgRJv&$FLmx$S_?-iaU8WA!8kftv?n|yY!k=jc|SG3gSEb; zE86S1Oq}*y-7)#g*}K_YA3JL8Yk9LH&OJ()Tg}vaRkce|&DYS(!RSjS_7WRZ$*f&C zug%mhnDD$BTN#^a(1SueaZDObCP;cIrGaNuX;oD*_MIS8oh<@Ze$wsCJ6w~o42fZI z%^hv?v??&U(G4isqA|P?y_3F{7~(4i7ZI+10_))OyP zVCrZLM9C+F0F5XLN)kg&nwc0E!P4c-dKwgSCsSWHBZkcBHa#27&9odOj5@--VwS8b znpLzjGBSE9jh0MTXekU2R+^AbUtTETiKJH=yN6^ zEn$_Il&HO))T1-z9=6OI_*yr%s{=!pE+gt;SvCw5WM}LPeC2+vyvq@txzh_fPKMfR z9K**EgaFSg^2xs0L6e-XS0<>sXIDd<*UY*Ztjf2?H%1qN z%FkjW5}C%@BGfBOslw@I_4*N$Of*G}b6#7wGj3F$YME{>y(u(a6RfeGo>QUN@xFI_ z4;>iGgvsoA$mgk6qh*f9Qjs-6O7S&=rUa-~*__We4vw6x;c5Ytf_nWBX+`rPB{&Q@ z4qLnvnZYw250ehHf?BRbsXiCdN(VPf0|ocE1I{`?BQ!8Q;gEcg*?6DX!*TtUFv2ItofE+XI;we zS<0P`xv*hNCALidix9PTt4YP_?BtqsXQsFp(Hw_Ii|TF1*XzUceH^WAx*pd)ecbu( ztWP6eb4_NaB4#px7OITYnppPb*tJ4g7k~(-ee)+2fhl%Gg*f#U;Wg;0gtZ=vqC;ND z&8gQmlbM~jlbWG#EJ>pTiv*a_6NG=+e;ymO!Pa6G*Jq6*@Ahq0z3Bi2QlrH%J(aTPUe7ONY90|;^{&!X7|DuZ9gsUsak6Zmv8kcbWaMeh(9ag_ z<*{QPLfgH|@s~cm%Xmc%BhFKWhO06-V8ieNobh6#v zsP5)aoAMB0jv=CDXez+kq;siYM71msAQ+RiDINvZo(f&M1UE^oVOQFG3Y%G3d#_Ek z=6YQVt--suxxr%lw6{KXH@9*bzC%V0%cZSeTBcR#wmh28onDn&nCN(JogR#hR2N$> zHu%x@Y>q!WzkL^*uSjY<sdiWxVpb zg=vC7Hf2DzGkuwadF^^C)5zPY%B$PpYh2Y{>!KHq6Sm;<30;~|E>N6@h+@vKTanq| z+8LMg`#b&F_{^^dpV95`Tiw&Cn`bwa9ke4SiY0?2tX*fWi#-&iNKDDx*~}boCn<;1 z^8I;fA0N>AA1l>+4)121w>@tox}oOYgIQk*(DT~-ovK;wmX>OklBFEhb9iw*OLw?b z^vkv8XiDNMTDd|m}hdHs3c zEggkb^R_GJH1c#K*H5+8+vm^C>w2dRPne#LFHV~smz_@oyr++sl$TQ$dmS!l!w><1YB$1g-tP9krYdMD5EQKh8alefUQVkg_PJ4m@7Tnbmcke^v*PQ zW2t~Xg63KCa~W&mc6*Gduyh<| zJ}0o~_)h1aUc65~*z)zBL9u%>^wQI_^4(731U^r% z-Zz}yxb?a7OPT3b!0xqk(#zjWpY`K+90JM!{dE9WPIPxeOb@)$Ir*_IG;R(8Mx8L!(g+mdhY8f0lBG0bAEYPNu?%9idK8xqlGE`p@0uV8t+zL$*KVEOy_TY>0t zcQh*1-^s#q>pd>o=POgx-Mr*BUrSw;kBA86I6AJSLx}c^(msA5s6R*jR0iM3JL&1 zR4C3A;5f)&lZ+&!=!3{$nh^t%fx_`KAfA&_w8_=ETv0SrCnVuG&LJxRvYw$}<1@38 zldwMa43&Bh7q_@CGZxNhVDNsgS3B{ubX+bwmlv$IugfFpc~>0gSIXj4do{lp=(y{- z1q+-{54Ps4MRl{}?RXWu_!cm&NoUx`&Zr)pJxj zsq|;&u##j_1ery&1Yr6JybRAGz{=m(D}2^+Lr{S{%J>n})A3+GQcjr&8#m zs8qe5okp>RG{mIHywwPtqC~*NFlx?8I6Y&!@{XId(?2WFr7M-8T50;13xnzj@B`>M z3Y#4{zK@MA?$(Yv78GV16U($3H}Px+p=elY?5fU{iPw;<&a1M^G};D!oKx}7Jo<~v zI5YCmb6C7*ZBG{DtsTxi;O%Jhte*8Ok=*uB%@!|6IfJvHHe2Knxh@(x^{iT$LfRop z##=Tj(ptM>sWhR@>cZHsP~CG*dRKc6CHqcWC(BZ|OMAIz-{i?f@dy{Ui)owj≀It%Wqq7IXvw+^R4qtS9!FLxx2*K34qru~ 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 sdA7X8oVHU59ZxdHwPD@6{7^8L!~qvp+F}t^5`v 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

    !w(T@bBOm2mF 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

    KoyOBUS(>(-f5w%gcLN^G2P3G)!Vgd( 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

    maryd-0WH8Y zf)?OKgqD*cuf^}f{+^B%=Ey**))RW2v`_o9=8iznID^dFTn34thkHrqxObm$HmLT` zcr86(__rXj-Y&f96y|*jfhRXZJWQ(-oTCnWIK|-C%&8c3e1aV{m#${npF~!MJ}9K^ z#~>BYt*+id#^;(Zx7!Qa5^dc}T^ib@pvUPb?Q-TIl3QZ~kq;?u$3-d#_V!biE`%Z^ zC?ycBC4=mflJ6U@7wuh3xELHvy=JEvPgRA)Ratsf_KU5UKI`N4@BcFGp0hj-2{9$2 zR#&J7z9F$3EO(SGP*8oF?3TwKXbP{A$ksCLYCs{@zm>&h9Sr=KezxV-S%q?`cJBLykXAcv;(ABi8{ZBN z`t7Q?2zK3aw$?ANed(WDe*fS}EWm$D0DwPEPXfG{PXavSCjnjrDE;3;SML9WF1Wu! z*FxjIzKS!?^&LA+QDa*abR=-kpNM5;duA}i{Sa9f*$5n~+5j53 z7Qr5%$33S0Xw%aG1iBrc%u zl3O9Nd8zr04ZVyd!VOF(E=1!If(Ebr0whRghQ7QZo8dS(1r0T+kK^oX3vWf+y-*<{bLC^D{4VwI48QqCFG_!lYZw#X8v*_k6Hg(&PmKyqx0 zw2_CrHx@k(BBz3F+WlUT7%lEFb}SyFg0556=Q?!RuaQp9iY{4k$P8U(l^p4J2D-f& zPxSxMhJ*d~=eS!A3mHb^c;ysqO{MV!T*yX4wxk&45Sl|}*?xNSgics)0J_t=c=R$` zcWfgFnmh^)2v%)*AuV`vBURzg;t8NCJe%k(6qlvG)iM@04;%n(J`clFVIYw-B_TM76regoKudXI3g1t5_)*Q|r zz*{(oHn@1$WYJE(#$=c5o0QjF@(~Ld>CZ6@t^4^7bi7{3Ye#D&`m$ZRiEe2ONv!Ag zi`l>Mmh>WIgKdT#afj^G1V2dGk}7E4IFe@Xi1Ffqh$w#hDF3HIDLY zMZW=OAD!gGgpjx_ZLb9ao)y)6s^oqBH>>=-xknatjNQez*a9R(%9LRM^r{m{U&F-S z4k$Mh38R7#SNMgValj|KlG1FGcS?wcnDjAy1MhnGJ`Kc~1J*lX31TzjZ>3YqtX8$~ zik++b!-Q|iag9HAybq~5I=5(_-#ePfO$XVc>*w{ces{;QAf+nbp`J{5pYA61YUL}^ zM|WGSpZ!#}s>xV$V}b_mp{wDB5x^cVw!dU=S8g+5NhmtFU}m7B9vSlq{9WX5a)Qy^bEihKv+29 zf=H8!;;8NI;U#h8`kZ-ziLo|SpQ<*fLwxz_`PkJ^(fVDv)zu1u8hG2^mz-o~`oZf6 zy;=A+{pr??I%4&E8<7Ix*6ULyNOVIvXn)yY3Jr8^9ymxmD_0||l>nu%-eMCj<-v&8 zmZYyq1XYZFqBeX|G;Sx?k*d3N9+A*=rT)>IFX9^?JysBs!5e$`bsA7?SRN-1EK}0R z&&6RRHvER5BlntZb+!(i!G83ND*{p^bKO=Wi!iFMR=}M}qfbM*%M8}H=(s~Va#Vya zA`veQbc)xeC24E9z<_2DznT^?XmKNd>C$u8w#HyPc^_?3XlnQANSM%9ras)nar7Hy z1GT1XO)O}cyp_O1C=Ii##y*VtA&k~mr!3#wU}z_rjFDLabwkW&5T8vq5&LI*LudD8 zm*Vhvm5fI8oLfg;5(lMV*=%@*SzuMJYADjMuI60;jE{DKT-0G-BUy{i6>(YoDEh;U z>jKe3)%HRP9Kv;?wl_6((iId18h}>$sFgNKM_Ys!9tW5uulvQ;ZMD94Vq1*AAFmol z!Dd=aQk$rn2=Zy`ccWT-ZGL&WG?sI$mAJ&DPgX`ba^pA600567J z0ME!SfEUp&Ao&XOzpmGqsjpm2G-JJQ`*FapO*4Sw*qmR#{l-o3{C5;O5VT2wli@ za;OigD&JgyGsl1Z1>IrLj*e?9!m^&Qgt$%K!hKnZI?Yn-0*RN|@hsoN*7a)NXk zK9~ivdPqZD{V;*4UOcroG4YaAt&UZJge(zt`9iHe;{m#qc@SAHP>j>7BbuXw2uZiR zNS9(#f8p5`^!F(NWdC1kFTxjV1Gbr#WGcRZt_;V%#h$wQEJ zmwNE8*C2MB>Rog=R+}cWEl=N6&$<(@1e%UIw>I2IAkIipe$ymGs$hC2(m2iZ^rVrX zztf{xxC7!FY|3Vansrn!GPi^AUZH^v^(J~cssZbUS%*sALh{}ALTBo$)SmjUc9v{B znli-%^8`rj6pwqP2Y3O${r6rea>nDSWde{Xq;JhAUY7a}**~=n&qq81dfiNm*hE z6)vFp6rJ5Y_G%=-pWzM6N42D?Z4p!P`h*mX4vL&rsdwfD7=sMDoMC4`fm@MakkJ_# z_vYe+(?NXm+XomgLD{)F7bXJ4^HNujthJ zP4I7E@U$DZ+@U0|KH#$N3m`${XO%mY1;gG8J+~kJ@iJK1|MfBee;k+rc(IrPc!taX zyvWRWDjNNsm|*vgG@n$;#r|+@H+xmy_%@3#w(XK%_Lv1o*>3~!Rz^yxcYmX)I$&ABogE5 zsgb3%VZVg}RGkq*jJ+TqzoS(CzzZb7Y-VD`Yj1w#O`4>1j1sVF9yPH zq!dA+&nc+#)8)c1XoyIxV8ScYv2#^R5+MKNOH-LF`L&gZLo+RlLcFH}UXexXC(ANdd>P zBIDYcnEFUhJcVUzkk=KwZ6j^uv)k(LV}_08KYcrY93TRCu^<9?h7bX~$PoE^p6=@R zJRPysxHDWHjEM=9O&ApNkEdSIa$0VpUw4#$e~8`PpVho(=fL@l?*RkQCvKw}arI)8 zmjz(m1H)c`?oXb>w$Sq{@(?p#fCuce2#jkWT znx`6)e5uf`pmUCxEcerk-n222*j&(MQ(WXj&6mj`JnNTv4xUNLW{mOpRP_C3gN3`0 z#eaQ>jr{(uIEJ-0)CQ;Ery}v7;?QYpMf@!+$|lStF2q}>tsBrmANIynC3Sx7aF|*u zja`tq`9?thg;gJF?c+)tV&LY(n5h2%HiA>lSo;HdOtQrNSb}46KlaU`YZLj${#2?COq>tx<=A zGe?#1Ig*iaoFgM65{7BtkGDuW%R?C;cgr{55f-*S&U=1?6dLqHF9J+g@KLYH!gfsD-+_AEakYWpVmpdh=LYpa58!FMH53i`V=-ip}})R^z74? zrZJ2764%atwxlE)-&He9GC+q0H8LAb3N}}=`k;?~pFN~sHFTCThUyf{R39#O-wSYT z_%e>GlxERV@;0?~-w-eH*qfVdx(LCMJb3l|b@2&4h(b0S`0Xikc zBOVQg0%<8(0Gdp(ST#`PeVlo|M%)r)LIr}T{aAB5?Nt5t6Kkwr3_wll z-Awhxiu0aZZdgcN?wF69X6;fEI(KwQuh& zeP}M9Vy+eZR)ZVsbctmcrLno+>D<|`U8%FRjGJknn3V}HLr^;b9%|^@l{DZ?^PNtJ zbpM`^!F@}q!GNC(DIIwB+;!pC)k#Z z&o9$Q%t*wKxK;)XfU{t{uM}%i4hYems~L8cW{_AEObZXoCG}+m7tnHvcU{C!x+b(s zHWI<)3??Y`dNpkCd@kj~dhpSdD+YSW2c7j)pWjJ*T&Q{HJ`GG;DWhv%KhWG@Zd$X~ z{^;iHz9w)h<&h)3L3f1*ej!ylr>DTxP2iSXX+fk&l=lmIk9n!!xOBv3?TsvxL}qUC zk+FeBgB{-&-5nluh0$eYqpEBx794u`_%|LDX_Yv28n{9*-w%95`|u2Dc$FCRxS&0| zQCxKe1|0>Qh(8;)M9Rmco26)|Zwx*it=$k-@xl%Yp(L)S=lzb{vh`1QKh{x2x<#wb57;T08v`i+K`fgR>=p$K+erTJd6OOFv*rnqD zyeDcOik}d=K_ZUBFJZHHtLn(qhS$DjSZ%6sj-Y zzPbLucj{Low}mWok>koa2+A|1OGIKhuVXkqtSYxOY~2FUc%&ABB!j4Bl+ipCjA`m) zd(YmEyL@wxVZA}R;PIkW4V0&yFWH`gqSXuyUaalKzxNR>+2~gi*}_ z6*J{yw|(x!#}?K6I<4-f9hsA?43?1q{y4Q7VLhP)K4sLFr9*Ro@YX{R*8;DApu^45 zB0E1g42y^Ib7AWrq=A#`KQ*L3PH6zVm}vk!<1_$X1T{?kA7P7V68^QPdK%`=R|_A) zz@^LY(U$5ivnwlNlFl2PGGV0L2m+QLutXHeMHH_@?~gvvepPL(qcxs^*{p)Ozb^E+ zlJq(b|FN>3BzxvN?=pxHuv{oOu)IX=A5wW+bN5Tq{|p&T$A&xY%Sb=yVE%)$noS8X zw>E2~%#0=3ski-ff2bVJqPY2$){T?+rc|yz<|%?si%t;z>;N7o;pJ?aKIoL_M`|g| zd+f||)XeWGq3L?Uk~{}?(`H+?qM76)KfAE!^VT{pOBXDg?sEKaUCHRm_8Zd4x;=r& zT%1a=1=|HvV*&WnQA{&JUh0G;o_&_+N($J61P4jfvDv-BSe2BToWcenHIr1JW`R!# zZo+Z98MM_76;vbzW}?`c9n0EOpXn4=miraF*S&*~R~Wyn>#vDgaPnJ9is$Z$$8|=0 z3@i@}%4gZ|;hhEqJJ}+ID543QAuWA7-q!g+<2|*~X#Ge7IWR|*o#=BvR~&GnTzt_x$0h}V zPlJY&AU(&|P~o$Jy_PE>58i8W!6dUixe^zf2P_k=U>5tJSyyW)sEX6@Q8V&D1x(?Ayd)xcco?acDR94SMUb#elIKJmltb$*E6M7!j1xui4>%g^Lm9b|T2x z$FvUs~(@oDHc$Hd8!3yt}aE_rs7Um9Q)PY zFsR)v_JgPU92xmun~3=8*K9a6R35N2{!N~pvzr@H0q&gf(~Ioix(BPM>gN~vaK!I^ zN@-gWD{M>+Av>+ygI@+*!#*1i|4!q${#z0F;}{aaiyaccGY|>jWfDo;Ust5S;~PxA zvPoIXr}lak-tt2dJA8$ZS3jVup6n^YC$8Gk#28Bz0j(&WGlZY0RboB(goQ`IpEMG3 z+?76BQ}yng=3A4W4S0LYgix?En64jJ$U@YpRg~8^azIYj2c#ZuIqNKA*BYoIGs`xa zoZ6`J1#~^%!|M-{`{7Dv0ao)PLMhb7)0@!+ig%H@ZYYFOmrHl!o*DPjyc&k4DKO)1 zi8Mr9lk4)c8kxav6&QzG3sJ@<-xTYbehw^6FeJms<{B<7V-qS^FAp@&P zZU^^tVLF}xr2=OKrN);7OKxE;JL{ZjU56zEnUN@S-vzQe9*v$En zdDLXn^`Ra4Tg#O6g&owvnM;&~x#aX0-vxFs9Q`12sG-BOA94MQ{5A}n(w4Xt=?yqU zoo60neN-TB`C*ek6nkNP{3*@YvLB7PF<;yI`hENnbPyFqh@n@^Ir7DAhv1Mj9S5)w zH^r)%d0es6IXC_Xg5`kV?XaagqnFRVw<}wwUR}$Fu!yxan1fn$cHd2Ig6~Yeq!TI6 zE%blv4_4rRz9{{1_y^#{`Ul_{{sZtr|Knf&kffAcG9CdE8gBu&T(bg<8==|i5NYY@ z!g7Dls~9=q$t9owSq=)xy(TIwn4M4Yo(g*cKrCz&h1k+&g~N5dm33_fkNa_Nn)y^z zpPpxx43CY>lEE!LK4T9?=-(UJI~DaCKt@$f>))2=2*h)>YDrtD;b2T2TCW4)ysz5` zl+f9CZkMuov*v)Bls+I0cSyF@r(nWuea^jyM-R)_VuMX|%+4S*69}qU6R-*eG1|?V z#aEw^%Bj-#?y~Gu4R!+a7x^st)H?DT`5~skJgVO?0zZN&N82%RgJZhU;c{;DN5&0z zIh+!po1@cD>En-qBCypC$;2bYsmBOW-4G0!s+KF|h?2qSffE_hl%J=?4rB>FwtU32 zkM;B%F+oj0pyuYeVi8wB(NmHI^I<*eU+y`TDs3EK?5h7R9LyW)Z*wD<{2+)2n7JW| z_<@Y#%+YARr3I@{>1kh39a}0~?4t~R0HuQh;d`8%U{pp&P%&)=jwX?%KY&z|h)FaF znJDW%>(XZ~%($g7kNOoSVcNeJZw3pSO=?c}M@W5S(43Tp;9eel2{CH{`0?Dk7CSN4 zlSZSQa>=-_c9lLuPaTom8#MAt!uJUg;CFkdqG5wJJwpo13!xbo(*AE;#?cYCxy@{F zKQ_s}uAQls#8VMNDN*vZ(GZ&YsXh->kVesQi>Xx;`wEOG(DHy-{B$c2F{vPff}k~g zhK9!65|*Tt+01&-3;#aat57u+t!WEEAaQ*X+GkoILn8pABe_1FXu+rKBA5dsJO6%5 zz@veD8R|BkYD455HbrdNA>cgqTK%xTryWL5ZE=4b8?k7F#86tuZM1f0Oz&Z6*(5HF zVi2S`0e-+NY5OVGpe(hd0Mq2DOV05$eSR2wb=F3XTZEI%&mK#8?a~Qzp5{AEHceGs)G4*ee%Q@K5FqPDOzPz!rRC%nAXLyX zVAAMT053VM93D!m-FCqD^Re5y%!B1VA|0A(%lZ1ei*1hQo~i;@#aPMIO?irGOxg?lHu~>5Dv@-Ex$%~yp*zYq3FKx4M-DO8>lap{!+eo(x-LYY&S-5 z#Aj)s*(6hHzuMEHvl&rGv+9(<-k=QIl*Hy8vd*wDgd zIPfq);=@58bo*;gddrGKy@<>t@!>l-ka|$-F}z5k>@Ar-R3Ri|&dH_=87wtU-zy`$ z>0 zD=s)WGP~O~toMrb-{yvvbbb>Tqn=@<*uZ53eQt;W64ILCk$|Q~EnjEUr=TwEN6-_3 zpr~*(Dl1V?5)EA32p?56(tqalXoqdjaq>1eac#PmsmIg+JBhf5;O?XYMufHV^A;6z zQEK5!4FdFfN--AJ_WRh5&Qp=S+!BN!9Ip22keuk|F7Q57jA*-mLN)jO0>}-jOP=WP zDfby8M|)f(%O%i`|J0?Y74l0e$yC2I1D6dp8< zI@wbRcj$^9nu8vzN3v1ND-f>uR4Fdt*K?^vJV<_qCj_LilP(wG6I=AR{O`1P!D&}; zV@17i=AzDWaBop#E%6rJinKDle|0MQdOo-Z3*=baUNqEe#b5iRdbZOafA<`EoDNJ{ z*n_aJe)!1doSV5FaUIa@mQUqL

    >SJZRI^CEfB$-V8{16 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

    -(SjE_~30~ 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 Date: Mon, 19 May 2014 19:27:33 +0200 Subject: [PATCH 2632/4212] speech from linux erfa Signed-off-by: Nico Schottelius --- .../2014-05-19_cdi.st-zkb_linux_erfa.odp | Bin 0 -> 811621 bytes .../2014-05-19_cdi.st-zkb_linux_erfa.pdf | Bin 0 -> 889138 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/speeches/2014-05-19_cdi.st-zkb_linux_erfa.odp create mode 100644 docs/speeches/2014-05-19_cdi.st-zkb_linux_erfa.pdf diff --git a/docs/speeches/2014-05-19_cdi.st-zkb_linux_erfa.odp b/docs/speeches/2014-05-19_cdi.st-zkb_linux_erfa.odp new file mode 100644 index 0000000000000000000000000000000000000000..f722a9cc6b17615a4976186e2f9002a05d436109 GIT binary patch literal 811621 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≧qJ^yF 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 z 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

    7_y5e;gwEUsdU$ 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 z z^b8@7K4)%;U{FY2xmE5>Jb_b5K|opri{^lwitCy=(WhxnG>pa?h z_EJu3Fl)ABmiRG%F+%c*ABKJ^?iVYW0DgN(9HbWU4C;NZ&cd&P_HTg3U?8_d_6o2n zbV68M%)059zKl5T3!0>PU%q1G)Vb#j{`TFXOjZ+0rRgk4X@P|Mr^fz2bAnS-CTl1; zJDXOz5{2+5CPXfCs}ybA!n&)mI+cx{tih;1s?>8}<)&rC&d`qwRrVh_e9eyRjNPa` zkD>Cu3g*5B#X`#z72Jw$iG%izBfJ;Red@<4558N%lSCGGFN2EHSu;G@rCt96@XZl5 z#Gvn`BO)r&Q{(D(3m#DPsTn1|B^>8;r(Yy*@8Jy<8x)FB=^a}84Iym3QLICcR_#_P z8m;XL(QsPrRQcNf<u#I!K)UDy8ROr0grWmmAXX%0v`F3L-%dlUnr~Zv ze3c3pu)h$P$uk5|YG+f|w8i?qsgRQ3Nz{45IOb;+eg4bTTcqKI8T?!L5rc{GU(k>G^N#a~F#r=*(HH%!vI_XLb1M02;_$ulYutX2w(RGFQgv#GMd7W zmy}BMq7$Yy;IhF|Ldbb`S9xg%LBBQ~rB$c2i<9(Mj*o192S;A-Qae?qNP?e2LI|=5 z%g*$0${pN?48S3Unt~moK1tD-xk*d0X!BT2%F*p;%XIznVKEc5!}02-*J8=198VA4 z6{j_POpTR}8|c;6G4{<%yDC;pa>5ts=|v6nEt5^4Tsz$%LgDENRAtv1Qw)m8u+mMA z;5|;8>=A6GU6?aBikq1-9u=fr)p69r#`}oF=d(tTi95cYGelByE|YoQbbqk`@JJPV z;gqmyRZ|UlGMP@4_}1IlK|N<=14T_c69!*!iC%+Kvr-Ppyub zZ*7}XB=dE0|K+TjvR;CA<{0`uWHf zbjfVVxM9zIwRwJ(q03y6{RLIG1CRD05jFp*X-#O+;C@l_&=`kQ5r*3~E#xzhMLCx7mF@mY$_$``b3#nFCkWXc>Orhs5 zT5%bDjEUg4g2a|_w<}zNhcE3P_HNF9xpF~>yApz8@ zo_}z`<#9<2k^Ls5AR5mPnCF>Igx!j`R zcIE>)+GuMNHOUCpFS!bxrU3G?e%KIy@9iN*g=nxZbeCm_%;FV5@5swf=gW%e&nF z$IwYiRL`p)v{`?@8(CCmh^l3gr;CPw=(;~OCUjulwH)H>F@c~PaOvlBB@~>bmL;M| z(6qjrDprO_xZoEEm|$EzX=nz3tZ%qM6wkYdNv&(79N?5 zq^4uxMwb3P2DW)GpLBjL)=@sr7z_(nBNHN^NyspNoq$?7vXF-w1G@ge&8uolyOW1IGG8{ zozGcYuMu@}>G58djJ7~9d4kBwv-G4GKF-9wGkzT)HhP8%D85$DPNwiWN)#^(A z4tG{@zy5oPf?_^~Nj>=ObIRDqC)IYZ4%m0@H>oX0D&)4bquT;mZ@{1)UqctoQhxN&_pZBNOpOY6p0XF4Aq|Grs4C;ytc<)gy4?d=$eww9FEk-V zTMjdv;xPWEkzG^`Ewr3vssQKRp`|DA^@C-M%Ka)N>a>i}dc1 z$!^Z|E5SY`WovS3rxZtnIfj|spr^ayUGC5jirtJA)4*-~g-)1=cL>2JE)#I6ol@*f zLYq#1*!CPtoaTDSaNx&&N%byPr5`H4xGQl=^w>McP=XtaT>0dN`nYw~p-1Phf^k*k zgETtFI>YH`k|k=zNAqO@zx_auD>7&Mkw|8VdfD4}JWt*f`HCDKS@m{veoZRk{a@(8 ztNH97v-_e11NJ=}&uXnq1WgShcIZQw65VFsyLw;LX7;GaTP<$&qo9!@8SljA7rlJ3 zPQAtCdj-&A)6LG_h4gi6sWugjy9M6@Ui~hY<_P36#YNARCA9?g#xli!;3P(?cko;x zZ9x7I!SRXM*`m=Ud)-H6TU9KY0)DTP{XeKO1>*PwZNDKJEDcl8I0vDNinATk&<4&fvL97bcVilQNWHNtb(U2~Y2@#49Z4FS53o zOp=|G8_HyLLuScRw6rR8d1Xe2H3XL|v49}s z)`6i|Y@qB~$Be-BBTvzB#Z5zhji*uf1LY2FgnnYEP~2W(H!ow!mY?~Sbos)K@s;s% zC)*(jqEq;V3`Kee zRb;0GO9AP}A8?YHq$6F@lX|a!#$>H4vFAk2@vP(8lcA68POW2=hRaxeFA4E*6?-26 zGF!0|sqOA)5)}EV#sF<(UKFdGn0i3ChWfY*1 zn72s6-?9Ci(%IvDfk}GIYiuA~ARFn_G?(o!(PqHf#K^T{%=D;ApG4|+u>W+_+G}MK z*iF?Ykjqx-K4Q~NI&J9r_lMZsDh}RNEnWRH97WHdROVaYSE8OtL1fDZ25}xC7>lE- zs}DbxD4)Ub51iW#bV{DqWoX@l^}#p|JR>Fl>I$e4XG+b%7YA6q8wm|Z&_wU2QZ)ev z%OnW$rfWYf;r(hheO%0AFXl;)8cy@^GtN+(zVOo?xLF##UBEU2=igm5Sd%})IPEeX zwq@>zA&hRMdfqb%nJ;V6s|1->(rqUG#wb5WIY?zB$udoBoG@qFHmZQVWX>Z^6(efW|{=Yx47>cgC+0k2>Co!!q5VfeIPWS?Zq zTQ3@ud^V-2n-_UuH>*_E%cvJ=)&0vE@@-6p)N(dc$GVewWz(P6 z;8$0=R-dA-WMCJS9h2uvy5Q27)w!f$FH`lSwD6j=YBI=#x9Pp%)?_7(`v`I}(b~&O zH`Gt8DTmxGfYf}m$>2@+(5fr?3xi4medDJ|Goc?WyA3_Jf6s&MuX0-=}u>8&vz8~I^ zbMKj(jU?K*Z_A82@@Y`$WoTRm9*sn?gQxXh-kEIS$xu4&-=&CTHWlW4iKz z18)EktseR$67NH~aryJ5@AhVy%%$DG6#XYeZ9jp|{|J~w!vt>87(Q|7md@r0y{39* z-=Ki$9aSS`nz&`Z54^e2sjZN3d6Pj9AlI=4 zilW%c%`{Y5C90nh|4I0pVCw1qY}*Cz-Ywu>I+XFAjC78pU_{R(HTy{Ju^8jSAX0Y( ziVTdy2(BK10`N$G*TC9*xII*BMGySxxARO8m4exl^3QB4hL9zyN|p6iDo3AS_YI#Y z)bXO|6IgDD8?EXn+lkru!N<($FQ!*b;LDo!fD==P=>_&2PxDME_IM(x)>3bxJz_I6 zsf^pj?bO_UQ!IIV+LUuE#us_akCs*=pS9v7M+3Db;!_P@TYhE>e3ioRSzIo*d05PH z{&0d$CDV5F=nd67+)rvjznP{pWJZN9VovvIqH(I~S+Y-1uthgb)N%s+> zKxwr=6om+!g%Ux&{~tXzlBiT#Youge@hF!TUAO|)s?>?RyRkK0xg)iCq5@CcSO4U` zkn%V9-H2_3tzzNE#0(T-?S~2D+uC}Yzp{xXW7~Dkl1WTJB66=pa1vRLs?vggz0nxc|Jdm;p;!(4RwZF3kt~S=SCM*m=LdCa|C@3V-p(8J+R;c zP*-(b641#ebgDmXlw9}Nbt^ho87(`Hd_XbqCHH@lQAmVL?W;_cBArngAA|BalofkW zRy9x>ihSO%bQT=3p0> zceQI`!?AKPySVhc_2bTR;8^s9JIH%}JBQzX-mKt*`@_;yqmR|FmhFk$nyq8XD7za_Nh$fsw!~t&7>j4^SE64vDBvk4dhdVp zKtndM^2Y%yC5L)rW`xYMob4SNS3B(OUN$VpSo_b_)chT9QW1my@qsKIFPdUBDgEoq zifIsPr7ulrh#<{^=Er%$mAEc1AUt(C16J8$p^yxC4xRx2?tQU74h$`E!5#2ya0?og z^jjLKRA?Ba$Hq1?90#qJd|H$HBnemBvLi(5@R`uXzv2=YPVW2btbUZ+L-+%~z6U)2Y?E}TE%%oQe zU(W9<+W_;!!Col2vqXVD|A8FM%Zo(2yo>qhx9RuasfL!;aG~8kK}(rv<__m3ZL%KS z)%93p3~M&Dw>ze9ZN!WwL@lKR*WnqrjIvK+IFMnT;npW;2}SvSw0X6kwjO8==I?um z5;f#k=4fw)ngzHA-BDhb_poBQxZ;`ykaZnJcu#V|^}admlbfJgzJfmD$6#5m7ZBt6 z!yfdNSkm~{1RG%=V?kFDmwhX+qT6(h-q3BQocEv()y<;;$q2V+_1rDShMHmuBz~v2 zX7`7|1U*p3qi+rWCIQO0@AkOULLEh{{<%cC5OE*zK1*t&maLOST1P7sh;(Y65Bk9o z`DuO>UFxws?C1-X8`QXM2v02FTc1MQL2$!W-Y3b-@oIc-N%*Y3g4lLu)F%4Nm6W8R zfvLK2-99|OakZ|o^(I4a=qfBVcTT4>3QWp-Y}v~OEoR7-ZgJlXoiT$b)iqJjZ)@D9 z?E&H=mOUFIJ@#Uj4l$aik_ASq>U+ZDXld--7;K_8nX7p`VSHp!stlv(?xJ2N2?B9U zDs-joFCL|dYK)kpefdR)uJ%jPBDX8tWIg3Z%!1>FSxWgmY+g!J7PnG+&cpS|EdFE% zQ{s1;c0o#22yf=Lr^tKwsaPY(R{eoI+ZuTI*3wJhNTn{@OM_or`~8j?i*-k zPg{myi0*Fg%fubHE^UNl+%;k#D-ynZz_5?1vHKpZthK*zbGr_RR%qdiZ6gqa3exQ# zc*?({H+&>o-W|8K2EfrBVEGJaSoAlLveYV{?_w6BI+{2o39g#{Fy zsoE}B$9z-__IB4UArQyLNJ=D_n}~?L*VGZ#0#-IdAjC*Ur+m{+Ri||0%^+?>a{Sj% zB@j6s&|}QDSp#=VT8N0z>+O}JeO!sn|Fi(?Wl8iEpJphCcU<+2vBtYBr&8n-AOxS& zp1z|=wtlUmuH~dEG zU`_k+M^uvEkh=uzdxpQr8x>(6z`-t_|BD#+1&ND^d)u;1oB;9VXEg}-(CREnHmS^~ z7+$Ecq<>$QIa$QaXiZ`AZ8?xqPhWSUP|2Nr^KZm&rK-pT@}4%cO(ebdPGysH9F-re z#&&xBmjx=4i~D0WwTHI$`rFK`&Cb|l&BGg^Pg_&x(J z0!jp<$Fo~#-8B%*#%B{QPQ^n-nEs?Qm1H3rASIum+EWga!)xEnrE zimz_rTIdjjE-{@ae8T~cYG@c>Gpm%#upOQX;415VrC-kZD&~dWjYT}fC|m9RU4}B_ z3E&49V!yt&Fw@MOG0{973~4MQ-F*K7uSO`y>3c9iip|UC?@%x=xYKOn@#n-rqil>^ zc|*vAEZ<}Wij zSK)+yg$6~r07-GCFwL}(e{2-5J@3n|ali2<@k(AVw{qT@JWqiLWQr<7n)2%`G>XkL zJ#!%oVz-Z_>PBh)L;6V}y6A7pX7iMU?DN#jXRx>BbDXfWrSoFx)@17Np9QD(2&A19 zZ8XzTJVe4P8tig`PJK?0p$>-DQWIg;0{i!}!zKCjZ9T0`R!@ET zkdr

    ulS0khlbZXB%SIQaMi}KraF^imJBc<9_B#e$ROv9PM{|or zyJajY@@@keHDc&pDYo_i2(pM$l3qCyBQzPhzA(g~B)!``UI%aJbI};kTnMEIg+7Ef!0Agx0+;H7dHs zFofcem#OYqKF+sT${Zey7S|Wkj+gZre$F?KKBP%$`S-$Rme{a7~=2}8UKU@aw-QfBAallXss(QSLamRp= zDFO#2pn|ANQmroEAX{H~rJl$LZBksm+D*vT6Rpz7bo=t<( ztAyjqZqoDaBh+{2qE_FA#^n0ZbCp|^Q6dL96z-RfEJAuM9iA`(FkFJXtizD%pM(>V z52@cZuP|D8b@WzjUu+*$o{|j0aov>#I=s(FS?;>{5<P7&PIrV`xQSm!_ev7^_q zR)-(JfDpk0r_oS@ctZ)TZ6eKxvjHQYp9*P^B>BV?+Ezs_3r52A#JbnjWokA$mGjCn zuOQEy7v*(YKj-vuKU5v?5^s*H6`k}BhJFXB2-1*4sDia9*_D#lU3K|Ja|&`lJja0B zp-611?){+hep?YhqiKyoy1roAtWw;Ip_&L%(O3!9nKeUbmg_zNQ{{T0r0^B)dPyi) zihF`ZZDpFJw}qrvKd5ZY_hSa@SGMB$hQeOFuFtA`ON3*yJG>|ls|17beW@{Aoe{~y z$0@dd{cYm;521ywOp7zHkAQ*#ji=|xKW4MU2pGbp%km*T>QKeOLyBqYOWl^eIx6`> zFADslXtXL+QeTk7Sj#RjaHX6m)(EPz*lgXYNGx~OUge2Ss=0GXQ%`fQSg~@UX3i^k zPe@J^mhc)jSvlFZh|vmc-u|Zl81daAJ=b=BcbOg8fv6&pcP$+RX2)EmcZ6_- z5qdY`;6vaM-y=t|1N22rKr?R_1@8}iE``s;t_Rdmn5x5IooJpXahVa1rj)127>~SX zbP-e`2JU3!v$W+qKSr6g#10!Goi^$UX4AH8ZDc8sKYU2p>2hs5eRcEI*Qsd?ZO_GN z&*0{Cu1}N?7mxkHoqpi~(U&z2e1Ua9O{@mHiBnWkd;0ir`1tTi&68}NNz)`|H-QvS zv`?Tz-+xov-fIg;fLqHQKqh;~6c8mrue#}A=;;0_0K=;2q)YhROlD@hFfY6VAf($K zcAt-03(SvK(T`U}aw30#wh_9z>U#at;5cqk*rhA1??DXEvqyQ?5x*7Mi+W^-T`QRv z7?nDbV85>R0C?)FhCY!|z6iR!_hOqQIqzTE(%X*y`yTe_&LZ{3k$*VJNrep$8yJ1;fviS7|Q zyXrgFSAcgk-~1`NgrzfQ+O~9eN%niq7;-G#h1){=-M_ z)yGcawj=4;ddbLV`H?8{MH&(7erS{p+Zmp1cbn|c2kioFj?IE^_D#S7_{QTnb<><@ z>rmttH8XSA4Y(lzbEB5A?;|o0!cSdHw~42|h!TAop9n2by*s zfMzX4o5kCh}9*4}f9=HhI7$C*kj2UPWTZX>6PPtr$iRo(DQ2tuO z3*GAfrM|*YJk=c?yW{r|ZhV)+)}qs<7d7T+(!=Buni*>3hSy515y-Iq(P{cfuCgkK zGE!W#Mlv3wYsB$$_c8WbG3jr4Ud(X3L3!a5g{1FM6uqhLd!6EP({E!fS^J5+9TQ^- zysv;Mk#WlOLnuh9T=8bv6^1~c5&w-iY$vwHS0*Rzdx(W%#Qg@N*ubgo6<}}jBpq@Y zV46?Gsrqfhqj`i3$59ETV^?J;*7SPojW3ECMKH{F9bM99rMpbi_wg3|6fQ5HnBD?? zlG@J!4R-(|7=XXkykB#5^Z`vn3se}Ar}%#Ktk(EKcfV%a3c}k{O&;w?O|P{ih;QFN z7IeUZofK^t+*51KDaIebe+)vuhJnf zV{&i4DKFsYom(ReX#4BtPe;WSiKr8IKtB_}ggk$(UYCv37lX|BsiD5<9@`Cf^Z=<%)fFR!(3bfhlXh8;!@6JIRI}(gX}EpU zCCacHS_R0C8-&YZ2{LeU#|Hp%`!3!IUTjGfbfikLk(Wu#oo|?}2_?6V^1v z57s;^Z0B|$K)T#NuY}$6&Kl;%7J3}EUItM<#u%|Y?4*lqx+-|w$#igd9d)1?1ASGV zn$f1imtBPvGO>kV+0+t?_1Fm2{l)Bbft((g8E=&6b`@ldyRyt3Pt+XA_~t|P#yVYt z<9Z~&K06w+wG>r1aaod84@Nor=uFaJXv7$sI}2ef$AINoK!NU1E5I&%&B+&c%9fQ6 zGse`$EbA`Sjhm*LwV(3i-J8CWmchw~M{bjWKUw_k8;ka6hOmY$@f~Ap#jwM$F{C}h z14TLsG2d{tKg15me%8sH#SB}iZOy#uX1w#GyRvHEvmy|T*eu9OsD8OzzdL8pN@0(y zT>Y4dLJ>DdV#52}`lLRf2E<*`m^Wd*^>S5PM`h4di1O(N+2aHXLRmH?1Uad@jn)G->47m^OZ{k~M@WZP>**d_s>Gwd{e&KH|JLgf z2ifRn)u6laW%up$JD%|zrHS>=z%2wfdkc6y9IK zR;}IXz=*$@`j$;r3$yAcot4kZ&TsnVMAtqJ#2Fahp~gotaq6%oK&U)+Xo|(1!rxpf z8J*zM$m6gwOce#Kg=U1vKNn)04j*Rz;B-BxZu1L(v0DLx-c9q@TxOB|C_(sJ{qhf< zLUPkRJ#;UHlC`d#`HG#v$I>+NA3erp;c|?E?rpVM;bD)p4<;PD{45fc!$c4JJJQ&RO0x&cSQXmH<6qdWsD z)1@dx_L5zE)5j8BdF83de0tVJd(z!_Ik^5IT|z%e0r~x%!2X%=kKf0 zyR+B0ASxo_tS>cco~aEyHHi~cqKeDublr?+crT;36P!dpE+uX)867Ikol(w1D#)%s zK9sOt1$4+z*yUc{{Z{mVC}cA|aIX^ZMRE%sQ`R@eL;GCHQtD+_1nZ}QeGK*>ug93U zG2X{6r-;52CM~0FTvD{~-rn1Ex30?ExzT(o#4Me&V*5tTRq++Ra(of}k3YPX?l07Q zKy?_+R*FTOdt4Q&gXFh50J$6iuP6t|WfSOa?a1?&vGcVbOVgA(-r&g&gz`npehv3W7j0%mg)_vyv8}CrG`S@ITYEpsP*p!H$rbW~j1zwiE~}L9o2w}I zAggHJ9bWW#x%b7p)7M+PKO)BheM~21u@`pwAaeHFmDD+}r_j;(gR@z?q>=dn+C^^Dbq)6Z@! zq&x70dIz?}2YX|6WpG4(?jU)M_iAi1;3kr{aOU_4sGj)zF-&;mchJD8TxYR#;WtgNt^iuferGIuN4#=SKP=yrUP>*jn>&u1<|#^_n_? zz?}iyr&E*S-v#5qwrYT-d~ktSI%~xl{e4zKiM+Mh+wJ2|4;ziVoCG^%+^)ZLZ2vMH zv&en}=wR#q7hUfZU-uSv3nyu8+fHNKPQx}$(%80b+iuv{wrx9&vtrxd%6|8L&&7An zRr^~Px%kgHAB^!lV@R<6>p+o842(1?VgD4)&Z5NDSpu45@-t3LT04NCPGv?_9~Rt22BH$Y$G(q z({8reF#U3>tn)h6`78hE(8Z`KT;ohaTI^v5?Q{q<{;SC=O!8J-bXt(ez<0P5uGqEp z)p^Fb$O@W}r)8HWBQA^M_;p8o20xhZF;p64y8f%~FrsQYDVSR8Bqw7U0;kWjA%`(+ zv{M6f%q0r@{}ywGlqELO;m8d?{HPE=xj7XfD8OA zFAJPmYqoe+Qfv+xKXEWT=C|k9z&QK~wo%O5ep=2{j#%sWb=WAGGdY~mnAJ#WEE`{G zR(BMVAvSLCZa&F_bL78OR!yg>nlLq{wgWfJleP(e#0aH97+=<~3>C%IJyRdr(V-%fLB#jN9fLr-m7`WHF%6|Kp0Lx#r z6kz#u$OM2O1=}C_Vr}x}ss*><7Bn^MvF!_ zcbhfzF}Y@M_ANEF;O2vQCUDJ4X7!M+a+_Q60v>~?>71P0TvPubJ!K)(h7WU*QE9i1 zu#7zsn9maz=ak{4NHn?yId^`2#}cMD%pT5vBmHjkQe0nmnG!v8?E#V7F+RCwu`#D! z;h$t0h*E z`vz9OXR%%1q3TW%eXyAV?7MG{;J2n?; zv(Db~d;~KOolOD%@&mvSWl$#kPXccv>HZn2F%X8@vWsO$24O+284BrcnJkIUI9BD> zf@i;CXxM*)vW@~jJ5$!?S)|4$Lq2?Y)qj16pVeOV$F*4Ubey7ZrAg858y~d8y7ql- zO2r>45Jq{^kvUII9cwF8S(c}C<-n1rye8ha#v}al>)&iq`*F4SGdnuFDie*JHz-q$ z#+hT(FpTLe{lDd5V?Y9n=<1rO8|)cXE0?@aXrt-UX+&iz^JGa!MK$o*V!dH~E|($X z=4s(dxI#;7yH$t5VKkH2gT#2kb^ieUpFj8Q7dAeTs~PJ^wWtpNC)0_+#l$mzH8aD; zm=AbMG>){hyD3o73Cf5st1KdcE6}6wTDqz@CUz3{>i~VwdVnC+{jd6&4Ez-hA2|w% zFhLcre7(RlyDxf1iY!~niUy~AD>CyVvI{0n64+jHtowGI4qkXqbWO&GC{1zRdq4JT z;-ye#+5VFL7Cx9r(htp2cu4=Y70Nma?xMh8$I}jcpBG(6Efr7i}qplFqF`? zIe`MC$C&YHrtZCKHsAKiy#?v=mn!}}vIDG7j$^aIV&oGi7)Ng2de!1{70?u8h$TAT ziOjm(!KJVZfa^aa&x7j8+#Ry7pAHptCyg-~klRNYs1eKY&3HJG4%|z$?}PV?w*hE* zqz4kW=w0nko810B3>&2d>>dfYyO7fnv7evR^12&O6K!_KmV;ypRV&o0*+uAg1Y(!F zn!#-@=iTHfSbK@HRxrL}TqsI$iB<=6qWp}Fb4Jmq7DeFxseT?rEG`0>20gH0hJu^@ zd#jb)Zr4pZ)R~mpL8jx#nZfF(pCF`WWviw=R39xV;gFGqqqNM-BnjNji8(Ddc*73<4}2C`N(X7IB0c zMRb{rJQiozn%l?Q!^;+>{*=F&OmQ471>_#@m+uC#cKZBoCg?HoR});uS-UrEI)hOO zBW73RxbEu=(%D=nlJcdYYHEaa6GM7H!<4DO%$@$pj`ilAm!~F!D((=si7VP)hKQwq zoXno+LI$n}Ow5VH4}<~Xn*&#vM%pdfzY?{UROdy9Ga4_qAqwg9xX66spOpw<#29{t zJN7%J#C~&12+?32bv({=B2qQ{v)=d}IQH0NrB+d5!?(1>tsZ};Qb3pSw=}cM#}d~0 zXY7n>QmWBfe;bRM<;S$)kF|?NJcIMGZ|_RF*&RYm8Z>aYFXJ2Gs;e;^IZ|?sSxWZ1 zLM43Zo3}sH`i#cy7mAoBEBAErrFdt`dmQlpiUBwgWv7|K%CjG|yn$%p?Lpe9H&JQp z)gayg+5oaNgaY^_dZ-w@!u?mU`PM}K+mtML>yF01L;)MW{$2oxiPqjJ^llyY-wv07 zRtD?r|2_dAs~LhDVHp<~`Hr@;ZEi0Xg#M0r;zi)08n z2MVM-1EI;n{O7w{d=4`*Pwpe~G_V@9tA6gvU2e5tGBoDS`UC2UQ24^n@fGcdWZ8np zv|ExB+UNE;_p{bc{q^}60iogAaO-J>712&p6gL_11ndZ6HT7reOK|mTs&;$sSWbbI zfQ@#WUG5>nnDllClUA#@|C}tL2Q@q-#@}|%~^o(jpPJ!3y2W@7Ni$_^jTqWftRzQ!pbEpf{k-p>s zT{WSi*{G>DI1%Pm|=(w`k^}Td60gO_=`0LYbO^Za{l7@zVSFq z!3P?NK_aQju@9eq-RIKr@sS1@0b;q~x$ zsBB0_1am4g-`X?|MP|6B$OexrIB-gA@JI|GTjyx-c3iYOTz&N`W+SuqD$}4=M=mx~ z?ZTAHqj-z1eb^Dsqeec~rR~32fR5hKPEpd2$(7DZAo5Al;)HsY`eWUa`9f+U8V*4q z66A$0B9lfpTRg=)-)zFx$ccTMmAMziay_zv;-|UO;E>zy;s#P)z^%S>H$}Y+UlX5C zwRC|CmO-dcDd8{!h02h8?;O1}Hk_t@Vva-C82GoWWrabjf;Yabm%n!Bo9}P7$UklV z+xx;pc|1uu<>2_=X-a%hYf=0GHkzThR7HC_0={DWVOJeZI(f5rv>TS8;~;p180Iim zJC-D;ZFfD2cy`3xHinZUGTC-6zJx*SU<}#v7Fo}BZfGquaPy~J+ z-@VW3DpwP9)@JBR6#@$0o#sl$cPg2<ioe_g(5C5}^T&E(I8v99*6sBD|%ubevLQyvfbS^D&!RzxRp z;rp*zFwmRcYgzFpp_G7YB!9T7!(=8Zkka@Lfc{hxUkRBtrR~G*A#hp0s&wfX zYpS~q4^o2GR1A9U*Z!6AYSwi9?wa|~w!6~x_Ok8DA^+{4F}iMyFd&ky9XGa`@HwEB zAWrNZ$Be#%U{8bgCt@>od%wy}eg(-LF>#%%lR zjF1+&%VFMkG_Wi+Pwu`TLfV#Ci^Gw=m)^yElfzv?yuZ`jDOk!uH3Ity;`i-#Q^!z3 zasGjJHw9*j2M&7;+LsE2xpzDE+0)OnP$v;xb^`)|MPWVMF_5K7#9!ZVf~LY#1WX7d z*s-1RL%%sRR%q-xENjiVY71oHS*4%p{#a&#AsB^AMy4uIBE1BnSY!lKgIDKp9+Cph znU1hTGHuJ+bw`1NY99E#g7+<_R+g^*VT}qL>SyVwG`wX1wXvwRz~%jB{*&wLtChx- zrUivdwjsrM?nNLCIl|yJ6sm9{1<~=a;UR9%PkkniCJnJLLq8G)gQF}wq^qCh)YEUo zf9xTD;nI+kwzRVG*?(~)o&QHw1bp^i0o}`=J62oUK_G&;>r|`<+O3hC!;H9ZBmG2F z=Q^HDl{5;nk_@zzU(w=}0e-fvnGHLIBPcPn<1>i?MZRBlzRgMwXZAUCT0WYXjSASZej|u&stYIjXa@(?`2jEHv<+4=yCfe>^mI%;_bC%tK;d zSBnvi9$Nx7NEv`r)lJv)khNvnRsw@!*_(#1%f0%y$8U4Hmq>mO9M1yq{ytABKGMY~ zY5YbQmNnQnw-W-jI`%k?)S{U)7G(fbIrH#7>b*aa&F1<f^O^8}q+I`hZfE%OJ8GRe$GaVW*t5RB%2r%;l6RTz(@`{3JYJgJ zG~;l}K1+Bq+2wg^OYF$b?uQE?9h2_DRQ(ysRz1Zq2;Pz(qR02D7%u=*unV#0Zfy<` zyYamKn&Yoc394ZMstqjH%56H@q7cbnq|q)DPD($QlzqUs%F}1Oat7C?rN%lQ<>(&(t4`9N_ih&539$tr?myyC1hy9Z5h{vB2c8DLe6;Y&&r(@>Mi?*(ciDnqI) zkM(u=>udi#?4xv!!eV*;6Gqv_r7@V?6v6IxL;OV}!jyBxx8}*zmO&$~x4BCOHOb(u z7`22^u9zlL#a%dvt-xlmR4KVlv)0L9PYY})kp!miQ(>s{igf<)F2dR*7}NGPd=S{h zUolVsn@+JzhL4mE-jmu2?okgPyWkM!!V6xQGGP&s9LNT#+Ss@th{h^UBP1UzAIyhZ zuU*haWD&23XT*7bWYh|wyrImpo4J=E;jD&I^QzL-hKJRQj2r#vOl~qVvaHbYG!)tc zO>@4u6QP)F%2 zM$1E2pw{ex9`oV&Je$(FXCwW36{@EX ze&wly%@%_9<2_>x{F9R#m3oRJdP13Ns9EId9a8pW+L&mXm@>YeH7U3rX^iePG!1pq z4x-w)Qsh@^3;8B-dQbILicUl}8B=W9_No1VKgPVU1jwt7ePZ`-`_V9H=+T4<>I7RW zH%eu08@VkzPp(;0Z8tbw9&eYnP{Ze5KnLVyXuk8$Pdd~Q*5v>Bk>4bR>J??V^a2DZ ziOXjTLhHMwx#p7*4D%K@3@{p2=~%Cl+(|HH5Fm8j&rcAk|f^>(gkl!w(&XlK2$eFNps_ zCFv;7o2YI-%qMy)28RW`m3P&k``tou8Wu%dB2i@*)?j>>F!L;O!k_nu9S{X42&qWo z@fSh>%imdipDg^~%S{t)PTS?;xS8)yXXJ$;952yJAhnokw(@`zh2ry@PL8qQu)u87 zD$(|J9mqF+a%vMmYThv)JBqnd_n2d&pzpX6_ecF0jwV9(a$or!ctChYf=dNdDioM5$bre z1ALb4;2#xJ*-}%$Q|M{pLH+?j07s>yOAxujs=M@@X{$$9bvWKTHsTbko3^G)2TInj z8{kE6P&jY<_oCY(LZ2!F3t_#nf6hn-x|~GDzAA1+I7&(ydX=gyPy=j+ivLL3f7yBZ zG28FEcg5;}QilwnfyE~CE`}LaU)`z$gqEof)Xt5Taio;)wVhT7)d3{zK!_p3 z`;&X*qtBNM^fabZrP}F$Bqt_AtTyNllHt(t<4-MBO$5ud3@WZNL&l+_`_^PHtFd^E z#FNuI1*?4=i2HaloyT6RJvqync%1E6>z=SNZilaF=fQg%@6`n8xzP6z^$3$ap%dzZV`m&Yycg^e9UP7m*0vcBcZ0db!TD z1^FKBnmpE_Ex|d!4g$L6*|TEk8_7S9E#FUQ?66k^wM{u|tVBtX2D}!_pz}AC#Pv?9 z+99X+E@yk830f4us@e1*QA?MN-WX0Qmn2)z$L0K<8AbPHMcJ}CBQMGYGF@3U;bY4{KvGACwXG7; z>ioClh|#V!*SM6XQzoE@I@DyuncyTpx+jo7r>A0UYX`L&QXA9$20{pN`0ac zH5-v77rgg5bkQWM$aLX$fa*2H%U0XX>Qnk)!`gbe>hYLS%SW_gedw{l44gS^EvRDf-`(%0Q&mDC(;@W&V)MCLOw+Xlx$)K!U69 zkcI?t>A&cB3VZ;`b!J>8oUD8O&^^IRKcx0ED;oz)yj#*#`I)t&dWJ%aGr!vuGa@QS4}57VFE)8f~4P!R1#(B zP&SL?qfUUDunC_6ya?v`YZ+aGHa=#(qR5KLRpr_!Uk#U->VzZ_=0W1uy(5@~d<=*fkG0h_oM` zP&-Jb-2-3{r}1K=1};0NRnb-QgKH3VFn)6xS@G$?Ke*IibMe!B^o%>T*=oI%wK4>7L|{*InV7 zdThL?;?xe{nucx&m zR}Nzb-Qre5YrM@rau|E76X=?;LkRi9B8%H&0$>EarIR;x*%OL6vsK|%M~~r`!E~>#jXsKK zaAbgo{G4-=2{T@U1jU~Jj(vZsxui`sdtejl6eoyYP(~ygfkD9&rdOAArn=ADoTe%) zexV(aVI?`I;^2;<5S^_9w^i2*#ib1*JK<=_SBT#?FQ67)#Lg`C*yR5cFQV?dlBljHsi?v9ET$` z0XXoDMHn?hDvQ$8TCVjXx)IbQLk=m}tBu4LR%HWo`zIo-ZQ> z)yz>$H}ozn423W&E5_T@??92Gs#e^U6j5SIn81j*&l#}IL+~8>913LjT>rl_A@cL+3bK3Wv4r6S9!gYqfS8b? zA-~poo(`P#K^Rf|AJd_hk3bZeFm?KAf{L+)WgTM$Nl-)2Re){`q`uXRZrSXwm8SbY zbYp^xa4fl1d`dIdN4G)KXz@Q&iE}|*Z+W1*XK#hUysf>0#=kD4wyBNLH(oYDuDJLH z{UIM9SmDgJ)F_BthUU&n`^8PpXwIr+-Iw3r$^m6oR=wK9;xA%%%iZ@l7*xn@;<=?T zC+$Wq$UY(~8KNB2=P?)TmNXemZ+njQKb0c)t{dXJGlV1722c0gJ{O28r_d{3jznDf^agZb%MxD%+O+}I>#f|%u$(CCZG z`SJ!2IsG7LLT!P?pPTaFY89vuo{Gv1S)PQHG7AZd0TSo)X@L9}Xal znJW^u%+<-x!&BviTmutF8tfQUkkQe-;_eGR*T?fK?lg;VmLQ1yK8ULa`A}`!XE6M% zOk%)46Pi@28C(nSmrN8eh;SHkbuL6HN?#?@H-eghCfwVEa%G)%p5xp!EsmdyVlCA2 zxr7>{yu78{L7l#Ou9eqij`K6rKPN(qY&GjPyhsyO>xb~aM6|g{EdxMCd&Zih=gyp3 zz0hH3SR5IUge>1`fdr$MofVQgYy$f}KezzVgFYlOqRgIj8Ie6C_Z zKPJJEIb^UfZx}iw+34H~X5Z~OY_8@)`-U)Dk`N1}yHhx5nNM63G`J6afd|nU@x1ZS zsj4z_@1vt!pQa>Ht3nOs7v~IUI@iZ&hraEV=+o3N;z#sLS1)jKIVr4MTJ1!A zwxZQ2u8t_njEaJ-jcf5Xzym;n0;L7Oz^hwL;kJsnpjn$Qs#u$;L9;P7No+m~?CATp z+CKQQJcD5v$;to8Uid&iww~5pD8b*K7sOwmYEwlew3uv(GzGt)D-%4pFVLGb}D8_uIW@0#yQlYne{fe+oM z4XhPKmL!FcY?4b0gC-=Nbh0ju8Lc?XH{D2YvGOKO&%?7UdLC(FmHe6Ks|%V@e;7Ys z&2gxf)}gyl&! z7HSRs*IYE#>MeG*R^5MB_Y3%a<=~JXN)zm7(D@>+D}n{At0ze_VF;z>c0A-Xl+nEI z(0B-?h>Vgd<|`&+!cG`=0+QYqZn>J)vs3lJi#z2*=$sbEzW8OErUXn;ccxqVf*HFK zZaEa)6Bzs)W@fm_D^ckESrwr1c$w_vGVADAzDpLU5N=X3=yV)eSQe(ry8)T~#i#jT zpDge|^s31N%vGp*_1qN^f5+}L?Q(9C0`aH3wS_4|W^sssg2Pd<=czIjSb6^!o1`00 zyOISaBE-0fisO@KwTYkc7D*>>Inq@gW#CGw%K7UBDsnW}k)vO&usWEuJm|*#7HXxu zq821pq!Fenbop}l&I{7fMi?wA-?6i6##RSv1S4Vla=}L7{?c{S+9W>2d81pN97>f% zj5Cu~fX$oJonPO(YJ=W&HvIbmO@g{N7F<;T%f0_Z0!XmBTbsY@zxL;g2K%#5D#Fm{ zRw6pp8<1#EuJu9{;2!cy9>;Nh`K^cD#)!M=2&yDnXvkd?mDOGA91$T{{I#J`WxFI4 zLIm3qxaagWX<$&O$Euw>%OL+)>h-bMvEwVpXHbUgfCFYoYrkkwNH?C#x42qH!LFx|LBa0t=CNJ|YpdkX znOE(Mltj9U7$HVFGz zuGO3&e*AiqA!>)pLv(yd@ecA5`sO={^CpJ2j?$j-S&Dz=qf8`VE^-xUT#oTOsw4kxVADHtL9WhS?>GKJH zRW+=o8yKPp|5DXWWQVAj;IRt#)^LjV!Mx+DCF1_g?tN)zS)1Fz1OY>$Dm{A#BL-F= ziqRcK?Fm*5viQY+iuqJ^iSMgx@Ls?}Q`rn}Ctg;W9Bs_rF1A_y?369`&ftp?5hgw& z!qcndKK}s}8*RL_n$AfqpDQ(64b^3k`QXjgBD2_1DK~(Fu#A_5w{m((OP>sTg-x&< zO^y`jPnpv!XE_fMHf=d%Y)hFp1`7ZMshxIm32e{TmFK%)IQ)&JJA^<3Y^Gy7t^(VV zm$qh#K$=q`{UA({0JkIn!*7kaW$m;3{0B-10s;#H>i4U&pT8gxft~=u&=Mn@D~Ivo zmr>h|nr_koZHhR2a8iq@2jSIJ&%YLTTashixQw0j$Zchv$IX|7K-{DKD}}wILXZ@3 zJrE`q?prIpoH$=FTa1`Jg|`+6_PMEFzUv`KKK9$X1({<#_u=f!xst1a=@1-L$$(yV z?mCc|sw!uZWSQ)LUa^4+r`CY#u}RN>0f$sRAD}g!quYSx5vFJGnr){nc4EOsG?coP zBnUp@bJ8tI>GPMgqAFToYm$|*05!=opfw03S5gUW-aOiJZ0{R3HZ6qKo2sc7mkZPS zg**ndOBS#;Up1`ADpz%g`*!Rt?HxoA;%!=(0yogf;03KS>@Xe|i{;!z`#+Va#8y~9 z_q#?aRdhvD;pYc?6V6d%&`v%|UP}J!Um*CDAoz6B^?tHLn%ye7MXS8|Ihb zxV&)(00lZ4x?ab+@DGa0`zXA6?1`>gDg&~)vylD*F*B1}?wi%dbSKTJ;t}wc(N){v z*YT+qIkv+V1RvH9vTm`7@tQ0wpDQdMy-Yx0jmU-D%xmQP=VlddDOYMM-XvL_HZm8J z%h+yk{!YRs4{cR`L;9Cy37xw#bJcwHvcsk8dh^z4kLT|4O#`QiX2)<`^ET1hXfWbIJhY!)%I#;mucIP zlq^ZWHUkv=QrqIK`k9KB3HiZ5GkOA_4_VKZTQQPZ;tV}9nO~Od{t_dA=I6P zi>mD!a7+F3P$jnRp-;7#!wTnF-i)~0fsF+OGoS82@4%Cvs8xF8D&L*y+M{56n!I?GPZZCE5I_9H zX|@=z;jLdGbU&9|bb$DLmPkyO?iLV^KZXNBoEI;h7kz(Xg|>CCI+k{dcyD#p(3}~G z;yON&w6K0ig*a@FC@-q~l#lg|&Z{Y+=3nm;A`mJ4TYQ?)%AbFZOS^KI*-#YvzP^b6 z4Cvzi!kzSdtIjXnGG@^-v;ur^Y|XVP?Sn7CYIVxz{bsN#eHPRdH(>LMU=uX6t^2@H zA>!KdiVw}FjUg+*9Mh(De_L+&+#WJzGS=ltGZ&~_{qeLb_`dtO>jSB}tHsZ9L!a$7 z6QOPR9ux4KHpS2Qm_fpARt31h0!pTAzWv>-U~GEdLVDim8p+w3aUTf)xZlXTa6q7F`Mf-$Eg87W(btpQs1dj7e^yo*VSlzXob=%mU zWKtg|Y%Ww}l+(*xlSC!8mfIUd*w|Z}ysZNLTTqH(SfF}onkk`O^qzk}d#T|X+X zQv~^(7{lfjxB~Q)1=Q17@_Ac2+lr8|KZEkQgc^uy_pici{b9I3kX?T`?yyczV+%i% zw(H<4s20fxTBn?U1&tYyhYka==0X>k{LrHFh)?G1G?BKu@_K{(c4mGXeZkR1(EQM| zKfU*qmNOGLThK>waAf&@APDez@3T_IB^%6tQsF6o>Qd@!kV(S{=4Zr}JTBNsC(2`7 zpcXZ$mvJV0sl0fulx9Ef9o`2j)UB;WT0C+682$9Z`}SOpO4*gpCKKc?oAvW*VJ_N^ zSHe=aMDoDN*tSVBtM1_MRss|G6<>T)Je%dN36ijh`x7@ff5&MMcm#{XNh{)j^ zG5U^jq~zM5r4?{nr+U8b5~8;+6WNCU55BPhKLy5k5YgL+#4~bq_0c9 zT!%cu_3lnxttJng^q*xvjhm=tlkFGxiu~dT5xGFDLX6c;*+*081Dq(E1jSsLwuhGC z=^*eJKlf7!fby(4Y=JP}O*)#$g^}#;pI>qlj8IR(PO;v8Vz}NCrn`xEe&f$tfIiws z(Lq|-;YKE(;~&}P9#|nj#h{1$r;L(rro^6!Y`ED<(GVFkCW5``BhlGIN zG4a;%kyEZf2Q{E9)8u%hwnhnO3*i(5>DytfGf)VasAX_s9r;vq3;7nQ%p>eK%L` zoF*#7&{KJa3$ytJ)M;;xz2@d)yl$!ue9#m$WPGQqIfTk^o9%c3j;B=$UZDwsj`Z9l z=bQol$p=7amrF>u2$u*-V*Tr9F^Pokw>Z~|eg=(8VQpyJpSDx*xntX#8_%0Z$u?RW z-b>%c)c#&5fltAJK{s-t_M7Z5iSt$;3H;L#aKHclL;PEsbKv;W9LpRTAS8K&{Y;*kM9?^oDoBF~y zId(<33KC)4#Ct2d_5^o2q zIe06E!OTKR<{z0gIHu})y!z$p_`}J2qSap;l99HK?I&sXnZYd9j;LWyevj9y7*B+} zw>K|7gWBEa^#WJ!@DXjGnUIn8`Ygrdg7CLk40{ijC60eOgU>VXr*1XJDrKrp##IPZ z+Y1=iTKrcfypvY{h8L57daU$4^)eF_smcsij|dpI?uc)-w|8v9IScmu!2VJ(9Q&jc$+(pIq;+2r-_% z^4C5^uWW+mi^p}e?l1mzy*Kc0XRWRhUG7fNcBcmm-CdLb!y7>tFfb(M>=zoT9?LBz zwaAB8Ieip6gHoIfm$a#;j2Pov10)mC3k>fK(<+>hM63C@rpN{gEw)m6Csp1V4R)g2)TNl z@!E+}3z%swGqLmQoK}9jCL9T+R9dm|P*5@Sb16^saVntmD3JRfXz3l%Po-wEBk}krV{W3Hzrflj6ng_D z6-MZDl;SPDF@*V*EqSt0DDOc8|M_#l8S0k$W9Z|Ns1as4=04_qM$mpK8TpAOE=ev_ z@TE@BL&(Nq=mcnkId^0v__5~mV$=9{gaIaUjWXb%m90rgP;FYlxAjdI8M-E?EK^YG zSel`Z{pPLC=YA^s48kYlm!(}R*~>LiZrg`bgGqSHK9^Wx#@zM41@L|oG&iVct6|A`8O)DzVweStsc{&5%qzSl){m_c_;a>zBN#i? zHF5WNj;-vWbug9#fOeo~ewNfvMOq%(&G%)#<(bNe2W(orlxZw|KjM|_=Ok}id5^Jk zR|%PPf>b5eg$Qeth;3y85PR$zO?`0_r?*b+y#&55UO5OpI6#r6C3*u#!&c;dc2NXS zpV8yglL`}~21ac-44J}KyiPIsuHwuS5A2<3#gCZ*eoP0@5|d+eS+BGqGlxQe25+l| zWD9%6xdI0uYYLo}c+-7n+wd~=*GL!qHENUnWK!8{=y;&In@4+X!J+u($7|-l)WG%QeB)$Q1&W=n)R({qnkDBIBJz!Wg5 z1H_&r*OH0Iq2=5mG&#Ry25|C@ft8GED7pRwY8YF3cd%QY4bUc-W%a}=rIniEHcD_v z3W07lOT8f|2c~^yvB*^6Dx-f0!0Po}i#5?bHm_^h($#y~738ay*V@>3wdxro_BUZm zXI3Asf8MskdoX#0*4MhvePg=RIpn2sR23W9O5Zeo-Zx+!sz3 z>$BIJc=a5QwG6jS1_+$18@-Q+V^DS!&$Z&6l!fK?x^I=da|xq)xiE*V8CCv#yJa_A zPX5M|{F;hQF>vtYy8W0(+~ZD}mtvmC0g+F1`AP|eP@>T_qIaIQuhTd`Y@0Tk`KE5b z6(Z}-owA2}wa$-u*SUoM5HH@#ZJ76qW(r8I1E1;cZ+f6JI<>l?zh>o_G<)SU;S0GT zWU)bhv(x%ss%6D5J=HG#ER5)mTl3(T^M661bx1!rOr9n^pmoVVn8y%5SY0FL{W7od zMVK0}mut*>gietG7maNUfI~~)$>?-Q0wAf4{^hv(6;u4^ttluAnd(@00iwh^$ zCURC0CAT&+fwkE~%^&Lzfi0UU;sYP@#h=f_6F8%4C~CI(!GbVQzybeVLl`gStHb+c z9I0Q-wi~|SCSf)ZMh3V7rhpl|Xscz?xQyyx1B(4bE!2%cD^1lFNwTgZ(`kf}?6>3! zp9SP4(d}?^TAy0N;e)gyJ8O0fpMAu{!F~0b%jp4iNAdW#5KDsivQB9H^Xr2`TpB(k zxD=iFN?;Uw; zHvzgjw^9+S3XQeXC_xV&g z4$m4te?UX=gDIf1qHhDXtyp7XY6u>zlM&-8t&42~f{R1%p?zx-`h4F^Zo$a2%fDZa zrpA1i_EdvvGPP!pnTmN^j*(`Uk<>r0ym0#^ZLq_x_8Qla+Q_gJ!G-C?mOoqRnf z-KgpDS%~qW2SJHO7;CYl#RhMvEB%vZN7{j!uFhNVf88Cg^uTuE-Y?DOrJz#CYft8| zl)Zo>kYENh@Q=%U6wG@kP^`rlh}kD#ZNRJ@`WNdN2mP8d)6XC^`*#N44O*Y(>T1O7 zr;|wg)0&G?O9IJ}Tkh6N0LwdS#G%3P2|62_J;F~NL7`LT8AO+O&TdtV`u$>lM17Gz z(5|&pj*n(C#zP8-h3YmnbFK}=HOmqSC_?v49WEculCVjWjC z819zBMVckU5Kl^){n97N_IWY9#DERK1zBpw0x+^%1`6d2)DM(x?(NgjSs9swJAr+Z zjl@Jpn4|1A4i}qrgx}KH3y7< z#0yFtFo$D-SoP`YfU2!P1&b0lq<9S|J=8Bnot+S2ET>40a9yGaP;L(gfhPyLNE@42 z)5Jx^Gp)FT4Zv&-afYwW@zl~0;k%T}=F6cIB7g=N)E+V@9WB6#n}{yZ;b z^S1pGiM2M6kn=k7btRB7fVBlXjo^qc-V@kXlE#B)%jR*L^YjkE-vdQ(CKNQk-#}CE zxFvodZQT)~e?34g`yPcQKoqxq5oX+!Pa@%ROBi&VLFFf;9G_80j#HrNgz^g&5&F0< zcSABh&bA^=1?oEcT(In*-z};CZ^L!-35oaNR0NQp$$NNZ*;q;RNd{v$nDkQ>jokU^ zZ*<2Q-QT<@lCUbl^d4NNOzAm2%y%txLfhH%uzHjFh3f|P&HaZM<13JeIH@zci#kzv zoBQv|Sbg$3YdQaudKARK>D+#-jcNo^dZQ7Q)>Aen41AC$^3((Emd?v07Nm;EW(#S`u5N+IBQ|zR=2H*2e&wPH+8z5|TC1Y-o`=Jdk+v|%6f}-QnEWrk z_fxmrS@)kvM%H7AgKscJO6evwXDyN;yC8 zhNWop_fXunZ{m2GQEb>|Iq2&fkd$jjC@2jyB!eEY8kAq4gZ z?fk(ReV?JDU!)tiX`j7;KD5FGA|#KPC>C|*PKFYf)?g+Mfy_G=i;;vumD(0HbhVN+ zeHOfIh$ZAB27?t0{%>vJg%1ZaRb(~%-_iR6;-eOEKlOAnB!c$wN+BmiiU!5RqxE<1em9AmEXgWjTw{q zXSA0$#ycPD7&lMmEM@5iXp9Z68ljC;-V3$cspQG_mU*=5?C*BrTc(w@&tOaC}y}M1OJ+q04~cUbiNaWH(KX z$4DpGx=eHCF6N{3XLIBg9BP*zE6E zemK4-7m)~DLKzy9q+v~XHS~!}Ms;OSaVRXp#hoIu3a`vsj2ZsG{CMb|{gW*LnWmI1 zv2mSzI1?*n(KSw0_#Za&l>m%h&BSXR!L8uaTo{NY=wV8! zA#1RCgiH=f82M#WVovXLyL6mr>GRo; zwdbKI(bvg`5J=~*7-2mLR6-kBh+)2HXHI!uPcfkpg3w@30h&b!N$uiA?kSSUk#FM$ zA*mH0Rj%6M6O;K@YNLSVvPJVk`@A8KUKViRl=cU&aP&y-aC+KDf$|<`#>ZdtR~hv5Z1x8Y^p9I5zHv9=$@ZGa+)9{k zDEk)N#%(wv8=i-q#*%LMT>`@{=3!KOS8E%<14z73Q%zi-g+_2aOzEktbe?+&oD0F6 zSu2@@8;&EZtZ{4e>C@qtk{l*xe<{CcCxQb33t~}N9BB!%`P94qNMj7*ZKOS=7TgmS zGaDU2^TAThaV1xmMRiag+C!H>~G^ANwZm#I`05j}r`;{zxiSXc_44cTiA(*#S`X*U~u-9)cAcd}?lA^1cVlW)n6%6QW4IX5F-1snLt8FQZ)+7_XT1C`Fr{L8- zh;>jaUD8n8wk~zZ9~Lupgiil|be&~a989ooad(H{1PksG+#zTP7Tkin>)`GhB)9~3 zcXxMpceerVkaOPi?fwDQET*Tsx_UpmPNS}P7`{Tcg1aE_ztuOG8uT%ttC|LHH4C{c z5qL#n{%CH+3#2x(GL;>Lgw*6bHM404BeGuVtzvaa~kn#CRk>04)~nm*wh0 zL|WABWTvbmZNkBM1cN(BHwor>1)}lvBkBk>UE^_Pqvi7Kw<^SR1_2<6fS-D%1=el% zz$SJreSY+InTeHq+H_S-esY-&(<)Z`b)n2=*{G1JySy63!YC(Tci+3pHZnH;qW zXn>xLo4&sTrpMm_KIa*BQjU1zfC99xk9%9E+M(~0xKGbl- zn2RUR1d(gcgcK`fL3i2oPy|_2f$4kpfWlik9`xT*lH>j2geqk<$aLhJQYVd687ovtbaEjtk*oh-2B$$1RF&F9Z|(o1lef^+AsND#qYSYS zun<8g-h9`0k8u>?5SsC-dJ!`QfrNZlv~X+=#}l7+lBWvsimxw{0nS!rDSCSI+Y}RB z2CwQZ+L#cKSV;JYttilUNVPc$D_SEuzqP`3aJ4AG*>^>@JMS5_tI~2cVPm&^cNx)T zJ3X84CXh2NcVz=v#S(_qVRtMXTa`WKCGB5UoT{1;pPk@nK4D2L5$aCB32>ed7fVHQ zyi+J&SX!n|yew;f9hMy2cfgm9cW`L09~)arADdViiZT>$H;{IyLQY-MKn-PiU*xWLg2Gy26N+|9#G1^ z99QE!;TGt89q|}LJ=~1Pa!jrtw7Gd+h4+w81(|QAeSkr+g*B~Kxa)a1f!Lk?<~bB^ zg8Kz}t`b`O+6@}1XQN4Ea1vL}1ABmk91o}_SkzR%P(6O@tx*EIgOq&Ne)2z%046f% zc=ycF@H}Y&eJiUZPzcmP3jwJ$%k{@~Ou2aqbe6r{_3h70%{A8&q*Sx@mp%E5qF}07 z>iM^lfGt0ru*zX~$!InRmONGJX++e?uk&KR>vPeu6EqVlx;mQ}X5!CSc~HB5LzYyO zSr;s@06amoKCKkaqET;xlE~s7@~IO8sJ&OEdv9#Ic9pX9BQ4qfb54?~;%`2P5WnuH z#dFYbiANID;+nofLbQ;ubVMI~x-2SnWXhiAy6&HI*Dt=$_kLVS3D7J{~s za~=L*twr-`63<*iCsdC9EOcs(eN>fG-JocOV`tx#o3(8xgh)9f!g)U%l`6lTQH)Gq((Ng z#zdqahUbhD6l0++nU;#ql_$I8mLhH>2f>on!^d1?YsHJ-D`~U}GOn5eX1H;8U$tR# z9ZDHnKV2a_VngWKS?tvuM>zx!M=2eH)dn~|WD7D`U-A*W@1ougn=DdFBKvl27*F7G z$dyf@w!(Fr^Ffg$9>->Qud@1rl! zwb|;i1cCyH1>vx$YXu7CuzsqPR4K}9S{P*i(f*=3VU93IAI^}9-lCFV+;_@qz%e+B zgb6K2b(&u3oOHU7&oqxczQv;|4U@dc8-H+RSow860CE;`Qe8EwQv->KNBmt4WrGJ)Od&M~sskrI!0 zMTIgB(kn|#x$(M5Gnslgqy(6g3q_P(|DDe|B7xW7nvU_D$$W5ewI|`RAvs<*j?TXlF{l<@4VlmvnUAm;IVQu>)KV5 zr!2N{VtJ$Lq;l)teD(=(PW*?$CKe6aJnEcgj8$yQnq+4VYpC#0D^pYFpoZ`t4=-lh zpSuBh(?yjrKXP1FM1gW*eq?`1mnZbKbl|k_vSZl_UyK(s*aSY4043kB0z^Ymq5Rha zd5O6tk_$m>)C8!}j<2wu*b%u>f__HwsJY4RwdV4H+alVO$!F+U$jL=nphQF=Mfy@{ zFOH1=vhg43P?uu5m)7EFXExQ%_>tR?$Pv4FvS<3Jw-}%s%_w}(S+7(efp0p9l?Ruv zowxG*^;gdlL!yxoetqh<0jW{5X;8Q^SjpI{?gp_$x}qex$S$-U>mVdgZ{0SkGvx=o z#3m%WmMW(8KqbjeXb?4;j{g2MRsV6QRc0z-iHz$rOnHZ-C~bupEj$zQ2%T~G7F!$j zbcj3YO;yZ7ap;P=j3&n{-{h>ZOq0h}tp?@+91MU1-WWpZbQxO23QibuJTA!CMu~YM*qgO%{I3FOC8K}`06x_Ap z34#0K32B+Egi8$-FGCPzCT${|QB}@bi)!6PQwp`e*+f*CCtmQ;-6aw)Vc!Ol8$ejpVvvhesTn18R4BGghD;;`ZgZi`l;X7CEbprd< zcsX$tgW^UYg`%$9^dJvbFGn|IXm)K_EuK~i1@36yehL0LvPLV}^gOkBT6ZEk#iDMd z9MdaTwEwJ>HW69(-TQmw2Ya-KQ$)%jWzmGX)NjJKgFpOs9Izmbe*cqZ01?MJC^~k< zl`D8N2qT`#&BV$WuZ`cTBJ&|6G@Az^jqof1NjkB=F1>(Aha2xAmG8_k%?9|#HB~LDqSk_rfhJHHXU{Zwc z-Gv??W_QOZXJGrXe(|bv^Shy#4R)zuCh>{k%-j8D7HK^;fH%%~{5U1ZBf!LR2;R*F zH3PRN??9ZhIs8BzN6_mP&FgK+)kZw_Nk%pvv!_6rdy=ta2&0;6?g!_e@(^EgwE@M~ z$Fz3G-7_=!bJcj~cC5^HX$W=bUSXH!x&PyDS7|>kUWJ#||K4hL(0t)POEln&F*5jR z!s4F&wGlqm;xogx7Cxn6uXblFLNC#gv0sQIprrbV4gXinu&iTRL8s`)Z0POPLI4uH zr)8d_ETT&bUr270=9<}<5bt#<2gPyM+KAXs>{7x#mWexSc33Oz`C>4$)BN^DOCy>n zKVaRd6R%e`tv-|!D*+P2$jwL0dP0hKkyxY~B-4I+Gj9^qm9OM*iX#v78<=cr*={wc z!^mV1h{UZ#dNbyoZny~(LeX866;3{%F5dym#Eu+^;R(7;NUiB(13)4I==PIew``7Y zxIkP==3{84E6CzQ_*l{&?KZRFg)?8qm7JZzhhUvNRZ19Drdoo11C{3P{k>$D zYyD*}s9MLwd!H?{NG~n%2Ss8w*_C-(_WmzO$jU9PacJ;TLTj?lV)%|9jiB&wadO2| zqV5y+sMT$aU7Rb-BWTQ9Imr9UwocDEI)x^CJa*WxC@`+8bTYCo(Io%wa$(ITSl`q} zJd`_aw|PvvvJ;xR7oCH@1{(ueI;*>1#bHOhsPqN1(IhhuV-*zO<)alJq@B41X|l0W z{BeaP#;5itK}pml)?%>awJ814pr(2!uBe0`6g`oMu*-5xGfD(S3O|`zYobPJBcDU< zQlaR9*l?be#57DxkbU?otNt1sWc^+msGt&%j2NG$Zwo$)5Gzk+&uyK>G$;n=0d*%N z6BM}~=FB-IQ;)yuiQs6MY=DYWc=+oMLf}599F~6*I&yrB7h7l#d`>9jg9epo-3x1b z?*hr99;K>V{qq~h{{f|rA6128>Hn@iZZSR86>FM?QKFplpUXI8>Xe$~nrMh{&{8-v zB2;9(Vvd}SaLZ+dfd!x!Dr6<|oYg4Q)zZSbuVQI*ZKh}D?!M`R$aMI=^#qZB%kJPK z{D(D$=>)Bl_Avtpe_lB+&-*09<>!P5#ss+5fiBhYNRiic_8*HwDJ$C0GrNY2z*5HcZPA~IiR5L zAGIOn`|e>(yGC831Amhn>9_ugt)Ze`Acp4Z5rd6eI8!M;bUN~~^$_WAfMPSEc?PG> zfqm=ABIE_GSXnEN?n$hl7L%D zExYRoV%W{@Y}f$z7{3ux@gve{!6)i>v3ndkch4Q>W8jr) zB?8cm(jj(}-JIv!&=g#C;J017>zSM(&m=QaHbwpFf%=JdtFx!+kO|n$G}+C?b#_mQ zfkue1nPPrR`WalzdKWqgcO7}n8#Ji0bDY|V!B^!-pBnjc6S#~Dky)(MHnt2VvgPQ&Ig z!nVAsH2=tv-GZ9$az@5uR$Y;4eY{lO)406DG;8rX%=iGg-X8Mxq*HeuxQilA35Epw zC)?yxi;EK1#IF_L{l@ZctIqj+lwv$t_zpD`Qf+0U^VMHYDVJ?Zpm(C$K11||6)v9q zy2noA5!(j}3k@a@k{(h<^DEXbF8=DyZ6xmtbl#ODHJ!K`e#4qVX65k|V1Bd3?=}fn zaQ%+Sx^8A1_%StaTN73rY3?fWRxWnRg%Q01l=?(@D0#EIvJ{A2hbS@&liafz2ac8V zGAXV&Jb*0wlM&PwdRV3g#lEdnzsQ1UXxZL4O)~{@D#CA!)74G}9K_oR*uRu;tq<9> zeiD=5^7?c!c5oQm)kVy2CXlPcZ?rq|nBC)At28wk?<{QA&uoL20mF1q>pL}=n0uAC znTb$sBgX`quZkF&t(=aX6YJESUCQWsM%6Ry`rs3DTumG2#HXvpIm(m{Sbv^xD4$3^ zrQ0|lRUqm9_Au^06cI9qGZk>`?v2z@0SZs@em{Z(f5{{Et$ z?Ct`9ePe=>g#>7DQjoKEc88qY5IF?Z$Z;!Qb1B}QTH9uKv>c4^MGxBGixTNbGUcY} ztd`O{Q>5|%QzUHMXVPYWQ}V@eX9r3$GN7UmUVp;9?e;AzQ&9ZAM5PFf#Dxra`D0qa zGG=~NH4>=fPJZxz4GXRhuFeK**}D3p0-Hjw%&B7y66vT#CB(cOm2t86Bd1Kv;V7{R zrcp9AH$e~(iF#^UU;atDb;f*RPiHCTs9(nbhA9r>*wrnZ|CpLiUDTD%962$}C*oFK zNH`Cz`vzq0xdtYk4(AT;bncdzm+b>~uFNDZcZV=5GFIm%PanjDuT*^Y5 zS$&pb%{YoCehQDDm?qrD9ZnJB`?8{BV_b>h&UvTZfxEw+br91(p=H8n?ATC|yiswG z22(BwQDDeq0Z%91N=t)Rg#m})nmo`&l-y}EHz2RoYhy=m#Hgt3;Ba5*E7Bp?e3=jLe?wMoPET48c8 z6Q;sU>>k+wreNzSb)hxrAyo&>e+@+vxbgn>&~oePYt?wP?5g$)-4BEylU$#O7>rom zadEJ{leS+znhM086QZfg9=nV-tczTfLk=F-n8imE6gwfNeEWhI?P&MA zLh8j2w-t<~kvnb_%QD-fecPUDCH8VMQpM+jCSUeK`Bg~rd zjQ4XPAk|6Ff_t!N>1^?)`-X@`2%->{ABexK-)_$D1MeZdttq$&zI+1>(B3$@3Dm1u zuN3nYd{6j1$6>f+Pgip20?j@Yok4phl}MYUV5D)!o*x^Wkf`unT&Sc2&il6U+#4gj z>S+)8Y0W`w!{^}NI{QF47sNpeuOfW0VB-VvKZH~7lfPw+jYx&BEwBV<5W^zSVA0fB zsnnw^n`|jbTIQ@*FKrmd`9c~KUK`b5(-*cnO{icO7=j4f^4Ze!@DDBLB;vk0Jds!A ziI_X^TOHP}VH)Ef={Si%1?^)CMv|~I*t4UyRB$b?JvfPE#Z=WIoIRG;xwg`2EZ66523ukbCnxRYMG{L)kqrT$85BuRUy6|S* zKzeb^n(WZN40^X=9mbxR%PjmFh+axHsG3H_>=nrx_K+4in|&ou`@{qh9Q1>?$K@CuQZ9yPL{he$(-Y`z~Uwq!}OT-hqA8eMl7{ z4Kuq>5=z~MrjiPSS>0sOdNSw_i5V&nMBOK;nZLRT{LzmHiUIjaMEkGn#W|_oLR?lW zDe?={W>x25cn)sB0HVLO3)>$b#-3wa{_)3Sl{WuLDm0P1y`QcZ%98wLK@(O4<+_1s zRtcEmqrqR%)W&DnA(Lv=2rGISY?<)>+iyAeFv)DmoiuW?(U>Z@;F9SoB?o4 zPkx4LHxgD@^hs6Y-G{^9EGO#Kt+|ApDpxW#py3*ut?(|c)u%6>`T)qne1?x(U5dnx za)v{kf_2sv(LA)>TSR{LQafBz_ZRo2e0r(g+!6{*lzmd~GAD0|+05X^I@_eU#ioGw z*O+IdR;5eSnoc_Ei{z?YIJ&nQ$vbRg7fTvb%jdBaKeDlfABw$Z8A7khQH)8;r$vKd zm*Js0@>HN<{LGE%X=>Gq=YB6bCFQ5mg~IBL&NH$GXKg|{!%K+Z&oq0Yuabe9VO6wm z^AzXso92@1&Ur$*x-mhYg(S&**JhedkK~!%{C3X<6=}uaSFoll!Y`=vOSEPry@ohs zq;5*TASmpDeWAf!JvQQ;}bfC$y%Aw61KrSH&8|v0nYl4pRPA3U4H! zd)9ETEW`%tt+V_zYmw#>OhnozRw&zt``Bq&wYQ)LDn&%d+2L2aDp!m2bg4&B%RH2OY2@FLH!yaURX=b-q<|FDMO^IPkY{M<> z3aCy}7xM@C+)Hy7rjQSz+nS>U;TLo;1Zv9Y?ry_ehf$}S;gu}~D>3!TG|W_&`q?So zf7X2Y3YELVvd3~Tw|b5cc^$c)2U7u5qvCJy@%{{v-CBCX^KUr+j#VkiO3f zY4X^-5M zlkte^ASAiB6oujm-o)6zo8R;!`zb0q+Bz5O)8{Qu{{ab@zF*%%hWIHL|3`SYIVF;{ zNR^^V-T+a5{HL!f6{k*h+D}@JzL98(yQB&rtc7meo3v@=pxD`=;t_6U+>|Zw1((H7 z^}UAY5cHT#;EoI*G%?7xH)Y|@qrOU_CBVE=woIvcuzN%}RwYGoLxVkLw^H|Ouj86e zZ+qVNGha47b1IbKO+u^yHk-O$i5b>u2!_Luf?99FF)@_2gw?KFMWX{@(s^X5f9`{kCVA|Hh1M`ndRl=?*=Z`>uU5*Mn~VUZ#*h5Dvs#xo$`P+C%d$tHOd}f8yFM9zA2ThspPenf z^1d4^u1ImMAZ5(=1N@A3R?gHMxAc^)U*~mJyQbjo2mZFd)X2nbMnrRo&kLd}hD1p% zXbGuvqPvvW7_ZJ>3* zH|^16e}0Mu5xou}FNQ|WtAD@RM_ve=(wgT6du>CQJ)FjY5iMj2 z)y7Nf&GE8DlpeaQOk#Lv1b&tr!VJcl6Z56=m@On5Xua%j?q!Qn?ML2$;^##_3CVj3 zZ4bj#7wQ(q4l(s=>3T6Lwb3mC7p<}y6;EoqgPoJfY?(b(tN!OO$IcJ}J9?Bg#(>$! zMw|PrP0ToZm$6Injzr=z(nr`hR@=Pok_&ma!>q0iH-3AK7XaYOwBV3#_C4`Y32n+? zRlA*LI7oaC?EaA=RfQZGA%Lb5vgK)`)?M_}9ch6IDw@Ci!RXzRo>n z9gY4@^XYg!SU_mHoXR{*UDcXy!tgB0BFb2?#<^I!AXAReoX|AAMsIIiZRG^!ey-0q z#w>Qh*uaE+C^Umw;j#HR&JyyGgHsbSwbcSq>N6Gruz4wV!& z%XZv#f3yU3_rM6Hyh|fe(|?P-^w;rJuiRLb#g?=FUR`PBa+Q5Ghqm z|MwRqH>rT??y5QHt*V7kh(B4J9=D&NutZfCq+@`6G+#x(!15@ANS7jckEKR2d?<~e zf=J%^0sfr{R$UyxOE8dd;6DKt7u6+xqU0HXn(~sC%`LJ2i^If^Is}ZHQ7#!@GFQ#z z8#{M2oqS1WbcU#^y4yNZ&WvUx0s{C~5tQ-9$m${IQ{r6hUi3*C++r0Z^hQ40GRQ*_ z%P*)16edP=gTu||;lbw;wt7*YdyP_cuRQU+YJS+}uT?tXn`+p0hH`H$+*A^T8*+3z zs*UmLLN5<9cS!^Vt4kHD_&_eIZK+{TH@75;!jCF~6u5G=c$HC*e(iOW~nj4I?U z&}L}J>Edh4L30e_?PuB%d*y04344-xk(MSXM-5$)cv0ZpGFrC$pXorDywZh3K&sY7 z_v1U*0r#D+E_2k}ufMnI^UT_6rY~PTCR_@Jn`vP;{03B1$}C$(3%vzox=q)l0HbRA#fgRSwSu|_HqyGmJEEV^C8<#yYVS(eZm=-M9NxRgvV`tV)CE ztT$Hi()$j$*#Q?o|4fGRIEuviyF!N@NzLgC^|7!EZ5l6^K!q1FtKIzCAWwrtk+~|7 zWQL0TZ&&h`xwn~Ehq;pLzkn=6l#-ai^7;$kQMJij%eolt0{y_c>{O-VZZww^ufieU zPEd`5-}c>;H8s3v)MfC(Ag! zWqC?pY6sgb?*tJK>%w{4(3UKwNWzPM$w?8p*iF>E*u}FIN!vfl_I`RZL{Em4+8cF* ze5&~c{PsudPx0?^HGRg@hoAREC|4wB%o@4R@HatvW!c}jSMeeZ#m8YYRf;Mp&k)qq ziGC1U+}c`*T2i&f%n_+XQ5!wbC8R#tIu`AVFc8SNVLfLz zL6k$jft+QaeK%db%-;n|!v(QCOFX7$z}%d%*E!MTr?ymzlm&tr>2zP<7gT{<`L!m; zldP64+q%x=A?JlVSWW`7h3r(MA;DYUn&r{PVZ*kb9?;Ykgm3vy832?&&@COjc?fSfPdG>JSDH*twoEHmnHnm`4 zYYEpFaO@#A5h>1l#L1dA+lO>A9E*W1BKDANt7N8gXc==S0p{B5pQDBuLAgz^Vc&>N z&U=EQ<3kZZ*8ZvdoK2gBl#jF*X!D-xG@+*h()pDMtVvcNTHTs%u|3WN&TD*Wt5)KG z9Hd=ucOTJC2xT8sbB1|Yq)Z_R>nM9m$LoUY{192#b9(H$QaGUHOJ(q6$?bthJS~Rx zoZ0C#5xM%2ZJzUHqS`%k+NxHe{~mo=CA0SR>C|(K0qpzo4VUe&DDn7jlkodlN5aNY zQ;mDwp;Eezz0)X@QPmN-t^RpN+?$AHOjl5Kn^u!_`?=lcna96La)2(ha)&Nj=Oe;t zUOp}F08B&$t0=hXxDH zYi*Q+oo*Rjrn%LcEtZo1tEadm^e)U>SsYuoJ}7J`aXoD`Sl_x*?k$k0;rhc+Ay=;i zMq2v_@^*}WSRmfKFet0P*j1iOzJFxwA>{99RKhSPKL#h`2$i2$TD^njj}g3*ykC** zY)orVK7%9&7u_4Wni*2>Yaj#0;g0TRDsS&2$hrHNSm6l`=&qe~q59{!kkp0q+E*=< z=T`IiG#OyD0bC^G#--1<=Z)g^KSstPOa?OpCj&f!{)+Zn=VZz{e&uOjd*RAS^L?a% z$J8^^`!&v?SM8Zp}dLI04bB158%0+eRpB*yOauuB0d9I?pdV?x=|jn=K`B&s$@K8F~SL9 zdcUT*wcjrDs`~C)Hfv5#jmq7fGWCB#BcbI*W^CT?Z8G`nbE4X*jyK-UHekYG8ArjR zsMoS1{e!FbGj!2Dll2U!a5xln7tJ{GWu-9h&J=NhGD^H&0{XHPGlw zU)`5FT}-yxd#CzszSwC3$Jf3+`TIJIW=PW0P{ zzT-+kYgO@W5tJsYJIn+rUbArdafb3Bg8XoRAB!(6ifWE#lT6TkYA3Md-FF*IxEB*l zOE_1>#jrhziEW6*E1|^IlpHea@%=*v;1fA4cugUA?JxM~pHF};8;<}j)!3wE5o9SA z_N1gwp%TDSEK+g4EGFL!0Jh43g7m(=b{0? zopeQ!e`8!xft{#W{3rsxJiqfi1e&%hmrr6lscQ<79ay8CVL8xU9u`Sd*Di8A_gzyd zxfMdt6K!noHeT8`JSIHWDT;cFK6E9Kx_dVR8M(ihL87$T2i&Jb%{_OUFnOe#>?a_| zonEWe+7g@6|4ElkkiwdtJ(CL%CrCAxIsV;jhx5eK+L9pe@Y^DO)7ZoS(BzHl$H1ql ziW`6k@!*bIcEOKa`Z?CkZ;=?5?oIA(ht`aD!_<9JZK&36{Oi&aCHMYE~Z?;L%PT_51;zrQ%avw zcx;*5z3aV5geVwRrKdGWn@|wpl2c$&lk$Wrp!8YzKyZ z`k&%@-hbOSul(2bbM5?)5JSRvx-@*ep5XVXd%{S|P6ISrARk)#LpiZ2@A%|G>bg?!)b!)FK4F=$K9x6ri5dA9x z&$%?y>4MVjquBe$sPd2a+9BoBj)LWO_QKSM)8u;+-yN$eQlyg?z;e?mt%vq@fKa{& z{yspKI5uPOJ{dHg1KR%Mqd?m@-#b~z-IO(Jl@0Rub&PMLeU2<>O->gf*tyld0id2sSctK%t6WjJy2FiApC^~QIOPm8aK<>9UU;za;j zvR(fmReCg<{KJl5ln?=}_zkd#nuyH^Wx@e2V3+`_mpYf9hBIg*!0!DqmYSA2+Tlk3 zZRXL+^waDV7vOuPTio_#Y%+@*fqPMf^i9*#y`F$11zTg3%Q2TAS0>WyrQq-Psd!~d z_lfY7iQIt=1~*Z^KX0viy74fGsf<9!t1Zv~bX@N(+|d#$1kaEK3Gd~l%#aQqoGK#E z0JCB<6yZ*;)3sdg#?L0Pub|L8mTmikM~92Vws}+xVX$-y;_HFWHEZhEVv-cP%N+X< zjNWSB(wHeS8$Ze(+2Sb*Hl0$~PP!F1m38CR&Uqj(siC#+=38pqkfq4%ssjU{v*}K> zC-2I2?VykLmUpf%!ezVa=S~jUj`e)@Pk-{016OcX8gaf`d}HoX&S_wjZ2i)I_9IB4 z&G#pl_wx;YA8Tjae>b#EJAWUi8erbH5U-Mg&r=^>G%WSza6DsO;W!j!!@xC}wnKTnAc42R9LXhL@1(nhe1(iHg^b6C z9MuEA&RXkldcxfVn5r{8q9kIvhOhoo_IF{Vy!Y|`&y0l?cNh*5`Ve4Ab9LYcfVYWv zGefw^Q@Sdz0z%q0*SQbn2|_+&g3&Q8N(VqgRGvG z6>PoK3Y=HoaMihGt#VK=-TLvfcvHIinyF315? zbnA%}L_Ponp8*`6{5cu6dex#+DQ^eAD+__lE4t_zAm5t!OZ$4|) zojspm3*Al-{Xqnv7ev?G1OkKGsnkXfpezuY=WodSIDE0U#;B+N*Z^KuupJp1@W4l+ zfO4&Jm61$vCLDyV^Jl{QOOiw>rcfUM!dV$b2IJq>pOPg}EE^y&l^Zp`+qSXPQ#+U^ zOP8{Awdnu_8_V*SNu7@4rjqv^S%l^-M;EILjT;XE3i0<0T#P88o?=LR0@^`cV4rR+ z>W}&bAic8Lc32JQyzB?K_cC|+z7xJ^zNK{hkm;17!8rPLzqtWLiRk@Kc!aj z;jZW(Gv7*DV^igz>G2!|QIie|;TEhw)YiQul*+XKB9oyXA~tG>x}pC$Qa8vIM>o3- zmOYHV^RQ~1=>S7BAK|~b(Op2m)7e;9`v&OkP%^mK zS)|#HOXHrc!aIFZeyHL;gu*XS?+tv6es`^+6S$9q`z&Tr9dmdl)56dH6o?5iVi5Z1 zL8l1JI{D!3a)^8**GFct1hF_H0F9boy4I}Apv18n>W+V+ z#QIllepv*oS?yTu6L^b=(skwNY>zR+d$*CJXWhwlwX5O3i!*U*FMJ!o=vp z@bvfs!>AU2mrM57^r@4!<{70hahdhb40pwZ;vy z2-4!JYMx%CeKO+`B18PIRA}%VPpmi5SH{OX7;O{bSyzFJjW?wMO}a;XvyEsYoT9(B zufpa;uQAJ-JzU0Z*~SOHOBaF$Y`k`~wSeK1#;gjN0=7?d9(XIHPT&mMqb+YLu>HPu z1lSSNAt-o8qq^wNYCR$XQT(+0&1BZbkd%xd!TltWw zl$~lOe=`o#dD{WKPpZCO`^U*NYtnmoq8f5fE79jm$|&qvEU{W2kfK4%J* z{MNsW+~-CL2N<2KjU1vLFO*{n$w{vIfJtYka;HSPe^uD-`Rb)8!h=5UOE*i{H8)g1 zR^o<~=rlaJ?!SYf1K2?|U|@L)2zN%WUI09zzHfOiornPRn3j-_Z-SkP-InBR2S1%< zp@%Go?^*){vPKyKUuo2Cl#0_uy7VunS&YKqqZu0KP3?moKPF1}M-##(-W)hLQCSs~ zwz}^J3V3evxwyF1zx8MK%y^1>DU&>GdN{Y?TL`|+2%fDV>WDg<6|mk73H$}G=vDSO z>6d1_&G&D4K-|Js*o%mI(vHx*c>+8uyh~s2fz}>w)C1lA`_2=en|vl<^!@#=<4rA^ zIfXv@i#iWm`I6}NBS;Nnb@Qo(B8D`c`z9Xd?Ye$_^ls)yOWq59kFu=XrxP$nhWsY> z+61jnpXD@Q*P~7skyTTjM$2^^U2-2;-?!!@0;r=v6KlUJCD|nATWPs&EKw9S9O)l2 z_U2{3Vid)lf1$)2lkZ0~;yc;;HP|UfjuB_~maqFv$??9w0Zaqx+q>B}CgHq43BH>= zZuC9-I`?0LEIjTf;9hQ(_fsbI`|G`QZo{RW)BpvvW>PBD6iSH$UyKOI0;-g1G9G`g zx*fZxE_I;y7+>1NzZSl0&c}5@fj!*D>!X{qLO$t^i`!Kb5NHLrj%QEHe0kMdz!`-#HMZJ6m+}P)O9(! zPPATf3V&qU29R-dCes^~mO`*R`%#@QUaz#!r52#*Ha-yBDSTNefeyJ7Sc<}3k-XRR zT`Gy+c_sbV$l65Jc2s*ufKZTm~`?wk|3d zErgblJXSz#=z0*n_>;z;*WQyrw3aimb;}T%##1n1EXf2RXq=Uz(;!&8m2xWzIC4M{ ziqt)?bh6t1ffR5?iWEfj5x)*?IQCBQnkaiCykr*~%=it+LzfF8{mu!6#Qq8I1GQa_ z9or*ZjqcQ648beh&V+5}l5mT0=7HtAxB%MnWp4Ngu2dBjjrz-GOa&+sjGXGf(Z2s~ z^ORPco~-p>kN%z!eR4ytob!-i;r(+}w+P zWyF=l=2R?+lQ7GA&)k+! zsXDyU2z{0~D*UphBri;`3(luQ=dT1z8?{M=cYNMug+ue-&(u%f$Uh$tu*;Va=4ciM z#KN*Oel@@&!MKO5_KMbx*^e= zjcEsGC{5-;wsz1sb`B>|1#{HFegX$(xs%{534CjqpNJ7Jb>7^+1)X+bf1oNu3tC8L zxGUxIUqg|qbjZ^_ZjJf(f5jId*kQ02=;_TTP$K?Bb8+0oBB3$FNGItzddZozX7wLE z4ieS=*g0caCH!~3;Xu^nVAE^pucR!F{GNZPk%=nc?p-p_J_V<;a9jaEAu(F<#~_|0 zk~f5nT4}~$W7sU-`83G@84j^el`nsl5g6v z7wpOkM^4gRNJ}QHuh#cj7Fryd&l)=#TRvi7m6T7NXZ8YoIfuJQ;^ig4(>V$_1KQlh zEyU)`rsrE!mrh9Qo65N=-t=@sYpGh`{t6AWZbG###nI|mA|deM-xR#|68ORWL&wICmMJX*h%cUi_fkHKG= z!Krmb_2Q?EeQFpuV?{wF`nPf>HgGsw2;{Q8es?==F^@HCQ6t}k(pn=0|Eg3eDwXiP z8xvWD5k1#WBMvUohnhLo`>}4H(>@Arts(e5kWGD4&-%)Ri^*eYgpZv^kYEPIi&jbl z)sck>Ttbw8u>*Ow>Bj&DP1%giCN#$WL{xRTx1x?rS7he%q9TjJ_( zJezb+f}L7l(1LkZL#RIM1Mg|;j>|kJ2n3m3m#3rf#K?_w|Ga$^B5ubl&9upWY}4^e zly7YP6EnRHw=rv;|DN&r^gs3y>e8cz?T<^^7`mx2y-xMM_tS{3^*}mOmbyq=Op(y? zvBseO(i-c}Hb2wVuvL8ve=9_1C^V6FQA{Wl<0h%CW|v(0RTivoa8ioP5x-nI7hK}_ z>fg~F5FZW${aE83!rNaXdUOLwIjFu-n#W0FLGT#VN#BnD zJ`5LpeA|B?SpOrS;evIL6MeG+D9=Ge#xwbhQmy7eYwI+ema&5YjFE>M_%XFFLb(|&nM&Bjh zrg1V9x9Nigw%l6Zj;~@OP|Ey=#U3VoM|!bujD!3Fd_=k3grZ5Hvj^U5`V<8D_rAIL zyP#~>X?L2SPwcBz8(Tvtc@D^(=qcjAI+%&#r7!0H>7HRn|K^HzWm&zFPT4)TNyKLm zYFbGOMzZe9Fx(2QFbA$wUv&HA2e&I&+VWK1EK$kB!zvuZ^lMvHS zDQ%G?jf1hQQX9VRwWvqLN~hi?&=#{6R^$>)zXtgrCqDme%~ z6{6+Rx*AxD!DTe7!^W3Np|P>D5R%h)87HoZ8BkM(T{TX^87LiJn- zf*LvKW`{?7$6JBgiR9CjG>|Ys*k_l;r;S8}waNp9+dMbo^)?4Zi#|cA0b+r^B7yT$ zhC7=yL|XO>m$e=sFEm`faXTWjzD;6hVhGp!Um-R9EpWziKXX;EdaUI@p*fm#A4GYg z39E_&$s-czAl4n-4W{;DdV_YK^bs!vyPS6u+vbw)&IcllF&Xs}PgOw@qP4=D?SeGx zYN)*`UAZqvf8{G8%i zDV#ypuKat*u9kJiYU?3Ul4N~W3>@0bCilXix8yE~Do}Klz=oGP%z3gY`4bX_ARH2e ze<$fAI$p8ew*J3$G9sE4NAfUmjS#$YD2{6n|FUcZ(Z~ZYTL0KYn;g9dE#VB1Vw*Mn z+f%9c9s0=ktCRGfZ$qNjQ#^!8BHvr`aE!<|o!=XGSxc zCKP7BW=o+_*(&FAB@*7t7q1krDr7P)8UOAt``)WK8YlYy$oi|OI=f&A6a@mo-5r8U z(BQCeS-87PaCe8`7Tn$4gS)#s1a}GUdKUlQ`;KwXdF6#QzS*;9cXf4@Y_5uW``#h# z)7Vdxm1YlG!fIbASi-<;9r9fG_%+9j?p?-RNo>TZ&_Da+&rUeyoq>f?q>u|_xYl281DI5;J}?C7Ay_|Z5X?pyQuP+?BGk9o z{*+IjZ!(T@^FBXF>G8W~^mcCHJ)>VB=hkidV7;ibi(rSlM*$(_@ppu#8lmu%>> zaQi1P%YkT(59N1V&Zk=M{NN4cF^lSTUl2s$1~{gAD8;ENEW=d8itVrPM6;C#11ao7 z?kxcXdftfe{f2)}@NH42wM_%RadssQ3xhygw;gIUr}6KFvr{a73D;FvfCv(P$;Bqi z$L`JB{-&Qd3NU)|{d=R%@o2;h)u~_cOq&;H8$#Pk^DAz z&c-IIGwqr#cp}pEFM|?4e6G|w2}hR>(&~aI_w|T(?bTRu9Tzl^xrnPzqYF8n#W{kA z%HbPy;9%HF5Z7e>3*kZbtQs(UJ7D$dw;2ToiWao6vUxu|~UZB-> z^-kB4&WW$(=sCzYq<4HMtMTt?fiE0yWZR$0{)p?OCdrI~{Nnc@WjM@j2}->m8V&&} zxlQ%&d`Tp!vS0l{anPIsgRtPn{02}(2BirFRJ#azphVUdL(6%J2|Su@+X?xyOH}S* z`vP@!$dsyhwZlV6tW3m(`;_P3qBUsJFC*UU@8_UN4?Xxw+vu6Qh|aplY32DOXax9i zAB=AkQ*O%nHO6%WePVDmn0HX}{xKKXTjHJ$Swt3yX|^8&J&cwAe_ViV2{Nf0$y%7^ z1aYO~Gcvw-c?!=nSTPgqQt2$*p@N?vPo!ZTF*^ESys#vyMl16Kc$$E9IWG?f)?=A@ z^~e+-b}Ft8;3!wJ`IAJGd{oBip_!G5H)yxg_3dt{Z?w>i=)>nSfcS4&SAo}6@*Cw~ zgDo{|7mIp9MEjti83}y>BF+5_N%L_M^c4J>kd^_svIVzI$Is*|<}SeNHgdj)j93dd z9v(*RJQvh+vbm+ymw}ONsrdD;e)B8@6 zUSo{Ga>GQ%f_{xO5+)gtC)-HM$X19AxdLpjn<&W%yWk;^*)7Y-G!ttdMwAeK8@ zIoeN)yGFo3v4~F_@IwRcZ;G5S5YG)fVi%0(wXe?P=#F|}+r*>>wF*#PNgh6CWp%sO zh9dAys+P&SRwqg)>e}%=uFQHwZ^s|xsU?T2-b_PHp$!ktEu{)Y8XAa&9YFz&%pgz8 zis`^>_O-eG(YO-~nyT0CQQ0eLvbJ_h(yx;25W|vogY(pB*Sg~!hW#{=D@Dy9uO9tg zRg^wVuM9IrbH7%SG`wsNB+|; z=dTUMg7v-xZ^n#S&Ql&cn+i{zeRM&}qZ~qd?qwN_6W4W<^{WMxj;tn!M5IIb$V0PQ zKbBO!M>oXLKQrQwQIC6KQSe}SyLK-|`M*UjmUzuT10RqL^EdgIHB(-ob+|aq${)V$ zKo_5-N5lm;zH|0R`&K+3sDu`-D}5U>On*q#$M=5Q?}E3t@h>tU@TTuf`JdbY(rAGM z9k**gYW^Sz6HEpLqywuC$IwWTF%%0pFgX*-W@ugAQ!Qs6ev^E2F%S&sdgzi=2+Yb- zmGy~Z1+sA=1NWsh8q$?6;e?i#kYMsa|O_h4XnqL(KnhV$(`Jid<^EnZdG} z|6(}6+K5BPvt<<)?);;`LWr4-@UYHX?h^YkVLYqS6 zAa*e`kd%g9$nS4aGAlUl-~Iw}jWBp9xuECA`#D9Dwy_{hQG?$rUXuUBgX1u+$`B;?G`Oi%@me*gQrB+x5L`O;7qvqSZvXb6!@!p&uDKGkMYii8P%!RK_ZRY#mv6K0 zIgdf^u9oC|kn@i4$1^EIP8Y=GEo-^|dj2Ehc&M(>c+2F#hKT8~XA$T~b4U$Fto3Bm z_2z<{vtO)lML8kI+gIGGDA5wFlK7Q2yKH>O*$%&UUQ1gAnXVINs+Z?JmwE{WunG+c z2lvI%^F2>E%kfNuc!H*)h-r#l%VSo)ox(m!fe&*$3-8Vo0%sb+$~Eb_x24Swxs4>? zX|$b=G5Ou(=RhC#&qW1$TDBe~dWwy}MeYsGWNb8Kt?(wIDIuud-}ELe$kO8l}Q_K&m9$!03!hb<9HPkl(?bz4x8n#-=V^8N(SI%w)wFYJ@asen(+?*SPnB zT=+e2!|JH92i%lCD{NOU(M%i0>JzG>FxpinM;=0vpcFrdv?>gR7fu?yrIV5eb-X%;!<8Yt1{9^6(@uq6D!p$u9oWbO*z3MRd9nx&0mj@k-WJnY1Vw#Siv3t@@ZKJ39-$Y;8gR-xdMi0B%%d+j zC*la?&T3tVA6N|qzM6^Vf+VU`8OFiNio|HSezWo>1e)wgL+~R=`u#4r#EjK(VI!4;S_=4sY~0P`ZFw~^VoHi8 zK5>BR#7i*BM#H}QCJ}v4^Lqai4nlda@08$)}&{>)L9 zyb4mj1d+BhlnccjAcg^J;S7SfJ#0Hz_KySxW39x!0ZFQ{kU=u{%JttUbXNoquV2gW2%;dn)dMr zx67Z>rudmDId?56i_*^PXEcNUx7X#igTxzDzb(YL zbAsN(G&UCq54yY|vLClt5Ew*_%;{J+)^X0uTr*W#;yIIfnKXLmRpkl-9YRjSzwEl* z<^l`A1S}7HVTVn$S(jdLe^g7{|M2bvuWmh|W!1?*sn?q0?rx1VyXE{--a#rWJCn$I z`@bn$0R@z@sgGpVK2!D)47q8^_^6UlwflsnybkDDwkVe~jN!53SOgq&h~AS8uQ+_@ zkVsPfZEg#Dm=uQyWFx)E2k69QwCU*$$Mb@_TSzz~SaaGQ=ZW1Kh#m(V)MpD>Y!}n! z`%(z?8)J{x_K;pgCu@wz#yg16zmd}@Ztkmy5f$_g2PjJh82^b^pxix!vU6E+Gt9(} z!;hZwT0S-|RmesW^oG@HsvWI~x7L zyxB6_eArt6^uxve zVEP54amfcU^`jyd7@W`MNdD&8wYqnS7{?bIe_mBNmGM%R)K}~n1;LzO1u@8y&`$lK zi2rlX&p083+0L5-#5zFHu*?Nn01hN|xUX%TdD`r3r)$GAS!eN8>x*C(URePdvB>M9 zsLTc%V;ej0$Wo4k{gUFVmPdcOZQ*n03-Jou9&yQ&J7k-Gq+ST)o#U3T)lvQAp5966 zJ)=Rs_7=_Kt)sk=X%C9&CZV|p#7#}Denp2+WQ#Ug_kLLSu@`cnSZ`2)+lKMQ5G(B8 zV>~^w5O3ntY`GQJwfo_n2O4CYoT3e6JX!i9+wE+|49D{8egw}ViX3x|;?u<>eK+oH zpb(7e%2VtKLWZaoj)EpvP+Mv4CtT3t{(DxP*-OQKkkMVFn-}ywNMKvl>`XJ)2}?Gt zL`g%g#NSfD7i=#45c@m5_r0;Zec9$P3-&l_21eFu#Ot^ca`>mll3+!O;0gt_x;4#a zz|FK-_VH7CbsV9_$9Kw3Lo{XOvJR`0s{x<=-OLLws^^rpd>5=#xG`bR%U8BQU?o*g zNR+A?Ihi5zEx{zx>U(rh3ah0T*K<>$ulBm@ruTcY{thpwcP7(^!rJyS7&Tq^-t2K% zGOn0p3r-xp|L%Y4Z0V#I1n182%NO?`vEm&WL{~7D-|S`Q-Ef+dp#%Ww1Z?yr3#nI3 z-)bws4jFw0^FSwx135_zI^ZmYp{P|*UbnM=p+DbpbUdrjRmD07YV-`j9G>NK5CCWG z4A8#PH2n}3BQ=2WrK;}EG?y610%JMBtn>WczL{aKVtbNV_&{6FW#)P9&Wv8yEijv2 zg-ld)yB*zb7rsjL7^k*epZX`eab@&y|H`Lqmae3ZRKX{1GmKId(%&cYn^CN`_aVQw7kE1$uhr_D$&h_X!tJc(#*&HKX{0Uh(u@EYrrw zBJ#67Fmm`C4-hd;CgC;=*6Ai5TXzrnhiBU(HXbIagH&SA&GMV5!IeH^S%p5qkXgWLW`ukLe5GQBd#qf{KO?>`7YnB22x1A*6d z+I(8BiL6C4PJy#Cswkg+qmHgfX>_SZHPvDWx|W=}&ds{<6q2M?sMV`$BP}bC`P3xjOElv?0Fl1*@rC3D!+2#+=v*@t1dt`lf@x8rIl`f#A=e zBR)|E05m7~j2=)omy0L&^$^$OGn9}a61S-(@H5tlsoVuhM$ljF3OqheT(b$e$p)qH z|2nRfk#NLI4fpXs_8`-m7W?)0RklBqV}1_eV5A224>?KJSI_*^=Zk%At7lcFm{%qa zb$!>a=VLl}O8_ZQBI$&7q5M{|jd$iIU40kRFwmhQC;*jR8cfO?D3A zL1+N4A8{G8`nKJ6bl*P9J;dC?@>t7o{_4=5?5lAqQ`oIfhzf>hIszzcn}!?loT-A=Vv$yqffUR z%izNrpL%}fOTBv~*~BiYN$lBkPPt2A9LvER?~?Z7;JS_jL`|x5RXN~i6Z!7$Y z+=5i|UJ;yq!1hphO=tV$6T+q_og@B5@cMY!JcO7dN9b(HCmm`rMqBs&cq4wl45^o! zPL8laH1M7av(?>PT5I-2K|Yr|3czXbQ5;zm*{HGU?PXPCgcT=8|Rw%Vlo^5ieekHPT{o7q&QeaGau z@l?$(4Klf9X~fVAjt2#yAQHH71J{pN(xQ{N3(F zf8CwXbhM&0Yasy6!Il!ye*2w>RP|UAZlHR=GTo?THOV)h|MK`^LZh9)8{{q*|I1@6 z3DHEEWpjk+s=%c}o+ZrWX)GW_>pI!L9~lav2Q~OBk0Ui~o^im)6+~>ERF0!xEYHrb zYwWVv^ny+k+e>7iD~hi|n6E1&@zfkz;Grbmz4GK8z&G5!<&Q zgh_aj4$*NGF=enW#%J1>Zwu_zr%HMVZ;oK<0>!Wb9dFJZG2w`P(Q@r3|GXDRe!UM~ zFRGilB~4B-K9Q*&9ULaUykrSv)x7HwJM^q7A7|z#>I*6v|KGTskE3=QmthT$Pdea| z$EFk2!Wo_cC?!UU-}FUdm9nkobi#+(kQ>PGPgdtSDkLt73fA>T2C#-cymsd2TCU}i z4)b?^J$~MwZ zPgUeDJ-iUdJNKJt|9>+&31|=;*z;d2kQ^egPIs8aX=QYtvc5Tn%lo}V+{@6Wfh;>g z`anRJ?aIfIs~lkVqoAFJ=jtwYvzpD&RAhzF`av zEsJ;^V;^XZAYyNg^1EwsQuggDE(98H*@3AGYG)u~_)I?e9NHI;1NmMI;kwJ@R}?mF zz9Bt_v42m=fCXPSF-b|iAgt~_=ozZ5P%%}vZ9EE0Fo_#8c;9=Ec0xKx-^3oh4+fp2 zE*Cgru~bRSY;DyISjs2$yRanas2FE?>(XG#ndww)S#Q1(kDx7m+eM0SlWnxUu$y1s z9F?fK70v5RJE`*EUbilcvg`Ltp&F4-GFgB4y4vw^=+SF4HKl2M^RnLOD~74AXnOKh zT%2&hsE5^~+97$FhSB)~cIr9Q^=p3K%fH^2?s<0V zqx`yBJW)&`dh@V4En1WC;w|7w_f4tppcDeCWE;O9)jCxv1W(P#EzpuC!VVy&-+?Fc zbMn8d2^!78`@7Q&u3Rsf@qpmC;%EVf-J|XI<~oyyTQ^+Bi+Z47$C`J6v`t&Qr{#_; zcUUT)p8JIg1BDb-q^s~mAlm3xftHXBCa13Fg=!&ZQO;7)d-}8AUVPZNM)6!s{oq(r zksovXZ}IizS@k}kcO@ETF7Tb1RUbm!zkR5`{r716Zki|c=ftGo zE0n``4LEQ$$Er{bFKrP;g7#i2C&|QEy;hl=?#!6t9S~6#({e+8sjz+Sw#P`9jKl z(Mzj4BT=KMJj%q$;?As`47Aq-aEI;2ucL*cCP|zMGpN5)k7;kNNFH4`F%3=4-YEgD z#(amr_5d@M~+dB7wtyDI&7~LdUCrUc1vYhl-p!fUg#p5 ztAA;=P@Y{JYDkenbu7hND6?-6SH8HE=JZG)0O2s8l8hQM*djy!lhPr$b&XP@-MVSo zX71wK-uYcMd&AK(tFb@aamCT<>C4EEnM$&j{;XbFR~f)7%>eC$#IL=unrQDcBiD83 zWT}$YPmhvoto@kc*y!y#JmP<4FONg~zb%YO6fZh1ylwZG%@ph2m`WkPPI8UHKmVN) zFO4>yq|ksRYD@-{G#xqKOmK)319bw+foFV}zB7xlX4?4pZZwU0&6Fp3UD^+zbuJjs zk$k+(w{us$q^^ydtcPX!((la>0}NZj@kH5#;X#{Y-hAwfG3ST-yOkHM1LAy>a`t?{ zc7F=!N({80Gq^|=Xtov*ozW*@P#<2(zs=1R4}b6BeL%4s7c{X+?mS74>!n@Hd)V0T z);-$_K8QYX=t_Y(`SbBLqi{YD2PjVRo#E;l5Tk5KBSc12BVWbTOnH%x6P||2OPo;Y z98aM9e(R*0+pF98o+zL67kxa-<_3@oQ3{(tlqZ)FGQd z9)O?d+)o~{gYH{fs2|VP0Ag*LWF_{9Fb4_8TMOf+Rmz%8Z^X+TqKu17Cs-~k9UQu+ z3sa;|YoOl*_8n*kv241Y9^aIg**d-0$LgH=iCmURFGt6R25uMSSdyS1gnCyyb9vVY zpHfEq-}79{bqPaP_E_TyW6HEYfZ1Tm&q-x4MWi;Nf>OmO8PSuk6WUI9%+bB7=mUfO zv3w7G-2ZC+Ds0un=vc|ztEFxH?^JZLRu|bRP_M`WV)1&xUY3hx(%53>_E@;$nG3Ra zm3#91)#O@rDP-*5=HDs2I$c{d;Y;4*H?)tR4&$gC&%ASEDK88O7I1Xq3dtFSi{Z|&;T)a8bJ`0IbQu(Ht z7E#^5Du+hvvEpN`sa5G0qLVp*7VYctI+;Fg2R0c8*DRj|SNTq-pP~qIzXLa}_tfsq zaLKR=b0W<9K#t-4* zl(07m!rlpTbTYH1QJB8wB>)*0xa?*1$DwgBU1oI1Q676i@Va~T^!Hm$I_~u)9}OJ0{%+5DrIG15Gv>hbi{vh z9^Y`BPRS0KUV?0WcKU^Hvma;L39xy0(;VdQrw6=g$6f-JHqP22>>4PA;4t^BqV;I~ zSg|u$8ChDs;G_i z){t)bDAP%k{7cY@WB?!%zwagK)O!P&Q4%^)JS07G?=}l%${isVrZZYVBjF z*8r4Q%jr(-rzB*y^_nP)+pg1QiWG5IjLz~a3k9oh>3#Wr3(WTJ2dJJ%aU^5KF)SS6 z8m{{)p8xs29rT?|9-BI~Ar5~J*7Zq|6Y3DA0L8kz$pYWH52m1Q)LgyA1{H3>mlTDK zo5cGT@6RP^s)7RzV%zso29>^(t}%Lg&0%qHmeZ$U|37UHRq4%@d{$$7G^ z3|SY!PU+uKiAGL#t+1%WEtm7arkMqTlK=r{tqDx5qkYA}?@yxS)=4y(a~A6#LOE+2 zo(#~UAJ6K9E=FVbw~LNr48)#GS2>ANT;GUgu+FEM_)HUq>2IU67J$zc??zI#acRGS zjL8K)Xj2^_BsoQ=83$}O99MjG&$N%av;DS zoQvV->Z&oD=eKG5BZ$}~gC_ID^+@ic77c&#y7aW1K z{dp%|;5wI)usXE@X|*07o`dPZv0R~Eu;NY6DKq81Ix4m=cY3G5+v<@9!OnaIVG)37 zrbx(9J;1e6QFlyx9E7&4u$t`#{ZMJ_;-nCkf8EccX`fmODRh>-|k6B&7U1e!#D z;B~ZC`mmTmDxR}oZtM8y$WCPZZ)H6B?X$5Jt&aLEu4;r~n&Z!#&VGzdvEf9KfM;foHX5TSemmk9LEUmw`0-fjvJU(>(;qBDz#m6`eB?Rk~SDF6n zP+Y+m^Y@cKaPln`p{F7Xw$q?iI#SQaSEe%P(?^VgL(8DoS|wHy@Vt zRtVvpl`WsH&2D zVrXm>l1ZK3)+|w;ltI2@mKlY|bz0wEMNLZ(-DB0hka6cnpY;WkZV`+0IIc{_=1T^6 zA1O1muA+Cumulk|{)_^0G`6QgM9czfG(B?>!g$Kuzplywatf!A27IoKX@%IE8(dY; zYi=*plyrBMSX$<5HQjh~O3&^*X>%O>?JP3N-IogJGA4PnRpJjOgIFo7Lj*cT}1jG6jgSc4RdfH(4nq2831_8%zt)qhzpX;uVNs=Oa zTIRLD_c|E9Y(~UewJR{jQF=No-;=#^bc0$0?gi&51?$wonUA;>WBXQ5$0RgEN`I={ zQ}zBJ;`-}TYeCJunsyPuFUFqwv};dEcovyEcAQ{b8hB_91=6HgAC4cfbt$EhX1Qwy z@|!DW78r2n3ZHPO^Cd6BI8B2V3#0#u{A@oP*Ps};)UbL%C=22k6T)-Y>6K|+pfyM; z8OBC`@&f&DSdDBY;pR@3Ry>`;10U7bM$2$A4}g?RlF|{IBZmq3h!fq=Ufoa3$w`qD1`hI5c*8 zn|dqoxq;v3+If?i{eD{vlQxP-^gJB`xJjLA-wCI?6`&mPs(TpzcPK?8 z4IUp+r^RI10cp`B6Tcmax8H;IkTpU+e{uHf9u+^xY{m1;hF zq820ve=O&bEAE_} z;Wu0`NTVljdSgyYK)O@td4>4(1jSbp2VN?VfJZ>OJnkCWk`UYg@B-OsHUNzIfQNfe z51*UaGfVNGzi_d<^Id@D>ZfjZf5!l5vyQ`LP#ybIDQ`&pQ(7jJ4jOSGHc&84 z^pp92*jTa^{rr#mF1Qu=$z=)z&))uQt_i-?Y}+(%{upv#J3s4s0CmKmXimm&2Q8Bg zG?XT!`u?-jiy!Vdma+9%DA!FqYw}2f+;ABCuJ=5fYzK$tx0mEFyac)h(O!FG@vUu2 zjPA$OPmCa_V$TtpafJK>)^1YkFkH30Kc5bK2@RK-eqtW%1K)+7zddAp#AYL4^(4VuZO2uIE98Xd zRNw9XCWI3KPd2W5g`A3S+pa(Y3}chlT7Cy9nmmr10*vyLrX_Drwn6*3+&G)pNlh`u zDhgJ(X_RnWSj;gJN-f0)@Y^~sIGL$nN#l&M0cv?v)6>wYX47E5-M*NYh{=Srk$rrM z1}&n`$Bnv4lB*MEfEW&CP@Lj=a&Fmp&&4W><;{cBy+l(c9eI(DhkCT7Er(g2)Kgss z&8@y|9{Us5ZsS*1BsW*Br&WDEnwX41YhT2%vd4Eeo<>9d2Nxb(k@a_|WUi=nLvv^ekF}ItQ&T&jWBiV{1 z2LH4`-8o+7Zh)^TOGZfGxQy~@8}k@^eA^QU3L-r8|SfmgQ;Mp#}y zJ|S7ud}W*0+j7Q{8z>TS8YQSa;;EJg1QgN3L==a}r}~ZOwc?6v-kAX|Dmf7Q>=p4J z!;Ud9pN0mdw4x*IxUk6R_o>o1MV1ZE#Pz&KH zcSG8=#VDcC_Xu@9Z2JxB86chV&^=9x3q?e1VdH>n0WRL?z7Whf?pFszHkQ>?NTirE-4e+wtwtbeh&uKSpoIIY0Bzp5jc@h$ z&JUV7RWox1lPw-`hgGl>V?Pq|zDE^tDS~0b!^H|SLu5ewQ0E$Fq?3N#NAr4p0r$WQ zudPu&x%&x7D_B`D1K>U2ETMPUSCRHdvw8=5z%X)$hVYy>_ZchnbqzMSXdu_?lJXGE zcdg4@*;?$Z_+hyeO^LH20d~IM#QF(0Qx?n#dyKW@l|bYS(n7WF`KZmcKQta~igTmb zH8Nexwg+oIgB%&R^Cb~Tj7f0qc03Se`nJp)Mm*4XE2(zC>!V|4S*0xbY9$X}zRlMY z-5Oz~=k`}L`2~8|r8+d;5WNT1FVrDJ~MBlGh&3*(18TY=*Q-PM0?>6RHU^-_5p}>ST5&?~8n26csvM_?@Nl4aLQ@TtYqx+_UgQxf?-MO8DbR|2vPP5v z5)rbzFJ2F_1kY5;ex|~VGqYq#IBT*BvSK!chybWIe;a7JHly@cgct^@o93FM4ey^( z;;KD`>repsTzD3Wevwpfw}y-zJWmVR6_`tix60qquKUSlHO#aCQijsxTbBMI-ZEP< zW3T=^3~h%{XwW-;g~uI`|8FLKG*3Bvep&?K@yH@i!oPhZw3JkD>Hs?hKGu{{$tS2W7^aXXTSBzX(0~3n3=xn=WjaK7c!3K@Nv=^q%4B zcVR$#nvu2~LQnc4F@rEC94Uf?%Sf1eIPMZ^t+dy>ioSU^J@l3BuiSQ&t_v>WsFV*o zdhM^Nct?=!D=KU@?&N8X%qJmqwL(YwOuxoH^efQV^RE&P?B*nUaI=1fu-@X7%=Y#s zUjCVnQ6{53c^PPhWEPA&#sxRg6YC#$B2Z;t6`w+wH&q%vH229Yn0vsdi|t)u$^CfOEaK4#P}g{Hr`82j*ys;qt)%Bs94m%s(*PZ7Mb~C zvr_(x=JF_md@kSd5hB&g;b1tQUco;uemBvS=It0XA^(E9vS-c%S8fbH8H;4W+ed*4 zXUI^SNg1jDy5kH z3I@G#&*C8e0Xc=U+HHU?C6cDGAP21iIrJqk35jh6|6zs0luuCF%7|~K>(M@xSlFm~ z+6xwKqxz2NecuMIoWI#O071)xi5j}&&TF2v3~Fiztv1kp^`2;P%QiH|0!JB}bf)@1 z(E=@glp-hCaiqH^&)T-x8MFK-*X>#Vm)oe}4nAph?v|@~%Qc$y%i%cX&ooL8rDYgOqgSzjO`M ziCf4_i1t)B#y<)<*DHKM%hvB8xqy1N!$%Nz0#?t;yg}8}o~i0rX)z1Dx#~>67=)bL z?WmJ;%MJ5AW#fy-n!S2J&C`jd&;MmB7xd4KhB?Okg-E*b8Kiw#Yu}HUBJ?7AfD4y>qOw~ne@itPWi5E zi78g4 leNe+DK;sR>>xF(-&Noik9tlOjgG8enkwc0bv!-d>nHE4@#}RdxH?B^t z$TGhV&IwTX`umaZnL6GTDK3J9v>yHn%#PtFM93;SRhUXV2%6gmREb2`#hC4BTdc8= zMJkM!z(HEBVCERI#S>zd(2mv1@7s%$I5UVBt4xj_kS7%ahQqOWsInBAZZ!Oxx< z1Dg5{p(vBghiI(MvAGI$O+NvIS_$+`co)v+B~&o?zrn7|e(1(lNzZA5%=|YD3c1q0 z^(u$&*4w0PWiVAG1C=v54(su zrq=((e~i29>id)?>g}^Y88XK&j#>JG%#9%;<&|bjYyv@!P6~;}B}4&nGN-b*=5U(_ zn*aCMh|QS&Pc3Htxp-|(%D?-`s}>dM{^w>hz1}(Yx2`g0mS3YPpA*78sDCXW&y8cM z8u-572S3l7BN^;xEs5s*7C)tm%`-_pMMZBb51FSU6lbg{~~IveFg6)bK^BkXW>~5LGG6PWq-m>=~F;9-~dYBKyo(qOwHioj1vwYi7zb3EoQ>TG}6=?`cbvHb@C#sM#J! zs$E5EcVj_MePaP>&^FF+sRa&Qaxw%OIjo8b;UBin-{>axE0$*epl3{gM}vJTX)hMg ziMm9}dYETwrjVs4JBVds?ZSG7XUgh@+NEUas>?Flnf35yl54RoKLsANq14%>4rlZx z;miV~I1y9nN zKD#|H;F&$-A?lHT%SAg!mKeVch3fo<hvT3h_q2!a~_2 z05Bw1p$r)ZBwGdED&IBkBZgPTbjXL1(hq2J#yv=8#fwtG6aXQO8ObvnBz^YF5P1}7 z+Om1SoR3&){75QWRfSM3Q3Zz>sbdjY$TnUU4SD1~=1W`NE!W=7*C`BDZggwJBk5nB z>{5I)4mOycza%uaOE@;h-tqUn`9a}&Nh7<0BopmI>2y3^e6lNPOD4+V1Jdd2IT#MH z#)Vg#6u3f0yl0`!t9kq;Qh#i$pR}>VdDpOWxuN1 z={K-0$A(dI{*XkBUvFd+STTU}l7cp1(v(Y>>HiDj#ROlo$~nhj4thYW4HNHreDgUH z2KWBSZ&U*!}y?r;J8@FW{_6Zqu78S7jInO}Ax8~;mypBRf_ z>f6$2r*hS}RX9A1qwBjc4be6Cyw_NPFhT>3ZL0=BU29RUKg)}k^lJ&J*x=LF&6Ody zWd+gyXOyo`2SZL#-p(9m2^f7dUTvm=CF%sS05@EyL|4k%P2bK05?X6S zt0I{DLuTVw(eOot_od)SIZKj91@(d&N|=a|BH@jBm2; ze%~g0_T1L!P?1SsT*u)2?T_T%`Dc2rpIwn_SEIMooZ)F`{M)YnJ}l>kG0Dzunq^fi z-A>rADTe+pioraW@_#V9D(S4t#uJEJB$}Uj}#P%F0kg8SF@*mZe z>mTzGzO6})Vz9UWMVd8>-<#R~gyuC*7lW;qLqZ$MInU0!Vy{X}xPE8BYD~ywEC0th6z`-etf4^P{dKL+D!YF#j#f4{dOV6~jGE zZJ9jA37>H(Wds9aKP8=E#&wFqDOldb$Mael8%l3N%-4`Jak7OBd@Oi@6N z*SIr974F^CsOZsW$N$ER*l?iAg)yORX!#Sa zXM;QeXkk$`#FLi9jUMX)0F4R?16KW;9t7a)tSE#d?bEo&^z8Qv5rBi)hIrUf zYz@~a!&T0>Zdi5#vZ}UKdK_hYwyX;&QM2%?K65{9axNDnjv>6tHsSB8Yfi)1j#=e) zb~MPuU8BMxf+59p710QyWjbx6>MbYW6a!`foDklZAZIixhz-=Fz=HBiRLtjU1(uN| z+>26~cO$~)GuqIc+%pu?R5Sgd504?bI-uEhiv0bSGbR<30DVEwUb>SN{||d#{g&0%tu3K+cXuNxozflB(k0T} zE#2MS4Fb|2NOyO4NJ+PR>rwan?tRX=zQ17q0$dl*v(}trj5+4WdjPgCTnacp+o&f$ zZU&{ksjQf=c-9y2exaZ0D~;AB%HF_RFg+O5sb)~|F-ftCtZ(b)QUYKcnVXND< z+o_KdT(q9v_2z~M*Gn9WR{aH9LpSEe$ks0Z%>rJUZuFF}mc{D=#N7$C*clZ8)zeEd zS`T!ACV^^7*@}yqZ^L5jWx`$F+IbPeYJX%^h z^bP!#nBXGWo!Yp+HvK0U{8*`j!2;rC2*I7qv*`Pi7``4v^@Xr4Kcl~D0Uq?#>ZCj! z=&q<`3ZV%!vX&V=n7f8_bP$!w-=Sr{B_q#EB?t++RfC>TU68}s;r(V(R=AE{;7Uyh z{W#P_j{y^mv|!;h0<@Yz>zmFq-$IW@2Qt|@?8TxGEXQLwTg5n5=FE0#zI^n%C=rHw~i90wYGNwkatAVcTEJsZvyP z(M!7FmNeyyO&p*qe&_}cIqdS&+ERy=2jNS}cW(L?oK=BK6HT`h6vR)FTRPSxN9k3o zNsp%*FEAkng%&`*i$AK=eb}V-t&SX+hIStk{mJ+;mzTrxBW^FOUupNlRF=(GsV|N* z@H^t*-zx}HrymD}aHrz0j?8rSHK+?>#m8kBjDg-S@X-D;B;s$c`FNaLB0r6ZnrrH@ z@b*IuoDi%fpH-O}5T-DKW%)I$6S^W6S+mtsHZn7v4M4k$iW)tr6_9Bj)JA{r_HZzN zEAuQQ@x0mBj#Ltl!TGbm%%Kch{T8UMW7K_<71{RNHJ1Uo=E+_}Wgyo)A4OtRVF@h1 zZXq`|&9UK>1lCigQd;1pL(VcWd8DQ{o+dQ%s7l)a#}R$)o?<9$4e3yOl}HerZMO5^s0vSfoB~V<^iM8KTtn{BsAYP^nq+>X_qfEaA48e3Qw= zZS8^VFC#I7C!N#eDFd#rYx$Dq)L|p36}l4m%Y%oEtU{pJOzF?GDQDi$`DsI41+2=gS^ZF*$Dd_ zSV7NE5+n(*LKMgp zx`RG8=czad+3XWaHMm_nQls@Kr^-ATbNkey?0s|?@)H0!vCb2j7!l38D72yVPNCdb z-s-b+J7~JL#(#hHWJr=Y=s`~NzFUPI1xh}r_-mYPTZMF3Wh7rHrto+-%L$VeCfLh_ zfUdIm*9clEd zVqLj)u<4QZZ{gOH$mKIAM;(p1^-RVizytE9eoBQKaivUp-x*ZzS~&j${c4>X<5n&ViET)U#Em|gRHqdDz?(?S?mDfN_r4~ue4Q8nCQ?ffh>C7 zM+K6!o#%|W_w%Yw!af&|=7(t2WU{I!*ctU7?=t1NZhG;o(cwQz=_7|V-pS-NZzmdiY7kN#pd*JawOAb@#g- zNiObA3<$pHQX)=rFLZoUJmopxA{9v3YC~I3n(_w16gJh~Iv;VBJ>s|t>F0M|Ij&&T z5~Y$?DSTERb#)o$blfXWu?#A4M=jV|o`{MQcZijuF%8Vir$w^V9q0wMqvhOq%e6}= zqj#lqw4w(a>)a$LZgwQi(3qaVNY|~t)f^%E9-=AQYPiZS$-rJc!O^YCLl!>A=gsF* z-m4kY0P_gBKK$w*w)qB1rG0|xNCsg{QTh64T5=pVg*cx$uMWIdic533xtV}r)4L(! zKbh6EPBRw~y@Bp~hYK&1`#>67yD(o@~;)ViwP`m?7yfg?ZaM790 z7(Q(*3XshKg4|qSP|i0hh=nzFpGRdyI9r0Gk~b)jpw9UNlb1?dka-`&z>0E`JQQQM z8nJWIN5aP$#Dr5)%55ZhyYVTZBGR{N8X5cP)6)hK^&p8=?MsQjf0fHBp-Gn~#+I{y ze)Wk$sdx4R56;;`W9Q>7D&`pfTQ3@$&hrNW|229sK0T5Os$z=u=nb0kIHE`ZNo62$ zHVBkR+U%3FBs0i5&Of~1P$DK&BSM-bfB&N8$7$zP*lt)Q<_0>sJ-gO4C$qo_m%>O` zDy1()^V=vv)euBIM~sbT-bz- zaQP|=yt@YU^UIU2*?tPRh%FIX1DFmlQD30cjJFbwFTvgA5mKR=MNt!?9BE!* z9>EO*W9eBG5Y(P-QlH{CK3U*~o)?%26~I%?x=ZLC3GqS;osm(BQVMgT=vw6AXO`8! zaVk~BUa$Y5TB9+IDjtLz=35ggmUqQQX}Dt@6tDMCyn&CK%M-53CEj515pn(ioya+&Y4uXc z_gw8&A&sEV!N`T`!zm60`LCDzSu+=tkq0aHWh;wXxq0AG zVZ4VuyF77jUz)1hz@b@C${5s~#%Pp`Br12%-LR|kniX&8(HdI{`xx>fT5SfP;#>mJOS&i15%-kEXI*Vi1`wKH=^9(NrnC$gM*-A=^#5#;%Hl11L06@NavvmhAXh=8ZZEyAi@{<#S zb2}uTH}J>(bL0tO<O}jH{P;eARnDJsm1wWY6v@UF3&_3q78`(JQah5* z@mH4d)xHlSFqBoRN}40o)vAahmtJy&SE#FW8XyRP`dMe9Dr1-O+Aer&3@Gj)jgUVs zQpy{K6yWjMtMMHTAO-J#D0@`&DyYgZg-H`O9&|bsVqo6#?>& z!Yd0%`p2rT_hy{#ohv81OI9rrMXi2gMsJ$Bk&-m1%aKM4&1Qp;5j2Q~yUUT>SiQg5 z9Ua0LcL!Q^edwLoDM3%?p=!*6;&^D#)s`;RaKKA}Z55R`TIllX41z97g%0D#+NzwX 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

    %Kzf@LH>Gx{K+xw1Jn3~l=# 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%0AG?hAWWgrLNRP47M4z#mSK0r#)hNgRn^(pW+ORB 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 ? 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 z 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≀27#EJMkE1alxEc}G0RzZ?<-8eq??;Nl`# z#=s=+`}f3;Rm#ZfALBwL5;E#GvpP(l{@vY{xL<^hL^>dn;ie3V1$y67mP|a>(uoYH ztqg|Op?|$Xx53xu-1XlM9t6n-r2iRhGhg0lK~X{ZC+CDU`|hfyx(wT;Vxu=nSLr<< z)#%KCf##btwyQQwVU+u>1~{}y^M>2r5_mB^jU=#U9E_gl!iW1rC$#98RXF*!1y7j$ zhL)Z_o(S-gt{C11bRZ-4a8 z|FCf{^aSHfF0A9k;~f#Gvjgn1$=e}2ajyMl9Wj<%pXfNJ9#LF6h)9G@Xd3% z>y+lVAto#_sxi?}c>2qyB&tTuWJF8*fqVK*gbSB*P1e8S;_Z zNO#tG#`M)gAm;~e!_JI<>J_|^0=30e<9P->dSGf%7e|v#lxYOvD&5ZrH06+reQxF7J?x^tyc5VA+=xCneb7ywwd|Gmb;9TeQ~ z@^T{*O(C5~__ZW!Uirsxw-+U8ZCdvCM<$9le?R=8n-*Js0O&}kig3A?w*5Qg!Hn#- z=6gX4R<3k`BErV9RAl0QY~u7KDo8N8by#q5B4o%N@}NP|5yL`sBvQ}8JbHHD(A-Kcq{lS-HQr;ay;ueB5n+tZk$hP%>UPpK`} zKiqZk%W*#}^f4MQ)Ih{R-=wMj-4P9sGUx?zt zZ5Lf|7tjG8bXK3(B{dZddaG_&UK?ssmA`49;zn!iCCf>t6=<7O7I`wx$aIibwPm*< zwOxoIhAoN{W_Yp{z{4nVBGGgVUZVd*N$Ad$viHo^G>&BxcR(D#uMUO9Q4~1T|{IRy2Yj?S>fevtEst&5p7++Jt`z%8W9bi;C zpIwHF-O8B%Bf!bd3Jt?a%p92P44P!a=N5fVJs1tfR{O@2ZeB%D9@#%T*q|=;M~JW* z<=kC*N)4N~j9>g3*cZQ)&lzLj4=i60mMH9~thmU~ASpD^UXuN~Zz1>Kq3e=^vB{h8 zW)aeRKc1@Fe=U%IUi@z7t;NO|s9z0+c@Gj=y z@#L(C^05Dx+ItPwFsgRrm=eyc{639)c3PknjoHy}7xQn_jpFgHe!4T)OaSa0bux<~ zI)ZJW-Z_U)h$#O@a0k<{`@a#chYLE_pxgo43g5pPwb@}VZ#98 z-rg&hHmc}()}3$p_)*A%n$LlD-F`SHR<{rMfLR>n3uh}@^@G}5+bs!v)@8_|q0e*= zYm!HQDL639cnRdak2$7kBmDKI>dfKw{I0UzmA0rks^5XU2hIgSK91y zE=wg~T0-&R?%ltMM+5-2Cqf*nSRuwx@iz6yV7=f}im2S-5WP34_&_RYOpc?!+4X$> zyEooWyPhTFF@Mb2N#q?R132xA?D4()Zr=$Si6Otz{|Ex_&=hVPjx5E?Udl@WpY$p| z+y^LeMz?kP=cxyt{3tCA3i%W3G&_P(OKbc+@U2QA?ibrdu$#`5(}3cpG1;n@CW*8d znq05tZNMX_>XE+po+n5%dq4*{!P|at&Sn@!?SI6C<#+ z+%e@?v7;H+7@<7SS15di?c-+w&U*=x7?%ZgpECrc|H_fQp(fb*{q9*B!TG3&yvR~- z#FLGa*Y{ecoefRWUGEl$Lg_|nIC%P`Y_LBJ_o|$9e`2N!rh9$?;bZ$Lsj~st_w`fD z%sjatnZe_+7ABY6{CXO4PTiuoNKQD1kp9y}Q!)&o^4|j?e%-e#aq}Y8*QRE<&2<;6 zAtT7MCf4oo8F%Bienl;rRWXPE8sEKT&kyJQOw`4Q?mS9Cs;d*4_+92_Pf!z$_ifH< zTWKsl`m}9yA5pnZ<{Q*tH2a1yvG1V87@+MV-K(9onE zyuqp7IL#Aj{6lT}&Clv>@yNp|1}cgJ*@Bvg$;*Pv?Xx!5e-YsEt`g+9*&@fAZ_Ie2 zKro}m+k!2z+{!T;x}ox)WG+3dE2mEwb^1@~Xqz6ahag|!3&<`t6(NsbpxRiuhGN)v z(fFCC6mI_7xEVMFvj*Qs+AV}^`7Z zQGgl72Tz^!xqXena5SZh3ioM%hipk%voc7CAchXi^D!S(EP(2CP10_^~1HC z_+*ti+@Lz0rQJPsASua^t494-FW||G_q&VEMqfbq$(2iJY|-uQXRcWL(r^>r*sF8V zys)b``Pi2!by2--8^;=kO{A$cU130TC`mJFPQ`+0t*AfSvwEp8P0@_4{2db>qc+Im z?KfjT6B8C3gcfz@H&CBOQ*lL8gXlPl*$u>0l7FjLV5n?QBv z+yPBcbq8ys2YY_uAUS!{jTNYshmd?x4NHuBR)uc5waR#t-EGRnjHM`eSYO2l0oYI zin6HOjzni?Bm6$)(-|hYFP^dDE;d__Wxp}I2fy1|tY(AIQWk4R_>HcEHJck%M4pk_ zdP@#cvDlQB@+1N_jE8XU8(f`EXB`4xmA^mzkKnQHvk4-v&y(C06YZ{{@?C+8^qgLV`AB)i4^c-IAgQlX8gbdFeg=zKeASY z;F0B|yeT;>W;`sWjOmTCe=Xg%?>$wcEsZyZKlS@zX3!1n6f2qmKKIz7AYra&|VDB74?tp2IY*+#1gij z?iaco<;G@If>oTjA$&gICv5_JTF$gc{pw03IMazpWBZm>0M{as$YR;Rt-^h8?+v*> zP^EId9osICNr9O?B<(x74u6fl(kh*A^b~+zt*y6DxB^_Yrn3lV*VFXJKQO&rc;ySe zdYH+%=bny^$-`Dfi@YW|^)y^KbU46A;Rlqh4rZGWQ^{FPgDQFvbG_;bqd z<%(adFY7lQE(G6@L42Q}pT1!LAMDRt${);hGCygVEG~0?-+bC>>DU3VJ&_DtwWa@@ z4T=9?tfYioFtOh%J_ln!pN?K-Y0K%>e=U%pXeEv9*YgB^H&0lPWhH1>tOV2;46FW~ z{R_vw&zMo5v7oQNa?)(!S^2Q+bpyO7H><+OO{)ph#j-KEbe-3Z^b{u!ZFyl+nVyRM z2vWzFu4+k>9F2BS$)5p3)wY`F<1C+>Qpw_Gm4aLbO)DPnCjXA++KR?p>q%LpG@;|O z3KR&f6A0XPPhj&_?>Cr0np&xbxxHu^qIyW*($#qA@Kdl_tESd4(HJ=OoG2$xo(IDXUg zMEAxl0Mt)w1327k}7! zKjNtD`F7V;`L_6kxQ%6$e4bo+J6;1oYGxZ2ylmU~?o$4F5GLHzGHGRa<=SJ4RAhp& z;*kp8VSz)1`o1!gs6|68S=-n2xBqCFG7PR>dP=4SOJV_2FGnJY)>gWca+QH3F{ROJ~KRP9$7>J{(MFW2q# zMuf_A`Tb*WZIh=#%Z$`$imIa8a$P(i|L^%B9@d0~57)h4{mQ;t1Nwz53X18!&Y#$!@jIoK(r!0&o&Kndk zT2^@JzfauLRGCJK#Q)gURHR(bXsc1!e!c7ToQ^=4XBb;p zQVJrXh5eu}KwzRVvQtFqc+z?_96c+#L`xQH9e$GvJ-tULEDqJnuNpmJKEQjq90g#) znlY<4{}H4*zd-&SW&zZe>NRb=eA+JRUrZSqKB2l+SNGL6ub0iv;Lla8%BC2sV8DjI z&`O2Z*M3N853!ME#PmrO#R|Bly3b<9XA{d%CFl5u!h3@3Zyrij62)no&UL(-5Z(9vo-HR_2r#h z>bZtHH>J7FL*Y*4`Tp}SdJ>7P+GEYfQKKWAPwnu^7tf%14mlJ+O-Bx+ogdLX60BqH6doT4p~u!>(^v47rn zf~Mo&n9877+j)^vzy9eIjz6iDit}+i`!h=J;0@0ggo-BbMk;#=Up;4*_+h@^ff$*w zc}L-@vP0`C$cW1YI+RX5qjXe>M5qQzyA9*9_KMobt z(DlEFkcm#`uiu^6LL{s0wdgkLyHx?b5x>Y8oqwE<)9I7XWja=hT0R?nU{g0^L^7G%y^|9e6-3dq8vEuivq`%|>ZNT{nVTAcgp6l;W;EjM-dFDpVVFP&wnlb3_2h-M)G#|{O%ndd+@N+dQG#Jm zrBBHNxW4Kr=EY9-jp#6WIpGrv^WJTdmoNN23B9!@XVNBg7CFH@q<%~HAA#5naF$Y6 zdEXlb)*N|rhSwcQ@$~TarvzGcM(nWrVcE|{YOk>A;UK-5@TbQ4d(-cAWoNXBD?81(ptg$S~N=>;tQ1J%|sW4 zch2n^-LNi7ap%w zty`CE?)ot&(>Bk!3Ch@8YRh`5=}__H8bSIuvdK*Qy8?F`^xs`aI#?D65t(vY+5KaHxO?bWgB)z+}A`Z-k0n#gk9o9;%;r zcIWB8h#QeD`a1pXjoy=99scMK@C*8xG4~JIoLY$HiRXPid?@wG;2F<03QiF^ns5iI zEh&qH-xM!Gu)#Hu$V%}9bUrGBy1V)6GJrD5WyW~g+Ur=oY0}zfUW1|kr}`?dhh@Il zPX`KaNW4sk*t1>o)^i3Ld%r6ih4_@Mm!C=6T)&TZRo3fZpGL5j`wUsC-CWT}k=n<{ z*h~hz0p+T_4fY4=M$b`_*%78<`*AxO*vptOh0Xs6Fiw%j(XkSals$#V6711L6OmwAQ-kxLD{e?6x)Vt4U zUj&g8hmc49H$WgnPe@2efQQ40|M&5~cR~VsIvz<4?$-_yKF^{uzc=(6pWq>Lazgxf z>U0oo5s38AmK?Ac2sTwNB8%GOhp@+4{qzn!oKjjt`XzCTX7oFr`@{JINpaH2iVEiZ zTMh_(I+;U#J@VXP674YK{}FF-Arv>3`#6J)uPO)t4>D-)0B!PTEEM^HEnL7B3O4n4 zk$aHBHBk{PHCwWdqpy`QwFp7SWeZgX4tro zte#^qA0Z>$`$|}(SC9hIO{z0~=Ic%00t+?tG_;?U9@xyoYse(weVo6&#RuZff@@+0Uu9O6r^Y*V5V6S|Q~+aL4};Q|^PP+7Vh_t35@;LJ zb->_b-!_rY7EK1pAG znjL*f=w-Cr6E|Q?+PH@EIRGxzK@&)-l!oL{LJC^I$n@LIFHoS9e$-qedvWwca3rF< zJE30$E6w`=ETpi2=7t~y12plCq*v=P72G(ZH z@|H6CMsx>wr+WA}EkEs((@1xW;0dHelX1vR0S7tviWn9$kegTyd;-eKCcKVf+Z-W` z?al1A0 zShZo!ZEkP4Nj=RRCgs!vwivQ-rdYa}Ef6T4v$zC8P<`7SQW0B)-~r{d??n&1QaJxw1W=ufn7`WdzWYz`bEp@0Ew#Y6*vu6>AzP8ZGhg?*I6dg2&rimD|Q zyueYvRz!+&W~T%~cL3taVGK+thxp)$-n=~g-LLMgcbu@k{ZS={^ANfsWsov@h@M@k zHZ%fmk`j?CAcKI2GJ|N!(lXM2pV>+>jCdHPmng7AF4~_Sa<^F~r%|X`q_$ZBcHk zmA)L@%3b5ekjEJQ3=V{z9tZS8Q2?JQn<5&TR^i|kyWZ(8(ggtIMG(scr*yhg8DVM( zcQXEA=g;inZj7;_GX!r*+;R7t`uyyG43X{=?V{(#X-aQ9u>q%s5R<9?7;m^84Pnv6 zeUwVLhJPTzsZ0-)sPCLRP`$c=-Ek>CwwYxXrjj0+hVt6(-ZYrvJY8L0I=0|2uV)vb zt>+RIg&H4rLfV{}@CD5oZ0r54@gY5i*GXBK+3)BXs%Nk?wP>44YrzlsGVZyHOEsmS zJJH*HbrA6aZN>x2SmJT!c$WON#UuK8YOo|&VuZwqoQ72n<$gN4JrVggf-qof(*pzFKBXr0%yW{?WMId{w4X&dUa?Z-JS$hOvC*8Z-C4`Yv;ZOQD=|8^wbCrDmG8{6$^m=rA)6a)`bgh)U*KV8kKHYOPa2I$ zZ+QDUEcj83;=jTyf#q_&>*in<;AW)Y#mFs)PgemU0MTa^;^vRS_g;kzOU`;f=B23i zP~M2Ov1h3D!UOBpv=v-rK1tni$1~;81XGH24Y6o;kS|+!5#O*&&jV5TouMOJ(5cT1 zSxP>NqJxjr2h1@2sbgpdatQlTpZ#MD0{=L?0~ux04Mqj^ArwX|f`^U=4@fQibAZa} zht;$~uo4cWeP)}Euc21`#gMi@bi;49GUW$!mo_3@oIG>dQ-Ifm87QbtK41J=(c&oH z1MFUBfR~dW_owYf5~kjo)a}FgEESi!EY5zL#$$xY+7AC0|L9Xm4^I@ZVcbHgQ6VU- zNyJ;sZn;BhYr-k~Wy_d+)lc{gyF`0KM0OQ9)+>0P;9GC6~elon*O-OS*k2Ps_uEc*jJV4R~4lL%zo?*!PA0->a2;=hW3 zn^bk^0vl5xFIo0OKf_4!{L%GCuTRO)9V5S`kfe<_V5A%M$RKnDeo0Gwxt-+)HfI-2 zqU9XH630cNtuiVzCAk^AtmVvAIQ0XStN>X$imB-*kAfCMt^tQOM#o9 zz|Q~+_3C&?fJ3{sCH;2g`as~vKwBFtUXFFd^W`<*){e-w2pF_@nR0sG*S!PQ80s1! zQTI)!I%earg*th08a2NffwhF(Ma!9mE^`UtNSpeS7uY)cm5i{jDDxp?0Lk_?=DYiDOC1&XnJezY| zr=eIBj&6Y1DX3F5o*MenNFQ5)I0*+E_5n(T#N z?XdpuSg?iQ5cj6y!&9^`sct1TG#3+o##Gl}+A#|_+!{)U=vAPa9 z?Ordm5E^-=x=2#xMIuaXx(?B&o4Q$(bh@o? zLjZaJrtJ-L0%QQx9HOwC1B#@+#nZaRmDYjK-YtaC>wNA_{!jNZFNHR+Gpv_xivRz# z$FV?m8^hZLz(~gtMdavS10eb!2DGe)?pfFjL0|}53IYIDa>r0?|IACyQ!Vhx4SpHH zzIBVAf>6M92(MELK9d1Yts0R&ojAdsET1a1M6Gcrtgl5{wJfkF7UwxaBC2r%>)Va= z{9ubynpPkip~%HCDaJXEp%)YoI!?({;8MK#f0q&ekGR&mi?9WU-#M_Cn5!LOkyYTP z(pO)J0V(M=+8kg3KvBhw6Aq4O6?9{PvJPoTa#(p9MffZ<#-!_8%+|G}LdwB)#C5$e z#e=BZwfE*!$~!ms%f1m|aplD(&I$8k6NLf0*N{qA!Elkxi8ZPE&W25OQ^;nT;oe==c`S3b1gCvajGr$%-C!Tx|PRC zA=HlzZLdY(X{tL2r(3y+r8_oY3(Qu?W@Xsm+NR5{oiST6NC~)ftaQr$*gvkUF)hRQ?m9-aUWI)og#YJuUDA&fTaZ-=J&P&dtITL5@Y|;Fpf8(%Pj>v ztUXVI)*m%0;1{&Bs~SMkbn-j{yw;&8uWOg$UF>Wz*y55J z=6Q9mc#U%M$t&lQna&{sC|FHLQ+XQ$BbOTq$vvW&uccsyI$L<{pY(XWUNg!bIt}at z#yL6rzdBU8mp3s2LSo=AO!8*}cL>WwqoN8=peSH>8s0r{SbV2*M{LI~Jq&-!U2?!) zupL@jc0imrD=UEB+4+#-hh@wv5%Ap)c6 z=Y^2oP*6%LFgPsU>ctWsrS7iv zsW19wyECrVcV}dm33odZ`gpX@lJALv=I1~u6#gT~O7|?%4bN7mj>q3u4r}Q>pIeUg z)JYoSGviop&G3W^`5(O3E`)NK~z9C{Y6Kmy|wJztQHI0aOY~@a!0P@(s>50fPVBFG*El3D>IP@*suzzwZmu>!B+YOh}_Fw!g# zxV)TxG=YA=&=JXEg?=D_jBP{j?k_7BMxE-%gf_JG0A})`=>#NJWb8*wT1iI|PU6XP zhYQ;W_3o38E{3fl>_*mvs^pPG%UOa7PF*jm=KhGSX9Y)k;zYumR#X?jJ2|*|&^O3&CgT5_{_(KQ6^2SWR)@cmYw;%Fb3 z+zO4L=dsfWehGRH0YU+9Z(GueY;2Ma0x|;M2MdH|cTjunM;asJ9teAU+}9OxWI(sk z{8mXgzu!MAbi~4u%`PqgK~#loF63o-LpsclS)IqQspF*_I=WK&E=tUeOVYz)<0P}W z+tcu;92|0P4P9ARd{QWTD;8<6%_VLAZQ{5)rX0#5YGOGGwMRTTB}?G3{@NkF*3Z0v^~A9Mf^^9FFk zY`6na0&ukj#&k%kTGf#my+H|dE}#Pr^O0f5Bi+O&zZEmWVD&D@th=LlO5h3z{UJvTq1jb35BBV7s%?*OuFLtYF;s3_E5TkU`3@u1K58#Z%i3%Xt6t|eIx2&_ zsiVODP#At!X6XVE2b3`FnAyTJ&S|;-t~O?}p|8Tf+%ERlN1&7NCX=GhzUsyp|D=$( zKl`CPoffPY8Z&zxt-2xc&J7#HD?CCb+xtw*H6=}0WN`B)$vztM=|-v!*dXV@s_qxn zso>BdT?!d0Y4I763qy<_UU4wZ?a^BB?Bt|mD>bT|+SL0A%)%$hEI7A2zN?qVHumO+ zq@K6f7+sJ^0slBSbjUrpeO~M$F}{#(0kV)#wNY&by3i~Hw%Ix09mm08N&BIiFS&=y z<4{g3gq%Wq0iv7Rm>g&)QfwGcR=cGL<&qRQ|Xxt zw7OY1o07R5_bgkt*aRP*Nw>!R;gza$u%~Tkdv^H8+@nXulR2!(Rf*RNHc!`sWw-j*Q_YKYJQc=HcWzs{l@L2YY%=yx|sAY$y?ec1GvjoP<)lWbTnt zrb9P3$hQ4duSNGHBamhHQzE*4`I}(E3ePlmdyLhv9Y0@bokb+eK@}N2mgaQoPd#UV z&@?ybFi0Rv{+xXDn4u@I$HM<~xh||zxv{g6`qR|_U8qA^qJKvRA+fSvmrd&FIm9Et zQ!(@dT{hc|QraOCrm?m}4Rx(RzxUCv#d|cop0hKTw#*>Q27d`4G~cv+Y<55)Sv`EU)mBp0`$X|*v*Sjm zH)nYk)bSP$i?YhlYBo}KH_8-j$mb&BB?!yf!3p~1b!wM+L5tWgu3F+ky>m*}bLu83 zI=2N}d2JobK;Yru)E$%aN9HSA1F}P++0KeIH>%5Zz7f@)g{v=nGwMJ*5m^8xIxlE^ z#-8#`(A04~%a?!gAehM9%JKpht>C-?b4S zEn(Ab>WTn<+D{Vxyua}&Tt9A5y;|K`I9SZ}lzJ6-bfk$c8o;FZ}hQ2yjO9AU|Tj`%5s(kVMqG?}_k zN)2_F1)wZ4Z=Rt_Dt+$zFF2E@?sh0c6czXXFuQQ}1@l7YlrPYy5o5W|q>tuECzfZR z7G(P&7k#Jtq61WUc^qx*qa95BR^B-P`-Aw`V2*f&v?=6MPphrQg#q%z?@QGVNY+rv zdOiu2!UbSU8dgsR886hzonz9{@l#o@fOaIcrNWtWHS(}r&nUwqFyx$i|4OtU!L8#U zm2QuM6&ArK#rILD77}g1%9>|(zI^Nc@;;?l(TdW`)1`XE?Z=c(Zk!>-MY{7j&ny^Y zO6zwh)*)53jN0-)Qo@3q7VS*QjEg=0daLS%2({M_6!u3AjUkt!c8EmsHmOe4zD#j0 zQr_a?gego+4D%76)qH`H7wvXk$_vk)Poi4v;nOc$(sU9=W`!Jsu0_9~DYe1HnF z3U!$8cn7_({SJ27zeDwNIvttYaid6aBu}^EgZWN%P<0v4TsEtKw=tc?`}5Dq zJ%E8Bn}TwVHL(jDW+HtnYt`KO1dAO?0ZO|8L$jOZ2G_Rbu(M))vKU5XI zcrU#rJby;Ms^S^;F_kA2F-tg8%&UM}`98#{Y91gClNHx7;S7CwWYO>De$kmjIp+g{ zI%J~hIk~PVj@#expHl_86o^@!D%T%ELb5ug(zEP!8Csykr5K2m8&nSZ2st}Nzppt* zpDYQ(`{x|_r!C`p3ne&f3vH>hR7XZbA$wc*4&v{4lD&>}7HCQvE2Z>Pbo>spi9%4F z-2(j%@*dBL0pr!k9FxAr$w(SYsi5fKP@o}B@Ibn2C4Pa{wcinD93K0&~EvnwdeAt4b zZT!@|RI`7wjQ;B+f^Hf%K3vV>nc2&p3fpHoY~60(;?LZtbn049VLfuSd;p??Hh>1U z(|;WDx@^b;Qk85dH-cs3Ysr-u@AOz=a193{0*6nXTQuX$Muc?7j?~|h8d9}fWEoxq zJ1&+|m4;MuLdA)x7xB9Ud(@0@nECZ@m)#ft<0R+b{0?s#^$?&saR}}NsR!|7*r->> zdLLaE-$YF!!-D-EKMCf4k2*u%=-p(8HGR3bI4n$~#gO?%lpyVb0E+Je{p%gh($)@^ z|3WEeQxQ59v=GC>hE>fGH{-x1v8g~FpU(lkE={Y#Tk+xzbzq4t-d*DcRLw%W6ZI*8ih zses~8Y9Uf+-#-CSb!P`y$(tZ(ISoTt`D8S<3hBNo#pr+Zp`9&mlZLB-?X1GgU*dQV z<7avI5yegz`#xMlDuAVa2V^Jyz$oH*pg+PRD=DB5%WvCzlj@-4{^Xo&ibPvyx2e5T z1k*}ukCJUVqlx+TGSlvPC5QH@`retYqw$>|7#RPB&z z6KZShnYwJ+;IcYgRX2*z7%5_uXjED=5woHyVoU7wm(Ta{dpz=2^3OZ(alT)#^LQS| z`5G1cQ~$8yc7=*a&3gvR_~3H!nU?H{`aV@YslteDlrm2yxDLcfR+5kYh~(D)j_G%g z9eFOL;P%r(aaU3nsXSWkHpq!$%biNJ`=#w0Ie&sX(XD?`fmAmXZe#Usq~BM|cZkBX z7Z>9(R~4u-17iMNdI=^!Z_^OkEDJ1q7h>=m@bs^^9-D;pw=@*7MIsc$V-oe$c;)@U z`6I}-RE9du4iy9v5Rv%$E1flCt`&aA3VPX5$-Cgh+SitGGc(1@GjxJI#$K)7BF-y< zfAs{6{ka?48Fd53if#FDu5b=p(it5c+j6`ZdJ@?BDQY+ZSv0PB5Fw}Y$^xg6DrFS}iBjlPMfKQ?Z9nREiIwnXa$P$|3>9zPg= zB_FAY=Mto;vcZL1Dn|)K1Gn7G?gz*jHpj(9T;^xlE-bnM=#E8IILn5-`CBY-nZdA9 zJjN{G^aTaGdK+izXAd98nU@4JgZpq&Y88k)EC{Q~=~Rg}9mvMEWUrcx8W6RXo$d{7 zTM8Gg3C+tWw!7BCWIR6V#^qhp;(^CXwt%!c*`D8r0+MpAgvolEH5A2)k1!s}I_@pB z;Y97UtrVl^`XVo?b`~f&^pxi5{sr&YRW9NgbC9>77+z*c)N0ACF5#bUJ9T0ItC??F zxOfj4cF#+kTV&k7>Y0RzoPMFh9jMA4_Wt{69dyj>Q6XhU;0k3+CSz$!qhbA^7uwj~b1eklt z*m`^Zq|N?zam)S;lP4WB%B@WdM%N#ArR((2hru}2T7O)4MNwKyS^+xtl4y2L?2{-% z1gy1M5q|{t_vxI=eN|;*TeqZns||PcQ*^?Cjj$HodG{e)lyJyNKw`C8yi6qBt3Jbb zJ!o3Xd8XTL;p%Bs7>7fq_VV-tvs;>zS)e;-lFxgm;)#bjAQ8 z3)MX9`0N?UG!cx7IjTYx2hSVo9tH2==sT-6;Ed?oe?)`0>>Q%%0xHuX3s~qPHhY~Qi;)LH|G8q{WvN-V4Q1` zwXyOuz8R^FOM~`kd3$>E=KJM~RL^Cu)(TUAj$E^#VQ;MnffwX(<$ud{LZ{Eq9pP6CVh0`7(G{e=NSSNvE2oI~khlV2go7FgTQOggfSD%& z0?eefHoaKHFg*h#M{YNtu>A+~Pv~-?3CR4j~p<1misa z+`?fK{xvf}F7u-cD_M2#(VqJ~VLa*n3}Agrk2ZLuLQguyEhyxNnKohbOk(K?BjGz! zhva4Ft5k5>xAp5Xtmf)NT<|-3UBymnX88nbA8P*s|xy# z7EUj`41&ii@pX@y_*TKXYj*in>k{&YT;Z9yB0WlHVYbF?*)+m!#2UYCSA}cH%C|U- zsOx0jyQz`^;MjnN+@0>-L8ijIzj-b-V7)#KiEM?%0v-*2_gT9@?RL?Xtb5p)0(^Y< z7n4moG(7yn%+1V7P8fQLat8gw<|Bsp7x9N};yp?1gYBjrRRw$B=Fw7~>{nx+BY&S4 z-{{)j%eNlv0_9fh_2jyj!+`g^yj<^drU;e$s#OrNMC|BmJM*SjKA!IJO-NJ|vHmje z1zEw#^ghtX?{y*yU%-)|K(kcUf0Oi@*3^{dmuAhsPZm`d4@9Y$U1RDJ`>u;((j%vKL%QnN zgD;y7i_3SZkxh#+d#LNB2J2I>H#*gLStX^R%{k{?$Gm(u%aamF1zvMPq91ELr^ zXOP!XyhXZF(jip;qvf?P>4U!0_hv5r1{`;mm7e7PL3Zg~=A_w-m?UaTb!9nw(RAM# z?@HSRv~N7x_f%-Md?M<>^WozBX>l0Hm+1*}Ja6yy^q{wQGUZ@fIMotJBF3;rg|~#~ z+R}#Pirb2B_J}JISK+^q50L&WnA@dFt8L=9IEcqkokGn$OIOQ#sqMT$m$Lkdv|A77 zbl6AG_;<+)wtGzqZhXh68+~hCR=-+*B>t4ILeJHg$Gv27Fu7b~SLdz$=AS3=g^6X= zvmfJf*>1ffA#-I7$zPjFBcU=oQa1QvZ@iJv>FMICUt)ojJGamx`)hf{)5zc<7Z;u3 zeajH=ZDlH&j4>xp6F=_}8U9i3slBmbw@qo)*lWNtqvDy?lr5&7csIq)L;I&B+!Pal$Ckfh*_!t<=H@(;C>FXmQOI=a*dRnZPUo!h z^{YsLp${(BmYxLm)PxniiUmH4St&xM2s~{~0CZWGZ}jADD=-mN?=zLx^I#NRUHGTf zH?qnkm`wOP-{S|6Xzqwtq<)%&Cbnh?B!3Le7bhFGbYY{dd53l*`VTw<>I4i#<#~~p_)gQNgTUU zh%)6p5#lQ*UXk2q>MShCcIEz}^&L2H|-k-a(IJ z+nG$-d(|kut$Cywdap{8+~1ki!NhqAY;A)Qr?u$D*)%%K>1fbZ5sl81olPhcEw1z) z9*C7k^w7ue7R?+zi72jT4M)95J%no+vORy+96@l}vO@>UH zX_j;U*mGvU}9?2sPzlXnBrmn zK}bn1$W5~+iCoE9Wj48n!_-%0KMAQ%n~a>OwZsm>BNc9 zZzSGY$oxSkEgDG1Xz3u!aYI>|v1p6rYa@ov3GNJ(_QJ|1%f=K=VFF{7STf ze*yjmka3e#|4fKOEbapM4&|KaRzN$;l7}}7r z$o<1{4h$j2eYbR~$aV?_^u3t$ifr7+v$pj@^VmxND?{&}i!tRPq_(%o#KYKO2xSnl zvX{E8yzEDSML8CS8U|CiOakr0HYmX}uBT7!*mh|qMskPK@YV*X)w9RLKJb)A` zwf8xEeey^@E+ba`hmnX;B2P+)i7AyBa2DDujNOj*)o=_z!+1wu<-OS@ujA_2b2T5{ z$O75Z8PrHlt{#jm15(!Cd4W^LJWAp*J3eS4Y)u%QOIZDmeb#dflll!+tE`owA_-qR|vhwmU#(?1xu zdp*}GIf{7A34j@C%i%x|r>;Y*Cq2c@#qkF6B z1)mZLbV5sR!>I_r$KZ~aSXaxod#cYc?$gq;SmA#;6!+_*Qnl5T{=Si$KNGLhZi%)) znbKRo0cw%&PDe>!4>By47Jma&w?nE>^Pqw5U2olH=;>>nEpcHY!%H=Lb>cx);vUH*L>N8_E>&E0R8hM{XkL%2W5G4(AOxZ&HaC5E(gt37W@Cv+=ACu$<4jrw|AEQADqkme{k*sm-_Z4qd`YsHB*{Z zkqT@uhAbQQwMeP+<8zk}?*?q`++~PuYuh2dX&3sNyU?bs2XZ?_CLL6a*m1h*O)If$ zC@tl=)>0nK#9l8Vmm;++4V|F0;E7E!?iaa#QvLkM@w0hy2+oDc^V&cWVitBn7QJOM zD~-@3Xo^w_d>FeRtC@_JR$OrljxR5Kxc$;$*1KNrP>FmEJyN9Il#=HsDN^W|;Vryo z0(}NWycG<0bfIMoh1?yr#s+K@5>@N&^Yh2zV|v%1=s~B_L*4uBA3G1!(XbSz1od#G zr?LON{SlTUb&pO7V;qe5HT#cWoEkW4=G5wE49)7MP`UxcN;6x@z$l?)f2O{w%-|H6 z*N3*8?L*VYZ5r*j>HEu)pO-k8tG=Tm7>7g)*^lPa85{J$lLpolP}|M0NRS6}NKSce6BNgb=CcvAspw zfySXF1{U17=F%S)46XD%e6)`RSAj{fi|r?W#cIWk?ZC0!3#Jp=N7{r@9@9@G4k$v)#$y{hEu+_OzboECf4UNQR)3$pU0*=^Zlo=2@SE=Xl;-DAHG0!@F|n+ z3r{qXG!pZQUy%T6LJea97f_tyjb@EoUkI3p(O)#4d|j|6k=OTZ zGctvwTb?@1QK5S>h63!5_~P5P<)ZOav8`m1Y7MGN!r{SC>Hwb)*uFz?BvD)G4C}Y$ zKdtK+8)``8!UVf7SMp(QAlv^r*>Si28Y~AuObfbT+@E^;3VNgkF}Rv#Q|QAh^;(bh z5OUl|^cOexMRn4hC?X!7cM+vs_Smq+`nx?#bi}M6fc?9YGbS515 z{_K=%St}JE6J)Y2&lFgOnJzwy_7#I8s@~n!aVq>b#rqG*Kl2Ynl}#`8QoM0OmyBCD zQH7!Ms1U~?MBz|VqqbXlzWEb+JkHY5VF=D2-F8PWBqPeP^JA$+09D8RTw!5j!nt9s z66YqzfHGJMY&uO16Dd?B_#`AnMTLymMly6Iy@R}l%ZVtt0~)=9cOK?4xVYrD!k9o8tj|; z%wP8Gf=BXKzuETT;+ftS!~=;ZYUtOoFU0QZlxEH4yQ`h=MZ3dNV702e63)X-+vo&d zrBlN)6I0Ge_8Ly26mb#a<+3-S>EOGM_I-P_q8qfI48@V*`cwAlns>AEDNO_)HLk@t zW!{|5*p_fLE@-d=w99!AoV2lX}YQb+i;rO>l4h6J!4=unC`V<+#(k%MO0f%POb;zwK*w4pa zr=JhUmne@Ts)VsrKYoHU{oWzk9K1ga9_$*9clQ0U$JcEE4|F2XtRHZidH^l+4XE_6ko>%T7{_fMKwb3!=9+7(=PW-}inZcr=XClxSY$u*l{?Kl zhvgKTZtm?^Xyi-nFTTX=2A7c-LEyIe2J z7Cx2Q8cg77n`}2XTM9k|>*Y$&20dg&YF{ap^(rsuAhQ+6q0^3AHhn0cjQ)GZwxI>hd}z45G(^+j_8P z&a=l-_Oo)@Oo(uDhD>S`()&uz#)quvEUMtV(|?F>&YDK!<{QeOQis`~p56L)uA(_U z!f+9rE)1c|E-~Or_SfrCRy4c$k)&&dw!HC!7??%4vO3yb(Y_bC&6WcY;++=Dn%a~l z>LH4!{PP40p^;b_mQ_TTiffbgl6t_A;)34+S3n@|TA{p_tBNA+w5?CG-rng19bnbz z&`WK+(-5F6h^3rotdf*-k2?(aLY8_`)hb1HL3eyiAp@bqvc64{DSxHQ?8Rk2aQw9l zkPCDlhI)uuB5G+W*{f)hteA0s-(QuYvi^@bNa`pv9B-|tn1iOi??*c4K~w3h1{Yf} z$*d3Yy4*IlHRGAVWDj<#jCH2@6qd47wYZkEod}6+_S+=~Dc^x`J0!#;0}i_q0a;og%}T zzUAAyRK!O_E-sw@V6wu7W9uq_e45Oc!&KdiuW{3jSz6iYS@M`8K0^y*Dy&G1f$X3v z+NajQeu>^bJBF~JtMv84Kyy)4TavVA8xe6DCTM~9jBW5hZ5%JcxrnA(#5lNKpHmZo z_b;q<$0K|tBd$}m5l*pi$`~-1S^!YS)r;SUBpA2~Xjx`Z75S}=l_Z5X=$a}P(i{Wt z-sex@}xjbreXmqz; zVr+;7D)RZdaTzf}?EwIG8ymGLK#;WxmZ7L_%cd79EIy}!m8?&OCSZa)V)jAkixx`!V^z(&Y)liiv&=Q%q*4)vJPAHs2(Ai5}geQNUye^$qNgPOc-=13oR)#5DD(?=5^l}1z}qSiL&eVM&eVA5f_Xc@+?Zy`w6Mv-{(Kb$Tb zBTSrcJ@NO|ZO;Cr;apSx5b6z`DsB z0~sevScMk5d^-OdAY4_7=nfOqLO9)P*fuoFr!MJN!Z+a61q*o7SqjxAiA$itEO zo}U^XK>P=YhQOlSvZ^~3**%5kNbFO8iz*KhDOsN8zbMNE9^d?MISy?$dU^zVy4x?qirVH(2JohRMn22t`-D^PLJq@sbt}U@ zSB7&yDr0aIZOsA z?>k%tD<6eZKTQg|0}rp!y|V&R@$K~MrGt0r-%_0duxprSo1*rr!ET(_(ZT{-#GMVt z5H#^I`!OWtKzG<7)^KB!BqVmI+HGLdM~ks4#-@_5QD;kRcSBn|$Z&r;AfQ;Bt{{pK z7Rabv^-a~Nf-{}ZJH$SBV-4LqpS4h*d0$ihK67NX&VlQV%E$p^(WpiFToD(8kAU=l zG=2gu1}WmWOu0|A+x5<7jYy4N-g_a--BIMzEZULj6ge<%E4ym@T+jPc!(qa};{|M` z*VrDk3&Gc1|M$U!Djj<4m$E5_-LqTV(qScy~H z4i`qS3%ni>o`3~4wp<9!y`eOAH;l7-!B7>V{%i6D+JlHc?m9|TDH6(!RS43`zv=^u zzPfS}Ke*0#vqib@9-R57P@sgov_+`{O6}{{MLV6oh7vhu*eK?*HBGnbBAX2rJC&XwQvQqp4xX~|WmQluoqjHL^|yOv`iD!L6( zV7YP}QzFkeD(AKZlw*{|E+~FNbPHN+v@CARJ*}iH|6d^pNKHGFnTwwAv~$)gOKjz8 z@&amci(GGKxk|Z;-X4-Lvx_|l*yPa=`|;V$iln{zHX8OmSU>}otD5<^$(~w^`!vaAVe=fym6TPMm6c_ITm^FA+P1eyDa?_SKRuUW1TlIZcm=WJRb=t=lMNX)ha+sqF>Fj3-v}fJ> z1Y#QqM@+A$f^3@&=uXs4}~}o{HZ4mJ3`18|QO3 zRM2E<`48mmq5NcCc&@Ee(2~;iu5rzagE6W_l&9CPK7R9aM89=TxgDb;R7~iv#`(_} z^dWz2iekof3da`aa*a=}jEe24erTlKF}W78QF&hr>1e9tf%}7kz2JCB5h-zEtn%Vg(mDGhIgt>*I~SG*x5N# zm&Utmu0Gk+OOhcPM456zCvPEjpRE2J_H-R-?0zMacPTw}aTNo#v(hR;2$Lq)&*${2 zA6P`T0z0^7t;gc?e9X2eB(TF>tc(C7plU-^(2~-s0TciiMU+2;E52!gztzGBs%;-8 za=|jlh`lE2VoRT+`ugBd(oUsi&ku8B%_Z#NqBX$+om4G#G-}(s8KIbYQ77tbWlF4A z3#l9yIyAxaCXDd9sq{C1wmprLQ7(*O`h*e0Dhoc$mLG`w&&pS7JcX#CiVAT+f%L_* zu5?#lJy?3RVQ<=#1M^q{fz~R#RYHB(ah}0|yfUgpUyn9qq`t9bR1YYM0YmaTV^%7? zFD`5Ce7E?BiGv#*+R~XqF$+SZ>}{_eBHF%83nSbS2PA*ql!?LT&iMcI3B)3EPtfue z&0QyX0W9!ZB+(NNl=8A8d`{}(Y#NYxBK}6|o9@GJ-mj@T4-2~TZMUs*HmEWWwF2c) z>XB&`rEjd{yD5Lza~Hqf72K-bQXN-(d$-3Pfy@y#Ahnd4EF&oCa-WxACvLv-(l$Sb z$nXwW1r}Omy3|6$ohx*N#(?dUnvX1yIimw3lx3CSOf{W{9bqdyL|>KvS2Z(g^Y3>pP-%2}5_X|fSi`1T~ONoAwYS8ZgcQdVoP^16~oYzzK# zk%*HBo|1-+dKN;X&aL+!qLzt?8Vc?=|DFpl6l{Lnh``Cl17&zC8&Gs0K3hvYvk-Da zVxwC^!rq4X_+X4n;-;Dy(-6PzBf%Jc3sKh~?5I`DZamsGTQ|TnkZCMH&a1q??LW5F zcE0duDB-7oP5S(-TVwbj(^>FL_&_>2XfPKT}4cPJzF9n(Cy-VRV!S2hIqEFo=)vG!_XX0zQ|1gz&=P4IPDR;XJ)5aTo-QX#4p618^FHx#Nw)XYxKS(R}nZ3STff4J2Jim*A=Vm_o7}(7#y0!F;M#5WwK-k3CbXpTD9eeyMP%WBcHN0k3^-Zhn>hXDInVvANwJk8+7tzT*3Bh&4Nhx~c3@ouoKpc7qwJIW^a< zQM~c%;jTERJ$>L0OX1I7*DgPluBBF5NVg~Rno1B5nUCOE*ui3ZRg~|s6S#u&;FkZx zNC8s_UT2+5o*CY}n@NL{*)me*9SppYRY`o${pvu^gR^A)JL>}%=CvyKtC+e@AqX{* zVyk407%SE9-IWMFHyYa$wUzAkiz zWf?`@l>ug7Sfc!zo`6tA#7QvY!lM3adJ>db_CB6w&(C-f=IY9&e{&-TSp+cW-p;o= z(t4Rp5s$^dTC+*&3%4;>GMtIp)M51Xx7p!Uw|;hSo;4fuAq&<7gyyh@--YENF@2}; z?gAoTLN_nH4_hy6E$*7Nw&WL%s7NR1hU6lJf<{dMNJZX9d_0TdkH zY1(c^jXzbD1Ih^(D%MqJQFW?GhTg|LzLvM=mHsh3>pE@^CYlEk1~Pj0t#fTz!@lMF z=nYhDh=h~R{+D)AebQ63Bhi?D!rf3sNeQaA+NRXCmgsJ;th4gU&`v4d!F9&F)*_G= z_08P%8bI<_XZ{*lyfzf9Hdh2AyCH019(a5Gq3In3kSYSET^Uf)_4}TN9f{f^EVNLw zGJXT@DQe{e%dYBrR_>$(W9J@f3spp5Pf%(ieGqK)d!SGN6Un-!M6f2ue7W0_F&O5y zIb#Y;CbT%li*cQ~KdoTtP^rAGSe33Dwta`m&69sh8CN;3t~K9Hqi%*K3{ezFg+`HS zscnyC(ZD*vY@Ymqg!coxwtUEBoaRd2#}>Rwl)-|UAxb^W+w(22iVc03SF>6%JGvgC zP{3Z67}QzRMHGQ+nmFR)#+g-ipUSjsnh5Vjpwq<)bTWY|mv0iOYh1ivk|2)d9@{;; z;7Fz2oqFKphYWU|b-E|%C>#aI&pobGOCJMLFq|A0a%kMO*daHsa;171kKOgTcMVju zWr=>}SNkz@GFdryw(r;-YeHO2drCV&C`BgC#Sgy5B+CmOxHxVU8>2PKOlmrqRX+V` zp|J*cH$SE?Bi%m{*V-du9YC|KE>?%KVj3}1M2CMKrWx?4rm%Dl{zfib|Rcg@PSqJqu4B<8GebK1(LcNo~bF;~QPJIu( z?-}#C7`eZ1CLx-;sVsjTgM-c6v;0NMJz1$pz3u#r0;;sV9Q$r7)_ltcH?6Vcp(VcoV)?-K z?hZ8*w~c4#Yg#Ygb7iKAYc8Vk?cW)@cKdgJ#@B}meY4V5&dJAs#V;CI>HJEp{ zU$G`3UGEujF;@8}e=EusnW8`PCA2RFe%w@e2v@DEcoxBZPTuG<+lsuA<+v#ez#phY zYMJwr^{`jcw0 z?`9!iQ>kNQe;;O|PjXRS*x^Id^Ih43Kpb|o%Py0SNcr*S;mdezXieMyoc`;NQb$1n z0s_{w?5UZXzMA8j?;Iz`tP_WdJ$k0KWr`wg*P`WEqV^NWTXQ==EpNd0$mbU;@t**`$ zu1z+Ng{IK?W5_jkujlhAMqXIOS^i1_yCZl1s)$Ej*$L`#;n*IAH$y~nN=715^Tq|=uhKyIr{*vsJaUEd10g4t@t1Sg)q8QiAR(?G` zH@4dPHf4X^KQ*Lr;!K{BD>C9k-^dF49wpsC26o8gUCFuYCnfyiff9eG)Nq#u>E91# z&wXe-|KoWx^hSrVZN1j>Ff_GgkS}U{<3v{U?&m0741~Ja2bgJU^5$s)8(CUk-H~r< zr0^`H9o{T&MQE!|G?4C3>!!;wTQ2DoMI_7r6RBr-v2AYOF#j;=ruq>1YS@LJ3NI9k zz;WpH3I5Ln;2jj*Or)MWt%;P(%_kIG;B2746?{@OXc){o|FnqvQCDjaNIZ4Qg(z{! zaWZ*QSs=N-+x6BEp#Qjd;$rvv&pd5^z-!udeZO+lc(oD1a7BuM!D!2$Klbe-eGPbD zb3FCp3u3{=g)7CzW4%<#M&)Ex_eA(Mf*kc1-w2;=^zEwfK{w@q*D6aYeu5{9n&?At zKSADcB!^jb=kw?_KG8bz{+lGd{6iakfR=_HNC|DGb?jMLdbK*>?SUqxfnKE;Pv?3q z(Nh~tK<-Pu2)Lu_vs`?>p7>b}7=owJ8M38bh~zf{P@Vp9L^?!$KsZzgQMMC+*9BR;tX+NREoU;9wu`s?LSEyIlg>cYUE z0T~lMSmc$hz$XAJa6@w6mw}t;e>~z->F)qv0;&3PV0866uYZWvSX!!gG4DuPU!bwV zi+Pnb$Qxism-H9ub^*U_Y_nL@?hD_{+%00^{8jcl`i_Jx$<9C0!i~Nc$A;-Mgd*+8Wpf2()Su(}cJg7%_q9zF#r>THSMO1<{m-~&QX)rYM zL7Zh_whSfyGeaHeQm*-}FfV%TV}B&NrMB_DoTy`5TA@&@;A0$**r;oVQa{y)=yru& z=wf&xo;m!We04y@VIXV+^7emn{=C-AtCmivf4-bZe=UBdnUKKnLMBzTUV3P=HL$IG zdC*C5_uF!O(9=x6KZT}f8X}DB%Mn>KArSWxD?j=e!W%z#P3g~ z=x#djNl(r(OxBfrRUE;{bUmEe$bYwJ$P44F3Z4m}#Q9s1eF|IA^3389JCm|9S@G%* zf%qT&$5n5ArRI_nq*eoTRb}bayyL0(zb>pC=X}Wb&%5)dSz&^JK$`imZm>eC8AXhn zmgIP}^7U8lm=AEWvU>=?6mICx1s!(~aH2}3)jZf=2&;qmPtccb!q$UshD}Jf5${HL z@aWOyvoQTWUUNO<@{_(emmKJPKb!w=#^t<_p9^GBoGz9v_E1tyjIs`wB^nkYP38U5 z4rY%Q1o@AYegjU}az>zYs8-39=h+U^_q@iv>DJ7`E~;Euh;e=;L)7WWJ!zLb=y(9| z&+mQ2Q}j+9MbQp)iwL{%50MM(bpJcNtiBJa_ihO|4Cp}aDqPERE)z}E;r+}r7=LjH zYD@cB!>70O>B1;}A`JApP!uh&^t28Bc6hrb_(Nl=VA}dFt0XZ+1y=W#gE0!*77JYF=6kuQ#x1Ku*w9RlGXMEq_&4B=nn(eJaH4@M-Cxk|$RMOjRUyub z&Q~PNocD`jen!>W`^50|-_5Vg_)`G7;3Q}w&;eP&&wsI1_8YN#`f_cP2dBig8ZU8| z(d^y4HdT;Zpx}LK&jq4~b8`-Wy3W=Ho1C4@-Xn9^@y}=aWYc5Q>8t!Cwpe%15Ac_+ zjT_(%iQ!q1Ipc{cFC?;aS#S|7$ul_aVjK$h6Mcr%2iWK?^_o_6M*GV5+?6a7%z}em z5;yg9s(crJa`L(?-xF7%m-5_^QLdZ2{v9busNk{&59lU(d7?c%D}AejcqOZ4ws|;4 z+7_$lD_VbycHZdNrPd2U<(^PPV>tilP}I5SksnCaX0DF~O`c8q#}N%3=3P5KE4cr6 z%GEqVh_Y&VuxG1Z->}ZpqA_I8yv9#i`FGrkE8jQWQH;0$?f;b;JEe<%$s{~9b1#`m zsHZfWZp3c)k5(EF&OA(TOQ=t1WH#v-i|Q_xiR|QOGFtxq2>Q79oG?0+bEiL}iA*TL z`9k9nmS-vfCpUaY18|BQQyDkc@k5@}hnNppGRG-mDL45|A+xAmH-}^g@#i9K@``ds z$WfU#K52b^9t%jNJc=H5pBb{txHeyCKf#q9qT48oEcON=91@>WgJWU`566#>0vL)7 z?VNAXsJdvM{B9d?ez!Wm5LFeyBtk|pisbh=( zTB1zliy9p|r5B&(dOt~6`utI_x-EkkZJ;$JK+TWpuc@9gq;~82 zVZh1#y2zc1EUlx!n33nMaur>p+3_C0!F!NZ_FaBEd@J^j(lVTr0m)B#q(=Fi{DKLE zWoxJSi-eiJqf?NI^-l!na>k{MpQ1~`c)Hp)Ig0VZy{c%@ZP<@C;t_sHHG}PCv^;C+ zdY`Yj-6p<;V^;$q2EjVzH1u<~77Z}iqsg?z>6;v~zW}Sa(%o*YpFQfHZPZ^{fU+YW zs+Q#|44pc&KOs*IhG{?C_Y>u{H+F?vhAhJ8ST{?vd^5;R@kC;2AaG(DQe6Q{mh;?T zC?85JD2v`z-p-UqHLqo;9mGm^Dza^J+ix&=02WPOp|W1t2~FO&cvuF!fmQ#|wk9;| zx!8ugXFc-mOv@6I6HLt;L9@gyBF_3pZv+jot3RgqD(yELn03kcPtZT;zgAe7n@Xs( z-rC6LZ(nWy#pw;S)v0Mx_+PoKbdqqE@|8~5xTf{PrN_*kh2p`meQ){+M9$)T6nSXq zjkvYJ_rYT!y@WT-FJl7+MF6W5ApfELFP3DAhbnznhcUtm~r*7V4j_w(VZ|yV?7paeMG$v{T-euoL*fWvd;<}JFY z*&&3TKEqV3DY1H5r06%GT1j#AIozq^V*kb`u?hu>?Mc(Sp;j+^(iujV5wNG;a}(EP zdDx{^t`U>8_tDlu!VR+v!kO5F?n1`eGfueH*gn4jT%aU*m`L@lAGQ#wp0QiOjSkZV z$-vg2v88NWyd-y*&Nd!Mx%#PD+F?mO&+0(GDq$91NJ@iyX@NK$cjkBbIjh7{AgkKu;xS#Uexqt1;xI&omvc?zxrc z_lueQ>%~Dp*f+-h!^AM52)4Cn?4z={%(rcvpr>GQ+5Yt7;--+7+lR+Jxe{C1JC)`a zBbbSGezB=Vo3l-GZP1NPmtAplBvWXS_^M`M!aQw}*V#Ck_1~*UQIK?^DqH({OjX@{ z$=aQ75_hRkTjRS*rm>oz0Z65f;jp>F6Q#UNYo;h9D~H01JEa)Y4%+b z&(2THd7Itmh!e$k;bRW7idOBA&3}*Qn$vFP{6aP6F>n>q%*}|e8>#okiQfXwhBnQH z(o4fUyn5u-satsocbqJ8ZPARHLD4$BmBzXW>azAkc|;(mqMrtX83LKz-_#jD_c(Tk zC=zGbm6pK3u@gRv9#Zv?Q3~c5&E0uuKLC8+`;-eBa?z%Mg){4ReqG9MK&CZbdH?97 zP>6zrE}vhwCkeIOpdq1ezC5Z^;n8e=P6%o`jgLPCUJ6ZvfWQL^zDk z_Po1G&F7OU#kk}%_0RBI9Y@s0Py&_MBe+sIepvs~yI<=xcY&DUE}&mfrCv%svb=wi zVI$;|^u6M3qxY~Fl4B3iiAk=Va6IvNI?LpH3*1cfKhu8A1aJHXv|evQ~le4tTzS96spk@2-0@cQ^+ZpR`np&aO@L<3>Uyw3Ti>NoD;JF;mQ08@ESq zo#^o?j?o&}z2%Qa1m%BOcaWNaK#%r7Z!N^8z zt0W0oo)ZnP8DsBQ?wUU?= z?$149y0unHbHz=)-C{im5yRNKJ_|Db4e;KakogTzp&hWM@hlJ1@#)`yV($VouBC(1 z-+{a4FqUBw^vb;X>l(ncB~| zkMDwfd@S060hPmzsNaCOLP(d?UC_6`fm;W3ifBU5Epmwhd(aJb@Ebt<@707Z*IK>b zfFDn0j&Pd~b=p8O30p0p*QK8ox$jY>C&GOrAbsQ&%X^_1^;fIbnZ@*DUVIMBY1+tuXHvddZoW1nm zOlfkj^aNvT{9TLoqtDfC_Zk7T6C9v$giI4{kT(DwOmhnUFRc6Ar4ux7RuPx@wKqa@8)h-|wP>ZsUv}+`u`apKd9HPF zmc!kk+w?e4iSPscf=R|~ve^H}(YZe|{r~TO*cfxz<}|0wnDb%ge9V~BMwzpm&ynO% z4kgVDW6p;ml5qQF51Je%_IFj z>rPXUv35QZd~EV<={;}RnlB|ED}8mwS9Cx8O+kDaTz@eCP3hIOyE}3}`C+Talh%gr z(Ju{r%^dD}$N0wj`ur!XaPB$M^v_uiVLbI{p6yb+PJCm{KL7K~hgTB)S6)0{{je)- z(IsN`n@9NnugG^M3%JM3Q{q^=IcXEnUZ>elI3^Rz5%C+y4tl@wd2(Q>=D(G` z`8qp9=%kNs+c(jpM2p@+^zT<&S^htKV%>kmT|Nr^X7XJU{qW*RA^mulT@APXW5Rdm z{De_pVsP@9G+lB}37PnvQ|4>CPdFTkC%C$}ZF2Vf%AXPh~w4%&MbLac;p;}s9;@qn5*}G}$ zn{&rK9e(}0IqfMSH>fM$sa1TAc#A9kwi0j4)cfD4TW_YPKWhgzr#r+x4NPDD`|$mj zlShaC+(|cAIj4XBwzHPg?yxq7-q>sf{!rO6I#&DdNXdV2(meg^zjgC-Mc)hyMgCj4 zPLDjey>pz`ye{x@D0FzOo%To~^1g7-HRiP8l{CW>N06HwO+XE(*8cN!Um(}&`rfXE zPoM9({N5mkBPWx5ny9kym(ESOt($LxcQ!AWuO%yEpuOe9_fz!0i4?y@3B}@lvlbae=sKd``4eNW9kU98+rW4 zKN%s0ul$G!BVg!jq3`P1-LE?qBg>B`^b7B#ylVKQvWM7ZPCi+%JdnKG$^4x?l5i07 zhyGvW!^*iOUp~hBBY@lCfZo`OLv>H}^@V?34C_k@*%wmJ{G3X9SjOvLVfQKoKQDZk zJ9NZyELtWzM#cXu<#UR3q2CoQUH&>ErerF&Hd?o%@;^XWiOBOpl|R|Jw~{{GdQv0u zd41r`+V0oMe=<5NUw3{UFZ%D$jPZ{*f%Ea<)*dXT%O<9(_eR-KU{>A>g*%>cOUJ2h zZ!&V(C+ynMW%r9p!V$>8DDLPLag}B9bykzufg`{_oAjob^9|Yzf+A z2%nO8l)~hV&t+=+oAIF^-&{WS2J9IcdE}wI6<`xzxCaMIT-g-)dswIZ;m_@Fu_=$o zk3&Nz&wl>)`yb!WZ~F(A&gE_S0OZ1+iirAO4;Hp|%xS+pRwt4?jfqLux?LA&b}oOf z&gW$D!ZgI<%WvPFx(zl#;v*nsI zWxUwX)U=wdU*^Y#bdTM5BxCutcRO++;JHZVQcBvzL-~Nfv`hAb(o@+MV`)3)W#5z! zQgXU%IH#rl;48@S+r}pyAD??^!iW7Hj#uK}7sMU~@KmAym%cm7-W`2M@jCzj@P7e3 zT^uPG8vp-`F?NtoS9US~KYzysILhCZr8jk>X=CgcF19ydBP1N#E0@GZJ`4-{2|q5L z_(p1_+I2QAIJkHaHJ8)@#CewHJ88!vPa!GHO0mS1GnG(5i9Rm__W3Mc>?c8M-iE)5 zdEwa}IC%Bx7*D6$En4f>vRx$4~^ZZ=2^l(L|1-H97;_zApHc{!|t6!$qas$v#_Lv&z?>T9HyzWh#$Hv(!_tt&l1VdxQuahnh z8Oq^UAgcL$f+gn(FCX43ff26Gx}E=>xOhw@W5?(~hacA9)2QYcA&AcNM)H=rjJvQ+!1wE2D>*aY0Qj=c=v<)c8|j1HN!*k z9{R&{ftC^33zp4V0?rW*j`bS-^k=UP8EM0LbiGA)F*k$dxoV5eBy$bLKARX!g;WtwQAM_9CP5rKd&&rBWtL) z)nL$7_j&@DFN`p0FfXYoR#*}{JvP07lG(sa0XJ{>Yet#o0wBDq?w1?(X%maZ!YvO` zp4_J@1>8-q=G+#(u_tm`+&FKwoH!)-%vJgobXv$MI&Q(&)*7L=bXr|_YFx%egw)W} z#{Gf;3^V?ojW`bkcW8<&BEN15UoADBYGb&mlI6h_?QTG1!1@PWC_nVIs=H~Pmk{b1 zyxV1Mr5E>S$`QW;%5HFYh*`A+MUE-d+`bKjrls9mIHM7NOu@n`+#l;D))3nEX8F7Q z%X0!mOPeJ5ow&N-bo9-^bWn7s#dzUSX)Bi~`W;F*s8DgCCwx8uGlm!!m5CPnyzGMg zlc#Tltv$NHG~xdPP?c^0Z*nfCEC02-X8+P~)4Oi)V@~tsNK<<$ex#KO{3#4NUBPtW zmI5nEqbKYo@K^Kg9kwvhEitEOl|=N?tnIRA9jL^12OrRq2zg1R-AUj?`7`5)N7CG5 z)FBKVSuyvA%+Z-=PSmXen`3=oyK>9SsKl;bK~M7 zl|bDSqLrggOOG-v8-Jtg?8$}3%>UdQOFUXFh-2^+#&>(mX`beT%`QUzgpXluW88_>x7}J~3R!+r^!CMZj)F{Z zhVzt>5$^|)tbL@Moyu4>H8^7f)zBrVo0UYc6e=sHCj#4b&av+WBlxvy8?RF5Rs@|n z(Vn}I!*F3mGpn{rM4MU;RVwwD(YPwX-5T-5 z3AH3))t+c9HTXiU8t26AYeHmbCQGHJNeF(Q-M}#3+Ppl=;bWUy@+=#KR)PAY9fNCh z^&aqXk<_cY9UicoZ@4m%Pqml~#sv3r?-me7t?a`75HJ1cXq0DobqXPd5gvy4Tf2IZ+p@*t&B zUfOYud=dxLtD;+a0Bym~8d(kBhgkBIZsRI|jXpvc5)zxUWMp83UoqAHXK% zR!vDTBMvjSAl*D!Z>ec%KR0}|4SGsL-G_O?8f-!8#0pfKltYstX`3GQ+I~-HK5DhY zGK-$-ObK|!x1wB+zV?*Y9@(*UK6|FFly_|?5bjdcCXkoyhAZrhzj4Q4I*V9U>I0ZB zj>P6ZUKT0jcN-OEY79v7yA-sYE{rxkrwob_EN_k69c|mjwxm#! zVH=(s`d*l_((L+*JvoyM8?iOudy0BP&(jqyKGAzqX~YhZf!s|MTb<@qa%gTRI{Try z%@*yg4O_jy!GFgtaMcl{m8~nb$zq-{ry7j{nbR(Xt8M)j@OV4P3)S3Kl#PU+m;h9E z084R_9~XXs)qZKZdEit9Sh#*q#!xgG1Z&oud_pYE3{EBg#0Gh1x(MMmNR?xSk%m6T z&iiTysub#vm&U%)ZeZo{?&aSZqpG_A`@zVSj$i6bp$)S%b;Yw%b+4#zmh0;fr+kdy z33ODW-xXHUbN;(yUWZbG0tX_2n$3_~nN^3;h4?!|(FP$sPXWaQ@P#+Mm0V=$Wm0+2{*Ob)ktm85X?=$V$>l2BpsWjtkSaj3y%9HA+GT&U&SA#b2pDf{GPnQ}iT!Sd#g@Y~GOINm2Q$*<1+qoJK@ zWz-WzYbt)Krc&1VC&$+o1hg+y-S1j{6eBEqXcRCHvyi6+GoGCGfAeM9z_lLz%mvxx z`gwg^?JAloR9iv<-lFs_ehiq)lJMgu27wt|yAtgK7^;{Do=9m!A)8PfHNU+sEeq-a7!{zy(#2QH8nW<&wl(%i7AQCv`3B zPRC00#pps|WldGi*=`VPJ^gv>sZlNlW42D=jdqX+{IQ;{8)E8u=3u5JAoBPjcc5^S zkmDJ_T~);JnLNQ}o()hMf)K=n+3W%^Qa5Ld`SXMG=Mjd>bPd!JW-3Hna4I)py%5Pm z6J@(>a&x@2@Vd9EFFCcu^KjH&1+&fCcwBdwmMVg3s^O&4r$4zJf(1_@bzS&xI~du? z+98O3neZMzN=0~EPP%@ZbxfnCFLFFnH{=@+pw^yEF)7@K3!HsNVwRQ&+w1w3XXRhL z&mdRqLGtKg-Mn9D#th|$)}5L|a;)65jD-h& z(a`5I z9C?d6l65m9mA?R(j>MEVi=U+4)l?`3#k*@#5{hmE)mNW~Zo1O2m^V6B4rA@J-1U8- z(1UJoy4W->27z4FMCI4yLSbFZhjs+JollkO6ZHS;GrLc1UREFjE>`YhDMu>#+%=;2 zm}_8^qcJYjfU5ZuBZl8NgzP+vFHh!fd9tLl^KL4*5PfKSG3%Y;0z>!;YlQC*dV3XN z^?tTN+sY|qkx^QHk)`G+ftRu|(6j_R^B^uxGe3?8AeFc>s4Zz$`3l{Nwo3}yUb%L| zSQ?t0TF~f%1R!BRkQK^CSB+9!#U1TEU5IF#`H*j1s7i~{{v=YC?^B}PK8_x;rOzvR zj{8cTn)a(Y@1~Qz$CG)CQ0-{^WNofC|Bd>Rz?u+{xv<=7Gd!S}_lt~^W!+n*_b%0+ zEx(u5O3zv;@$mNCjYmBZwX3O&!F3b?tP@D(r@%Mpwc~L|>_Zrdw+in~5yxhl_^nLX zC*+_&UsP)9x_;o22P00zoy2z1ns&OYoJ(IeJ=RmMuen5x^R^<96jV`paoMk23R?7B z=h?pH)`;g_!Va%!85b14a}44Xl0j3d6lj&~Q)st>AnN6uYcku^sV5yoSDzK@8_RYI zhd-ts`TLZ{-#TONt6c%8dmQ8XZ=RJ@Q413?-ZIGd;kLH!FzFJ>yaG)rQ0%N+RFi{q zf+?|z8t~hY>T;G^ex&}Tys@3T)7ydEDvcsgZi&&@CdQRfKCwoP9C`F~t80_`H8yBW zbRKPuXtp_0pBf$Gu}iUt{VBYCJoRijSS4W*I70czPMZT~>IiF6qGL2|pUjOZ1aY@; z#puo(Y$!5M3f^ZHu6SWz1?$g&J2H~>#G$3E>i=A>4KM~>cF|8JtilO-(|0km(xDJ+ zW^JWRtpWS8!VSz7hbKz6eN;<@qt8UJY=!V^rz9-m#h<~(xMD@!(@QBvF>I;MNC7s8 zZ5VnQJ3DliB-9x*UR_yr!nLK_D~!7` zfa1!43L)}*HQgL1BCW~6b*D&aQO~rgQaMx{`wsR4$}?)8cHqzi0JbGte5VG*I6-!Ht+ z2+V(;V~&Tk*|{r3;7=W@0p=~>1-$h{&7@4@!Ward3oTK)_6Qdh`YusSx7|ana)5K* zhMv)6w82*;{G^)sk7wcXgZ}>kqKd~HP{S< zslzIJ=G!@ud^?|h z6_*%-iu!?ATQGoeiu{0ra`%G|J=!F{&bGx1BwJAGJzUoXLf?wm5=Z;yR2e&S{G95q zXzf{NBbaP!*%EppCc^>6uqQzsY^rTg4{QxC)J41yZ;&^8BM)%uvps%{~zrq%Fi(aUM(3c%e>RWQPBRO&aZh# zgJncR%_MY&9G*~DEERinDu0B32%maT`Ngat&$A=s<+=Ii!K|VjM1%l(b9#$vQ+3G- zb|U0tMw+YsEo3ry<>5r z_;m%}(9y zF#{p%M*f=A%#_^VX5CEE9W$F1{S&Uf)7KhwLOlRqXut;O*;yVJz}kur-;Bg8y}B=N z`T|cHAqnK(!1g^|jh^)d=XbUqTgH5(w}HLHc|mAV6KlDA##%G^OYTwoDA;vo7|KiL z!%JVyId17Q1(W(JoGuxD9S99h$|g@l^|RKwKeQSXP|W0&^EhTStT@M|Y-LU)gT9_N92!pWV*5lZh)MLi@@XAMQc2^v@=eiZ8T~wRKgsuAzHYv777TFc_0(9BM%MJ5g0b^26W520``h2X7bkI&e21M~6g&-!nnB_W5iN&PF{X$#A2He9*o_TXvGcT9-+t&5@Ox21F zsBNw%LJ(dO2W5M}R}KhIRc(!74BJ{X9ZjNw_P9C=45%))iPXbkYgr7TT^<`v}&!_SV1NqfYRd%Ig(X_MCPlKWuwEo`=yXIsAN#raD=u3RrQ{|03 z5Xp$vvW-O_imWzQ5jE$aQ2SgOyh&JFF=VTf{-#p*dCz|=afXlBw<+tO!P7u1^oaUW zu9$VguIj7>Ue-oUvpcTkc2~hY2KiMp;&=P^m8%${<{2 zg-^4veUgEpKBXG z6>QV{@>b}v5am&mkU~dJODVp?%zIHDB$$uvQZD_F5T_Iexz;LU7bn3}`>O4C%S?SZ zo3?iOPd-Fr!JPN-Y>ms4kQF&djw8qVfzx55MjIdOV|hn6JYKB=PyappJ@nLvU=Sr- zg}O20&`=o58H^gi=vx>o@VEm%`=X3`?XtUzwm|%Z4w_G|!2mPe zw1~=re_U$mu%ZT!z-gm8BoT8tjzU9fQt(b;!oqEk_#!@@(JPeYZC_76h zea`Jf>A=wY-1|plk4D~UU&E}GK=P4lOLf0(sVFa0Ejap&QR^d@MrAwS(tNWVxC6M( z!puYjYNY1Ts%}kij1Gj-ZrU7&Q-_{{2Z$vvi7z`0z+LO&v=fG&nn-3SLPLBEPy%hT zkz8MDLx=xY`VPK5405Equ8B$v_%{>*7d-fHKO{I6CYi`|xr`}6*eKDe*61j5N#y_( z!|<-qE*@m7!vl0B#KPgFM$~rpEpGy>x|D3~&ZP=vdG7&+9=c+hUvp3wTq+i%ILVkj z(;-%cl!=E4x1<+|NG>ev|2uh;@}C?F{DO$*x?=?+dF3Be1ckJ}1VO2Pksq6|&J#o)!NIdSd0+W#rAaZ3+e- zYXCRpiF@?a2_LiMaJm}L5nAJ6{t}`sQ;z*P&0o)l@81aWyA@;k^j-^Cen;Yfd!_iL zpTpsa=RrP+mOU4VOXxxcKIKPv-?k~&;TC^uKE*dO<^+|dm6I?@*df6*|G5zQAxfYB z4_z_rrBJd2r^|cHf9%|*)ClNf1a45qWc=F^s`7E2Umk??dlh>fpvpkZK2>P(xwDTG{Z$=<}97wL!l#i z6y&Vg_G%nrDv$BiU@C7JQK}C@bk4?rse)aSB%pM-N>ym^3F2}b&S;6Ht7byI3h%wz z9K48gvdOG+X$j$;mTG6y6vI%HYFfA4W}E|74CV(q7eg<>sXJDc6|TQ4A>=$Lf1IYS zBUlO$PkFEuU~60A%!k*~l3eP`jgwt!cL)d(6uSC!!@X0DK=XITQenJh^5odKgZ21O z0&U@sYD>#QbzF*#RSv9t;X?evo$|Dl@gUEttKnfCP*D8?g%Kp8yx8V?;dHxr++KBF z0u^dEsYyFUUJ`CCumK<^Xy(nG6l2FtEL3}I!8p`qS8ZF@pX~)TCpcX5CV>C7u`+z$D*@kMqJTwQi^zUp zJ4@U4@#Scs3P*-6eHb|-M#~poGknAd0E#ttxbNDl_Vg*43U(GODH%#Aj?j1PUnd9> zt8+*l(?8VFTb&%w(FMz5d+0)AWnV5hk$3q95*Q;a*d#S(&;hZA+6xZoF99|%EfW<% zi#YXApx>qCA`I?!{Y34gPiQ*)YGLobi>=*@gs)ZE#2RhCM*cIoJg5e$-^;4BaY*om z3()5bQJ4$kg+SOeLdkH>$n7Rs7<|(8ue*%8n~DfZp}*sIO1Zc!`y=&J58?n-2-_G6 zc6S8jxm$+EU1G?CdW}cj_W-AibkFaC#MP%y0YLHrvSRygo2XY-<_Zw5YAK zc*dapjG98!pc4Z8gjP3gA3rpAsbB=GX$_=k=)c`xMsb>A7f6~}e#JnrX)HMJgDKt1^~a%g3~Di+ z--4Co`dr((@e%(3evdNSH~oaJnfis2P@K%~GC|lhN8OF~Tiw%b6p*ikW0rh;??SG=q)D2NS%SIj)WKb7h^YfB1qmgFFKl6n6TxGp|T~ zUG7s&R|>M~H&L#7b&%cXIXSN-`x!O?oK<`AeppeZ-?(tOD#H`-tNT^#W4?V3&w!~- zn`*BxxU4nclVn?jvStM4c$}i+uBf-Xif)tlkvXC{=&hE&W+cEWcrBvTZt8S)gBtB?6&E#JY&3a6Iw3xeP6_*MU@9z=NwA>Pz&+R zA86f8PcnH)>h5XA!P-aVknLC4Nx+bDho}qM9OVwIX%<*Qy@m6V<&e{SQZ>RE$kR#g zMskrF5nCw2Gg~AUp`e=Pt0o_-c)n#O321`gaZD-h$e{E4fU{jxDeCKa*NP65PM)2+ z692J>ckY^BQ`o9i9DwFnst_|SOZ!%yY*Ctri=N}Hd0^Qj46?FTtH+2fIk|$5Ar-)6 zDo;l6PgUV9OXF%({m_c6BG5gkFK%omQ@M18M#zVrs#Yr!%Wmr78IphO_v-9tT(-NMIEHh|nO zfQX%=E}T7mO!-??`uZD-YPt6C&l?i-o_#MVQ^A#<@=GVfPH%9dZ|alvEAIHnKT}M| zgo)hKUOFt{TGjeDvoc+5A#;&=oaba_F=sev$nMGF%?uL^W5^y`-{BoEgI-H^5f0(M z4BAL_+3_}LwFoU>u=xW@va2qD^J;>2GUMAS5;fSWNcZU$yOM0)SQWZX%QbN|8uPlmgA^r}9Z$2YD!-Z=}}1f>JoGAKwRn2(+= zpIUI2>Jx9|)}X~_PDs6n%~Pj@8`x{FW(0X?-0q4QK$1k07Yi!GvygxDo^TPC)_a)_ zemWh}*q+?;IYwaHFJBxC+Yu_tYvO@;$3+3qU>=uMMBE{FvCS06#X$tyG=DP@uq0Y+ zw28Q#4&|mUL(h#mEL~C~O_Fy0v{=mjDVj){2(wdn<@gZ`V+PzLoDKEt>-BB7;P0_c!Hjg3+hdRtf7mZ#)YeO)o&!_tR9oxyXonU2cn40$h zu2yv)b=_fRG52*tEwE*-Lg2pP=-i3y>tU;5pk+T2ZBqJ3M`*BC;v`8*JUb4fltRV| zvR$Rh&n)bpbm~*(s4WEbOCOb5O}C6AW+9c3%-v)9dGAJXjYzv=!R9?!E_Q^j1lNwX z-31dO{t?(+$=r}6PMVdwa;&=pR>jC$fD;}wqZJAK@dWBADg?tmtC}I5tW(%X z%tb`65W4O7Cctyf9MM`z9(}%H4W`NhKNggKqL>``a_p4O>~t2k!eUPe z#Rya-_`O7jkNQ2j{7-sY#!aNq<-c`ySOo1uqt7If^=x1iK#I#e^|rmr zBj2rPBDw^oyH*6~T98K7paIHnXwD6xp3^hPB=0$m=oi?E!ot5C-%lphJ>h;87;4td0Btn{%98g3uQ;* zTRbov%ie=ithd%dzUbCfh0ZoOH?N0!30Xb3*>T}+`-;=NeOG2fffrWd{1TAvp_e-w z$?)Gfi5SOgKhf^ycA=Fxo?Wo&0`CfMLL zDMFL1Y5o~;RZsm5t$1m37mE`Sscw8BPYt!<+2Qlzq+eOnkn{#ktTrGct~ya85g1kL zLz61KI_QV^j=P7KB?@Lt;~K?@SN^yT9N@*$KgcuBwl+NLi^~j^)%8}ZO}f}?9Bvx{ zpw)65L03lKGS07oB6?muG9ma`juxj=*O0K&rJSBK$pl^(LY zh&En7iyc@=!REsEHC_R5XX6G*GxzGGSNqh? zWG8F91AJIUE`TxEW*dOHt@d>qFAeL(H zc8SFT0IA2cN9rX;kegh^}hSZHG4c-6IYJ0xs=*&j4`%92p|nz~@q2N^p@{CwHb$ z53(X&H5s9Y5^8QDb(1!HqG#-sK<7_vJy5ZY$f*Mh~X-; zmJj~wnpaB`Wcd+E!nPfvm0a6GhqB0BF&kP{%czWCq6Ts@?O}i2k&QQpExh&8kOSHAHnGuO zl5@6IO72g%TRcz^BLjQ*iHgodozz8^C#%w6bwRcn5`^p0AM+Jna!Gu6cYr}6B&Inw zK@UsU6UribA3&oLs?Z%W)!$n<`9zrQe4IJ}=Y$Z#tFSd|V?0V5^;x1+TV-;d?S1=$ z@qzK7@F<&D_iUukPHOlAE8%B_0vVz~i(VQzkS-<|aN6M8W5{pvh1@6T02n3AdoBF7 zShVZqany#I9{S&~H)EcO6y&dKQNC2(kQ44me~7Nq?QgX1kseT&unfL;R|*VuZxvqIT8mXe{O{gGJV%co0Sh1(tHKdm}zHEF64;EgFne*~99X$?HB3j5-pvmG6* zW8Cn!(rk3+o#7Q@ek{p2c&m%iY4wWyH@#qS?5-fvm`_uuRA`Af#S#-3oM$*b<@>r^ zo_6hz?I~>HXEpB$P+3)@R?;zX6Au>#E5$y6@Rx|T<{Fo65x30S7gldj^qWhmB^h?LIGMXDNCwHZKZ?97-uSLe2~k1GsbA`#Hnp@fq1fPS9vQ*CFmrDcn4;98(W z3PY!9S6Wo-r0yTljG(^o^^m*l#Y9LQV)@(ngDBN)mj=*v=(vM9>3A&R`aSBvsWE>) z_a&Mq{L9scPgUPt7ad*=aTR$w(&sxgs>yiWvgsvnURunI&p%|F9FI9dnD7zgU7wm} z#B^JGUnZ~zwR!Am-sU~;8*jX|vcl^RI(4j7QC=8a(Hlw8ZXStcg^oJ1( ztrP45O2pYj5g&U}1Kag4p-JvtHyGWltjJ!>O$20BI@^9PQXxR9+Sr+HmUb)rCua9E zXZZVPEtbX>Z6`MT@0fwF^NUH$hH#2orPv?h#d-`qs}lvT7Vv(mb8_`D$hZS)S%N4B z*h?g zZSD%Lhi2tH;Kz748>u`hFHo>Ba|Kpy?b;|Y8qJM-L5TCy5f^Q4>t6K>@{`VPNtZ6A zxNg}q{o@6%qP#m?XdI1F?+stU!Je^Kw?Z|A*LB~@p`r_x9{jaQfAwvmH*&1@A+!)i zIchkfA|y@br_ZcXW7aFNzbo90&;ZS@7#7lXN zSxhaIVz{mU<9`){; z2VU&!V7kP96VDe=jzraIAu%FsLVLJ2BJ4ly zc;!S%l9z&+F?GAGor1Jl)GYnN|6DBWZrJ=2#r4Q)F*R9^`dhZxp%5a&p5?_Yghg!= zra|A&tXITT-5FJ;u_V33v_o6`Wdsj-_fmH+0*{141 zD+F2ICF{rYT1W=iN$#vLMwLDj%9l(iC2MA+8NO2xXm_b%AXyC#n#J(sViCcvTTnP+ zwo5h4@jU1mxY9*U-3Z(-7i0$s52GzHA9kxilP2e4nuGd39w4m%a?q`gS9hikjlS%B z%PbCBLKq2c@ZW&q+GjD{XLf{h&+MpGjEH-`sCA6zzD{0SaCXufu+aAY4;G*``%M{^pbEax`cIxdmzj+|^*=y+&9C;y|5b5QS2EIdA^@N3m1Q+AdpRbEaqV<^+MD z1x=AS_2a_-TAWO2nc!OGnd#sOoVzWpEG?2p9MWuwgFLl3&h1M=@vsGs5@VtPb_0E` zekiwSz`h)8%Sm|Utg;jrcBr&_wwAgG$d{xb=UyM2ND?{CY4S95YgVMfHiWj4(rgWx z$xXqN}6|>|$iGgq5+~jdxt{O$eTN3pShsxP3)+memO7pvN^TX`8pQ zA7Z#*sTt}JRh*hF@uaD{i*?RO#@2y#I0UIaUlJ>(n-B#VEu-4^oD(V_-IVyY&Scx? z%AiLo4^Q6FThHxlPoC{N3@aVovgFQ;yTY<+>i`rC>sR9Yq@fKOd9AH{RX?H=+wg%( z->xlawVeI()3kQ^4<(QkvDOd?e#2{U3;qb39(F-k**`zKzOf{t#a#db|5O6Yi>&74 zxM;GF9$GSF!-EY}W%HQ{&8Hhtaq5Z={WXKXnb_hKHHvY_qx6j?Sw$E?+M!?_*QFe! zaA7{q=7XNZuri`+;P{nefjqp!JV*1kEj>Pb%a?*qQ&!i{^*-gMTEMTXPqU6)Wv3iK z5Tx)gno1exSOVpTXB)f?q~TQ!z`2Wz*B)S-J)T}SCXyK;OQT-kQh6X%7%3GP#0K&(hYy;I;tUsb0{z9U9gn!{S z>cfE4()+3#ddz8Ueg}ViSo60HMRUANaHG&t!@Tg*enr~d5nXnu;3XdY({jC`zN!R~ zs9mH!;Jm$S_4%gN;OpZY98X-Vtdp+K&cMZg(lCwXqEWN5E7GpZVE=hlukbFt9^eP) z!K=F*>1!UmK>eOKOFGX(YZ#**dvd(>SGDq0YeI?8&12x(n|g#W@ynz3%vQOaM}6x! zJaz$GB`!3&rQ5fzK+^s1Cq&Ch^*Le^a2x!cH>uZElZ7~C<35s${~c$j({{Jrme&8u z0E`#~6ibqp9$3$$+}+7b=Nsm>vfjDMR>6!+uSjU6i7;R5;-jT0`k{S>6mK;#!Y|&# z(v5X$(3;!}!0xdD3H#y)74dtDLP56T15l)-YDsCn)CKpxD{1n~T9yENhG~(EPzpA_!Q?KY1O~n1KZ&=> znV}~eRpK26aSSe!WGWU$W$N66bJn42!u9#9>oM^ijom z!&&8tpil6BfqL&3rYrBxsn?9`KIkKTJ9>ho$#8>CK>hlam92B&ZKJiAlNDZ*Q}L*^ z8pT_%F}=|}LGf&7yE~`Bu@~Yhyds?$9~XTa0SS+F0Yl|Pr%$Vzx$e@LJ$tg=+gz#= zyC!SWLwN60^!~*7or1G#%o9Npd!`YnY=)42w3O|=pggW62luv5thvx5p;1NkbCp82 zi9t@7*+eJ%K5o>$ve{!n8D*4mFyFoYjiXADJ9w?>CDV4D%Th)$rC)a^O1gv|DiS|T zcuTGXm(uHy)VN=uOs&kgR#DKVB3omjFI>-r5PG^j<{M@et*DtM!tR$i16G7ZOC`%a zvR0%vtS&ppt8aSs!WxQs)b9A*bEN^hu%*KoX%^kkqgYZeEL!lWaCLm?HyK*5N>5UF z$O^FMKItUAQBZ_`z#|J-dVuNnEKfToCMLj5&Wf-5W=b48;Vt2EB>pd{eMEuTt#}oq9^IsZ)xrOf;cOo#ivy z*eIAO!Go02s50tiz=vuyYzieOv0qsFX#A=;KCmcS{$BYl9iICl)RtNGc z`lUVmpc5Xv`sqfxQ%7L`6X_civHo>_sc1t|2>#e-WOs~+!IBAOTlMZwt%)}#;5)7L zd2TDV1oY(|Kuz%g_9y%=s?Qff_6PBpkFE_gxyQ$67UB&O&&d8375~@3oUc^OWG@=G z!Fjuky~6SX0=HqkvPI zjLmXQmPlqPEmn0+d-5^AvA^2l z<)>rIOLycl1)Ixnav7Xx&E5{cNHAUH{zKn8w<$3?9L$-qwrRN^B1JTJ4js+7B0GAk zL{Ly63;6Uv{1C5SG@4?);2>Y3$=LR9nZ&(R-}=^LW<_E53H@532f|>Ty&W*x8p)kG zl_tG`@K!coHvhjQUeKhFop+|*OMuZ* zTc!^<>b%N1EJKu7Fnz;~RYWbK)>c&lL>7eAJsLn#)zwGCRp=<%pje!p=2CdW>gxC` zG)jUat<c^PS`^5f37zI0yq=+3*0R&l66kDE~ztrtn^!5 zrY@dUsOy9=%AjrM=8DR{m+SIk-|6QaKjwDxATC#RkU$-8721XG^JMHayK>+iEd%+q z0FHmXTeWYvns=_XC(jaF&>)K>NXU&Nq&YkV8E0PMc7MQyJT6cSZ76&L-@uubcL(X{ zz2cEH32pS<0O7v!Yv#;iq{HJi6!Xl4k(1_5qQT1KU>7)D*uElymT;bg_Mp`o+GcMlM@&SeEI zccKk)U0*Wz4#U5<{_i^yxCHS?T%)T=8rwX#JI)_rHWIDIA62z$sc%R|v z-f((>Y`1E;w*1K92YS+ASAcRv0?FVVh+GaNf0>`?b&{b)9;bKYy%4Sz^5lv;mer6@ zZNgKO&}so}O$HfcO)ge1+H{&c7v8HHhykbOste2|6}dhUnSX_X2-%*co#sGK1YdqI zPdN?syAdKygN(S1^lW3}#wBC=A?^4Hf!;Tl%*bOs*MN>>yyD$GuJPjYpS8nU+$(t= zSJA88p8ctUNgq9KrhA9RrgjAaKxwnbZ_yDGg8V=bq4z+51w8<<-9LcRbW^sm|1k+n zt-@7m{2hMXoM(u5)gik_3fJ)8tHY8O{9^V>bXeX?8Sgpgjtk$fjK9k!r@=q0OP$lq z%SxN9ZUqqBS=u?6Q;j5FA#L4c^(1IXo?H8dZEA*12+-eki>Ae(%iyTW^YNvn*)Fbe z4LT$ZGCAwY8-986EKgrw>4>P~rE0ug1~BK706(C96F>}Fkf}vaYajW9W`VPrz4=}3 z%|q|?0*^dgbMx^QvvU~ss4ZC+|$L^CYoK11t71Q=?Q5ve$99BhnjcMNdrM2oR7W)4h8CIP0^H>+%bmFQY`Acb)U33u5J%->=6EbDpWYw7 z-+uspxbOSA&f`3f^L1RlK4rQ-sHlm|9KISM7E*~a_L-j%v`+P`E9fNC^q|N7eX$p- z=&QSbw;zx0IiCatViYi1w71gK-h;S=ppyW~&Nvy|q}lN)*`9h?n3 zhto5J?dsu-P9zNFV~OFt$Zkk?xG_0~(ZKS-)|2*dp~24QMch=VptL>vs*j5iuYMCA zSa?TiT~JmWPhng&rbJa6$+5lU$=``7H{^Qf5o{^rKo2d3W>ePgd;GdRqf*l3ooeZfmU zkbh-Em$(-x2nuD;nW~9+q~g*D?JzYjt4NTzNDyPM zBqLbEL95=HiJ2Q#6Q%2>>UxxNh|HwcLlRH=f-6uBHCtg^hL!g*`ikfMFu|PbzNCPy z8Jil4AJSr``i;qtOrH5jo|Je%!-G*df`i|mIHD6jhTMTG(mmvHF>8S;p%J@L&Z_Pr zZr^7pRPkl;_g2-6Otbd&W8Qc+=I_Wx{H1@Z*%w{@U0%N3Uo6X%l$E^8`ZZQiL;EDp zGj}D{ZN(!-`&rnEM^Vfpf3$#qxUI}wlCFnI8)M=}8qqiz&#lSm<%4$|((=v}B<_tQ zYUMO5yv`$l~ z*&XL{p0n>T&5$<<+@*&vhB45o_hhb(S}ygC5YY@|b|&%MQ$$uL0a_>(T-BEiy4gZY zM&?h|(A>#|&v>Fs@&mGLZ{38*+L_Um&m>J#C>=x*H60_Gkfz%-HNrFh^1D(&+e>59 z$qV16?CXklSAnuzE~^LuRV_~|Es7CG=jNOWC?e=W`lA==;tgO077J^jdqx*adpYc& z`0B%BU=P<1T|25RiF8BRlWnj(-SWb5!PmHgh9mRF6Lh2`=hA+hCAEK^78 ze4zj^d}@5pChA#`6ptz~zo`U#4#NO6QzE6W9}s;1a>iqDCopMcuE1{(#&jilUGwT?mm0b32mnmmi< z;0Q29u}MLxdF@1wyDHBrYPpF%p{yC*gpEL6{6NowYkr*HDm zLh;;y;<^W%B`ZmoK*At$W&m|*RK)*ulnd{cq`|lw2pW1cGa|X5AWajPlb=(as5$ z!hRRwRMYw8aJ{n8YL=|9A$IlgAwD5Y`WSb~1#Is%GW+H}y1}4Gv?1~XYC0|+ihbQr zn0nqLc+*o|&K$I5R+@%gkgY?uChDhLC)TK>BQT{eY8vkEu&lJS6T-RIu+{$qpi+a* zE6T$;(-FzeW4Dv4CH^AqyncFhINUa2?N|}39t_cA*_v3O7}l9IAtF=5u$`{aVSw?@ubO|40xNGbbPMsU8$OjbvT}#v30a)R{juyLDzqaD;I`M$ zrXPqyhr^#CJj<7^MB)*Vdtdx^pG!>{S**RIINmR;kAF;NJkToD>lq>emG=ex!;(QlTemyZ({pyrlMoqID;z>u`7) zT3Hrr669=hv!=n^h7OpLrDvE(Aq|Z2$unL`=)%#wValpSR_8@E;e!T!+cA>s0Z{Br z1fOUk{ZvNb_MP?=GirY}31i)L*Cb}8_2GY`F_6C!t`~ZJoHYWhPvDe|HHbJ*wxOgk5Y)*);s07;gV@3HFG^yF&~uw5ICsH z*e+fldRD+E^QSW@km(gG(eB{1hV}%Q!{QP}6BBu`>M6-ye79zhNMiwnTDqFEMfrUL z30C9wxK*6UcX>v*{?bz;{%$XIyWoWw@8AHIpr*IP595a{WJt)rDRQ@WHTkqUK_MY-~s zKtkrSrq3rN`neId20+ztB?37O`7#T&B9w_-(}`s>hW-!zRS~b@Kx#!{r(r(m_bWK` zP=hYb(nfB0HBAw+k)3FitptS~;Ndm3=p?xcmZ-?B+hnTjTM3c>UR29*#E~fP&*cW2 z0s|Jcy4>&XEuH@U%eIurkW8ghj#WZmx;$;CCO)KPkG?1rUh#dlgnH;%+^)@ajqjFt zi)UkD-0L~$&1^!edLV9W{f99^ZfX1sgM22_vkw@*->-Es;&CPX1J=KfLhanWc$sPx zWHE8;NxewWb>v-}8C`wt2n!W0Ct3O4zcM}3;%sTf@|Xb&s>^uYYnao=2a}gSLH?ss zI`=Ptb<}tT*yAyZSNL-tZ+{0pHBj)ouXRx`^Tz8HANcmv9nF8%XYrM`m|A_th8{lW z3}*h@#?Vrl!4gL-f>-9Oy3&v)iMJg3uNb9rf6^#AdVZ#$|HPbMZ9wdVD_;s}8UVIK z&KoMf)O!8=c~t4K$`1F3vOru~uzf$l`wYzOoG)^J4p4H3>v@-dSh4B-EjQCegoAlA zhtd@(KLC&*|9XS^{%$>AdbRG)0I>Z}KI;HyD@d(U`sVnG7 z=JpIuSkNc9tagNRwii^bY7w7#rl*^fL5!BXyXrT5c;uDtWm8_SNgV~eM)i8##NL#< zgZ9m#pL6I1kI|s$5P_Aa@Kzpwht-t0=Uj9(V_^ZovZf2kp>^R7`Sx5Zf^Q{QLUWeg z86p913u@~4<973Z!qk|sE5NAuI^=6fQ3u9YW5un&5uE-inO%fS-~7h;7$+p7|G%iM zHNodq;&y@7Z=iWsfWWHQW*ydFchxD^Jp|Zp{9jreu1G86%(yoNmdw4Y zbg>Inn$4onTC=mN@{Mic10numzqEd%YaxE=_GQ@pKgBBxexSVy8JRUQ_hCy#E9Scr0G9T?z>U?(J`+~rZ81)Q410{>A-qEJ1D?H{uk z7y)A`Hi0qjZz2$d!5A4%Sp|9;&zTd}YIiU1Ll*56t!&|T4ut0JA%!3?xf4;=v#N)X z-ndk@4R?|U1%rgHvn#NJFO9A`{FImvC!<%#PA*C4igu^Gi4crGeA`tvyWVo;y_m2} z>nJ3qz~yE#q5X}sy~qz7Co;=69M0p<(JWH@H7=ZyB}{#XSV%)U22Z-^tBY&CqvY62 zZ3ces_rK|h)cZ1Eox1B$<%5)v9OFt3Tp0?*+p?OomHtkDw(sK=EZ^@>JuOnl%D0@r zA4!*9x2Q2zN(@Y(R(T$;TZ;2!MRCiE+pBptNyqK~Sh-1ftzi#AF~M=kbP0QDuFbss zwufszb+?(kh0%v}t!bGGnK|lHu&LpLZ-y1Tn#D`SceO~@&sV^FMk@dV)joUw&S+@( zzc98(BGX#v?C`H_`QJ@h3TPtTzD68+BZ+d*#v~|+GZtw25zpZlAr0BfK-7YQTSg`9 zHO#!2c9swUI?`rJN9ZD3&73$H9J9~nM1O8JCCCr$;xSfdt~tn6BVlUZS3rw<%8EqL+V#H8>#Y>?_?&k^Mw ztBL!WZrein4vV%kc^)DNhLLqi<+{8fl5C(rkKpf-30_sbfnLai z=IQ8P=Un`gR-Hlw6SM#wyeqy?0`-cGIzJkb*Mf14;R4UmUd7ehR~0Ff-o@oUIy1RU zTHd2yR1oC^ISXw64*;7SKI6e3opLcWPbz#fQLnavRR>zr*2cb5f~bcKqXV{2uqV}c z6QZ1qqclqefW%fAhfv|baF+)rlu#BbuQ>4~lg!S&IwPoTpz>~)noQNaB6ejCCnwtA zwwt#}M=?Z0{itny>OY9hCj6^0=5wFnIjb0Omy*49#;Gwp>E`0#Ev6f(L}8&qU{g=e z&C+d4nf!%gRw|crS=hciDBJjUN!2GtigfhItNVkGO_1f)f$A#Y?X&?_1V`E{f6ni=q;60L|xvnb1*4z3rCl?y<$da%DNMOnfaD~Q-QW@sz*KV%xlPC28`ZW;H_;I z1=UBX02UQuUM~$MB3q6;HMxz;S+NHhd+~n7GpF zUIP0~?C3X6n!Y-KDI1lYSX&Zk&SqVA$GwFi*+ zaRygS7la@@d`ZSPJtLkk-F3b~aEP$t$%q!mPs2N7QrhKfO~mg{&v=YeS|w6rYF*b& zSfmNWx7eO)7nOLK+Wq3cn;NOrl6bJAh74G&B>Vd6=A6YA!nD;OH8#jqy)kOML{Kgc zxzgXF`eIx^qq=V=p{T*O<^!vjr+d2>Qf*`NAfrVRW5Y#e8xtV=J_)@oi`v+6oHlo* zX{8OM447SmdRz-^IXqt~KJr*#Vp~>b-x1}pO^ZF0DI9QA#TD!$bG=rdlYihOzGa(` z2U1r0smr#7uSq*BTpmFq!hVCBa~FyeisqiwKluRYu`A)qZJ1t1;(5o0wGZ__v>S6h zSxj{l_nfOj*LwD!Ol%dW)n3xq=UOG*;C@)|P?um4*O&!vi(%b4FMK4U)vpfz9{_&p z=9z{6M}5Fpu7cY%Ke^wLSmJ|OrO96hrZ3r4@owhknxHRg zrhZRkZ<+@;@W*xvZw}bvXE^*r4VJPjSALn=Wk}3P%$_o~mw51iZvtLLU`38Ub}W#X zjAYU>{MCEMitg71$hFzIO;FJjNSsMuNbd&~jw`1wvIT~Ke^F11@Us)Cq(8_;uHs=Q zxd01IhxzdxS#QE0a~B8LOM5>~OJy~h__Kym)6*39O9gI%#b2`PVntUA;cMG00WuNA zRX5}6OLNQC`9>O&RM#Wx`O4bn=oT!a&bm)3fjOt{oqssKD%kK37E|{4MaBlp6$x&R zw}j`(QJreIhHWf)68?0e8gLa};tKi@6>&=@uT(h9l}pfK`&fUuugu?JM?++L{ljcR z?*270sa2tJq&FHxEMMn?s?(rq&Nf4YD`T`#*E1j+?enNt4gHuFa26nxghmEfOUA>+ z3fy#gf_8A=oFpWHoP&dm6FoHdN`kzLDa}K4huM!7Zp~yg%jufAShk5W@+u$k3++Oh z*_JRvB&3~OkIj`SwdQ-6q-V3+ZNghooiW7;5k9gW^%B%t>E-Kx`ByaLrKK<~Le&Ty zfVq+mHS}};Rq}lD1I>+~ly~2m-0NTueW=xaC%azF4Re5JB>5+^Cg%{F3LlA`DRbQP z!n{)?Af_IMSPkzd!|H3@0wu1Eqo!5W1W9wK!V6v_@5`dN!%BeM`pwT_AJ;v!A>R{8 z_fQIJ>jT-QBZ2b#jIMCjw}bgq;DV0M097Z}JuxA;=T(5Gm zn>+s)n)xan&PXiCgh6ybr?yi?2Y6)~o=eur0Vyt42m5+d-Gw$D0mcA^v_?J z=ty^vl-^^{jBzRq`Zn15hDEXcV zvTA>>0(s`X!L4#U!`D9$TFmSKVL4$Jcglm+3`|hhi@-3@8jIy0Q3uxc!8qs28gp zJYtMnH!075!?lC7aN0T_2m83?MAn+JRQhk^!YdY=UmSBU$bkYXkzBgrp>Ud+v6q5n z8V+w!NF5`Rg<^6PYLnRL@Teh8LJWKE_ zv#AI`Kzxc>=i53SGIZS164<6LeN~QGz^eS^Ipe$k-d(`Y$&(?Z7(+mpmRA7!1rLn4 z4!|~A`HHXzSy%d_C)3PAEwaD%94Bth)XagzK<21oEylpaJQS`-Oj;{htu6PP@?ap08w32wzalQc@qP>KUB^%L! zG}p6-cqqirc))7Bf=`;;gPKzxV}=0gp(PuT_#XH>H#N83 zRkmTz4uAJ+p=oxbFES*thPM4+gH&e9kUp{hxtC4j&w060;~Jf*Hl;|Yjk;#D9nV(a z8q05_Qlgr&L$LigR2@zT`*tk!l_c#*@r&{t$6GxNYUe@n3+~FW0glihMq2lE`L4(0 zrz}tGE1~^iW<7n>=ZAN#8nsqLcHD!^s(pL!R8beQ>u(9S%L*RBZhZ)_F|MjSW`V)M ziL=RShC3HS*O3{nPi0C}AZ;XPL3qa`!EyP_D%wP11KNo63|-ojrP7GTor&{g)d zhB)r@(xt5!JlvL2a*yjCpC+<^nNXrM##T83+?Hk&;mp8GFmr}=6wkbN z=?8sBM*YdIkh@J~yHIUTNYN2fJ*lrdTx7j;hAdF#F&WAX1i9elnco&+#e*TvNK_=a zhx|?{JcFXxON(|n{}~*V`xolq(Ecq~wU8_Boz`UO#~ojeYzG)jDJNzr3Mms{B*&R56gaQTsmb`S-QlEr6K|WU z<`_Oe8+3?Cj=uFQb65y|%y99f{L8Nf+Dc>hja?ib5La!n_3-Tvza7PcogUMO*&G|8AW-f8G`x(cdK)_yafQYA09+G|&K*x z&bbr!1>@X^pXNL+=qvx-fK@f=*(X^tS!A!0ZIIG3RP1WhCOrehmvYp@_7^?tI?N%J z#Ih^H0PHGKZ#{@EI)oY*9g6f%K#DQ9iSWhAu@}tai<#Jh`to22@3$<2wS-aFj*A3)3Lvfb!*nKgF< z3zk+ZeVP5)pKMtZ^kDLg=&0Le5kB~{wa7VVQhd1Mr3d;^9USQhOYdOoK{}Uv;zNs+ zfu)-S0Sit_?%g87>y4C~9bK}2EF4yw7GaeVg~lDBDrp`?lJvlOgu1m`RzRbOC3oOU z8!b+SM!peUTNCp0cCUXZ!a_G-%D=>Nq9k}_yPxXn*7P^I2JgQv?kAHd8MKvYmk6Q7 z^s5$EUa$0fY0=-bZVjt0Xti^i)m#%SQS~L=eQH|!+~tkQ`&gYJlK!lT+e&-OpR{o~ zDu(!l@>ORS#g69KlBlJH$lL^@PT1c6GuK>tG=lbzDY>@dJ@~U&%?O*a6>?ycoLQx2 zGB~5MZYk!E;x?;DX=5l&Q-Di}!M%zPq%G?+=-2;30K8{CDmn%t(9d_0X`fd#%h%8F zq5@*45NR3TgXW>+woDo(t>O^)GSO0+T*PT3D>CKCE4%K&a0mQOJ@8~;>CSsLS+TXA zxwMrRL(H!90Veu7Ml!5^t1XK=Kjp=N1z(dCDX5Qj%r5(G3eT+j590q~`VWuC4thj9 zPtnF0u@vE0HLoxPNpgEx_wJ(+5b3?Y`es3)*=U5RzO_{VsZXHr?8hLlCn#RuQZpV~ z4Lpe{dOQzHU^h#hU5P;UK}42|rcYEVz=!+iJe9i+p4>!9YskJeR;I82vLQtxO3?5(xxwwuNS6;{f6&+3A3CeZuDy8auv=I7k)Pb?rZzQv^$fa>ew<^$<1qM$ zPjgA&G^2IR>ky{jsq0o=$s+Q&aw*z-(p@w=g!R38=99|M2v?7HAW7u}+Og7B0tsj5 z<)lgN25Na|6~FtMno*(2DRhEXj-!i=r^V0RE^;}m>q>B*mG8h?^>tVK#AIrlolU%b zmN)W*cGYq28gc-o9z8ueQUY)jx}On~)$58#rID<4*k~&%`7lG)4E3}qrJgghXHnQB z5}xa6aL1~pxlr7_e+h@X1ElvG6##Npa$WND47q+bYsftJsCuE(%}d}Ixa`DbC8b?wyxRG6Hx$XCAjpW$6$s%f(#=>( z2D23Sj-1I2%!=qlK>CU%i}}pQwxqKRxr9T^O{R3%pshS6{W=G(LQH&`=Rq{*tpglK^b-%jV3LMkF{J#Ai^tqH`VdctG@xP@64 zWTroswdGR2M5|EA@Qk?y&ot`SKiRhrMRh&ew6;jB(z&u~0lO?A(ArA0*I$L5e8Psn z-VDM?mGeS>o7JJD$#nnsQYgZEbX4WFkPhrtv!B}9?fQM?;nNJeZf$mc<)MCWWe(H& z^0nG?j&-?i8=E^I|4Uj`JIWdBxK+|fnqxDI0sP%KRZ={zf4?ZcL?AmI?-XruWiDtn zN^zBR>OuL%y{j-E%lci4=11`K`JG8lp$luelQqAR;jecz6h**AiT=%NdwEv}T!WL^ zE%(AH!$Rx3{3}()8fxcQ+RU%6+$r`H+bFq|1&|YLYq&1=_SLl#mviflt_~jvX<)3n z+jGlVsqMD5yH^e+;+V68J0oTUZ5pD|^z@3N!`Il>;3L__kPP?<+pXIs_nzviv+uX3 zi$2_7AN4Wfy>Qyh;A3KyhSH@EFsG^(ZBO8z^B>SfT|1&oYZ{6vz*ahIb`44%)t+rArG}}%DUw#QM^%ca^^{o57~<#hkDfq{jeGO4%;gbhb?+R?xsjeWl2~%IR}*6 zh_!!D5Cm0C3CmeGlw2}ToFY<=B@5ghc?mYjnHsoi41QT@#!ATDs}4hGd+LeKpA5<5Vu|MW8k3=j9!O`-;nnzn%*IXsi4 zH#?D!jY=IgM-0gJgHo3_Wprbn;g$s65r=Kkj6yEeOZkWQ?I<&0Q3`3XBXke@J7k_W zHhFkAZtcDD8!zi-f2=vw1W2Iu8 z0WhM~{8jNi5+5BpKuwHMpS|R_zBhu&#=+;~rq{2y79;0P!WOTBhX<@i(h^7vH5(_7 zCzmO)taE&f4rjiUp#yyza0}G3>CEcn_RzXOGB5M+6eOev^PBhK4Ca$C3T{DMQL$4Q zR*j0*RmB%7J^98r%rseLJgT1yuix}>zs61eX3)hgkS5Zc&URAbHf@s0nN>2SPIbg% zD(#(xwrijFKMb|@dUmbUd+j;KihCy}CDNSmuCVK{UjS6q^8?8Aeep?J@d9~Sca#OC z`~w`Dih47js@$-5PgqK!1R$zequ-rl^?3j{irr5>VaH{+ydV&uschF>=VJ1^B+U6U zone9K8eR@dt84o9uvTz_%c zongux)|i+ol+eDaSTmBn9!>v@t-{9z(3$BZ8y2Ew9EWMGuRmOIAXnWE|K$!n_@*PBqO$Y3uyiNR20>Zb3f7loA9J8er(C>EmkGqnEgh84W2BQ) zC_3Q&^9MZ#2V+rm-LX=Yzr5~OrgV{W_>7nA{MgU@_&*^^cT3R5?Ha#Rd)Fk!Gq=zs&6po`C89%CVPr3;^%#Xj1dkNUccw@ zyRhEA4pq%bo>J;Pf%#NogEif>5HbBMeJ+A?S0D%nKY{;5AcvFiZ#<*?HpaRSwOz&QA>$bc?r?b()Hq4@ZZ37$IG{|yBG4#1=pEQEm0lEI0D4={jO~_ zJw|aju#TEQt*S+9hX!n(EOZEVA|gKn!7d+BWem|tAaGY>98xa+WA2eLB{+6)A!PZ(o&&4B`2uM4U)JtCrkuO zXe^;t?#j9Rt6XZeZ-nDMaE!yaZ>lKbM34j}=N&lPJB=NzbfCyN`JiQt!^CY+{FSau98I=74xM71%S*q(X)T$B+mW&V^bCL;{T(MWOr zQG;>XMPYUiv%PsMv)g?jxi^Yf3o>CXOJ8J?W9&L4Yn?dEEvGS{0Xt}d!(O748m5ueXfaIzb%PPr*9*v?nL6oX=^*lV;ee?dsI(zr8e zLa7BjlcxSxIq(Vtyx@D>!qkjE&PKn0cEm?3LA+~bM^iV)L{#p?#8pbEQuWy+7? z)hitoIaKkCo8ZA&J$!n`U=jMWqR@?XBgjxNt|1k-c%Ejucuz$sI`K}hT!3mj8+gQg zaM;R-_jLl)y6jsKgLNtep=Q4R-6q+JEc42E3JDu|2iPlK)VJaQ%(ewoy|Bn zv|EFJa0e1?kdJ5bxK?gwR9^^|w4f((Z)eF!efxFU$>w&dH%BVxDd7#DIm^gd0Carb<9>gzr-&~d^0KrbA<{1f#M=$xGv@24_xBVxD-;WYdMM5=SQYq zl|nr!h#o1Ih>ohdrPh1oBvhqQg0=n(+v;0K?_n)tu5g&}mT2%joqXa;B!PV?{=JTx zH6~&QS0cvWs_M2E)}N?n^Pz>fSw3)n`lF$&^8qXCYfkuEMS2nBL2}6JH(ukLyp^g< z^V#RI47)qFU^h}LW>n4n(^+WI-Or3$>1KLYL5|FU(N3>4%TNk~i-BP<@7qVdfFW{! z(SeT8U;BIiCE(L%WWD%`hO&hFD_^>;Dm@+B4%VJU)RZ)>qNzxc)VEHV+bG@JU>A^K6yHy}1;mAT%Q%m2U$puQau;;l~MIF^{c=I|$v+h-dp zTo$qZv|GgaN~|}peT3og-gSs`-?jKoYGI3+xWKN?zmgN{Fo6lsU3hk+*uTFFUXUNZ zF1VS6BNQPQy2-<1&-s7SzDBOdycmzr#@=8l-Rr5~9%o-cr>aG_okOnon2MFpd=qSg z*Mt!e>+<;7SLSNAgE`Jvdm8jQ9dHjNQMNVyl&kaII@brysptRQU-Lq~ZT#Kf2)Lzi zdS*Kt)%pN$o~{Glk#Ta;3*eeot&LdOmQB93I=krYp^yd`^{s7;_>0(oZnTiv_z_`t z2omU@#ZJbtdMoLR#^}Q=c?2#Fs2p>X0onEnno?0AhVpZl>~4pqTSect38h_Sj=qiDt&yYuxexup1J|vdgBBja5lBdew1SQ zO3W7^wX1Jh@k3-ORV0Ux$$EWrO+$pgfj+d?rEM{4?HKD$C@50={#)UF?KcnE-+?av zlo?^A+GK4+@N{5i3eD&mE4j3K8XMSL!x_}Y62{vzCh>3(bu!1fEk-_)U!T1$#0Ylw zR<$`u$ao)A^eGY|cmX@SOa|hJ5G^5e5g>_h2^rYX9xvn&to{$98_1&V?x*zch{x6| zO;_A*?0|LNu-qqq)(qso0gt`DEiuDVf<7+0_^Xei zjc{<+n%<6hPglB^^2ZhP^ZK31Ip*P=Nu=OW?)!jGjn1is=dE%6Pq~I54eu>g$*r>Q z-N2Sr&y2&%MjeqC0fcn&RUhV#c?I%nhMFI=h;mt(@XS)&iHhNs?#P2TQ6W@QWfn~>@=mi7 zq$x2yzkVF+0)Hy9EI%1*+a692 zy48T!Z;Cc4v-Fw{QtNO#4=1JcrVp1uvM<)nXF@dfz0;88q+uRwdQVE`^N(?@ay-_#f8)7Ld&oDFS8^?LpfuqXcLcy@zH^Z6ayuA5-K zD+A<=Z-VD!B%HOgU`r4|(ui$w^A&CDPR_fujC_@?I8AFgNURz{`jH7%Dwuda$oH#L z8US@c;qraly5Np*(L;t42IE$<_J!I99*VuR^#^0f>6)^#u|fD#_^`eB6Eny;rz$5c z>W3$d%d`4o6tA)PwU*cy9_`~k`esgBjGp&&Z)2L~Z;nxua+L$)KR$Brk?fSU z*fo`#4Q5jsb&6^4vV{DDbbjPJ*8%rW%Uxl65qPHSbL!fh32OE;>HP;I?c>_@7 z={Bf{@(M;(9S`N9?mS$wxTVr75WycZi@jv= z6CY$&d7(_-M?s*16hkTYMy5wU))v~8u(JLyREw&mHeIm$%<2m%^>&Zz=O7`dU&u2<`zR4MS6BVp~O;rA}%_wdgp_T*mgTp_o zPgx0QkXqg0FI^f!G{#6{+wF~T3~5#=Z)&ZiMApegam4J%H+2S5@)hAQG&7Sft}mOnmR=#-M6}I0qJ`pUO}S9K)SDfDtd&-1 zJ4j3|K(#SEBsn+U-nc0W4LR#)+tWr$G)tgGEdDU`L{e?{%u zVfv5q<*sE>^i>PhDN%R{d^%qFW`uN%Mp5;luhlp_FRedq4%j~la|$UCJdg&iR0*Ly z2-D8&0sg9+7EVc(`y$U)4=_Fmr^=K+6@|BR)l6T((h^gzOkghfzTP#c`h)#!Gv)8HW8d;Gy1Z*-I08|&;v z}1)df^bAX}R+tvNdNTy){K?C3I5dmv=} zRuKk6*KT`eF)%k}V;9|5`u6%i>%#Up4($~-xAio!FIw9{m*jB)J~D!&E?i^WB?|zX zhsy4k3MUiIq5hB0^a>q*5F>Fy?mt4VKDdlcwBSm}(p#0RfBywJPjr z_cQ^#74NJYa#;Uoy$&sWx_o?-_sa1(IGxN+`Abd=Xxy#?Nl{HKQa9V}tM`23^mLf4 zGQsl)X4`zWP2z(!u3xhZs%%Ps(8iz7#d2mS{N=^7-aYp~lhwZ{cf*Wct;}K=yYHcMm*u6sx_{Zrk_^KcHsl%~vrn;EQD{83yrpYH0#1lui4hHv z*X}lTT2sRs$fU4VyK@fbOxHg3vCu~}xE6_9riB~M(p`YfT~GOh+G4*=Eef?Q0l-%| z_h?6d3fUgXA?{{D&UwSwlJqggJC$a`P70N2Spd;Puq z)u}A@si%tO)~q8E>3Tim3Y@CA8u>n3N@8UXBa&8z1KaBd!4*IzNfV4!AsU?N4cM=;0%JMa5|=-)S(W*pO!*7XdRV ztMc9^JmDht$w_tl11mE`&(%i(fs>^Ip65HN6;i!syQcOW@n*8TKM_z@M%;%bziFT+OlITZftSEsKV0E0fgc=)KUv`;w!kT2(dT)&Nff3tyk3{P&!l zn)YKoxp}Tv?`!Y7?Tf;s4(_DrG<0NyUtv>Ue9C&bF!@O9od#ZmZK9gTe_ctmTX((icBQ$K>dl4!6rg-Wv|5|G+J)%AY`@=3f^xs!y3PpP7#? zsf)()V_xjIe-ARxv8A`9TdZmv+bt=fJ(ks003YdZF3*cN37|Wnz>ke=+b$^GMc!Z4 z;~&5Cu>EF@N54HX_{BRfH3c8c?dA<%V$t{J;Y=6$di4+6m4S2_no~p6Vok)%tC^Z< zicZcYAIov=LGJjN8rQo6qEp5Zob>hjQb$`3_gXe@EXPfD1r2q(b5nb|%|2)EWD=go zLVXpoW~2i0NZqQ%DO8+I8z|(J#*96Lm=thqLg2-Y}(+uDQ}@ehwmrW)RV!d`OwAAoYp>4Q-Wi=BaKa~9OEE>Dw9xJp7} z{fECP5}4XgX`}6fi{hn17#zb8*%T-E(;7DsPI`>(uLJhYH21@%b@laL{wrF2BC4}$ zdC8fh4E;jB+$kDRvtKN@&kLuKm=eRa&ay-WDVx)%*srQykJdAA zlWMkS3X|O_;BVwB{@V4g1xKeiieK@Ca0Z zb^upGQZDaOx_&ydnACmpj@X8YdT=#+*`Uz3YI~JjNGEUI0-{)kG@ll4h{c*j%X3|M z<)>q7(>;;WJjn9>Uzi=ad&vptncs^CtZeTJn|>BtZqn9^1V6)`+|&!qShTvaC)C^I z?cB5+{?WAcXX&3!!NFnK51&^4#j~)@#+=l#AEo?Mlv9VK*PnkA-?r>q zTI=h*%t)_qq-bfZo$4=@>RC#Db8hnBv7p(Bs=U`*ODgW1cr{D9@OoFe<)FT{Wi#5U zR2Y_?J?v75607p%faI{0To9oj*1%~g6IhlQhU%0LP*GyRN(JzK>2y2h zKwarpRms5kx8*XvTsHSxxgoT%aTZQ!fc}CJq`>4PCG#qabQvS4Uev? z&z(3rE7!1S`m@Rp>2WRH=GHrN;JTBbP4{Fw{uC>);N=ML{{fdkXuqeW$EP3y#L}FM zMmIEJqSb|I;e|x^rh;1EVuN-B(Gr}72I|pPji_wAumGe$M2wPs2DZy#=Pm_qn)v`} zJVN5I%;90UyLDFCO!%r*X}&oQwt^7^sU1W>7Q+QO20Yqw)07?3t4-3lAt7{uuv>t; z)7vR6J~eHo#Vy-sTtSHUi{1s}DC$+D+d-?ah*OO}CfA7QHPzA!$Ad87^hN*;0rkrC ze}7Wd&8EARo)!JF!rAuGaDHXgiW!fuFZ<#UDgx(`#rxOy_hJ|TyCb;Ap|~$f$3}!j zv4FMAxZ4z$6uRVAmpxQ{j8H4YCux1hV!_tDd{l(EL*u#JTo^Ty*st7PNXGnB=?9ZB zE>_aNS)!L97rD7=1`Yi{PVxY-sP25iH0*A2OW6vmW>joT-X@+SxTNekU~IVBQl&;! zl__0O2BO|2TB$~2`GOK%UdE^x#{-hp6v5zfA~nYZ622Xj1aKxlWaehrF_LtMsO2hw z{F2J04JtT+=4o%-0513=VGn zN6K8|zpE$L*g>3dj*nKzC0nLDxGQF^V9; zmam0!Yde>1QU%=sOY~#Bk64;Sv$|QdTptx~y18tXSPtI8bs-J}K&`4RmQfVDcbQcM zbFfp&Y&C5ciy2&52&e?vRROny1kbiBM64B-1e7kAi_wck7i!vDJ(>Vv^n%5ANpK+g z2)Gdz;;V>?qr-eBK;0o$q2q5jFRX@+0$c?%Lzf9i_9{e8C>ZD>bfAYE6o)HZ1r-CU zL9fymSMnMGYn7bNF5!%))KUrdiv>z4OxxXoY2*sR=&)EuNHu*VyTdgtcO@FMD4ts7 z-3vBXVJz%!N1(F(F+u??qmk2yvmB<|boPh=oi#p5pe*Uvxw++Rs(U6h&E2xD%7M5n}bSU zYzH1=2q;`S}Ycu~|gXynr^q zbvaU$GZ!PDnNRFy5Cz1}Y35@pxCq1962WJLs^Y1{3Fvs6w)44&T|Lw}P}L(k;GGsG z5EfLyuP~csMWD7U7TuD^XaJls^&1ZFBUgJhh2q>P4~zjUh!VO;Smp8=wFd@YrZYrE ziu`N;0I9xjxBjC+li@JW{hSbLpSrdIQ1E;P9|W`FmR?7Xtg85=X34{d(p%TYWt%DR zn;5nX_+~Ga?fhI%!WE5UZsyr%{1~cenm!BQ(kA~$d3LgVf^5-Zw@CMeRlzw3yuM(9KqGU_;5~A11 ztPum2FE1$z3kkcvwrwbuSBhCDLol5vaQ!SO&@mXsw7rt%ET>hAMA> zRr`e_fVNO8S#g=@x}n#e7Og}VR?^VbiNh0(h`C`#uPVT<9nqMx>SHyrNU`G+Y!%22 zgaoz)h!1W0*E}Y=0BuNK9X_KGd87wED%I~k<192m7#+nb4irOi2FpMS%XR2K4qSXm z>;NAJ({=QEgmS`a>p-^s)B7|Y?%*c}1%3nmXL5&6h)@Q-H|8+m+7OCW`}3<~D56O1 zK&OjwgM9lZ1<@>^Q;lrr$ha^_v)kAcQmY5A#nA&z9ivm5R!gzSAhZ*}s=!Oc)3hhM z05sPk7TtXgKcfdaDF3Lke`IW9-NM+h(yqhTaX14+ z9*uLMo6EQ=&9w*l1NoMdzxhf*e&V#4u?Sl--b%@HX+yI+B{0ep5=uyg2PrctNs)?{ z)FD({$|04b45pcG&@)I;C5fIQ_fY|~GQc?kQ&DSlg7{QQl9@^FVHHLAM+%4{kGV+V z5%Yeg;k%5MBDTe3APW$)mR$>V5lpgG=!yxmYNaBiX_o=RsA}nhq6PQ$FK{ua&=8`n zxeyI;6_Cnjg6b(Cd3MY{Z%@}zps+@<8V;(JRYkcsh9VadxVo1PzzmN1dFO%T*k_^Td&;x|-75MmNog{59)2L4`HQ~nte`ektG1KCkuAMpy5{{XLdh@!SJKkCmg~d?8UQiEQ?21pZ-*50p4f`8rS!sCeFq z>*@i|Hc%ylTZEP5j0VyKi+3nz2dMYxz}3wj4p@5z`X$c=Lff$MQ;T+(vR70s*RAJx zpIiY+qPm|p%0POR;sVbF!mYTJ8p|`CUseF?lvw+uR+UTTw;uUpv_2aPf##RSi`*%w zbV{^!rX^Fm`zf{@+KQuk7vi`GA9-Lq^de=wUy8CGzywwf*G@jZr65hj98l*~<~6RV zgm=Je$38BgYd{eH05|*015s>I-)>jx38n-!y{?W76Nq4^bj`wx3jHwc${r`4$R=eM z;s>GJJj(#BcofcRmh==Z(o({z?~BX(0779FdOg+ZzXi$N3uyLuDdaMt-y zO&XMERb|bnDpkUYHpMSAuw~&J7zWe6U)9XLHJ(F$e;vFeH7wWwzS}RycWN%j1E%(3 z8Pxq!e-VH~o<5W*HRFl>!Fnl|7+vu$HDE{k{%%}G7uACQ0BITp_8qHBrLZ zk{TgsA+(Gp6969v^9lyGQlJas`boev(OdhQR5u0K0aq}il(h}~PkxY8qpEYae|<)| zqq{Hv0I(y*jj*3_K>ibt%)pn*;%qFO6(5Md-5zF+qw#QUlP^^TG;E@i?lHik#3*9& zghOXooJ?uh7im$VQj?2RuC&v+hb%jlHuC_f%uob+xqxX1)uPKXA-bBvSo=@B*MAo% z$cTJv;{O1IWR_x!pDNkIF~T2C$(8#s-;>8a)S%k_Y~rx z?C@LSpo!*{N-a&O^ zRRw4_yGG8knk4|AVR@x7_21tGxvAtKpj|q>>yJtc-pB{Ai1WoH*0BM0L<|+y)!^2e`SH}t$;`@MLD5#^(AL2fjHU@=E-xuZaE(t6QAE0`Pd=EtaSI(O+hQt8z zj{MgiG5}EvQ(4-_k*hsaN)6!yXnC8{`W^sx2(lsTb=Px4NUOi%RwV&M6pm1@kQxZ6 zD|K938h8SMS8oW4__IH#*61Z-azj^J5-@Q#UjjAhRxXPQ1RrXw8BPG#E}%BD$f-ct z;0RFEIgdBDt1@C-M70IcQHz?=l_(QSWHegZn4*xVIUQ;j(O=R30Jt{(hX(zmhJ7vj z8jgvSz9Rnsl^k2osloFvZLz6+K?Mv|7(V9Ffq*LAMG^jH>t;MoBN8mNAXOQ0g$+aH z5!E+3*s+(IfqY{@?pI8JDsm!dROaAVLx^@{SqafpZAT^FxYTh5D2*;zio^h3!k}{u zpp=Rr5_0ECg~uwpyhCkh<MFcI753hA&EG{CGNw7?Q&UOEVlcB zrAC{qhFn&|zqx!sUH<^;XokbX^BfUK2Iz`S__39!+jS3Zil@iaOHFO=JoE`zxIOMd zh>wW0Z70}=M16|%twyPs2}_UwYjDtfaSY}y3aJR$#Ez*2qcRbEQu9Dy-Xhx+-_48 zAYDKbq+;qQh(N4jFN%Hw0_729(`-6U2&Z3$khTgwDj7hBF-NodirBlv8-uXw0_TXA zFdzg=pKprT0v!AxgK_2nR0oWe%cKX?8;bm|+;~y{031;2ZKz&VpTY?<+**RK{2P|W zDM8CPT$p%>(FYFIaSA4=uA(7f+Bt|>WK>&&(3jVY$ZWahX!(zCxxp;_%dfpZ5kP|3 zK(mpo)u*01gGG^8Zfzxsxd-aDAwNM$b_hkC{e47-rx6nXS8ac9sZX1wI9Pjo#{AU! z;*L6n(5f4%v&ujv#0u!KT%8UJ`%|x#m(O}HJWv+k#d5he>Y805o4u{uv{sI4k9|=7 zdR(Zg1j?6G9&z8+WdTtXL>O9$#y7#m6T05R^qc$rN|Hz~??0hMbty)9)E8V|eV>R_ z4NJYeP+R_lU+0(wO$n>IS)!=~68htnP&{UL&;AZjS7k z?(Fs4*0$OMd_;{XR&QB&xGjtY#>Z6^x3>sK+Y=HjYJtPBj+b6dg$gaDl7pZ}T^y1> zIMHlo(wZS2TCggyJ+1xTLwCfpz~A;p{efi%2%InqrKYcFe*uqF^IK0INVE zMT8MNEUu;dhLGbr%pjL97bsnkXcWYdM+H;zAZP`S8)Pa`3i!{;iH@M{#2QJxV0d8% z_JnD&vG)MHX8_pt$8{<39a`oJWT&ZJw>yaDzTj13EXo^M4Ll;CEP_U}#pJlc=Q@Yf zzDv*B89n9y07xiy(KtOau7#8;{{S&sK|!#7$e30R4Tl)2PY<}1f!i%{SAcJ}2)avg zEUjC+ziT3r_)MsMH(TbPrf&?or{ZsGE}kKb_njhCqmU1%(W&GpfO%wF^)UxnsQ#iJ zXS5!hX8MD0{U;`4%s4m15|Z~&4FTGi6yJbc6w&rf-TJXPAOUcDB6y58gmVOBae_7q z{5s+d!G8f)!JvK$p|6%f@)blO-!My#Slnd$%)-*|k||*lCbWgZC2YncZ9oj17_G4x zM`Jz^CBs(F18{r^AXmr1#1YiWQq3WcfVXn*C8?#&_P6d$J73WUn+1m@zz_Gnga|Y8@7}sgVVH=jLmWneqi@^f2Px`jZ6OJ0s5CEw6JBV&hYYQ$ITZC)HO}t5q`^4LS>(OG zoMaw;0K?hBe)H7TNYd6*`}_Lt<>mwlrx+>EN5AF}F%*ye&tKfH@+}l`PBVdbT`z*FFC9TLn4ZB7>RVrpgielw) z(Ddj8)5rpegTN29lFtMfQVN66vvkt1mrCSH#ps~1N0PhA#sh`mQ(R3oWF}Fp&(~Np zd<_vT0=QCCv&m=Lu~zG#@W4SA&h0LgkQ`1VCI-fQiNvK;>a zvE|!fgBLD zVLP++)Ur@V?q7maExk$@aW(sjwjLYgjG25KlIDa!hbBkv!_pZrspa~Ek`zx-r{|0p z?oz$Aq`XTMDduUHio_IFmE}v4V9b3HK%n4p`GLT*Y+tCo;F$hnt{x!A<~RJVP^rQI zH91aUXGf5^M8W8|Jzs@6gM9PUxfg^#+-o{HH2lEjA8@FKd>~yU0>ISA!V_US9|Ug` zMavJtQw)H@GL0S4&v=CeBdSGDz)~v^ zC9tb`?iFX}O{*WKSVDP}qMwK*WTIU^0U1YZTufmnz^CBZ<_&)YRKFZXlaGO;Jfwm4 z6a%>KpSYRF_W}O^x>wQ;Uh>bmodpxpXOR6dCcmk78TgEPexcb9%wHt@#SNn_%3w-J zk>zRIEbXRU zf$<8jFs;632jSrH4m3Dk7&onaG24y`asvdGK=3FWar{(7g=5H}EAhX$L0${m>be15 z*fmOG(ug(ZFV!Apu|g|=vLIzNc4ci)t5(aJaq5aJwQ+6Ts4cV}dJVp=*PCKqASET1 z$EB9je2+A}F!yTil|)v})wOhkg|OS>%dLPl;1C_~;@7{@q%&V>6>WoWo)i|NLn)f1 zj0-6gTAy^cWbAc|rpl~t=#1DDa?4&*958`HHWIvwbN=T&B7f2-H~#>uyA_JyO7$we zBicn9F0`n`L=haM#v2_4q*{&8WBQf`6|2YEH2zsPMV1_+&+0K9;_BYm>Wq@&fp@W` zXk{>NRgz*=9wk_EYTgmu6|;0ivTX@pb0cV#w3{-%;TEifRHMXngw2_OB>-9V8L5Jb zBAEUngvjP(5;*&hg~$pyD2|gi z3$-J{^;UfhecB=Va2Gh?nV6h+XB6+;$Bv_xB&%9d7(Upp4o|Hn^a5E}#_Jjrigu z1C3a0_XYt(@qNJ}n{HEiEuoW=y!>sNml2B~F}o;&zwk@ta_^N8q~Y)uJ_>|}hQc%v z4knSJM{uk0RTAaQq@L+{%+h=2(zQSl2$c;b2$EHlw>-eQhmEL`fIP&t^b>z^FE1qc za``SzM?|_jmLZu$u2~P=1=MwM;}<^xkKyi3!0nIIu9ltg`(+CY+#^Q)KvuN>0O`YW zueK%6?#i4KhW%5hzY>Fhem*}4Q{kt>h-S3~oR5gJTk#vf{6^}q6!#neI1IRy176;+RzTY{H; z{$(Lf+vYW1Xu`O*qNcl}gFos!d(dU27e;Fz>-J`w4H+wXmQ#>uS(d(dztm+=L8^od ztt@#?XGn3g??47Cx9wpxyAnCHRX>anMdErnu8= zZzVUW5HwJ$3p~}+Q&QB{Ug|l0UI9|L8F)&_7AW&$RO`rxFVmQ;Hf2ZJf0OelH0M0- z{{R)i)46Sur9kp?)a%C!d)<#>%pq{@oGf9Z!5-@Naa1Yn=){3090Sa!VbM(Kg?WfK z2#s3dQj~d$?M$X_{lwWTi1yuJjz!^x0gy|sE*@0Ba-*1a1pua{b=sG;*|KJfl`0&0 zi72W4!p8Fs0dWTvaNF3Rh+@bqX^3mZ!>8bstPt~>OTy6tT~vB}qOcS}?QGPa2_~i4 zwE6KV^a~QLfMKKsk)x6p>R$nI%=?#Vj)75Ytz~bib7z1%@R6y7Iw1#Ul_(1iYAxX@ zEWO2zTEegKDI0DbdWMaF8Wj^D_^{9;X3AAPJtFW3;tE=;O^)dr?7<~`#y|BFOC1}p zrZFp&Sz{mY-afP}@NNcxXbo*=^R)olC|Fat`N zhVQ|(>OVkS~9g7CfX^8rqr4ZnTM`>vUb@47I z3DgRgkcwRFcj$ z7Fe2N%6rGl7;(%sHI761j`RQ~f)DHz4{d6&W?5f|To&tFP=DNNuF6P@+z^|@vwJmW zcq4)=O>S@k{{S+$Va3LfK`&sDOt+)(gdk@lC%Ee)>ms$hgC)-cE0L=R9_aNokX-#D znpfnM#?I&&_Kri+4aUtYxLqNqNajRIB1!;U)T$>L!&bduIxGQ2N~?um~!wakG%A zVmS!4T@#)t{`r@|f{B;GcH-9k9CHvWL@x?g8+I>tjbTkgq0_T>OKhXaEvcs|t#!R9 zEIm=*xre0PDb?*h6YBVfAjX_YmeEifXBy2A+iEmm152U1;$4)zXyoY+8IA8s{;AX( zvh+?*AlYCit~x)5-W_eIDp0Z8;Oe=cvpIB+&@%b=e*_*X=KHCELMwpY0J`QM-eUbm ztPxsa=B=%wyuP}_Z zz9YA}Q?Lm)Eg9h$9K(oByAi>X!%^X14$3INA90mWp$`HGUBOT+WCp?=Kp^ZAR7Gh4 zYR03YU)xYd%l87;S?XVM<1*l$5Cb6dIOLunXpPAbQ*#S2#9T~U*r0fMm$7fuw-X(* zUO+EQZ3rE49c*iWhZ{R^lvW2L%N^QOypp1-)KxHK0b!Px#yN;yT#LKR$28uY#i2^A zLkfY)kM08++oSNr`j(39c8ay)h+YcQXXS+KUWb&wa%iz#v_jYp`Hb+IitE&F9<()& zTLT19cps=LhMouR0$6iR1hXmxZ9qbxyXGZP1BJjTV^@#jSu7&bdgucy54^zsA~ue2 z$aen4MGA`eDfnN^`+QZL{84h1D$2N7Hk3=gGQG=S8Mh&EBuPOm%WCCJ6onbmPD&$> z5oc1K5GrD4xK<0yx0&{iW?5Uzv$<=}!9x-0a`;p*)I~{CIiDn{-+*9GY_b)XIEX3n zxTZ4fmq&<2US-rAGA!-`Hwejc6K?pL%h${bP*LJ4mPb#+zk&WH7(nE1K#R5+UQP==x%7;6vShoeL0Znp_j1!hpTAm1K8wr{>!GjrdX1bB?-|R~I zQnjxK?KkVxxY~dMw47o5vsu+!sCpt4oFlZwiSPm*6TM&FRmM8L4bZGEinHG^ER8vU ztACvJ5=<0fFDU+aflP^MP3%dJ;TzQc%s6d$pAmdQrr49<_FOmz*)jfigHO0y_lAs_hffcHmuPAh4zTZ8|90Kj^udwPT zL$p0Kw`8tRge-EV3z{5GK}$tI*&&rkStE{HZtM=u2YnX)ZWfTtwOQaqKyR69T|oxv z_b4w+jt!U~hM{f`iEAh7Cm|?g*r!v8nbVjvc!T!%PN^(50V`6j1rdK(L}CCf_DhFm z*vQhvb+FSJnJh=Byuj9GYR@p@8D)6;mINX|))_&knR{D{!+)5|4z?zgH7K~KLstQ_ z`j&TP6sn5cvWTfGJ=jY_948adwXyTc7y2qMm9p(~$N^3_5Z#@dQE7x}r3`PzY(lK5 zi{IQ;S$4qsg=OC|1BF3*uiR)NZl!n+KH*Nw!?!Ej;2OWoc{V+tsKTk(q5Mm-Mu2nf zY4Fkf1hnD~3075gV>Xf))K=+GAT^JC#(D-aeh_(>D*_4J8k@nMve@JB8cQJru!^y2AllSvhN0>VlSr2n7Hnpm zL7dTc^*m#1_?GFRq4gPybE%u-%t~c4E`e^kfj5V^w>EExfikvBhX>OU&74JP2bj#* zIC)|#K9JkV9W}=>J_kDjHxcIO?WyM$hOhKC7>ZCRt`1g{k1L=Ul&WK^)$K=)W*H%FtWzQ;6h3n&IdD>NG0yN1yvg zN_g%*hluRjxsfjleMJL<-!W>_@q9!qHNmh}rFm>`4H~++mHgsf_Zx!fA6Mu195xi# z{jZW${@<+NVIvtu5GY2(^B!e1XJoxE6@A3WC)^ zz%5lm(%@3%Q}%Y#mpC#-6#&z;%70Rz6{3?zjWF(vKS?s@DY~FOnCwyk-QuI~nM-uE zlt6Dv?@DnF0geh%_P0p*D64L@N$_wAvq@f5`|5AlAdE@bER+c6-5z7yT_|{5*XgfLRN_XM`5?3BW7;s@iH^22stL9806*Vu+YPSktYmvLib198=M zTV;JiG*M*IS6CwNhA1_okf?2kWqKFXtOa-4pAia9a>+)?Xf6A=6h#_NnE4yRRsGNU zLxUr;EIj`JQrwGW^D(yz{=}`I^K9SLAaI7H_V{iHogo>V;^bv_%}3` zcPW6bWk#60c4y47iV=WcEZz9HVG2JeP{O100Mxa* zBa@}ZsPdgk!j>X7^88C6?{n-V%(HwEQo4X5G29!KHc(_7%V;5nx!(}cm+Dv;oiP{% zIj91)Zl&mNm_VVSZ{QUC$9mGdMWY^DKkZYCX@M`Bs*gL&7~#t1EvC6Va(63aL2Us_ zupT*yvoH~5@n<&cOP%pWQUO8q@A%I@&O9B}rGW7V6iUzE-)33j%W`?H= z>|FaPI;r?+ug2s2J;YX<&I8pj7MS85x&8Xj?5K*u6+GFG`^0ZmxM1=A`GL4kB~y_% zj(nd|olp{X>EyKJ?E8b@i$q!hw)%2#>Hw?rT9%7duF##@JG~T0X8<3EZe1pNk*~tE z5DGOLQl# z@oGDOP)Y;M%5mx_^kT(4!+^H|ve~OKAnY>-7F1Ebqrw=*tVfek5dNnT;#zAZaA7NM z5Fa){q(x~#dx9mRM=_gl+CUc96R5hg$bVxk=x z)nj;oE|{p-kcuoFDhREjaeVryppka?C0%WGSXnhZj-sHVku&o@|SO--`Zc z-crn^u%j%ET+44|UB}u{0Cxn47Zp&K%oc1Kv6#i1@xx^|3AM^!KN}mkmuygEvG5&B z!zY#nM#KK3W;O9R_%;6kix;wR`B+&|Yf;*64x}Ix3Hh$+Hs$bN_Z^dL=)ZLi(!~`&ke;RdF4`Jz{eMs(Zi+k&c>KTnF$$$e zgRJNKJIH|b4o&NI*ZqDbx^&e`yVKwA)e44mfGvnxrQQuEjBT^GxchKhtMkJw)76CZ zIPBLPj}a(p3~qtgxOt(q^$i>VTDcW(nx6U&@$>}rG1dP7-WiqPI#78V7;mKI+tO5G z#ODnMI@sJh!k7X)XGM4d`G^B8gr4)O@Gcqfv$;hY*EGiBiX55MP;I;f>JWB(edqqNPbjAXYItoRo93 zT3J+68P`=eyQq-iK@-aaS#g+T;9zAa*oS8k02Z>qF}NyJ5;{?v+XZ6OT->#SrrM=2ugYKHhA)<p~S&? zPjwi0s{?+a?yA#c;g{Bq4!w|i3!n@C021E?AZrAKxr@PpcQ&hnHHTcwykLpBe=w}} z&v(UVa_WrBp8%&n5<>TgM5-)d*o-u?gPB*kuP`fErrEmEm8=6JN0^^7?&YsD-yeYX zmUk_d7XeVubZ;}vgW4P15qA=FY?a4E*O<_k0GA%!KI6*2a@>*ogJ?Z4$zG-{yPE)J zwSfpIhRb5nT$viZ9JNri4d!Y`p>IT07sJfY!%xL$aG}g9a|?F`?lhX7@rhc6Fidd| zj)E0pJ+Pw1=!<3HR-Qe;M0hP)6s{|FJPoi2-GsW1U-E*Mi)0_@%;2KeG3)P`UL6XD z%cCNKy9Ps7AQ$gY)d!j#Y1=6GT5B50;G<*7RCT_X=myk z29QY1rhb8CV;a~3EpH(OmWnRG9N4x(t?9GHrSpx&L8(eEo$@^D@x0U_A+O#Ia4L1f z3F84%X=TRNUt_oyW8$lOh^>YA?%-`tx6Cx7X4KZ8R!T2d)lG^&#Y!9PECvo;LnzdL zaR!vUY?pCYPb9A4iKTDqI0Vn6>f)tGKr~-~{{VMofbS7EF7K`%{_T5LLZ60L^BDnU zE!W&g7E!QXHORH1XR!kTeGl=}(@>DuhwO%(K(f+%9d= zdg{il@Lp`a?%zm+amK$r@dIk`^P=A?3SODwiR2Q6;&8mv^f*yj2EBSFm$yMtic9LurBPg*6d4yVqx}YqgY*#= zfodLB33^mL?ec(BCAE^zPT1yvmpnrmn*GXi1D{Aw<@=p7h5ft!W;j40x^7%L%Q`6t zgC(FQMLUWRO*70Wpwc4&1Pz8ALZTX`X`&|#wtnDmlt(0zm^gTfO;poPCd(0R85{uI zeMV|6U?|eh3qxzs5L^x=x4(u8m?*7{*b!)l7j_&gi}CAH2p&e_f!PU84qdT`Acieu zIb$HA!D4xhKITDnlG3ZIX9|bp9%7NaQ)M#-!c~%pT~(Y%;EyBR#6n5|f=aS?#}gOyWuBwGw;!CRTf zn0w1&y~G}4*0CuIg9JRo+9}-j&s>ROWj9Ny6&H3VpN^j4?+x=Q?pxg1S1j9`Hc{LQ zY*@2zE(Y92OGItrY$|orGiIbg9 zcnjHTJ*$=n*!MOS%PF`>U|Y(Cgz%q=q;kYWK_xjXfEpp<$7O&x#^4IroRwq5PYe#u z3S$-Gt{F~wt^PgBnj(v~FOI-(XSl0tjS)=ns;$q)MXzxcx_G`Wz-#{iw&?Lur+&3B z!3Dx5!_eBlu|5Diq^~mgc zV5Q6A`G8J3Mg48P5(+3xNfIoHE#8STy0J_nt zvrotB1R1d5Rs9`$gfg=78*=+82m#D;YUm#|bx&3tL%OtdidV|()tx9JghFUow{6|% z@*;SJxXyP*j@t?a#^^c{BFR>zS5|brVUZ9a$y?>h{{X4cHx(SBpmDM1YMQkwAR?n! z;9xfU$i+^SP>nuGn6ymlisel&g3S-MwkyLpEsCY)lv=lmuz^qsX}c*O>RL`hnUahx zFD-dv&0$KvOrcPGX_#UerlEBsXE@>_tY$FPVFJH*>jIkL4Kz}1Spqq=Z`CBRGm5Qx3* zDy}auF+!KAYMxRyP$^$0QugAAMY%LpqIUq>{5Osw0&b5u^UaRQKYPG^$~X%JTzpem zUB^NvZTv=AiPseZqJ{^3Mk#{Xe=?F%QfqS2cH^u))Ljuj9mgQrsph{dQb|uz;ftu3 zR0YWEnO~ia&;!ghsdp;xWqiOpkD40h zduNd>Q!fNWs|6}n&veI`Z*$!*z&nSU9`GxeR@h0g!ln9(1!@8U`@|c%Ax>MAD|Vo` z(keyegv|SHo+27_aI&x;xZF802y5E`EH*}zKoH9xpealcY`?itZW0LA(X}pfui|1# z()2;B2P=-@&xfeF;$%g$B^p5jje}gpr$0c@&TW$UoF7aeUZp_JlXU>4@sVXN+lwKFw3NGR@_sH} zw28~IkwoUa7snAu0G7g1#d1*n4eSOz)a1JI96L`<@esomEn8OhRmghMFKQ6|t(X3w zvH(-srp`}iF>xi(Lnhujugh>06XbY|pz<~nJ)pcXZ|Q@IFWc0iR?TOa__vW*lDg5} zT9FducF4z0_>x8skgDVlrAwb;CtrId`lyZp%ihPg4X{4 zM+id-uprp-@Ni zWjFRu@!STM^8KG%b4m`16->WYUo$V;_iwV{;>c6kEE5DCu0!cIdH z=P?K$PNKC$CLoA)qr}xK%vDjQFml3S5>=&fS91<_F2TK<41|7JII1#IN~&Z;qudHA z&XI6aV9_ICOKeRBCBU~UW+}-Gnd0ESBL}wwWji9_WT7?t8DJEan!jWN0bp?W$#81- zwO7JHU<*aILIK-Tud)-N>^1|15gn8eD{dI2ohtpqSl%UabWFf1b05qkYL3(?QOQc* z5Z5hnnt8UYFv924H+!`qQKh6UBT60&eKGXV1qS6P_g!1g5j+P-{}E4E)uW{^2=Z1{^q~q#GwJ2GWt{ zUjh_a2;n*%rIIr0ICdNo53FsOE+|}i0GAMzagM+SusI{A#}ze{F5)z&HA6XpXg&>4 zW(~vlI8*zT#U{YaF_)Uo@=>U#O#5XeXWTl$CoX0j%iLnI)kBTU0k{QRM0R^;Jo6!) z&vZvv0>*hT1DFCFN?+U)YY^M98Vz}e@mI2-7@TQSh!N&!MNB(W;#3RH(mx9vLn1GL z#ipuf5>ZTX(&feDnP(>b%iNc!54lzk<}e^ZveSU9UrJsiGHWi-_ncd1KXYHZO6J zZTV##$eIhDm%t4~O%P{NCr{v40 zKw%52@o0a4nN%7jL(W|<@bwBg^8O$pi+FANMnNfK2CwXi+n;A=- z($gZNnm#Lv33x}sLqpM10OzJ+Z!v8!zchCHl>67|tMVxx)l^;%-z&tZ6q)p*I}!7khG3fl{W!7)PjTGhw7y4(k_Egg{b}e8m9+rCIcw7(x`j zW!anu2i3t+5L;~gGU>D(zpkN9Z3I1x6+>H_v~Q)L+KE2VfNkET&uw<$jpfdk;EG%BuK zTiK!}$yCHDI-^5(sFV<(s+5kdpY;T!Vx)s_6Y5qS?kyu3L`6GXyY_FR`;QnVJBo=> ze7L@OTwmc2o>{zpp>8Bs1Ol+MnD;E7l?rR>URWE{L}~*$AGt{&eh_+T5^UexQD}pu zGIXEZzM*FY$}L!V(h8xCxkjz-Sum{$Qk$jqDPkPdtQB_$D$p*emqbM7j5UZR94gT2PrF)6OKQKni_bhJP z@kdC%xkVtQKbdW8Cy<$Qr|m0M7v^F0eZUtl#3!jAM!?~-{X=;aCI0{9A1PAeT9{GU^q+BYr93_Ff<|;H8|vqHYIX;>csF*a4fUro3YVI((OXvTR3{~H z+(bE@J*ko(4FOIyb3Z zXYBBY=vV z@M>A-Q#fz)C;)JFi`Cg+`lqeeDy;>PbPBVE__r0NC|7HdwT~;YIbGaQ z^rJ!DG%wJlB;%9N6?IkT{{T|f>Rh^hAZU3d36aiWGO#sq4kaB%ps^1L07pv_!m%dj zsFsQ#SIRqUv$6`*u>`by%c-&^*ffnijzR}4;ygcs;TT!*F1Dm|g#(9(wIh1G$H>G! zQZtwJj5`n)sP_bQVI{E!p@1m1pbCmE`k9Uk zvYFfIfOc?OxQ|d2arJWEaiMeSaRzHaQK`!SrXQfZxz4F?ezELc@DB!gn{UZbb4lPkd(Kj2^^wpuK|62pq=D*olb3oqZdn55`b+K2!u z)miFZK~-ajC-h%~{$p~8ES&j)3ab>_7|NCX!J=LHiX8q}ul!LO(A?(T!ufEf!F+KQ z6n-VVdA*o^FB2o*q8-h?5|j=z?mb`4Ei2=;T8v}Veo~MseZj52 zXfoiI5XB3h+iWG=ZnI`@&oE`Jq9xzV zavXDQy~+jc*D~J9fk77%`zVY%yWqzPX}>XqD9yqC=lPK!w(0#qdw`R0tUBf^s!|+cBAdzqbij1QHNQ~MG)fC# z=33S$M^0dPhlST)C{;Oon4EcLEDWMyV2Bok!>ccwu}}<@;q`;TWvOt**I2~S+*lGk z5fyYCAymL*OGeXi%7VnE5c4Sx-NDg#GHxIaz@h-VAwO`YNAu0$3k`Bn8id~bOXlyk zPf-D!1Hm^+Ur+%@6NExsrCdJNzGaa}4TA8#%P;vQu;~hp6-BRuGkTU3g#gpSJl{I| zLQ;r}_EI(U8s{E}aDwcm-V`2B%cuuY1|Z`y4hodDNkxQwItXoHDW+0ff~UuheiBr_h{#a@lTVZ(a$vN%iV=HDIYh456nWzGE&0CX+zj z+^}k*E(j<2|34JMFEoMik+P>lJF7VsJwp2hct6`$~0Xu6eOua}8ZII-< z*V`R8g8P$#)XW5Rk3)`X46m|zd+`R6(xHI*02lOkHcAo8V}r@Xyx)?8V7U31YjL*t zLj%NeTID#6{{YA}x$J3t4Q`imG8;>ZKRbs43DkGWx&PLJGwz|rPbGHnZ}ybpDC3Y!;I1L`;F8j*_whvGJ= zX9U2T8RlOq6^@|7(PBllz%tf~SXx=f5|_+#Lp`ojP1|#ujSHf_qoyG$8gQEdu^By` zJU*v0w2^VRxiFY1t0j++jttope=ysF^Zw!y)yC8X9OH%cFwD1D`%}pfS0(UWvz;@{ zwU<0Zs9#cs3v*LoQ5%~*#rG2$Za92I9!fSSye`=2fSOAF=Gf4vjbvJ+xJ5H62*0_4 zu>{o!Wh}XXL0Pjghwg3^^26}FZMjd<8B~C?Na3zag#Ku&zvUPWxI@q4JwoN8Q(eZC z@dYC9YZ9-a3>TPiU^Y0Sk1@=nq_tcxex1eTT^lG?TjnjSro-(^SONjRtV!v=*I0RbYQonM3MOEva&$5F5FX#m&uMa7UDF zl!1i^gYfYb{B<3oIT#);X@!ATaFlW44yDk`>4%8cvN*6t1o1W0bky=x{!mPK0P`;zXIx(5;DN<2xuReIh_LPzkwa z`nS)BN*rB*OS}I7e^4sD*7bfLs4LTl0Bi5F_2G*Hf<+Z#HH|O-0JJ+zh~NN>D$Dvq z6vEau!GXRi0IA3)7d$Z#0#7d@Ts--d#owqbL-7Ob{vt7Oi(AObumg_GEsKEWKD7hX%s~{{ zYM_BGEXYX&A}G+ov2=WIQxLP5U7#&3f6tg&8}|eRUgcH{(6o9>>|q09L^-Z*^pn%EYtTW@cqsl z{^g8Oy$;wzDdG=g-Ue)aUBYcu+bhVOJM{p4g_~-5Jhh9ctgp;xkNS)eWIC5&e&u(3 z!7DkM5mE|-ij6uWb=)F=`-VSfjFtzk(aI%Q7I=zX-XSL_HeS!0IwST$3suT`g;3_K}geEeM)}~{Qm&I)Ci^SB(1cyeq2l# zR?COc4N~eRYA^99$#0t{7UO(V8Wi^9?%)T|uAm|w`h7x&;2Izd9?$aE(U>jF*#1T^%9E0oh7)IQ?oQ*xY_Pcuc$~|m{=LoF$UKxai{!fcC99q$U&zN+h_pBTM|CBS-)(&A@%kpnXQj zF$1+;VhXMMk2d51uW_a(OsD~CJ;HZU=3mnW&L*fP2J?Bv2w8ZP+X31h!yVHZfMY82 zfQ6daz3Smj{$*OELs3;rfrf%^!AVi1DP#8;(BDM8O#b17U_d-a9f&p3PD6V49VND< zjSGCj3oFDWK`Rj)S0oB$uE%Aa4@o=V{6;tROT|ekkq5X}(x5hs`yyu_scu%1^XDjK zLyB>Ck-~~Tp#_uMDn-}axt;eN`->^Hh$N2Q_6wrzuQ07CTuHG>!^9hct!!+$U^*t_ z2HhZH-MMWk=ghy=SbFs@Q^dV}5hFw@15->FGYSk4Ro+Ws4g)UYL#V+i%}QL;si1p{ zXN!s9BPC79MnzLJ`h3EM1XD+ROA?Nm7qzE};?iljV1Q|fUAd_78x>H1Y{nGACx)UY zP_8`7U~>xy;MH}qtVHL1j6a(| zGTpDhKQK&abbqJZ5CG<&`-uyGAV+o+&*zK$IB@~eG63}+=_0$wr?QF7;fJIS} zMvp)B5kX?5m1S6zDk*~Sq(b6#$iWZKA%PZOn~16&0U=>?v}81)9)b9785q9T>lm2K z{OkO693@4oGwYe(C9y zLud8G2kKOyBt>ES?ScV@5opf2fS1Z0NoTZjcxCkgve*$ozjE^J zkUYFZQ%tZsfIQ@HErwaD`-tJObH-h)QC34JJR&0ksIsD^tTJ5FG>bqZLZXVfK(-Jq za|LlM)J#QFQR-~CRnLG+iG`QqH&NzV{DkE>0QMRBj%6Kx++gU9Hw2=-Jir`>iIQn* zWk$dXCF1=|`MhGk5zQ;3uk{Tgw7Pwea`ge*m(*v79vwy0B>n`K(EYP!kGQ#dF<`1r zfxlNQi}baoTpjmah`^>&oshH#VS5o>Ux;Xr3)3%H9>geG>DU$#f`k_@QvPYBue=_ zoXchYhLXjv910f+g$^a-u>_M!Viva}Lh$NP4gi5J15YG7EC@1W7HWlnZGu=Sfg+BQCU7)KCu*m%%P|$mI79}qQ$pb%1!pXCN_bov z1>6J;SR~r?%oB(MHW8s3A{tD;YIVCWvCZS|1W;Xf5$0k~iiofAp+-t*F^rVnkOyDS z<%Bl28V2HD75z%Gq=R^0<$qBz?Nm6txAhZ+y-ruZ`h-QQbN3Ec^A^(U?lOV^8mhQd zmJ*1$%8+T4u&Rlj@uy|MNFH+9uAMn1VMWr#;!h~$yHCVYf&1kD0CrK~KCy#p=Gf2F zwbbgX{6J+C2W$G`70a}r=s5@vpHdh908is%Rw=8hYr=O2LP%6K&-?0BNW(RM+w6{bB-XL5}vhudNS<{6ZRX(B} zTBiR1h~nV3IwyyA&7>j_SA#Ojwd`rDb+pbYJ)>^mQ7k51U4ko6!DH?MGOs26AemFd z{^Ey{4KIekc7`xdxXyT@{{Rq3rM?+WmT;xR#&k3yKr7RFN{*GK<0#Of<^-TPFhV#7 zxI_~9i?uC&U`2vj7K9k5WLy0sUhMH0Xs%5aX=LVc)b3QEXuOGt*vpF>4XuEh6P%Y- zY#zFZ@ht}!y3yj;+Ig(e8u`pJ_`q^N^uBL$q`2~k3L`eMDp=8spXM#aOV=~2Be-P@ zMwPQ+as^YEs~Z<_vhA_jAzKvH@0N3Ycq1^YxRJO+V(+YYfnJ-pi@6;5=AhTnoc8HJZscO#a z9A=@>yU{6z>&$AA;J9L{J;GP^*sNXnl*_*a>z`<1))SoO4}pXW$#obix`9#IY_)rW zMQm~ui~-2t33_xggMTc4UK(bqW(0!9c6bSyzM=Rrr~m^*13A@3u0pXvR zC#c)8_Y+W}@$DUhM5Wcc06YH&)Dit^m7bU@t&KmD7yEO1f8zN)-(!BP%}rxEK9PkqIu#5j-r@8;z~!8Vb0 zcYjivlGDC^{{W~+RAXG+LMMBiLclN|%p8fCNLq5|iLZh7f39G$v+oy2RsR69dboh4 zis2|YOSAs~CC~$LgOT-Z5k`^#Sz_4o2jHG#6WR%fVvSc#ULNC?vV8n6briU71hK-6 z>8c@pYcD8V&5t5f;%JmN7?+kji;ylcgtwTFBjI_A+o<$Uu#}-Ga(l4uPpD7H-LmQc^(xx>j-9V? zt|tQ@&$uP8O6nm{4+LVAS|h;4df0-w?h3&A45mGDsv&MgnhfTb{u~%SrL2fn)5UcT zT~$Vg47|8EajRT!WL2`5aS7EEZgD`(T24a^uA}Npn%TA2s5$7WGNfEUNHq2{JI5M> zUb$Ug)F20Ms7f`Jn0oV&n&<;#MsDE>a9UBn*aiP=skK!|@&s zHNn`^#ohNp_XW*y8v0$0iVLOzvgK5`D_Nk`Ov}i1ukJr&B1kdRDC#PxjTpySbqulp z01*x{cp2_>sqQOE;x~j1UvT%3dts__f?2q*7YyY$)bq5m*>_5iyrj{{j*`FxBo|Ol zbhF%6uA@SWT){xA?rM2wCS(VS_QisIP-zE8ILDx*lhZCAV_tk>(+dQL?sQw0lF&5Cu~%82nfwg$>=*3%<|l3@FH& z*>P>B4UIL~fiQ@a4*>uG_Jd9C!Vt7$?FEVw5NeI;I-?~hmI}^Q$`ZRA#TKcyrIj6N z#0N;v89cCQdrns{Ht0~RphoM?e{tn;a;og7xFA%Rd4Kr`qk(UzN=>{&qzCmD^aF<% z?rgUJKfkF;jy8#8v8*1Vj)mjO=1m7rSbpWvYAm|ruNVA5Xi}@gb|>)@os@+hyco)Q z9}@I|j=(hW@1OLW>lzc5Uajs6b}Q?`e5?$%L7a+;h*WB;g+&wIv+3_ zEVEpiAn+0wL5fUjmTlV;_KmQr1fy0wvzePfMwLzR_^0ktycBZEA@{#R#<&%w+09c2!K>o z5izUS_2@JyJyZ=Yj$}bAMSN4D;*_TgvGp`Cs><4d@*J?gP?uLwpsyrib2~onT?cSH zL-bX!F5_RX8-h~SM2pU-5!Acs(wv_>b-*AK=RCWj|MmrA>5p@=rGRbC# zNt`J1%HUs=tfNe`r)B(+MkqRvrFkl0hjM~d_#z_@aT=xjf>gmkwqC0LZj&JVpeX40f`w{K2Ks5(wnT z8)fX@aS{MSaI4?kzELw2@T}v^a2At0V+#n{qi{UK3}ErmaAiHpNnm(~NWLS+g6|`_7q(VW`Cl5-LC+G~qUc0Y`L+pBVCD9XWS(J11Y@v1 zz9Lmo0&R|%6t;8QiqMBJkqnC?v_px_OZ%Bfw#%5v5;Y^F$oY)XWqz<77DSW)^BlQ# zDyQxNDt$#bF3(UrrXCCE9d9;s-9QSbkAesBD5|YP?~m~=PV*PkysmvshF6(-^f^u< zAV3rC-|7rOu*q_oqZwcn2b09HQDrO7AAas7rRcFA+yqcAxau&oxot&|}J#P!~CVMA5?6>$kTG2r@ehKZaXGRmA;1UQQs7Vb5eiM(t%Qr*7{#RC zE}3`&n-bi2c|=N3Y{T_A)@kzfDK2pJ3$^!AkigXNDx%XnJkK4vz3 zk88}rRy&QBZMYZB4cxs>Vr+1w+$7Qaj#lvn)`f$zs__~eIvuUy2|y zC!Q)Ka54H-%ggJx2_+6{I5IBYylkjDR1iq4yI1{9>21ydN=I?-!P5()(v1s&C?l+v z?S)IR48bZrp|3E03pl7)JVU7B25ebkUPTwDx|q$o%u@<#EG0m_hUKY6;|_u68x>67 ztgcc8kP7dc52yeO%uw4Qx9rJP4mmDa=Xt4FdeBxsbI(|^Z>LYh#!eOg03iPWhGa#0 z>OG@FiFr+vg!3og&Af0<``;ad6eL%f<{4J))Gq2_n3YxY`8l> zP^z+1h^NGF?5LJ2XF#-(bykJP*XM|;=>wU91vJ#)qV@OY309)&8D%4zk!#{wwz?kn zS75`_VX#246Uh~OxtD;nuQF9QSfCWVzCNchDJ&0H2-(k3%86yEnLNrC;o_Wu5s~ID z%eV=soV?2DC#DH@JrJy~D6s0&8^%MO1L# z+!dCnt={;CCocp^wuoJ_nJuWL*_8FDq*ksKnM42!UZbA#%&p)KBf5EtUsEM}mF>bG zj&!J4yvIU3%5E*{R=Yn0y|5nt0Ej8e_Zz~lHI1km$Jq@?4gxPmx3~;&Es>GcGUx#J zDECFMb5rU(LVb{>FoWl>2P+1@uyGX%yzEx08Y0_{RHTxq11Uw^^93y-{{V5n5_2xy z2SlT*T%gIrX(1F@sSA-wWF)EwxV4KVW^Bxg{V5Q)oup8Td@wN23~p72aRDI_s?$x& zCFw5u82(d#)WJo@fY(ykF^G1dt6p&su<(Xed50w8rNZnr_>PNIKCx1q^}|mM*zH#n+F!z6scoH%=%~+A5x{8 z)bg|ypWNxjYpVSNHq|g5p%Ew7(n(93*r<@=v)e_&>TS%M9X9B-+K=Lt z5MZ#`A};X)uC;>9$#}7jh-x&Wsg_q8ofNhOU*AadWhB6)Z|rSH+h0c zuWTFgnvn?I?7`L)#1t+eB^!!ZwiQu?eIil2h~^S_Ko!PPUF^vrrLC}ZfvSO*`Gl7W z)3HHikP_YX9*mbOYmvFTa?V#v%v&36EYP%S86dpMXen^bK^JjIKzbv?4qE0tbRIlP zBrw)38}m*PY}T<7_$46m9R))hlV+VN3G+J@bW<`S8#%b^AojPK@EX2 z`Hr_0#BEr#-o zE)iIpU`3JU2Mwl^kP35L$6Kf}h43q+EASIUrs~+qwtJQGD{uLL>1WTzcNNlIAMd6b zJz)0*K>j)Y<{})K_eHDpq0Lwr#-ps0pRDNmu!}&KF^>RsR54YYVgz z_{V>VvVkpsa_Cf|dOIobY5{OnVw|aSc4#hHwAcH@H?7NjKhgm-AifILQUZ|HJ>NqR z1>tckpUfz`4+GbO-}SJ1#jSgtk|m8RFEO_@y<|FE6mOuXCe+9fS-)_sf1fZHwCYep zJ>7L#38Q3Tq&?d4PZAmR3iB@= z!8CMYN%;~1*~uCU!!%? zGiKRXsO?d1DeynJSY1AtAU?gkfM7b)l5^=_Pm! z+)k8A5LpI}AXxsOG-q+!N$Osolu(5iUS;Deu!X9E)Bt&vB4Zng+mgZsYGP5z<b14jzVfc!s?Ew$3c#wI=RI*nf zPE?|Kc0@MMiV1j&lbt?~{3i1Z10}^S~77QMyxh6(P$eI%E-yNak%jXN-ZFDq&Qn<4-j;xG}!F-c$C>iN=li` zTI7YpiBK8l1`)YrTuO^&od`#uESHdhJ%mnM_Z~=Js8UBMvFprX3jAEFtA65IR>shW z+F82T7G#5GWx-v<4G4<7#|xy4k~~=*wQp88PW-UwpjWAKvf{@QQ?-!_GwxfI{OmHF z5G1~PAk}5_Gpo{h%I*ME&`Sng_cBtAV6e+-8@JDA47##d<|lY~=2|B)a%?t_Xc|}S zjuA@;I<8|&L{=5*5#v10As(h6R#5>ImW~x3{2!45z>q`GrUbPOdVF z&fo4U7NA(fDYa2U9GHS#l9fPv;06_*dVH8N9im8cu4X@Ln~nA{QD zRIWk2c`$1wI9^`_0I9cV%BO%ki`cE8Z#s#socwnPwooT!84iIW(cDeKs8mxcJ@b8W z3L7zlZCMH~%djN^y<5yst2Q}e<|)fY)T^hY-@_{wfKe1&3EtdSbk)&pEsdbqOQE9g ze!_HlM#S2hzK@OZk}1&U;W?M6r;6y%C38YS$-z38UofvL&q+=n&3&M~dz| zlC(CTi|p|ONq}Oi_-5oA5+x>O`f)V*Vw{n#FfMrO*siAKDBRxV`b00*uf; zH5)XZPZ9*P<#r z`-h6p)ZtM2k5GPUA~ao{eL~CdLBv8DdZ|>}iinNOLb*NKRviV_Nk? zo=9%JRXoJir_5M>4<6;4waXu^^(#~j*-*dWx41g%D1XQZR>Lp4S7Eziv!oeYaNFvwRU>XOcd=3X3o}!{nkmUC` z0ovQ}%*S67AD-r_o?1iO9*s|JWW49K@jT!LQn0na zm36sWd`nSFgcej2wZ!c%JJihuI%UBJHeUuk!D5%{Y-;}FeLqk|x&CD}{2jr(hIdGv zBh*c#i?+W|ew;{Tv$b~!0oaQza~4~S<8>2I>{{8+FvS7pW&%5lY^hedCpg?)S7Wgqz-~aIf_S>uvKyU4`Ee`s`-0^)ZsSnDF$dTwFIKka#2e4^FOU+xmHUi3 zXS}@GC)K}lw(nW}<$?V_%xcj#jgAUD!Yr&c)Zt3ktZAyPuMh$RR^07DD!v5emm(p$ z4r1(p5&ZrkN-9>LgNxqhFso}yc&_7Pf}{jN{RrQb8X;xlaJ?M!77_)a#aEXX_zjpN zdU<|9LY$qkOJ(DBr;$~Fb3wbNdQ^2>c}k$|TTr>YQJ}l@KZHukON=mcz zpSUfqqB=6=?%fLa;&>M;5G<-$QC9-3EOQ(Id~9xM^(#n{jPr04a==zss*g(jM>7)> z#9F-mQlT5}7az(>@uzA^0uYX;a6n@FhR`lDkF)w|h+H43O4zD$D>OM;jMBy|D^}dP zu`V2=kSX|sC?)3`4s`NEM{-0BPLRCy4B;%H#wieNzgmQWa3!)U9y=2aU&W zsYrm`vqc@hPeBEJ0fym@osHsbqrN03xp|e@;=l3@gXQ(_NjgU6Rs1@!jY-K!( zE^t+G1)wfiYVDl1N((j;5Dx1lh!yRN7Pu62kX+_EQiyXD2HXI=OG6m>nh~|zsJO#N zF{>LdYOz_*?jhWOa>|ibG928-j2@p0LIGcx39VKl#X&O+k^Bs;@*me<5&M(WTkPIo@)tT}o&Nyt6>{nd`Y@G4Q%Tb>fwHU=d_fyL$Aef!eZ!J~V0c0( z;vySZd5z7%3Us%(sevzsM8Vt12X$MpnH9>H6+w!chEyjD&2FK90`6K;5-xa{qR^@< z(%`mRiQOleP=?n{GidT(}f^mj;k%HAbwVp$&F_ z%tXkW6d?NZIustD4Fk#4Y*n1uq+VeqjIw(oRWBGFC9=W-&av@jM@AFWc%(5~Cv+0! z#A@Yhu)^371v9ws@Pnu7T&b723ls5Cf`BY8SJc2v9*toa7!4NwS#|*)O<_?5Un#}; z@j0=*DmDdQB8ma%K@B8330mrPU*;aLU*-HnDNpc$TE}Vq!=XX1s0t{iTnl}t2R@@= zAxiGTs@~r5%*|&UdH(=vGes^c+AEY{9kwstjnSkK|z>uF;S+y4|l0QNiU34Z9$-M>GQTX=1Ls!`P?I zC7p6-4N$WE2A}Z$V?b!#JGlN5yN}rZk%3!y6#EdWKw$c8>+JlJz{6?m={%n0I>PD$ zhC2ubDl~AA^Xd}I%0W?GtC!LL0C58xCr`FC7yZmEzi@BtM1!BXa6`mIfc_xRTJp9v zMHR$Ti2Xnv3i^RNCTH+U5AjEq57cugsw0hTw(%Iw$xJQHHSL6p(l~(QHlS*%Cpxcl zF&~K43PR87rS?7W{6fiI`LZ&ooTqT9V*db9QL64(THdE5vWQV`RS_#1~nAhZS0{@{riP$=?8 zb9?Tkli$LBQBb{s1#iKoqG=BXI~|YnG2YK`o+vxSw$iL1?qf$VSTffnp|$2({Y%lL zs5yF`r4w{LVQe~8u^aOO>xIjd%iY_|XO3f9>UA9eRCA%kvG9aIx`m_>(3p{{Uvf zo)1ut@MvP`5o9U@8}%rcu(;-vhC?Nw{m)E{0v83kOF5#wzVsGwQS${t{L<40FZUcAMm-OV)~fVQlc?O(s~FUtBVy~-BRrlTq= zIqK%bDbuWWWC#G~kzv)UW%+;77FmM4WHs=rxl&FFVd4J(zs$Jt7NkH94+kHH7t>G! zZHM~CT6%_4V6bdgf|=22l9yhiU{0%Zr|LVnD{BoW3aiqam8cfjxt=#mr!9H8&KH{1 zq1`ywoH&QUBqGWz7uFakRaKyDR-)FpV-13h->B@xvK1+g1Ynok_Nk)!H_wsgQY|-Y zPlR$31x;{QOQq#1yv6#(XjPj-+PkmG%Vr>L(2dBxF_blHCn^#0LKTUZ2Pcye!B&kQ z#A!6!No`^Fg!+LPB`@Md)}M6TSy>ObP(#UV&DRSq43OR)qL8!8EbL3Tg{=(7q`Qi^ zio34SF9st33CKumL(4yq3_a#!Y3Q37_=MYEQ&*1&K+5MI5YK*HLCf+g3F`XZ;v(Yt zi9?^bjY~Wc0bO_0K^4vY!~?vp2CC(RRpgq5y{oZ$QR=Vv19txIQxa25J&9`Cz>z`&xZd1l3SS2a{Nn$$4=i& z0wL;!z_^z4cQ4n53-FP=uG^w|h0s|KjBqXzCNaB~Y?R8hwg9-&#ZC?x&oFRI2LYCd zQBkV4_{iig@R)vMSBwxE;4aBo3~G@MtNf#5YKtsklTD*9yy8-mO%$H_m)q3mnMh^& zmkJN4eTj%)2Egq&O@*b{IYhPb<}6KscaEW^iQ6piE(?tcFld+r*^>cby}25=SfGB0 zDOn%L@haNMXX++8iRYJwgu`O~<5GVpxu3M$E}%-*!rgcKl~Dv%UV&$rFH}(;>hDmp z-4P&Yt*8`(YB{V`h0h^ArMjo)Gwfck#Vd~eOvP0iU18j{I|$Gm#vrSVV)YWLb#sQv zaP$d9Ysj%w4=@*Yb`OO>Zc*wIQp&feLK@|i+WthiI`B&AQ-mkDxlt4=scP&=%qkT_ z^or_;&Q%fVEsB9c0V24ZRJ36Unz7lfSX7-s$cZl7EfVvGAYH{V$ifIhq;8cVytwY0 z7l?#LPW^L`hp~}#r=BGwcgYv4b~tf;!8{&gYVR15xP!v(B~wf_N~ue6#;S2~>iE=N zP@}hvq2_M$g&}jC#f?0I60GD@c%-Qk2T@ILahK>LSd_-4Af(7p@i2j>Sl9v!5U^)) z;&TZ~M{j+F*2Hk~R}kmgUBY+3*Hg}2{X}N8*>w9(-?+eua)FuKYwxM7wHVNmdNuj*}y z2nCvb2R*z>rhx$|aN?7V_4=hJ*=x9pb8U0(T2Tso!`rG+Uow$^P$}gFyg$jza_h_4 zxNz aTmZhEe7`%icllclv@wxS{$FA6HSOodpF$6kQ8r-bE6M_0%*3S?&|LTjv?t za#$0-2Z#8-%%!_D$S_*u0YIw6@2_-36b*SH66CHWf^ZiEOqg?sV`XqN8>qIGReZ5W zn6T}Oz8F+my~@X=3_z837Xfc&R9QfG2U$-tpi|U#z`s+BAH)rbx1#-!))q`!ub!fm zxXqlp9U_VTWu-Uxjn@IyL8=$-TCdbiWyYq9gI-zVWBr0aDXW^p5U33XH*J-$gK9Xx!D!W@yCs*U-x_Jp{jE zQcO1YvWp5RHO~-uOG8o4tJS*tWhnMywzO^f6oXXZM4@Di!N4-jKl8%jkd zlTf;NfwvNZ#wa5##T`oTaT18g_cVM@WQBFWm9!fWR@F;~@k0w$$22DyiBhE62(bhs zwqBTF>RPX395>WEw~sQMC`QKr0C5VT1fS|GQ<-p~_byEOd_c5F<>kI0w?E=i6SKR3 zo0ZqMQqM5=`o&HpV^zxVPDX56YVO1rNx^nXy zdXu=&OZP58A#^abdsMvnmtmwL_H`A4&vAfJCFdj-6pUjX45}^~u;$++sSuRDqMHrf zMGd#MR9}WyyB(0SUeRVY4W&&k19fnnO&XVW4EmW?3hh9^M!2xl=eXAf+E;#m za0I82!B=(TVTf)ggZlhS+l1lWKbVyg&jMKqRk7zwyqC-+cXsESN%X#A)t>j3eeK|mSg)>(I{92lpF!fel?ApA;bN| z7&evHh%7~n847a)w~?6>>LX<*-yfJ&W~&&Wda=L$!Wy_N>1emmud0Ok-oOIurmLH? zn~W02A%d2=1hr=gVp|(qO(B>x-JCqif*=;Q06Rn0mgyp*ttb=}n?r>+FILwS?Y8X= z=ZDPXs-?tI%BKlT9=MxhLrs`n{=Gr{5+jC$Y25z+5rP6c*$OzT6uEXoK=)D{z7P9~ zmO)c3kgK-U5fwrpIz2Rloc>`%Q&DoQee!ZR!St^I;y4oA1T}zS#F1f(4FcJ4lON)2 z;^esg(E=l3_9B!;_>1kxa_8IKRUivD95Gmv;hFxtg3o)T2)^QChI|dgO@| zQ>gWo-7`4h>Q;phJWJ0Xj0bXZ$y=ho6)cTc=a>Y77KY2DFR}+Nke8`lhLGT($}*$; zPPmo>z>>%!J0js$(4l@~;b7(DCIYUw2(dVH?0Rx^@$O@W?!Y~r!vSN+a*CxC(C!An zRD`^@TOx~0w;>(E3z(`wJ0k~!0!mAWhN@P})IO43B0Lxh2)uIzF0MM3)IVgW1mSY< zPsQn&I=BHqGLhw%pic#Wr| z>Owgj<*jN7dX_j#j%*(AuoX;_b@wT1FKLeAosfS6uGws7wXqagoko?a{6HcH zax>)fCA`^s1{Po0ExyPZBNnrm4HH5+VlMX0MxkM(f&~H?&g%Rt!Vr+ITtCv{eZa? z-(nH4s|2PZp%W^a{-HEFj}pyy)4vf{ZVEV*f~n$y3gLqC9zbpJUQPVV(SdKshabBB zV+A!Hhku{tEY^@V+<~<*{HmTf{-Dua1?;uY>QLoC>$d&>0My6r3M_lR*8czy3ro$P zZTqGfS8)Z4%ijKW7AD%ln&@zLF2b*vR76}ubZ1tB;a4LA-37~n4X(te+)z+$aOuu` zU%6G^EyOiJ%_}m3&Ir%~2c8PW?SoJS;W zQwaW`jjQT85=S+D8sZYWT0J0*!VUSF$0<6ggBFL2?I;IfKbs2Yp;QGi+EOp)6@mU=u-02f;tD8NFZvBMf5~9B&ZIc^B6am2}QBow5^v-Y~`5@hXlbFNmwFA?`8!IzIV>JmK222%{Ivl;p%5Wu2y!lp3?v6kY~D$s4) z_JPY?dYXQlL>RrzB{1pVZ2gbvma%m-&=^ zL2HeceoN9{jGKF2FY!^EHevVGe&wk{hVJVN`b&xJI@UOs{KcUYKun2ZS{Gnxe|7ta zR;u$iILG~B-;oz>jveFK)jQBn2}4RrZGbJDx3jn&A`}bEva9n2L=MW2C|8aS@j|;dC`1cIu48); z{nzs>E5CEBl44}OC>_Uw!SQ`U(&bUR{L7-0K*+1aKvh&zQgPx~R0L=vSg(=twYs|rlN=CrJy*w8Lco(Dm zI)=zKMmQ!^X&xYXbYk#8yk+&by(;wG&z zOq|5f_DTSsp>mr_>M)P)x-e{VT^^o3<%DxR$`LDRWuZbH4X{|F$VArgBt~=3xWs~E z7YmC)RV=VCl&7}j7JQvCnhPo(3xt5>2D*LCqjnS;{uKO1?bnjwbgc6^9D0{mZao1@ zyCrR36xmz4UlC|4Q;}<)1vXu_#qR`cN;L@nC#)1Hdw6`kh5~d8YIhomrKv6;39ULF z;7Az@Dpe4(N0~^oy+Y=E;&B3cWJcV#W}f`bo&B*^>Yp)LI-q!r4-FpU8H%^{04om8 zVKRRN0E^r)T32K=r2|;QXwmZ*Ri*PO)*?2-K)X0uzDPZ`4sy2t0K@^ZwwbU20^z{( zDz`kuU=}dtz97)4=A~h(iH8$Wt2YQqjbVk^F)EStxO;2Rij*&ituXn>$wT8~oqqx@ zSbfXV!OAC6Cz*B&3V#xx5%`Byq_$8rH)~}pEYUF#>fl9YGRx41vInTZezLgGxnaI4 zHm4BbX-w5@$3xT9$8h&6AXeu2Mn#vsOyt<3Yy^WF~oq zF<)@5?Ox*;*K+8`f-yAYnkD;dp=1Gec(g_}1_AC=zr8g0rg-#01=VqLPHV#h=oPOK zYR@Tai`W+_hA1y}IRX4cpf}XH6ds5T06V4z(!3D|0a62ikA3m$+^K~63bumKD?*Tq zS15V|zbqnq$!}4|;_?&cp=__jqJ*~B;R8AoXD9fZ5macW@fxUfpj!R-&+ZjhsE#c< z^UMm+&?f8s{{VY~b{)#|&+CXX)^F7}Z>s&vy93xLBFo0B_Xs0}BhLQ-f>_ZSLcn-_ z=B)1KLizoFn3G@ws`9_gdAuc~dw(|!+jn|avV?VK0$`_3pT44}c~TnI`p@6E@Z9K7 zb^bh&o3)WBu9(=UwXP2hQE6Fy2JHU;4<{mqtgpG81X6s5}$9 z629^fDh=+aU1w6C4z?Ek{{V1(rL_xw)xTW*!>C9G{Wp(_g6{X5pz@ubeTJ($L@Z7N z*vG>>xRn(Ra%3(|8Z&nT;xYwg=HIz({He+z>0x{ysQ#4tjV6OL)t+1j6FxmeoW!E# z(qZ!*kI{ugX+-ldG=emg`PA~3a?iA7in6zW#V)mVa`><$I;&OUzM@;YrD0QgHX&4w zDC0SpXCC3NLCu6<{q=}H!r~TA##wOa7>vEddr{p$g9nk~1j0IQ;D!B1 zMs1?kavENux$%$O96s8Ki(!2p<2Yihlzl}+oJ3Rg6s28-vXs|2Zsv$M}TFhb1L7SYFk6dCtUo&l&r(?c716(yMY~#H;7gv za0oS$#NCt@!ZQ^-)KF3N0;=b73=_$5EG_tz0!HWsJ7Jn_*e(R=D!8K3x?F*ozNHw+ zqJ~1UtqQ2u0N}wVN?z(Y5Zll0arqX-#*`ItODG-8rr)SsFY5szZm#1XLd0awFsK61 zGU^;Q14B7tn8+Ypv|YxhuMtI-bHwn4#W+&LA(tHp6PBY~fpMy?bdymr+i--}+^m6~ zWr~p!p<#kkQ+FsHVgNkONccf+2l$lfoEIJdq13-bIZ%;OJZ=#3+hr)YtSI}6PFaZiiHjS;FK&60qBHlIYCpPL)ff3`+$`i ze^7D=E}*>t7UhJL{YTsqtp4Fj7ho24L*g<3*NJiK*uW!)xTJU@@b|pqP^2!nW`o~wsixqjkGh9Pd8lTA=GY7}c$Q9YfZ-mv zG>zGN7iXog3;a)TN`?aNYUvp6@z2B_A?<)Tzv3n^O6Wuy%s50+7Y(WbpUN1fy+j3I z@hyL{ACj@9ZnObw7f2P9`WM$QLy27T{%Ta9?yl?q0I`}lPj%n;ijf72ozMIHM9omy zMb-Y6H~}7?<@d1+I&Phnix)wCGVp?~u-|gg%EFpF^Zg|_HLvS`wh<7W`+fNQ$6Ur8 z4-4m=f+~*}!Rz^kLdX%eYG5D>1-t8xJpQ7l&;rYhYA)^2{{Toi$Q!}~yWwwrKrJG8 zT(D{gZ$h-)>0?i0RKL~#020$dxwD0@hu!`nnNf8K#nuUGQO+gQ=g8uy<0w4tK77M8 zZ@VCPUFCB!FU;H->Ch5CN3rIkyo14SMDlU z7M3&7mLgocWw-r;7Z-~*n zD_Lb&1*EwhK%hvI#UN^6$>fi+tYHgw8CwU+i?iDXpdkh(pl{NVPf#IC-Qidw~lp7b~ zV6iM~eq%!Lm2LZsREM|EDt|w}n9EDzHB9e>xhPq19)G(kz-Cm)ZwB{Zm3Tz;; zejwMO>6eATuUGAxs^BC-Qlc}H{SxgTgsqIK4ND5??lT3#QjTGTYhgp&$V3YjUu3+g zr6>Vrp_ zKqI;-0H2cncer~Sm_mLhY2pTql&On9$N zsr;Yr!&OXvho{!TYZul%Jo{kCZ8g)@`}%}Zuof|W%HB@&e&89nkT_^PoBT>R+6I(= zUB#fb@|cGKO4=cKG~ikmy?y@xFcEJZ5KfXJ*366FqF}_&FjqeTZ+*Szh)jXkGs)H- zRr-QD;5>HwXdGfa7!L&>yM2A_CsiPkGm4uI2Mx^a>Iynij|1#C-Fc574M!cN1&MUS zu;KR%<3RKcn2Gc|MS^4SAX?Y&_)+cjgM}hc_s)~ZleCjlzClLL-%ODcVGz1Wuy58g02)Mv5@$Mo= zm)zpwj05Th%;9dKDo{1Vx~rFL!+Qt19#83tYC?(-#Dcedo=!#cIW<~%_v#kCsOBws zk8qB~unB-;)t*KnXtJ+rA%&sA#C8(Es{Z2?E`KqX3IkR^@I0g)@i)20-0zZvfL>X2 z50yi0c?#pj`iuScEVv|IV8ufIj77xzl>J!Z>Tg~{#BR?`$Pj9C(Ux|H!x>9Qr>Rv2 zYo^d>i{(KD32wp>L?6y?MLcj_dDR4Hrq7xbr@P8O3OtUaZC@oX21m2q+}I*rqatKlBp zhcP_2h+szU4fiV^$pZ$(bwzE%U{+ETSGWWU9Yc#z_W(X){itGye&WS)p(UEa-jT=f zOSSx<(22if#!`7t(HkiJM~RQztX_DHq{yQsXD~cvY<2Ko_Z>HeF$tWJIdbIyjPnAq z1ygCF6YgnMq9`?qR9Etgd1u_R8{#k;^)g0QD$JiRuRG%BnSojf;$I(mReOYS)W^uI@HP%!)!Xa*62=5N(J>-HGDY zxpPFJOK_oB3Y32mC>U9#9xhNF%4gS^vZO~2dg?PY6>FdO{-CHTTDpCIU#Rs8Q&aH9 zg>Va4^&L4armo*tI9mikER;2 zOQk#=FmAr1G9t7W!77eB$)p5A7gW_X{{TnSKGX^}9obaq?QCxS%I_=G(7u=9N9wApHX9-^&S^zsOq$?qxdC9 zpIlBvuenEfK?)+z<$?{A!Br2;v@5uf(_l;PS#A?U{HJOt79<9r;R_lS6)O)h>LK#S zS;zGllvwjQppGCS0L9la+8RuFj-2i!6uvB+7%KUWv*m(VM`jRsE2!uLt?K@uj9yD2 zQ??9$G2^1@{UePR9(aW_I5NZ;FX8BooAWi95Wc5pv~UdLauww3FG~JpJnLxChR!*7 z*O<7Nwf)S*T&os@(UcQ&IxUord3 zm{eB9Nt2aV+(KLN0^{7n$oZHczF@P*9_0vIJjN}p&SpKqsSJ3Ac#3tFhgw(k#qG)5 zq#XE`&Pgw)cR3*YMo$CGxlA_<+`7V)Rv?|_u>LVn##fFRBHFa?llSTy=-;8A1>NLIhJ!GN=owVX6>BXgtbCeYOz31AR_w zxn3dtSXBIlW*7p1JQ*oV8m3E5EmAqS+<~9_1O+Tp#l(;xaB}8U zxVM_){{UqocpB^cPgWoq_ZMlgve#? z08_dE2dBwQzbN13G`&6eZ;gy1lR&gka{~H)Who^q3hfuh_VJC}w8}J0OQCa<7lV^p z00>R=27S`xbO*@oA4DqGxBd4iBFCBJdYl-10Xega{8x8z*`TdJ??dM?@f(ac0^~m2l7x z+&fl?)p3WY{@_$T(XP@SVed6K!B1Sq*@fy{g7eH?52V>6+GIJ9V-$ZeAPVsq%kxon z@YcJD3r@vxEtqWA#ANPbE-h=dkUizhQ$RI4k0@VvX4~|yC7^l`swi8Swl7RhPafy8 zqTI^BWMO3p(G2wMTuaz(Q(wfSPA5tzMoJ~DIRCrfF)9j?i#T@MHp9` zjRw`h6_z>XEG28igKR)ltW+v}5tHyLga+qz4$Xd zgDID8Pe(XXH7kHG#8o!_CXW^3GHEH^VkOt9Lu>X&E=JsS6>8dI%*bN9m2^OrTC)yz zf||kR9@pyP9wl_gb_IouKN09Gk1njS#E}Kz^#QE3Ej*?AEri0w&9_nzoVP!7kSXyT zuLqe%rxB_->K8 zHi^r&vK1n1i$$S=8D+8qF;k5RSk5_5^An&Uz>UERt-)yQO^@b3WC#VQKrjBFT)Ou* zq);S0kt!?lW(b({SzX4Q$MY~e4xy_ka+Ina8<_P$_&K>$V6WpPiPUhxD)fYG>=0W- zMGRgW5albj3?+Mlm0u7IwR?%6#V|Djt0kh&Anv}QDg?kTapaZzQ~;K}AgmTJip+H! zLgj&?Cb>d2URMLO=sROZ9AcBpkA+y@P+I{;-c%oZQoJa6ynY~JRMJ%=IxFO1QESfT zmOpVA7CIY|inCN#AA(%h>|_^cP$Q+KAE1S0Y__blFw+Bq3Xt)E2r0+Le-Ka&)6Lh8 zNkU43@I0Oe8yYffK}!`?Fj#M+Rn1qi!*sOuThpVUNQX<0-^}2uG zFq9o2EdiwqA6*ib%I{B9FXCS(D9^Dtzi0CSfNoxaqxE(CT%#a>U~YXMVqN~|92~0Y z=jeT$?aOEJ{u1A>ycDJXCVjgaWol)VMm*VI%5n6EIdd*dVZ0qdCC6FaDiSUw>)EtwG_ z(!pV|O{5 z95%-TL0(A9cuhz!WR)I>V`zVh1Cr#=;L!A$Si5 z+!pdX{!pkZ;-`Vo-b>=N)sc~2U`L_tmBD-!5(Nu|nCe88!$Gq8i{#>!e@x(H>=)IH zFt&@O_(&uos^bd(01^=LM-uv&J5n%Pe#nm$OF|bFlr?c94tQX#1w2bM5nAdKoBhvv z{^L`D?jpy{#b`kqyJH;pmQ<$0R4;@5EqQXW4 z)M0K$m6HPAAUQvYK!!l@Tn-@hE{(#zCEqgy-Mn)uf{${_ZRR={nq7oIU`3QgN`Dc~ z!u2r*o+T+dfLdD((p0Ju#w2*j+@7;N2!Pk^~_{i8H6J;5{PGy;%&I`IOY^G zRh4+StP4=GE?hQRwD3ewrdP#5!R20pQmtj;{!1utWx+r!JNgaViY+kr7#G&6_fG%~ zlmb{O^nAoPu`*PgJVA zHE%2x*=FQPPijakZ`d#LUXGfKEr5=F*PH2~aIhZDZn&-;^$0&)cE)p#Jbs?&lB6lU z5S6Du-R?eJjD;`4IhV{3a(diTL61U(z^edSs$Ht-dFHV}m&s$GTa9_%4J*62YFrB| zu`#O3y6c&cfKxfZjsF0DP=NQshe*-mn=juWAP(_^p;>F6kl8?A4O8 zugTPGE9_(gghK_K5~YRO?sp9W3}Xoc+S*m^pO$ zl)BPe`BSi3!0)nOiJFW@VyfU2m=81~DeeTjFP zSl!~ceu$IAWKHPqJif1Eh3(~dm+vsTfC_O}D*JrJENyofHZ5FEmA)hIPrH~7+{Y5o z^BRTG1YU5U+&EPr;_vN*pXyTqvc(TRC0v#5g>1d0kw`LXbMs;!ze7h7BGi8Oud-Rz}DIB`8;us49T+^DFmB zSL z&Btmq_Yr+w6veA#S#bsKUcIeGB$dg>1^`3BmF0`|Fe>6YtR=yqL<&F^1jP&c*u5q0 zGg5nmq7qxpxG{vPP*fsXA`09lh4B**Pr?gsp5r~&dl<@gA_;8s4Z@n{C?#J~>P!OG zxF*4|V04cwx2`5_0ZOSC^ZsSscoZpBTbEoHo2rT(S$IeOzo<4Gy}Flx?M_FSgnsJS z8r<*@H>$oa0?Wh2M}w2ZMO+xpPpOj18tZpY>YyFt8nHC0U#Y___+>*jP*`+j?;IZt zKpX%)mgkq60W>;VdsByV96g~%lHEOne2bW^AsdaakExxlHHU$)T0&PtA$wAa$)Sey$yr{cPMRt3mqgHz>H}|Ue)Wvh8Rn* zh}x$MLh;qx!(!k?o^Fuac-ctw5P{{g?S~%aAg;!_qYh4b0_r|N%Xg9?gGTOBl^ZLk zc;^pHrdk>_O0RVP08qPDt(+%=_x>UzQBn<$VgCS+sB8x}LVZ8=4=tdFR*O%qA22Uc zR4mj0QFKFvdZ^lJaFE(0rSM$0Z&jxZelk5Lo?(a=FIxOWcJc3PO+cuwyhNiviAuKY zWEGy}6$SBgjBB{zUIiIhrk*CDjjbhoY(#>BJvT#uj#3L(Q49G&w?vPSKA`|AAk7BO z;k#0!bYg4bKh_syHni;b0BmK;3KzK@@}41b{Q?jmy1N)x$#UKxK~?Kz8E2b$%8Jo;7+`l#vs%`Zf$L^xla;xP67WxXjM9_hU<4i=az#?k{ z;-#gn`icNsxD>@MnU*uhGOt&gl*)ss3a#5H2YZ1Zr($@A3PDp#vT{f>d+-F${xl%a zT%_(nYb6;CH=&IZht#&)^%%X#JJ)rC3O+O zKm~HG<_@ix&NkRoqPW<|hrq&|H^g4Osg^>iV+H$#%~Cah;ZlS3c`SJIVlewef9;N_ zpEdsgNaXs(Kd8Er^v~>yVx6PJ z82BxygTi2Xm#3ZCK>#QB3{LCRF2|Qa1HeAv!cgQ!DhXVKsesWNj4+_=$YO9NhFrXXz<#IUV$!N1==;Vm>EU0a65Xl}q- z{vwAYUH~+;FRi0PY*6Z6oX>~;_YHPEE5{rCe$OmfEF(#J9KIOMrc`Vxs{UYzXig!m z;pS4MxOQ^95Ii2`Eh>3VqQTYdhd_O<&>6 zzq0#+=DAA`p*@g- zH+e10bG4P_azqC<#`V>FpIbn+b~`gF;>!y-(Xo1LzxJ@4e1P30I`b(4l{?Ep`R@Af zA`)6w@sHMel_lv;-l+coNFfPYYfn0Vm^5~CY2yp8+&lm@FEdB3cmDves0v$ZXz$rA zSTYK%%yX15F{{VP}*Q30O&`-D) zyFs>v&0ul}5ju2WWgns*AiNa~5Gq{_PGe{#IWEu|cQ42ouC?_8P#=kZ5*lc|#UUZq zeB2Mffl4pbx)yk1jRzLZbSQ8bwgZl#gB>R_x^?7=p|bO^#o6NH2&iFk3>2h$l+K@3 z7$`48h6B1IVnMdFj@KOzGO^O7T{{>pYFfERF}U<#bW-*KqgkOWG<0j9sZq{NWVYKl zBKD<0ZDZGPuT2)A_Nzlk$f4w3{Xr{^M6edST*h>g)ofd92kt)L{mi!2@{ldE&QJNT5MqeE+`q%`CBnzJ7mg8bZlvWNsuBn_%m zL5d@cQz{h0nQ#8Y06^D71}}Q?3l}BJ0cv+b0*B&1vwcUhUsADz3W2sD0j4+#zr;yq z%BZern{nzRrL{M}aKS-tA*j~M4+&cgOAjR08|oj-kT`&oxShXqO$U_(NTBfrtVdTl zf$VB1c=BDxh2G$xQ`9W7fKYxzXMttB2#%2F2(APo(`M}E;ef4G#dv)|3We=;4iw11q@Yr#af96rp9L3J zE7YQ``1jm(1p8zeNm`{qsF9(?MuFp;s2pNy$NvB&pomjK)Jq9~bUlo6#@e`I87>tN z0-QjI6=??jfdMAXYFuxW*sU7@AR$!H!Eipzazf>d05hn+)cNLF!Stv+QaXn2kK7sk z-cUkYG!ura@lh~=*D(|60w|3*U>Z@#vG+Lx`G!`7vckowO(L$3gi5u2Zs3BqNGl5= zq^J|ucj_r+;5XhsC=ifW09GHULL1QHS#|1FRTja={r>>DtQRf2*2R7WfEbXWT(LY- zHJeaXy>*qEboyXaHZgZ6xoo*4YWrd$6!8sMsfw9o*cS8!D~~or(Zv*~Pv3;UYD?Du z2Dlyc_=?3)5-ORx>)F(LkdT7!A3Pr3WhxC&X*KlV`iqB0Wu&*{7JYd`rv;l8Sgy9- zE5cOeQr*(-_))IPdW<(!B)A1_;PH15LZupbF{SiP(rJ$Fbiq0jF_GG(hmqwFIs|vn z`G&EjVcYFHn{y^6SUr!E{{XE;07`6TKXvz&10jm`{#rf2vQCGhlRc^hP`N%wb^%Dlgjj^<81N#P+1I$7sKo@krOcuOEG&ynBYJKjZox8B z%}bnDXp}u9Ll4u5c51tZhL0NovDXX+6+F~h-*dR`YDPwBvDJc?q(S1{x=a@L3ap+%JhVmZ;OZ4i{*m2cwR_u zjp1L+XCuhMgc=-@f-j&5rqe2L3_7j-Lz5wKF51FwjaPAJ^a>tW*5&((m0b<) zF_yCXsbxpZ+z1uqBEnp-VJ#i^(Hn)L!FB>@c)kdOTk83h1cPcYbHe4}gH>flGnsre zk;zr7fFZ-&TJ*1QAmH7A>sNsNL`b^>^+CtxIth>LIaGh1;{gT^kJKZAgw7i6{{VQ1 zhKpAHd5FMfo1okNrExaZF;54|(S9y=g6apq8~h@-K^BW%c8&UYi84YHktm?7rm&Z$ zU>pO_hxhr9gC}OClH(a*$lQE5nfwgKbW>J(vC0to@B zC|krO)X+n2tDzVibgsSlpx3ZpJz_Ck30T{?RlTm+1!9O`r#H1*OH9pUi(m zCehB>Q7kR{nl&7yO$@{ZG8`dL0>zX=_(ys&>RR^0LniSGBQ5GxSBc37;N}%@ zaEw$|I4Ge6Sdz$AWjKt4HU)0(pc8p2v4#@b#xX^m(umOM=OT8Kfnacd3yyyTFuDoN zd5rM&G4cdgJVRFXUvl~26ASd0K|!3XDlan8D_2EDJkEO#nKXA1OhS%g^?gR~B&$iY zfED5+xY!u*q>&XyiS4^P?FC=cQbj#TS@qUxMLXt{YK!(USN z*nLFcZR%5rJ(CAt;sMq6%}{zk*FK1dYP=-}$xvC>St?4a;^I|vkfN#9WUl~B8rEAJ zM_omxwVV-178bEVl<;&wU~sh)^9seC9Y$2`T(>dcWdfl4hRg@J6)L`9^<9d%w*3Xh z$!o4g^lx9u5rv95P9$V{6-aZol3A$`h7w;9aXSC;k6xsXmg*4#KK*@ z`khluKOz4Bd_*)+d0qbi?Bzg@To?Ec%N4<(1K9rI`(whnCGact{w1f2SB?S*qNqdA zUT*K;hR9b(H)49@_GT)gnA^XS0wAHl)zbd}AE6NPLg6Si^~>r}Rf&tNo4j)Eg$S^^ zG_9Y{+a@zLjIwL+y68%Ts`Oy5JJ89Hv|6wa4llK;sL5cfo6`Yq1~&fpig}}uS0 zNK=vZj_+70)?}_W*R>$1 zdV*!u9MrWm6gAn-L&g%0*#TNwHugmo{nAB756S-k(;XrQ0dE!ib@i|@aj_{}C_S>M zLt?N|#duX&UyIe9XX@?!et05uMyRJI{q^~;5n}U)1#h4Ia&^Qs@qEVa2LRiJ{i9=k z9l;2q_RrA*iD#AC{Z4YJ;7)P$!-yC^ayD$RSBm56zeK+pn}YA1>j=4p>~g8E5jB?> z)Hro51Ae+;?*ef0M+(~do3|+gsZkeMNI-5m6^9TSZh$!t*EmS2hF&tG*$HcmNzIucOTbK<>YCWU$#k!t^Y>P&hvz$iHC^_)b z(x75(U~vG73Tj=+V+;^!P`)9N(YS7ZJndXUq^P@~Uv zY~*`iSL!t)9M%)mQ9TN$?pMKoQqGUm5mZ1pU&Ozk)jUh_5h}l^j{g9P47&cMgOYZ@ zBQFQ)9jZT2vcU>&7F;XpEaG3(DU^FBFdwM3P>gX&Sx`KI1GF)fM9e@zc#q6`l`-sz z7xv2{@5I&zy18(WM2rF#pcz1G@d9ihhfye|cp-T+m0T1N3WakDrHx{O`RUh}h!t~TInm-@>=0qH`;=oHd4q)yQxP7j3g`zlQ2M1jq-AUM0{}d# zW)^msI3n7L5vU1jdV|afR||7c-M~LGnj6YYiWb4wf0t}7R}zF`zl}&lJ!(R_!!Eq19gDPdE#f^(%g$jtUsAaTyfjTyVnoYbz*(Wn>X%%^ilK$N zVa}f7I~{7*JNlJ?o9OfP1(fWG^VRjlu&Dq(9GiGz^LLI*x{Ba9^0cGO+_<~h~fnR9shK8IGsF`-3 z)C`Qi4%mb-xWhUll_>#~+NTlAa)n3omaqg6hJ`(J?4t?TN8x~np5;CJpa8$P=yX+c z5p_1}aEPUmV4IJ4hk2}**I{{qS+b-d^#P62JPlzr?}+V&Q_tCeG^>*T0KG=a)%L))nylN><_psM13wKH1T{ zudAL(Q>i|saY8L&xD$C!#UK`2LCw|mHgx)w!tNG;*N9t2Xr$f=_Y~+qFhaj#aBQ)7 zrTZ$SI5TUsE(1Ri3J#zwDqP@{uttJ3oJYWzE6gkwB_yol;#mg_AWfE%q<{XY6`GU` zJd7?@`nc%}hbW?OkRrDCQPh=~OL9x7_#Kl%YpT;cxDH9&3HX(jEW13xacvzi{E!*6 zTOWS(HfP*#n`U)&cOAg6;^NdGfx+#I3NLUf1@~|jtLntxKrS*>=76`PN{$3LBHs{M z7VbCoe8O)q)|XKxXcv?csnooe*1sai3DvS1ng_)(42M6{yM_RH?NB zLB`cUPy-s$&$b%UUv|q7-&YZ}2izQn`i;RBWkY@-n6`O?7!M2%7kxqiPUX$Y0IYds!fqQ%i|eg6Qzaq88zz2_RhWwBD$uRKJlU0`+L0Qrk0+qd;B zWt3XFH~#?Hb#0N&S*rXo)`P4NFOGMI`DOPw4Ni);U+wn+feipk0axPR)DT(+QRai5 zzsz)~m3eB~Z~ZVb!wT0pbLs^wQ?piU^g$dAt<=l+hbcv>-KQJ8{8&IaHZFmo2J^G@ z#WKsTBKSNUMuzGiFJ4bfs2sQu*I2%F)TZkqIiHr0I1J#?jw}e3rh9(6tq)} zzpKa8LJfe>@SHOb5`xETw{a)pl=1MP)y?36;3cNEtG6g#atDZ0rc<G^$_S(yNPT4{{WUg8rG3({sVX4GXDPE z*(~GI-%2AYh^;ghF=NFaP@&G**l21S|x>*v-E$l^53dpoI zR1GpaVZv0ealW&}sYQ+$$)eJrup(Ymb$FOgKqZm7xmN_?7RS}NEywCNL|WN&dWl@G zTtBEYNyg&Fyf?&8b$G63ubnWVPbKUm(8BGgso?uYXd{%%Q^Iy0VHATzv-J_;v`;95 zApZdHjwSB#g!~TKvE|7cWzI-8QtG9t!wdXNN)O?Nqzy|6?jUp;U(9@}(&Nh##i!+lbZ^ziwck+zDfo=8ur3gt0F(!q;S$sMO)6Y?fK@=0 z3__VY(Guz)fKP*Y_&AF4i;PAJNNO5DUDiILY`o%DYR4*N{ZT1Aj3&Bc6T|KSj^8kO zf?bhUySOYS_()wKzY*hk#zuJ}87x&9})z!eJte(aXw$A&loUy|ctleZ?{ zSZprs+L}RyU3USZj5KidE{zIa;Hb8jeL>I}RcHvIvk6lJ;S9I8ik6j|$qXy^m*7W; zt>v|p{IL5#U-JX1P)E&jpMEB0^umRUwhrP2$X{0stHqJV&mBZ-(Zq}*9z+xt?POE| zd=ik-a{{aYD_f1p8?=tS4^Tw_91a*pl2Ns;*`(=fR=w;jYQ^`+O{GBf&-Ti&Hlq%8#jRR4VeXKX$UD2oEJ=+z_ivMdzRTgTR8T!p@Jj zWy)t2P0D(b9r`|gp($_%c)C^Ji$G{eOYT^?ntX{$z>KSUoyr@KUL zc~blEd6dh-fd!6_+VS?fxkfl?@Y=+_LfZDIRmQG6Jb7+@A9GVJ@M!Ianq4}aHh?-{ zb$Ldr+ia|?IyF{z(PK$~tGLTTC?o>>*EBSHhC-2a9y!|Jb;dD?!rpIb>z9rRwHLA+ zVwQOCj%qmgi!IG@@pL_Sh?yvDDeO6X`u7!Rn5LD{^`G?@7KzEuci+^%zJ?t-_vgeQ zQPMX2@Ak?fITXe8S6<;*x^~vA{{XMaZmlta28u9+>jm9Nv&ptwx7p(%m}{)hBN;AG&y8 z@*o*fh_*2z#>KNX6kgx^Lzudg#T0~Rol z>@huzvWG?UQ84QnU8`>;crfk}foI|j3Aq>tx;SMz5VuqCz$(M1P)%lrDr-O&7gu9v zVPnb(Hm49YDxF=C;k4m$JiA>1V_vv0~iEDuu>nSRieHL zX+Wi5ErysX7eEuyDD@IRscQxsk>MH=n>i7dT7ytB87lTwMWzkFs4UYrU>Mz#y{(a0 zN=TOjvMTX%d5VJunljN~n~zL-jjLe-mwOBa;jG?bo$!d*@@>^YS&P&d+d2v2rZy*8 zM0p~)m2NRG@jiitzU-T`TSY zBRkl2EqIpFpPnUn+VR{^S^^qnK|-i>`-D9JKbWZ(Rm^D3mI`dyLjE4&WqLCSrAkoe z-9wpL{YP6ts6CK&#i6^?xSj{u5Q2W9bY)fhEcDi$9Y$dfCwvNtXpCR@$(U?W<$WKx zKvUh*>If0Gysj5?Jo5R%I_$hf&-G-$YIeA&ZEbf$q)jd+f$8*1fgV(IGx`3ZDZ_^` z(7(?!e4^+pD*piL2+#mT-zleenS1Ib#&q*t)15GUv z@9G_-u&1;IqTrI{DRR3wKFMcj?r-bIuf`EWtUv&+k2BQQ1PQ_U_Z*9q8w5q&w13~2$iW%|&=le0zcC6h(z~x{69fllLk--u9FDKk=5i{= z808n>GM@!k|376v>In1r?{P&hRCx9*84*BjkJ&opQ2+7hsUvqtZ4 z7CV;0b!fd{Xf2dGO*Rn(Xa&GmFM@-t<6zk!m8tvP}4)p1r*f$hC!#iAGdJ`e7rRn#%}K95n_M5q<}D}&c?vA8h7WfJYE z27lM)3sADqHAjeH5PaVOI5J`-gZFTTWf~7;y@HNww+C(X^}`z3+avb`+kFn8o4{(S z9a^ge%#@PqhFR26VO(y;VOOTjzFkB;J7Vr5#7SCh%rrA9Bs%Kh*p5|rhFfcmF{`vb zb}^`Xm!c04fnRJuSksDvgwu#1amy2r3}lj+Ln#Y5NcAAwgeW%|OTb8pHt{HY)7(^b zHId;cp35^S3YkPMM*iUjpwYwr<>fq8)9wRoX)YN~;tjGBP?%zbc9zDgt-!1J466AO zay1T}QWn%3_vRx4*5KN>t}*~zZ5l@%0;TTpQbVMy+X8Y_)?4IM3@th+Y=VNXZ_EW4 z6oqxz>2L%`6mj~L^sY8-%VV7n>J}j7DStCwJ`kwB3Hd_M5(JmG0Z}ApRt-nNoTXmG z0_DBK>W9l~(Kkvj5X2i`z$EY$2^iQn@R#!Z2y1Yb^EkqY%%ue^f-q&j3J6qVF&lz) zuu}z#vZY{_1pAkBHF75&IXuM`p+YVSkq_kzS<9!0ceo(r1DlTF4t+;=RsjN1>Yh^0N`CR`1 zyB^7EUz+Bfg)+sn?{Q%s80W~VjFSVcfr$gjCbpp&}aBjhe3p%Q-*H zNki~6+ht#0h?gG5k@7$VKtC~Y^zvdO6A!u`b3|NtwDEn%o(;TrjsE~++s(TwT!gcl z=-qvx%=DPN__o#ymlk!ac-p}Fr;LVf>Y$>Enf{o?{gYqT9{Y^BS|tNi{{H|hd9Vc| zPb0p6QqVjKpk|}%i!KnM>TsgbJX$XCm|Af(MbLSsob$`5()MD2m!%vp_3mI0?LgsY zTcKXw;ZUdm-R82t@#a&4_(_c|$A@^>&~)IovoxgKcmg3+z&&!PbLDrItHt9D%6TtN zMXEnHG)rjOOMj!STZ%F3+AZFY^V-zPE^GNQ@|9iG!nXc29V?*5U5N@2v!~nCB2BRB zXEyim^(|nuBfeVbd+rn+n>E0Fc>dvua1{RlAN3fVo?Aq&fKX+9&Y(_JM1rixZ^1dG zn0IR)eg4Rpz|`Ryo)>yd`{=04S7|rmv_4|6C4kIppp8eMi1ntq$To~|+&CLNaRUu| z=^Ck?CWYH{vDL-%Dc5XXO<_&k^>F*Xwloe)4-{yC)FQKT;R=k202SVI3jjBdm?`!l z5nK@F{KVn|)CAMA>2FXlQQYQyOEU#!3_(qIHK4A(;-#z!$~;aX$mrKG$ORhtk49qF zHT#e2?=MhQlsXfcxt%vGwz_7^2m27!e%XCO9-@K$FWgFJ(js86@N9eo?aZX2jwMDo z#bU*5w*WZ~;UG)m8wUlsNUVkqrZDWjNly`Nxr{->y8t0?1V~7A-@>X;h^VkEjZBnE zOIQV|a#?VuP*}Lh$qCUL8<;=<5R4+!O8C?SD`1%b5dj#I6*Vf7<025s5NjuWiSq<^ z73LY8S|mAKD@k zqm0!Mt5xb!bN>L@&l6C4)5!j(9nw;VKlJ{|!L^X<3vZ&|#9=fdvrvWp`{6ra!cyN+ z=;M?7?jW0|8tuxnkWKGlydj$qp;h#Latm$%8nV?D#(t1;dIIP-o;81%0=kGZfUQ>1 z`CKsD#i+BR%MtYc@Z5& zn%$by_^tH?SXS!TM>$pn9A3ap3X8k+A#VLbzJMxO(R!}mK@*jgac1m!w-wJM+S1a| zVQYNZOZklm9CK{4JTE2FjIZDYs~!iFoT0A#P1|S$=)2dG{KaH7i3;Z&-|L9~08ZRl z+r|rc=C5VSN8u*Rou>Ze=joL#4x14+&(lo?;*J2xq1qpc7Y}rYQ{`pcq%A$v~TN>J7ka#B?E! zp>NbivMT%d4k#BmK@nn0O0Gy1tTRxB;Cf;;SEzj=>IOG3U;z4@Q86||+%16uqh~N9 z2?&m$2*C3xSf>))D)k>?18Wk?m=NrTRBq^147`>3itPodMK@$N_Q-p|Y>wtC4{%AB zs)4xgNVWwZa-lB7@8#L4YfWEn}R8TAei#VNjQ1g&dbb`hrsA0fkXjoP-tN3vN-Rc23+97gjUQJn<SYB}zd<0;=Duyts=rQRKmRJm7Y|ACB*Kw{Mjw596wiRf+l8g;D z++)Y0_AD^pagxB|<@`xgkO8Y%Y7qA}5+pEf0lVK3j-{Vd5y!X|mwmts51WR{MLwm{uQu+5xBjk-8Y7!^}%`IZ|cuiNfcXBCbfrK)IX*O&eO0EqRv z*tYvW>-m%f+G48z0CFPYAz{_iz9qDlAG~`X%Z~K&rEs_ZS2fD#rJ^{-G9iPjtf&3&W48 zj0^x4JO2Qc2ndyxty)lYzsd=~+FFIC)@6VD8At?Ocm?;L`b%oRwhDV++!cI}?r4Uv zcs}47a_hC?DOiKee}Bw2Xan|sqg58VYs@e*-!b2=Y67Ho4Z4RCtO2p7Xix1=+~geS z(u6^-tn%hJz<3h?;W(gvn*kbCPYNNURvy<*WEyvCdH|d2fggbYQJXf!Hl3NL>SG{< z0uiQHJRKs-)HH5@6ubOyik!+K1p|VQHvVPiIKggOt;IU&ivZ9rg4rvf<%?UPe4}aP z#aEIti0M=?y`gUvd$FcatnS>fYJ_hvTuj{toZcrzaPt&(V8(}PV%PF~MiD5YlsT_T zAAX=KutF0!H-KIdWlVWP+OqFHlpFz8rKBxt{jPOUvEYT+t7>)yIq^^n>2?Ga#+CXn zh-)Yz%K1~2=-%S0;F8i^8_i))n}j0%K&GbqEqs|disZE1L&t(H7Ns?Ao==`F=U_)5 z9F^N$S6{e-+N{R<4hP%_2}cVWeBb{7BTybk_2%KqDyp8KwJ79ym9;73q*%lQVkEOz z(pkwV?<(O;pQa-uoKmUr4-$apaSk}8#P6}>a|&%m89GEnxYN`oQqXxA;&&j*l^$%Y zge_i`EXa?tB1A#zQ3>%-=O3~JSS%dpTuTqsM1Z%+F53EwfNQ#$ww%T4fZ2BzJRvgJ zosbo1cj7F|pHk`ro*}YxRY7%eqTjV~I4ot|4|O#+l$5CHmRN)7kiHA*g<3*K^k!h{?Iu_cDK{mz7t z+HY}nn0JOD#9mLGHWM0ZWN~GEcC_)%Tf{4lpDu_X-+0000Yr3RtLDsjUHDL#!F)q-myUm$jD4u zUbA4?VCq-9(8bIl=b1)Ng_jR)P7to;pnp=hAM%3c%C2wjDK#`@#&-{7IcRjUrx>BK zp8do^t&7n;))vN^NH4XP6{QId(Lu|U7GId_Y&6m#kwt2u71h>1}<_Ch6rF2);D zpY25*y4qK3-Q+d@0IU$ou8vUv1bK`5KH}6M3>8lW{{S($4!h^C;$59VVZaST!G%}q zDBO5Tx6kfrlrX%Wf5ZSLxJqKtgGYS-0LZMA7ZJEty z`9GK#3?)GPa98R9($I#2xof+!{1IwY16w;D(Bx}>FWthG}db&yo?Lee&Je78p_K#f&!Bd)Xz;R-+O_VzS0Ay$@f>Cu^+G|bm z_Q-5WERSvJPEpQWa4o%6TdZuh`K+=D2WnU#(!EPi=Z-sw+K_gl!RXS`pKyqTcq@4i zS{JrJZ35JMrKP+a>i3esM+GU}t#2u72qdBq*O0$O8rG2WcD9d7q&RtecLIsEtVLbf z*FWv=5%tp%<^2AmF0EUiVlCdq(bW|bMWt2uEOD%-kHj`rh0yZB*$#rGe@cE~%nl2{ z8nP_aYopw)2YcoyTVTzA1y4{mExB-HO6MVyM_C;s=?{>0NQnj7oW@!c!3jDqQR)NF z67X^4;(8!5aBz6Y2qV&97`z4jO$Q#x^se(sWm(mAETs=QEmcK;DTXwIV|*&*Efw(q zQYpg;(quIX+%+p{E#risj2IVT70eWkI$eO*le&vJjzU@~E}@c^I}FyZH^jcwiBUX{ zge7ZU&ZFklyvu@Q{lX0=QsR$GWzH9+u;PcBg2#hW;xo8YNNiHz@UUrTryzhqm&p){ z#|TcHK+9Mx+>O~w(Jcaa!_DrOumtBW!W!HyVC)pYsZ1^fw}{cy!L3VexWT50bd%vM zQ($#zh8iIT1H>K%lUk!#?VAVshU2*iG7 z5f{W2aT55HNK-0XxQlQevuI6Hs#V6*#yix#6PRI@@o?_ku?-niu4zo0EEkSan`M4t zvTa47iD|(15d)(*fB{6}4mhfXB^RdU!E0>ZCHVv?8ad5OB#u(U2jhCSE3I3^9}0|k zjA2!6wdsvQvx9vwa37T={E-n3@Wguy;Co&7qC)cRt&DE5D_8?7#Ui0t!mW|Dj_5R#9HMAlIdDn;g zf5b}yr?l#Yz-sTm?lcHL4&U`Hl`781;v;DbQm+31GR!3?3g7gJ8Y<3DsO2=f68(Sd z6vn7M`-YiC72iMa+#@APL!kdGfvM1ulRuu??Zh0l>vC?D$;_n{{X0kUV@8a`G}9(a=-Q@H11d)V>ZTz zY7g!GK(e|oj{57#(Jh$;6h*b8j<0g#Fwp?!t(}~y-(GRrx*(#Jf1P}gq{R>xC>4Lz zdxm;IsHey;9+o!>*rJiOZT=IC$QCaG6-B)H@_K@Vrb9}6bH@0%C~o!(ru+2(wL796 zJYw+UXq7Ceve#fu`ZI+p4B|IqPiH?$W|jj($SAJS`?&6hMoWDc{2cvdpa2Gd@_~G8 zkpQh!nQOH1W*%fwj#nx}F2OxSXhA_nXM>!YRth7Bral$?62MlGq@blmwm60mJS7IN zhG7fHv^D@T!BhjlWq0&|wi^_t#M4x|e6&uBc>e&(HEcL( zvC$U{#+{7LdbnmA4tc%de8nMF8s-BQ4oji{lkUO7+6{l+AjTFy!1w+kTCFLr8D{A+ z$X!Bssd9iCBVA|sfuVETB2s;l(wf~na~f5elHg15_W>y@!odjTmA5cZz6facpJ@b& zeUi41q!7`e%&v|PiN*{x!n&%QR`QN)US(QQNmFR2L_QnfM`LwCablttH8}?=UB-L{ z4PH^8DtG2|G+P!qlvJ(e5mn|*h9JE@_P zDqodGl*MSExCtF^5yy%k6s{P6)x@R zlt~*9N9mM=t#T1oPqOYksprhH(QNQx#BN&Z0k-+8my7vI8M{ZXaB9jwD91O~AzaI~ z0!QqSdR5n!RK zZnx@MNp7AYO)wLa4LcdI&}dN`tzXrCU@qF92~vSCgX6$Muy}3Cc(@?yHEtK&)|xeT zE!*x`fJX%nJj4;27vPVos!Mb|bNiMl1zOq#KwU>3zmMiKmRua0{{TokhK>tfa1JR`z@kY8fYjW+IEUe^tg*dgi z1P3jF^P$v62LpfRD>uM-;tDzU5&}Z&54g?al`B(+czU^53-C&$2dDWXQeZvZ4JSNj z;;^v;g39r?qsV3O?p+g!i$GU(v@hL74T{6T!0z^V(JcHS!EN1ETLAaq&YT^)TRcq< zDliUs-yfvRfYc>lWv;B=If@C$nsra+tIh02g33m*;{8*uDifBfRq@z;QR)*w@~dHw zOOH`7C|hd!qg{juox!db9CDsZ_Z%ryYAw>2o+UDwV2Z$6CDcz;Y~k10rdfZ zqU>v5xN2f8GqXAU zr}&n%`7n3CFWe9dMk|lz;Wb4lMn6)(W1{~6xqd9Pe#uuZ6hWrK@UwfZlqwZ6-Y8c* zY+4g<3`t5Xa2%vrG#$n;T8lbVeJ%1^6&MCs^A{Sv;!ITYu-M_;u#^Up&bS|ag0pf0Lgu7{3K(Bx? zp+_-m3xv@>R~Fc(t|rPxK}P3@C^>-3%32E`)h+SNqCIB^P|EG<5Tnt{mb5$5EDLjx zVCD{^z9qmZzAhHV>~|Q6C>-Wv#11R27|Ojm4v^OV3ylEZ47(BSE};JaF*sV)^DpMM z-%(#K!Eab`hGgn10S%QKyb*RG1z1uE zVMtQ(6AVN`D3&X!OW(?nielH8k1RVGrePWuSSAb!o}z5B0Z=K6QxJq)AZ?16m-JmS zlI-|yhLEW{BHzVH%u8cTxV%W=mtEOiBLslp<~odNU5Q|BMU=5nC^)h<0^4XY=%iWY zGS^TwKz`;xo=zhTAm@Bb&BfRXSy3h4@@JGawJuymZ!r}H=>bVj0g18=T|idT0l+tH zzr+Ent)Klx76QV>E8cu0U%B_!;usZO8!XTz?!(H}@odCOmk^a_g9o!Z7_c5i(hpV# z5RQ}O7TFIh6Rds1Je*vlRcg6!1s8I(h%YfIYWb;kT8TY zVwUcJ{{TyX&FgF1a=^8UaP3;*c>F>dAYH$sJZk<33|!h4XI1up5GibQ4Ny^ibU*e2CZ(yn zUr+i*;{uA^;v?|VAy?Tn zWqy6mRp%J?>OxFBkuzQ`7RwJsg@cQgbx_7Cfa%(u|HY11BPoK_*%4@tzl9knS(7XE*}MJHhF zvMj1om-?1SQ^K%ag&d4E!F)4-Qp=DZxN^XGmZ3h-g`aQ}hIQN*lDN1v2Au(BXOza;WU$b1&r^vzKhNR0!^p-37hM3Q^rg!F`~85HvhRZ9;PZ_fe=6k32DC z_K_b<>y_>FhWoytmbIyomG78w1#U)aAf*zwOLI}Ok5y?G@o}WQF!e3a{Vh!BrxwQ-8_?>x&hgKNaHpdjsQ z#0tKb=2qc--*95WDj{xRo~7q7O<;R{O3*{a!0*I}iv!Uw=!6U(M4|vqhnY$N%qbLQ z)OE=za3jPim~|gnK@rf2r~u+Q#B7YC8pe{-Vi%Yu?O~?15_JS%Mye%#1+pzNmF{c5 zfGj711?)pQZg$onTolW)H5C?O2nk8>1>MXJAr@80cN4ghwsUCEYW={{rR_Ff5Se&{ zTW2xz?#5z(q4NoCuF(!vZJOOCNiA(TeB4;icJ46IzEhp8dt(JS%1#}dDXOz+knu|M zMa)<|OqEeiZeHd01Ch42*WzeRjJNN^y1-tB4YeH5mt(d8uv6=n1KdEBF)V;CvlZq> zTLEeuml%RyON{VOD6|RD?okkPUBo4^*>eE9bFdJ|zG3tNFe@?SL{*=BUR@k-*uKxhHlVi}d6%BY@c(?-tX%4l@rv*O{X=xe2>fgK7 z@dD)`EJ zdXz%9O$wBzil_3aRP~}(CtfPg@Qr6KhK2i9bGz+>B`GYtx}%N|++1`8tQ&kQU3_Kt z2(x0_hMFsn4D$g6YXAT`f#_52Qq(7*Ky|J1yf_~aSt&~aONUAYfypWw7OJpNaL+#G zy6KJ=ZMge?1QTYKXsS8S2Rq7BNC3uw*!C)YApvd$nnA$8=Vs{z?H8^F-pbLII|eqA=N#@4KOSSaLY#DF2O|P z@2EgkoW5aj5#jR~ zfE|w$kq`F7)(;bO8{bl%#Js=iGfmL*F4}G8TrGmbxJkg`9JHs2rrki+jKQ4j1S-yD zt4*!|Odh51SS-luX>juz$OoH-Yz|0QkAwjsM&J`Ulsh(-poR!mvQSMvrlALdC|(di zUG0bPPa zsnJlR4=*t-L^_x=P0Kt>Bp;SGa|3gDx+e@aold?*u+(6Z2yq=SmuyUf)w}f-pq|pn zP=fUYw(~O9R8$JmIN=c)z0XRR7;xDA!3iGJDc2}eXst(tKVHMTNVG*Xub~Shzzf$;iB5V?2brI-_wm69D z8&%wS*^Z1|lEofK*C#s@c;8VeCa{-%n8#NuU(|5W2Ai)Chij;MHd3{)4^Y8-im!am zd>n?+pWHwmFQ<>@CHOSs&41|tTY6YIu8--4bMtXtzfizR2~RUnaO>&+0H|dg@|zmU z9S5Jw_mcgTJb#!qdfnz19A=yzCi3L<(4?*^f>AR}zCw zh`8PreEwGyBv5fE_TGN)W|B0}-JIj%$M-CUyJsPA9lBU^aC@cBwDJg-L88W~z484Z zJh13fspLkJ*zU>{(n~dVhK?3_EZ9yMq>xIbUwP(Oq*YyT;iG}|T$eds!CG-;7t+@G z@KOWRe6FJZvY|1D`iyRdJSgV`;+5 z%2fpCW++hx5VtHqLu91*f>4*aE`l&FR(qy&Sqtp}165FJGXV)Dk}Yz@Y@*woXEKT% zLNmFIfG1=d^$S2&M7co$TMJA_u@((?DKc7*3^pZ8qi0ftd<+bhBpPWWOUMp69h)|L zne{v-=0&U21@dLT%4~2T$h#5J7^N3Hv2f%gO?Hs1ci4J7Cm z{?4J^w8Xk=kEj!uv>z=lseb zkQmX#89&>XLw=>I`iJE9M|{v}gUbK z)0Z6A9C+J@@pdC?P5o8=;uvm}ts#xMwt1~05jh<#$wx?Zt7EQlrM8KmbQ#^i6C?p$ z8DY<}+#_6(Nv=8bPuw^>VQiGS!!=d7FhI*;aO$E3`*U)fL0oA8bk>7ZwuX;bDH6X^1a28FXJq zt5{J*x(l1{k*4qNG@snGZ;`z}VQYvD`qFN^2L z9wTbx>SN+s?pOfaQ9(1a^D#ujr`#@VzN79Ykkd+2{J}(Stu`21aAolyaYWho)PGBy zRJd6AvSByGG==R-@{xC3Dy G3$t`)tzc^1-?ks&>huWbgw1DxVRR1f$I$C?l`lW zgyVM$J4%2%;fz3TBh3yevl+Octr46urQ_VN39cIo&?~t@!Z*<53IL=Fa7w{p6s^K+ zmHL3JLNiyCWIKOyzS#Uh6{7cI(e^wt!&91Lrt%mqNEEgn;u|vIE*2)zpv^B=36B0w zBFhuPECLUxxvKyb2dH3z93e>E6yXOvq*m7v!-$87rJ$59Te#%lijKA++$tA>5{v+R zP$Ni@7cqZw=x>ELS@igiC;# zdX=J-kJ*Vh;R6avhGtJO109Ga*~(@&R9}=E6h6pDz+OU#VR~1Q7roGFdPO+eMc6~D8nlpA1alu#6C*ST+tX%ruD#^qM@ zzzJMV_B7a6ltWmSXW};`4NZaoLeVLUS!Pp=xzz3AKLQy?A(Bo=VHFMIh%w3Ql2N2v z+|Wy1$1JKxh%usr)foQ(n94%M9}k$caJG25fe1haSX)Q;HI*?~uRq*OA_6<$nB14z z*RA&(ps`Lawh1)o9-^7tENrBN{Yx0wv{P;%f&yCq0I7Mn!+n3PL7?Lvv6U?F1&uUc zzo>?A7sWN4^>s0muuAmm0aB8NdF@KduqnQ8n|}VKI?ipX`>Xz5pbVRoIMdzP{^N5m zwlsqI_+7vh>)RHOFpp>c&Ut8sf-gkKYew$9A6M=#K&4Q#v*UpgEX}rI0dJqKpaQoL zcaEF4x@Dl21X(dd{{W7o9k}*#3a6k|dXMBUM9|(EzB_~aB9xkIRn2xhK?%U3h@f_b zsr4ZaS5g-7CfQxrjSM3LBPIMl5=-Tvo(Dq^# zt)2r8Kab%NDtii+g0tHkxTqBLTghU%p$3x?)0x$xOpwKLwDIP)xM0z36?!X|n`|Fj05wn>p;qsp z&c3FJfdID9v?#5)qnLi)x0%{~@crMCW~nFulmon+`Np=0+5rUsX?x3@M z!*xfIFJ#)vk(qIEN~Q)S(aPYfOQ9-LxR?%pqDwCe z>Z0UN6sAma?mnbp?1Xd+UZ?j$wpcwL2ss<#t7T}E^8vsY<`6|Ecao>45GfqN=TE6> z4nK)fm+BS!J)t^n02VKjIIsC)C4#iGe8u$$O0IA)P+n)!GM>l8bocI4+0u7F_W@Q4 zcN*Xm!^}l=jZFx_XL*9v%Z^(g#PZepGRFC_EL+57LjA<_NAQb)!`ec@eh`K)6%Td9 z6IBMWQg)_54~CA!3aMd{ogiJ4D6R#?R=^4fJxW&!i&ERx0Dul9eM^oeTtM=HWx;49 z7_cZZi-n(17=Q|hR1Ajo0;3)Jl}<+7mWp6PEs0q|x-ku&Pk~d!3Th#52mpZOXBn2n zzf;~z9wotS!TrLtB&Jivz0SxUOvc(6i6*HA#tWs1(jc88wdK?uK(T-PiW$D)HT8s7viD&jM+D()kzawhm& zpG?96)8cqbT0>Oo2e~U>Hl04mY7H8ChdMh?c; zaODq5)axOo^#mF>81@%fev&Th3r;Rvm3tK7EzD&b-3Az$c-BV9PZ30pP@hlcbvR&p z?jUejvCa4IxTzn{#Ms8(mhDhbU3cufj>ILfZvOz}WE&qVozL+t16uweZ2B$CrDB6( zHDH46a#BF#q5fj6gbL?>smg_cW|-bfO(^4K7TtK3!kFb62HR{sJ1PLH~zm27{U$ZOKMnqFp?mC9H{-xwuzjFiNWOB`F z77o?`u{X#Zzmtz}`U@^P5{@~_>#s1^6(B%4JA2KanvD*$3Sw)=<>~`sUjVyf_09e! zIb0C1nx2oh=@haPO`9U-o-y@NTR|$Zr4C&juRDt;B8@g(x~ikwf?f127lMlsKlKKT zM-40kmE9j}m&^cbzBj-9Z@Ey?%5;ih$83axMwG*Y&UUbPz+kYh_~-J6odV&Fs(9!A z&=FEB^tE@}U*S4XuzFe0`#@cUj{>3#Uy!au|M1rX~sr9V4Ztz>Cytv)3 zvT-{KKo0O;^H9PGD%rG&Tvtv10J&l-j2_P4LNT_e0u<0!N~`e0Q-ZoBt9a7>y+>MW zO2BT1bl>NRnqYVZc}uf<>dr{o;HNHmL;_meDK*ywoOW~t4iuQLe>eT}DrL52T+Q>I=sRkS4U+%_i z^20BI`g;x^xueAs_$zd5j(I&ojrMwV8K*eHd!~T@0K7_tQ9~8b^uO<#tzUquT~ItC zO5oKgDIee5H^IJ6j6!o89C|(f01RJ9rCJ#Xl=Ozti)9?X;1|o#!4VgOW5jb?Xr`Zt zs}$NCKneh5(&MmU{Xh~GmX`>d^PG?@YgC&SbhO-)vWJEX%HAVDL(*DSA-8T}c~NJC zSb*kKFX99Wsah;%ihmOB$4YT22_0#SFtBh!UyVBzsu$T&9aUnNRLiblS`}Q05HDo7 z?Lwx}29Y6Rg{LJBx>;FKYI-F!2Hn4zc$HR}L#r)=%28k!{6sBWDzu4PQOA-zO3r0m zBCA@KfL~G456&1!JBEKJJU@t;HlE>(9th$wf;k=A>RBqjP9t#xs|+Tlfm0^Idrzp1 zOMYfO9@t1)AwWG5K>+~}6dSb{R9k@q+Xiu&JB%aGVb0hD4%nGp!LkqBu;L0XF6yPS zi{>Tau%$rhI%s$xuM)~sDxzNT6ju(?AO}&UgG6coBNvI)DGMuf;$-gjDP-D4y8#Mm_3?}$E;ewxC0+U{y2b8y@*;b}_ z)<@6+r@qu2gTyPFutDAw;AMYs!x{^H?=WHOwDia1#t*5EH$uMFn@j>5gNVeQu=7j* z0I<>a35eEMNoV?EXHkp12TcOC)R^RdZgQ3+v*z|Ma0wh)x z^W&cpQg~JA#NdWXz#~F%{?{nBMP@7~9_1}k;<%+B%xfh;@Sy$Y68S5ts_pxhRFzP> z_3*GoYRv+;4_){8jEbPMfc-e6izf6MD=>WH^uUR* zjx!wf%AqL7CDG~pU+D>f0Y!1i{9xv3vAH}P0j%VIm;eb{I(-Gnyd1{oMfR9r;82P$8gZr zKm`Q`kQbC%&-@8;EIcT9R%&;}_?A00(M$=|b9<}KT3>+3#B~pEd4~3MFCc?4teeO_=iD>V5Wn9_y@_w}~Z)!Lx1<}CS{lJs~9D)ZI@5iWsbq&IfR20w(_P}nhBnH*Kd3%H^ z0YaJ|UPt?hmIm~rp1;+@%Ah43AISZ`rFAaFz1P@%%9PdxrOjHr6!48QgNX@A+H;nV zlCtBYTSJs;gJF#>DWU2-At+lLTVu!Cdm^f}25&0<@4u#E%LT!Wd-26t)JSV3uJae3 zJm(2F)kZt5c()ti{C5n9rG}m#PhYO0gi%E(@#Rad@9GVORV;VQ^Zu|U6}JxyT>iL} z@e~+8Ck+1pd4qVS(`dy`Oa6Z0VzO1O@*CVZ3gIO$y?g%v>>}2tvV`{Ov4ngqPlf?2 z6t%ru^u)A7OXc+|OjGPj0S&`Qk9IFUqY?O8iG+huBCI?UhK3DG)Ce`j#^?rKovRjATJ+yJn_>CnZj=q_rLlc7tpT2m45WieQ_8X%m zLfhgF6#gO>kjfJqQi9eTb2MudbF)!kJTt)*A}?5xD2DlB8N?1&*!azP_!Z?uuBEOk zsH^S?%us;ZlsS#rtqQUuL2B$BX1vZ^g;xWqml@iYTC!23L(E*28y&FXD)%CQ5CL-X zyP3*XJqdU>hrwYo%WWAvRWMM29I`zyYf(J0+})=Vt%RG!4A>=Fb0>5i9v}yoJGfYs z5~DbFyDE#MUSbBd^B9^tY#!waNlMX;L7qeP2nV&w)LTIcg-;|02wt^P{eC62);M7> zAmWt96J$Dn2*|j$^f5(;Z$$8TgGo~ZRyP#ZcbNmN%f(8ppAeMjVO0QqmvCCxaRhlr zmyOd;vK`yfD_>_(bF;{$fmd44gMxxKGQsdF;p#gU?;<>E?c1lg!ii1e7p^sBexQno z0=i)9V(P?=yIO5k^El25_kaC@!^f*}j#N`XdNqso{##KeC4syTl8im5nEWQ5# zxF{+Z`?!E;u0M$Q1kks+#4s+pkEWGX-xd8u0nk5nA3+{Fbx|oPXAEC|?{O7i(x`JE z`-_^8iQ|*M1Q0;5G!~d|T0vZiv-U6bT)>m&P}}YIp63XSnegM_Asf&GhtNL5@F1)FaP;e{;*AVIyWYxGp4nvJ)AWjSciQSm~bfnUY9n~2yl z4HAbr&Pq!FqXNM}*XtGBR1}0Z*A1ujY-QD=_AIVl=lIJxRKu&^pFdH{`W_rw;%f8v z=V~!|T`*~OCwxBY7sg60S~=DEjYKS=G@)KsUp@{YHkOLrWrlR0!VY}JI$y6$VJ*Im zt||KNA(jXavWn%u{{TK=cTcd|E7bJXAJSA;lmaO6fO>u(OjJ8|79m5w^=Z^>4;^A&dk+w86v!)PwEAnGRl-KhUnsb@(hjwBUTng zXcV(@ToSw-C32}&Ed0kT4QGf9hrUUc1^e{@SeM!Y#}1US5qjD=Bi7QW^N7q_{gJNt4xv9S!`to^Q{}FurZx0Z z2(@Wf_YmQmC^Fr&uD$q`w`{AcAycmJ_ZJ(`*iz6LWh|d!{jv21!iI+5;%F1aaSl1P z9k@GeqwY3T99mENfghMsMt~gw;r2u*0|&RG-!XjKcC`IR2m?ICqk;}_%b!!MWNCPf zaV!$nst2@t*$_d9AafDsUEETQi0&%N+Zc8o<~&E%Her3HUgaq*q`-9*$`WKsxV40^ z2)p3`1ZXlnh;a)Ruv#UC6L702xs-Pgai%5GqM;#hOExXl%!X4hf*%3%WMs+~$wAzr z#(sV@HWCLfV(l!5aW8N@<-!dSrpK!t6OoJ!Rc5fwwsTU(+=&XHTEBDc!9~AsQRy{^ z^ElY2x9VM6Y72r&Ii^b}n?^10DCP?ZiG!3igOx3y3xHSDs4(F&B{X$A;dP= zcy29BY*267%8OeNgSWW>1^^d?HScfKD;j{UtT2}#HdnH4wqIl)iAWZ{{7eLv8dSn> z{^$vnw+P^0V6SnkT(qkEL2NoZePj!mRoMPx&!d*$y==LZ20_c(ZTWhrRgow3E0>CuC$KvUrV0Jj4r^0R*vNmFZS zZ)~iO+BxIyQQfDpZT<5Rx{L|r<+dthSRN9MS2T5U?KZdKHece#67f>+D~tZRhfY_R z_KaC~$XK;5{XnRM7)M}We?+4_H|+Q>0lx~lJ@Snz6IY?Y(uW%_BL z+AELez2-BgYz4gHkEU@%nuZB$p0D*X0*K`d(`* zGOfrLdTTcD{s}p*53UK1cAw4wFFB|z!Rn4rZ@4y4Ep%4`iNpLqnAo?YQpIZTs@EG* ziwX_1o%f zxs%|vpP#SHIzo_zis-&Nzs#g!5lH7Z5Ns4#XuQww3auF3xl3BTsUGcs3T?Q!In(fp zs_ZB$D#q^*>GL;0(py*WZw&DT#uj!t$~eA0qan}q11o!OQn?Cysd0mnDHx#PN)(+s;g0M0B%GVCuRJgTY8tWMOD|c>W@#>WW+R z7yQ)G^qj@*XJowMn4mVU{{X~&c8aZ^>tU2r;iCqD1*mE9OlwaIYxVfAF|&rn8juQn zlHmZctvx_hTwY0HbYLVb@de~`W0j@r6=se@j0p)IJD$Ly!x?%KxP5t9gArIz{WFc0 z8#hANnw6ON6N+-opeGsrq--t z*$^EQZ^5EW)|jQyeDuW#Nde0CuxWC2!eRL$8_3qDVXZ^h>BWP%5apt zVD7-Ias9$315?ag=;UgY)Va8QCvq{ZQ+fWU+XDDt4T5lNc0BYuEc0R183DRn!oaY* zRWkBgOXeV!yK5kD46^2lZV=Ki<~AZ%sCAWBHZO@mzM{dcYCb?^a+-pvbBJpAg4NCv%_VkR{H2C@C4sqh z31e3gTL|Ish=SraHYKt(r-{Sh*pbaK#hxxE97_Z@Y_20~h!nJx!UbS3EcQgY?Z`a< zPC(7Zq-27nxpJ^RHL)bHHJ!@9cGnTr#M+wO6%_i|kzPMj0`r=s(qrUfYLvZ(efp_J z)3_LSlHU--0_{9P?}4uof|piQV9{?E7ta2pk;#@ZBD2cyOIuU7an)3+w<04yQE`I4 zl!P1>)MB*Bx?M#ZG7r?=+kPQ9Z35TaB}P~Y0T^}OLfJ(*N_61MekGy+G}#rBRKnl5 z6qF-50w9r6ZxPzDo&j8YffB~7)|@~01So+oH~t{ff`Dp|U({qUst-P&%NgBXVvkN& zil`w=vRBl6mY!UCg?1P#@Uos=>FWE34G_;J{{ZSf6+$#Set+K(9TgzAkJn6fw<~rD zJNN2dF;RaC{{WaoQiVR+Kg?2r%WKgs_ytS5_zvRUGZ34VKsjaIi>a0Zd1VcKe?j<+ zUWR~cjW6_mB^M#S+szy!SNe=47OYySwf9fvAUG;j#Wr0&V9E_p%p0us9;Ila@@@DM z`7C;zh5#H6KczqeU>rv^b<18ILcjph#o2E=M~rGz^Y8<)oT7Ag#vq1;jab#+C0ETn zzy$*LPC0*##!vz-kYFoU-zNzy!iXX_)4yj^I4Q+O@j?9>@hE9*wuC*IU&aU+8JmOa zyZ&ZD)o?6Rr#%hS3WBsiq4;(D<;~f%bfBNLFBXDN3$0VeNZrnb3v1qVMvyOJ{8Cu) z{bfQ}Xc(~d+cw1K1`Y%H97S6Nk4L9ERdvLHx_CN#`3$~Wt?Lw=_`hggt@;U>1m(L?kkib9!95m4LM*S(&907rP7sya! z-Tou~pj2-bbQ||yQr6hqG09i8>+YgqFySlw)qbd82PLgXM=#A4>_{4FBThWso?QEu z0E<&yVOr&L=NM?gWX7k6m zG}I9~KfJ%xcP84DSkj3Gj)JReKH%*Ls27+w?T(j%0Z;pkQAmWpOV=<2jDC$L_4}9T z;IkYHD_bU?AKx6ns5=~t9c00BnkwS6>H-oRR@4a5fq0l(YnC-b>$yhD^g)bP4&f9m z7a8PyTw;NXb8m%oIKkAmf^!XSC@=bkK)p2aSka)0Leh+DKaTGClVmG0=J0x2p(ihN-cee0YOnN`iU~G1Hth} zZ~<2n$8y`|QmzPUQlcWqC7r`|Kp3luYqklO3G}uvgt}2Ahad+L1QMM#cj_cGb!=F+2xPSucGtfpP$2=VYAh^4@|6jv`08_)>P zPxy!cx(7h(ocR1kk~w;sQAh{y#D2*JkNzR}V<1uGXZrkpVsn6BD_XbLE_%68P^_ifr-D^)tU~U$TSwGaXRANNT2KYk}VmpsbX+EDp~#sdBuO*QFl$=?L;f zChe^6v-cHU*m6UurihlkEkCRM&r4f4AO_b;E*7H#r3;_bs;Ux}^lirmqO}Ag6(? zZB^rZen@;!z|+g{^}N~LOP6peorUYQE7=>1Vht^}*K~de!mwiUF3!-c{CbsGNCnqt zUW@u-Fd>Lh9rwOnp2*-{lN7H@!M)u+q3x+DHCAi7A6`5}rQo{C}efl9H9RpXUHiuJ%_)9MCfmtb5Ll<#(_gf%BV5vpqE zucj36smT4yVyvkO0mHMFSSBFqL--OU*RdmyE=Ldq5;!HW-Z(E-}v z(aEA+NZm_7fGyZlVO>BCGH6V!h#>j40JDzJF{RownCPAeLaNx))EMGrEnZktk~qR% z*BXLYnN*|TTpDf4KG3}p0bIqI3mi);mMDNXxV!ZWNqihm9BiP@AeIpXIigcmmpox0 zpnwgObIfQU62@(mv3GGCM2dNpYlftD7$6sBg+!m3P3))`%Aw_&E(ub|6c*ZE1t}(> zJK`aE66t`Yj{g8Mipb8K=4VhizV zzyvPOV88s=zx!k^qzD2h?Hzx;w7E3H2fftD5S^Y|wd z%_+@{-(qe>#WR+H%H0|J+$ z`|Z!>T|@|rg|Rm|S2^_s^tNatNV?8J1F|5n1}CqgF;zLcyB^hj5};5fhXnv@ zUaFtud-{rKfcOk=JpLYHwQ}qWQdzxUacaYQyaRjhpSWEPwCP80*XA=hU<)Go_kmp5 zl7c)=Mg*tk0}i5A$2k4}05awRf9xWk*iqaiUk~)Ckh4K+1^}gBU@C6yt*ie4SS7P8 z3#Z}NQpT6n9V=_QKbwuT3!u6ut^TGnCZ3sQUiO*AkR+4%y@Sp5*VLx%Rl`nhsQO<3 z#(5UC(a&CM^G|V&&?y9^X*^y2$foQ!UoM{M;kZtz%9E4Xrnorjr6nrLE1g$1apyaL zRd-H=I=th5UsCByvqgCOt}D-V#H4@{4=23equd5CaVZc!yo2hPCG}7jt>3y6r1vf( zhZ6D*e;N}m>r{u-4#Mvy~hDY3>#K~ zc^HTV=b~E>WzhJftdT4YEVtnmWF*>h-hUFH4n;l1prF8S;f(^3y;8zLl<%Vgpz})^ z#=WCbB3qmY1RMtuOQk)CkcdL^SD2JzK!2t!z^aP>05I;bT}u4UK3y{7Ef}ejC>M2F z6DUBo=~3KVPw~sxZji6kA#5zDPjIES+UWdC-cJpTW)I60kk$GVERDTu0@+3&^oxiO zET`-+^YyRs2BaK3vw8;s8ClroH5sO_5O*ZsP$O|RbME0N9x37q@ZLu}o+A>rwwji) zLfk|zB}HvWlSC`1E)$02ZURzxmM-A6khxV0HN?l-yrA`LMKP)A!74OFqXV!M@s zEkHOi7X_=Cb4-9?y?&vZKPW@Y){^6373K??6mt;R!l;EYltrwoROp?MV3%;$5J?+z zsayzHqnHMLPAC@=p;B@{rKnVrr#U$nvdU06ZTZMQnc*-@z=|vR(5u)* z5>rzAsBWI2aTc9`mU|5}yXgdz>nSSNa-+r*7bo!x!*w>l5KTUos8h6G%zYX?VNv;@ z595DO0^+pFD*OIpg+TOWm;K7zjqFSG{{X+#W*~w80CJqqB%&4AAJGsy+O_CE`zisP z7QOKdt+fXj9LhXI8mukr>RgkGYemx4b093Mc*axue#rHa0(w92KT~k60mJj~wE|sd zz}U1=4Sm3*Wrc?yc}H{>1ku0ZIIK!}UVG~Q0Qm)c68sK(_x#Eomw+?L>z~srcv>5= zYtPz#AS(|CDTOWZ128We4c+{Bbpxp^J1M6;SaVl!x~cl;uN-~x4J}E{UH-4v61bXe zOUsWuT|99pQR0Xy+T`w^S(f&&{5(5n5!2%+SG zyga%5!%Yokq3Nn9_J-Xd=D;qFt!Mqi54=opMgDOtS~s(id_R8rnn223E3eVVsN}7T z^nZvdHL}8;p=sYys#6Kp!F86F+Gr~UIT5e1F5RS$-b;w4-N1DDSa zhxma|QpU*h?6a?DxYoudO0~p2YhPqdFUGd26z@v3uCK&-4O^NkKHu4}G{n6xc^&*U z-95@#SUj$|KYe==0_};$+;#|t-2=C4hBBao#;!a)-aolmV+kiZ zJ}K$__#YNaRqNk9$^tk>Cx5tYU^f)-+CU?KM+)ys6>*UeBc5Cqgi2eeuzuxBU2@ufgQ|gi`->6)l8ZhcftBQJxpEleJ z@q#zL$ThLD%KX3@4z6$0H>P|pE|!reA9I`xS;=TTBG(3ZAZ{f=;6~w9QLm^)ARVHV z+rWk404l-jYt1XnY64nDi z)Pvr#svMU*1;i>RYM}W~7;%n3c#a~1SQHZ?f|cSuc2S_#Xf)WuJRaDkI!4$nFngEB z-jGhMV(9?@Y7rI{mlc4uf^jGjU71b8NF#Lh8>`ahUl{JlO4P%3@=8#p1n!E9*+ElBc;$37f@SD1$? zZ#TrIi{P%07v9F94i#+O)A9UEbJ>n>4|-eps5fjEOg6jsz4HXnCm}m+{Rh=Wg2n0O zd^oK>;fhsF3s6G5^}v@999Na-CSv}kV^gp#cV`{`kgZsgWgeO6N4kp_OMGqRDwXx7 z4bh@dvg{jczuDAq7a%Qd5O>c9c1$}e)t%cvk^cY@fbyXuia6YVQvtVgS6tQkD`V6q zq!g>Nfpd8C?`4lfw6J{NdzY>*4AXLW38NcaAP2 zeK~qCANRzzFM!*3{c4|3NEDkdNEO6p#|4Hqs@z53$pi{{XU7 z?PkRbpc{0~;I#{QOHcjtE`cVTpO~tcsY|}x{%g|%CUixO_r*7#Vde^ja#u~``>)ZD zy6`CZQeO@~NnOH#xlU2%GwGwsK~!NDTEx1|LHsZrz^hd3qs7_#4>1c{Lki=9v$uFh z%m#FpYMfA2C0F5_?5LXH`s$qW9!N1+(#9C@asL3UTRYZI4l}ybu=6{GS6XG1>WBgM=~Lao(|N5AJH z=McU?QjVOvJ;9vt-j?a}%(LkhyaR>!mFZ&zUfbaD_b(^l_U9<`a`arP%#OoN%Q#FS$`=KamB4o+Fws$0Rb~Sgz~51 zit}_VeO%v2FysE^*zudQ&lwL%=`4Obm0_%3=8wh}gHOy6Kqwa9NO@IJID{;-1?eRU zi-@;zi@Rm6f;(;yyOWQoMAo1PFybrfbCQR)A$c8UvaqjsnNq`GRB!47xDH_mKvE}| zASGZZixk~#*jVo+h%a*KsZq=dh-0w`mG=a#z`1s)o3)6liKf8p#5{8tdB}lM!pZ!}#HES54|R;WR@Ap5 zw@@hB@=B0<48}MZDOn!Cs;K=Es^DRtxaC#xa`C|OMvj4~uSp3^Q9gsi3=TX34-|Oq zgdi=-Yz0hktbXi$T&x{!41%M>sy8}p=3E90g5wmR1t_MDd&%pvB{Aij(gY)x!TE%l zp-jlpNv64*)U>k6lSu2RH8J&)yxQ^9drNGl&sh|^3;zIgZcep!%gdGA;P~s@GI!>n*yhj=&hZX5vNrhV^ZZVBw}F>x zukI8CqiSU2%f&RTfp z&(EoB>cWlc{BC3UocJo76d$AyJ5aqSb-xEU)gio5i!WM#0`iW(RZHC>vyZ?L#2qz@ zuYMEp3@|DJHtMe)e@Wt}lr@!H9;>UCvwLv6Z20s1+@bHrN8`(|k1kXr}41YkE1$TH+4`tvV=CTkDN(_bzP}g@bS0BRbeapbX)(RUFnU z>I(>Kw{)tXuCLs5M7dRfa23n%rlKGUvH(>3^8VsT@j>)8_GG9iYy`!G^6)>1*}+&) zrJi|$VL1!VHZI>O;K2|LZ7auEFr`>q5NAe)vDbNRQ`x+ zFIDhuo%(|U$-E^DeKQgRK?^C3-?$~tKsq=70FuFCU2dzyJgE}&K9n?t2jz8esxcl% z0m0JWWOVnfY1fZR6YttlngALy^ah_h;7c->i+$Mg8v7qa2f82~Sw(uw`%G0H3RJm0 zxyO;13(S_B)paRXnTbGaB%k!j+3n(pI*-T;P(Q@54erxu7jP*+9qY=F3zfz?e zR;c;Ly#D~K5k=|a&R)6vLd~2GO6vSV1xyL5H=hw0mZ59(^dz?!6f7RqtZQ}mTLd(0 z2q^kST)`mA7t}LgC+ZBcNEPSz;w8u52H8&zSC9GyXqwT)z(H7Z6tT*i3>L^pRh|fZ z617~9%&daBTPgrD5Q-(d*q?Ay7VKpD=rsq`etRk)Ru`)MO5g@7hup5EUrAsnt1Zdi z!(aI#L~362mDMhJ&JGCHfV5kh#3jN zEe}n)U`8VN;#r7m5y#x=5EZxg5tk6P{{RuTs?zZw2H?^q_P`q`R<_><+@XCb(8{U2 zr~c(+kyt-WR}$!N;%Bj;r~NZ!f}#?j4e0$trOTq}_?#TdYn*Zql)>r}15-sHHy;vn z7En;lNw(HnW+x?xqs%B>XBBN1Kq3t!qVSLUEvT~}S zjv)*X&mgagg~(LMs9aQJ@<3Q3)~sWgEWu$Xxq{GO-J)*gc4Dp#HrPC(i`+IwQPi$n zclAR)9wh*7qHJn1s%b2@b2hP8V&G&dZYl^M>11T)#!%bZwMQJ56dXDkE7JV~~%m|~;hDW0&40`!5kTg1KPl(M=hxoZ6ae0b@lWm^XpRnjNBd>?nOk75 zFL@XNs*_*{(c~ziex}&6eI1?=57ZP45PG`q2sjf#Et_)(4gUbhZpWH9s^{{bnB8sI zwAYX8_REVNuV+8+yNEFt3&HU7@V76H;YYxyh+%as%n)B&s`9ei-fC;W(m6lRGK@n- zw!y>x_=yz~*5Lyp`zTHyE19%Y_`Y+pBA_~IS3j;Gh)k*hDMSi9a0 z9rG$2xF(<=RemB!>LZOEtC{3fXyU?%Nw9;A20kevH z?$?~|Q-GNM^Sn4Fu5^nTNuc@eOl8~qaifmcP9b#6Z}21fz(8P8Y&gwP6I4&R55 zaOh~@=ZyXnbC83Uv@{dhRCQtq;_E80FRGz5f7%E=-jR2ekFi)9O7A zZE3;2Q<{GdQQM(H={*mQ;2R{D*za*eo z4N{x>tQqWmMO?swtV2)L`WaLJ3!jmD{z$l|nU!1YS6(xz=T;oHrE^!O--xV)K@=Pa zUL5}bywqtz~K>iiev+sZ&#~=QM156QGha1#*;*urpne+&N0&Mq7wtmLaiVb zV)4>C&f`gFFV@nnk>j`!+S(jObFHa)rav--YB=Bpc!}g#PDX0iu{j{?r-X-QoFd9e zeIX*8eb|r&hs^M*L4x;+1Y@KM9xHuEAk^P%u92lPaj;J3Hy!8(Y*XAuD6xJfl>i(i z?;*f?m+u>-)Wtj;$7@8(m)M$mSTP7)ErZUBJ(`HBRXuZ0P<((}?=lPAjtI6TPQAy1 z1yk)#M_d@>Cr$usID&WdoY0>(?jl0Q4I9J^ui{$Tt4~ zFK-YprmicQ5SYoa9ZQD@YB~2Qp{{Zg1ujkZVakk;_KdJWtmk)M7*r%c{qS4lxyg` zdvC;3;HVfaD){D}iiaqf)&+QTihBD%t3>rzSINa?_MH{tzpAZ4&IPe9fT>Qm(Pdu z22qqQgUROjUvt1xZUqj#FXmZMVv~tP56q=J)1z?Z;PRo~M6#oPvsrrF1OOM*mh zr&Qcwf!80UKgaG=jf-g7s(&>o!N@O9B0vQ5IJ)2W?gNC1*;n5+&VI;PD*Tv~z7qN4 zk(>yDaH!_Z-f8qEPA!EM`wjgkiBpe|K-VjeD*d1wb(o&YZBcI`KDhEeU=0jQ zV^-A{B|Lqep&CPHZD{auXVN`Owqe;8hUxmhbuRgeZiW2N*U+5DK&HdAZLS_0&%aZm zzgu354Ce3V-bfipp_q{vj%P z3&_gQ9N+eot}#E!9NHN6L_{!Jj&}mLe{z-{*)7ab>Ga0f@=$I9h#c}VlnLj5QpiH$ z6kNKPd4t?aid4{WL9r2H{P~9)tuUnJzgYSAG()Xw`+_n$H2x!`cn|7XAUZums0Pzd zV;WsLh`Gz7r9z=3YG2?>T$?uu*vtN` zSY<{?parZ|P}VwPV6P#GNO+~qKvh{5YrEOr^Tf4i1H`=t4a=b=@Qs-J7o}V|RkWQY z#emX=Msz)szlc-3fsL}(+hnpChXLvhTFUY|xVYR=+Uk{_Tm-Yp^`zlgrLZ<>)*t245mrAGN0ssq&-yfJY zEv(O8C9D<+(^QLI_5H+Es2g%T?Q&cifdbw@3a+bdi91Rc18Q;iU$`+8*A+Ft6|eF^ zWji&7^J_Cd5XLU>+P+Uq`iY`OUAT!Mjv!CaCLz$C`pU0_`Y% z9q-6Rn{nhDb=MxcjbPADS;%d8EG-q#3BWnED)W;PU zPJnJz(lN@T_{aqaI@=pfyy!ZC0aBu_6?pca%sJq7I8gV~?rPMsG1|5G$GD8$!lIIf zQ}_CY><)Wi(7ujb;gU(qET--%t)wuyV4$XYn2ChRSWS`2PTEAPO{J zN(27@W9SG7o5ip5D1~meTYB^Ojre0~t@-Kx$-;*~b9q-faNRq8U_qpdQ~nR1%mv$8 z2ie2h&!mlIij>_Ke~tis`GwRj*egKSqVRHHfl&)07;a zUYh!{7aDEWkKaJIUJnu4rSpCZQ96{`-v^R2+_QJ!D$lwN?)&#<%v%o2L$IqZ0W40KeP29)bS=L>A9|xBwbqVs!$| z3EOrxTvhSv26felKKbVQL3MbA6PE(vB4!8AB%`8vW+MkM;4aYd5g3cAyZpmE3_VI( z8=JdRTty^8GM@1aJk1`I@L4x~rbi>omvJ zI1_TdaJSM^>8qgoBdxo%S1=rT(IBV@U8-Ni9uPFWeKN?~Jb{M2WtLIm0(2H9ONGCE zwR;_loV0%(L_F@_A{cPem1NTu?5*#JiV-w-@hngZw^k2D9SLXL9ikSe@_`jPUoWJD zYek5W{6MfhXAk)$TK*y|2-dZJC5&g7P?Vzbp=ezF~u;RdbMjkY7`j$~?*9ZgW@xXZHr2 zKnn0G{VCVI($N%p9tlLBOF}UDr)l;zcio3e}#T3iT--QpIdsyQ}=U;g&nVEJI8CiV!n!(yO!W zY#GQe1=P2y{{RH*EpAamsP7~DiPGBG8>x?qPHk5aQ`q!=L7NnF`xFRdg3} zvDrf0f|K&NxeuUL3$?kNAE;D?05)(}9^WxWt13f@FXbuxB7uuiyRvG3h4(0MAO<-f ze2Ky+m@6Pe-kzfy=U23#r+Q~|TqaW*YQE3ZeWx`T4P6hn_mIZAC^Z9bzXT;fve>L4 z-`Zp)7dgmQ-mYaqFLn!cG4PQK+Ilv{wDvTMtzBup5l`1Y#A&=Pwb2`z8Y@!PuRH{x zR@Ygld+sBG716_9ewZ321!dJ^?&5K~5yUC0`M*7N{*udkOGlC?zkZXlF5qKGYHi`6 zZ{c{2!7}*aw(@Om=@pX}gM5HnWLvI1G1iceL_UGyE@t?|+$8N2nVMsvva1 z{B1`m`?L4_L1Hm2gjYmD!-oZpZ3$LQocjrMI`b$C#BckQXmbZHRWar!KXBqs>Bz*g zjyTB0&lr>i(6{2CUj@94s3x_Q9JjDyzy_|e%_GXeRh#xP3n9SjKxKE-Z~)Gd1*5B~ zh`N0j76@^$WI?1$>b8bu~mBUc{fdOB`cRSH#4 zyq`fB@lwLBVma<}DkEWsIEt0bM`5{Kn;NJPCagLk9pWlc@YS@JfE5y(V#j9@*fQ+E znGiPaaeu~E5Rcr(jv=zIVx5ba4>QtPPv&(?T}v0#X~6+aY!Og%42wx#BBc@Zi)0uo zB?^$Yd_*+(gh`^MX=Y=)d?4ICd|3oh>MWy}xxB*s1YzVtDFIz_AVIK2xfW~%&LJNN zD_|11nZT4_CrnX{AmKqqyO;dB5G7s94u~}DqcqYl(|e|E5Ijn&$Q8`ym^!&2{UMG4 zt|Tx8M08+g(P`836$)Yuw20E~p{l!*vRIx=n1BtkUQ``Ne~5BQDMBFaT2#AOuF(Yw zy)srMolx5;PV&YSG$xAk8Y!afC?XMdRWj+a%0Z`*ARAUp9ZD1YYq`B+j8R7(x`9Ab)DTJ>2bR3VVHMaL#H#2EDx{Imw3szmYT39&I8M&lZ9hF`4`i&H-6`tGb78JH1sW?|`xYf@7PYedoL!mHGQ{+daKm4~uVhRHjW=rO2Dr~6KnYTi(ce$t z`=~KAs;fA7;?Taw)HRb7Y7Pm`{{Zp?nQ&MooGWVn{^myuvV5Bg;88#BaogWAL?lg2MQ!8AD=g;_pV!*b%Jb&!is#BnS@qf91IbyGRI_dua zNNtDOKWF=pIGZZml(H0$3@%s;N-F4S-uRa`LzY5*v9_WWHHHd{N=}fZFOHg$>VX)P z%fmh_#Y5vrJ2(!?lv(9s3!P1Qz06H?xY>*Bj8AZ!LR_KA;%vU|#7gDW*u#wzji@Op z=Am4%_A($Vm_eOh(m@!sZ0RSOVrhP$Yc$i6_+=m8)L~Sey+8|3G_vBtRROR2jZRVy z&+!aH-Bpj-IX?NnlZe@C!+guRvg@Q@py0b+rrtpj-?#=!X=#8_F?U~ZS?GXA?jy7s zY`>->J2dky~Xm)sRAh@VMn@Ixw!>dHLAhQJ3gK6nRE55yp4`{00i zjo3id!;=<{7{FCRpw=YXi$z8m4D}2Kqk5(Z3x&bUmMDu55iAOXWN(rdx>N;ZY_1|) zyDS6?F>Z#&HuEkynP({+1A*c;hF$}i$Qxw~zGG6CElG|;qZZ$UHH8u8I!p3-P0r#D zEMTWojKHc3KA3A~GUB4T5Meo-%uC^N=}nTd1y^vvsicR&8mm)c0<>_z>|C!g7XU8U z#PhRgwp|H%ssqUu@LoR=-lLRHD!Fm83acG?gibVZWg~`cLE`o9{YD@ZTfDXyTB>~k zP`J3-UG@GYjT9ok<|TmJZhb^?R*Q500EmceRh_{^3CTHSQ39ojMXv2Ks_*mukWaSi3-He3qVSnt_{(X|Uh&2M0EnR!4|mBxH<7^`t=n_tZPfHuYoGffF9*Ws;QgP z{Uy}Y3~t??fAj7dkQ4&a%})18<{{kxMv9{Sy>IReBmf1McqY|o^>V4MJBliAmA8Fw z64+Ukc7Z5A^vXq~vS~t_cgZTCFqOzu{GC8#Xeu6@yRE>qX=*h^Px}0=nfq zO1-!M=831l;a(*w)1bXoR{dF{=;Sx!&nEhalG(zyt z@%w@;kQ$TzpY%qM6fDC30O@P@6G8~sIOF_N^2bFb&Tzx(eAz9+>8=~^IwY*Po7PO;5On)u9@}ZEFS_apD*!++aDh|N%?qa#q z2Oex;r@zPKU?fI^ZfPrdv-W$Hit^WP^LTYWm`!k$*nOPwZT&LB(xFCickeIpJLbbk ztLTrOKEhE|ED?FCF3WiEmD~pl$_`h@-k(VTU{G=?bw~L>BOC=JI4CQRvaj7KwFlBd z7PM_Q@bX-2h-fT62lhW?Fn~cDOmAaCR(M!=yFE1fH=i5HF5s_Qeok-?9V0Zj)wua? z`}1C5z%3k8v@8A67`L$!i(Ft(*B4FQ}9NeFCe^j*L zBXgz?0Ae>Uhop(QNA)ryz!6gU=2$gwKsWh7ZB6AwwrH~4hm1KPYVaCyCCFD`#_7Sd zTNlunzNbHQ(N_@sV5SaZ*q7e{%IYNFD&76VPaG}CQh|+AKNa7EIaxqz$e*vJxs3!0 zM{nG3VM@>06uuM#`KSpUDE^p7RtvE_`kWkAm5dY_%7RMXI?r8^{{TD#r=kenRh#uV zg4n3F3C5{+ZlDUdur4Z#xC37>+b>MsyL1bvMbcCLE?? z%PYpi9^$8oV5QDfMyQAl#WGm)%%GwOujV9uA+&>!hY8eEhT1dJMxcc|0qnncVm8topHt9EWAi(7<}VI_ zgTwA;n@b_@(;pB%7p>-FLC4}M>84~>F^~kH<2kM1<`@?BTP8~%6NU&FVjx*wRAk5` zEDm6>cKooc*r5uR3dFLfg9jLKfZaSM+@)7AaxZT%8T1i^3PZq&Lr+g}4r+8c^C<$s z(o7!4uPFMj)0Z<#0tu%nMmw*$W($k4FQqN@?k1GGRlQ2>r`!Ng7;L&NT-AX2)DYWB8}d^} zfBMBrBZoKt0N?5j5}daU&++?@E14AV->SdrECour8*TnLHXy4YY&apuUeIw)2kB-& z6X;7;ozgXY0d}I~bYhJ~*@7teWj!uOL2oe#D3d zyMm`T&*$m~Yp&hf$A>?s)L6|-M{2ml{{X3d@a>2l6UP4lOjIJC6%@AkDEjijNTk7H zR%S2j^Ac4SxkNbdbsS~93_xG^cY~TZfk3a8l#5E8K-fHmw0D6GYT58=vf`tmi zoTu`NyIa3r;UJGD#1?>>1RfsG5s3rD#ER+sa%x)$H`~N%fcJrJVw-q^pyG0bhBK<_ z6;Ny{zj52GFH&(d_+VJR!f2;oaVk-NxqHvqvl_(xM*=n9ftpAfMOk*aR(D>=>2smN_=atzfy#eYEWTn;j4z#%whS4MT)2SM0us_ zVc-K^54hwT9`UlJ(ovNK%Rj_Kz-t3urKy#*!}S6OaP#*Y#XD^A7`w1AOHzv*A{Gt# zmt$;N7Tf|0Z*hva6QPI353vTdEOLj_oCxERyE2s#EnH!Ov*HE9&{@mO8aqUICeXcg z1`eWtf*DgT!A;>dJrL5SAl6v(l8YsllT9%c=OP8F*kGeyPzDynDmHmBA$J&aa*za6 zaN#K3+&6gu19OE?pX`GDL<)ma^WVUEA}^cD;&k3WN*(f zV1W*M&e#L5F}^ktVr@ZKH8Yu?SZqpk#(_wyIhNwAWsYwG}gVMf$T(PnzaB10M;VT9;TVc>P9V`q`o>JS1S${S`i0u%@c#8T|YY%59b z6VBn(r-;#ksNnm60gg%}KbsvB{{{Ua9hLBTTF!Y|wufO}3W{m>xBY>EgxEwO;;k-UVQ%mK?VUx z7SwH**#4+BnNVH#~M?$IetDGMmQxs~}C_j7GD8^f+4Qjj3Kx;ZQP zFq^?rxcE;OHN+I`z5We(DSHhppOnZ>zKW!lmg5EJqP!N>Vd8yZ+?I! z2!cJ^uh7-hq5-0m-Ke8FYzv~cilsgJ8TC8+M6SgY{r>@w zc>LFs>K&oMMX#jsf34WCQB5U&sP?Qty68! z8(6Ol%6DD{S88yX^-ogtX~K)Zc>I28j0K8Eb$V&nhup@+~cq}b7W96=G z-(bKqqEN4=`ubrMAz6uQedXumU`E-%ZQSv1^YS7N=3mq&m*Po&-H@pPN{U? zA)lDVdL9LyEXQy6Dtwdzrq?gu^X_BQFDhMqy5AA;yX{>-+oDjhJA%zb8r#KiJ@wqR z4NbD@25$CxghQARM7y)Z0x3eNIg8}+H^jA)i+wSQs2Bo`u=@EI#AK>_U=K%8OGB{Y zAPc8U5G}nhA#S|FTv)f%Td-+ylW@=TFI618uwDLo5-E{pZqc9Ps{?ISVqKra~SyXDj=P7 zM5gT6*hnvcSd!M%(P_8`X*qa4pbM^}u_C~B9HtouEY>82!g{?*aWP^ZVT*Ciz{M$7 z5krwJA}neGVL3U98*3fq(4VIe^gN&a#*Ec0ep z=HPaNisa&Bf(Ls=j$Yq8ELfZePF+9WF$WaX~G& zs`=&>K*V1Ae08vP*U+vG)BRVtoq>0dy1M77%1D(~8ejd*O0j>WUj`gbum1qQ)BzaS zJgxQmg|1r_oAvvggIqj&{{ViYJ1m9%jk5m$FwmfbL(-f55ug=dFWLDtB9o=`=IPJV zE^NCI?fo$@rBqqn4;P%JWNu;hYm2#3YKzFbwf+y{8%g73DsfxSKPQeDX-cm`tqa@( z>futYM-6!__2|ZyT@#xd`?CJ8%w!g%worr0^0K={itLKlZ}=s$E)crbKZJ)B4TRP& z)xiRq1?qwKyq;yG7Jv;XW}X$w7AUf!SUKy%+$c5yt=md_(Xa$sbEPoidS94DhV*g6T@eEKD%UEwj~?`6qje-7#XXSFpSJpFBdw*(qL zT%IDlRJ!l|*qUd`j8FFA8#x@AxPF;Tv$C%5HChi|765}RDY`luKAxI~*5D|lS)W|j zV)F&?TB)ka+QWXIP{4)vyj*i{dm$0G8UX;cog! z%I2Wf)B^P%luEn%uW?Jb zPQlt4=TDUCH+=&pR?{lAm-XUEw4qzx8H!kzX#!>av6qeK6w&>TH%RY=<>oA3(U325il}&ps)7e`mMtQe#M33+M1{)-RRL^Q)s%ww& z1*u2345uDTaK%Lw)9yBqk58!lJj0vn1%%ud*{?SI4-Z5FTZr##Ki?2Ap)hfI#~i)D z5_iLD(=sm6R|>{mN}!*e|PJ=_*vF!lB@Dv1J1qr%EpR z;@_KvKowBctKPXDJVu?opuheIw-ARND0Q2({6S&b2Cm%S>|;W$1cg}sL%xXN(9p#O z%;{{VI$s-9o-D)enMto#0> zoRhdny}QY=L*{XR96KqhN_#TDJyHjk#^)u z4lCT zA)Hr-JBW!m0Y&D~&9lQ~UIlVvcS2U>*W{HABF73pbyxV#r)Cs7S>Jb=5R%0mt#t1n z{e_O=Sij)pzjX?p{5AuZ$F1;}+^vB8(MnR!Htl({vM@_6EnjBV2k`ocV75BF7yUnL zsbj{qLcr^sKhkvtc`kb`8vcIl?q#5sFs>KJW%RJrWq48EhtC83MJBDZJQN-{`seJD z_=HmL`AJgC7+v$OKM@1kpkMF6zwas%K$%_c2k0T`cV(AYI7g@ zfgA`3Y2?fC3Ae8eSJMJe4k_+pNc$pbJJh-*evac%iqlm4is+cVULF|ZZ8IZvdZ)=M zzl5xXS`~a-`Hh4ZFF$8d*rlDdG63xl5nQJQIAyMM`jvx5?SIl6CiSwVOgCty7vfa> zQ9BXG(!l$QnQhTvP6S03{va+fO@H`Ht}U+7;#CTz1rPqktRBZc;wI|Hk?Q(~)$%O- z`jpgYb4Ttfe#CivP6bJ2)BM9A;%KAs0M}T7N**wP7)^kyVSw`(*hQ4VR}#;Jsc5B} zln}Ke*oAd~z0@>r<=dQuOW5>F+84|b1;)Uwtx6y^$_qBYZ<7daD-^fNP*{Fhd2cf% zLxZ(}VI7vrw}ilXl{MTYmmxSiOBNPnS+sNI7Hd34t;P6;%hn!|7#ULzB>|KPL`W*G za316?hlk>?;=&8lbv}X=Z+;a%7=p*#sYC>Olwhc~FuH#*Mlm5lIDqp3L^59Vl)ced zbs1h-%9qZ8+^ZONR;3^Sh_XwNl$;E2qH5p~5cB?KWsTQzCbo_sTBCg2_TvK~W+8Y% zP!js8_ZOZ|YMAGgR?!_P}1Cv8pAQ0wGR))Il19d>_w^ zh%|Pbb{XZc{lUvfjz6dI6Kb3rwbEzau$?Vn7O0~)@A*K)5I9>y{{XM`i2#U3-mF-1oMqhAg{yg9USi0!3jx(3(muaZ00hu4v z1(7Nv?Ot$e)TjjATok|Um1RoSZj?OtYXj}GO9E=c{cIUJfZ=Js<>%Z}CB$lrR=-4r zpbaAzKg#9~X4wbp{6?VyuaifwXX;*9g`5|={zu|d2cT^RTmJVS7v7OxzmMh?;ktA1 zev3a$NlIKLQ#dlTuN}*Adaz1<&{Xouwi-zxgK|OVaYQNXx$t(h1 z(1w51C|ejqxBO@K0LIaAJ6(tq~J?}^IL$ zzIdQNOkpA^L05(IbUwkAPzo-syr}bk&)n;8LV@izsZYZzBGDuReA~v=(~kR(A1PxV z&OFfgL4etIa8Z0O-|0QU<(F4MwfpnuyYm#%YORsYh5i2kB(#OEBQFkr?6a5%sshO8 zHT-=*Yb42N-mN|{^NcigiL^Q4eQo_cMb=itAWCd|{{ZP5CbqN>eAZR|KA{T(0=5MR z`TqbE%B)raX|{T=@9rp}1xBBx>E^tXcd5Iw&nCHh`}&H2U3dXoVBMbh2db0-iUz)= z`~LtORVIa0j5>dD>r5C6zFuCdKd8V)T?Re*{^|-VPzn}25uv9G2UW1-e2?lNoQ_%0 z`_B=J3hFTUc&Me-H^<$}%0p4~V`?(kF1<%ota$?Aq+nV^PhQ{xLBUOUVZfoZf4c+m z#*}^%`>^Ti0WS<8N>J^{u)&t6_Z`uC)CFs%F$G_oxxO(u`5T*&XbWw-^$;s?cW__& zKY@?(rMwRi+EUVy@5H*3wJx9e5?xnz02G**ab>dgFhEB=%ii-7uR14GqB5(CcT7sbs2D*RQpb#oA$M^SVI<;uHdSs@ zopU_orpk(moz~6RBUqnUI0)vAb8JK$L5pKrqU!SixVQtpBZx-EK&KaT6Jb$>-AV>a z(hhtr!WCYl0pwr-WrBr3+qq5x)K}E9;TD0G`IHCoN0Yu#47iIqsH^Lj5+S6U;@Yv;Nb{_{3N=$&i??kyDYc! z5->i}$>De0s9U6uNwy;_seru1!-VpUn}zT{nN#fc0E4h7-t2)yxLZtnfoJ=nyaiq> z>Qru7AaxMvLpvk>7!L|;XtnQnj?Q{H1`hAQ(OtrqH&fnCv#pwPe46L{pQmH^*ThSKMLX-gFY-xU0a2Mp*kcq2C?E6t(DVH2n z0HqgKe^kT?9(P*DZ}Y@33OB-P@yo&iBqN;9K6--7(0Nr+{AEAHsDxmulw3Sr@`Z+# z6UAD({QW~BEee4t&*%38N03w)<9KgEVlcT`VHFx48hNMx0H^9bB>`A#&pw_bjSw#s72|v->OCr=pLhLJj}g{B zVQ%WzkJsu@4TcKE??34| z18c(%@v^Ek%pG$L;)QBTd~@iD0>HXCzaQ7}9I90lRaXeslNU!(b_Q57&nNTzO2rQY z!2baD1(K&c-#^&P^kSCRXZe^iwLSgHrD7@Jh6NQ06q@zj{{XzgHv0EHpsD~pfqGsuRo`|i@xR1GtZ2{{gSInV6B=u>0bJ$sJ9zyHmT0`o%*ICQwzj} z?;PJgN?>VXQsImoxel7={y1Y3>~=Mg-E^$VK? zKxGxW?oyO26DcbL9^U2j1=1*?h?5fx-GNT@iBmM53D%rHw} zHc`9u9+Fc$ov~B7NiDWU`aDD^0>_971sxCZ%%yNp7Jiw}uo;ih4I#8>N_a6T!T6L5 z`i(xWecUEL#3g`LO)z4Q0q6e!V(Uf&Mo*!>`I$%P!DL>tRrEh+8Zvgh!<0+C=?}_@fcdNjJa+J6}s*u10IdP6FOWL z-Vm%@0Ypg@LEKSTcj^YImjpH*PzMvaT7W9>?ors4xQw7SA);B~EGd(RRTE%^IF>OJ zAcr}M;(>9@YlL<_3xZOSx$A}z;Y75Q@q)erHRY61YvLnJD-y~}Un#|T!$U%{WE9Qr z5#@jVge9@&Y60^SG|5riJi%w9g5sBG!JyVaRBc1Kvjwv94=ph8KL4ZkY^xq>ca3Xnxg$^~Sa{z%qa6zWcXAwdbXt>lUn@5%{Kn=yljkiHpks!mt z+bG+_%E#ITx;NICIN^EgQu9A6g0J9lfYvt>s=fx+DjI4NR4=0-*cdE&7e=18IZDj| zU}p2|MLe~}`_lbmFKB|*QlIAt+9h3-eXr?;L?d7}704fF@c|`@P#qD5C@sG~_Zs%G zQ^j=u0AK3^V&HPCP5qCp?m1Yt%iH7lm%5FJeh)tORjTecRAryR_c0-}0^bjwe`Ic> z1HfBTi{4`>4Tv_L1NTg>5YcM%@pXJJ)US0B$UpA6{lGwQZE(U9@dGb(@=!9r)r9iP z!&6Q;yHOliC01+E`20_E<3p9dyi5amwc~aH-k<3$D!2htSGM7AHoR3O?cXm)a7wj1 zawjVAC0I3<@ynO%gh$JDSwQV4ul#4f-4E%C`TE27-(Z`Y<2l-Ar?z~E*!~{LLLX+8EeIJXL>$Dx0U2l)|j!joo8|8=ifBLEbI6S_k z_0*)NvI3y(u+jG{3sIV4c_Yw^g?IG{Aq&eYe{g&k$~Tyi5f%mVJyv~umf47jH!CgPD6j#jH-qE+SmN|#~$ zL2b!bQFdOIMqta!^ERmYxP3tvqisQj*RU3S)Np1|+v(zWrHxON4FvEO`-}d89-CiL z?^O!LyXGzST%&Q1z)l)3%j#OHn4!WVitJYlRXjRGnxXd|7lI4`fI(aiSUe=Kq!{%t zdJt-7adRZ$$61xw92aFjW7&e(6$`{(EtGO4Rq-Be8@xrRA;7|4 zTt%FQ#1PZKPGB`oEfc(jP=Wa)u|koznNm4{y+U3{!OTS0veRpS-^8s#f*h+m&Za_=pjTH-_bVDWQBAh`;fSCrz4J#O!^C7#?6b4# z8+q}=prC&-MbfG|d;5r7k0<-$AO`3vQor~_RL?7?HI?o^ib+OizrX4W8w#_5YY(dZ zKuCk4JDlXwD`IIMr=9&7tp$Sn^VbXU7Q};zZ4W<({UX>+r;Ft4%8+LuJF|sX*#VR` zio19Cs-K=>!Du-szj`@{E@Oc}j$d3L_?#hQ9qYIE6r9t#tU~=?UMChb0AFLh+E~gO zlBg{|eENqK#d`Ld>t1D|2-rM@p*@t?AEK$&>#O>fbPD)<>yKZ|a#le72LAvM_<m(W_Yo@^&OCqNJb@O&53kD@uRNbjqeZ0yjq{CPXmiOJWVE&! z(ffT>cqILXv@$2-o2~Trfc3=&uX>l>H3q3oYkaxsBuWGNmlTMT+p@ zvi|@H8yd6;=WXv_#y!S2ju!=S6>VB-w*H?`J3s?!r?1iUguk{D?OAS? zP@kqAEvdq@M``kSVZ>fS3>U)M3B~l&+*QSUYN==2r;R*CF<2DYRnV0E_FQWlpfcO? zJMs9&rnnp%^K09me`E_$;;i2yj#fNy*&MT#*`GqIkKsEa&|WF17><6bxvrrCUK(cm zu6vr?ZHRq7{{Y@d;R5DQR*#~ z1y3~qY}D*)jDE&l+b@{G_OVxQiCIHlWKyZ^9mN5r$HC#YA-EsPJwuhB$JFTV0$aT% z&Lt47kGS#Ya-L@$Jq>;%?kFC^#5+|o;H79K$UUBAI^{HN=hxI*za@EvAnK5F?j>-q z0<7*-Vzg=F>|qq+bx68s-xtIOP4y&GXq_Hn2E131mGQE;zlos_N0?aWH80eEE%*?4 z0p(?*m$otsJ5*Ysh8zy%6re#Mv)n6o0X$9MmtvoImL)`?m1!>rAsL+Td*<}5nBif?j}YgA2DVh@Ecb@;J@dHg{ z2~RTmLF!rGB(5}tz6Vmut0SsB!$X|LXtct6)ibIHFVsnW!HIB6;oQOemCnUa5lkkZ zQEU)G%yk=E50Nx{B)kAFp5viPa~74h?l8hGfI{S|)v}?@0n}ZyR56|?i<>j&XA8^) zwe7?~I7o;kSd!fZ1masMu=bYxtaVJtGxz#}Yt?RkrdYQ6eZ~M#quJ&P5KskgxTCw= zRYenb6KH3fuW`5xsdN62g2u);GiO9mL!WUI%McuQU%8A#Wxm;P$2Y+A#alM!$2NrN zjBB_|T7UuxzzU1D>EUu)^Ud$L@6bxODCn8iC@Wm~-M`$WGFt~1#kZU%`_AYn0cEd0 z^!T}e1ePgc+wab?A@y!}5@ zWsN2k&9P-74uMT`k9k=X0008Z+s?5+P^<_A`!@G`dFoI=U}(Knr##$6kTkYA@7RM{ zlIWm-A6CCr7bq0Z6eC~1FMq?}aTbx_!JwfxZy4p?3U`S4dU2z64zh z7`h+*%3p3Q__{RxL9JU(no$1$AIvl{a&_oG0~@S}f?pEx$Qy=NXXO!r3U1z|)hw#t z>Nb-XR^%|)7eMtogevl!1HUS({{SOYL1?t({{U~t)KHsqpr*whGkwz$Dh|s##~y2w zvw4Kl)D-Bz4d=7TWVTko!%tj&@qbZjE$zRDj{g8;=p~s*d#|t9`j(XoeAf>-NAWDN z16Hdke`0rI8A6vTx@G(4e2{RInhK!n>rb*NRMry0wYxtasxP!zEaUPtWSNKD$| z9+kD-cidGHHXMu>&VSRj0u^(}Qt(y(0Ka7L;k>$4vAIAgVg#(VtIaSQomz5m(w(91 zt?pA+pa*Pj-EN4k_55kJiT=N%!_}?2TMF#`z0r9JBNnp`o_AC zuY$xL2u~l>2)IYJety4$%&@}LwbX{!pWHT2x3u~WzZv+M7(BVBvQa2p{D=T6_&q_y z1O?<=50;numN2ek)XUREl%Q_G@fFvA<+VqZTgi-TLi5Ey&v#_o?M{f zYsDN{pgN2X9xeh6cOctWlJLZ&9&C0rVDeO0PR zyLJ|ecuVaU+Y1T^D(fS;1lOJ91U3(Ikl5n@i&?KJ#caVoP_zXRx(?wAi`{@t$YpDs z1S2~gk0WBF0%0`zgv~b_MQlP zy@PkTUAmrXW!aMTd`j0CXc4a)1BGM7P#sX$ijAtcMlZ*x)OuzFTZ2&E{y5BL!J3ze zY9#e+wlCC*v-F#LiBiImt`oshxHQbJlE7sU`k%% zgJfPWn1NDMVO=e^xq1s%gcMKB*=b0{X);%sYZ zA69=+P|2iJ)2qtqxD!#ss8I0TBV~i+}PqgVLM@cz~@YmanS+0I6zm zMpX-+=OBOp)4aDUeg&BY=<9vbYhwPT1gtfI4u7`zhOx0II#mAu0CKXTwMyWtr(LW4 z%PfI5P-?V&nFU!24K=h=$4BuEx}rx#$A;JXn1a~T-KM`o_ZSF9vAk7$*4A+j+p7bP zg;VSMhC|M{?4AhE3WA_1loZ_i&<^ zAAA0U>l73fP-~jLlldV-rc1kN<#XALA{<1n2tMq8n1(k8K)f3Mav+-u>Vd2J@Am)# za)Md|*ANw9@->6}%C%MZ<^K7JVAi^E!@>EKF@Q?MTK+TYD#2>VS!w6~pSfUB8(?8~ zopC6klmb|G{^Aj^*EwtW_XD9}z@qNoh@`CKQqil=$;<`-pJ;!>n5iT;XMB&`T_|rJ zTsQR*WQC&82Nn2)mBb!i*kQKaDK!BLEoSiwh>@%PkWs0nQ{tsO3%8QsJ%bwON1xmY zBH63(M|jHY`i_T05q&uKT#tH3wu%I>PhKxyOuTy*&>ZHu^Y3HCNo~bzpX$%du>kFy zxPL$IGR44B#s2_5>3$*vRRHbR`9Jb1v>{FCctNlC9-{$r1wqzz-_wyQgJL&z@9R%z z)F1Ra+xYtXBj|)5A6@?dm_-@{G|fH5Hi%KMZ|?s9-eDqC%DP_%>%aVlnkjHP!7IP| zjPUJf7OK>LDEF%tm0Yg*@0$pNWr7sqhFwE z>|)ffCwH}fa>M|qgg7hj`-MO`9-~$H{CSrEI$hlwx#yAv0KuluS&jZKQ5jkVEqOZs z0PGaLIktX(?goMyTPjv)C>Pf;cm~|Ep5>$;ka>u@LOjRKR&fxQJkRb}Ddk-;%Aq^R zAdsg|1j}bG1}dZmuSN|@wP!J1=uTNIHcYH9wM6Vf&k1;*=8WJ(w;@sZvn#|vvie9j zEVl{8%1DLMSP|OqXP65i&=fq9y}Lz&;U^FjFAu*Em=NtJ*(+iCcd>vjZl5!jB-bDG zhlIAL595X$Brc|yw9l6IB@aoqy>`M-pzuUR9LJ9_Lx}>2HH97`rDS-C0*l?(a*Cf& z!UW;%7>c=A2OcI()|nA6Ul7n765xj{5Z_5gX-#y5$8dAtO%UZ@~f~ za6LaBLPdjAvyO{nO}t6~5JzSu6>%vnj%ld5Eyt*67Pd53Q&NFbo+qJ$84S4$`ht=) zq;vBcT^Ba)C}3{9M4Osk5}A&HP+|Nl!SxU=h1V~*Jz8}sY*WOpw1s8yG%RJB!ZtCi zEeP=yE5-A0XmHp-AqP=1vWRz4&1mf_cGFaNfE25ta`J>LM-b6qZSZAVK=LvtQ%4*( zkLoZmc&3WtaUNP9aF*;IFU~Ud+kJ%>4IaR6k5ML?0owN1qq=d*%&~MF!sAjFdug!*5Bxst0O?E#a!) z#A_f@kA&GNg>T;EyhU1+4}5o!FhSQqu76BNVz?Q872}dEOl+c;GyIS4CzcmMkMAX} zB@?q<@ySoQMgptqWmR#HP~z)4VU+&>r=}#j01*;p^nK#vyABK*EyI5w%okw%SQSle?Sj^Z(~u3X{w1nM${s`?%sB)OS_^*pRri*F z%INT2-|s16s*AkcevjexG_@Eb3(_S0yb9* zgD_wI82H+Y9&N+(3jn0Dw}$@!*Kk+VpJ7Fw{{RVO#87lzAE={cxLea*zQ}G$Z2QHZ z+-IvzJI5d6IFC;%6evIGe^KHUS-%2QF95-^i?AQR9_Jt`5S~-7RROg;P^N$+0bIp{ zlAqZx<^vX8zqEk7ln^;T@dc(gshS1+hQLW$!Ab)a`TkI77Dab};=lDM4lL!}>+$@f z7KKfQx>5RP9NB}Ku5au4m=W$OpsH1ZaZze+QwLy&mF59BMVwht>{r@eb%XO-l zi-Z$E+g+OEaxD8FU-Zi3<&W@vFX@%GTAKsk@Td1I#=+$6U!Ve@+xBmcqJSIxa z01yexZ_l5uC7V~taB<^Ly*tQ|O2RO&9y{;;m?2?&H%r?HNkOoFtn(DAu88N_0#*1M z(E9%X5};WQzhZ$)ZNdEx8<}$(KNBR6mH_oV7@X=h= zeZ(nS1f{CKqOZt9;8&1y=8rt*WFRsHw6E9Y{$nD6)wlh~x|L|*)IZICP%cY)Z||@D zjP;~#_wK)vcL7xPAEo>K#0!M%@#FYl6|>lS&#rw=dYrtpj6@iKnyFW*$l(@exQ=Sc&f9sH4vp5Clbw2@=fQ8FhKV zf3jaHa;^v=56nNTTmr3LOiESxi*ZKU2h@2@?#2u(ggm_cN>>LFtA%Pcr1B%lDRhJl z=nn|#E^=`lu`e|JKjLD|02KcKGTb7zEANx~i(P5#c|0(%ab=+WF;OC-cN)YeHKtIw z;oe~$OA+xc*9Vzkf&}Nag4;ys7Z7c$WgvDC3p^3lhqwiNvoeMC6zV{fs3?|B$Q2yH zg-7|7{0J(c08-beH9v_#LMWJ6I`&$$mNvO46tOtJnZ{dXfpkHX+KFIinc3DYG*s5C zwrcMpi*wXhJ|@95%mf>1qddOn(L+GGg5rR;pAqOP5Z20PlQ|c#w6%748k98@zWMk; z4PgN3MPg})%D+&^TlGEAqnV&l@!7VjrOMPtONt2GPFFE$Ovt=T!)c5tW(90Q3IQS; zO@L_=Ym|7Ep{T~T_j66F@I+GrDhm>-J7dc1GT3yL9UziIn*L>!I-UjOukMKCYe0BW z?*No|hDn6!joMjmU3h_j!A)HCX)z#xVof(5o zGWop3q$UH2a+DR`52%ZDXt?^yR(3>|3vR=P7laa3)=p9j)AcLWFtvAhvhY0(ZQKyX z-q!l%ARrd*?7d}pTuIU5EX_-XjE=apVwi?!C)ybA}WoT{jY;_m;=^rYr8N)Eg(j9W6Ru*zkd5-4AY%e z!gkZ#YJU+%^Ive$`1C?Z8#Ic;Wp-&uwq&b{F#i(0q&ujDYVM`< zB6zM0Q$6u)`Y2c>Pa^K}xD~QmTMv&#PieiNY*zDJMUhoK=+XlatnaBm^9e?(IG>Ps zFZJ}Azo`>uj`~mpu~2=C(=s|!b@>GEQ<1w{#>b!21y7a_*;VgIX?FGlQ2lE7bo63k z9wzP3{@Tl~pjI}vr=CzA&gYu6F8P>fH?teHKyN9BZhriDvHcikrKxbRah55~Z@2F( z=cOjMk&si(@)l?_tU$ATexZN1ZVr*ughvYADeCCas8&VIlS1RDUr$;Xwj&>{><7R{ zo;ZwmJhk1fN_`SR?>-Poa$cUCi-tV+-PqmBAs0nm^I0k|7NcJl#}NO+<-0131Pq_6 zhtyAt@LI2H7q~jLtHcR_~14M$^?WVN?A-wM(2Jdcu030xmB;5maR$kTBcIixA z=JrlO@FD+UD|J90|k7r86UpB}?i@56yd3n;j9`cD9N!4gP2(#FqU z$AUkU78~P-q={xJG(n->u!uf_Wez|`eK1GnjzW;iL&PUx1kTQlP%3^pfcHG+-|$=4 z2~JHiRs+vVfz)ewC$&i}M0laN24d|32RpeUX;83RnjQ=p&BxrV`258`w6`t1i(MDd z4#kvXg|QLzQ=dB z9#edGlmn`qC3-G}mNbMiepW}(E-lv36$I2Na-E)nqlSBE9LTFfTOz}k0HcW>Zf(j) zXw)lu+a(Wwwnk?i?JQ*Z1t&W!Jup0%S>x_XNBBvXzL#|1oF^lxyl_|CS z{d;$Yiv6MGsSukP%jygvC=-e_p8~QZRl|jad)OeqpGFd)ZL@P>yPFk_`0{os*D#=q zsGzfxMON#v1wu0O%1}^9TlmGNJtn+1y6YFuGgW;GV%6g*ZW`4E^|R2dJtO1Q)*;8f-WsI03!05@VQ z1%OWDTuskM^o>O7T7h-y?V{gP$E}3WrvWNjyI5Q5+^Eq#HhG-@_)1Yd_RPFKNT|fY z5Lc8+w{spZ1fkxkot12$$+n2~HET%9)O}6e&u_eYK_-TSEzydB6SP*RCbOkh6R$T& z{@q4#7Qhn*NE|z;Pke5TcjLnA9gM*Sbact!x^~`vvNN}k(42hcr$jYm;;foq+!qx^PN5ZK;xUtEGq^;(@^y!MK}=6) zjYjU;c9^MJV@YY6{z2?ltAgZ_`QQ&d<&n@n!AZQn+f?;_U1)4&qE)aS58nA9@kPjr zpNCppkE38gm>e-+U%U-FZ=07Sy!S)ZvQYpu2zP2Qv2@l|l{s-z=-{ko@!s^(7-9Xw zeXX}Qu~4j#1w`!)5wn{0LFnQyNVr+pbkvb&gSO68NH_-*EHkU5*Z6uvBLE zv>lOeGrHQRxA{_zs-FdQ=0emz_1;LLZ;goRtip%Y2V{!%n`nH<&b;?ws&r?`w4)99 z;;IES%0_Ej_s)^vIRI4#kaNayABmYnj9U3B0$K{RPHyb#i~iAT)XI^kIzNkcjfo2u z4hb4wQ`@z@U@c?400Cb6gx{v-n*p^Pyy(T#k;^HoBo4{(8lKH5WrDKGr1~VU7mic3 zq;4Uav3E(5;u| zpWI5%GsrYWv1K#Q?(Z=C;IU0_dT{v3fWr;bK+ECwQwGe=fXkAtXeq=ze5B_qs&ZO0RWoC_N)|*X zPL6yq@C_(?RbSZdeHe#lDki+IzIl?W6dkmWy8x|3ShyF4ee2FtbF34Qz)3V9>P+f zp0kaGRX1=uiBWh&%Y-%n<*nR~T?AoE_jenh2_&F1(^r=$6)KzJ@w}a1x`Npbn<79u zK!K(U1UW4a9f&~%mU%?WU;}2zL3^G>Yk@Wmv6t@9rzorENpg@Wni43jF8fLL^Yl`?ZX;MJ(p z;XDQyR3@8}DCp5`DkIm^mTf|T)V%Q~i_axywe;QwId=<*kc!6;%%VCmsj-=+Ehx}Z zH#q@lcI8&0LcWrLk|^fx2o&|IqL&+U!bO=fQfnLI`XL6{kRc&qgnSHSc&}DZosDZa zA0X+~frIss00X#>qa?Ol#(}mbM7Hqo{eX~7>+d$7o024z=qln3XR@g%fi8n6O4STVI_^^*`zliAqlk{Ejt)+wkU4ztG1ayj_m zJ_TZ+&&-&~8n9A1Y4ubqs`fYM|C|{>%EJB>4jg;h-xh1&Ngo~$X>LPQEHLE*il67xM@*K6H? z3)u;CRPgMGPjzwWJehhP3<&%vOQ4yy)3f1s&0SS?{yZX1Sro_j0<2NS}P`6B0<35ID{<{uoG{ z^)?umV`#XGstVSrw4wxFS5I{a@B#-ZC^E4)RQYWO;s675Z478$xl7Sp)6EFD(~Gfu z5v>YPnIiHmJYPl0Zcp?SX}eu)t*004z257YecOH~J>6jfIbPV1K#nzDZ4X>;Gfn+H zsT~}jKS9x~6@TtQf8@vmHaBWrvNqu`62S*$P%>u~s(h_>?_4t>i{dg0&%iGqU-SGO zMGFDEiSmU7RzR+KDdt zSRZi_c_s|)R48DmAa;_G5@yigA@W>{xR&l&XguxcjWE36hj1hbpsBMbtaqh?pNX`$ z^IXYU@FGCPsjY@5j2^{u(h~^eJ065zzQ0GQ=XUC&x;H@8LM{$ztQ`-t)(jBb55!JK z83P4m(W8LoF!yX=dz9gms1r??$WX>dG*Y#E83JJYQc@E04nss9>)zQgU3X58P+{dz z7Cj3|z*6z+SJ8Qj){(#cgduOBUzu02kl@uMMzxc5USX;f*55&QA_!NK z0FYfIot&fQ3pfdtV9(`^(@ZVKaF)33_)se^-#h5J6!yJ~J1)>#fkwuBU7HL;loHq- zTUpIHp+oP@Xha6_)R#^L+J;{Ib!YA+r*e86^1+V)b(N}NZtTeP*L*@FXV^!dTWU>^ zcP=uo*{?+)i}CHj_wnW*F$Dz1E*N{^ad+HbB{<>LB&{!rlVHde@%fOd0}{~bSU#^B zM&N~xU;$@k8q+J(RMJRAC}GlIxV$&*IkpelpCsv!s~4#j4=U${mzTTEYF+v`2@TPB zD7|i9;9VUwMa zapcH3O4YStw3R8_hB;$D;wqpM^tZtQiyGFGg@|m#CjwD>pff0`zatBpYLxqFbxFKaByuN*_i!k=SO)pY1?&DV z0@E94OcAY4xjV!^2nsuoNp-Y(r;b|Y-h*GipGNuF%PVmXNr$u_PRUG=F&gv%C3Ri<0O&ak zhTjbTfnOr~>LBpoyz^lYna|dy2kpz{M(L#xSBGS5c7j?a6vt!IRvQLO!j(4H`tUeA zQ!j|yDe5pPmfMbbukWSZ!#eKYZ9F1JUPIH9NAjC*4TG+$MrB|4EVEAtf>wE5dP7rU z8f(c>)I5bw`!ZBXxAi0b?TMfOxC|?>=?>u-eH$Tddtexu}cbQhm6f)^$Ub&PlkMW8c%A8} zx<12niQ?7OCqf+A6jX|n-ut1nS^Ycs>J~Gk|9X1chC<}pd*BJY&GGVY3uqi$8H>g2 zLaQOI3#&p85HJ-Ndx(0vW})O4l5x7$?E7=%x4U2n>%%?2O6hfCOTG;hVpE5(WuhthY9Lmh&{gPc8#t<%vq z36a$<&mN7EHb{GnDIKWo@15kX z6Za)5oVtH&FUI9gd$O6!@>&i_$v_l%aA$0oB@rZ(ll(Ln*(WP9hIC;y$_6AF`Xhfg zQZF?5jl_>IO6r4cgM#0!!l~e@Nt~l2EtI5&QA8P#(0%nUDDTq2vt)oL$K$zMb4vwU zzd^3*6QHuzccL5Z%)(mvO0PIY;Ghm`zNz-P@ysL$Hi&tLTAgxi7vmIHs`L|Z4bv!* z<^{N&LHx}6fH2x2f(0tz&1tg{#raJRn5tX6M(k0&zPj^iu(vxxq9w9C>QlYddKY@JO7_O5zw z0IpL0H{kXW`!GGV{#T^x*fC6_xpuPv^UssMY#Pc1AxTJf&k(wr9;@%y=A^mhF|sK= zo0`J}E1(kEsl2BB7_f_{0_@yfu> z8k>B%<16~6YX=08V2FHnw=5y-%6#bDulc#YO%V2|PewCwuq_^IyM*5%(1E6g@(BVvAN>GS#l=_OKL+{oC)-Zgf-41; z6@QE^qH05UJF7-;M(RXrzEmV1H3d9hZyK5Ab0fj*>-r$8U$=Jr-5fqi2?pqC;mi*} z?6L@TFChZA&(+yihH+98zg*5cdnx_;pJBxxQ)2n1_Y;iQ*<-Ig`Z z47cK03I1j{1LLe-g~D@{x}_SY4q-Y@TIeov-9;Nb#S#^opBY5uXXnPfPpYkp;D~ES z=YmUn5^r39i>i!vd19jtw22N}&qw`#O-aIY=McD7?kY|tQ~9(>`knV+!%zF7(`5*&5cYH#f2E82p#R6O!)a> z7^F?CO&!e$Ibj&Y%q<;F>>0!?4IE8GOpI)dO<;f#{`GXOX^&lWX` z2mRPZH&uc5;x-|Jz!2-+-g_N8DI!6O+P@X}z?%ht`bCINm|o**%BZo; zw*jd$V@hei45YI2Q{FDay4#AEh9K?5sRO6BvaJW&hCK|WDCYOBYd|TUkTfIS>8$zN z&6J_>?XR+&R^Vf)aV>pSi_oSSst+M1JH<0~PT(-?P8)msgEFjbpCR<2lC<0LH4iEu zdj!2Cqig?e7+fVwH&&afdU(%b#AR~xT^|AD*~W7>fdQNDN)LVpzdl=fPRA|Y?FQ`i zrz+~dd*wf0+fN>4;bi;$^>Y0FdjC5Zm-F`r{@*e#Gvn_O|HZh>OhB*yFUE~ml?h*B zL~46d+iyh@Pl^6u3H_qHCn3=Y^f71%6Bl?tzxIl71+M z3W19%T$*)NIQigjv3UKYT5#^4zxNTI(icGQ-;hG$=0-lqaJPSK8QXfY zz$)EB9}-j-Pkc@$Z4PltHP5j}nh%I1o!{gKvy=duKDg#AOa!pjEI_=?IFS;y2-h)>QGT48V$L0*xQ|`hb=AKt1kJR=0e#RwP)dOc; z;-7Xp1zt?WESn-iS?jX5{~+r}w=23N(K*5^Q%i=5KwOT4d3mVnAYTNYZMIB`C(pta zBbmdDNv9kP#`e(Rt??kuUn}`Q{|Lewq*oX?ow_mn-Y&qU*`DcQ)tag*X!)$Z&p$?$ z(ySyqZ^5Z3dC%M~oD?a6{;Hjn$SxAt!|^1mRkWwe4y}aXR-sTYtnL*>ET~p5@fY#8 za6Tx5i6L*fG(OO!f^tP6>TEL5K)8;TAWr^VLp&iJjS(8gtH63h#;M^i_=DVZwArHv zF)!IW@!n4;bWZg7Tfih(Ku1FcKgrsjxOD*~o`dH3$t+9DvD1+P{1|#27F$s&$3zUf zOOktwtXB6RGu_F`V~)JWd4^De&6|vy&?AX?3Y#x$C-acdYWxh=c~kQcWa03Xdx*KT zyK70gsjsN5jW_3~U|AlIC$n2`I!=6=jBYTQ2}WxErv3lI{Xg432NUzZ+duPvo8V&p zr-F<5uY!yDp9rq>SgG)3M!5d7S2S)0QX{QuG~x4XmSiCtVKBb9)%qHf1*?UFY`ylF zw1aT|c|%*{qv#)U^;=2nQm+2c!f#n5dZV+ab8dIMTphp&gh6o=TaZRTqB{M1PN4Sd z_xQELlP1~-x*qz%m&RcjX20ZHfG*aqcAX{>A(!nnu+Y(sXfF}6wgj_K<*y|=O1zD%P{E|i;JfKko+ew^O!AV|JoTXd5P=aoV0zhf z7H3si?{ZXHRkm>rOSWrHE58XDD#$tenX5R3HJk}s6iP)4_o~o>)m-h(ltkNG^RZ$6 zF{ZkkR~IV7exWAqA5l#|UdAJ06F)7|vfYj}i|#**>zsF$!OS3?e3;EJBeh#e^Kauy zU?1>*LsL!9xZ6G?9*vwyK|rQCf zSpF*QSpJE$b5fL%>t=*&+XJd;)AV1{U876h&TEodqsDU*T36X&WkrJd5b$V#yvddr z4Hw9GS$^d2DCF@A9=(H(DV9TWQ15W`GMPXu|jp)R#!dY42k^@vynAR zFAAZ}^ZN|MZ;~FDjbrK$y2dR@Pa4QsEtj*Mm4@yaT-NiX>JeJ2Q0bSIa8!W1TS=)C zmGxn|9@B<-avEsnQ>1fc-#PU=jv8T(V3DriOdlcb${=lM8kK}L>vAy@5 z@tifUKdW-k+cNiK{~MlXLLv3!ma>a4g8mC-iru3dB^G2hq1)whSw= zSJoR(`}X;|Z`Jx9AEfR!y1dT(r`E2F_HH_?cvJ@K@pZIPPZ}L^!kr)MJQ^AI9s`11 zQt5YLz$Oi@7IZ3dVF#@6`RS)Dprwkti5Y?%oA5EJBQlCZMSJU$m1GP0-EB>zSccQg z)sf0JZ>mC)re?l4>#8M>G_&@H+QsD_hR$QHpXy6Sw^}GxF)hqHyDpY?7mippEIPVS zXh6z(*&P>>4v-y|<}bwfu}ERul{+RoaV%M13wUODuSuP^&kD1ZFqS;B;=Ks|7)LYKfpiM1sV+J3 zeTG+&`<|z_kI{bHx({rDmq#x2>6ji>sKxZ+)oHpA@KAK5H^(RtS8|L}Gr3sCg^tgpipJnr+_lb-#~8yuQ9*|rPAB*S z5EWwLbaGdki5La1j+mn4?1czkVm+=qU9#meV6V3w1~xO>o5s{$fhMWP9!4SP?lWam z=bt^+JiAvbg{RGD&Q2Xox^JT2%+*L~g99vfwc2?|2`0u08Ng)O5R@(Y!Tg$o7bm_5 zeZn|pvwSZmb~L2f$Ta7hhHU}mFKKiV(|S>`$?ddhx$lJ=p&^-88};2X&JGt11^gt? z3}d8TTGu|`J6)jJ+_}F&3qujFyPDKB@LMgL_zKY=LYJg2X?t@}x!9D4gB`;oaS#5I zKHAN+06fv`L;o6K8B`!ur8FTMe!+@Jv?2tuLap*jiobc)7bRHI$S&!l=@K01q#~q` zM!U5Lf?QNoAEQ>ZUJ4T17%-R+ ztPD1W#ob&%wFXBGX^YU$6M!aG*_!BKLJ2<&AFp&&D`xwO%n@itO#vGBgTx}oo@!5| zc&&X0E@!UuJIbM2$=v%2kOsM8GjC)M9WkYgot*C@AD!~w&cfSnd0#X9;EnR;@VXCN zKl6TC@$B2~*L&U106FY}$p4$x@Cz^el##3)jQ?&8tp9B?lJ%d;NY=l~NY;NMBb^la zK7uj9t-R2%LY*2)Rik%rWDn$z(_Lo?A0&|DO(x_C|L`W`nG?*$a+K4PbKmqNSYJx- z6yEayADE^H;iCT5+FS_X*$B9$7vG};IU5bj+eBs6_K;%<^-J(_2o@!4D1>u~6&_d= z{7}G0+W_rnz|D)uo4}Z-&5ezMy_`S~zfZ#EVqy&o13TAj7U~pKr;sCmAkkv0#68VW z2|HGn+q2ka(esv#%*=^O1vl<=R#IY>no4<8q(-v@~PD~7&U|0x2q{S|@P{s{t~Xbf2!aiFXm(VTMo&XAVg zgTm2GT0woUD1m)dxKHdUG0fjMN*{a)p|-(+0#>Ee4}kL%OYZlX<3 zn$PHJ)f4+37S@C%4Vz>ZzI&$>~yIfBlKN#Ee1eMHKz-Y9C!z= zG}d0OHl9XSx_4jp3TeNcNFiK(sc$qWGupKej_YD38k#PG)2Eo^JiBDm2@2>8+P`-*;NUd4j~a;|a6T)^+9?jC!t~Q9g$D z9~bGPk5I4e!8*^c($M_8G3M7@*ljjf3MF6P7bsZ^k`zR?K?!y|Vh<+MIg^;5B5l5O1$p$&%;jey9 zmoP2@`qSAnv~zkJ-9{pq-K2A*g`UGf#9JW;yqY7tB-iFBcnd?cHZn zBxQ0>5mN7!nIQJ?&t>xaAXeW%Tf^sErvU86Jt7X@8kk6>h=QG~HsTbX4S8>+*Pq}M zX`V&W@RA^)@r|s<8g*qa<7rcgPJT*vkkkgFMfS8G+&)aUiO^>BI6e`Ht<#lbQL`oA zlwrS+P>01&-gFe_WvEZ*m7M#$=_kRPSzoe(!t`#r;)>JF@!0GW8<{PX9PdD0_RUKu zKflWWTL3=uuK8UmiZA;(Knku0%Ttj&V1+=OS@BpBs`Pm{(%GgCz9~YXnAa-)-Hz-u z*`%+?mazsu|Eh74#+$sf$10&QD2l>cF=cZlz-wS%bpUA<9@oQ9SMJZ8LA zir#+ii*}rZqBaMe7^Z-Sr9OEkr^zzbkdW<)5A_m;1*;HB4NKD-c#>f0IgZLDF9+qh zHREMk_W!6wP!v&EaJ58bY!~&;1G;v83VJN^J6{Uz(J|2ztWUPbC|gxpci3)fvFN~& zEz{#-+2vtwCI91L?vM5;{G-BnalV7PsJ+)F0w2FS)78T`@wW-5Q+?Z}yry~1w?pyB z6^4Mup-)VjSn!{IjMHzgk*~Efe{-^Y_cf0ALS1b-lqJS#vO3Gz%d-@?2gq$dmWj1{ zsZmKjt#s)8bLo~=Z%=@j=qjiu-@c6EREdOTn5&vt&oDo9H@U5i+YZFX6 zD0?S13*sW`u#42w#($}!@=7#|85&S34S70PK4_er0Tw0^o!YYR4t%y}=+jvhyYCdd zRJj;C->8@J$|?iSJrOsOvAZ9OCj{1n<8+$n+Q@a~xSACajNHO+1t9n@T=rish9!lM z+{KxHbt+5GGk`o&qb?ilv0PJL)pA;FQ`i>|p^ zDc>7%#644eFI7lGR83?^rl#a@jFx^v`2vT;aQa(W_)=am%b{n4=doGqw9pBdtO8p* zhuC#d#K{Phn!42NU52hOzUK#W@IlQ`#m`(NKlE3_a3ZCcG89#=v!vqLMio?4mdWx{ z#1pgkO0e0ty69lgYv7&DO+I84z|x^InEQN?S@0<;toYzM@Y-d%Kj1LaTB8{?-J}>0 zGh-m?<23hpSXk)|{PG!+BQV_;xLam0zNYYcfQ|3U?>~&eq4Z-4pIpdoCA~+T>8sh) z5(QZgKqr5IZ%$gg5#v*fbyV`nsdSSK+?%(T$NU&(a;RcTJCt*l3cdEG`}Fp&Lpr9E4&FZ8RA2&;UKTyMK!6| z*wL5*VB@l|-UnFy80B_*}MgdJb$OSwI$jcl`6H)y~nlLM{KT?AK~ zud^Fw!iNH`{fyx_0W6hj=B4jq!-0CI_nGJ`)WKg9Ke7Z|>?)&7S$&pret6th)rh{y zAm#E73W+0hD74<7>esB;#VfT|!A?xbmX14r7X`B&F7z<6;zCeO*Z%6_c6I(H%;WBC=VjN&y?^A}-)Jzu z$nT$O3lkU1?`kvKf1BFO_D|Jjw!f;)Z2v@Uj#rWTIeYi*=j@%n_@o321{MMPUuW;| zofX-gC-vn&kdAm>jR;@J*!q;H?dhDP?iUFL&?gRGUVOZ{=zJ;jk3GBBcH^=Ypl%YO zZs&}hxixVn_D}aN&A^{-@;u(KDU-NaDLJeT+eIG{cm^cNY2KmdCbGRFh^MhR zlW0iV^$gY|M&fX1t^riTP!UlHK4laRK$qEUH%Vo0uIYmQZ4wbW$ zei%|MFa482Up?(6+vMF%do}}n2lIhB_XTT|Gm$%jDomH-!0i;>U^od=J4h!EgPxK5 z8Y$NPB;_`z9q-kI+w85C3LQ6riF<@Klh)hdVu9nE@mI!HP6s-Bi65-jo$0R)dMh7X z?}!>s9~zb-`lYS!hVX#PD8-t6{;s|L*5hDjVfuG3m+il;$HDebdmQY4?QyXGlOBhT z!dKa!z1%DG3>qE!(AdUkS!}aP==v}TxFXbX=4(MdNbk(~CQza1G}EUxQ!b{(uEb_v zzfm)&IC*hsDrMgGl79478d%TWSmtHl_e`PSnb`&t8I|O4ns+jIYKEhQ+{wHgS{Niu%uUT437MFfIS3hq%pD!%P3(njtZZ$pO{^V(OOqIcZ7glP&iAW4e77XyHR0M{P@3GibH zAPfKl1^xK}Uf{qF1T+K$I5-3h6ci*h91I*BaHIhi9svaj9swBv78VHu2^kd)9UUDG z5fcjo4GRSg9qmUK02UhD6mk><1R3z72Y~l8ZwQc|h5U9wfPjHRLV-fR`LPIq{v`n9 z(et;!zy5-3|JCm|pZ{%`;BT@1`U{EmSHItUz*v8C{q+|l;je!G_PPDH>;F0af7Sqq zAcP=5p89`C<))ZVt(paJLofPE1W?~10H}W!XxyB&_G~eBjYYa)z94AIZsydf@?Rro zn5%r02f(`E(QL6eNy`@mTvlh(j<6Bs1kv(&A6hhh|C|nj?jp%^bi)Z4;Az5qYB$ zy_BNjPqX)6nn%lL+mu05_`~sVuVwYJ{*pN3BY$UAH~Eb@`D{OaNroO6a*-V?m6df+qdXi34+GC!`PR{hB&@vYX$+& zTw)hu*&l8f{Bs@KU-R|=sa2#^`rCklJe8n30OlhT$_2{Y?kORY5k;A0 zU9l)zQD}%;h}UTyur2-Z0vnCrOEc%u#qfswg%A);lbX03fX@rEx7Rp)%-ON@%NCDv2Hz7lYTch3p2FT_K9yW7*O~oD=jg8#65kbjY|jSB z9m^Ml;eB2!vT>VNM7nf!u`<40zOhgwhe|S8-_zgIm*^W1+jBntbB%-S{cK#b*%FOb z)Wn+P|0aT_ZDp|0fYEOO<${RZh}`p8A9BgAu9v2mV#Z&_h_hwD(k&HGCYZ;cZUfrQ zv`zz-FaLxiX!urbOX@=&%K2!Q9$HsNW0m}^PnC7=Y=@>=@`6;TYkm zedhe7$Zb8k>EaUEM`*{RTzCvTd?n{R=gKyZB+n?%@K&1s_C}75MrStn7Y`$#C(!#f zWav+ooX<&{MxISpuiw9Cu-o;5OC(=__famIt9=5?ZJrBAZdL7K-<1_Jxy*5I>8;Vy z61Ad>^7-v2_$$X|ZX$IBc%XQofNlP5MDyGjN#M@%(S8K)@!Q{M|18JhPZg!4Fm*Hh zarPsL-{wtewazE8EPS_uNbj}~`h z^BPHa$E!6SsQa{wakA;Qf%99&WyVHpU&%D%e%_dV3^Ot|+TJoY8Yn48V`94emF#~0 zZkPTMbzt0f)uSDdu8>x=k|nyOg@;9?Zg8V?-E0)Ntd;w@Pt~|aAq)zLc8STk3rj@p zU$cj{iGa66&4}zLye{>Rxe3D3!p`9trJ9Cz<+s8zpOO!q%7xNOa18N*gj>5({>T3V zA}d#G|9$xx?tXQs<~#)Gcz%nJKXr68HrR4J%&OeLf7B+FQqRE{Io2`O`Q;Izc4kk% z&{f15*cib%bPjPoPq`#3iFJ)d9O4j+$CpzTjoC#=?CU($>6D9SW*PxoBCsv;M-Kmq zL(nER9YZ;b)r%2Eh_1Hdl*^PW+N+(zXRfZUKP6APjq*<{Uwzc{d>})oL8n2TyXE;7 zCBXk)RI(R%7zgd)Y+3>iw=A`A*_P#)cv6M}Dg|cx?1?3M@!sA5B{0*U*^>ORVgXb# z!Z_p>DAtID?voqjK%!u?=&b2I$zkzb;IQe^*8(&KDYBp5_9xW|M2a71z;tUZB5XF!9W=qy=B$JQG&TNoiAs{mPb9BTC zaf{dDl&{$Leu+NoXq|5-lD5zbSO-`mlQa!0O<$kr5k1OPaxxhP_QWN6Ur-Yj z(?Hq9xPip5pVsXAhiU?mVez$cU2t_vA`sr41{97pVkfyJeOU>}<5SvOh8yM`may)e z#1Hd)@=Fd*4uzlR7M|FXo~=_q%d)rE_0MEDN#f*k{h9V(N&l769}0nS+pJ0eVi)79 z|L`@y4Y;oylZ1c-)9h}}+WqS4m0pZrjDF&*V)^=yLA=jD0DkE~*BFNRasvDx^cTN( zKO!?cZ(h9p(yB#p5<97&ccjk33KNX;7KhZ+6~;toeZ?d?A=7<<=HvryMiSL+3rage>Z zZmAxrZby2DW%|dfL4*8FvQ2VAp2#)v3?+DA1BD-N8nbQL&wpEhqf4&G;XPcmeStEM z=R#dlEc;6YWCm2GnG(gi|11IkQ2JueH-;zx#?P|9-0X|?aLFS8CIE_A>3CP-`GA+{ zm+ALrt~p>rE|a7Nh>t|>cXIA9o@Zs2^D!vNHCV|yP&8jI5gu|~qAZGc+xh!VfsMj+ zeeVTou!d;UBYn~L52f+iNxWBYl4w1hAlgTxzPehD)6Ub*z_gCO(G%bs5FHd96nlX< ztmA#YBg3S^qzGEd^8!j<&WFLcDY_GEbrif5u{0qTfd<`TX{-zZ5?~x4q0YIndj{G# zwEPi8VccfE5`W14kj<^*1%akoJ7w_mhGSH2f!@6!6_yQ19F6WU=2bQFHS(!@6vv5t z_%b{aE5u|KqvlFT>GZX;OrEE@hi;SC>ANV_DApJjm@pLX!3Vk}e-sc9Y!Vtt=D(14 zuwrdNgMfSO4ABRJ0)w4ucGz#lB|!aJy4#Wa5ys+64dWE!)YRRPVoDzEFzYn!H1KRB;IJ~&7V^2&nEu@zU zi~~WG`)4z!fIZ-;%jdO)+dlvz!!Ja~Q|v@s2cwu)S7a(K(QkV70(RO8>?-`>>I|IB z`4{*B5B%_&Xj+|`^_mjgkyy30;pX32ld^?Q`-ExEdS|(Rga{P@PKc9Mwq*jy7 zO2m?h=PC_Q0kqa?vfgQ#Zj<9ojz{FzRd2ev1}KIZEtg|byZ_R$RKUP8~J_>KeXp;ZSvQ5(@GplLtMfr_uA>HQSkZh6=nr z_o$0a(>`#<-QAI0$IfGG{Eyi~&~oDAtI`9Bqqt%ySw&KD@2LL@MnO3a+1cSe(g!zc|-24OZexVvTwovdjDmtp61OUMXL}RbEKem*Am4qlj z{Q^-79MJfmE)W^HkL7&-Q|SNm|G%yVz|!3ookF2s8bELE$J~;t?;JI(QfVX?xn@>V zE0<>6oh!qENBzxFAI~#kR`wfTjz;dWJ0m>f-Se%ounSoJO?`k2RO|CC`_JFK5Lv8R z=Qld>GgJXB{j*xNi=Dmw20SioyBdf7sbX-xZmvn}B#(C6bA#ZA?o zyW?+ig?Go*JMg^YA?JRTxg;=Ic*u{;@JNx+-#KBzng!1B-?*S?X)ic=w-@y24YW(S z{{WP|m)4n6>A&K^V|dRO@;6!j>Sbu=1$q8IhW;NKU~$F0nm=iCbk0Z3KiY)n;x%DX zW5{Q)VPkGZO|EA)yPLIl^Abj47AiDq+`BY?^TtN~A{CAA-n{gpX+D;FbVr6mZ^hV< zLGSaxPCD+Wxles%^ zolIMvp9+J$R*N|05mWQ6n)3GJGyPHQ4ClAb;^V3>JUYisl{oBsf+Fx5M>^=V1R4i3%M!)oAL_gQ_#WgvN^h_zl68WsQSvdY6qcw zI(9gJoA}Xh{(rIe)=_;d+qx)Dg1fs1cbDMq?ryh!QI^*g1dy^?iyTz15#ALIjtW${8;2Xh4F#c zq2pqJCkgS$oz-#ma~T)Dal+z0A6UcDxO~-7+S)^n4+sc?X_D`r6^CZ*+K=5cmnz%z zsXpMEj@)2{ulR+z37-Q)ON>S2z_sls2-`w~X0yC@`aEM=#JpMI#bp^G&AXT%HOr?I zDOnR&&EY>d4(#-=L*InA9r7e5!B3gAIPS@)$s``-^d7e%GA`N-iJA<$#}|^xb<1{U zKGYGne>e#5sMxl~#YlsuM4hhRFSA#g?OVTU6&D+wCWP_=zVrW5X0E|DXyQeclS$i2)lT$}SL)U#E=d zJ3d>d3s-FaKes5(<6>0X4e&tK@&!fwOt1PWUxbd&*`+vVXaEvHClSy(!j*{Cr{CZjW#TPLR zSP2_PZ+9qpv9DY=t#xl0a!W{Fzpdt-2YiUlEJ|Oe6HVFJ;W8PIxn5VToHvxYR`0|mQ14W`*?ORb=5%;GPXz%z2yt!BB{cXNB~ z6nWpienS)!*)4qCl>5oy>^XIriwy(4kWXDQ#Dj*|txXW25X z?`Z086A?(e{J8EsUF#myH0~@D;mzj}U%sR4vb`KEwb^lt@2p(l z#c-nI;MCA@{Be|E>cqW>e8KTsR1w00tGxGi?P^|%l>;h1bo7r-GhFv+rnV&N&N>HM z-wOAml~L{Fpb+*m#>M(ZxK1>9nBv8F3HPP*4TceSm(y9u*Ph=VRD9KnE`dW zT6(u)aJ^`WXJcMFlOv?Qc-+;yVhTmR4mT ze0@2ghJA*BNZeBXpPdWNLN*521_(`ijXMW}b3Y|m(LTX>w1&)Ji@~8NJ zHvhkG0RiB(0B$4@FfcGs2oT`y0tiqDP)HC6NN^}nFc4^D6f{(H3?d{_GDdcew+8Qt znONBr$SIhsFFEa`KK)zzkDnmIrd25=PCqcQ*_#KL zo>5!kTti#+x?A3_3>#3}CNbLT2u$e=^NOr87_2mVyYESE6&yG~?e?OenziW0qInaA z^XG$$u?OV88g{ItpSFsH4oNB)!%c!5O9U%?k?ei~zhS4sf~#ncSg5~K^bTNYWct!L z(A;_CObemBATjMg$wkF$poaOy?HBzKmmB9C(&b3zOJ4VVkin zL^|Iqf1r)dm)fJitYB_oa$}AfNQYu(hHUm;BW|L}g7|1pY7biQd0^_G(u+MklOY-e z3{$37yn}4|tXd$^2!yfJO)U@pQzESfw~wszgxxYxNPnoZuTIxS%W)!DUutl3t(oCZ zknWSw%rAy@)6c?hLiuxB)!+OCA!fL@F&j!s!dksW0492iidMW5Ij+0r*^}}LUW424 zg&iEFwKuo!zg;+JWu$LcWy-U-I*;%*V$d*fSuyHT5lq}EE_rIZ`LHqGkciEuI&(<$Ml;_yy4xP zD1Z(o%+z4JZfJ$R?t737%tHQhL(`vMS8S5l^c}AikOObfWd&Q&?DtG=}&fF#yr)-3%5qRevSEyc$ zN*S*9YsBO427x!uWnmuXX)PJJrfZkC3?B z1s7+-?%d9<+hzBfrUZ9O(Bch4e?68>@^fAH- zJ%k_mqjc_YLMwOIgfFrbw$Ajb_g9jJ&pv*v80hq(4$!NHmG8#6zl6K(L~vp`y)rH; z%)m=d6!`o{y%X5uBY%Mt=|^dl=#h?V0UI+k#5?_s2S`2W>fAh`{Gw}D0->;Q7{9DJ zA~zUnT51??4c{HAZ`CCf^ZKK^e0&ASI`j9hsC$KOsAFR5t5rALz;IaKj1bg-e6@dq zZ$OxX^yDj$*PTDJ*Y+*H2$-tm zHlN#z8hJ{`$6ds(FCpt0a`{3bDsiX%03iz|#4(A85E(z<4R)h5v##+v%E2AGGqa7h zMt}^CHlWGs$Q&W`D1`OgTeL-t|8K2CpF3qK?;_NwV>HwGJtRcZJOK-F?`ixn{w@vE z&%*hva5vRkBQq`#-@#gatjrRxDafJ;Rp*8?+ zh7*6Na|6#D`zbT`Sopt-ChE}Q`_WIUiq2|pD!~E)*QD2clr@l*jI7)`l zljqtEtCSOjhHQsEM5tORQ}j;|A}49Ap)T*9r!jNvXMgOoFP}SVwGn3+gQIOP+;Pac zOP=`;B__5FZ=$S1vOQ&nbUjCbH6~PpFnpd{Pi8>#6hXMgyPuBLg~qf_45+WbpF4}y zYmAhO^{d*}`a|V%ygJT20GPo0(RM$EyoJ~IN3*~-`DGg?kSB{HAHgrsdFoK(%OD-` zUWBk(=$m;YoulK%=PESN?Ggtw;#t>*0fd4t$-$~y^H|(T>_+(N;W`F~I*TDrdUW>w ze~1+P7D>W}31$z?iAL&waN%0$N-7xOBtcwj86SXXr)TO$;;l-A1tqT&(GL6JlgeGh zt^`t<$TxBs)5N6xZ8xbIVkvmF|Ko&=uXGv{LRmjOGdh9|sxSd@_*u(%55(#V!e;;h zd8VZf>F~4GHnh^-m~iQZRYah08t>^5Hxmk3C9U%3@^5_-am_Vymvwo_BvNaGtW1ws zogHfJ5NqJT8%XU zQDf}6SGnP`jRT(n*)+S#@)N{WSid4jes9Gy&R2o5pNw_nZ3vPY;>c~A3RMV!lpI(7F4%jYpC{uX=C^Wc=LO7#x=;Lc z5}Nwem=V92rJmY@B^NXTQUdo(?qpErIZLCz(3ED^+ zI$Od4$go&Sj`E^T4BRKnRCKQ*!l-jl+U-$%tgUXJ(;6yVHQ_zKtL_U!YYDe zx<>Z}4DSCUy_?q;;we#H#a`X~RNtAt&LS>Q_7j+K-RC^~ZU(cwZ@Pi;Taiykrrzjo zPB`ByvXtxBnyej{c*X)P+l_{H>s?aR;mb1w8^kL#hp`tSW2Y_7P|ypnJxCK<^-NVO z?+&3=m>PRQe}cf?d@TqOwD`s}RQ!dbYzdz|>VjCyPQ8}f27gPaeyz#`0PO=n^@esU zlTuWzI=Fpj;cTjb%i@D|)m9aK-kMY0;S^kM9T9hPMT*8!i{)Pm2lXzYuczJHBfo2$ zeMI5yV_5!0mjIxv7GsK@^17iRB5#~MI?4s;tw@Dhtt_%f&cU*IpC#1NW{;!N#9d=5 zILa3PqQq}iaO7v19Qg3HAe2ku8%(nI*dp z?J+IihG39fp}+4wep`c?Jt~H1BpT8V34A7wLM!@>dD4FwT(o=|5gTuS$8+o-Y`DLR zfM?;1iN`AYQ$q{TU=SAkV^9zQv`q6L zYry*S{OPgyLIK;@7Tw1ZHR#!+L5OxsfJTIBFZ4^jU*#Y5FWe*mZe>A;Mvx)xP=F<* zKe#Obq4bM0>uVL|b-?76>FKACv9)n}i~CCo){zM)H(&Xu0!^)R9pt-?-mpWR?R%PK zErJa#Dl%AqKcQk58wvF=&$4`5)2ODP7CPMMcC>r*+Kj}*dy72N?G%#-?fNcN!&svc z{A4PgFe#WG16$!;$0V0p(v9V%1je7*g0<`_(#yOLQh?=Lzj`^*rVAteTzHDE)yHG$ zE8qMD+|G>aRBsblQd5!ky07)wi@4O}Cz+lFFe8hC2-ZlYPyjq?hv_v58G6&A?u#c>uZ=vu1aET36H^u*vgcQyWj`urpad zywANY!q5=~y12mwD|Y~op2@d7@Yv0PbzV^~=`R&*9xjb1ODzC2-AOlakR*CjyjMTD zU{soRD)lS2@5Mhju$0dYvo9TH&r4`kx`V(%?~p}UFvG7YP`sL>8kv@d7r=!y zaH%HFd;5nK0Ov#295j&8Fdl@tOi$`CMHl!zy5{vMJ~hI0of!y=`Eto0fq(Xe$8y{i zC`Y)2P%)g2Gho7F^<)bpsh{qZAAsrFZui#p>%}cCJ_Y|v9v#hbX9<`cUV-}HiNbxY z)1l9uCq&U01sBo`8ZeKLo&>nj^}^Ri^(RO%+SPMBo1K1Zw+8-S-u_ox{Kb-*>hSdd zul>{IWfwE@qp8o#Z5_j$ctDF zk(4?Yf3n%|P1SzL0L?|uue9LAfH-viFL9T*dPtXDFR4|xt0060D~=PnNx(r<-}Hr> z0rsnJr#^hdyFMzUd97gQ!HJ*>QE_{)J+DXwv!_dF$S7qyD6*_ZL55yv9Q+FnBtaZ_ zs0>L>Vs4uY)<-=JC?Rg1Y(xn+1N0Z%&wt>y_?-tk1GrJ&V5eAXg4@K-#3ai<7-{@S zzu9Xuw*DK($yHES;ZYF4YX`_pgk!*K@(Ij*<0r5EM9>%j0ep%;1Mhj;$p?%? zcvsy{hcro>Rxe?sk-~k85RMSrMe;-K-oy6Vl) zDr$uD1Mb14HdA4!+28Q-G!j#+o%x)c^sOT&IS1|jFQ9%A7z7Alk*9u`{n@l1aY!SM=iF-&or}#(qbItUIMoiSTatw?6%*-`8#Z z5MF3Z_^{(^L?f3&kERRqq`P*{YsCuAf3o%GcDvYkp!~hVioifWQ~C-CLH^HHLrOLI;FT90j4;Rol&7!~7G_FF+7iiFSl$L-vQD|JM+IaC>*9_}uhd zgox=cP2!XWYhNX!u25?e7^z?!i$!>3=Q6pinT>sGhxt!id|?7MV<75%%JXU}R{y8U z-@?Czeu8-FPJTLMZ0D&B8knChD@-IeH$mVD* zc|SZqKO7N|W^%carS?ZsM(GSw)EG-{C-L6ooZZ-U)NFBWC&fvYYfQQBj>TDFux4^O ze0@jo6U6zy)w;FoXm#K@s^o~*WdpQ;L{|?8*B)?V@!X<-pO;nyFCc$d)9>`Wjz<29 z_c`ttHF}f3Q3H;06NNTZP7;~LvoM?2abW|Ihk*&%-C?|(6`^> z7*I2zc#CADhVHH$bp)9>o|Ugs`whw9rp(M_Zp1}?i&wMfOY993CP2P0K$q6aH(bx6rh16a+3#wcS5`N+M8%QiLmAz*;MeIQbnJuhG z0y}?fEaf;V^uKfI_KROF&o?@ip_o(i=N;F6{(8&k<->4rwEM|I0lQLKcon1Y>b6J4 zPNzbz!g?n83LN8```oU-9ww+ zfkoAi@j=PT=(BoBO*YM`WmZWAobr)a@>54~^y-7tUGzEU5vSY}j8-gm=x7wLZkucA8JIN^rU%|9S#zT-E!LuwYf<0Q2t{X1?=X&~ zX#r&|tfIL{rUy?&gO}>Tm+HSrl`@Gg=sr`euj@(=tiOt|)Bd>H*i<4DCDjnwW@E>k zf|p>0+nBn}Opy|zziLQuou=%(v{t~(MLoxU((rl2YhbsL zfu})8s+Q$Cz1_i>&meH~KuN&tga_KcWWPlz*o~)KL_p#Q{9NW7 zaJ!5FK3rKo{U7veAY9{-#6!&qm>uzu`gt;`Pro&x+=ZIH+*J19m>w#nN_bq!p6yriYrt^sRC+(C$ccCbA!xhXLXBX-6G0 zv7ts<(Z5zZ7zP?BpxecSJluIPl=n$!s8JjYyP1<{_SA65Nsn@&jH8FPe$dmDOtheE zen7rGf6&(qiK#A^osPR47pV(0vQ1A){6L;Ajq6y~Qr%Nc1=BPn;`zvbJE!DAg$o-9 z(N-7B3NR}oqv3+kwr#|o5MoV9wrjXfjvRsM+2lg3_|QueUY<&eAu}ehc0VQ(_!lG% zs^c%eHh&X`0{jxx453)Qae2P_N}vt{cf^~Bzhf93u<<#I^@J%T6El7QKPY3(vb+oHAA2c{vj_oT+YX8*fx%@a?KS1KD-^sggJ;2j$m`WeR&lC$L zl4rd{Z%aN{D7@U%p716u!52*uGFJV8xt1sWr_f$Ri1U;PhQtCQeW!sy>`c@@s~1mw zld-%x@qXxjjLLVy(0v`LzN7CRNgps!cFE8#p2|$TEJ<_2xqwK~S#$nOw+e5N(WHBC zn{$mL`#Q|*zMy59aFl&nwB3EwGnLCxGb`}pp-O8EC*gS~LJ^P&+{AU*V6mU6S>)f< zJQXBi2^V}MT@d_tro{e%dRZc8)!1=1^#-o16JiOZ;#IY zeSK~oOtN23NO#^r_GCg~2af02k#L6}L7E`i84Y+VGCZD1prr~dLZ%wH=WtTrTT4r@ zBDNP?K<`t8chS}f1mb%(1I09PRTTE*L2J)O;JwlrX)4xG8V!KQ@vGv$c>J?_IGn?; zou()8s-p|Cw_Kd;SE0fpsEzES7G6$}g`l_GJk|2AJ&b@fr?Q)u{3Jw$G`9`nJgJcw zNJkD)r}P$rfMfy?8SuK54-(B+GO_@^&jV@^!j4gU^cH{zQ#8K-fPAJhhmV4XQJdq# zor$|R1$p#^hY>o+zkvl5y$u0N;D1^A8($x<(SeE%(94V)i@xLo?FqR` zFCz_!i#osFWUv;>!AD=93}~-`3vhHX$VB-iqATPsopyOONZJN*6GkVeZQ44c?AhDZ|6b}lYH*`1eM^L0dq);Y zZEBa5&e+ut*ll^7d7j@Kjy-4V^B9QTy@BNEzY+OInvuL#I>#>Z1=UuZD^(5KJoy0?zY$K`^sD=Fs!agm%}r@w|fhfU*6=pB4_d-BC);1Ts&R|GiLe{zK|uxPt>$;=kS`tO}d87QGoIDDLn zUv4_p%NVcMS~*f3BRt{`{s&8cI3Yy%*68!0!;d49Oh5akyBKeer2QkJnJ+>fI#dpU zV!J=+%K~8}idQ;`XW!>YqT?p*a95(eA<6sj7_8b8NaiSK&9dBJz>Sb(yU(a|V_IsP zc)D#NUWt7jBrtu^ay+WCN*_Bu0gM_6?3HZ{cFdj7r!?2SMm69mH1mT6rxAXOEw8w6W}@Hm}F7XiG&K1*&n99*ZIOvg8y;9k#${@=?~3MaR&&^oYufwM9(V|A^FQ&RvC@!8b9h& zkG_UhCEe~T){3zz#yNbnXPv`ECNfH4;o7TdC4*DiGv}S-5b+Ju8QV`C_!h$?o!r1x zyQ)?3RlfG=Yhhfd5-~sj!B*dSM5Q}lcrmkl^&zvIT@*!XuMruXGR5DNtNFv@tlm#< zvYj$~a)Qxp!k3f0KPz4&#d))kRrwRd;u^a~Utas_4IO3bz;O(dOiKE9ja3w=Hx4YB zR=9bB_cR{I`KK`H3D@hJyc(Iv3G(7KqMiNGC+^?kWe9{0M6O{pZ}G(>?=M>1sux8L zHn1pVd0C$xq;=IQb7qF*yY>_5bDfCFhatDgHs580-Jd;NN;oDZ2l3i|6;NKnE}DAD zK9mj2vZP+J4_V(-PpX%ch#h#)nLCEf1n)89Rz>L^Yev6bL&hx|nKS*-2%arA)2pbS zMZVxA!z%3h!vENM^h3EAsu+=&;Q(qW9+@e)Pb^or2i@$ z97u&MUaSGB&_7r^WX-ifV571YB;a^7@t3TLa2{L^VePB!&RepK%QH~uDFcj8Y|((>+Fa~Lm1FHR^+ec zpk3@{eq7f+oX}$vVq!7DAV2Pyemoxo`_+LUi>a^n=Rh`aSp>0hdho!_@8N_C$=vku zZ!+^W{g5^YSp@O!fpRkqQc?+FAD}Y}o;w2GPVVbHM$s7!-ofk}WFVB4?<80QOJ1@i zYr_VJ5cGo6=5slo>VKnmem!y6F(Jv`mf`2fT~!w+TXj$KYquUnw(^(e@lL$ePY`r& zVem0{Z7j1<;HA4C6ziR{VubpU#R`boliqI+;1C)4EDV=<02x6oEa&yf7imObZ+xQb zJCa%ue$!n|RFV7)ghZ|c#}6Z%jR~%wAZLc4HHs_rm9SbQ7y|6FI@Zd;C^}QUd^@Wf zrDJ_gqjQ>xTnQPz?$+fWP($__N(p6csGC5QC-4tP#%n~nsnYd#h1EmTtxp*>O@NBJXV%s+!|sCZlP)A98Yr`aI;4#60LVK_ac& z2OlhZcL0AT%y+D&z|aFU^Fs=IuQC-_KfYFMw9Z2)Zn&mQz9w~}YK?!vhJ;yJ(=+b2 zYJ^bDn|H97^=A)Jjt@F0G$O)9B6f#p>w#fXWv?5F=ao7G*N*%dbmcML(A@t7x$ua< zb~Okvqg1`_c8+7~@)R!!#TXBo)^Lwi`w3Ei*Je2lRT{Vo<^3t`C&-k|V_qLoNyUQ$ zutw$h6Gf9ZgQk@~y{^bS64;Q$=po;-tfRoApn>Z5{A)7he2h^!;!%I0kn=!gBP~+* zO^R7v^?buG3iTF!`IJzbQYemAdeY2sYUIg02%%5=ND| zJxsC)>|i2MJw#B-#<8$y(V6tz^@>t(fl((KbauEzidj6_v2|*<$!{mQ@@CB=Rjy^j zE0ZIq7s^!+G%j{+W<#AqA;$LIv|Nn!qp$jXp-#wVVZ|b(gx=et?9{!XRH@rq zO2Ipd2rDbTD(Q2gc0c^cd9WizD2MRQbT8tI7!D~uX-PLsxij_d{0dV!SCy2ri_n*0 z2l7;Dn@HM|9cB!khMyo57-Zt`S5$6MSdIh?z=xzXJlyq{L9WMQ{ln~i^Rg=eQtZ>F z<^w^^J5$wiyin3NLh3Apd9fFYV8ST0T_Pw8Ihw$mIp=Yhc zwN>~Wnhp)Kh5L&7K+hjateJu_@8v{z(PX;6-jV7eO|J85=fL2E?^9Yz5X^1zX`Rf- z&~g*vbS52kkcPXr177E$sIe@VC5zWz-!g3HKR=b|w!RbL7fa6!e~?BdOL-;S zZ7(P1kBaR-Hlw(}^o}|?WdXBrWRRFM0>htqS|#lpx#8B5E+vgL;clarLP+z-8EI0nB@%iZh+6Dz?aJ6uImV_ZWs z(fr;li=58 z^|;JCVAXT1J=)Xh;&9eP5RleNUBxE{dyF@vH26+A+L~it?QXcd(4uA5hs&}9a5o5- z9diXaw5wogqRx<~%_CzqBBR_)Dl48q6`O^xA2(WVthyVhQmbJ&h?7x`A{B%+k1YwJ@D$g|v{Hd38Tsge39k zyEnD+YEj=3HOCG9=&#}%xJ=QXFo|nPpn6bgT|{cXKH14Pbd$6zqr123fq2rW-d(_x zlsvLoOG#^lxxrm#JofJo&Z2kJ5DrIE(4I^;5%#|lh;)-lGc5T8Y7|wTM9}Q?BZwgI z<1dva^AL7M)XQho@W|ugZ_y** zslRl1ztJX%v%#M?*|`J%IGi7daqQak#2t0U|Hf(1Hogf)5oBQ@Md#viv=NIaa7eLv}{P38!fE>?a6@keI&W>5^5>r8l!}=l9c}AotD|+k=-zBzNa@iv=>U$i8M_ zUKO(P#z-0O=E?3QHQmiTF$L2bt}YW3gvE8dJY{ zI0Q}&mhVc=yau)K-BOz8Ah-QOZNQ)4xXM=p966VlBgfBQTyY)pEaS#xZkw_26XfL7 zSj;rI`1~MjAmuD?#bC4-f|QB7suH$7wi5i1k5;15kv+9{CameHsDD{5nN5ZM8_Q$< z`g6S9E&(wlu;5ds)Ox1N0bAP-_fZ|}4~G=ZK7TdJqri`lth-Ljo$x~F!zju}?Dn1jGbC^1zY{URIT80{dcRsP8n598Yq=t9g|&F?nv5{d7ON;m()HRc`j8f5%6SE;QLUa@ieo3+vBNFRVz{biO zA-PDaVKXJU67&8BX0CZ`ball8<&Z;_>zO7h^j>3B1vU$EnTz==5N*> zCku$wL40Z5W0ZH1jAZTB?I(a$| zE@Z{F2@K1=BO0xvd7osVhEq=g=_zxCX`C{0s|QA^5g%SbN_ZNxX8MthEXz)ng2aIA zMBN9yVe>DIUBS*D`oO1QcZSX4mW`!(+z>?uFn83nKF+CDfpIxGRyl)|clC%e>!_@% z=L^JwT=o2TUxD(Fn7VVK-cl)HD%TZIh?AV)4}MZo_%TVx^~gZ5O_EJ$G7lvt9XF6l zatMdCGU6 zOIM)O`E|`!6u0h>ymx}iBf<3--^ZxOM9QO(`~<-+BSl-jiIRqeBAofhkf$NFCjE8T zTMwJ(6-PhHX5b^2;0M+k5>C4u;j#C<*%#iz^~fhcU{vq-DnvrCvDieK1C%n-)Yl`U zsD>Ux)mgMM|2~K!Nd!f((W$v`B{>t4GZz!NSLg}_9HXy!Dzb@6?`>b730x{%w&hTS z;pH8?T4gb^pYpVzOmZN0C)b%#n>^g$`*OcY*k8X)B1CoC zLj`g&f`w#k2tq_-ln5zqC(jh|TN=1cq9?%H^a|1m0%v19Z^@~vF)&wDKvBoCTzz(Z zjA?(xeF{C#lSMZgS?Q0V#cJYPYrH&pOtGa^ly=^1vu&>P6iZ$W3hzp5XeAMp{GROm zvs;gtz7pF!&el-&qL$E(aJnxr#^oxv&EQlsQK#AV*r^<1T-wn2Q8K7$1`pfZ2aq|4 z&M0n2RTwH+kL7$I9`_!YBh&bZO@+_fYXWgRqe6+bf>sA>Zj|UiYeb$2t8_nK+OBkK zPoLw9tvVZ84jZ7ZO6=rBec~g9Ln+}X^BUxJ-{E!Q-4k3y;VLW#dE4)^1L(9(Q5ZF! zzQ)$S8!XQI=xQdvO0lWAgB~cbr8+KT)vsMugCG2w!eDDG(VTl(S>^|gX+#svjtx%D z9j%w!Gw-^r$@Dja>lq{iErz8&hU8Z{oWqb$zGb9u=YN6}S<)B{I-k@yw3=+NPSRF0 zIMl;KksYMMgFae3x$DtclZHq)7eYiQM}9-Lm!bDf0S8@X^JS!>2WL@jXctSzOCH6y z5=@JbWP%1syxK>S7WAi!7mN=#Y8{u z6PVBWekv3>ckxXeGmzjKvXWp*?vi5hQH3I}Qdd>Qn83`18^S^`B*^v?HG9Vy$r7l!bo@*g1teJ2rHOkQzqDC+Fm2`(b7mK&42)G z%w*nPi%pOWcTYN3qmZdM8$`F8lck?NzOO&zP^3T7c{xN!93H$Y6fQi>&=Kom4D~3$ z8&kK2q9ExNBcz>NU))j{DENvpnlhA8DZ%19tdYIWV-MtnsMd*!@|`va=J}%lU43(Ha+j3FJT5z6K>8U(eH6N_i|4Q+|0n!#y6%`}WcYlQ6{2^bF4y=XvC=WjXyz<{)z}S<{`C~VA1$Q1s~su=o3J; zv6lGEsZKjyi$AGe(jI1hB^;N(yKisG1PYk+IBo7zl5L^m&LGk=$)C=d`0Lsa5KxcP~&d&Vaxs777; zJI-D?oKyjSk8SOm)SZ7DR*$JVQ$2In8}=fK54LCQ zu11||`8yD!t+efX#lbbZmNA}Wv`XbYmlX^20IT-lkh@~pOC^UgP2GkE-CIU26G|Q; zFhc4)X{Bbiy%r|hJ%!JE^>poRRd(ceLT2T29}P^t62tMGG6M+I!)p^}H`-fvDn>h8 z4v0pB!|JA2>l&ns^?PX0BTK1vmc5dIFkAv>rS`zXxW)oEavW2dpe}(@febPiI$;hr znQ>nxAYAJNg35@b;k>t|K!6LTCjALq0tU+py}-S$Vth%=(O!Ilsbbs0H1kJcO{D!Z zR;~DjC3|)DRH2Yxx|$S_`&_j292n1i$UlVesegOf+U)=Z5uIZkuq4VlNW%!yv}qJq z+G7*qG*h+d#Wa}Xs+omBy^HJR0o+qb`gk@a2plIf{JJJd74KQ^ZQZ~&@>kufMnOZ8 ztJTGFOfAJ4QTN=-@W(n#pgqm{npq#vb6uO+8jKU^-$H~KHj zet3Pc_==S1yx&u=g}GqnaFWV3vxUm2TxdZ>0wh-JU61C}z!bBYUJhF<(L2WJ%~U*V zh*121w=hMbt)xKMgleLcy0nyPKCDZY5e`?7b~uqhPz@|w41D4%LiedoS%;Q}+@AK3 ztOuiXIb74AqX&ik-C9Yx4TyhnwcqOm1{|-vlfYS37Es3S{8G=IEZ78U84L56< zqvgxtCMyk2#UDFfUx;$@v4gwLq5T;_I|?mIv$6H`)H=Mvp=5_~UM_pN(KJ{3^#EUd z8Md_4Oe|`u&^+X_vWwAMqPIeg9I*(hvQVYi!isG+>u(_@Gl_xaNSI~}MMXghfA_pe zWL&*GCRAhjhyIsl`gNEx^lH~RS84a#>vBi02MgR!thgsBa$FIPXKVwW&{9K3pIqH3 z7&}R7r}t_rT#<)kQNiU1s+8RW|E2f1&{>*0zIG~cE{#?@QT#{B{-s|kXpvTX61)P$ z5TC7+`C_Muuqg!2#Z&^wX1<9^Rz1J^T~?6#YIr&-M&uSr5NqQ3!HK&W+x-qb_#r~* zhff%4M2!9_1)_=L5R_!}Pmr!6UIk2xurMa8NLC2oPjQ6jWj+ zMKlspWM&`pjmRJ3}fhs24qEPH zOk(0!FP~(1$UXGta8rd1t;X^UXR~vm&(Q0|(8SPyj-)*`?+enTx*6*lvY+(+{hjjuyXG31$;vyp+uN_=0 zoH*U5OVHGME93?<hu{X$Pojc zx=2)d7w`BYaS^N@3e{k6V`SckUgQ@=26na(5UGy%5IEh7c(;q-cb8Y>6Y~b5WptmH zR}c~N1|NFFKxa6qBzQz3wVCoBk#d3Tq^<-!9GQ|mL~0<(GvpKNE)9(3XJ*^0 zWLqvu=VR6uOWthT&8Bx< zcasx9*Dq{Bs;nM(5X!Vm?dIlg+O`%O(WjI#mN}a#L=MT`bs74^7Q;ISNaY}0x`@p+%tErkPbK}kFRZ>7Cc2hz zJn!HEUYNzO98y&8-@n^&-Y`{#YKX96`8Zs_H?2;xwWxaEK}=*IbZ8#>#VpnVL~)`MD|^2%LHfpxCyl=8p~crh%}RNeQb3w@A(>xtuno`F!Y zs_LYmT+RB~NK0PG9$QINI64UO%|QB$B56+$B^zZf#-)x!aZPn~0rzwY03mCLgrv$? zI8Ing6O|u$T7)?9sLjK}7&|u>yH=PxFy`Y7P6vrdn9r%S{6@xhw!wily(NK*Pv~oq zl$h6b)4k}B^CNf1y%I)x9O&k*+*TdvH!C>>QPJqYz&CU0<7Lq>rqo-g#!o{gZq-{{ zIMjv#jd@#;?}7%3mY$4dZ+b&_EMCr}k$T{s*us5bSh68q@tvy63 z)#t=6$0xho@hivXN)rVoqip0}y8;FXc;V~f&$yt|jdlgvh(+8gbfU`TCtO-+3l`L+lK}gu=+8H=D?z6oUE>Lk;CGH%|cCD?)j_7Pd$@xC0 zL-7PM;|ND*ox>bGN8-&l^BHTyyTaRh?kun`B?(aw`VUbyFpiC%O83@S6H_Im#HpPg z2^;$*YA1IU({3U=qOrJ~zpiE9z%Lt_el8$%&TTp&)g@s3a1y&!3S6_(X8#}B&N{BD zZR`6g3epWy(p}Oi64JdlouYu!-KEH;8#dkDAg}?EP+CfaO?P)ni=KCFJf3szx#!+{ z?(;nFf36v0{KlB;gL94Vnrj*yN^>JdQpHN+6*vay3LaOfN$JQ-L zsnDSjp@hm>A<#Pa{5Meis)Fj&x}q2It^x=1)!`F${-?p%y%+@jJ_o|;+iueu-d|ragqNEgOMeZ54zC~rxR>LTc;u3y1K&rB?kv!i`$#LK%`3oE?C78*s#@_;dddElH97nI^d?Pm3? zw~=>st$pTUYEU}8#X`2jF*@)ED*yTq)ce}kma+LR$eHd3WxUi9pVBbnn$5MVN0umWMom!8Kx&-b>@FW4mOrOsF`B+}uBKuex$yms=!>Qmh~f(IqJ&VR$m`3F z!<;X%gq+dFklSk;d)V9fU11eH8Z8pO1P!|ldTL~P2|I}@IZ+!|kJR1pn`az^6khZ# zWg<7-%u1W3`0(wi`&dmZAuBMQ6JOz-CL?<*NFUX?7I=xCRKMClIN*C!`v$4&B`1H` zD_vY0~q+#9Hoxl>uSO`{8c%9Xw*-P z%h+X*i}1voBlwG1dx;!F6-M6gAJi4I^rh=c(syN4pvUZ?AAG6XAh4VAM@dVFDw>W#WWa6euU04bh zkJR*E)H=_6DR^3+qEUE%{v+REB#TSc8E%b%bxG*h?TpAv@_v{;`-r41>-6GkQ+5l# zrnD83s;m!|x!!KVX0`y~?!nQV+B_Lc4(wH7Zc7jkyKA5GP-^JuxrZH-T?ABJ@BPT< zd8y=tcV>+*lsmn=MeE}Qx_XPspU7|QXZQCRR?qSp#-r}oI7la;{>atsilZCN#V~m- zHJBLzG!n&cJdca9E)v%sVo!)nemgL4%RfICO5+O%UF9>a@AeEGyqyt24Jay4*vyF+ z)QfG`t-I{XTKtmAoEG%zibbSaWm3EyzlysXt@fOrj=vmcppWmZ|w^%c~qe$uO=p?3e2S*Y71;Hq&smCph-F>%={7{SM5U)Vym`pLOM8DB5JD zCD~+SqIWnj($@tuW$hXxtR$ZmZSreikN6I8_jXU$Syoq>%3Y!$&Xd(Uj*2K&YMtt4 zH^-zzYahqF#SK5dBR{oNOLyA8VN6~2(0+)PUG=3#dIhVbs`Vh`i1fc3G;P^OeRDB; zS;uoROGelGR^F~>E1pi77{CELxxON8x(a-gve_p1c&UtJ1y)yUi=^qh7+VS&&Bao+ z?j`v~a=;fq)@j`FM#rl0nZAL`rhHOX(Z?w7(7Xy(3T$lC@6qUlq^@j{ zvjKcH=2fG76zru2E|9xNBIZcMm?;4b^0;Z>_k@gABe(Y)eQr(qP|K^;9jlX2&CK)3 zMbXwhp*8;mG1(4$MPhj^aVTz@C)+!)>ZDyf942-XdmO@ycXqDHXg2-TLR$l)=ci)4jh9F2}L9Tmhx z2xPT0s`IZ);kU`;y)$J-H1Yj^Y|0Zrn3ol{8H|2)BHa=*YVxuFx5omr(unWrzqKU9 zK0}(AhDzRQc!@NBxJ5G&iO`6xb8!hJ-$*Z} z)JD!~p%bvB?09g3%XO<)RycB8LV*OO-12-HQ^jMOL?hJVUY{Ntw^P9!Lm*>7guH7H zcva4h)Jh^S(s??a8fh!c2dNNS<@xpVO-CH*w-bkER-(4Rvd$9)@8Y~?$}b*#987gj zxtD>*M?X!i3gr#AC`Tp{4yhOZt%t<}(MD}MHkr~`LZA9((-Zo6tBE0&-g{5j$4 zc1dmNjOCV^YRjLR#)%O#fY(=DnCLvlH7&FoJ`akk&XtwL>&IdmK4zT1eyllm1NqCQ zyJ#Vvk=!*?P*K0a-lCq3tzdhULT?DgU60XLN4;+jSZ_5Qg=b~@Tn{!>K>flus;9Xp zP~LO@64nhIXpkDGV%*o#azvO1dKs?uoVYOk>PZ{q?{k8f!RLbWtC8(8N$-JcbHD!! z_#z&ELo3V7tNl_S&g3$Y+@2eW?}aqwL*H7N)zgWKR1Sb4qI zf}63Nyx~lgMKwB#-ESR-2m>kq@Xb>`e#9r zSMmxeg^2}uMyCW15)+=v+=Y)WI;pQbjxX-@@U*l&tIFDuG_X_Ui8vy>xe;YisdI<1 zD~U1EILiqM94Nvbelen+X|5YvI9{NyesCSB;BS#C{~GDZpDA`6Pr9GP}nIrPEu_=gFssD=6UFf66gd2|o z)=vC+N%mrht`&}j2V5v8@b1wlZeZ#_dE46mLF7vELCoOztz-D?KFoxJTLa4eIff~0;^NV2r{YURv!)AWhQ}xL`NgvjQnc`v1L?%mA2+w1kN^wLr^=};*Sy1I!pYVV zj$2#`NNWAxFUEWbGg#y37#=p)7KnG$FZY2orHR8*HS#RbvPSTVyzrXG-z1I$i##@~D$4 z%N4VCLf2BZikXLG`VH8kl5fxDtqp4w?6E8gaUHUKd313#RrIkearAY)7(?wYl$Q9T z0weSPXEz80P>F7jF0o?)7(t~VB z%;%SOU_c5RLdxLZmVzNE=`~QT{J1mW^m(I|E~#*;O*$@j<4hez-Qtkh6^DCGz1a<;FpQQ4dl+#nw&uomVZ#P_byu z57Dw?x#7w}<_&DPA9?q1e64YKtbo{Jf!Ma*{*PkIL!{YAsq~;gWBJLh7bP0}F3H7J z?1S^go~zBQ6*aO}oneE>r9e7a%lM&vL#_Ur1w%4o5hVdA=ac^Nct^Y@Z3?es4pdy&RwmO zf$CUtP8rc=shOV0M<91lD%xek?@H$m_cqC>`BeHiisgJyje&Mx+SUb6j2vpoz2<@^ z%Jj5)NJ(-oV`huon~!Di+L$_ts%ENDmYKY^wIGJjErb12iT29D)0vYhA`FIftNOKyCpnC^9{wIobCRYiS_rr3FHZ6BdtgHiMNXuDMii!H4GnN!wajSO$i8jmSnAsw`XQ`nz zk_?yogJXx^9TO(_KP5UoT~}LP{HU(a@f=ZW`k9|Uih(+y)(TcpP5@0F5yq?`N>;^zc#~pO>h@HY zJ|$+HWEQLs^0=3ff>mGT6x>s^6r<9TO~qo2$tlpiz9q zh6C1^Rd}lhdPaivvorNf8#@SZ+ioC^F-eQl?p+DL zLIUrqJ5!-xO_tL3U@;DcCYiCvAw=EmIO5glW44j)K>spLdyAJv@sq0pb-C&UIO2jzFheFZ+3dR7ci;M7Tzsp0jKMDa>Gc%l4JPq+ z{L&E2u}F=~C_T&vo4pW^VG|SP(e$}`DDCptYc`Ql3G&ScRq9-j%huabf6kFL+=?p}`pxJE? zkeJvD?)GL4)`Oz4EX*P=f0-C$%6 zim-Lk`v>`+ASbu-)(;r9oF!{g#>51tp1S+8*uZnl@g8_p{`@4X4=b%m%sEL%!R5JI z`KsJ?%ZXa{U>rKCO4;5?Q!ynaKZ(g)3E{dzyMh-+a$AekzKt`((((4N?np4dve@ak zq%G(FEG!k#Aq${xskScf)>QvUCPq2#-rX(DUv8jj8IPDv&#RhD#OX21HEMYK%C{fH zZ!MwD${*!jc>zD2qR_(}_ z1S1)dtej%0X}BqYOuPaIoHcC$_N2 z9 zJJ-Pm{`3e|hJ(Bel9{{hZAXY``ec9T3jgnPiM#Q7wo=yuZ~x?LBO?_S{(iB82^;RoZKmm7hUjou3t6cO*S@fvY)6`+=3paQrFqk zzn=;jc0p@#J_mS7+x!i@sb6lC&TQpBOXtBxld0);$wUWbw0WKn$34egRaf7o;eCd} zG21eVVsA7;z&=s92Y2>T0v6H@Nc7`H`9VidaQXv$qOZ&bc1Nk|!Yb6-gPEinX0}jT zYTnaZJxvZ%M%N4H$X0vt>pkFRJ8#*#6>rHYI~;fT#iW3ID=!kLyrU6cqELKzr(_Vu z{>T-G;PHztEW>y1C9fMeEkcQQz-N{$5A$Wh?N_I1ch%hP>~cxYhWhUQ<-M?RnoP>& zzc)!~neuVAul{sf;wJsI6x4QmYrWm8FeyCv4?vT5oFut7m(H8$t{+PkRpLgKn@%*^#!?ip0)h2-mI zps0P4Y?!q1ZB>hujCyXy1!SjSb__8Ro74Qf#wkX=xicer0n!r0^^2h^Es793sv`^x zU=jw(=K|&0ac1n{MU0T`Wpd?X;iFcWIa`85=Kkg2-r2YCyK$)>*+dB*!UvhDyg#oU zcQ#?t1;valj$LqTwe(w@LEEZ^{3&(;J7v8)-Lm^ERYMRIFQ8<<&Haw+^VeQPEqp!= zGuF<~CBXGQLn^0eYPqgBa_pNAlE2(wQ5c^Dv@~du;z<2N2sl~$w*2xy{oGvmk%wlG zshaDjh*&$NB}b4aYx$CJwZ<9K;>rh2G6=pFCo zbzBf&I*?bFQ;VT}R?C-UYCp>O^@eJaYO@0y??_DKk>@%7UJO9CMW%rmbfJ@xQF8zj zfL&(^!33u35>(=fG`|#v22t_r~>bw)ykCV7q_m{@Fv7Mg9Q&AS-+d z9i`>E7rN4lR{!#xJ1%E+zv#Lp)}{);1?EFK504LXjxsdj766(+QcHxr3DARH50L6h zV+bq0{BCfcr5Sccsp8C^Sf@dSvYo9@n%6{0Je$t9|cOa|E zYjat8wW-*^|BBgRc=5$_sil53g>cC}kZyAQxifa&J|9lHDI>8ot)3**z5nUd#z*IdjTngX~iSdCw z8x!e-3dk!&m-pNn08%VB0IXtjP~K@Bj}B0mykfZ}3ms2Q4^(2BR1K((U|CLX!%0nwolD znL0Do7RGLPjfk#8VX7V-0#FU2YyJbTuKA{6<=9jtWf49V`oxI2WEr`Zy1d$g^mnqn zwKJ`<*Iub+KeP645(;$fFQojMmJ5^X%y)&c&7vUz4C@~R|La)lPj~wj@#Ot5L5}(4 z)|N=_Rx%=uZQH1I@NikYi;g?>Pz3uZTj<%StXngyn6zb5>G84jL{GwYT_gI8kH;l|UCT*GXie>`#50IY}@)v4;axpbSQr9om z*yCYG$zd0=WnuGvKnOe)78_{>^7d>$sLIz?RomgM_O5rpP+Z3$N<;9PpI(>&FTDXf zs_PHJJdnJtJ>XjQrq0^aPQv5X^#qJh{e%Mad&rib4d%*zi1};;u&CAQ8L*(iQ8r2Z zTB9%Qg>>+(Ax_88stc^8dx?Wo>_VVn|MCPCg(Gl|b#Fw8T zyZk9+nW)#aIZXin>N9I7uz$NM$-_M0{LOMG4ChXk(JGxyTfBrOkHw*roM`>;BE0~9G*41?Zg~m4h+lJLMYUv?YYq)k)b`ep+5tKkaJ+RF6 z6Z#yK7M*$n%)u#}m!sK4ROsT(y)5l3BEe6M1z*;#DtcR6vI=qwv+ll4R;<&H)c8aA zIW>U7mg(fNcV-RQBKQ~mG;`wfWcOWu6*CC?A%=FC8i=%EQj;)^5FrxL-bs+(1`pKj zXFrLMXlLYq3~v&i)98?G3q9ViDo8ayf>4=Aqw%!(-#aaydCe{ zIdVQ!{1)*~C;u_xU(^2_pp1z0$86#NYinR#64`|o8G1ZAay^I^hB47YxU4?`=P(M>j-|Wn;f+pT=9qKXp zQuf{s0kV37Ur{I^K$aeMx~ns1^cZ9e^?Kbf9esr_h=u013p0Ymy%2Mm9BPre z9-@wL1oPgk$|K@uUDQoBVbXpeW)Mgz+>d-}eXjM_uK!t`G2qC?SlF8RPDJRrmbs1s zVLx^pb-`O$o~+LcDp2mnZ`4M1*;=dt;Uk)(e>pK# zh5zL=M%pF-%@S~Ul*d}99 zvK8$Cw&)rnGl@$Fm?d5tvPE5w#Hw;3nYc}$3V`o06z`H0OjDyksqankCcRi!emi_i zL|}3jonVTfSMkO~X>VL=^YRfibdi>K)CE9_e>X}}C0?h3na!INsXKd+P#ZKe`j^(4 ztMUVLhZks__Ax1rz!4&iDTi9*2~)u7P=|eF?LVc=(-trTU9|C;wNI6a7n6UXA9NiF(0ooG;$+f6I|v1mx9s~(4VuB z@YmV+3!eecfaSf;HkG|xeeZv{RyKlDNY(&Do!NM*BR;@Cc~`XfE@D}7fn|{s2i|Mh z9UaSx=})O9M^HiFpX-LQc&(EHrR5SxgN>2&zRRACa2(OC9tYMlvTqOJS+Dw2wgjP> zjdt34{=hq#SMMnMHgY|Ey9m*FZL=&0 zuhpUTgN>U9qs*VHNQ{$ z5#cX4Y-c~@2|n!xh|nz(ko{pO9gF zGyTH~TSxG#BoPF9yCt7gpIA_^pK5ttq0ldv-K?xaELy^IK$jfmF#urDsXzLN{7y+X z-~cencWYC?mxkDA^h0)0r`l4zmI>KA(mL)8gZoxQUiavR;37S6gAB;{-j3t4<5X6j z=N~;ZfFdGDN#pR)c)lRdL-ZxZQhFcetxa!Er#4qmh+wZ*V)7}=2+BGD;|uK2d0dY_ zg%5-9pLMb5hX@6u=M^UQx}ikZ;L#vI*+)jTw zQ<7_6NiKEqAP8HlDo7{~jdS|e*pr+04tSoj!uH@!SmeBEMk<5T^5L$PSc!W|7=3<; zx(C4U<^qY<2ZqQ#6=m?@NvW{>XoEkf7qfji=kxfmXjo4-p-?*x;EDP6jdsU_CRnbR z*+MWdz^^a`i>24O&45>wA#cApBYy#&W*VOCVDnz?2DT8ZhBC zrP4V#s8ErvCbd+0<)eOHn6B)~+W?^n{(!YnReW_*-lcrvw2x4)ssErTR?h(h-%jSP z^io$yXNw)QEhmnnw~b{tqfA)CS${Hx51>(H=^sKEH1{p<>1PUv+ll44!{x6P11QZ) zt!?I_5y=C1dd`uz=u`w(nD#dBO0zguD+)E%8Yw{=f6e&@T4P6A!q~xg#M0C$iip7-PR}9veRi|2Aa< z=<@p^!MKE2tsxm%PE#xlC<RG^##Cr$4u;h&cd_B9Y|u=qa43b<^dQuntU@0@M&lZ=C^L9T9CWB3b~L@>&a_VevL2a%h1P z3bu>i<6^#}POhSE8A6F|Bhh652gU!Vb^8ayKhr1^5kxJ~1+dEOMP+IOP^zEpAR-N$a0V{100M<%td-X-%UwT($0oX!zllKkyk$yq zF~aQk+OnS+qv7Qe{(|LBb;9TX%@3vhfWZsw#D6O)1VDp71sEbCLpj}9oDhe1;5P;V z%nN=SpkV$&L$3oceJi0~Oh!~TIV%Y6!LzAj*LJeUZ2DZ~S-(N0H$bEV!5)Ht-hvHHI zbfZnbdruIaZoPuQd*Zetg*0~o#MbL;7x#dVP>Er+n>)qgd1#zpy!{T9qN&24U+_jNQ|pLGS89o58q?&50hoFu$(9scqDE=L-o7^|LuK^sHkY1c7#buWE?(5 zeWAbG5=$0|Sh(S;uio>jf{&*2pEig$t)6ILv$S_HO<-7|>!(xe@Snf6su0_iR;?|* z8&T}Kds@VLd;4jAbN6gf?vxrX8EAKUS4|6btW(h|>Ye(?F1IAj`p)iYaasDzJ0G5~ z4>HyUkqrRt5*yB=;m@C{pUNu3FAq&P0}c;FS%^QjQA9v79Y%dZ_PuK_AMb``)&Qfz z`GhC+wz3VFjY;|OI_v5`I=C|pgvE>l^9rXl0%YLtw7zN(`n$XV%`NZ2)pwcxtgiSp z>9))#gy1v^0i&oW7VWNJRP$;5)rKYl^Uj`aKrMKeMUvLiu+*mn?St?{v7N)2CDUpA zZNN4FkAAbQ@l`20`0ZB_pOU-n;Bsh131J)bFxP}l-^vH0d$d|@Y%Qx1_}ES<(gM<1 zF>GPh+5k3ot$1X(clZ+_!!I{(y)mFNa=a`-fr{TNx%F%ti;(23$C{f5>O{~apQn$G+7pkvJXn5= z#d(M1jiWFSzQ$LD=-{bD%Xv%xDwR4G{TZLB(1-aqabXC0b>~UCwMIR#1_WLTw}5cp z{UKZyp8~lbYoJi?By0C-hD&}2lscEg9OEO)onoV7Wuf6h^L0cof>!05oeSc@^Q%?h zzDWhEx=*V4BkwWNg!ucy03#Z66XD&^=dLT`<;^<8Lk5Vvt!c4OBQG%lZ=JVXCMg>yCYT5o;0UPJM5d=`5>YE#p z^#$w;7Ib2f^>dfx()A*A4Igh>E*fIv#7+iGr$kH|C<|*(@{&~PE?8j!9+||1iv+S9 z*FCx%>rjN-7gg=(vJMQdiqmut-75tO>meplkJZ4v?gqIL09Q`o73nRy2}RK?5k z(jxM4cW1`I^uD^MDWzGyBgMxG&-+N@^VWVz-nmMjwW<8%H*&hfv^{?uGV{ajuO z0XkrWRMY-v`P^HQ(LT(asJ17XDdTyC(HA5{&d_UEgcz{B|3~Z7&;R7y4^4~ik&<-F zYns8>N?-?{bDEP!=Hs*RM<3Q-r~W9Rfg`>z(DPSfKPvFl(jW_`YFay=PSYXzZpYxZ0zD2E+H@bp%`r&oc*v?{=;#`)=$avQbmUY&DH-P z>-Szbg;%-L?2mxz$EQ*`$)F`;1VsJ>aYyYxBY#&{>f=)+d^q4&lEJHMO*Cp(0g$dp zt5mZe^N_Z8CB_@a`Fnw0>1oZ%aiXm4ZoZ#+8UNAy5Pq1`_oS}WxDw{9&BHuxT*CAt zG4Oiq+hM~?Tt21_C>vT|0zb+%6YGd#mM<%Bv#ct>AP>Hl?96Ft#K=YO>u~zZ{)g17 zpUGQ)fzd@7ovTQ`XKAgEFaNG9z zHU7Ym!nx>|oD(0vrUgL9m;a`NR19xk$_ITAfE}HT7y}+mGRMPtWGIC3Agv5E;*0y5 zhtD>f_(dLyCSW zn86;zJ8x2&7lp58Ke?Nc6cnW2n?z~v9pu0!ew@Urq5rkB}5y+rw68AN#ceE)|8(2A1QI}TXhlm~0N zna?Z;wuaKT`Yz-tO5O(m9bJQz|2F@GY5#XK!s&lsd}eHZir#_xqKB9_>rWuZ=Tpi3 zobb8hG{w8(k0EIl*eo)>-|8=K%s@=r)yIeqdEx!EB^6s!2QV5iqez8|A=<(n#yj?j zi(FGdVrMKoh2BfZN+DJVtcPZo-87wionI-O4lyU3`e?pus`xKDWTJpIoRvz3uU7A> zE)GXakrFAkdL{=EvcxcV*Na-G*eLAdww^9Ym5299qP;BS^4NGtvq}wf2k$(bssgad zdjNQR#DxPigJv}E%z7@!eqYBimrnMYlIW?r4s5t#odmIPKXxHT;Fv!T3DZ0;mGW%g zZ#MvwSEDt`(e^DgDu09bIe2dScv>O_6THl*9v@>7^_3pB6)lnCbR9tc<%SFb9+@H& zAP|aH+-!{}MSHVJZ+Hv^0`R~r9!?8n&ximF=%=pzXA$B~RHI`Qo=<l7=mjJd)3)VHMo@tsSne}BCN;vw|_B{ z1=!PuiJ)V93};e9iSqfhUz~Gl6iam9Y>hO*vR)pw4y_sT!Br&ms>3FQ&c5NX= zumHDd6~Q~+MBYf+N!vt9$B@1IJ=Hq!>Sqf8Vj^+B@lRr2fS-}yvmR z(OJ(!>0;V`=D}3m3}077$(gsFu~YTd6H#u9NyJ#i-qE zNxS3#&U)-ZL6cdL!P|$bi)Nz>6IG@cbqw@Y)Jv63qpigv+UkGN3ls7hbg|KWrlI02{sZ*B|_exxqfwaEgj8?f7kg z6IniH05y3|yz1FFh9i_xW1IiHXRZPkfMq&WHeIZH1Rxp{q-6e5{;g|-q9eYhTr$uI z&7}40T@F@_jW9ELAtuLb*H$|PdSu49GI3B!O-F|Ab&CKM^=&o8>8Z`)n zLbsV1s@F;08UevECiB@wPcrWN=0iE?6;?3K`gt6iUE=Zgc{#E;b)7I~D!(umY4n%+MC25c>|3GXpjn2P6Sux4T|%EKmoE zG8l5?B5SBs-WHkxzydrQX40$-z?WEBwjS`HMLYsnWbEhzqz6DOF(l@a8BR+104O0i zdpcnUMj)1?UT%WzWHjw&5$e_3m>6Sa`-}|tdMl#%z%M|z`~{6Std}Ia({JRxwk0n6 zaDz2nB;eshZNM5F055d1y3vIOBh>)1VczSk0=_~5kP_SkQ|5KvUIeL7b!7*r8$e1v zhSpHq0>`DirjiXDE5qYc8}NIR&WFlm2H>kHDO(UKtn%##;sb+$&JeF{LGgi48*^Hc z%N4n-uInmSPo0)r`+?I}YgqeFM=biuRY^l=g!>_)Ysm`#$#JfHcrK8d=zOmcR=t~3 zCuvmX>ql%rJehs)yEmV2Yo>{-k#F3gV!|R!qBCE&^awIw52!zR(KNknA7jPzJ%=ZY zV}|oUEO)YT%IQu)qR?tGmU-{3dKkt>w0iV0`&X%%r{8AGCDCKF(q5v4-A7lDocIAB z!sI0!g%AiNN7jEhw&2&I`>>ipvEXd^+gdWLXx+VFfq098PbqmH=@{gj~{*BrotJ(F7308!gFEQkf5!SCZ9JW~G@Z@#X~Ad5Vj1R~V~&h-c* zT%1V*V-R5BS9j?%j)!ozU96H>m}z7PdB*}xut7d_s&MUjwT8I;3WvIm?PVRA)$ zwH+Lk^+*A6Sp-~`+z)OkeT(UBkUeSf{QK4F)bc=fvwEdiw01L`pV-h^s0enh zp=GSD0*wT|8#7G;%EX52{ul`qJCqaIxhcOF>vlRHe^2EwhW~2gpL_OTWAd%|Vdj#QaD=gHKMZK2LdF`=phnM*YLc%E; zIC1MTU>Dqh`pXR=MSA(ZWV9>R8;(Y_G%Vw}k{X zU3oVpbDcM6NV8peU92~SU*VQb?KRi8UPZlDFzDc2pLnBwTs*wc)6Yu;0$kdt`}Hr%_1`6ZI}(?Ow87(GXJw#x)rRC|Pyeo|U=bPi3o%#*3O_&w=XicOCCU?F~C zr~6R4)WgH(7ce0-r9WeaJ}z`J9OWjpFN^x7bP8|)~-__ZbjQTETHdh!jn+`HvWCX-rLmro}2v0 z8R0KC7{BC~h6!4Gx1IrCYMwsRu2uW^=4ExAPv4&B_e(eS;ja;vZ09GRj`;4=`VQ0` zYjO*029qX|+t`u%@~&7kOy@H76OIlFY1bSYkt8Xixlu1@KD&ZQB{c1}66!|Rowmjt zRlYE7m#ik)vfNy6Ghp65p zS)5g4CdL=#OL20v2%WjaSH|Av*k5jtKDzY9j-=|gbq5P8m{|7a0UOeJY&YyKB-fg@ z$+*?Q<~-n*zWR=jG#D>+JNS{oO?`U~_ zxxBjEowO3`Z*dN7%~38sC)o#{5Qm2H`hStp=@@_x)mOj!>&>N~) zjfbW0R=%yx@J-QgY1ps*`FGOyw4yu@f>(!Lzc1;&Kzqe^Ygi{fJnZmrDk~oj$$wC@ zD$1Fxx%2hC?q@#KfmOe~K#hm~X{s8fFSQ|Zn~~I;c5l~suZR*H*B;FTPjh9IM@+dUHhf`^tT#TunmN5kZ)og(ytDc<( zF3Lp;v4t_w2Po-JYsL!tK-H$G4^2##6+3wZKKC1v*KZr06{|ei@7y@jE-E@|D}#9G zWx9F~#((X)z^$>lp!3G+0LK`$CBRDkVQvSjieZ5t1A+In>WBSn>isYqMnb^NG>Uy3 zO@~DNxvDbmhV>w|l5<$dA%=*l;{3fO4^e9g3>5Gj9-Ic2wW9OIK|q| zC5qBmC0ML4(Zj)8h|18-^rmhU(_!8Q2khet7w%iNDRz1=SsvdIO-N+^bmEJ016U`6 z>C2rl9JLX3iC)fSCopCBj;2Jyh6B8jut;cnA$||z$`F+m4#orGa3U(x<>*m7kEDuA zZ?C>t*FLL8UA)jgVZvf_YhQ3O=S67PjyR! zq!$i!L{rZmNM97CpKAzJ%`15vs;VmzD+JL>zje&cwxFsTA@N6D%W+%uBqTD>?yxvi zp0*Er{l8lyPJ;e~Jc5u;1K*=o-9}l&E;cVZht@vB1EDWmIRir7aM%=#v6Uvs2u0 z@>_6{=XjimiBQlhf^aeChT?#D3#bel9N6NVYork=_M5_zTuSGgQ_EErV+|oiyu-t( z{dZ!0VG>Zn^$HS_QkY=1*VBxRi=( zk1d!zJU-zFY4COX)JiCyOsj2kLhHVNF^IfG3U6S`%Ou4pF+J&^{K_0N`L$fmqBem4 z6_oit@OARTz~MwLOrcXY4IidQBr8oHFF*2SG1h0Cwp{qlE$S?-4*1-CoCvN=g7T(f z5fap1uJY@X7&$ey@uD10Kk@Vm6?izSY>jXnhe06Lk&i`bDL^_@|5<*c*w9UgnyeczcY5h3@6(>)IHC*ebg+ z0)lwtP45VX7nb^oQ6l@lLH;r~NB;;Y1tyZ5)ED#Bu35PDr`|Ur%qo+pTHSrW3T(+B z%xANTN`;|t*Sx9@c=4#c{B>T`CwvyBqt-@lQ|xy8q2W$vK!kIju!%p4LK{yw(y@Y! zs>tDk3ubFvG#&g{jlzzM6xn_9wZe5R9OkPe^2>Xp%Zd~1DhEJAz^ zJiG1*##R=0dAJa*Y3BoBvG-sJjfWwTg%W>oFnJ+Ibu-$Nxd5R)b5op~TOk7kI?W7GoETP#Uqxn*10gTjQBjx6p?GdE;l^SFKvf}%+p z_stkN&`r#~OeUyB-(&*?3!Pb0HNRb6lMAIi!rGQfR5oB+E`O|vTd zGHWO!yklwwCv$KtkL$iHUsjeataV|q{hax?wdAqqpc%Cq6TIA1Y=a-u?N6-TPDua#XbJe!nU zzud5jG1zSzU)HPNIa+IlVyNbMcl>fg|3{-vxU(vId0>c3mz`^n$d@8?$EULvJLSAz zUrDRrx1Id+edP$FC>|9MqT`Q+8L}YHNlt$!7};gzQK4gJsmHMhRuM^1e4p?+{-pIj zK@h!A0kn)iqgX(jz4$LTp22&TL_~T{CDKrZm*f{y`lIZt59i!+Q=Z%w)v41o7F-ha zz88MyoqIVqG`lJH+34YwrG9x@sgwdpHNABCp&ky+7!8eU{bfr|7()~{WAA@T_VJ?Et|C5wwcOSFGWXg874>uL3*V3Rkb9qc z6jhO7!J4~qko~qsQHv0V{oB!CKbH-0_{F45MFx2G?4W2PdMzbSkkqb3#muqrN&b8~ ze_F3~Uc}prkt(%43uQ*`Aw19A`St~N4o@DWXHXWktM}Q|SlLRrscQGji@1|_*BHjB z0=|1QXGE`M)V#{GR)$+JJ$|24=qzzpv*xI|*wIWVuT8LIykJE>Izi9gkfb5AJ%ULp zHZeYfd4~0fj~=@hvqVVFo*+GBaUXa+_G5g)>s;2!a<*oiC})#;ow1k&})@P zsVWQmwj$@+GEXgu&iwx$dv6&P*S2kq76byponXPGAh=6#cM5lh6a;q<1b26L4ess^ zL6hL_!ChZv?|bguXWw(~_rCY%z1P}D{b03fv*sFeO<8mH-p3f9#GYo!ay?8p?0wrq zZccMAA%k5XteS_frFQazBtL5+u`h(Q2yMQ`&-Zv`Hsl~SUR2+y-^zU|jGlq_8Xib} zaf>HY6F*A|(^OaDEOtTXp)L`@%C^7B`~vBJ7E+E&3fb*KxB_v^ZX zQ5ox}&j?WkxTHfedxZA4-dI{Xmu9aAX;pIWd=+HAP=sv_T_85jzaxtw)8032%PX(d zVm2)p{NpI$0~46+z#H>DW-30sFuxk_mxM7LT}d^b!eeOWRG)6ZRAPMF1(c9n+Ufd3 zDUxDazXkq?7S^Zbria6yjmA=1q#Z>FH#7*Z7||d1#I4=24kA8R1D^T#q5nTO&lLuY zgmv69mL%^xBfx}0c$Jo)rG0p{5-5OlcHkopTIr~Dc|JQhLrQLTeM34a;f5bpQr@!u z4dX$&-t7O?gW={|lto{(`e?6*dv4Zs-?8;I-S|lYJ0bDXU|gv&;t&YHYAt!Nl$v+8 zH)^y5nGYwFz)2#Pk%?9HRoPD96<1j$YbC>jeoFR;d1G>#jvwaT>F-5x6tXBzYeccr zI_Y5K$FE)xBmLWsNnCgbt0b4%L_&V{mr9;I&{NkCVlV3hiq9Gr-RHR;+3ATW%xF4Q zIXSr9?22W<`E^bEv~mrq16RNBFpbqHUR*Uy>e-}n)@QKCBfmq_uI!+LOx=CNAX zjScTEFNFFDD$A2(N0qf3*sb9Gl#%uTuBmpOW2L~7@GX9Zb^URxhB9i$<7!pFlYF2d z2x>gzt58grf1O-I&POQIqlINPx)wtHg)7V*@u|A^R=qBH!KX|*Z&09$^Xi`;%E(_I zO4aJAn1|dmTht|jUtP92fq>3vPu8=koG#*1#u6J<5PLxdzBS9C6i;ubMA7L6r{ z)J(Na-cTd_J3u9=pqySJqG55qx^W%YhxfrK>`KYOI4KD~3cb^8(VaGh;Ia={CX%Bu zg6ua4u`m~JhH&tV9Yam4=Y?E;XZMWF!VwGVAupq~TCQ5CGHtT1aHRHm-{txC|E*K? zY(CrPtdz7gYxnx21C(wB7LKO`m3h!KXz|nXn^z`_0UkuyE47Rz6@uRNem)t}w34v# zJD;Ai?$$NT@5~^nc4--CzP0}F=w5y3Aiq(=7(sEJO5HDg^ho%Hlq7DR=E&yfUFz~I zocl4notCy<@T~sk5 zdtU(K<(!26X(PcSPKpBM7K@=>+f3!-yx10S7kSSTx3iJS5hg7VVQ1*v8Z0dpZJ2!Q zh~qm@<=m@FpP$TcGdRj!#p|cNc zI{oVRj6SoT`_v|4pR<#y(6`ozz1xEo3CmC6rkw2ZgeUST@tk}&_`sfz4iLey7fs2r zaQ~g3JgOxVJxxX?%zSZ({!`~urQT$ZgtLWzkl?AX_~y;C%9$CUPZghQ#!5c$TyNRx z=_+uNOVBr0TF+KW`XU<=Sz}2|z3CJul7 z%RHc#dNix|m#oB~(y&@5dB;`Qy0XILS|0EPutK&mQfZP?>3TxnF8Wjk^Xm}8+(DVs zrU{rV*%n7ub~Gp!c>K~EXImRvNVnh2a;^$1>>HI)C$vvJAf=hI!*`Q#@j>W@AS_jZ zDyKrfmlJGg3)uW>ARg}KX1zE{K0Pof3%KUO{${^J(TvBsy5-rt{{ z=pH*C*`j=&y@*U;`q3XiTxC`-08IH>)St_I%(BJ#t)wK|jqWS;_BOMP&-B!f96syi z(5$_z@R7Rkd$0z>f~FSPE5^el$ zVV!58lF+23X55tzm1YrvfE1XLIgODa(&D_i{zyv~y^}nh%vt?JkSUF|u3be7YJS+RwCWTyU+ZO%vyt@BQvx{Hv}u(oZh^kvv+0ikbuHZ#C<@IU??%v#<@L zV+0gUl6VNxk_&PE1Il16#RcJ{s)L0pFj(2JNl5E+oP*uEM)_4q&1`uJw1S3)>*N0n z(#4JA?Es`=JdUX^wmfdujS0Awx`85CzUDhmt#GPdg8 zwcSzNJ!GMkiJYLZGC$gwz>UEZ9fXyi*5v$So`8yNz{uzm0c*LlL#oei1{^c>kMZL8 z`gbJU(#>gS3s)F_AaTfxnz&Ls$V|;MRZp)@%>- z6Bu^5QamRZ7-3IYP7(pwh9xnuhjX*Wx)gjEvw!h=5Z?YlxM;r_Fd0^TnI zxWdv`SbbGxq&od&XqYSeAZFB=3SLy(oY!naGU2`njTyrApez>za1aH9atM)m`bMcU zK@p8UENZDIvZp@TCyD`(J%cbtg(~%OPp;v&Py$&OH1U#C;=#2r2D%Nl+rnQ>V%J0iU-UedQ^f zrIb=08ghL#krZlXlb5`}4Z#}^@tpcOl$n=)ZBrX|5>F%qY_Q;)^_A(oE0wp5e!zhvd6p5(B=`)(itvf$s<5_ew`q-ALyf8^ zexXJ7&t80fUHzV4L8OmBUbat{PJvvP04)PMIP@eK%$>+>BflPf&OQro!wtzZX_)XM zo&(LzHh&bn^Gq*pzbKkMG{$ASD}fC`p7-uGtsV3_nEG%Qej0xaCy7fsAr`nhEe}zP zFN}14_kd7Nrg9}ghL5F&uXM=e+==SssBvJ0Vgai=E%@~r{RI%BVG!MvtKufK>o`(_ z#@K6NjD=v6m&*|%cmKWl*(ng1z>yh2$;imP0Y@7Vx?ah))DV-eL_!#*uzpg`q0`J9 zR-I2dPE`v-30PW8$>G;ZW6sN+(vqSY;Zw1&NKy8|k>v3$OCN9Ew4t?YJFwxAb|Co? zhVQjXj0Uk5AB`7w=!Dwc2tOSTou!PPb<# z<9VDd5P?;!OKk)k%x_y9vTA?(Q>sNNxy;=Xt5@GDq(nS5_OyjiA)^GN8ZUyfq5Dl3 z${qGj*;%;2u=mhJ?1@XOIuMQ;5U6lYT?fc>(S5zLWJ!{es1DtvFDlKmO00M1c9l-#$bC;32 zP*GWVS&nrx*ojc=-;02vv{)?c=kj;j7N0ngEkQkzJJ;)XD#+LznNdJSI_^`fEy)96 zLQt&r`l7MocAu+6AKANc3tXvpB!2_yr`xBbhe)Jqx9YT5WAH=f-#&VAsIKx`Zyc6 z5|s4|jp*Ky$vj@>nWtDj+E0(d(z3(!A3f*yk&A}T+W*#FcwQ*dUdyH}yQ-AxxKDGh zW!3vW2@~%vk?r$!7vl1mxE`^U_cw93Dv&7zb>k^6TO}#t1SGv#Mj)6~%cgJ8Gx$l_ zBRB*CiO;4}v7|{)2To(P2SGfH+L7nelHRz*m3fA~0MgXp=&uG)L_o8*HtZ3Wc+=j^YbH0-pT|H$$$klPRR%U`5tMX zD&(>9kq$R1A=_GT8Jc$GNKA)(^p3&Y^CV-g3?v3%5DU&1Q<6J;3z2im4HP!(RT&R1 zp}RL(q~BLTC?-ssNnp5Sg{ki3jdTqkbb&5Im_+K}YBXP?JKG z)iN8HCMog}4-~V;56Y9aQ7Uj(_99c+uOL}|FXh7mw|>fzv>Ll8b;3590^0or!UvNg zXPZh(e10C}Cc1>fv(=R1XTwt&J`5JPRwl2#(Tbh{!&|+g1@XZhNIEve9x!0ka1uYq zs$5J^7REJeMSRYA$2UvA*-Zh#SKSd)NZ-TSc4FRw;!r@kTCRDvl|!?IEAffn2^fkM z$-e&vbLD#DlXT>_Ie`3i_+0Ucq>a%mi=nA1mtSf0?gvko;p{E!hguM+9 z_oUIyq^DzSTIqMK%qsb9^XYRYru5uA7-q=QQ~ zsx*KbE1#bDzpykiV_ZpEYU^Om*Da!rY$+W&5c$dM<}n?eq?A^|5Qw@|S_$3jI}U=) zt=(TF8zdHvg0btR@B%%ixtSl`%NE#s-OZqYhS#UcW?7Ln`#JvndK;m($mNfw1{>!s; z6e1;=vXat1j*o|q1u1(?%$5{;!k27pbc=QJ$RNoHXQ(@(K@j@=KodTEyT=6=NSMXd zo)%V2#l|*FBgW$#Y|KSQ%y{G@h0XvtDoGiLaKZH%y8z=)cFD`9)e`~#Ci1bmIIF(b zMhjfzz@DGoFhA}WcU+>?DXx6$#jh|-3;Bd$c_8i=U0zM(=^%?x5NjxKVw`h9M*Y(`DmP2Oav%-u<+3#GWp~>CSE=*&LiW|JNoldZHNC9 zNvx0a83@8|M!bm3%0?P$W+&^7_`n2u2YpcJY`yI}kUQ118S)5`Q3f5 z>1f>BR(xTdX-g(yMdb13RB>QRMTJV z`Rst;sT?)R{SeXvu}do_0}Q6qK(B0PYpQCjZLEnC1gDh2 zd*`v|wOLT|qLKNe{XnW?q6W6UHlB~*fvFg!)n-$lqzI9iun*YuqI#wH!PxWaDePrm zSNq-7rW&;c_=yJ}+Cf;*u{lPl5x|Cm$tXM>V|KFfXO*RoFj4Uh>?;vz_d|yx z)wlEhCTW-{(n>AyZdo~MB#rtBnfgye%^KoV$7QPp;n#{8qTa+81G(#O zjawAF6J>r1*G)lmkdp|~JCZUar+-_pgRPoVMQ~=tmFsVn(Gs`wJKk8~$zN}tQWuWM zQ0idzJqyy0~mr zf;#BL$nq6IjzRW|3H4A~DhshK>9zK3G}=N&6V3};VM{j!HyKH&a8Dt zIA?L^U`l>7o$1wAH|<&>-Ua$!s|hg}3{&KhJ%^M=B8^tq7LUq!WpJhHi#vf^Rp0JM z*tA3F8JakUjp7caM2Dro7HeVH#6xOu-wJWbc#<3n>eKW6Gs&tcay=&7Sj@v)x6EzI zPHqupGQ+!mY)i)rFwu;G`*?JuzE#mmPp%6MsHcEmDVhLlDt47pyv8CW)zku&=h^X6 z7{RTSnp$!pV?JB6&Z`b&Ta0o!@#zEA+|+2^M(CtMS~(JOJ_c4jMO;btM#z13mdKP+ zL!YdSArNI1#GBvzaa#_Sj(xszAo|e-bV0k8KQjp~nO=~t`^KQUEv&C#jzV`xMlI1E zv_kD}2T~-6?JY=RIi>K#N9ZG%^l*)T_M{ndn&s%iou#(;EBE>Dl@wosaxJU6?a$SQ zNTnoV8jp)}+Ca(^Z>4~dJC^jszfhJBzQr-qw_gKj8#|V0#Epb?UF*xCt;O{qGDc4c z2gRzInGDeTQWe1N#Pmvu4eQeRulR{sP!idBQu9s|zrn?=I}e1_<-kI-$f~qQ6X+Q355l4 z!h{gq>spNR!a7?}95+8eI#xnf#k#Z#&_K{{I@!ueBWoEnogySo=Fn~+uOv5QsQJ^@ zOuE7{G!EEU%lx*4p$vGijmtKjo*qpkspVcuwQ^`BtjtJiH`I~M``6boRxDOr6Zt^= zWe{joY6GGic+dO?#RpRM8B=j4cIDW-tLy&bHSF)an3U(9P*oq{pUF$lK^y=CHt9R zo>UH>l?DQ86E z!abw%PLeexim$SGW!wweidrXL0I%blgTa&4MtS?fqUNy|)Q9==F@5N%*G(`*5HpmC z9jTbAXJ2u?Bcv1CACgJ`OttcWAQMqcUyoQIwI(L(6r?tqN13=#E}^3=E14PntdwR{ zM$D?qzWX_>dQL&ZrZ>Q1wRSZ1SrvJmye6@oLp4U%RBx%_5&Vbpfp?^SABDUnC)vtE zx=>OEN(X8wt0$gxSY|{4>lpqK87z~SxcmUXCYELpiB9^)wSD@?|2m)6UPNA>QB_?a zpi*vBXa17#n8wDZH^NfHi?Pu|#}$<9ZvQHTgA_>HxCK-e8CFsBgNXj{#Mp|cDd0dj znWZ6(EsKziuH;@Q2TDFRs+-De`jOs2bt2m!=^Tpr`l z&PpNGiqe`LV4`-o-IE@DU&HdFCBbqbci8Tzd;};XJ>uRkyitc8%t6@RMA&&^oBNm) zJt_bekL`0SQ7&CepeTF+B;R6`#A0-*16-(23*hZR=W+eKe!q1}+Xao@U9b|zKNJU$v0R>vu+%a_83S+VAOnG0)uMfFj;LDpf8doh21_c+9!g<>-uw#W0#ht8c zNuY^aF05fdgii&sUf+^?1{IN(Tx~0Gi%1#l0cjpbG^4`P8|lC0-D*AvC@gKGlK5Xp z0!bibuXKN-5^QJPt9zyrj(&Fp(k_eFCG+&vDW(0IJ=y z;_<}peWdHqhMlWWVa>ZG%2Hal^ubaug>5A=*M`W(U#|D_uaG?k-PJ#4)mvKqmHw(U zUe@>e2ue5^Np*M>Rj<|Gf#}dtyZ=X4C-gU~)07ykFeeY8eAJK*Ffbam9X_JGvPV4sjIS#zy(sfiAPn8}@N{Wf{slVMm zLXhrxnhWt40IslbwA=eK&i$NY);$=txB2k+Si&5gyHS}jh>Bf&#vaV|v*z-b-Hw%# z5ze%xGmnE+UkrpCKmA<&`B$4YZ*sGv zv1Wp4$PZ5R#)u(W%@;sn&>iY+8Cq(!8>5V#)9tO*p)zO)UO3l$gbP~QM&su0YPR#7 z_>8K0cm8uD%v?4$3c+k|z&dRoGYlXE^VpF$_DT6s~i%YwQ)U(6g z_xi9;KXvKBi(|fun_!BXEyrCP$jM6Mi^-0R!j?p<65Q>#NCNqosCk?d!qzy&%J$l* zX9wjEdyp9WC6Zt$0T$Kq#t&M(KHb>A1a515o~!?B*bwzD>P53;Siv2g=D^`}jaF&f zK=dP|VBn5KfH>r6V{-H~N7Ou(z%I|jW}FxLU6w%{Et#}2R`EtsIzDcsOTG3}3oAzv z;aH{@BsT~JEZYVGg#DX`C0fsjuPd_8gjEw5QgqF?faHEEgJ?CezlcLfL1cP}8okVC zixy@UQOXF!!Z7oDZ%OgIp9HAgo>Ch=sndXnP|Mfx=? zjDR8+TYXdN*>ua5xp|JAaY0EVP;0Ca9<+wU|2`TEU#3I@@!iQlhH1C+l9X^zOgRW+ za$=ocNqKDNgYtn7?X^0*{vOutyn#GwEqV`?|+ zIjEsV9Py-CyJ7*MZMDgt*ne@*bKcWM;(XYXY*@K>O7@=EUk^1Eqx|^>j=pvNDqE^k z1@+May%#*qeBZOYnPd-EU+Ic^)Czb;5O7j>0W`k=uBoz2I9Lj)tckVhPfps|{C+69 z^P8?7V$dS6q7nH>NgVI0pO?hc#U`Q?X)0U)3Yq1>Ul;aFA*SOVK7QrXR6qK>xphB9cCV9V^dY0H-r}0Zk1< zACUQ|iuq69y-{%Wc6sc0{lCM3(;6)VH*sYINrI;mAYMzKTjOzw?1V(mw>4%$1Y1li z@}FkUv43&>Y(UF@e@;MqS?%}0r_;Nnbl7$)Uc}E?ZbzX(oexM`WmFCjsexSWVdJe?VNGIe;-cA}BmvbD9h5t>NGw@FQC;S7^BkcCEB`lx zV_}{zavKgDxDO(0rp#4yMjE|V`lj2+MQ4ixRdd6B$td&ze(^21=^AJC3RxH!%p8=_ z1%S4%WQFv_VP8UiI0k0msh$*R+Uho9DCTTgV)@rzG|8x_TyRIJ+-HrnC-mUn!}7Do zt>x9f0A?+uLj~V&E1MssMPeU$l$}%{fZFer<$Z#qz97eSWBk-{B4&mpLEiLH`*f4q zxvVzy0+92N3zK^e-3*9w$DnWQ$S@)DixRc$}vTY+GanMX=|r&)V@j7cvuS z?qC(K?Nz@e451!$_rU7OjKn5|VyLGfY<2ym;Y~*?!%&f3wV~|j?-vUYeDw5&tA0;< zjkfitBT2<(y*!Oe^E`J@EFf?c%)`4oxLkQNb$pVvERdrTUVZ`D$TBa8I;~<{Ax64MD*M3df zikI?^)IIT{L_=S4>@rqIyU!}i2DMAk99_k9zkue`;CPoqyHuzv-%p7hT4mPx#YssH zP#Q&ev#?+ZUGkv~-_-zcEjzxihKx_4{B*{F=gT*H*g65?$xk(h_1SDlvFXFsEFrt!Gj4{7UbKQwe z)TKoA7l3o2g}}7lo{QV4h8ZQVo0YPD&uXyos9tGWJocP=LdlZc9ZgIHv7EW@q+OSN zRk@r3u--9+)(sC8;5NI@WqgLnik9@`PZdZtU2$VoAhQ{-NC^BybP*w)K>vsSCV z*3KCO?Wtw&S`3iO(r7DZX$_>T#XWvBJd*P_rZ5o=D9|c_C^i^h2iEO!dq_CL?7*ZV zS!KykCm|RS90+HKTP98{7N>d>APDQ~Y2%_S(%`FbdX!m8soiM(OTu5dMS9E`K`zj$ zltMyUWm9rQnoA9cZC^*2Kq}vGX-bfL-N>L)Tnfno2joTyFPm-TwQZO1UkIK4)?mE3 zVL@>APK1?=yLcu0AdCDC6vw0E$d`trWk4tU&g@|x!c2+(W~NR*l@44t=(d#%#mxG1 z6;LeqHVov*1l}7@hAe^lr*np;taXY%YDv=94H)>jLHv^R0z^~L*Wdl7@p2qvHju^i z7%r9YS*~88L$@4Uv@?goa!ySVh!#FsLVS;TAnt8xknHP8N$F>=64*lxD;xT@$mOIQ zbs^dOVnQ}1YZ_CeWZne0tOm27y6TRMPk1L@)7^C`gA9& z(djVIRk%LrQ#8CBJ$|m|AaaYFJ3> zIf$x99qBI8s+hUK>wTsUFxaL9!3poHHm`NAg(wx4f6LCFQvuCrEYR40OJ<@#tC+ZH zx=N+#lk&Z`m*vU}Aj9#E{dysT9Lwe#wbDWQYixWhzksF{%Xn)}C4qrzAdOzW8cy+) zLZHsih<1M1jVA4>i?$zD^98SLTpL?*HinXjj)dB}!H!ss@nM=AH>uIb#OxtReC7A7 zwL}6x$$RpRlE3_FW!`#SQAkO)J59VlMdb_c9^v#*ON`t8rLa@|vFn zBi{dA6%Gkxe606;Qt6TF@_M7zpueoqfgeO(iWT3QE2ZXGBHZ(=ia}mLYnN|INl0t2 zuWa!>wkWR96WIvSN;6kf$%XN=n}PoA<6F`B*&i09ni@(=s|l|akH3sJ5m|Z01NUn4 zd#xyW;k$L6T+OI^mo@k(=(CU5YYJlJB2|7YS|nlTMsHTc`+da@XvA?5Pk94H9ReON z7y7#fEU2qZ9nqcNB@MY{Hrwh1=SGE36JxVIm@}E4!7uSV#*%8~0z}liQ%xF_kR|SH zT=YQUsuHe@=GAD%_jz6o(}YwYs%yro^p}Y!Bo!7b)w)1WnzZiTxu%9w(&yu1(BD?_ zYysF=iG(-mmRtvmNd-6s!+}8t3h4UMqGgfEPHl{`Unw0651aV2s!fU zb(i*evsU#nTh?YlC@z?tdN-ZBlD)e!p~+I>DJljP5|~4)0aD#+N6NiIU8=pm6=MIf ztg0bh6r-YjZQ)e#U@9`^x)dD|F+^YbNPy^Cx_PVoCb6!Sg2IBH58@)exF*iD)=$Ro>CIfNQ@svZZ`fzwHI^!+ zPzggZM4Zjc-{Z@M?v(BF$mQZ~iKYJyo4erU;KzYFoDzfo?X9MpAO9$Zl~tz3b4 z6$vT7^Z}UBpa9TNuU@@^fr5pCT)qN80nkaAg_I2Ke9>Y~Nph;YnFI}Nr`FFDKUYO( zcfBkC;34Ip1Rx6KyN`GA|L61nvnP=B0{AKl`1gM=fd40-ll^9&Y5m))Of&Nhe0S$T zh^SfgK5ISfIrRmQRpdpNw0Br*zYCMkKuPFityBW#1m0VNub6>n_;JY*_<^8D|AM6j z_36!Pmb!L>y@AQoG)93YDluw`2Wbv6dmqWs$>Z0;9~5>>cW+>Zib@1fgk9JL&06aXuSLm%>4n^qGu(4JmW=I{@&j`>l^dp{o6ypE|cN<=LJ|ax<_)m zltV(Nt)P>Z?|Ui3=}ud|Cv4yME(LO$#;ziH&V?_uOZP5`x6E`Th}=l`C+hDh$?5i+ zO@Vj?M-kH%tz!>#xyB6;7q72@l&f_`?PwmB`nl#zw%=m`TZig--=57so`@%|SlPQT zvjR`j$6o;557J@HqdX^Eb=yZ$I!6&s)t{N{ZTOWIsZx(-F#Opres z4g3oL?hK9a@?DI>#vrE4kAl#Fa;^`k`<$e{*0#nI$&*Us3Uz{BltJRNHzPhD%5!f3 zhYvZu^p(=Z(pk>E@QAifX}t&LyYlggIZXqevc7>|Rk;LP46CxU?|&FkrJAX3cTIg> zG+htCS27Nd5#mYRxuIOtH;Y?{rc8>n?WTufYurmQ*F1+v<%zUD=MR|l$Uhu z<4>2usk;NcRp{?5(t~vGmGeZNp9j6{LWuq&)gXcixd$o!TS_@@%o`?U88i-9_A!B= zNtl?(r|d2g8n(0-z*~_7wlU~#3$u2Gbw@uRHGC)E2cVg$C)GidpnZlsWpD=7)hi333cThDeH9B9MHx#dV zS9H>fpK;XBtFPnhKTWnK9CjXNWrW}BpT0NXpB0kU-!pvOY>hGfVJNZi@U71mjs)Vl z>$ME`iW#jUd&D7*2gBubkSfC2n5j4h?7j+Tk{9o@wi?nt{DBZ!&?VHqs%^L#3~C>W z?8>(|SyDch1vk}cocG{tA~WWJ&K&;w<@QK>rFX?Lm;~58u1=C4AmabmTevL8f_JZ1 zKYee-3Ia{S4Gf(@#t_H6wX_-jqMorWOh=ztiMr(HHda^Brs;iDna_`u*E~J%-*E-v zo0BhOKS9&xX2bHJ_+%T^6E3X?eU}4Y8y;wPy?vu>4$uE;*@h+3>Nu$nb&qjuU5%vP zc_!_$vp@h%E3b-xn!QVpQ+sU2Pd9gg4cB&`?y!?JKqH)BPF@_HKyBoL)i&%%+#cq?OI@JpLOmg}e7|ih3voF|{J7&b zHtljbGnJ^raG1-cRT=6Z%AG2kb5-+42@k*Fykvy)AKxXXXqUs1#Vy+L?HHS}6B!KP z=>R@ol3SD=Q^R02B3|3tkA3!t?f`|C?-Bx1b;;?t2LV(`k|PriLsEG-EVY7{goQDR zBV)wyV@WJ^d-sgDx|BvL^U6;sf~71S(`WGI!+AegYKab6siB6{`D!YRVj?r^&Rh~* zhQ+SaHQK36{S|$B9gWxac zXeyN_x4ziT@iwf9x6r1=dMU@sRA%}6Pu5#l&OE*}x$Aj_yEX`sPBc6#@1>ReE8eh}@bjy#GQGiD}v2 zY9J=L!vZRhpemwiniY3kNJYf7M>n(sHyH;BiBQbGG}hONdcy885r(77p5+CQ+Vw^C zRZO!%-TNzv)&mEW>ehiTu>`q@RY{dv20>VZ?5v~CHFqVY5%FOk6`1fyF4%xvCDATj zaH#?8RNZ|>?-3?hIugN8ZbceHh=ZCYF2{<^#jnvm5sEK?@xpep-x{{UFGi3vd(L9Y za~ksROI##?fACk?Vf)ISL)nMh*s$ME z$_stUMD6PV4f_VJH>H@97Ly(?S z1^a${$|3d|%7(5s6gIbbL5;#`EtyS=Hll#mM(@oRG00cSt`qwrQ^K6j_YWKF1O@jL z(kW{{zYFq^??t^H@cYD(lh8Kn>sR%~aE$9bG|7BUFSIt>2C74)JYK;`g@Ac>?CS@f zU}{lS?2S8lIELU{N9}Dc!WOcSDVz8;`@LXL;rE_za@}KJN9>Eik3^2Ia{0rL383Fp zEd+A2f?lhJjONnGrV%hszW}~`{p=_)mCcxt6oNjN=$ znoOUKyoG>SuBSBogQ})t!dg=vJjjR(L-x27Z#S|W(8bruNl9qmXlRSdI6f>vSn)%L zRpgun6z1#^+gsYIH=Gi0vv}wnFLkJ7F!R-!{s4qqb&U%p@;LU#&wBx=bd=Z_6Xq-E z$^>54(;*)$-oG0do%g4xeh$XCn0&;KlBmX*LsD z5kI?mTmQRSptk>BX#F#FOtf;gs6cxoSwmoA|3EH{Rvg8Bi#mEJvfqY!A>yQzwuBPl zS)G_2Lu_DQ=0lOf30=OUkY>l7V_99Q#J%Lxl=jS%eiwFW>JGnPHX|!g@s(7thsI9c z1xn#eWBDA6=ziT0u~fGd!ZM@dZ0NA54;}eD6*L%oI`HIg+ux`Hx$LeOBqJb0&QPoa3O{McsBo82wsD;vc))@!C#>tr%o5 zo#RY11AdRD<%Uxq@)11{PHhAyx8I6X_ls7jDN>rG2J}phwrc3c&e1QK5-;LM(nqII z+NHGiIi+r%h(_3O^O4`Ba7-)2SOVqp5n1MQQ$(nyaR7CDYI8{KI&Ug1wm|84`mAZ6!k>h z;+(1F5O&H?r+ZLt$_`wUSkf#~xMpAh7NHYk8v}`2>|nV7tl>lp9(caos1Dw38JM>GY&3Q=;rQ@hzk(+Xu<@48%`I zL7S3{Atjf;4hKL9<-qMZusbE|3aQ2ynqn0mG;MDTBqy-5(G{m7%K?8IAR-MGn#Z28 zy(?fl24CtprnZDLv~;Vw08?6JzHWR8!#9F@g}ry0P{N8#uhksr#1b*)=vKh0%#ao| z4lH0%JWfk)?v*xKhe-3&fCWf0Ntd%FI%ClUg=-fU;PC@&PB;Q(X=_D@$$y&Iy%Rs3 zQqm|lrn6qa`pr5mXaZQkItBSZ2`qrldD_}%B$S<=<==r_zZ{M%gz>rbXsC=LBX&j1^-83_IjE?S0?Nm^<)F1cxCYc1WN)2)72f`(8$2`*e?z(liKdPn$(8!nvBlU8PLRv#gKD19+_@0p_i5QTY59JT za&b(J1!*LnwAqesC~OQ5%Ygs_6T!A4jGpa9Aznd1P9EJgb7jYJ0*N~|A;CR zo=U*=AD5Awcy&BuQd$e+8MCz#Nc7Y0$KrDiuKTu|;&vIPi*r|+#I8Mxzk;vJJX^>n z3{^4OV!o=0$-#zBV6yti4UOfP#qQg&_HqVk>bewuzHA!Ksr|=gUJh%J2F62SupX(k z*);QIOH7LJIOX()d7#ZdjQlTqZ5f6+t9jvGscRT+^qap)=`1>ig}A1=AlY*W`?>2< zwMAzSj1ZYRt)#x1-puH;La7@6z)%gUqyKTSV0oo1$E*4Yu^>Ej%V9y60rTU}-g24t zcfR{5+p;ly6k2CW^<@QXMy_a%i-9asUH>%eO0};doOV zPU6sYGesEL2XW>qCUkQ6b~N<+91KP|MT*0>AmqVNXa}FzX>C=FWHRUSChV_B4Nk&P;ZRTK zqn2q|HKeJ`Bf8VR8Np|F6#1!v&eZopBOo~uUg9UfHZ~);Q^QwFK&ti@Ndf8`=IR+z zd5qJ%$?jnRUs~l)v_sPJ_&CK0NW3mVZW+yZ*6N#YD4=DULS{K*izXhlCH|GVbL&nM zk@CQr-&JBhk!%C0ax$ViKHDdP#h61a2~@kk1+HJ;gSVEwhk`VbP5#LOFTghabf_`b zJV)7=9OT|#hw@a1*P>j9bn$;Jh6|~cHHl`d&-E5XsUjIx=cZGH6;5hjc!{9A2x_DW zQ5sMGW7fv2fBB<DnFai-e{I5lTKxRkJ~XM0{qX7Z7gH#xh+aJKio8b)Kg-?% zB+Dli`sK2#0JgU~xmZ9JL8<=HEgmFfKNd}gp=8&^wePx$Ie zy>qV5Nk87GfN;Z&7Ig+X9vAhsQT7uPP-yIo3h?^>V(%@W@>sTY(I0nrhY$$v?he7- zo!}lISP1U!?(XjH!CitwfZ*@^xxfIeRJ0A?&_*p z)w6hRwve;P%m7`;yc`jw7h%e|X>w$O5BiEen;WCbL*u~-;8Ipgrio7-t&QCMp=?x}}zQ&^A z@4!)XYOx{b&dVP=FZ0>O6Tu=4O5efenI(j06G!15W^gS6>!FDtZK_({ugp>-hS<%y zeXG52W+S#VyAzrcpaA)K>y4`z5-XH1LUf<(MHrz4oG2b0>R<@ko6(m3-YZ^qQfrI% z{bRxuzVGbO+H#>%e7ghwmIopyJQ2pIA0~EJ$8ht3NNn4>Tvolg$Qaow;+1op{-wMN z!xwy!Q;P20tU867O&XVMrjH|K+Wf*Z@7d-HX|!jVf__($2m7D%K-x3d)6PLsNH%a5 z`?Yy4roZ9|qi#OJ-rA%Fb`oEk^7RmzDXB~UldLm?8jj#K1>Z3NLX>y*1pNW)h5wd3 zBIrPNwwbv=B;W>`>kgMn~@1NU|YxQwt*Nz>|fgLwrCo395r} zJxxv6f=L@B(A~ksTOlIxf6W8kE!uB>NG=zJy)}Ey{bq>6-omX7^;?$V?Dc))IH?G$ zwOk`k*Xzaeo<8i*-Qv;N5}8a_-z=FDx9iw%S){YqwxkmR{ly0#q<&~?f5W}ahAOjp z<*4u>qJ{i^54)aM_wD5*BajpbH=JGZh`2}ai*@mIudVYFaS2=cvQW7CSI0$W zPihoVo;^jVU}tB#KXZrkg@VEde2ETth&mV#-^m&=*bxfNOn35Iz5cvzaOxUi*ijt1 zAgDE#>f~O0Uw8ypL!d|tSa2P^nZr_*CB4YlDN=TNj871;OwPd)0culp^&k+LC}7X# ze~jp^ieS8#+`f4=S;U}Oi=f=X6kZjH(o#LPULHQN~d#Aa&uP7s?dwQ|o<+)Jha zNP)701qJyj;e#YBu{T?2shOkXme?SHmT-<5DjUb|=RG@g3akhTJZ{J>qNo;Gol^gas~zrPJaR)o^ieBntu-S4+k7!-BzvoP=^0U>1Z%eCePD9vEX3#*C%_p0dpZFGWWyZ<@wjVyuMxV&HHe-0 z%7dZtmozm9d`Gq4*igQTU;Y#TU=a+BVT&4yQ3+;E^OVD{z_ zg6?bLj90?x${=wbaW7=*WhfrJI1z>M*^ninlhVc?E)Ls}L-t{$Lo`+%uzM3^@3#QO zwBAIQF{8KZV~*f-wGx5`(Um5oo$xyixZ&@)zQR->8h6_1@D_BAfluQeUfKNnyblEA zhLI}AaqigfKlJN#ozX>U_;(;0tSbsD7f53$u|DBNlU4~`geA|*@5XamKun{3sP7&v zNg4+~hwIQ<RB>6@&=m5Hu<3#;%IADX5G8I_*i? z2z*Z=(K=mpSRSV0fg-hcop&NG3HlgUqP*^*XoyL=R1xzNP=o+;}VLl5p_3XZ>gvb?l1A1!4JPIq02o`k7_(XK@x)NQFOVKc9{GcvB6*pig&WlTuoy?uVT4sRg91 zORL#m&g0s}KeeuhoDkbn7P8M^tbD9Q;Ot1M_$q45vcaI);{YLR;;Rk-1F2(pIQ>N3 z$&hSN+aJ)V;E{1;Bi|xIYDrxtLERBAo_6NC(%IiNwO) z`;C>J=LfDp_D!! zN{W1eznT4TzYhi{)9hm;;vcft;8R3)rIUAvCP|A{c)qt?*xLdRo2cUx4}{R@HJ6V3 zA!;qX12N)NZoP&F1(ya}^Yc)rUO}cXX0cyT%sV3rYuYn!;nyw)bSET%LG5&UMarLB z-Ao*xHwR@1!7JvbCzN4}!77WdEJ1;x4v9#6eabfL3d9HhlYTmt2jfQet6%f`#|e7d zQ-vkAzOm4FK*j)FlrlhP*(9^;LZ@rTI>i%ggch|2cG;!(o}C;*b4gGLEV{w`35je4 zQT0pV8BfV5{bKh=n$J+oZdSA};X~f44N>x5+dnc6IfKRjfKt4gSTwM+5O`Ey=_voN z093VbHw=1kOdz9csc@bfE6JkH`Anw0ZOX79R{@};(G7}W;?>k73B|eqUU1T!au@F& zt|3S%!eo{ZxJhd~L*qkHX93Vj1Jbv4Nxd0y0AP6iHokC!Vg{=DX;@_Z@LIVISGtY& z4P*S?+pXTi%PcQY3DBhR4Igf6IkrHjD;P;{kAzd z-v`(*haIAnFDvZZTTXuE>a+Yb>!$6l%^_P0Cn@+9*)#S%Ge7a*b|hgS&OE7BL+-V@IQ0HtKgH2p3!c?wHteI zMSU9Bff#B4`oE)#1!7SA65V}o|UUS#DR^7Sy#@*zv%R~h@9?sp_@ zuZXQ}DL?sU2vbZJuuGG~S>h(@WiBnn2%d9vN;j(1@hn$UgVo08&J3!K-Vhima>z=n zn`aLinp=z;DnN)|0!~aMOc&5oqTX|8!psOJeG$%A_@hjvd2ZU8*FQ8_|2s|k_GbJJ zAq?-P7pGDkkhEW3UDEB368kEfstoVayOa8P^zpaV$@RHM;ogTG_#5Um)rw4Gl9mmA zp>>?(f2|%-OZ3iwQP7GQdXg>hOmDKgj3BT^_j48xSAWnU58+^F~JrEoMY9G~ybOHRig4U*>?Tf;gr=OXGGg zx|1D+fc2LBlvO_?@Dy#xHR=(aHV094NF^&8?LcOESXY6sLe&xY_9pS29Ue(Is%(Pc zji5UEAWqg(6x6;Sp9)EG{BxvORIygPsnt&+VOEhvCqI&bwRkHE6}?Ziqea}YykAwP zFXjCxy*y~(nW$9kuEVMJb_oTK2peYB&$e)+Wt*%U9;4p zsn}O#LRvMojJZl>%As{EnCXf^U5wPFr_Tp1jJfPJnBfLE(rG2k0#;W_6lHtxQMkN* z#u(`!G4#Jvm$;5T6A;utd&-DAZZ!6Jl>&VZpK+*q03>6)~pf3cm+%;#xSkA!g6Y}m;}sjP~ub_Ath*W=a~WoTgglh|4R-Q zcj#fY*AXIzFfNN>r4MCg&d@O7hRM=lACmr!`e)c?HW z`3@;l@TX1)ggrk?g2B~|BO?f_b4)F=quqO`w-zx~#(ItTc_MJSwVoz$2d-GOAVKom zwNSo&2q$&s9Bljm#dd|KGL>4;6HcTX^8)X@!f2Hb@DC&B1bjJ+Rn5{}?0cPIz%9h^^c}}wOb<7Wb z>M(_&KZ1W}{9XJR$`H;?sjJViS;!5EoIUzcDs|qtLjw|r<#l!4u1nIlFIwL?i<%mh zW0Tb7d4S;_YjsN$&a+~gpXH0S4I_TqKsQyzK74*A4r3hE!$`(7@Kos zs_%e)uF3p&0xI1U+ZSbNi{7O!$hR+UT`3}vt0az`@uQ_?$+9H@o4ud6$k+992rbZ} zp-6*LJw64w7H1~;;LET&Agh-eq$FYtZNlb`mIc8!`FriEO8+8TK&==@Sg-y>kcU<* z#dIv?oD#D?JV$Wj!d_sC-?rfIf{<&WNP{P|7 zhMknz5efgfbVBcmx9!nvE2ofHVLtmt|C1q<-kgJT_*DzgbFNY$4x=mN6=5KJYH3c{ zV%G59aq{Aw01kvmE=wo576%pe{IgaVF+`+6JT-Kc3@7v@uiD>=6RjP=`^=@*GNEXy zP%ryMkNHxwzHG3_=zxuPu0RHtX1OjrdQGu9B5{2O*x{1b37DWPx!NzGVSOamuRJ(P zVNK7U#8EJP%>o9}Sc;kJ@kl0U+yiccQ(!Ta;q(Wh?a!x zJg;TCW?xqGZqT%=>(`4YKgoLFkHrSqN-Qh0vQ#w1Qz;kg z=)bCCHPyb-pftnBoa>j*5IKgAQ^p09;lUa_)l<>ZTGX3oa^hKw|%hqh- zwU*5@>4?uf4Sef1vXx`le1c=KrWCSii4*coT%Bu%N#P=;Y>-Eh_N^FP@7H|VDVHF(BhF!{Do3c{Fx^2LrCd;M~%DWeW zue=oY_QHqe_y?+;rD_42_8b3&PBZ%7;EefL>bN)C3cpT?<=3UeZ#Nh~8+t?SZ#AUZ zNV`_ezl}+f$a8XSD_k}>AbS_=qi867Y+U_(hOz7%jGNd18W~1KN5~7$!wJEU4RSxAavDp?;%$JjcPL__o~AD2KM zij7?oS&BD7R(Xj~4AZ{dGZgTZiUbe{SX4>_Cg%P_QpM7^D)7TE1fLu9NgVT;R_Wic zC_Ea|MQPgqP40iHg1gy`v+b*DMl_`pafOF%5oNJ;~LRKNwK321I01sa+p%Esk=$KJj>DEGzQp!iQ4VSwrmXK)GpZK zEJHlY8D4@4f^fdWH3bf{v0HRz?8C;6YC3#C+{IW1H*^LnMU zn9U|%bUrtte)CR35OnRa;*?SZ;Zu24kO4Xk(pZ9`BnM&+>f;DK4Nm`UB}ht4jA$Rw zb8N6=HbbJf0h^jHX%(i#Dv??aYeOkLS7F0Z6O@cu?%+r!Gia$<-$j8n$S_YdsN`5I z6CGkwjOLUr(@&W)lPswwGYH&XmA&lPKFw~{vW`9t^N|q)@JLxkb(pDz_M5Iu${jw^ z{y^mkytw(Bxw*zaqY6-H_?g`L_#=$}nz|2^_M67~1C~SrHtiN9?epS=MEn*A=4ILG3+3CwH}Sqb9m9-L zs#+A+49voo0T)g5???)=gw!ry&%_RQ4`iCMIC8nBU%$k3X8(kT^NpMBIbL!fK9hNd z+`jSt=)Pr8ZKIT`%*!}#qi*}NLd8YV*)^6lM3^sr zxh|N>F%cqc*PM)^@lw)jVJRN`cIf}AFanGs_E{K?C*;(0-E&Lhh?CWxu39Z1(s+@~ zQLrJ$s*$sE67p_VUM{jPYTaQhq4b#HU!0LS(LZ9VM#b>L>GpeUabaescgAojD4}ev zCbvu2Up1IUi4M>~zXtn;@1z^Ea&KztP2X28lm}hJ<8};u1S>pcoWt$D`6o9`xc7Y65zBPD71kb}a zr8_i@ImX7-WSS|1P9s8-)i*2re9_|uX25ug$n1==WY`Nwf|cqi@}ehkFzu8jN4*OC zjfJs{Pvskn6XA*-3odb(7+f@LUp>)|h}$?v#G2MBf-vGlxUH|848|AESO>9gUIDCC zZ$c}#ya*H<_ABVI76Zy^(dE}a$~6lWESvUK<6tc2SK*U4?k&hH5HXj~DrZf#1}J+h zng%0@>|m|#8pkm6p!4H%B5hpgUWI$$M<^6%^?=YM+S?)y)hP>i{-&z|hv*1o! z&r?Bqye76HNn8Cgq{5*#z>#F@wdd-SkSf{T8@oWy$}sWCJ@7&bN5RXP5LxbG&91Bh z)22}qGJfEsotKtreroO=c8jqeNF3H+m{14ol-pe91tvI#lMdJWtvAsgv??vjNNw~6 z!pAY_+W=KVA9p+4Q?*A|e>}66cY*pKZ7k_RtcCM4xxX&0ZF);uj@B@lg+7=FoNOz zwz(}@;$Gi|BXOZw=Ee&VVEj;P1YqZQnN_ItQMx-TuO1okBKrg#Ry9J5e(H>T7I2dp zSF#C2^W6GIW%|U&?`dsWN7`iwvh??vcVN4w%gje_9s`4q@+lW=dSYG5@!kLQzlF&siQdBRDELK&+ zH{gSv7c#R&QDzW`2q%_(9ksTA%~}~y{b&T5v-ejd;$=Z;Ui5v`olZqSAw>t_;|D{4 zev|<(m6@ibvQ{YI2WZ?vz<#>T9t498&$s{;b-gCPk_w67ehtVb_q`q@!!%8sCcE*9 zz_!Affu_J-h!GP=Zh^5}3TsVIe<6*c;3t8*Px2LF(9jCx6a>nR&CHlN=rrb|Rd4bE zty8^HN&e?jIsm%SzteysgA{c3vtIDK=NKAXj1pU9OoM$`_>@{MQ$1;NJ~%iItx{D( z!$(J4&Ir}g*!>2_2s1VRQf!4B^O@vm?(!@Sje=3N=LmRyN_$Xk+5T*c!-cRS$sKWf z?1j@l5o(3c$`sS65;`B^uu3qTu0HQ(=$2X>25b6DU@qFQw0bSDYIV`~$?Ve!RU+aK z(|CVo>9QOhh-INyrxYenqzcFIQPE)<3hk7^q7gkoYRhjGJ<;wKrHFLB7fk=aBcX5E z8pOr2H=lyUE-xnEt~kj6yW<}Yt-Z6=)|9NeYRH*oVf1ykU?^OmCEGXLyUv2;oE>SK zeAl~D2_L`tt$=yn$VlBJa26lZ_jS$hu-7=ihY!+PdM_Q4>!?*C+@;_3;?=A8a*+iT z$JsHhz5JipaF}r#NmDVP376RS9K{{L39_16w4$_g9c@yC;v#@y= zhv3`MBGzV_!LV(S9Z!{n2Lw~PAu{9<#y}W;s50aGUCfgHX9qJildHxR;#cHZxzdUW zr5K=r0y7a+Ad8VqO{QY00*J+0jtf|!N5ZNaAr!V9#NQa|z(4E+>3J2@bb(~Mqb`tV z!C^I9#>a!rS|@9l@l1ksUZ5-%)1Va{C89x!mLx7hW&OX?ic)CE9~x3~a)7yrD3OZA zsZwAnL_t5x7nO6Dd|r#ohULz5&K~14x0$?W!AUtc36=X0X@Y<338roDX-Et?XKU8- zLV5Poe`M^ej-o|t@6s_?0MV0MEN@OhRb_&jTD_cPZ*!cu?&JQRt=cWc4fzt0*14%| zZH~w{#WIN?#r!2PVi>HcRYBKO_M%E~|9sWt9~*0Y-vJOj`7T&$Hn=B`CsFS468X=A zoy_$2{)QFGON+z!_rPo5m^|J)b^H3@P`*|?CUF0ipFbLlYR4)U$SQYrpOCFdL z?ry1%i|T%yb*}q3AB)w|{kfaxxhkq^1vsh@-w`gjy~t~ejLecGEnpH(Nx;?2$W1vMCN6U+Arr6>9Lj)P)kn}Z7;84`DG9t zuZ+gL;`WTfL@bpVbn$m`wQbczV2583G(2!seY3p7{Tlj+0$?k37hO32$2;}SO16@9 z?Us62$dTeABAV8fWx-)&@*HM~yxD3m72gqaUtrGr(34B1A)E|YBEyeF47|)5v+>iX z$OfwA;TfZZGg$0+LaFS9ygk@<(y>XqvH{iu_KyaGA_?88LvvU zK|qpvvS-rnYrts1)fwIX?A3->oq}^Sy^!D3LCwY<=c^QG)pt+oVJJY+*4gpAZmv=v z-;nWsY3I{hfB*xJ#}=!-!8@=NIkT#jL`rI*-SjNIH{ek->FhCUiqMcsGA<*ZRLSbk%z8%hSjDNSKeO&VEG0 zEJ(D`F+kC&$Dqp2nvb=qmS^540W*Mf(n4q6c;8~Qsw7X(!g%W@;Kk8Wof3N4xA6WR zw`zdib%E^x**L5sOD88+eUEW6i@{vk;%;ZOB15~Yu3&>dY@vsyqdi#OB^#DMQvboML@4F>D7h`=Wb*eXBh8 zw%?B*LLo=Y<2_M1QH#S0L$rVyF8-qo+J|z}?{Sb(_sbkszi?T8_BuFaQ z1u;c@&o%wjb7RlD%IAQU36u7glCn!wJU!T~DcyZGF_w8O#_xc(Za6T|)@`@UYvGT_ z7?POq-z+0m4e3NkkGmgG`1~Et*(}@keh9H;`gY$@t{M64>ibVZ2wR3C6=2=y z81OV6#;&PHE&P$Wr}uF4KCoZuRM~98!kY=qr3?DQlskIdkI1I|B_E{^sT$@)1~SYuIKI=Rr(BR?ra z#sY;S+tJ4Q6E@iy&&1REb#Q(XjC_kttj@_lb(kzT<*S=`<5)2yxd7OHHT{KQ7&3# zttY__n=2BWG|Ty1ezls zT@(4ot}SLg4@dF7nU%;_nR07?*m7q9mc%IOdS2QsNNLL6YiVNMwpiClnZkQ5QDBa= zx-;k4*BM&gNC>j*0G>j|GWT>`({UcSpqMTwuN1Tl&RZeBY$MHAT!(>5VDoi{6tl6) z33>CrLe?cVZ?#H*bwjiN1_IXIt*>$e?WdlSsx>^+XUrOThvPl7v7W;pmSRB&*lwZz zqECCW6s91&GYmhzdaoK$6x_m$n}U10w3zwYwoGz$Ybn3nOLeGtUoS=g86JtqC0tuw z1F##rB=0j48-L2POu@|UyrapL+p;fJG`j;_XY31ZqlgBALCOnRqpd9ms@KJG5-jl5 zE~r1I-__F_dirE68jd0OdB4U}sX82!d=dG{9ZT21L4pO+`x@mIL5E@rO$-$;s%SQ{o55P;1t3Iqv)`1Su%j?wao*k*xgBK zIB*=HcfE@|SoI?g=HJ$5!N@>g3Mg`Qr3gj3Ds+{9Jw~i8FV8I?i@#Qh?Y&4k-nych z(-Oy`a`=$I#hEltaV0XRC1j2;O2aMRv>47A+()%`=0m9eSv|WjeTq7NDsWv7SxVc{ z?+bkwy4{vmCe6_q*7qi*Y(BYRAD zp@N}JvffyIqqwkA3V>58CX%<1^H#2zQLjFx3>a_K7WYb(Jr0&i*vn2uDg(uO@sWiB zsFa-Z<((x6+>S25q53L(x~E{5*LZEqjjwP%ie~k%yb%cf`eZwC$^s_3Hfb%@S4d?R zm&bZ@lUup#rKEB(ond(*iCSYNa8XKM3ctuQt?=n`_s&l=3ZLXgovpk8e)d*g<9GjC z;rd2l5)=Ls#+P>5TWEOEEQ(;bbh8yRXU7oM)kOstGWV`*6E4gr9a3=mrES?vUuZW7 zvVKfEsGY9dR3Uh2xpwiq8BAoJMd8aB5;XlKrYRXnTw z9ob8jy_;wHR}F;Ix>`lWswYh#m4kO!oCwILm|dqf<|jMq{56*wo`}9Ki1n5s=F&f< zg11Y-=^9kw-ZMRGF{MhZy=n}vB`j`zViPN$!W33F>3rsvm9Z>ahbQ#S!c^;~b=hzv z0B`)t4DPvb6xIQ4$Fzqs2BsK9t8Ca7lLd=QxGQ zKX~yrj54q!b7^&^j7ZwZvKnsX-iGX3*n-?j=9MUT1RPiFp!Ml%Cc~Z6WY&oK3f0SO zfsXQ$2*#?KN*_X1m_emrX4(52OtnpC%*a|QTX5y_3{a+T*Vj4rO^AU-+HMECd$SOW zsacq_5M#wQ6T1d>%4o8PX>o*oSYp6Z<&#Wzt_ZO7`SP1DaIoFB!6#wz82sj~!IWrQ z2@Se=)ck5`*^@Wg_B_EkTGe}oPdanZLk|^|pkQ0()Ap3D(?#5QRo6@rkXma@@bBwg z5Y*~Ea!`Y*u)a;S0JzMxv;iH2HXmziyArolvlSs4@WSafSjSY);LeE}fuZ4z&+*h| zBDK9{yLqbMiZm|?&{Z1ckdVZv+z?d8ApE5TyZj@JqX1uJ9I?tA>0{QA;cL<`(~@CX z*Hj1zbN0PD5(mlPVXY}=r+f#`G2t8ucA`W5S&a*6>Han%1LrIXD-go|ALS3lJT}wT zs^y9CuO(rPDv)t(9(b3kuTNKuXt-JP0m7B>i@d$}^xi_U05SDcTT@bSH{)b+2zX!76ofRX{ocFAdmFy# z$&#M6FT`wG5Q902>CFjsRkpd*?j1v)aq+l52d^KL=(oX8V}S%w2@Qplq}cJ!2)iTK zbxcY9MsZ|f!qm8dTS~K=69abv)qCNSraHC3=`Jlm8GfeniI;u3??|-Fs=Xxu_|kQ& zXvsUk;2A)u&#EYWlT^INs>Xte!3YJ4$(bMk7S1}UTRqt!cNz?WA*p7#;dtLRwvG(4J<%hZhOjRdh;Fiq+!0NiSX5ZSP$g zt@>MYOSW!bk~ZikyFu|=|X7o&NG|lX{KHba3en$V1~&l zVy#rT5a78RRf$1{rvW@7qG$p6>>8hT3Ahf-^|4yy$*&4ZYY{|V)-t3AFB-4^sl$C| zq2E2|S&xm3uHu8G($p52O4duh$x=G1ndX>cR$4Wb zg2{}wAW_vQY9!HKsmB4myAqme$R27bZE3#3Z8BnW6D{tfF{(!M=cy`QMh?tUfL*!J z;_S<74O6MW8D|*<=j3I>C1>vBl2Mb}qR@9grl@h8{ALpo^_!kTR!ALi6^W8?u<4k1 z_MO2u$S)={f9G%sO%2bMNu9~qgy%44HZZjk*p9kkby&a{R0b8o$|=8H+~R{BcQeBb z?PRJ1mXcX~cvi$up<}+nS!gAq9LekpOW&&NJ4rT+Z zP^h-Mh-6^&~?_&R#jeS~_^1 z@d`)l8Y<#!;}m$AX7C6Q4no(=+1+_VpAZ9PTig#bI^xJdG{Xo|zLp~R66~>0E*yz^ zzrh}+ETzF?QF(8ebK}3ElDqmJ*BN?)odx7k5c8~WTYN?IRhb>SV7cMd4+mvyR4F!?Ex!v>Eb@DXf`XtiBY)A{Q5$@PaW~~Q;qj3gk#t7$_`dr-pw~&U6X1o z^h#X#xYCImd)88g9nFVa{$-#^T~oDQNY&HOB%3B#SL&00|JYp>JZRaZpSeVgS8O}E ze7YO+uc1AfcLM)2b5+4@eWH&14&XEc-NjPv2*O^ZRB^pBdu#PTp9Gv^VT8E!9)fM>*XW4@m=ZIf9D9{d)iseM)835SA`!~R>9L?Pav!l-wha56t~J#a`daQQ~w z!-2xKRHSp-qkZm3C|R`*T*Io$z8Qjj51?iW>z8h+o~uD|Rp^a5Z_c;GojEk0I{Oaj zFf~BiQ{zW|fvD4OUVn5Agi2GFli9(*?W%E>fyq~^>0u6#!iWwYckc}#$gS$RO_)c8 zwde>_OsUf%Q5!4ptB4sm_A25VG}=DgLZm@%wp!GvWj zD&IFC7_q^970}BO(m(#Hv8%5Nqpeh>tSX7(R$Ns@Sg@RY)iBF+S_rZSfrY7yE!W?1 z8DFT&r=qk_R$Gi#Y6=9L$VuR5E7h>n9+?a5q$o|J!uF)3bQDhWRj>Rr?#yW2*A-E~ zqC6r@;{2Lrqq7EZHtleo*(;nT;8^fdxBf&Mh4=!Q%}GU7oX83*A|!xI_0p+jlBI&( zX&;1;i7w!X!ZmJ7`q2W{_pSd)nXtLAChHd062!d`!H0Y-K~=;jah+m;MIE?Cl(G?B z+Bter0ZT2LbLU;Qm|FmQO`A!@Z{?)IP!ClIYlK|xmzE9+(We8M%%{pYWSZnnr_SYm z^>og<(jivH7`o;(*5QX^L|yco3&3rB2YLM3voT4bA+$i^0|2l0?JQ~Ib6DL+{>CKj zo-@eMC-?4u^i(ABi``kg0|sCxDIXrYuF-xfI)`tHD19D`8b}-d>W{} zNz-+J$iGbkO?A-XxYH;1>Or&Ase#Bvw7|}Mx=uWb2%=RI~=;Ef?FRnwl<&TCD60cFQ?o_9X%V4ZY%1e*y?!a(yvt5W7x4x+9(%Cb5VHW{e4!E&q(F z7Xw_!l5{?01b1PUG~QJ$STZ;iQ~=bT>E|9V(zIurk~@Z42F;nyK%^w;kFLhyZpM*ptSzk&#o2W^<#KWkwA$+8Ed^P+X2vQx2smA31GvE#Vh@9P zG;Hz*#mryMBeO{{y~@0s<8AZSP#oC#y5ai8pu=&~0y^R^xxywo2#ow{!HPJ5i@E>J zZHB@Vx^GcFzv!{)4ohSeRY(k4yVrp>i~dTTE^>)U2&R|-ZbIy0!zveZT_wrh2Te>- zKAS>)KDgpmQ_r+TWl&3?lSaQFm4kW~DzvY^l3&!gwjfGjoYrOrYU4+^CO+1W77d0U zgypQi1A1Afv~K-hBh{b-qpiTtf3&!pv+6qv$XI?b;+4;CvNGSC$d8u-P3bDz2RZER zGV>J7OB|$RNga{U5*EKzb9&K9mdUe4(Hi&?sl57PZ8}gHt~x6F+5EWkI{-BMZ(&OT z0OUW9dKa=U{7h3$!@cotNFAMzt-vaBvNBO^-W=w(8w>QkB9Qqi{i);2i@~pfKhEZ_0}WjS{Bj`Fvmco6 z*J&HkSKUtwRCO+BxH7d&&%mGxg?f!A$|=&tuW zpqy=O>0c`Rj79VUbiAIXzS&&Dwap$klFWT!44{MAWujjQ0f%8NEJUxM$IP;m#46gCbME*+C2NIMc zCzK}FP7IuM75YEtdkL>_k*u(?vMOjQDQW!$E)14g?{N+GsXlq21h`1dpQmmV4-pb3 zKPpi6E;8(2*z)D%R9xk@bPCvVz;ym)nZE-RRg*21`^B!JeOG_n;D4UToW9wy6ilP( z+>*}`{WZ#}9dHpCR31`W za*OsgaIN4M7w7Ww4l(NZYj-l?xzGOTpEEvNpi24`xm8<~=pPh||2ghEpmXp$;NWHb zg$TG(pc|3%ub?%hQFN~cN6x6~_&$yO3b_9QU+W`tQErjuc~|<2(mbhYj>zr3k^u#%oQoGRCn+GEyr2=^%t-+ zr1Fv`5x#;?z=lNsGT3AV$Qf{U(vS22vO;on|7~eT`qp{4MeT7eBV>7oS9VA5Kjl3F zyNWNr?GgcBq5qhGZGit3Njf{z^M{)CvN!&;uGQ~|x;xFGYu@Ob1Y0M})cZfR ze8T>uLNoOGJ0L3~`ePV{sU1dmq#GwT(SIVo1D<~0IsNU&&;1wRGsq8o`u{~Q_V=uR zZU3^sUl#bk$O3%;h967zfr5g71OLE)aRq<;{k~-1)ERPgHZg;Kw}4%>{N{O;*B@5w zLvDWmBY?m5Uz@*7@PFG~@c0Sl<_Yci?#=R6AW+0K; zYMY>>L9G+_fzx!JM(ABbbiV`S8!}fq`LB1y8lNOU@nMnm49f~(V>^D#CifGnCJf^)zaViOk847T!L{={xvh|HjZ_NiK>cgH zdxFsVQPy6*pz4);hv#GV7H@U3v%6+uXVWQVLx;PWa6yE`Pjt2#pvdle1rXW_K zW1Ed3f!nUNw~*H%@tMf;o*Vmf(llwNeto13pV`Zl%kBbdpWC^L{bR$<0yKFW1Y@Z8 zgK>)5j=<5%mBkQipssnqb#DX`J3mB1=UohZ8tFq#|f@owdsEw2rC55Z?*w!3;>z-82Yr)i~a3ND&ef{!+G5K`hhAgG8`P`r-O zWPG#osHL1XB1y|RZZy!Z^dzYMOO9qw87KDCEXJ9)$=273>~gS!llINDVc0l+Y- zBhX5M++VoX{S!#YTIjIcCySUBy1~Oi6XXYSJBi8Vf`F5D1j^C zlo5kjfvFo6&5!Rqi%si0pvwRw+H%-}zR(Us^HHjdMtehhF`%*J?p1rp7p0hoiv7-I2EFJ7D<=IOh%J4@=w1ga&s`26vyf-mEC#Y*20%OO+ zDInB}4;a3)kSSg?+yTHG6c`g0M?cdI7A19Xf~dKNm=*c05n5o3A}pJ&5SCpd(?MH! zcO%?wK{7Y%rTEHdS}6IYsbBjCVo|x$p*Z>FE2|yTh~hOC-o(l1x+js0vOXu2KnsOn zFRAp>*X1kue;kq3LCCF6q8ZCbm?wQ-i#=Fnh@)u&L3E`vth%eo5guUFdiN?yLJgA^rhpc4DrpR5JPz*;UA=b|1z{DW~u+ z%}Ldo4GW+PKpsV*68nv7Q-ToPgXmv+^`?)U8Np7n#?1#_AwvV=6JAMbMPQrTEK-f@ zd&*Z)?f5iEI@avM#>j^=ewwN)v73Ijk=GROj)86YmSp)zO4C=(pqIxh3b)&EAvnT& zK$PbMTNR?ai;cho{GPmBSno=!4>81eITSG_o6&BHAfI;Sb-Fgla@F%@+3HO+7HGu* z%^h2>-r0pO24@!GC1rhv<_Sp?E^^vzkpNo^beoUC&n)@5Ddo@fznwoh6(?)7 zC3{DAWkC(#=DbTW6L|guO}p?(Le6OPkJyzU*@j~Pz>ile{Qw=h`Bmnhp&Q2 zDk=amV}qQlErjTg@;vEu?t40WwryWAoYik~-3?dHb39sBd8*NQQPif?ILl|RNPa^3 z(A=SAa*6EnFXx2d}4KIFA!vMK&eV^>O z-wsvvZPSYNvnhVBCCkLUJ3IgP6k$g_c6XUR-SV5ybUat^+HbCrcs_wW{!`p4R?`&)rh&X zs^8bz*IF4t8z|nOWoeNC5q+>-|*5Op!C^~PkW*)kA4tPd{rg|Ls4 z^6gdMiLVE!Dow7dxZ(r(aGRTJa}D~OL)XIfW||(SW&D9eP$oO1d!9(H=9VlSR7JjHWhIqKP(e-$d{%3!s(?c~bHgWCaX zp0MEl#>wet*wO3#8sAzKY{P2Tbow6B@%ow=`V;#ZpzAhLUVhIkurRx)?|U+p(~+6B z)4B`c)UqJBg$<}~K$?{jv$01$q@Ne1tofE=Vb-Wz3bQwXDq)~*HUQX9_IUru^S43T%Fz#zzSO4`Sj2S(0^Q9#q&*E-4<3`ZYvh7wqj z5-ss;a>gRLWbWCsdxyn0pWvbuD<*+UyH7|*p!}qvcuWUgVo(cmZ;Pl@&fV;WIAPyv z&-p#yqF_`F>Od4R#BWYdZCLVZSZtAx??*OJl@t0~23VPb@wG-Uoj}9qYk-^en)<_j znUM&N)x+)s77B{S2tN1J{BVCW5v^K2it!oc$IVCL*}!om*v^)^84`F_M?d-f7MuTT z@wL%Bkq}JL9}G<&vAt{Qb~5>e`vkM8NwkSi;|Z3CrPJy4N&NqwfT+qMB7vc-MBOP_ z7-HtWR^gR7%Z~QI;)m`x@`^yYj~M{{7Nxh@7WEYOxbSCPwvuG|b!s^86>J$skmlNq zGs)h>!B}A^rA~ps7u(0#NxHhy+`~k%ku8F{b4c?~?K+1e-yN<X+Ng4=*-_Ho56f$^<8gQp6SmrMfkl?U1{5eEK^;ko;Vgu!C+(P zC}lSy=z+u^s~h?WtjcZhN<(RWpU0Kz7gIS$CO5Cv5WlNV7b>3@!Lz0;{G?)76}2~@ znsf7)!1oYGRr8u?waeB3HLEc^{@gI<{2azoA7ZOEvz^yJ%E3c&Zgm3rPpX=rhNf@Q zv3P$DzJ`Y&zu!#^K-w4~G7d!I>xyvY?Js9x*ps{Fc$N6EZPQ{yVo`6GGSFf`@Hf=G zTwkio?1IM~h4f2Wl|M$^RK@k*G0@lQznF!MJtcX143`K{*AHETytQu%r-;60&Zd(h zOvJ*AeA~#)CEqbGV}dLT!aTzpC~YQO_gK(#DufvwX}R?&>S|%STs2*@ckO5g>yp{Y z;C=!f8rp|lXp1XqT0s431!O|ms2QqwmL!bGi~C-r<1dn)P}ipFSU<_^%`$Q?lO|VG zIYGIWtu9b>te6s0aaf#J9|}@ToqVVe+evuzdDGN5)}t(}5jA3mV3Q`&Z*RDr%8E#q zV}bVThfD^~V|qdyfM)KV*tq-$6?}cEQZGg_;)Xj{_yCKpxPU+A^;aTgICG?;R=gPx z;dk%}3{UN`IIMdx>=!^9Kh^bF)_F?AyP$apUeG0v+y^-CN@>%?_+8rfB#g&2s$zqQ z^S%+V6T?LE$>WWGOC}Q}k3-^JQlo>FFhfdna$T|`f)tfbER-@lJw(hdt|e#76py?2 zwRsqS{TEtQJao~LK7dw!3FWB1ii^-*Q0LraZ*zTokh zY08ai)`#4cb%6Lv*Ok3Ka$p3A13iy6Rb5WIX%>xsVSheJ4Qu(wU4~lQKSF zsGKm9sO~aaP55s)8np}$Lt&f-{J109#4+b_R`fQ_8c(E<;ljIWiu!>IXm_aXFPga# zU&cDGvqsr8YkmVhL#0Bz!zMZ)2tP7QMO=xjoyvN{X<>)uGqO(*o?DsSv0&{Pd&Cjj1Pu3Hb0G}j@j!S2609hG&>qfZyBJ@l z+9EW_uCmQq)LRm%rt5m0aFli3#at=jbWOd_a<+pb6-VPjIDK*aHb9%Lfc4zd9%Rl; zvj>_yc{mbb=Ru^j`(pVXPTbY5dCyPMTNhl1Nm@F2lGbCsrP%i%E^!a;AZRP^Mn~m{19HZU zdh!nNa_LRmH1;sEW+Oh4Cq%O9f73%cCqsu)uXrh=zXJg(2h_46urr`^FHmF7zknvS}{G< zbF_Nxp^-3#Mz`RFWq-uU|2Sc9(kIzzP2(;h@hUBBH{ykV$J|-jYW-gkgn7Dh0!cH3 zNQ}0K`S4p<22-)ozz3R}qJhB3C+#dL5a{47RSK)n$gzpv^a?Su=A+O8<9+wFtEh}Y z=>h^|lPu2FwS;>(KSm5*k^3?8Uu%%~)&uGdTkZjtHDZrc*jB7)w$SnjUWg$(GgBZHf7_mwea`n-xPTocBLQY|T|yP> zGDg&n68G1Z;C~Fkgvb%k?;-eagjJqLRLM69xS#NZjbM}+=%ic=0z*?w^gLF`We5wN z+0+!L$*K3Gs6rZy1#1*0U;n6GM*MpSPV^C2053}^v1DbS=r&BUgVu7-T1Fit?C8IF z;?kDq_`-oXy9ry+5E=M5n>4IX*{Oi0ohzRlWgP#U3KG)161V&mmXy6*zi2>xn6l0< zg8ufSDoM9NsgQpig0Ow41TR-HI@7uMo%BW}e9#FJ9IU%F?2{MUSjwJ~p-3u3LSoOb z$HhH&T535_WkA43VCJ0Yg?*$f2uTV_o)(sJH4)^;NN3m+<3G1+z^c7TBI2kstE!Ti zCTq2I2fmu?h&-|S`k~mDM=)c`virz%d4J_KvK7WNq;5#gz5tIy@Sm>17;AZHn>u~R zS8*LS0aUd-%%_UT$YWl1};AzaOGDGSkDNIFdS3XP4Wax!EU)mNd zNQjtjkEP!G@DCn{r|en&1A3*+aHSgXW+likoARY|vwEQ427hl4lvt^Kj17$=co$Q6 z8rMJZ4rl0bImG7YsS_Yymut{ulAvYwOQ`!j6s z+9%f*&C@k_AjI1(&+-&7iIRz3zI?l@sxx8U5#>VxVvh=69lZo?Uvf7VY{aU)Lw=)V zW+2^+d`TxUm}l{xx@f(R3Q|HR#$umqgwE4bBSR_|-nE-z2E*cbwFL(ZC1 z#aTPb;W{YaJ87>tY2tH#Z=mzbc{1T&00b#G#72f^;Gw#1p!J{GlZym1)NOL>85#62 znhhk>I6E=fZ4btqZDQHP4HaasQ<(JwkBodZ?13y(1_H>jF{X_Byx0VnZ1j|E{Qs79 ztcf3G|L`b@kyIJK`5`?)IyhfR z;XX}CmuwbvBKeW&dJ|iCw5i95qu#i9PNH1BxU4h+A%h=u6gYqUdc=TB}=XD0ZsLwsbCIm zC%#upMoxU~=G!J&JiBCVnAi&-nIrwRq9>==G416tM~1JEo}8k_=o!l_a_A_ve~ZSV zG|C8=N*UylspLGcD6*WA+qiHx&Y2@dZGBg}N15#4>k$bXj4u*_rYW4X99&{G;M@oE zU&f2ybw>ovLR0f-RZXbda#$u)4A-Fpqj zJdS6ZWUT9>)k<2N`EOLDSR9w@?sI!mv4a2i5iswvONF25V`@Ugow_pvu1qZ<@ulc0l zA_QdyPt(m|`ofEwi&^q=OWBAFk>-IiYKA$#0ao-AF1|x$cKgi%-#<7|9ORLNiIT`g z-9TIy;$FNXWG#_sberw4m zpe%kd$d5EsT*43xyikvA2;@`3v>JJqscl}Ir^LX}#+OOk6`zpJcyK1*{|>#Vd2m-l zV;-3d^qv{YxuSn17r!Ysi3SjE@5et*hE8*~VW02+EL-v5pRQ$qc9V36lOYFUup3@H zACmu`OJ7`-xyLZmii1|a5X>hSoocJ7+`I!t%kwb>4^~>&K#pz0RTpvcL7bbO9(uqI z{>4uH5U!75^a^KG2RUfwQ`TVo-h?0YYTr8Z%3S?S_=Eg`N)&t6sLyh+(SGDVbPWe7 zR{jDY$(4k)wm+6+bF}}^4wSNs9?s1xL*?Cl^F-IEzVbL4r^_b`KV8?UlE8bmz zaX3a-J*?c%@v?UN+|gOob2v?Y+7dMwxsUntcrdVDm>-~j>2-S;0S>=ctR7pgormV8#dkod&VkO6rw=8nit#81w<_DIin+d^ptv*P;r7yk z!XUS8yH~?BgDant;lj=5DS#GIC3JXC|8Fqypl-Zx(WFNtMeDTWvB_QD= zig2~9&of_#X0AC16E&r1w!k$< zJ%{hr!fwfd<(Wa`w#WP*IMUVn`bH_9Clh?t5fK!ri}`^xqq+EV$Outr*JwQ7WN=|o z@(W8MHWsYqj~Srk8L{bq%d7??zwGwGQqJe#bNUMy>IQdb$99#qjm>>T>z(>(?aN#H8)i=xWF28x6BPX1FmA;a-?cF#SYwJAa*3Hw!prmFU~+fGq3uNS+|G+OkkFaphxwgk z^Z7^WLg=%NW_BnOdnC5^gRQdD50#cL+4=>r?i4PO{zCXqa0Q$=5ZGZ*Fgy40n7!wV z>9NIq;{5cIDbZ&F}K*d)uwo@E9Iv6Sk6iItI_A~P~-}tYCsnZvO4(uw) zmsE-gC1*I?o+pRN_|oYNroRCE6TYO!v1BQ7eF;}Xlbj!#z03AO8Ko@<8kq?Ma@_wU zk6$&4&@4xRi8LOVzv&dLTizl2jVb0J{yo@3HaR_2g@XheMSk0kzqUl@@eKtgzK^*DDz4IQ@ZrHs%Z)iaVaUCzawSRMH#6iNbIop3-4eBxh=# zw@G8$tSIU32#?4#EZqhw8X%w5B7Zg}Sr>Xl+Dx&q1^2_!L7TF?^Tgmj!KJ9xqr1&c zt|kBWiHM8Y(^QvF6P11!{+>rcp3T2U423&YgvXkA#cN1kY!MDtlx8P&e8B zt&X~sc!mN#tK3>b+YEyudzpsGHCivdF^`MU{t)1eZbt4dY+xQg^)=uP0~+DGg2FPj zIX6xCop|ao?@mGH{h%*5mOdhLu)%ILxe-j!+<7ET%AO!J5GevnohPs82y2AL{TJXH zvWPgc-#Poz4$jj=tnP}F$yY7}MLe53j9(?&z}Kt`ZI!*r&so%2Nqmu62j|C%hHBlL z<-WM!|5xNq{S$~mz^Zw)i9xt(vM-6#6|_{k#QO`dB=X?%oDS*PU5~SFqQ-bsONNQo zgKM^sp5l&;5Z;B<&w2LxsB)NDVkpgnYtGbQ!wxs4TBEk@#Z{Ol6e;QsSCDYq;}h? zkp(OynZzL}{9l*`W(Z$}IfRkQ%wwbCjQhI~g}QIK%R&vp1>Th>aFWY%DUTIejfYk_ zskrgW;QVQjJb^8(3<-Yz{wPVOU!Wg{@;DwDZSO|ZS1h+-rTk7=Y>}o`+`cr1hm7zv z7k<}nHoq9+;4f{2tIP@zANEL!wTvN%O#0JF{7R41AI=Y z(#U_H{xC(baFdzjbc07|dW`c6Fd-Dj&>pKT!{S_r|Fg3NBvHOUj+pviri^|%G|@~) zZ~f>tIZyA??M)0m+WoRi?7Z9pRX5k#FVq^wXF(cTT2Fq%0DU()c$ASrOU5-a!0}r< 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À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

    u*%FWx?k8gR9ejuwHHCT@6 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%0DlYpBreD-iZh`m=g7p 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 literal 0 HcmV?d00001 From bbd451433f86600d3a01e13ba271cc06bff902d9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 20 May 2014 07:43:11 +0200 Subject: [PATCH 2633/4212] add --url support for __package_yum Signed-off-by: Nico Schottelius --- cdist/conf/type/__package_yum/gencode-remote | 12 ++++++++++-- cdist/conf/type/__package_yum/man.text | 5 +++++ cdist/conf/type/__package_yum/parameter/optional | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__package_yum/gencode-remote b/cdist/conf/type/__package_yum/gencode-remote index 5f0e8ac8..32a794a0 100755 --- a/cdist/conf/type/__package_yum/gencode-remote +++ b/cdist/conf/type/__package_yum/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. # @@ -27,6 +27,14 @@ else name="$__object_id" fi +# Support installing from an URL +if [ -f "$__object/parameter/url" ]; then + install_name="$(cat "$__object/parameter/url")" +else + install_name="$name" +fi + + state_should="$(cat "$__object/parameter/state")" if grep -q -E "(centos|redhat|amazon)" "$__global/explorer/os"; then @@ -47,7 +55,7 @@ fi case "$state_should" in present) - echo yum $opts install \"$name\" + echo yum $opts install \"$install_name\" ;; absent) echo yum $opts remove \"$name\" diff --git a/cdist/conf/type/__package_yum/man.text b/cdist/conf/type/__package_yum/man.text index d958dd1e..65e1be67 100644 --- a/cdist/conf/type/__package_yum/man.text +++ b/cdist/conf/type/__package_yum/man.text @@ -27,6 +27,8 @@ name:: state:: Either "present" or "absent", defaults to "present" +url:: + URL to use for the package EXAMPLES @@ -41,6 +43,9 @@ __package_yum python --state present --name python2 # Remove obsolete package __package_yum puppet --state absent + +__package epel-release-6-8 \ + --url http://mirror.switch.ch/ftp/mirror/epel/6/i386/epel-release-6-8.noarch.rpm -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__package_yum/parameter/optional b/cdist/conf/type/__package_yum/parameter/optional index 1b423dc4..9293119d 100644 --- a/cdist/conf/type/__package_yum/parameter/optional +++ b/cdist/conf/type/__package_yum/parameter/optional @@ -1,2 +1,3 @@ name state +url From 004e90e9b916a87d1c085d85c847cc4119d91996 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 20 May 2014 07:46:35 +0200 Subject: [PATCH 2634/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index e40dd5c0..4514a2c9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius +3.1.6: + * Type __package_yum: Support retrieving package via URL + 3.1.5: 2014-05-05 * Type __zypper_repo: Automatically import gpg keys (Daniel Heule) * Type __zypper_service: Automatically import gpg keys (Daniel Heule) From 9bac6da6c934e92597a93efd64587466c8cf244b Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 9 Jun 2014 15:42:17 +0200 Subject: [PATCH 2635/4212] bugfix emerge type for slotted packages --- .../conf/type/__package_emerge/gencode-remote | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/cdist/conf/type/__package_emerge/gencode-remote b/cdist/conf/type/__package_emerge/gencode-remote index d4cee37e..f72d982a 100644 --- a/cdist/conf/type/__package_emerge/gencode-remote +++ b/cdist/conf/type/__package_emerge/gencode-remote @@ -33,26 +33,32 @@ else state_should="present" fi +if [ -f "$__object/parameter/version" ]; then + version="$(cat "$__object/parameter/version")" +else + version="" +fi + +if [ ! -z "$version" ]; then + name="=$name-$version" +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 +elif [ ! -z "$version" -a $(echo "$pkg_version" | wc -l) -gt 1 ]; then + echo "Package name is not unique! The following packages are installed:" + echo "$pkg_version" + exit 1 +elif [ -z "$version" -a $(echo "$pkg_version" | cut -d " " -f 1 | sort | uniq | wc -l) -gt 1 ]; then echo "Package name is not unique! The following packages are installed:" echo "$pkg_version" exit 1 else state_is="present" - installed_version="$(echo "$pkg_version" | cut -d " " -f 2)" + installed_version="$(echo "$pkg_version" | cut -d " " -f 2 | tail -n 1)" 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 From 90acfc3952c09afbbbf72ef9a1883ae8358ca456 Mon Sep 17 00:00:00 2001 From: Manuel Hutter Date: Tue, 10 Jun 2014 19:19:26 +0200 Subject: [PATCH 2636/4212] Fixed stat on OSX --- cdist/conf/type/__ccollect_source/explorer/stat | 11 ++++++++++- cdist/conf/type/__directory/explorer/stat | 9 ++++++++- cdist/conf/type/__file/explorer/stat | 9 +++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__ccollect_source/explorer/stat b/cdist/conf/type/__ccollect_source/explorer/stat index 298221b7..3b6f3dc3 100755 --- a/cdist/conf/type/__ccollect_source/explorer/stat +++ b/cdist/conf/type/__ccollect_source/explorer/stat @@ -25,7 +25,7 @@ destination="/$__object_id" os=$("$__explorer/os") case "$os" in - "freebsd") + "freebsd"|"openbsd") # FIXME: should be something like this based on man page, but can not test stat -f "type: %ST owner: %Du %Su @@ -35,6 +35,15 @@ size: %Dz links: %Dl " "$destination" ;; + "macosx") + stat -f "type: %HT + owner: %Du %Su + group: %Dg %Sg + mode: %Op %Sp + size: %Dz + links: %Dl + " "$destination" + ;; *) stat --printf="type: %F owner: %u %U diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat index d8cdbb9e..6e021cdb 100755 --- a/cdist/conf/type/__directory/explorer/stat +++ b/cdist/conf/type/__directory/explorer/stat @@ -25,7 +25,7 @@ destination="/$__object_id" os=$("$__explorer/os") case "$os" in - "freebsd") + "freebsd"|"openbsd") # FIXME: should be something like this based on man page, but can not test stat -f "type: %ST owner: %Du %Su @@ -33,6 +33,13 @@ group: %Dg %Sg mode: %Op %Sp " "$destination" ;; + "macosx") + stat -f "type: %HT + owner: %Du %Su + group: %Dg %Sg + mode: %Op %Sp + " "$destination" + ;; *) stat --printf="type: %F owner: %u %U diff --git a/cdist/conf/type/__file/explorer/stat b/cdist/conf/type/__file/explorer/stat index 52570379..876988f0 100755 --- a/cdist/conf/type/__file/explorer/stat +++ b/cdist/conf/type/__file/explorer/stat @@ -33,6 +33,15 @@ group: %Dg %Sg mode: %Op %Sp size: %Dz links: %Dl +" "$destination" + ;; + "macosx") + stat -f "type: %HT +owner: %Du %Su +group: %Dg %Sg +mode: %Op %Hp +size: %Dz +links: %Dl " "$destination" ;; *) From 8a70343e2c2606a444e3c88a91125690a3b9f4d1 Mon Sep 17 00:00:00 2001 From: Manuel Hutter Date: Tue, 10 Jun 2014 19:48:02 +0200 Subject: [PATCH 2637/4212] Fixed wrong mode format for stat on OSX. --- cdist/conf/type/__ccollect_source/explorer/stat | 2 +- cdist/conf/type/__directory/explorer/stat | 2 +- cdist/conf/type/__file/explorer/stat | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__ccollect_source/explorer/stat b/cdist/conf/type/__ccollect_source/explorer/stat index 3b6f3dc3..7c86d94f 100755 --- a/cdist/conf/type/__ccollect_source/explorer/stat +++ b/cdist/conf/type/__ccollect_source/explorer/stat @@ -39,7 +39,7 @@ links: %Dl stat -f "type: %HT owner: %Du %Su group: %Dg %Sg - mode: %Op %Sp + mode: %Lp %Sp size: %Dz links: %Dl " "$destination" diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat index 6e021cdb..077aa43b 100755 --- a/cdist/conf/type/__directory/explorer/stat +++ b/cdist/conf/type/__directory/explorer/stat @@ -37,7 +37,7 @@ mode: %Op %Sp stat -f "type: %HT owner: %Du %Su group: %Dg %Sg - mode: %Op %Sp + mode: %Lp %Sp " "$destination" ;; *) diff --git a/cdist/conf/type/__file/explorer/stat b/cdist/conf/type/__file/explorer/stat index 876988f0..00e34cca 100755 --- a/cdist/conf/type/__file/explorer/stat +++ b/cdist/conf/type/__file/explorer/stat @@ -39,7 +39,7 @@ links: %Dl stat -f "type: %HT owner: %Du %Su group: %Dg %Sg -mode: %Op %Hp +mode: %Lp %Sp size: %Dz links: %Dl " "$destination" From 17504975a6a803c2fa78db698b62f1f2d0c0eab2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 10 Jun 2014 23:15:21 +0200 Subject: [PATCH 2638/4212] suse support for __timezone Signed-off-by: Nico Schottelius --- cdist/conf/type/__timezone/manifest | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__timezone/manifest b/cdist/conf/type/__timezone/manifest index 81de0217..36caab72 100755 --- a/cdist/conf/type/__timezone/manifest +++ b/cdist/conf/type/__timezone/manifest @@ -27,13 +27,18 @@ os=$(cat "$__global/explorer/os") case "$os" in archlinux|debian|ubuntu) - __package tzdata --state present - require="__package/tzdata" __link /etc/localtime \ - --source "/usr/share/zoneinfo/${timezone}" \ - --type symbolic + package=tzdata + ;; + suse) + package=timezone ;; *) echo "Unsupported OS $os" >&2 exit 1 ;; esac + +__package "$package" --state present +require="__package/$package" __link /etc/localtime \ + --source "/usr/share/zoneinfo/${timezone}" \ + --type symbolic From 13943e710c3465a11574da22b1e5a57bbc8d362b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 10 Jun 2014 23:28:07 +0200 Subject: [PATCH 2639/4212] ++changes(3.1.6) Signed-off-by: Nico Schottelius --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 4514a2c9..c6f9b242 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,8 @@ Changelog 3.1.6: * Type __package_yum: Support retrieving package via URL + * Type __timezone: Support SuSE + * Type __hostname: Support SuSE and have CentOS use sysconfig value 3.1.5: 2014-05-05 * Type __zypper_repo: Automatically import gpg keys (Daniel Heule) From 3592a0c6dd4e2ac590dad4931f19ea34367c5f31 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 10 Jun 2014 23:50:53 +0200 Subject: [PATCH 2640/4212] +suse support in __locale and __hostname Signed-off-by: Nico Schottelius --- cdist/conf/type/__hostname/explorer/hostname_file | 4 ++++ cdist/conf/type/__hostname/gencode-remote | 12 ++++++++++-- cdist/conf/type/__hostname/manifest | 2 +- cdist/conf/type/__locale/manifest | 3 +++ docs/changelog | 3 ++- 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__hostname/explorer/hostname_file b/cdist/conf/type/__hostname/explorer/hostname_file index ed28c8a8..6a00aa9f 100755 --- a/cdist/conf/type/__hostname/explorer/hostname_file +++ b/cdist/conf/type/__hostname/explorer/hostname_file @@ -21,6 +21,10 @@ # Retrieve the contents of /etc/hostname # +# Almost any distribution if [ -f /etc/hostname ]; then cat /etc/hostname +# SuSE +elif [ -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 eec3bc9f..576f80bf 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -28,14 +28,14 @@ fi os=$(cat "$__global/explorer/os") name_running=$(cat "$__global/explorer/hostname") name_config=$(cat "$__object/explorer/hostname_file") -name_sysconfig=$(cat "$__object/explorer/hostname_file") +name_sysconfig=$(cat "$__object/explorer/hostname_sysconfig") has_hostnamectl=$(cat "$__object/explorer/has_hostnamectl") ################################################################################ # If everything is ok -> exit # case "$os" in - archlinux|debian|ubuntu) + archlinux|debian|suse|ubuntu) if [ "$name_config" = "$name_should" -a "$name_running" = "$name_should" ]; then exit 0 fi @@ -45,6 +45,10 @@ case "$os" in exit 0 fi ;; + *) + echo "Unsupported os: $os" >&2 + exit 1 + ;; esac ################################################################################ @@ -63,5 +67,9 @@ else centos) echo "hostname '$name_should'" ;; + suse) + echo "hostname '$name_should'" + echo "printf '%s\n' '$name_should' > /etc/HOSTNAME" + ;; esac fi diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest index b6985c1c..448e56da 100755 --- a/cdist/conf/type/__hostname/manifest +++ b/cdist/conf/type/__hostname/manifest @@ -34,7 +34,7 @@ not_supported() { } case "$os" in - archlinux|debian|ubuntu) + archlinux|debian|suse|ubuntu) # handled in gencode-remote : ;; diff --git a/cdist/conf/type/__locale/manifest b/cdist/conf/type/__locale/manifest index f3d75d59..ac953662 100644 --- a/cdist/conf/type/__locale/manifest +++ b/cdist/conf/type/__locale/manifest @@ -29,6 +29,9 @@ case "$os" in # Debian needs a seperate package __package locales --state present ;; + suse) + : + ;; *) echo "Sorry, do not know how to handle os: $os" >&2 echo "Please edit the type ${__type##*/} to fix this." >&2 diff --git a/docs/changelog b/docs/changelog index c6f9b242..26bc688d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,8 +7,9 @@ Changelog 3.1.6: * Type __package_yum: Support retrieving package via URL - * Type __timezone: Support SuSE * Type __hostname: Support SuSE and have CentOS use sysconfig value + * Type __locale: Support SuSE + * Type __timezone: Support SuSE 3.1.5: 2014-05-05 * Type __zypper_repo: Automatically import gpg keys (Daniel Heule) From 76d91e4b595a733c152bb5fc74fe6ac3650022aa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 11 Jun 2014 00:36:12 +0200 Subject: [PATCH 2641/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 26bc688d..094e140e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,7 @@ Changelog * Type __hostname: Support SuSE and have CentOS use sysconfig value * Type __locale: Support SuSE * Type __timezone: Support SuSE + * Type __file: Support MacOS X (Manuel Hutter) 3.1.5: 2014-05-05 * Type __zypper_repo: Automatically import gpg keys (Daniel Heule) From 8e060a1d838c38081eda0c8fb796cddaec20593d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 13 Jun 2014 13:51:03 +0200 Subject: [PATCH 2642/4212] release 4.0.0pre3 Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 509394d9..a6e11e08 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 +4.0.0pre3: 2014-06-13 + * Update to include changes from cdist 3.1.5 + 4.0.0pre2: 2014-02-14 * Core: Remove archives from generated preos (Steven Armstrong) From 3d82a0d25cda5f3cbbd8e9cb6ac67584f053ed69 Mon Sep 17 00:00:00 2001 From: Markus Koller Date: Fri, 13 Jun 2014 14:56:24 +0200 Subject: [PATCH 2643/4212] Set hostname in preos --- cdist/preos.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/preos.py b/cdist/preos.py index dc400ba9..0aa7eb6f 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -62,6 +62,8 @@ eof # Steven found this out - coyping it 1:1 # fix the bloody 'stdin: is not a tty' problem __line /root/.profile --line 'mesg n' --state absent + +__hostname preos """ class PreOSExistsError(cdist.Error): From 6a2f2352bea4668a63e2d03039bd615b7d70d3d1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 16 Jun 2014 07:57:10 +0200 Subject: [PATCH 2644/4212] new type: __ssh_dot_ssh Signed-off-by: Nico Schottelius --- .../conf/type/__ssh_authorized_keys/man.text | 6 +-- .../conf/type/__ssh_authorized_keys/manifest | 8 +--- cdist/conf/type/__ssh_dot_ssh/explorer/group | 22 ++++++++++ cdist/conf/type/__ssh_dot_ssh/explorer/passwd | 24 ++++++++++ cdist/conf/type/__ssh_dot_ssh/man.text | 44 +++++++++++++++++++ cdist/conf/type/__ssh_dot_ssh/manifest | 44 +++++++++++++++++++ .../__ssh_dot_ssh/parameter/default/state | 1 + .../type/__ssh_dot_ssh/parameter/optional | 1 + 8 files changed, 141 insertions(+), 9 deletions(-) create mode 100755 cdist/conf/type/__ssh_dot_ssh/explorer/group create mode 100755 cdist/conf/type/__ssh_dot_ssh/explorer/passwd create mode 100644 cdist/conf/type/__ssh_dot_ssh/man.text create mode 100755 cdist/conf/type/__ssh_dot_ssh/manifest create mode 100644 cdist/conf/type/__ssh_dot_ssh/parameter/default/state create mode 100644 cdist/conf/type/__ssh_dot_ssh/parameter/optional diff --git a/cdist/conf/type/__ssh_authorized_keys/man.text b/cdist/conf/type/__ssh_authorized_keys/man.text index 9fd683fd..2e4202a7 100644 --- a/cdist/conf/type/__ssh_authorized_keys/man.text +++ b/cdist/conf/type/__ssh_authorized_keys/man.text @@ -12,9 +12,9 @@ DESCRIPTION ----------- Adds or removes ssh keys from a authorized_keys file. -This type also manages the directory containing the authorized_keys -file and sets strict ownership and permissions. You can disable this feature -with the --noparent boolean parameter. +This type uses the __ssh_dot_ssh type to the directory containing +the authorized_keys file. +You can disable this feature with the --noparent boolean parameter. The existence, ownership and permissions of the authorized_keys file itself are also managed. This can be disabled with the --nofile boolean parameter. It is diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 1c9df208..5885ec77 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -40,12 +40,8 @@ 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 - # has the right permissions. - ssh_directory="${file%/*}" - __directory "$ssh_directory" --state present --parents \ - --owner "$owner" --group "$group" --mode 0700 - export require="__directory/$ssh_directory" + __ssh_dot_ssh "$owner" + export require="__ssh_dot_ssh/$owner" fi if [ ! -f "$__object/parameter/nofile" ]; then # Ensure that authorized_keys file exists and has the right permissions. diff --git a/cdist/conf/type/__ssh_dot_ssh/explorer/group b/cdist/conf/type/__ssh_dot_ssh/explorer/group new file mode 100755 index 00000000..cdea6fe7 --- /dev/null +++ b/cdist/conf/type/__ssh_dot_ssh/explorer/group @@ -0,0 +1,22 @@ +#!/bin/sh +# +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +gid="$("$__type_explorer/passwd" | cut -d':' -f 4)" +getent group "$gid" || true diff --git a/cdist/conf/type/__ssh_dot_ssh/explorer/passwd b/cdist/conf/type/__ssh_dot_ssh/explorer/passwd new file mode 100755 index 00000000..3fbad06f --- /dev/null +++ b/cdist/conf/type/__ssh_dot_ssh/explorer/passwd @@ -0,0 +1,24 @@ +#!/bin/sh +# +# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 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 . +# + +owner="$__object_id" + +getent passwd "$owner" || true diff --git a/cdist/conf/type/__ssh_dot_ssh/man.text b/cdist/conf/type/__ssh_dot_ssh/man.text new file mode 100644 index 00000000..2cd2001c --- /dev/null +++ b/cdist/conf/type/__ssh_dot_ssh/man.text @@ -0,0 +1,44 @@ +cdist-type__ssh_dot_ssh(7) +========================== +Nico Schottelius + + +NAME +---- +cdist-type__ssh_dot_ssh - Manage .ssh directory + + +DESCRIPTION +----------- +Adds or removes .ssh directory to a user home. + +This type is being used by __ssh_authorized_keys. + +OPTIONAL PARAMETERS +------------------- +state:: + if the directory should be 'present' or 'absent', defaults to 'present'. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure root has ~/.ssh with the right permissions +__ssh_dot_ssh root + +# Nico does not need ~/.ssh anymore +__ssh_dot_ssh nico --state absent +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__ssh_authorized_keys(7) + + +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/__ssh_dot_ssh/manifest b/cdist/conf/type/__ssh_dot_ssh/manifest new file mode 100755 index 00000000..2145cf40 --- /dev/null +++ b/cdist/conf/type/__ssh_dot_ssh/manifest @@ -0,0 +1,44 @@ +#!/bin/sh +# +# 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 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 . +# +# Hacked in Kalamata, Greece +# + +owner="$__object_id" +state="$(cat "$__object/parameter/state") + +group="$(cut -d':' -f 1 "$__object/explorer/group")" +if [ -z "$group" ]; then + echo "Failed to get owners group from explorer." >&2 + exit 1 +fi + +home="$(cut -d':' -f 6 "$__object/explorer/passwd")" +if [ -z "$home" ]; then + echo "Failed to get home directory from explorer." >&2 + exit 1 +fi +ssh_directory="${home}/.ssh" + +# Ensure that the directory in which the authorized_keys shall be exists and +# has the right permissions. +__directory "$ssh_directory" \ + --state "$state" \ + --owner "$owner" --group "$group" --mode 0700 diff --git a/cdist/conf/type/__ssh_dot_ssh/parameter/default/state b/cdist/conf/type/__ssh_dot_ssh/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__ssh_dot_ssh/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__ssh_dot_ssh/parameter/optional b/cdist/conf/type/__ssh_dot_ssh/parameter/optional new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/cdist/conf/type/__ssh_dot_ssh/parameter/optional @@ -0,0 +1 @@ +state From 379c1da0076fe4921f7014c67a7d9fcbdf91ebba Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 16 Jun 2014 07:57:40 +0200 Subject: [PATCH 2645/4212] ++changes(3.1.6) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 094e140e..f18a18e7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog 3.1.6: + * New Type: __ssh_dot_ssh * Type __package_yum: Support retrieving package via URL * Type __hostname: Support SuSE and have CentOS use sysconfig value * Type __locale: Support SuSE From d294a2c28eac3289bcaecdd6cf8686f60c2b3249 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 16 Jun 2014 08:02:41 +0200 Subject: [PATCH 2646/4212] +" Signed-off-by: Nico Schottelius --- cdist/conf/type/__ssh_dot_ssh/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__ssh_dot_ssh/manifest b/cdist/conf/type/__ssh_dot_ssh/manifest index 2145cf40..4b797afb 100755 --- a/cdist/conf/type/__ssh_dot_ssh/manifest +++ b/cdist/conf/type/__ssh_dot_ssh/manifest @@ -22,7 +22,7 @@ # owner="$__object_id" -state="$(cat "$__object/parameter/state") +state="$(cat "$__object/parameter/state")" group="$(cut -d':' -f 1 "$__object/explorer/group")" if [ -z "$group" ]; then From 7674cf139b449854d70566293a7e875fbc83e1e5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 16 Jun 2014 08:04:22 +0200 Subject: [PATCH 2647/4212] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index f18a18e7..b1ccdc6f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -12,6 +12,7 @@ Changelog * Type __locale: Support SuSE * Type __timezone: Support SuSE * Type __file: Support MacOS X (Manuel Hutter) + * Type __ssh_authorized_key: Use new type __ssh_dot_ssh 3.1.5: 2014-05-05 * Type __zypper_repo: Automatically import gpg keys (Daniel Heule) From c36fba4b996c084f83e8d4c4f91b050d3c37ed2b Mon Sep 17 00:00:00 2001 From: Manuel Hutter Date: Tue, 17 Jun 2014 19:04:22 +0200 Subject: [PATCH 2648/4212] Fixed global explorers on OSX --- cdist/conf/explorer/cpu_cores | 23 ++++++++++++++++------- cdist/conf/explorer/cpu_sockets | 21 +++++++++++++++------ cdist/conf/explorer/memory | 16 +++++++++++++--- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/cdist/conf/explorer/cpu_cores b/cdist/conf/explorer/cpu_cores index efabc848..25d91f79 100755 --- a/cdist/conf/explorer/cpu_cores +++ b/cdist/conf/explorer/cpu_cores @@ -22,10 +22,19 @@ # FIXME: other system types (not linux ...) -if [ -r /proc/cpuinfo ]; then - cores="$(cat /proc/cpuinfo | grep "core id" | sort | uniq | wc -l)" - if [ ${cores} -eq 0 ]; then - cores="1" - fi - echo "${cores}" -fi +os=$("$__explorer/os") +case "$os" in + "macosx") + echo "$(sysctl -n hw.physicalcpu)" + ;; + + *) + if [ -r /proc/cpuinfo ]; then + cores="$(cat /proc/cpuinfo | grep "core id" | sort | uniq | wc -l)" + if [ ${cores} -eq 0 ]; then + cores="1" + fi + echo "$cores" + fi + ;; +esac diff --git a/cdist/conf/explorer/cpu_sockets b/cdist/conf/explorer/cpu_sockets index 98836cec..42acac1c 100755 --- a/cdist/conf/explorer/cpu_sockets +++ b/cdist/conf/explorer/cpu_sockets @@ -22,10 +22,19 @@ # FIXME: other system types (not linux ...) -if [ -r /proc/cpuinfo ]; then - sockets="$(cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l)" - if [ ${sockets} -eq 0 ]; then - sockets="$(cat /proc/cpuinfo | grep "processor" | wc -l)" +os=$("$__explorer/os") +case "$os" in + "macosx") + echo "$(system_profiler SPHardwareDataType | grep "Number of Processors" | awk -F': ' '{print $2}')" + ;; + + *) + if [ -r /proc/cpuinfo ]; then + sockets="$(cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l)" + if [ ${sockets} -eq 0 ]; then + sockets="$(cat /proc/cpuinfo | grep "processor" | wc -l)" + fi + echo "${sockets}" fi - echo "${sockets}" -fi + ;; +esac diff --git a/cdist/conf/explorer/memory b/cdist/conf/explorer/memory index 982b5dfa..c7dc9fb3 100755 --- a/cdist/conf/explorer/memory +++ b/cdist/conf/explorer/memory @@ -22,6 +22,16 @@ # FIXME: other system types (not linux ...) -if [ -r /proc/meminfo ]; then - echo "$(cat /proc/meminfo | grep "MemTotal:" | awk '{print $2}')" -fi +os=$("$__explorer/os") +case "$os" in + "macosx") + let memsize=$(sysctl -n hw.memsize)/1024 + echo "$memsize" + ;; + + *) + if [ -r /proc/meminfo ]; then + echo "$(cat /proc/meminfo | grep "MemTotal:" | awk '{print $2}')" + fi + ;; +esac From a0d5e57ca8bfb1cf297e7eb0856e62809fc8636d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 17 Jun 2014 16:47:39 -0400 Subject: [PATCH 2649/4212] add openclouddays presentation Signed-off-by: Nico Schottelius --- docs/speeches/2014-06-10_openclouddays.odp | Bin 0 -> 1111801 bytes .../2014-06-10_openclouddays_teaser.odp | Bin 0 -> 639693 bytes .../2014-06-10_openclouddays_teaser.pdf | Bin 0 -> 723282 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/speeches/2014-06-10_openclouddays.odp create mode 100644 docs/speeches/2014-06-10_openclouddays_teaser.odp create mode 100644 docs/speeches/2014-06-10_openclouddays_teaser.pdf diff --git a/docs/speeches/2014-06-10_openclouddays.odp b/docs/speeches/2014-06-10_openclouddays.odp new file mode 100644 index 0000000000000000000000000000000000000000..e85451c8a6320c5ffea2f8076a35ad061cdcc131 GIT binary patch literal 1111801 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

    T=>J%Pi*+s37uloRNX))YT0i;?4c0+ig|^ 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

    oeS8F%HnYEo$M~?1j?I)TE8SUbm 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 z%0A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 z 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ìbjQ;>S={#?+PVy4Nd*^DBGwgrQ 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

    5>$V5SVCFjtEJ6r6cq|$D5#(NGl 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 z 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%0A{ro|mo#7%j2>g~9& z!Dj}m*!W@%R$Z|;60y&vVVlW%vKAlCw=`WvVc8-dE=4?suR%ssqN5E7lWm><0EP8w zejcO4DULwH?z!XYE0ggisJi6ObL6VAIpB4!qgR^G#QJ1Pj19uX#OF$y2@%u-fIUX`P0Xsw0N{)R^{!g9l~>OZTHBtvf8z^(5!^#)+mNvNn|Bqs_qtAp zr=_jN$s;2f&TEjhLw z(x8Q7wTu*V&cTCNTE2~?>6gE5aq}<-)Q`fs?K4?@M$HjW$1HgJ>sPg@uJ56T%tZ*j zMhP`Mw|7Ao(Chp?4aNSQHO0CQFB~ogPrYWv95SS(*X=eu%bKEW zcc~+}_pD{REzs10b{*)j?rsa3e0Lu8hL@bqpu_??sqg(ujjrK>2GXJDz&gxbB8I zH4PM*Uix={Reyrq#$|0jhFp4o-8Lt0HX~ zCaOtr2Nkl4GIC~+ybd|2o={C@8>}9*({?>-)J4o)l0a&tvf$J&b)NNJN%DHuiX=8p z^HhF+y;OPq>LYPlSc{q>e|mb)gIRxQr57IbSa&tjEtciF$9jO>d({`X-QJ>W zkiF|m5MOJoP%nV*Sub`EdV))^qdBKwxno|x4zZ}M?Ke;nTE@A?7QF9L)*@@9LfAPK zw+5=4KvwNpSvfNAWOip!4tmtk+=nBYsnTqk0AtRhZ_QCSsRRG8k6lC1z-(H zpaV49ooyB)mdDnyT!xr+X3Bg zsHL4miifGE2F+t?R}Poa1YO+nMF|PJ8&^{Zqrl~=j8=wL^CkQNt1v`c4a8kOB3RQm6%$QNekv#8uEa8RmzthAYdv0`vf_&c%|w!>St~6r zDs{NedWMTk(@82(C%tA1j1IK%bAi^OqONH9oKks}NL**VJ!J>ID-PwqGMZ$n#%xk~ z*`mN(Sxrgig&8LmnD=WRxuQ0EgO)p1orQAi-L$7_4AhXs7nk{(qK(ou!irxz(vZty zN_db}AuTVRO2fIK!-|GTLFrH})&(|Orw~an7c!S3>M-HQ?Ng@u2 z4i`1b-q^T6OL2~QuRf+Dq;v;&xo+ph7dnooJ=N5$Jf8hoVr%2-&Dmqt* z�xX!HgW5_8*7xESeKAImi{}){9>A>UCj0GlcQ6 zW2uw+)?LP;A-94zI2%tDg*4kq9)=_MOsI9K9iAm^pz&F^J{ghsOwL<%EyPF}r$+pZ zTF`E#)UJHCZ;%{yuU2i-k2HQ~iqXqmMI=ngu#h{{dUb)nxmd>;HR}*)T2#`MmC(8C zT+PmtZKP^4$qNFj$i-z(9HyE|%!?a3#>*cHi%`qIZ{uD`_KzlFr01I3*Zf-ZyGApC z#d3y5nnK4sn(e~TaD#H{ROFqkXviK$U7h%^Mev7%9b%7AnX$BF3gGmC8&46C{Hj5( zYw-TBZ*^d>BIQEk(!AWtyy?M40TjBGd|0CUOGzOBGJASceje(wMK&Z*K{%+j`4Y|v zS9o0Z&tJl&@CKJP)Ne5Rqmf=JSHm?ei?g{~;#&c*8Dp5+BlG5 z%C2jS(QcB?RJbQC>}%Ato7nZeHI$s?d)E#=r0GsAY*JkhFM{!e1;l$r z1J53{b5+sKpDeMS6rM6Fotmwrg9KM^G$#wBKZe1r%N&Pmp?91DvuPU}b!fnCyz(+XD#g`Mia@nxjVYyRWH7-jQtlz`<{vX2`%W<4 zxa;kXYE5!EbxlV~n$zc*!lZ~WGk{k)=m!|)w0to4dX?x^v$PTKQ6!EYHBrYHLO&o0 zuSB-ft#qFz?Zk8HER2DhAPCuuXC;1S$zU=vK_H%Krx?x69T18+o6im@wQFeI(nVBB zytBGc6-EKgcPp%~os>IR%vQf=J{Fga&;^b`!Pj%yJTA zk9m+1PFs_>o|z*(csZ>I^%=bSNQxsVSrobnZv015XwImbO~ zL&ah_AdQ~kp^e7z6aN4bs`WVN2_v^dRDK;>$v=thC%Cs4cB)zy5n;mbQlcaYI<+Jd^E;(INA6F_VQGv+^^Q}1v zxt(clNd=eb#b_<5*oWmH@JD*Hr|D&-7$j$dkz3Gsed0ySg2%DyDlAdSeSw?q00Vai zBBZypmJF+5k%0${XWRK2?Ee7a9F#?nI3tmce=4_a;X^h7M^Jr;?V6T`aAQs}mFiQo z3e~W(+QkZz7=#&8K6 zzMNzAsFE0T$ksv!oTqTwdwpv+5vg3Zlix(@uCh84k-MQkTvq%V$}|EwS7WFcMjL~E zppRSVfx*xD zKb3lxpLrGFRt{XY2?wA!^!!i%0A9Sp*2ykyOhvrLKQ`80LH70fS6854uAgj=3?ZY= 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 E@g|Wy zrRh_X&3mS!W^E_lxxpRll+|>YE{u{of_}AyI@WhITUhgpZ2-*(mPgsgdb4L_EhigW zaP_Tg+cxqHY6z^PjqRlhL8+HKle^HT8#A}?@|gL~cs0v-u$Q`>hf3&l3xTz=e}v+( zwY2jM$?H)~StIE%x=}^n1l+t@Qz#kDb-FoYE(3CF2f>RHXl;@65(RY{Iz)$YKQXT- z5Z5!Y>9gv~GY~fdE1Hz5 zQkT2b;cdr6aC+^8x?JpwDcRcI=t3Ts=%FimxqUbV&sohC83BEF8CdExI5 zPN%79kXx6ESnfV!&H?LP#k9ZLR?leh?n1m0E5r1Oj8cYoWl`7~_CE(}5no%XE;n(> zHS@U2Ud{6-bDg_0#Qb-lzJaR9qy1B{D_HirE#>?kWKpqSP%G2EEa=a9sX&0|b8}ZT z3t#M8Na2zoz>E{^UqeqG7qU8tTPxIJv!&Cej^M)TRH?xPSJ4)F zo}XuOa|k)kc&tws_+Haii|tl%g+IlCQ%^ILs#>IMn4Ou)_%<6$NC7d1d}E&V*jry) z#K&wa^Ltk))(1-nsB(LnmRTmkm4CvbukTxFnVmeb+Fm2VVgqpC;=E(VS~vDyr6Q=p zvEsd3NOzwF+mYN>2aoi)u5DUyGV9G&604CNAxwnrCnz^W>qATSNT>9NXeb$fgKR%2l1;` z@)((LM&fz`GAmCp`khpIfj}c+z~OgvALp8{KC8KaJ9eCMKT%n4cogAs+Eb#{iuF0D-F#b~Xm799L<$pp3GHbK5Q3@c#fjRaDg$SwD6_1C!Y2>0GVd z^s)wB*(8uT_WuAsol-ZB_bHGIZN_uYAO5;&2RxHIiFNqojZ{8l2cOoj+iD_xq{tn1 zgOCs9TotomEZ~Q9Ae^4HwWn%Ngk(?~fB_t1xTf?PoR0R!V$|;cT(dh#I6A$dt*P!ugQ5ZividJh6En8Tpih`eW@^D0M6`W`{TWG zz97^A$^o@;l1E{Rxpg#>L|C`XM|!!F z!Q#6e4gi*qB&))xb{Xh9e=4IiYmY3j18F5d=m6_dz01LEBy4$d4o5-Dx+NMT!`Lb{iPxJm2t7MBBB&3McbzYf1^`EE0%?W82jrk)Ty(>wESpyBxsof)E zip&$xu{Hds%h;GCWO3KjeR|d1J;ZQCWILp9$dTCobxp#_Idu6z2b}R*S`wT4h~QXB zd0a+|wM z2qBmT1asUCqZ#T5>x%Y219%n>2l!|;+zNFYh?(Xp+lujpPql_F<2vD=LyoIvo&;a=SYF`%-P1?%Fqqf#xN<0@y%FVyFF(Tkr(? zR+XNid3B?;ypI{01G!ng?1Lm9o7;h$ae}p% zAd;Z6^z2Fes~+z~mr=Ev;#lFiSY+EQZIH?~lDJ>@Rfk{UK9#W*nzie+4(DkXVY}Vq&;(Rn$0b^;DWR==OEP!`X4{k=|*oqb5vCCO=M(3TpiS`zW71ct5 z(X#?DPXne1>Cd<2iL7an-rKTGq@%&SFP#G(PdqUjM_inB_pX(+$smx*w{VQ9SfpYG zsq??BeCMm%dwGhs_L4Rlrbwb z6I-^|hIq`e9yoBX_cM$V2|l%xaiBJ(`u13CP?t2tupTTKo*Idw2^ z{55Aa+aEp%Ad*e%6!zRg+2?N1-8*|%7x7EM+6I}fYb+v$DBfn7JgC$RH_SM|^{-5t z_fDSJO}QCmZL8%;fZaY)2sk|P{VUA=Bk8&?j3m0A-&$=x=}C?#r;K@b8$Mr@hTJ-1 zEHF|g>36z)-tiDv_hfEhF;{$Rt=(z*Tu{oP8PGEAaB>fR zD{oT1k|`d?Rke7?AxzPL%$>U&5Dy)H8mX%IM@$jKE~k!Is zA7iSNl6!Wp>d-8Ddr5+?AmiS%>6JB@X4Poys)9-pSord;YT{4v5y z{{Y`u{11q|X>;WCW8@>p!#ZldS48-AyMh*&{XS{ut4% zyg8*sXA#0i0*b$8nzI$p3i#FF9Zk$%*w7Mt;8xGUKLX!d=_mVQ5GN${747mhtfwrY zzM`EQ+s1H;27M@0;<^RSdHf@4$jTyIk&czbcz58;dQXb3btcO!ofPyH>n3=Rr0&s zBca{jKJ}Krvu>Fj@|18zYlyx;*SkI{oR3ye7)nSJl7m4&YQYDN|>5eqh@@&Z>P-#@&wAZafqY)Kq(?ZCmW7d5XbK|&1SoMTQ`k-pvl z(j|~9CP?+COW++QHNaeZRTJWdf?!Gvd(@-FCV381k4pIk3ZKl%`o%toRPa`khaxaf z(yb?kG}!*^ApRAZcjAKq`C`ebEj(7lWuW{haH+l73bY&8+_&)UkX(qW#Clbv50ePb zxU30$Xz(0}4k{M$*^`q26@=(jmdvM8D_b2E=(b4P2&0PgUlnV9OZictQ=Yx5{-ffl zZga8{pjR8KU(2Y?k1KZ5$sH@R4TqdQBbuc~`WEDQrnD?%JvipL-D=U`lX|zzPa?Wm zu0^~XTPoP(deYS{-s9y5f$c>o zrr%&lrFDBUH=0kZl(>0`kldi1SJEiqPIhl5?RaD;DTWR-{@x1Rd# zS`xgL=Sr%UyCf-Xp$?6s8|}=}Y*qEG zYY`o!lExgBJ#gF_G-x)TGTYNcWxPD!jG9w zYoyXVQ(-5C=dihj7Gz(Qn0@bRZlSDN-)Irr!59*NGC=0ItCmY#vk{)+v7LA$o)BT(*;`MFbKBKQr(JdM|~%G4`!7Zf=Q? z{{RY+$f>I}O}9OUmbWSJE*U0yYS`Q*5E2LMn@PN zVwTIoR@0%kb=vskw-txhWldVz68-L{hTdK@vFvFWA463vbSZTfcM@PPsjYvA+8_2V zw9%>EA7U#4$5fura>htfJBs&c>rF}>LzTxwb(Y=>SJC|Oar^FZ#z6dPZ4TgR_ew6= zBwo&|Tq)OYW09jtolu;W1c9Gg?feO+9~5d4Lp!rGaCpxYR;4FS)7gZRO6;-Y9YJ+8 zQErDh>@aDTIzo*(US{&&zH6ZI--O47FCkb}nBzEZj4Ok_)ox_IR3V~^rVlm6PLfbm zpzUJ0+@7aZqu4a_{^?1_9C8hJ9v|==`kEWKCGuV~{7cZ+FW_xfDDF%FJkKz8Jw5B! zJU8L%`QwqTZeBTGjKo##B(hQ9=U57ZcHL(DRcpncO>8hzc4qaDc@K*a3>y-eRa)TXS>Js(uL*0uit zDi9e6Bq-$Z=}qyJ8i;8;i2S#VZpb*UUe4+CE9ZFFD*{OQstaEkYWJGy^ErXrV{bVP zN)eKWB3H1jX4^P_75K+c)n!WyqWFmNu5*u}scihIEQDcpzpZ)~k3JdML#BUg$0~_P z+*Nvt@yT^LAU`M|DeGR{I&iH`a&C>eQ&)-5TcOjgk;yBAkZYiS5sgihND)GeWkqmn zt*zNraseI1Ub2~CVs~(BIU*wOoRmzJO-F!ckqY4~>fT|VwMCw>pz?^$|eUQ7i@ zKEzc1Yec3-Bo*jumdc)}i&-9#sQgE|j@@EGjE+8TMPVkhcX>AHWs!U1JXaGQsU_Xg zG=LDN)2($fYp}hl#1Nxnr)ni$r&$X6h1~H;bGe%&diShf6v%I(3dmG1eAVWjDHA1u z`ii+@ZEdXFExedgcp0mv=P9W+R8ws7#f&Y^7uLRu{hoD^pkHQVnB-oBbglN8v>kKz>#=Yz_& zMtW3#68uf4N;bk5cYZ6(4?Ol+^)2C`~R%ee= zi*jusk647App4Z20Bwu-n~$wz+xTKvxZEW9YVFsDm@h0z9jmS5>8Hx4sgj{5(6+!~a6L_FPObI0II;-Yq+ydW5F~e~ zE-m6MkZ{?pl~|{#Dh-w14>~=-mariw2d)BV-Js}@#_ScmIZQgImCt5L9ZCHe}lXxg!zhy9HsJe*QAOBl-Y zL~@Dq^KvRp!9h{;RxV9-FO;c}TjmvVD|p#6$2D4W3?DSFvo!R*wIc#${OdVYk8NgRY_eOK;-ni>k=83I3R@C$#33!Ha zD!{obn)F+X?Y3Z%^ATPl;hjt+)G>p!mH^kb-&jX!qAkgC9D%eGoz&>pQH_UEi1cML!*Yn0P3C7%BPbe8f6Lt}Q+gI!*utl3#xDZ+0fu&$?ygtWDp%NjC7 zml}j>+e!Rum+=}#5J9jxYs{qaWU*O@5T2O8H5QxVJD48{$tOITs(70;%zcIK zdulb{gu0^`{XnTS>;C|>v0h0Wb5*<{;>7;Q33nbHheOh~;cH7w-*_!5ehWpEe)$*2TG`{z~dbaCC7*M{Gb6_Rz5F=;S~wT80M<# z`jW004s+VMx$$y$n>JW@Elk+_Ed-=)<+GgTx9of^ZwhYUn&ul>F%WZFR(>s2h^r6| zJJwZYS*^_-IJ1-SdI0wv1(RyE9}?Kl`aM>T83TDiKrW*m;ypEcTx5?cV8BNn2s zxurE`VBT7@%+B17Di|$Q6Vdlk6*kS4r5;Q0CO?%ps2gn)c^!N{3FoHxPnB6)nvB5TEN{QADp@w!PdWFZ`s3#u^s4ceiP&I@j~;V2>a?zK@1bpV z0P$cqK9yQKt3VQjbc&rRJT&5 z(mT{b&gO}k*G^=go@$(<4nQ2yB<<%Mb5P4O?k619$VDmcT04QxIjxwr7Pwf{o(H{T zeV6Sr?qkJh+d&v0D|D>tREp4^ZA}d~?R zBL?lwaZ0PE)wU*8EuovIT22Uq%Q+{xt!tek=FL8Mm}GIqYw6a8_VzYFfMX2fb7O0E9m8RB-mYWEtlMr14$M(k}S^M9)!O zZ^GR#Si6m0E@LOF3cq=3j)?Movz>ngY8KHWNeS9Jir><0t)2l3f2mrqG@!Gzm@HfQ!ZxiTo#@6i~23X`*lYC^;ZS_4`AF{4Uf0(a&$xfVAli12l zGsf&KT)K^?8T7AJ@ZOpd7})?0IpVJ9UK6#3!Z{_6=L0;7*|redN&+YYrYph4V%1m6 z6B7ND(j-T6^XpU>bk|G>9@TbBy|0is#YJk%HQ8>2SC-w@f;266i(-Ul1GOR)3$>5` z0A8g=RB|#7d8+p*9CB`B!K}HG(0a6JD#IKHk@(awsFao@;2s8gRSB+;F5TE4T12>2 zO}n%2-jcf99;U-X<%GB=Nk1rDc0C>*g34FO*11M>J%B?YM zDz9-^I(7Tp5I10Y6IXBNaLS@WE6-4~ICm@Su?u+%1_Tpavgwbg-ffKr;%lVUl-*jY zhdYPmSo&qt>6)4nM_y~bH5_54;%>;dKZCBV?F5oX$8rTp;rpANCiN6C3E$qm80xU< z`cgzTmc}z!OQ%O`yt?NA^Im$bDv8Eu$984->r+|Q+EsGQq!U@zz9VPYvJ8L)Rn^%p zq;0t>rm-GT2{;(VcfyKLOQ~))Jr_&3w7YWCpab5wW_vjF$BHLhV2%xWMTWX&%s3TSy;cOUd?GPFk9BNb?IWc(-}%_$mXcn!63LGbv-KVx@5YEFiF8Y16NH0!HtWYaJtgt-{0(glbN{pxHs z^UU8QY~MjwY%C_cx)FuJ9d~hx?UHLi5(wA76te9IYfj@pyIvA7%s+*BHJaK+qdr7- z(vmpF(^w- z7N&|H@*kahZJ)v2Ix9r`G)w1^&&|7< zjt_%3i*vgGE^-#U`q`Eq50{-A`x(Z<>6(n%mW$-g2z!Q68p_8%FFE7-{{V$xYAn{W z`9!?3Me>v%b}y(M{<*H!KLTnRbP_3i!Hz)~0P~(}kMUe_Spf%@-fHtUY%(^M|0kxQMe^7%$YBf%-%yyk&aFW;A+BZsU&H(Hr}JElb`;*V%=ECSL@rClB=7aIfd(2SbB0>>L;ADVU|DE{{y{VQ)zf=HPBy!03yD{9wE zNP;X!40{T(2Ao4}-Z?p9JJVJR57W_G0g;Pi(*RZ0v=N=p@d{Ij1IvJS49)Ovd0^~;zv2>9+~_xS-tKn z^dzyB;75rzw6bFuJvx6Xytg7deUc4?fJ--glgIL`>quD+TxHxaKK-%z)rqcrv?56N zIyeY3oa2F?p&6{$)~21DGdd)Uo?FP^EMvEGpMUVLfA}}xFS0yZuBUFFX#@!4#zG!> z_a{GvaQ^@Z{1YyxesxQ=%t*({iH`?@Gy2!jx*f7d0SEyKzcUa=6^y0P9hB+YR&*c> z$Ryf~e|5K>KBqqTHRF&)4x6mZ;FP=D<|~#1Yb%q~_vi8Ez2er+CP)~d8C8vrasb_u ze>{G5yc}yK^r?*TmbRhk%Hi4%f-;O9a#~g!O zT^LFY=*=x(OSaS#$QFo}vSqx3!p2--nmisk7~_lqkQe&lM7SXnA!hH1<65`$1hmNRq&k7=t_)t1)HjGQ)1xL&sr}-=NNI?w>8o z$hVF}n~vgR{{UXO`^AaOpHf%p+Pi6%C`ok*wc8E3SUR76xvIiAWU;tjBxrtN<&6Bl z#5R%Ju01zbB=Hp^rso@iJZ}F0;q1^}yw;Q4M;ZCi;+LWKz&JVJ<2+~9xK9!MHow%T z!`;fWDus?@U8S+c2HcGEo|DQPZbC zjZyKB!<|D;(P4raWtkRc-623S1aX1X`tBL}*R$(7bkC~B+C=c$o#W07q)tFQg=Wg& z^uQxI$9m7z?qw01Y2#H8lAc30ah4|;_81k~u`_~GlR278;yjB`({6lM;hiqw8Ev(_ zCIe}8C>a+}?)}uR0pZgoGQ*MrdJ=m-1AH-S-wvYO!bIpAX%jg|9DM3KFdcuqF`k*O z!%FauksZdLau1h1+}~uG3;c-RF93DqF!sn{+PWPdU$fBly9hxkY#AY$9Q8&}k^p;* z78L4cEk&-3zjf|;UZe1-BDnJ;kpluTZxWUydY0%1;!m}7dQXQfbm$dQA@5pi;tP0~ z#7dGsgp7mhQ!VYbqYQ%Gw@9FpgO&pwN2vX4#;J&%WRabccSoB1Q`N1s*j5w>7>?EB zSJSP|SUIm~@dtt9*Ds8hGURm_JQ3?z5_~n&EmfLH6nm3i?hhM>!_rZAxVPNmz7@vb z@SE5b;BLXMsr*l@-03L@hjU~OhP*RIe-HRaQI6-%jL8|#TIlu9+6zFDkqZVRjN>)$ z;qkPqFLg5sMYFb-#X5jhAT|%HS9@skOQ9K#ckRz6yapeOx^}g78d|PYb*|0Hy!@abA9vf{a2&L8%Fu$1fbteJ>yA9!(I({ZOsF0&*{aCZAPD}&J(X_sDY zv?UnzAXc5ewRI-A$0QSuv{TNgR90(Zo!h!SOGJd}v5?QZ>T_Ccs>XwsADwUys9c!- zR_35cFK*msTz)m2v+OKY-O5yC-iM<{sz%?&KRW7s19@*QxQiiDq<60;x68raP;WQ~RR1+o)ddP-cHO90F^ew-G{DRMRz7TC-=E+4yov z?=LUsTuC&n4XKVf;=0JJ;=no2<5u8?C2W!~E6<)aTHK{a3~{4HD%``<+OET5ioY~N z@~*Lj45q4>;wPnY{b!qWYxRCzna_(N`Kdp855udaDo6Ql# z$G4?an$u6UyN)%GWDNc6*72Bi%@Cjr4 zyO*s)Er*!jZ46T*j@8G(Q*+AQov4E}3ai~ z=Y9;=mrRvrZ}p0M`d6y>d*ei!b?C%p(;IfL821(8_ZFYo*Q~g}&!uYUzEj+(e~=#a z>Q<#0`^e5p&7I$kykT+UO+>pd0AWLQ#d1?XtRi~SVX9H!x_k7 zUp#9b6q>+H8WXii!6U7EWv`2DwFsic(T*Z{jE)6A#<%)4-jGrqgzd=Nfz5MLuR1SI z=8=+GA2ba-F*pPo+0m?HWOb3gVbC$HOHDEvC6SJHgV^-?(6GY{tjnVH#&nB(fT@x41rL*l$ z@ivb>opf#UyKh1&3t1S%h|BYizV*zbb*P%LsSIsyeAiMC_r__rmeRt@b#E&u9Dr-4 z(l0FLurORIhXaF28`?d*mgJrZz!=42?OY!!DN4tl8>#heZGP1$WE@v`w$bVKfvlK@ zAP<*{?OL1w`}L-?OC25@wMKEYjLMf z5=|E?$mAbdc7x+BPSDK^?Yb#4I@dp}S~Fcd%a9o7gG!|E?^P{Gz4d($qC6$=Hha6K zjdcr{zI<&-4SJ4~@J8puvq^FNqjMtdA1sfW>O2=?y!jXxE>!wvu6VCl^L3k*>+@h%GnQPJ`=`>rYuL_naxhYC zzZZy_*>;z!(P|Q1Chf%6AAX}CgPPOR^#&HDLB|!>8c~I$X&p^i)ZNNdjGC5P7KOfL z`D(X^ZnJnx}%~Zj7hXl4SW)1oy0~oho?ubHMdA(pz0Kp$ics z*A5 zO1qIl#S0HnnkrX@{K&s#)wDM4bvWm80L@%*i~tMPxm!67j@g_X`cR&X+Q^j)823H+1^dxHMFn-^|ZE)*a7^tgLPGG=Mfcn&>od5ZcM13#7v)!r22g z+YD6aWi(^;UR2pi!p8pM=m-f&kp1A;{3|QQI@G#Bj@k3(j-xfB;XfWls7X9f1uR(O zG-{s@r11suyq-pV$2cd7H7XH7!dBcHPIA|yekIOEp39X9$sMK{OD z_Nm+9ZL`~iBcE#6(EJjbRC`o$TvW5XH7MFr31DYGBP#A}ra8?|qgkxZehlZ64>s11@M*i8$Yz%la?9hpsGGM@D0z0q%+%sV;qnx)Vw|8D;r%pD0ixy z0gTpX#E%!)$)iY!%4B80?_A3iw`|sQ;!hXpr(&s_0%1mr&Fpw|j>J zJnS{reWo;4-zYiutsNTb!UqxtLjM4jV=ThUL`Sn%y^T#@z)z%T%GQ%QN*5rrZmu>D z4(gh$qB*3(1CmF2? zBraQc8LyoFFKU`PtkK$-SK;0`zIzE7CS*c7D{+eXlf?o_FJukK2D@Wf zwQ^nBFva?;paI2nT40voslh61o&L^ai30TIx_=Jp4H5+^IO=Pfqq@2^ryK5WX}V0t z=^aU29<}RU7oDVyBe|Dyj_u8PZH}fyoN--FldG^`GhTIGXVmMA5?UUkbE#?8kOWA< ze_F|ztgldl0Ipv0{hB=IHIQ|=BYbxBsfwG`$(TuUy-~BSYH6j%vKh9gWgOStMPlRNtRn%1!~dEl=&KDCcD zMF#@}*2jl*xh9olBaGJVt6a@q`W}g--v7>f0F9F8}urGBH z0U)*ytz5p;42p2uYo5B=(iV}pta_-P*b5%=95Oa?IK^ z&g-@K&rw~!hvIuHWkHhF%jxpTEa0~Q{*~NmX^pL(ItOBC#qD7_2>~)>Brol}E{;>X1nc zaQvhJR5c5s>_e{H~t)Wx18LSy$3XH8yiaj+^AD67=#t*q0_2U@uGKyfx~@#5emJYve+sQ3 zA*PdY_iE>!>rL@*gKzHjhLSv#AYlF#(_119V<^KQcKX!1wxuFpNH>62AIiRk)svu{ zbZpWvyRqiF_k*uq(IfJ~Vfa@~;SEny@a>c^M{EuV$)&v3-uCcY#z9~+io2tYNBdO5 zRa!LwoYqpUiG?m{HDYB1p69iAH^&VmaDApU45OZL&3V7Z?+ruoA6&MV18gW)aII^0 z@=B60ewAihlqr=0yo#BlnL%$>)OK*1f3Nv+3zC-6NsVlQ2QJ_chQ6 zEz1q~u6IpPvD@VFo|UC{a+|;h70FR1?szzt`^L@NG>PR48v*T_y(Cza2^@YVxi^{Y z)J(5cW$_HoOEd9Yai`5Iql)KYe2R&=Un3neST<3;_46|xoegC};s(5LD|zSMx(zxJ z4mRZGg?KA4Qn}DsNi-3Vta$aQMx^Nsiz{P2>MKz*rWP`N@lemBUg{Ev(kD^tip6rL z?;0qxDhR{0sF`v}?^NGIxRD*1O7q^j?K{C*mY+D0VcZW~n(5>4o%QTY84@r@rChO; zp|3Hrr73hg+en7XN6X3sxveJF?CuzC!c{GE!*@1%gTdt&8T-H<1$O=%_(^4{SVuhW z%OM<%)s7;)I3-d}>Gl_}n`a=~FXxWlCK5>J0;qVGO1tpo#0ex>^GC{5WLLFmUkfyy zDtPV_nNZ{t&1iV5?2-9XwYQ%neFCV@;aF14X-)E^%^n>!t3G|wZ!Q|}X5LKtZ8h0w zc6XY-w{L44MkblC8cqQBuFlHh9ZOJGZ9mFiR$LnBZnS%O!ace2CQen*;Db|J6$*7N zC83Yi)L!>FuNM3}y3npIyxX{^ico%J;|J3Qxzy0E((7bDG<sj;o)F|2)pK8fQthy5_l-BY$Akx;^vM>j*sV0S`7z_aKgIv=1l1YeTkPk|7_>E%D z=|5V(tIqdqg@R;1^c)$Q;n)UD#l^Tf}(yqC;JP!8WN4=YJg(v&VfsC90xvFh^5)Up00I@40 zs2L>jfO`Nt`kL>&eWFV9OLZJYgo7I}N6-`P*0@!&5wLx#oD;{d^~HU%(Du{lIv}wy zL^(#_obtqU{4>REMR2pkH>WFsxbcs|vFxqa9%8U4i}RK}@&5qpt?OvkQmc-Hd*i?K zs(wb1^DKR;OJ;}!2ny%sKX=ltTj~gsOf6NmH%DW~QT-~U*2{BmBao^>o)q=xkMaB} zt(ziUM-nM^Rl}*{131s*O+#$d)JxAUNmpqkkaq${=}wnYo-~Z$A;B!bWS_66AI_t6 zFsgtHA`VCOKK#^I(ioyu4nAUYgUwQR22&U9X>k(oA3p(z>5@Bo^{ST|gUP6bS1Jww zQge^<{(IG2eWF%*R{=6WC)m*fZX)7B497U&bMI7S+t}T;fM?875xbT?y?-v11kgmf zm9mEOQJY~*_QA^M>5tB=-6`g-{5m+$>cNtXo_w@W~ zq)yi}7r2||&j>kH9)$Y!=CG6OTvhcof3&2&mRMp_5C;ZD843rX`qxk3-wsKr+{YgO z05s0o-?ts`i}Q)iNcp&2YWZvOzTYnF!IJ0$`(4h!a<0;WSS10yw)J66YKWdM}{+I~-%{{XTv$*jK-d_A}EzL%(Jvg{Wy;q9JI1a1ca zk=Xpoe?HZvq%jbpvvZube~1tAD|<(>d2X6`rwG6VWIY&wJLjP}=h~*)52^AMj;9@_ zv2mwsa7|@@1GHua!w^##=i86Z-n%~wc-~zO;yCYRGTRpm9Lvto56XY1sIJ@N*T8o1 zze-n*nhCmwB#WqxtNuWd+y6) zKbC(=!gL(hxKga6@t&pPKZkZY{PF5KB* z*6~lK_=3R3>_$@JJ*wbz&Nu{Qkjsv|5u8?XrBagp;?T)er#JhzbIklREY?>7Np3~K zk+Q1ow3EQ(jy*vh-+1I#qeo&qK@4(5Fp5~>5g6oi^6lUazQALQ`qb_4f=x=+OPvbp zJLFHB$!AkMcpW&vao3&?udQQQT+JJWk?}kkMR=DaFh6y{=eQp*!OtBl7tIY;!~NY$ zuBKkGV=aubTWVIwWDGMtFj#sLI6q!V$6hO$*1R&%$d?*%FvtLKV?ni)_vi9C`c-AZ3q$G*~NA7X_$o3V?-f2^KcU4F(6U?>TcDj7y9{!+%jCJJJk%VWf zN1a-lTb?EH3rD!K(_z2UqK&MZ{y$@QU1Yar;2)TP$VmPi{Z9n(7CJiG+RrV;{Fgd= zIY*9Y)wZeG1BRV5qfd9`V{*_?`7+S*Sn3dLuL0L*@9q)dFQ zps{VGc<;a*R~@V9w;C19g6sV%*t@iI?hLzu`=E~b1Y_&PdX1)**E8vt`b(+3vcyKp zP!!0y&e7LBS#jJD2SHg{wuK&}9rB|rdt)TV%1-G4QXjX>PVD~xylb9SBP|X&Lzx~~ z1=PSj(3{K&D0Df-7-t-Is*uk-S7^;9j#37vIAzMe+5T+pj@BcuL~|YBhkHnwUfnB+Tv6uwMfg= zCAYbWFCZH&C&_sFwY;CiJxK07SKJ(VC&fASD>>5I7ue1ND=EljJs2L~*ScGHQav@D z8S@N)2Tq{lki*=6QaTe@`nSW2d(yE_FPm(Hyg4~BX~;Z4tnErjX|O^!jU_L^3`JpTYCxm5?!y^ec`LB8+8`J%xjwLgVR3bp0uCaG=*ICZi@ZxbyE&3&tvP$MdAAORS0d%zu>b zVofm@je@!RtJ^DWd*$269V-d181cLFtf{5WsI9vv0M}*~hradb#PK&)Q9Ug+n`D2O z4{CAO;|Jsw#~YwX9qIo7X;Qyn{Eb%{oXXfOn#33Ta(Di;&$sVlbH!<7x){3i?sQG6 zO1M30DYdB^jzwj`t3}GW8Kz09!N0aCsCgEvP4zTeQ;-jpjSH#EkG^qP$5MgLDWd)m z{c~FKc?Y$V>S_M~YfB$;Y0IpM?wR)%jkqGD`*~0~ zseiPGmy?59a;t1-?O$_})^yAE63M-Sza;d>(y;tLZxNQ^E?k|t!6v$Y6L_XHwPerC z2NeGbn^ge}~@OO3yDb5^9YXlEp;An-^$8s&7` zrm=YBb}CO_QC&^Hh+|=vP{-6$oFtxxoZ4z*YkE%I@3@2`r@e5)O@Fn#yPSY{=DW`o zYjLfrq;?lW_ahPu5&O4IGMb(sJU zx219R>n+QG6z*QejZ;^W82-%U{VQ2P$;L5z2Qy}U-2VV8Z6wtQ^)ax=u$CS1R&1q; zS7ea>6xF@6g70Pl8RsIsT5FLs)yP^42)x!Nju?=u1JoXs(P|nlr(Ttjzr6OyE2UcER!TJiC7JU7iHw5M-hl+|w+>CI(u-dmF%dSexxrRrWvZO=ZH z+Zsv1$^|si(DVz>9BcZWy}Wm2B#I&icKzY+Ua{frT0KWdiZ!({F&J!-f%LBewAH1W zXy89878wm*_u&mE?D}T$F)NM(4h?curul5qgSxRkp`%}E)~5E%5R3C+h{5_-Cu4Tr zAir0*V~p)8J6B9R*|3t(U#$J)4SjS2MUYj;uRX9QzEl~k)) zS&8kT=CatCS@2ohb>lUMF_+E=tjIy+`d4qRT*skZGBTFlFh|`YxO>Z?_J?hxZaL0t z(!)vAk1?cB>-&3zbplBrJwc?miOU2EL)O-gku{-_^7!e`O0jDWZbYhpkbO9P$Rt%b8LqcahBmR0 z;&T&Y1xVoiX-=bm3MThBU1DQ&L|k(+7M5I=~HYo@TfjLh*&qjAm-GHVl6 zvMYAU8n-eIqQpHCT2tOgIc~C)&`BL!#OMhobFSCE2i*YgDthI(*@*( zIN%lwSbjV3+&&%D-WzE*#yw7GRbx3QHcMQ`t7^CUCcmVM)si>5z|S~u#<*YjM{n;O z&upNtUMq~#=agYqLIfjDIImJ3l zG`Q8aLgOCQ)Z9t-nHE`9QYIgGFY^`6-d@{V>Lrn}j)i!xSw+j<5=DJRDD7@UWP>MM z)qAH2wp{LI?TUi-19yMtw4~(zb)>Hx47=CN`c?cIj^&**PM^e)Zngj(g?D2gg=od$ zDPfJR^9c7Y6G~HxshCJ^gEm&P}-*rg^{E zHeCG7KN`@I(kY<}uoGPjdPRn$f_U6+2ar0C!mm%Ez_wfBWo84OFl%bH>GG~!!C5ox zF9=#VxH34wHKF5qyp0x9(}Pzui(euz)r0Xi>_wtTGlR6(=rhqYQ`RTT^GdhABW|s_ zQfo`ZF!>Nh0)dh$ri*Alw*-V|s~Xwybg{`CYA^`N=D1W^gC^EF3G(U(YO!Y+Wxyh` zXS!tsDW$W%WkNS|T(@>E=^mTly&l?P?&K0Hp}ZDRxr~*rE5P&4ZDyAz8REJ9Us=6v zZcqu@4h3UUjHMN>qjOh1i%zt$5tFrfsU@aGTDjTF;t1kWTL4!xuK2>(!s-YuT(+&^ z7I@nS0~O0%2e^r(GT`GluV#i*O*@KJn^rn&e-T7wBx93Z96F3rTJ9>nI@gbB*M4=@ z(AgRFuA1vpYinEs&MSJ@X!9hQKGQ>T^Hzl>DgusatEevEPz?31A{)az`_^wIVub5BcP~Tk3yk$7@@sg~i)fkM z8&9q~{Gp9qu+^FnU5~wSF!0a&33jL4b_#pMoIa7Yl{(rsO;&TRP0z_OMh_)x-#lfeTwSM=8x?jKBpUKh82m1uO4Hu)i6nx=w>hs@ z2BjKGoa3r6sSkUZYfw)CZcOO>_2k;uFcnYhv0GBn4NWTH~FLl=M1Axgr6cY6zJnQb^{am0e*Q zzbacN4I2YkP1zjPhu<=_lLhJpd9JApk9tmc72i%<%9V55ir}?Go;#Mo<2Bnun%XmL zJEEQIrq_`4vw4E>KDE>6s9-993dPgrA{7Ml^sUW4H!c_&=%>#9Esm^1!dlcK)AKux z5yzRAUWi?Me*GEQR!AKA(QN_C}K`OD)ZfYQ+e**BG|#}T-7M9esp<~owTv( zdL7JHHvAFoSK2t2Ic#RU=fn5&*++m*2;#RJS7%YVu-^5~sY*)sE15KIU0Us5HB_<= z;8!XT-fBl30qASdbS+-N^eGm6dAo7VdE_&yYcjflv6$mEv|;S2-uGgJw>FY5B0fed zGU7}*VT|{!dxtW^z|S44o7798Bc*2wjz(@yb5fLs9nwAvA6n$Jhngo5 zfJv>}&oo8}1fKQ7?73xR%<4%lFvGQ3(yrV{7dRhU z>RPP~W1+H;G`9nHO27S-E+t$qHC8!*aqC;Ql9hG()J~+5x;0k5rd0k0n(E|l98C9Fy!`Z~gp3>=8CQ{WxNUnx?C+cgY`x6!Azglc|0h-9RLfx#a8*rD*Ex5M#r0_SI2(O#;~0B(2DEMU z$4;=faBC-B zyNb<8L;(G3j+ewOB-qa$mD?IIp0+a9I$Y^BzY|W&fN@l9b!&!A$2dLf9(#wmDoEm{ zH^m|d1~}_lICA@`6MOYK4-80db!jAGPXes!iT15d;X&he4Q6;QVE1!3ra7n2sF-yd zlHCiR=U&ZbvK<4yMo*) zjlO?MtpxsY4Kl=s)k4xWkgEmf+OMtO*s|y5BehJgC!uMVuu?G^w$X~x(`1Pw z3jY8zS2i_;ykqk1Q^<+w!-wqb^<2Qe+*Xj-lZI{m|Wyzn&)h% z$_X8C-FU4Se#>_ovmc)wYo1mmy-z*yLc){Eu@FG7GS!WW_Ne?Q`l?^SM?~_at-Z0_Gmlz&U&nJM)5TrXyelQ`g`BYD0tk zE7hp(*eZ@D?X}I7q7AVF_*J+y`&E1h06w^`OV0{$IW=}DoxnRt&2dUC?#&h=eHq!s zt;HrbDEz9>)L4Oofn0=2U>lh7D#Ti;JQm`)T_kiYMEacsiEc@EjaiR&6h(F|*AW1# z=qn%XX>p7o#lu0BA8kexaH{Ir)e`TFNUUwnl1nx08azfl}b3 zs$-1Yv__l=0`LV|w|L??k$@ichjXblq-7#f#<3>6y}2#P1Ja>Vl}+{>rlIO~)9W^| zF~b9a>r`y~O$xM|MRIV(I7TvYPqJl35VE6`!!D*w5<|?rlw|O90S7FTWz3$$?dc@k7fK^{lBbJh6gvQH#aFCaqIe zGIbl=(w|ai>BUohry2fc=~u{?L31`j&phqHKZQ%=$84MCBR=%| ztJrk-%AnlU&tG3lbCzR)>6+d#GG)y}R?iU}3ZQPDLz2d`mT4qyqrGZa*m+DIQ}Ul$ z*OK}mS7d7|JB0w&){z4x+)VtPz<_#Yoc{o0hA%Mf6_<6ZDoTbH9eZ}C7&PuwTZ>HS zwMLR;xVMpVrHB~83_mXX*Pr-Me-XyTSg7XYpYU&F2|(sejZ+&1NYQpgE7>;8Yj zs9!(~ag`guY~!)^{$G`SYI-JpoL@8(Jf<*A@<#||i#xV-867kDkyorPmRnEV5`?xH zo7b=7-n#8)!IoN-Mrh+U^O1u*ZI8g$5r3iH>FQ!v6QpIBNEbN=wm+UK?ljqY<4}Sf zimjg62b0(QYJ$#grt?GWaJzAyNdEvM6@>6yEy~Q~G>Y4NypTF{=B0o;NF)xUXx`sG zM;zlGgOAFcht75_bR)HnA)YXSv+i?Qx`oTnIAbU%7{-BrFY&CHXPRj;SP(k9((D>ojBL(>rgyU+ zPh3}^czz~H2r@fKA^z|n9ODBg0<&jKRgTY1Se^FB3cD^JL4}D&a~~ z*P(@K@TI2g*0r-(rUND`nR+b5sBk+eAcAqtOBL0>oj%lbxrA=Gf9-di!KTo0QD%U^_T#(CQ&IOp;` za5~qc2q-NN5~WF0e(}&--p2Og?Ilkkn{vpxF){b=5$CT;nsElN3q^fqCXoi;DpXSB zdXCM(>Zd-{Le4vd5{c?T2 zyyM)>nkh}PxiMvSgZI6Ut}|Ruh<+F8H^NzM!&%QGZr+@vP3w-?>G;>1h``_8rKgeI zM;Z2NznSDdAkyd4kCAXAd;rATy0GJ;t`0!x4+EY!?@|0iExbhB0dWjiUD?4P^kMY_ zpL}}O--|Sh-wfPG2CHP(7OGpzo)Sg@;FUeN#}&%T@J^B1NJiE_BFj^5KDFbx z%A2&6nd?STn!0y2<+h6A&F(DYGAe@j2j&ajvE+t3r(||jmvAMvQZsrW6Cw31vSQ^>1x6Q zF#*uF6de4n8_*xfX0fjHORN1Z;37zMt99Qw2R?EK;k}ti{6lB4HR|{FEqbC@vG!~b zb~nutL9w*Zwu#(eQ5_$JfVk?P9%1V;oHb01MY#ih1T$O08(l}*LM$zO`PjI&J zrNm`zyu;>1z=EWKl0N`HDy}ssttD`Z@r)q9nj?EBJ9@dLpJ zr~d$3`FmF8v*7FfCL4J*4LV4molC=Y3Ev#5I+S6RY`>ddh##Kbd}R_Z+sSG&|&-=RO_TDLlSPY0b5*yHcS-Mzu?zWu8L_67%I zp#!#hR!*B+k!g1-&8)PCsT8)Xw*->^0F7r{Y*1Hk2fbEnrnDa}Ye>Vfn|;k&h4P%? zhAN@DJcc|}P~A1cbJyOZkg|ivH2GX~WHo(@2{3+gYFEBkzyqIp$@@bBa5(x?4CS10 z-?da>sIHBF?G(t}`qY1J4EV@UYc^P%fa{(;sT z1D+`$mCE!Z6-xehTZBH{E2|3&R37I**JrM9YP()Jf4pj}cS`+6KDA~aEyq7DE0L~O zu^O=r_sxQNrzPklWw`p(R|yydf(fW$Pu8A{9m(#lSRa=qeW?=h+ywyR)}FBd4n_?{ zAo77Ael)DMXh@UhQc206OY2bijzGtHdXfhtnq2@!xWUJNTA3$N)bmXcD-8Fh$!C?$ z?kdwoFEYoTt^8dnk8!i6e+sP~uH2p9ok_Vi^H9(dq>RhUQ=?$N#m!b()UX)@Q?3{s z75yotVXZ}$LassesBUlkh|XITUgqdFA*%a)4M5b zXV$ay`x#BlWr)I`#;;3$b~1>_KBk?c8D8TBc>Y!E-Np{)YjV!98-)ytKm(>K8y!ty zwqqz671K`~Ce)b-T#s7gwOCP`<;YsXoTD|$TW@neRlIBBGo66+Ju3Bs#U-%?dJn?0 zCvPow;1v~lZlhZfw;9J;?rCx>515wHIHhBZ3{|LQXeR@Lp17?0La81>!xLMP75g>< z7JPBuxu*57u2Z?!62)Ap3P|Zp(lr<*ihGGh_alsog6lCzzSt zf^&+kF0j(wCAu(FVgbiW<1~#@_fNexw`GXVH@W0i_1v(v#6~v5OYaL@5B0y<*uAjT2@tDU^WF)@Wbho_**hECCFS5S0_HT(s(WezK!Df zO0ghkwRu%%ChabVGIx5F^er;$T83GHP=K7Kd9H&&@C)m*x03!_FI@Gmhr_-Hy-8o} zufE;+VbB9ucY3a&;qMitt(&YZ(T;em6r$Q5*JQeFuA|^BT6pDTng{Bn^!N6xtDSP% z=TeqwP&%h2M_TK3Tex)zVNFHRrIYxEKU(JeRp19pW}4GrgBfO1$Q8#Xr9M=&6_a`% z9q}7ii&WOwz}uBO_pW9DCp$>VuSnB88Km9np)X|$H+<)R81=5d#$OFI3oSMqtsung z21$kYes%PatxAIMC(L?jXGaJD@m6ILP$|xwA00yLjMYBiwPGaawR_ z@m@po##0<*RZUMpI!tRaJGZeF=f_s$nVr+nux6Rg zXX{W~>$d9yBQMOu9XeKOTgh`P6=0}Nd8Y{7T1bSKQ*tYXW9I?AiTrCq!s2P>K3uGd z+%kiVip0{VNbeR2IL`prRUVTB7Ygq%D&0F`vYJWkOGZt`mg#zotiXDaT_bo>>_C@3 zOGt!s-m|rs-C^AkJAmpAL9PD)1^Drj)alpJs}6yfvx@9X&JcTosO`wg!ZvpL*Z$&yFs9CviL8;y8*RN#f$}xPTD`z!?BR34rPg;vu)t|%{Ghck6oaCq& z6`yM?zF_&VYnyd)npV)(h0$ganJ_c=yBgEHwV1`aGDp_2?hwwavNPs=D&~`@Ol1%- zAoo+wYdJl1GfQ1aZS@^Z_uC*WTaKBVQ=>2#^vN^f(>MA zS_Y}&g%^$%Bv3LJzr9^KLEooySffKozKT?1zYE)*D`QX8r?-uv4o$lsxOoP+y&49y z-4ii5J!`JBK70y+agO9y4QN^Ev8OG~yI4^ZavTHbYWx?*7>WlZ9>=v*w6T!HImoA* zSujCb^Q4rUxHYNwj-4SEqj|?2>(0J1Y5_FIL~X>3abB%u;E8W7!!)D}bIo~|#a$*H zD`aGuUp?#etYuGQP0UegyEDYJdl@Yqr+CQYxUO%-S6A1U;b4V|4l+Kq>e6a9sS3u? zj2^p%TeF);3AxfTewFjjHcmE-PKQo1dPwpeGenkKZ{9}1i0&&o^TRihPy4iN9@Xzr z>iQ&HY>)D(+g8xZXKZ=;R~&N}e}cg*KlhJ0@O%?#`axMEVor0#a-JZ0)uf9>7~8N9X0I})E}Y-ItUs%_)bkS%u;N7^o`)4$Qqmpjp+WZRUW=?* z=~pbOxW}$(V({*jBr2q?anLnW#nEt3*1+)2+B3;-46Ne^inC~2117yLe+6j!Lu7U9 zx|SaR>2pPp_{XEt_S9O@lk6mwk00?Cq}IeD9=?^<&wV656x@I3kRPRJ>)#D@*=GmL zVnYFq_0U{+8p7*CHs(g!69a2|S9Tt~DD^AZ$}q9x2Tr<{%uHM5+q)jr`yD_*8VvF) zvAOWeO2cG zzUlf`q22f*+fE3gLO>MB{5=4Ha5Ke48k8$OWg{t4ly^KwSiQJS%dpokKCh@cv^$EY zPfGWjj|jnWFZ!{94RIbI@EfGxxIvD**Q%#ZoOz`nif5hZH?IxR4V?SeT_mRN+>+e| zWS;`+miH!2nN~f4tv1kg7;VPL%D164<<*pG%buK;gi14g45Yah(wv@^y{GC$(}Trw z8m5=1MImO4gHu`GU0OwkjDuUItex&9%$}(93#)*dQF3|OYlNEX?LdX~t){u2>q*AK za+Q%`rd@^HBI{Z@iZ*SIQf^wA=gg0A$2HdYPvYzz41;CXc;gtXv8CM1+eAFq1LJ)% zdwYyY3jv=>>7!GgS4Baz&!Fu;Y26u=2RJ`Uz5f6W6{1TXcYr>X@orN6YbRPStJ}Xv&!S=CeG1@qb0sv>7d;WOv)Q0N0Y) zX?GS{NkbV@RGxa(3m=F2hNl^kAabYLvi9+Zy(eQj(Ucb{&)UlOH&Qf7l`Lzcv}=F> zQ~=jc;r{>x$)-h#?M{8gX~E&?mC5q33umWlwaHa;BM8b%VwQ!bOL`Q@xjxm~Sm`jN zL3V)N^;=DWYzcW23!1pPtao=iVaFU-&*QI4RLGT9oro{=w;+Mj=~=dVe5p3wool(W zvJ)UKb5_5zp^3w773ZvETIG9(GnS0tZ?vb1CSthFdG5Isf^EBT^L530wzRMdWf;jO zx!dmw!E<5fZ5z7Rqld*PE6b@{B#$%FtlY++j0)*=`%RmBdm0x`kpqNG0D9K0iD2#y z@$}7hO0!YAMY$&?izzx<+PGp!Bb-;AYnFd%y=mhEgI;K0#94BqNjoE% zg7Qe5r?;&oqCEFxuU@oWl#cIWV3Sf>`I>y@M_vf4PW0PDkHFcvZG0_b*&xZTe_Fd) z<|J`RscQ48TKHU&YZ_^#bDNmD+a!Ux$JV)W-Zxi4p;m$LCx2HtTWJVER{=DLAV(V%@ejZFfw7 z1IDL#Oe%sA>gC}arO(H}=#|z%I>?9#JbUyWkNyRIP-sSy1 z?cD7>M|zJ?ot8`vzLhP2&&0H4a5 zQak3lZ-{EJ*|M)5m4oo(PiuiA5y04Cjnj zI*eP@9IjG})tk|4cOG7Ml4?jbtJVa9O>%l=@1G%3#I9?4JwYv^BRM$Ys!*bpxk`;q zH!aQLi;HqZz3PR>i+t4}zu{b-x8eac%P!$u_3p9c=jN%WhfZy-XLeRWgjrbbIvVISQM4DHhdR!(LBe{{&iDP)&$oQW3JMkm3^zIe!2+VUvyxer zQ|1PpKAm!AC=iTyu6-L;D(>a|EfzpQz#g?~Nn^K}HVn6ZYYGXcwPKsOAFXOy+Cpd9;Fg|yH!x-VX&^r{wv5yzFlZndtq5W#|^7H&>!mTe-X zYo2%F)Cn}dO7iQlP3!~J$MdgH@rM%4?Otgx-FnmSTPx@cCJ(XD|Q z`D$tOsgQ2lwJT@C(MJx2YVFPtR2rrHmms7|^7~iF%1zC)iool@6>*a0Ih0+>NoZ3Iin@>jyw#_YB*!ACUFt$1lpNMKa&{Yy zi%@CkK6dF&ms5%%u}34lWDQDbh{?dDEE-H2PA{k?qFZf2q+$;Os;%2JrFjG1q&CIA zVa-V$n-jw09nDpe4r4=1wq|g_tE9C=BMjL!%tr4B3a1|RTTs^IfkMPfIrOe)3C-xv zm`X8Po`DdyiE>Jl^`w$mpYDz;%twi?A{lZ???U*xLW zCa5-^${B#HOFtFw064{LTkFwGF_BHiQ8VXK+@*7GF$5l!PS)QWvJG^;bW=jdBc(xS z0yuMzrBro`7cKgkLOdQgr!r-0Qd>|-096~SStDPRX0lrBXJ(AaRaEk7q~muAGoMP* zODSjjz>2XIlvbE|ImK?Gh)J3Hc9IwOvv55PYE3!_wn9T>V~U}wYY~7@951y|(r>|( zs2K*j;Y#|mMWHPEV|j(#&80$zL}@n8;hAw80e$BG3*C(Urziw@UMYB2iTkWrnT2R zOA-+)MoSpU>X8tBUYOiRKGo{b!#c|LvhHgNJo2&Ow|*19@ZFWIrmYj(UU^F=mgk%t zkLg_9{Bn+0=19-o+H!p{iuRw3+Ppp`*5SR1HUdZjvbo9XNC)4XSCHSuKbp%JB|-b- z^!zK+aZ%DcA5BR$1r|YXZeL9*#Ul*mu*0$S8UFwp!N0bRt{F)AitQ($uEO5jEvL*0 zVsJ(`3g>kzGZAISnj6$`F;OjzB93C_(Y6GZAuIrV!1U|J1!i5?X{xQ}#H+Xf7ia)_ z4l8uPR#Kln)75d6ADuvKM4vQ@G7rjFbH!(S8*-xwv6*~EiZl=9rs)X4QA|jR!g5C7et=Lr6=o&W098Qf7q41Kto*^gVlsN;r~d$6r+CIj z!MKx>O(w8+snZe8ur1{{5ArK|wRNFJO4 zT}G9qwCo8RIP~N6qUEG?o(r~lSnZATwModyJmcm606qKHsc4WqxMF$7EL0EE*0^0B z3wR_|kSIC9*xdH?>MPRxGo{{N&E(ob*E0+O6ic{){o;Bk>CI=m(A_I5v#rwvYA{J8 zag*2auS3#oMvtQ=wW?XmCYk{fHK`Bfagfe4kUD1_GtF1<$Ar^EGR`h-*I9xP(&_h0 z@`6S|4V;2N;kf71rC7f4P`60@N2bP&WhVHwZ8?bKFUrrfbtBuc9<|X5J!EiJ#r>LR zL#bYA_g0pvaAKcB)D$hgp%`8ElCb%HU;qI2KBES!OFpB2aMm7TL*k7!3)@`h<-La| z3Vn}%L!O-18qnJ4+Oz4CNY`Ex*W+m|)Z_>q`PvRK*BJK*YhO-z?-*#;cPne+Jtq@s z+L%H9lL-TE@9$^7Ute7HS^ofE*ZeW%w|z~!E5^Ky^{pLUrI47lT?N1n&M+GQ@w)(@ z_J`wI{vGnKEu>u_CZ(l@#JWY+1dtQX26}V+C)0zR*EtTSHoJE;)?jFUFt-6N>?S|E zyFd;OdNQ7>!}I7)#*eChYe^l%_Mc+Z<887_8#0E#&nE|VLFi97_RU&akluyuCrFP; zzeUpJy0nd#d)mrDNPr_a1o85=cqgFhIX$J0pKosqVVQ))F**CKfH?Z#o+}y+YBg8` zu)~5p!0G{RhaBJ&j+JiW>?|?dLpBhA#X$K$JpTZmYh`3&+h);|c0fCod;b6trHHrj zAOjgE_)qxvtZ6RIw2JK^RUdgl1KTZ+#-v?#HNld2?T`VvrF?!|@;}F|Uos}ety4&` z)~uS=;TBjVz}fs!pHO>Og#1AGGkc&c*V<2;duX3KTZI9@>ygtxhCAmq>lc1B)5Ob- zM$lk@7|gtYa7Y;k+pw(*e-i2UGyRn=ZRUzWyDE?}y(+V!?-S)X zB{w!^BCJ$ll5Rsp<3A|}*NzXRbQ*T3m$nApmdh}$Q*9W(AfTJg<$!uMVr)MOU`2$8v%{H(3m;C@-h>6-c6MjBKd-rdi7 zjd)j9TlOJ_`E7^VBS1H08B`Lj=s?eY{AV?LT+n4YfA)kpM39DPq`}<0t8hDK)DBHW zZ+$v#5tzcrLd=c;9Pzu@`+_r{&!f`gTdh9!+AK*JK5IVFynMvJU*h?J_Z@lbf_7Fp zXAV|)M~?hA9i`b8yT!bK$hh@9`u6=lI^^!u3uvcc(oG(BOpUS5F_Z7u^si#^7LyjG zXK`+JnPHKTqjGS*pN@K9kIKC3UhviJjlIv6wd9ILWsS~!#USMUN6Y?kSk4-0)ZnQU zwMIp@y=ORB$Va)CguA;%8xKx^dwuQM6_&BASLQ2&_Gumd`{V>;(4M?|KkjI`FF#JVHpz1f?AxW)e)8*7a%UkE$Hr0Rm>c7-?`t|zOZdcW#KW6rc=Mu%SbA#_t zt{WdMdM)>Zkr<+p>*@%sd%p)X3^p8Qp;U_{(2_adw|Pmk%g%b5t0vZc`*B@C@O-;T z$f`FQ9O_E!$R5sSeY>o`$4}%u)^A zGt!oHaKmV+VzX(^PZg7W!o}2{851O6)p@0dk;Of2ep05Zn=%;IO%&H*$t+36DZ=76 zBms(v5&RQlFVs#|PnYv|7^zC$0&kDJn=i%qz7iR;))^uT5!j8kkrNdRLxmw(Y84rMxFTxU2H(QNTQi$$1YPRNfxbTEc0sZivYl z0Gd>y=qD$?LsXj<;s~_8Fxw(-n2t_6)mT~D!A3}K;~gu1LKgE~OEuc=M<*GlYe{Jp z%6TUWdk)nquf546FCw3oQp0Wm$mIG}p9pK(hJ|=iD}s@?RUU z`I)f5bnp08(yF5;9^!jgxp}CY`?h~DdEIg4HG~9ipTvo(goY#&t*P8dvwYLhYIU~JN(2bK%ADw{t=bmfRH5s9~v3Q}4 zUC8vWB=Ie)=~|3(MIPL@BNg33G4^Vj`^|66taP3$(0{eqzZr9 zuTS_}Xoe@4&Q>6D3G8dmekf@WL8=L?5dEB=yZ{-kJquly&qVT}W=3Vf!QzV0Q-?fW zXH z$U@b>V<@cs)Pr7Rw9{)DJE5}c#jnJ-3~&fI71lqE+UX#)NfD!zY}|3uxnKB2 zCDd9;%xsXT$Y$wYX{&2*r)y0NE_TG(2R#jIN*>!}T8nM8dR6bkFScs$C9K4=uJW;- zPvKpchx{dHV`t=CFn^m3^KyMb6~g#i;`BoH-KIxpQMHHw5%e|I>)tPp@+P{rB!V(C z!)M-#^Qjc$VQ-^4jbg(?u~^a=q9|AIN5TAS#&z3uo5V85mKLPp0X5Q1;yLvlB(4{F z{{RyV8su)SnQj9~f=|6;2~FDKX(UZ?;J9@|<=b&CI%AyIFREDIcz#nHh~YYJD~wln zrAs!MGF-G|BX%`s#=5nZub|1gB^LmF;yYIAza*4ex+)&==He4HYbZHxxy^NY4(s^L zbI4jmA1?Oe6~*Y2NKVoVC_SsZ(A5^=HE?6yz;8qETHgPFNP)pte-~D~@qcySSs)<*P{T zr_xM%lx8I(>?BxjnvC9ESj#bjC# ziZcHIfTDd;I6>Up*M#ER&`w>C(G4=}$7BY3SCITpwQWZK0F06=(R9s9GiR4@qukdS zuIid}m(9LqE%g=j{8f#X6AZZ)t(|yGI;}lVAHDGWio~3ssI2KU^8xvW1$zGgo2ANs z)~TvmmYb!@nJ%2y=JYs*rPL=+@I4xtYThjJ$*m*uOMo+3vm-?lFs zj2-(5!JA8V(cRAlhZXj?Y)&5$OWIXVEc4}rae5s7lYJHRg$Nyb8rhoC6bEPok4nIY zNtZ^mmh7)1y-THPu56lFM{M(5*jy}el9ZJF)!3QS1Fm&L4R zaEF}nk4o#bO;68=nRh7GbbE;i#656oqpU#`V%Kjstt!YdIfRWP~tf#ek z<-&4(YsgqkQcsy|M3axgGVbZjB>9bj?@6cX6C95<&*N6xNFo;V4><2eou|he6Oc|b zSw+fes4KJ)r#HDuLp=9cGO!u$Yff94A&3t-%HyClm#Rl8llLba`cxJWT%7sYKKZ2< zs)ke_IvHYd-bh%y<#goL|o*UN~bEb zW&7!FZe(1_$MLO56s!xmkKIv;sX0?t< zH)T)OsLeWr2Y)pXy1+SVhdR?*%&%(|(B4aXLl)Ny^%UpP?OqeH7oTe8rMr=c!(ye6 zRhA_KIr^H%*;ZP{MzO_5W`g&^ma|Gr#=k*St~@8EE(1iLl|JWGnb;rYQb%{^fEaUL z&KnnAiuaw&U07>kOMM4TST+dLZZV8iTdO@f(MtI-W87fW(n;l<1J}}-JTY9whfqoG zYt)WpVu+Iz+rFZ#!|>+wO5tISRrMmZB29Zw7+ZrTI%mB` z{w(nYlj2wetL{b^&XKQ2ra~fZG=MvWtD29* znNdPbW0T*GwYlNH8t6AMFWTT(*!2!8mao<7+B4WvoTS{FyE&~x#kK_r`x~Pk z#u{wbLMFoJ)K{*3qrw`B@*x@a6wmlp9u?Ptc)YFNs&QR3sM3n%rp(>z4#q&6#b6wSp7D>Ym?Nz4C_`~p4#=_+19zSco&F@ zN$g8edzcqqAiA)aMx%P?99F%Ku`S#gD05u4qu`$tS;|Y=nZWM36v%Hi-6=qmO}N18 zh0S@N*$O)K6lt#Jwy%3O^#w>;(M>^{OHsFq20mEfs%bIG5k!nasA8_>0Mr*tms#k(XGbSJ@Z=2r1)C>Mp`VN zaazX}R*L0txeko4baEOFr3SllkjSH-UMsx2@P&?>Vkb!BR>pE0{{XK^Vc~5W-sxqv zX!5-+tE!O>~%m<|=t*%Z$M?#~fabB@E z!xpi<6TDbYrDgcD;iUSM9%ZCNkUI+NrHG>{eD~0#nx@r{Ah^6)eq8hQsr0zA_#-*# zT9%&IlO@`0M&`(!s0gh>JI z!L8d{2nqwcnsTo=+frOzwmi;HhT;BIY!7Oe{t!mAgrLh;t=nkv$^qR{%b_6$8%<*I zv%Q3==y@iOr5gw(h=MbowaaQ=A7uG~&QDIY>lZo$&vzoClYn_%)q^*OUfr`Ma6N0= zt%;Wf3FJ2)z2%oVN*Wa;n$>9%`nsBv&z(PH-rdM&lCs zY>q ztCkt&x>9LsXp&;FXt2co6+N}-c}7$d+L@`xvM_5l#^|*89YrS|X!8)!tEoQ#700Dx z;F&<}T60b%IC2Nls7Zx69V)49W+Z9ah~iPm$*p??1-E9o+jZP`ZpJCisXSYPwlVKq zl_7l*E!gjLtyB9x~7b^W&YZLzs0wMS>E8+Tsh^sa96RFdj{oSr!Anww74V~XWVVBq(p>D^t3_01;z zCW#E>4&ybV_wmUv2*9Wn=dkL=@>Gf=jPNjPR@N)Kc}XpmBO^7zDsK9U?U{Zun{<;A z-na+1KW?->t}C$dM2yhN$KJTxY1(~C(KF8RiuxLBmY>M_ulaV5qx2sv=+?^T_y>Bn ze#;5Z6^UhIc@CLw$fS*fifs1RvoHF#2EIONIXzF4tA2N6YFz6}5I$ZoJu4RDQ=0BU zw48cXt3MCkNTHfGE9h%NFAqFe9$6XosZxYqk5W`;y^OGBkoBgWI$2*Lx(3l?jW|=9 ztucK#Z()!q=j<+7b|}N4$Z?h{inAV>8a7#j5${sjYoFQ-P%Z$gi(<-N237F1fWsHJg$FUUpcF3 zZx~(5xz9?3#NaVtLjDz+!z8cFbbB=vP?V}S$~twdEmvB$g;+Tie)|1TNSWk&*Ou!y zO>=(eT;snr(@K6*K0hSFsqWleFgT9_wM3z561uBgn>+eQh? zjd8Al6|UeZ3|xuKX?y*OuBFr*lI|(JX!&XfoK@Vq5!-qVDZ-H=pjQ z$ij|$jMfK-{4hLy<3c9YBGPp2IyRc}=5d{?{>VApdSGOZ2fb}w&dK}sa2N~{#{?7j z{{UL>pNW1jvhdcb-)ScCruo*%upx3WhnENEQQ3ME*Eq#}Jw+N+trem@3@kaSTIZ?w z-1vMlFNYHLTVP$D`s|YTZci>c00GFtfGf^#quRu&JADtWQ1CB|?z~+dp)JgNdeC!lj)jhjAUnl>52*)CcqDtq@Pp3s*e_1oUk16SEWBN9Y>`#ZA&>PfM~ev zSAkUVw2*pMrJNZU2y^tN!3v@I0Dqw3wlvstBJPN69GvF|^2IWdV@|LuASXE^q6+M^ z?KVq@kVb&To?Xrne;o7ltKJpx-S>%u#iZ!#KF_@}p~ga!g2l0)YW6P-_%lY(d^i69 z2^@FntZMej=J^tVEK!9xkZi`{RDqB?IISZGA|+Zh)}|MLz7cA^DAFHOu=^aa$CAqP z6_9{A00ksx2L$!^uSe0fog`@blztZvrTBut63ZUvW^kt|CPo|_F&uU(MRI;C_{R;T z8dr>T9KewPF46}eNfUgmtN{DU!GJx+)7P&htoV*yC&yNvC%1Nn&rp$;;S`()I3=;} zNN%0$rWDfXd9`s9si#BGuf8N)YkF3T<0Msv>rW=rP`7~a(G~%K9AjzDGt+X^*BXHE zcZ==sw?_UM*X9V!Wc|!iHwS=tR#G_X0Ug%3y&nEA4S4$dOJwr2FA&GPLvXm;GmI1m zI6c5Q>J;^@pAOj_Iy;{N_=?!aXLAcpVJJKl$snoY1v$X~0C{~YXB5A$xtyHWI}1y3 zXeaQ7r*aocx*i7usP65CrhaaE#*Nu3y_O^=7 z%^}f57k8P<&vcBi#BfFm{{Ru`$r$z`wor1>89Ak^KD>VzS?KojUg~!#X=Dlcr<5*R zjymvoJwGGg%Y0G$W@(yCFK6LBF|}KyTr}5&#~K{+8B~`9;PSyoJom4Jd_&`HZ^n9~ z&8ps9&oe1uh7W`UleRKSI`!c(^sF0wP)iQmtFl@!L@c1QGXDV65;@548(?)E@mt1? zz9wSo-(%`e6#mn`J=f-uCcio-?%AH&#H?gTjPCh2NrT7E3$LgZ=Qp1bb$hv_ifuvM zFFWUE%Ap&TvNvIW+5~~0y0zpBtcf9l(IF73<)f0^o=!M)1Yt=2DEb^4(TeOX%10sd zrIdV+Zbr?-<1q|jNjcpaz&!S?loIG=%-QG{KM^ll36d*@hDBvr21>akXC;nsPhPlg zFu>H%c>e%Xw~hR}iOfnz%O?yQJvlvj=s6hgoY$X2G!QI4bgK|T%C8?7lcqAm3S#aW#SD=Ke2d;blrO0a3r5mhwQSBItGNC{{Y_{`&Y`1b8-ur z0JoYm^Eg~GE6DxIy4l|=ot2Ai} zlT9?wtb8%?bHh6DkWV}sOtBriE*-GLu?J{9I^I(yfPJgGN& zZpWz{!s^u(&$M+(68aXoX+k>$X<0@Yii`*K&Ir%f@vNvWN+gz3+r@be#kpKaKK{%w z3d5CSjt@??^WKB;zgW}p4bGY`Vb290%3yFf9YP*0z3 zeqN+8Ve)~!KIR$bz}~UG!YMH{NL5Jrqhs?aBN+F= z{#D{uqSM;PB;cj7iz*i$W&=jli{m>L33 z@OMUf5Z;ID{VE9BNn|BMLoN#v0oq5nA9wkED}lxCal6Hx4v(&#Gh0jhuQueoit{mS z$m9$LB!UZLjF56N8z9v!YvFBcv>ry%;RYYLZKjo77WX(P$x_-&_0 zb}pdIavtNJFhK{@V3C8=8l!pet4@@OBFtR;p;-K$-|qT)SF(7UOt+TOTbM(AtT>U% zs95ERvxyV{Ff+6eIud(gxk!mu!>ePV6sJsrqEA#>)oyW$FT^7}lTtx6fq<4Q{uR>8Wg>zA z&1O#&$l3Dq_*DCn=rw-jVQXj36hKuYFL%G>sz)Pexu_0eK$ihfhk0 zbXR6L7&W`$*c!$^E>y@ZoRM8a+gn8!m=JCvyc*K>bsCD$!`Vhn*z>i~CQ@=fwF_x7 z2Q}yx?G(}wV<1xMa9dlzTqZ~z0Ip|JSF=M@Q(7~Ei$`|n6is3y9E#kFTeVjz(GUs7 zaaU%J#^DtI0DIQAwASc7gXqpYT8C~rQ>V04h@ZNB>$0)ZtpU#9MKbSBu$79L0Qyw9 zxVu?^?$d zXzH{Vuy-jzr;EtaX#vQs7@e)t03D;&yNJ9!Zv;VdxWz(rNM9;8; zS>h_I^H(*iUaT%6m3sSTy#rS8@0F3pkI=#zUBO^G%9FKbEb#D+Zr*4+Y8;&zx%^Gr*t+9iT zLpw}}HTRvIfOxID?M0<@jm{8|IPF#c0JGOmvqGd7Jn>F~(X~0!B#f3PrFOR&%bo0o zqb-rt%+~Q~u%aGF=~Xm~G`qQRGaPo$IIfF8@N3_q#^9?j@V82NrK}%^fM)<;YswOo^2ME_!2{<}Rk5=Tunp#&d!zR?|>|M?oi2c**HhHA{rE z)P#c=_U5}VwBYL{Et!p;$E4a^#59Pa5FCZ)BCsys?UFn&D9@>*%wh}o#d>jRChRwOtD6yOu-(|Tz0@GE961J-8#rUOXH{a0{nOIA zJA2(EczM!T$JzimD~^7(feq!nnq;a|pg1|f6_)_KKtsPinhq|??4zX0-)d%pGQfAP ziql<|BFbYs!2aho&1fDXi%z(7+NZZQ(m|s)h%^A6sG@m{tP3NgKnV3J1f zgd$0`G!4+2_B|@X2XhRJHj%-9O7kB9TSEq*l26d^JJ+mQShBRYNEktm2pP}eURE`^ zRQFDKS<2)Wz8@A=@-@3|L&!ZvbC#MM^IVB#QL#>VAFXt7-$x`)3-Eem;-p)7lEuQv z83@QY>GU<_bI)A|XKOLqrNynyoG>U(`|1wd1C~banVg<$rP`0#7e&> zzA8;UqnwwV@4?3n$gN{fmeOpfoE?m>qurH}2~gZ*V!a9*n_Ig`r$R%4)q8zwpYfvG zxkiO{u%y~O8uQIVQ<}nj+Q-DNvel(KvOcwKQ81*>^{3{N}QiTf%1_O7-YoZhycQbE9 zVNY)@+p>>Zr!|AwFfMR?Yo)l77$->)@DC@BDY}KUI;_zEzyr?)y*SpC8eIW9XjHSi zh0!+*ky_Syyt`EXA9Kw){4))Oi%pQ&8OHDBSW>L=IY3hztTbtr)E}zZu5zL1>7vDclZJ zlU&OR>VEDa=z1G?rok;$qnQhL+Snv|8ckEg`gPup1Vd|q&m)@o=TdD`PrsHHSrO3S ziel9+0wH2%@l2`XROcSSdlU&10Azi_Z}vOSqAxrE6n6=LR{|LwF6pR zIOWK$nBX9mvK!^-&(WP<#`kdPZS$dAK=18GV zaZQ@@?NJ5jYb!)jiBs<>pbsNQXUqGBr+*d)wN@#%E5s7N3p9=TabgF!laH_AZ!d* zbsW;XbiK=!San9+7J+TqSn>y2$ynsHxoy8NH1l;cW1M!SS7tvoU0lYsNZIIQ>P7q{ zl8G*t8OC_xqPDVYbMrAjjY?$4Ptu>}WpZoDg;~;zQFgd{TWE+H%*!Toib<42yGLI2 zUVHb6h+ZnNx_3UgtaWbfn7WOLC9dWy0Oq53-3K*s4|7DAkc9%ZjES6_mC9=DswpR) zM2zvzrDz)=2wbF;&c@^hEMLrYv*ZNh!`itMQh{&6>JJxLzb zE>!te0c@N5_>6pb5thOGE(wcih)^jpSc^d$7I(rXzFz+esyI_ANM0~!1) zf)%AfyGT9LD@XX1spycIH4W^mU8jbBXgv#1VFdDoeuPQIa<|$HR~F@Di#Zs@a>wC) zwcO>zcq5$Gb{ieZCgmbt=hIqly`XD|rCK)K^sQF#u91Hk+Z<#cOjpd>XN9kHbBjx< z6fbO?S4pRM&tK9%cOw}TbT#NlH>J(W$+7Ethrz8MR?cBVpK9Q|UHdm_s7$Hwq!l(D1T?49X-QEXKxkC1HpF-pU#=8d=K$%l)E)A59A)Q zAq*?btCeBud{oWjS${FBeesh<)u9N7YxL&2pA7iJM4r(Vriqx2go^U!_#1b187pHX zEPWcXZvF@OmcSRaGN>K1Ty-)`Jm~uv-7U=(R-N=`(J+k~@wcFivFefX zTkxMpv(jdjEm2qkcwAN=!tVmdb7v%;Us7?!dN+zZbEa!rEV0{59FA0g6x9C!3epP= z7$l6lvCUkbKM8@8sGaUgrA~6P*vfALi(b z_#aRxMn6jDuDlDY!#D1uB4`b(8P6jGwb!zBfDM~N{Mf)~^w-1*b~5uHepz81|{I(6N$g)ukK z3isBtv?rL?@~ZP__HQ62H6uQiw0M)6%5XDy715q1H0!COIE;brE1bQtyo%xX+p$yJ z3i>?gwxw{WpjBIs4_Y!XF)8D&D_C(PR-B|f1MYmg7NdP0qxLIET1nUww;d^Ap7Jd~ z!Fe0QC_JeZuj7l^{3G!RCAGHmppiDZuU@t5ItPVd@k|3!x_~5(pamnKud>8uRIu0z zb?V>V*v(Ru)1D#w%c?lrj{;jw^Emm3 zIWWp zTsQbuH2(kqFAQYCe;a!;5&Wx>mgiWqDr2~nLH__~@m;ru_5ExJQLiPzIKg97@fc-q zbdFP&)IJ1wjsi?V35T6a686Be=7Fxh#oH0d?%z@&kTzzGk|vi z(-pwM`$%2FK)JGtLOSt^>zpVz%c?D3q2{`;hqbGADL$QafDZ8-e=5tfu#y>Ft5OWMSMNcd^i1_sA(vWwZUbP5MUnQ*Mv(cKx>{<9XaycN>}Jl zB%u=_uzf2$$kI6g(@fcJb4V@`WZ-d8C|FN&dq5+U6YE(93v`+CX16&pz*VT_Si8hY$Bk5>3|V49ShrF=5<$;EY= zg`LHm&Ub$34j3NQ{TaOdzv9KPA}Ow`5yDq zC*7JChO9=BY7Wfo9jVuT8?uOG73xQh5igct>@m9+TXJ(cT2d2}To z-pQ|khEIv9Q%aXOC0d)hQPlc4X_|GkL8N5^>ss1JhBU2OHfWd<2T(z;1&hb<_?jh+ zCLvE#UFU`*xYBG)*0KPEc53%9> zEz|>^aJ8qQc;4Gext44E$Xxa7T-Lec>upC{X0>HVGxKqZ^D5;tgt_U>@37rO<7SHb zPle;NgqFZ>VbZnWxVN>0p-@dEo*~nxfGCkS0otoYd#AgNswhzSffkDYK#SrZS9pLcFhf^TuQ(W0rsy$ z(R>tjYg0F#tLz1H`n9prZrT=b*yw3BIIFZPJ6)q0G`V6-7BwV#dBz#|`qhTjBL@s> z6LaS_6!3lPHC9hejNFn|9+vRKoTCg#fxxFI^y-@fRTc@sFUg!N0oTO`b$~l*r#rKn&IyR zvdWUDIqUCUo#F_iy;)GM5BG(6cCBY~45eZ?O!9M@_3+Y7S)8pMCV^)i*exu$AXWRT z5c`TtxGzp?j?>`0l0g(=N0&G%pp#!id?@{u{BPs&WpJ>IEjD!}?xzF<1KYlRtGXC^ zl_l;gmXm!CE7NT*u1}X3F4^EH$v=g9r^4Ua`^8@pE}?X^lE+M9LA#X*00V+?UtxSV z{gpf;;20KL^*Y7*U98gZndhSZHQo4&RD;9%Sc=v(wT3VeB98z8jtAvl%^bBS%~kx3 z)jsEz=^g^`*TCHolTKf?>ZM3)$+9F{g42-(hEsln1Pi!`m#ytgPTw8|z9DCKK z*R3Q{eAORQSh|;rtZfyEkPV#dnvii)n2m z2@Vj2I5f)}eQ#90NIa7t0GE7_0V5qfaw@%?-pGeqF*ilR_5* z`}?+Yb$*dXppdXBV}PuGKbNIm(mWk){fNfu1-iN2xVz<>Nb{|ZG_Xk%*zTmjEKQv042Hs$mH>g_pb*0Gt)dFt?3Eky-wcoHE3Kz z97%y~GL{%}au{zw2px~qR}CMCOkNEzT8FigJV**K7}_>tIPLqk@7l4hb$gv-NRi}` z7DXm-ps)zp`TBbNt&elox+6*}W0rWC%SEB>UL^ROd?n&9CrGxnx6*E5hip);#7WnT zkO&-|>UwZTQNZ&}KgGJ9jpB>Dc;?QVsS_k&&n1~i*fX3l`-eV)uztq=D$)ZMSzIxZ znPtbA;C#pEcwzKvlIBnCjTYe$wY~kb`G|_cCBWQv{Xoe2H?3@v_vIKM(kO-0#4KDJu{l$y73i{gmn34)FWF) zLPJM$79=O2;NYKOPBGM%Ee?o7dSbM=)@P35XyIt$R!$jD-oodeq+^aa?Oe}|J~vzF zH!B5{jU?)Mw?+k6@zj>%*8qN1;$AoS*Qjdu5?fixC9 z?>fe;?IeH}RR=GO@?&nKf3n@Hj9oy18*XLU@`oI>KF8H+<(1J^+FO=8jA%K}c8vF~ zgp$z5bEERj+>mdZ%Z#1!7_h!#fKKTD0J!6vsK$R9zHOY`{{W>3ZUx9vj}a(k1EE$q z*)LuXQcta8!K!_kA1;zK>cO9Z6x?tRc-(rA{{UUbk=Z0!3oJW;c93B1BZZfbt{>}6 z4GSHR-Ny{fvqa7T4&GSvFm?$$#`(q^WE^|aOLZ!{EVm6B1PK0Og32%oiBlML>4z0b z;b>WR33qv5ZpQaPlD|Lq(;)IOfsabI{{U#ZYh>DEW>yM3-gDo|lYzCea)-WsMF7hY zmxWwBrd4=~fRZanN2=$E6R!kv|s9l3B#4lb0V=6QJG6FrtXIY|`@?Hc| z8H9um6}ZOr>Yq`7YgQjKO_620fLz=^`jt`?N5^OBA^!kj_!#HXfHw54JOr_h@&Ol| zSM2uD{{XFh$M33>!uQHB&lp~$S=BXVX(3x_U^->6F~+fH$}f&s<$9m?#z+Gso@t&fy^P5V1)HnB92pt)7&n9uc0P_QW09lW z8yPE{91i~CqP3l%`#kXwCt}15V~(GWdE&md@xScNq-xolOqsOFRPH@lPq$tx#{6;c zAH*IXw}8b5+SU{$=8uIVB=r1$O8NTPU3yoPRs9V4ZK^pd32rqlJggCIiZj8OyiusnPZ*Q#A0#5Rv00>gXn6*>Y9gz@3{?YCN@YMWnC}{MjaS?8o8{; z2Ct>XtlAEETeKhY&HEq6rhcBa<-Tb}sVz}Wt9hLD9arER@B+x+~q_+{SUp$QR2 zQpDh3j@_!Hvr8Y!$yhaQi6t;wOs8^Ys_Gscw1VU$(164SQb%LRGTPmmHgvCLX9c)+3I;3BJb$fT+uFDGTm|qtt#ns9n_k$ebQNO82l! znsloBIde%|ah|7$=^ixk9MWxQUuv8lE7^1{J@tJhB)H164o7;uYvH>XqBw{id}M0Hr5hVcrQ>6rz3>DR?kvnfrPKT^4wzSFarCaDE1sa!OMdeOMh$uX z(od;}HMJ-UXcS?T55lDTG8E_;YSgyq#?6Nhb&!B?uV{w3A9^eK&rhfW$fNQ18%C*T1o~$ z$f{K?Uo=c{XdxtmewC4b3{1_E>c`O6T@A6p+$sy5B_~4L255JENp^itEY`F|lHJ_1 z79BEb&xP(?Ez&m~%{}uda>RObRqiyICA$$2SDuEw7{`%v+`+D0S$@+`I+8O2N~qvw zlf$x2XREx0K~*>)_p3T>jm3q?2nj*g6{8KJ8^g}VZ(jA2Y2GEpzUND)>bJ4od9e&3 z?TXIvJeL}Tg{L4B_i#EIb&WucWA=MsM$S1E*y#l0aSX|Jvpefnliq(k&UTqGF|BYQR4%x za&}iw1f(J48t8S~21P3m$~qiWUJ>wR&xo~Xts-C@&N;7IhqF*_TN<{xec}2n(%;>P z$lNo{c4NW!*DwPel&Xw4ZMhZd{{Rm@3R(DkN_7W{c^G75bM&om5?smQ#f;lS6DVPl z4^TZtdG)J8Gqg^5Yq9fmp9^*AwLOs8NTl)(I{hm*S@fFsguU;h9QU)Y|xXA*vjv`XgtJtW{=<^%PNo0%7kAKs#3%c3Q?pjBiq>2OL+W3Aw|TEZ!|Nb`aYO zYp9G*x-ffpuVe7#^_BLVEd2Pq$6fJo!`quwR(Gs|`gG`>i0n2ti$KaQ>=@U4fJZ8qj%{4JF}{?*87pBS|(Yh!M)%Q-87 zwDK#J)GoE35Zt@T6o+$X2DxE|t0t9OBuZM|Maz5LN6t}f=C}JTVRE1{u9+p#>8*4E?TFv`4 z$C^CEIL}fl?t!nOT>&@UW8S;xk59Wu_M&{-7P zkU=cR&WOe{)U9;()+wrK&jc*2gP}b|V5=zI+Q^-DISn2rzmhv}c5XQ2*P+;G15Rj_ z)G;HeO3m=MgcjRVM!8^vJPdxd>KA%!E@JZJ+~_#3KD}!zMG8BZ)|U3x@W|_91cB=dOea`+S*BNaHWcH zO8R@&98f`JeDhoJ8+Gmv)}mO6L9S1ykxWD`kw8m84CsV8d)%APN&lEc~}UYpjF8x|%;Q zGCeu0Tb&&;LUbOL(7ubT z$h%rL3G8VX!+L`Cgx4)BCNeJ4P5g+fI&=7AW1EXcUNibtv0#?q8s2XX-|gZWiM%za zKORxdcYR9`{>%G}mn!IHEQBrxG-J8Qt%!Unei!{oKZQ&@A%5LsAXNVVXW|~vWh9=a zBFWHGxdyhE!B?fTw2G8?M(qzP&!tk!u|LShk}#O1@Wkjc zVg%IE_Rw2YCBkA(@~QniqD?hM#K)ay&s2lUWFe`{0$V5L|Ki#pM?=v zsbR%xE}1WJije7&1^Gr#)}}P^3+%tRtv4z~5GxO4JHO}5al8c-S|ieFa5%U)JHrJU)LjXt>IEEQ9^5j(7W`!(@qD3PW(^&Xy zDvW|_(W8{ss~gGK&B-H;y@n-0^5A_cI6RofF@kHkyztswVM6|u99{;6&&|QEr<7HV z(suXWxQuR(u?FikGvPCd z;(-eqj?zu=jCxeC{o`Jtkn?LDAhVA=fNEf9rXt>xBsy%t#3=s&QC@?jOQQIOAq~V4 zZX*R)SDFsBJQoiOhej&Hp$3+#VeWQ5BltC^OpQH^2&b+9;=JQk@Jv>2(NAoseZ_jO zgnW8cmfG;-9s?Td^=}SX_>#=Bs+J=lid@&xg__v;J6QN>rr)Cmf-|4?Ysx%b`#)J+ z7kD65K7eswRd}1icRC!+l`Rf+>TXl6Hfz4+qCTSXt9}4)R;Bs5LZ?-A{`@nHr z2B+|j_%W8pJt}(%`Sw>Mhqc}@+d`%=? zC-Ct;Tf3<5iqq0QGVA&qD$cS59eCos!&&h3cCs{AR^m6#K4HPGS61*vo#LFtIpkng zQgNP>M#`U9vWAcQL#)h#SulHy;=Kn+_{C>?5}&jU-h|hTYCj0=rYz_%dhuL+_keYs zDpGA_lW6D(t}2;!4!ZZCgymKz*m`fo3tPRvyiz?u>s<_5#l6r3KjdrSJ6{)T{u-PK zk=!q)Yq-$9KD1?Hx!k|+aBJtW94UjVcLio@u}x^tuSLqfHn252OuQKS0V7%;>Mxk zhlyrVGv9Sw_^T`)G0|UAgUe*UBr-#5zVri#6Y;#np zCslI252kJBK2jFskyd~^a%&W7|8dpUGU6L z2A2}5;A7IfoZXk#H;hNg|a-g{Htf}YJ&uGP_)dyHU>Q_cw(z9E<>jSpO?c{>cn|# z_=>LH8@4KbQJU%0q@yiI*%u^%kzH}e)LJ%T=tcB7{WnKg;~{W3HA`Lalv<%dGW@%J zE2FuzWMwg(yw#s6kq|KL*w@{EXw$@H(SFmG&fhc6cz#-zwa+lP_)DX(8>3%dm9J~y zTS20|oM;3_GNcbm?4-AjVt0(=)Kb~Q8HwXj#yc9UzE#v}N)=SS*VHOgjnZ+k{r@62^(z# zr)r981Ugm-=*wQNRh~}~PNe0~!nP5?q@L%`KN@^9s_Ob~n6Rr!v5tQ#@Z0|Y1nU-K zbK0{GLkCz}A|CWgawP^s2|_>kWu;Yikit3puN!;46y@h)EA_ z;Qs)+YMF~Cl_Tma?>$H0wwo?E)pSJ)2QG2NdopQLa_M8( zzq@0o@g}N_QYW190Kh#>aX0p;XD*CM`q$9Wd=vXZEY72Q4D`)&n%BVl*)B6x82FK@TG~CV$1$EW-xVf_@J8m&@JTBc z$8I>T!Y_s%e4r>$M*!oKUaQP7)A(kKN%Sknt0tjgl~P^3PHQ?nJ>-}(O2`jTE3k*c z66m=PwU>_Ft4hzqkX<7)oHsml73H}_)YD=b_l`BRsqTo5)VoQXh8zl$>^h#3%96^? z=f7cIiEpGwW{P7_$AOY+EmOl%UJ*HPTy!0UbvI6Nw2AXdZ1t@zM^wIL!xEr#itybd$JYKHnE4}gtJgKRAH?_6a`LjqJpryis%v{_ zT2XyZVA8yGs#x2UOQtL7nxk{#n~Uk1S>(tZl1+K0pW>))E-~hS54~yXx2qPJBMCTQ zd)5_bS)!$D8+X4EtmB_xka5dII_=|M6 zTCV*MNIb_VoiZcRXVQ z`uDF*xxQF!%EX~maHxX=@~TtnQoJ~33iv-aZ>3^g>dS8fxR@)BNhcr=t$OOwRz|k5 zZtq@U6R}ni?F4bq7XAKeGk zoDBMAm+dPO^esELmID6(3im(f(yLrZvr2FqaL*X;{{Yvf_9YeLMv+=i`EJMOk+=ij z^!%2g{?hr8%bzZ10av+R!~Xe0{{VebY7+U;HN0%g6rU+Qw(w8>I-q_gu=NKiDUm_M zYSRS=yA6@A{qvLcHH&78Q$phM8G<7+x7rwQY;MkDE`Kq=&r0Mj>@MW+faNl^xd}u{`#zCCv8ok zrpG?s64DA?T}$SoM&44zyx^RSl25tEYGvPq^eArZ?b6leNfqTT(=ji!0s!{w`g2RMSLx|nl0_f( z%#kiUxshB2+$?kUPd1LB?>$`Y+@uTrT^SwFwb#tfwfV+_T03 z9aX?(#sJ3~hbQ=H_V%XBUs$pcwR9)!G8H;d@ourO==)HTITCo>&=nCrBkZj!y>?cJ$az;YqzCqf4 zznnI9{{UpZp2lN@54zv5AdGGG`IM2@zqb-K-wY1R962&x1b0V)Q+!jBmVgCRE=A%WoxwDqu@a`bw zJC682HV>%a-We?q;fU@Rms_v?~kT%+={ma=^AlaW|iTDvZRu5 zHm~t#8O}Ys`&Nlumh3~W>-PQ~)Zb9Bm_cmOlQ=(gV>umv3~|MBT1}kZF0*}VZC1m> zngY%Qt0mZ5naKwRH9d2VPI%6GRK732({+6!<5brj?fffh+jgP-?ew5=8fVwL9-ozb z>8tq0U1MC5?il0K?LpfGrMluMP;jaTeuE_PPD$pvV+-nY%6$)9_^oZ?Uk=Kewu3FQ zX;2Kky_Lb1NP1zUBm%(X9qX0J>s?>NpO5|@_@kr6;ZKP+?Jm$(+f<7J?$Dm-$L}wy zHbMIHUMZvax?6JyYl#&UaG;j*@(4Hws+^pToYz0%%`G6iTdOGiq<@?k*J^{G;r8Tx zI(DrcH1&>*g(kN>i{j6~{Zrw;*|j@aqwxoYZyOex)rylFp1T{8Vw4W3-+>~$;uu!q zS67)~4sp4O+Wr1v>yOsEKZ2jMuB+flB+|804xyvnuak9Wex7Bu%71oL{!BRsn)H7h z{14K+ZKO@&zlFu_<5-WHlo_g3rFv?r|54{w-v&nBid9r>kpEAwg0Z(!LDt&FW zJxfG+^lPNHFvMN0WMF2BG7k0Kz$1*~1Fk6nv90+2%fqM1HwiV$e1RfjULn{<-h+XH zPCYxH=C=0wkZF81(}@^!%z%g+B^BLGc$_TWuQ6?yfQ#Tfz<_ zUj2Bl(tm&-vFC-p6boCOPC=||Y@^PQe904XKv9lHNI5;i)JkePvq-_n@ekR%_7~N> zO9j5G<90f4how^~(qnS7Ou5RLNavr-ZLiP|2lyMq{{RoPbkg)4Hq%G4NcMz+K8g=H zW696C>zb(0rW#atiOcOmiU?zY@`3n|{CCvVGuK{BY%=n z8;zyF!6$)$J4x;iGBNmPnM`dO_7_Uux+Dx7M5mH-o_$Au z)bmKvh4%)S9bv3Niq{c=NLvTvOwmFd&dm-OnG8sRM;lMnd}MB>gB6 z#CW^mM~A#^Z6p`ANIRJ$QP+;W`&W&4m-cMb^b7a7@Zf^-#!r%4DHy4d2*Fd^+#WD% z>BLRHDaH>)6m0p(KkGVhI#)GZH7e`hh;_O7!Q!ujJ}dCHy>&FUEHupSjz?jYQ`vyY z$mzi699Nzc-Ke^{lq}i77{d?pYxQRHPqw{Ga3sE6J&pLA%qHj9fb(pVxQGX=w*?a-Qd*{tHlC>5gI@9R5B5U4 zuv=NQN!tDxq|3&B@KfKfJ-8L(TIYr}zYJa&wF?=oN@pR^j9}x^ybMMLtqstu`jKj~ zwW^1Ux#{Up8D)Pcl?({v8g0=sqTrqlBoWIbszKm(uN|bdu#2}am4r4jJ#kQdoIc!& zZlOHZ@#Gx)b~Rlt+#)izK^+fKO+__yGOvhq{{Ssf&;Z@*oYbsW%kv$w-iEcjORbpW z35=8NT%GOw((?HWim1idhL+{$x`p({NU`R06{q2wY0}qgS&J^24vcK7iHyj!oCw3VE zpFPlyT$6$8PZub}ZN*%ZTA^CQL?=JsX)oU2&fEkG@t|4rIl7N0ANR@5Kc`Y*sAKXxhMr^U1`ZI zq{@Kfo@-7w1RimLS=SdkoT+N*QRJIXpw^73yFzXk-kcf0wUvBf60;WHko=fc0cQvi3EVJo zSu>Z0SsRx_*wjvPlhKoFnSLA6qPUTak!=Ipig$?o5e$pxTYRn80Dz~pC|=l9dOSGI>Q;mt)f{a?tr=O-UH=QZg=Lblc6$xzC}sIMALGV4;j zmhjPP zUW1`{M&{H?jyFF{HyExn!`?cdMs3CtS-PBHitYSA@iN-x^fdWh-I}^;I?qW*K#h#a ztuHMmV9^{Y>sfl1qVt?a3X#DWuKQQktu-k&+w5}vK(0?z(VEctp>vbTt{At?cD6EU z+~w|!W(MEGpL)&Eb<2+r>dQQGG8H)tI*NCQkS=4O zPeyNy+U}vM1#6P&&>Ucj+3^pHZzR%|KRb9~$IZ=oJD9_(K;OL2TAJ?bP>oT6E#Hw@ z&kqM{D+=14z3{)sM?k$))DV51Zz4*BaAz!!5cu@eJbR>7mmv6P`1m-z!eXJGzqk=Mn{Ry zmdBOO0k2Gl!$xLHhIcMLY%VJbv}$`rHPlL*JmT+0lG4$H_PZ7OHr$HNO)lK&atDew z>w}K9?#pRwsaiBM+p3ivhu->%=Po`U*v)4wh~O&cgzfbdN}QU!SzNbAgF)dtJx+3- zQjfx`_=n*-+go||`&eGuO4)2se9TZINPbrpA5W^#U;9Kamg5`s|ZSOwJcMIUA56!__o&4^#O>4 zJwaSzyX!r3!grP~W>^H}a#f?j`sSiEoZr0kHuh=tJjYYJv)1hrD@%Q{V;humKDC&z z&EcXOk-xD#HEBz64ZgK3mI@48hy{96HB0!l3&`#6K!`UO-He*J(3BS{cSdrBmaMC7 z;ugNtB9C!U53PD4TFa;TH_I?}7&{p7)#jh@jmHkC#t9C=j0bK1vR z!Q_1_DdD41rJ`kS$62g+rrS|yk`#EP#xg+b>6*48xY6z7zK%k@*+&6~(y>gIUt(F{ zP|l}02l`h_pqMp%IgP|k<$=ibtY?LByt%g>mr*V?ODoGUb8j}{+&9mHKMK;&EF;t{ zh>Q&S))Qz}CN~x(2VVHerPB2&yfJM*@An=~&qMUCKVb@r*97%Cr|^?1`G9=Go+`BZ zRIx;U{(Ui;&eA?7POve$wj4celf+$ifn3|EK@ z>>rgGRtMw)n-n=YCyI2zRd`@2fGQ_&0H|d#1JHg{36OETR5uM0^l_S3L1M%b#11e& zDzX|p%k(e0%?6(5aQw$LC`)lFdw znPVqo9DOSFq?c0itCh(|RMhe5c7zkPKN{w4u5RIM4CbMN`%w*m4m~My z`32F^NgcJmM#VpcHqP$ZX67{>_|0P=ySP6xlUjB*Ef+FIY1tv&vVBJC8M0A86_#a$ z51Bv}uJ%bcAprW-3ABYLl>_mkMk_KXga?%X8oLeTajp(O3XUBx0fqd<4W<0}T$4{k zB2jvv|^eOO#26xa@n8>A)L2U zSM1Zym3hrlNJicPtt}Eg(|sx#Na`%dmk1SR+=9lTiALId1LiagxG_p8pc76Bftq3$ z8KVRmUX++7fE=WP2sky~cpJt|V=bbe5HibtWnenxrscU{pt8J7V zGBLpwc6}kIh@GI0xvxa{qx(Ot`$?&2kM>K^^L(Fm{-V4r_~TRXhNN_@dfBa}Q?xS= zm4~P`#^Bbd?u}&hk!w`&L>I*X&_FN0x1c7ty>H$>?Kg!22^#)lzsCK`1`p@mjF!ep>MO9=^5lj*anO zThN(fnV72guSL-QH$$jwj%V0O>&%TV!L!cX1&!#rZB-gvTg zv5}ov9Cxf8C&e}w@voOM$lcYt*1YpWbq|)w)P5D=)ZzLOw<;~pPgt{u(>zLK)=N3d z89GK6AX+UG|UWOAd#A4^kMO~TBq+qWitiD#z z5OeKPA@bwN!LH`V;j9-C23d$F-!-B>6p2#>i~S9IpX$an{89W&KD7n04`9xUsbN@kKs-^s2{_qu;qxoLbcspt+tqbQ^aLdK!D($Ba5) zpHWC|e$4_LXRRa?LwYj&S5`M4RbpoeMM)>s6Hc6YQ%=M)K?KpW2FK9VObCqiq^lhw~EEw5u8_%_?l;JYRV;;tTIi=&lm!}iz)UM=+&3AQL?+S%UMb?ioMSE z2-g0>Cma!0ty}B^In7UHrtGzZMfY}$@l(%a>X|E$EAz~KO11G4n^#Sql{l!z$fFaUMXy`ctHb%-}|Tw7=QXV}XE0WVxocCFu7vB)@paOw7i zI}x)dG)bg99E2n3PARm~h?;skl|Qs+jy!Dy{VFz)%(;^Q`&5v@Bh9d>&0lQ+opYSf zskW|=?%9$C;8^31)s^Baotix4C`Q1ROJvFr3W31ptIJ^WK6W-g-L9WcxJfP0G+_LroMNTAk`W#RU>f|5^2T;j4qjz* zijzv8cHoB|yJ;ZPu31@vw&CqvqD^fa2XI`Ub4hJ1Vh-YqKi1~5qV zBA+e2;zDvy(!05@L|-U`bL~uaic}$x0&A){l|`$W4-C2gP zs87MWQ!6MqTK3CbIrV0d;!qSGhNPRr@{R&z`&U%+T9BQT_Az*QEsviyFNAMzGBu>E zFnd-9iab58!2pT{X%q_jMf7=!AS8ST*QgG{c~QKnjV_dtg_b>RQCIJ4GgC zWC49XwGF-e(d`lu8W{(CcI{rOii)&KNgk^ftZpAD8fzWZ^@}lQlXzXRVo@Lw{BrgE^=M^QL2CuJ0_Gw(mRg_@) zho>Vy)2(@bjD8@s%u8(K3`sotbrnG^=DCyxkl}d)KPdDSG?GgoK2%D9iNJ116;e!HOj=KZX-Awk0;;!{c5|) zXN~atP-LBlJapvLyAM+%P*WH<8;%(C#xgKZ>sb#pcQOJ1UH2+no_FnD2j($bas-Mn zPUbQk6OKvi(yH8PuuNI}v7CIM9!qqrWV;$CV*(#Bq_y0DJeN-~C$={M_2>;`-`lCv zrp8#wc+TMtI1&ypdi1T?wAK!WDfY7AvPO2E=kl(9P|@{ApUW~LTas99IBv&3{<`OP zG(>XRJ8ewA`{)okVSoW}0E zk}^8uX*kE=YOTrC?3v@lAsvoDViaemUV0zY)@{DVnhd=@Rql;(82NLxhf}u;#ykDq zf~>&oz9DECLaeE|qzi>CIQ-7q#PYQ{<2KT)Ya0F5M9dcbKaT;rp7se4uMDv z6q29?IQ%kyDx3KZ#_pSD7S`^@QU(c7PI6AxPD$(3AHth!YX!!P)~rHIsLFugXO%q& z^-tHmWJhgzAYj`V$iT@jAoaiSKi7lju z=8WwnSObzWI)m@q{i9KTX&K~_C{QwT+gzS^0H-69&mWNbRhcYptQO!xtCx(hcfmYv zy+WDujLPoNgx{kfwmCiGs!D%_=O*^YB1yg?mMK+e7XPSG9 zg3+uye4+DW<;fV%PbF%mrK-tp$!!vVu??puk~U!dcn#K|j%%5pcqE+Uhv}U0_+$_J z=B*Ohrf+RD#ztok5JMZ5hW}`9(<#abB75gX4Cm z@YhziFEp=YrvcFX@sDp&>}%RQZ}2z6zZ^85_)0z=y`_hUCL89`<03m-<~*M-JVPn| z;lej!ry%bcIQz3OYWkz)i))q)GI<;hypMY5Ep-K*401Neju(~A!aMyd68`{6z0h?_ ziw#27Yb)DlG0ksqg&sBs1TvmM9+f4Hz=Gjfz>z}&RE`~e$GvT_0juc^42;W(BRuY3 zPhX{U9}a#i>t7AEJ9(|Hrw~Np)WacJB0i|yzMU&N*7;0+RGh@eAQOWb_WIPP!}j;& z;!zBTrx`~2dVMKLDJwCjW9mzf_(OkbO*HB&b!Fkd95Uc)ih?^WMgIW1bbx;9L;nCh z2L$!bc<{d&_)A>)cdgB$>-uc^W&9_5MHh$Q{{R|1Iq`==gTcN&h32(RE$$SLwrQ+?<)yTT?Dp8Qjgo{ymTQ)ocA`5iTPQyo@0j+`m)l*1ZGvg7`JAe$Re4m&4kL zj_oJ5OU*v=++sVsX9T3GrRv?1Ku z_)qY&LHKc{L89o^u_1^cmCR$!k@}qX9sZku?OoiSZ=4XYwNS+E$5L{CLyyyeS+U;1 zE%TW0XI3q^Hr?m1IpFX`M{{&85Z#AQJ$`ji3FkS^ez^zh?OcuBoeN^hUqF{WOKt{3 z<$a;X-N!vgZZdi8_*7CyEG@Jquu`rD`?}Y|=R0517DtnNqAXpHAoLl6qpMwbY_p zLl~1Xo>VB>54K4Ay?Gs%y>k{`ZIPA)OrrT zt#O)fnQAxvr_6}tN4a{TAb>!}KgHM5v>?4$rBd%3EM-O%^Uobf8SXlqpQSsrO|Eqd zbT1Sk*vKB8x^=5I_MUu_OAE595(40nkTKKzdj1uI6|_^#vd8djcSOJgLqz+23 z7yvd&>7QRp%S+Un>7!s{JUJ}DAE?J~>Gi3ky7HM=9m@XzbnX}wg)4iss`klB#q<>#Y1I}7#%UkvFlP>Tq%f#jg zX&A#0gdG0>cAC)aeasb|zl0t!Netnm3K(uZSa$ya>(s%cky#LsLFDI?$;Yw*c7KgNDEv`ci$E z^gcTH(fd7Jcv{kJL&J70d1ASeMN(Qs0CEE3+p*@pc#mBB1g#9p@W?-gMJh+&YxNbZ znb0;etT_xY2=^88&+Q%iEsqjP`rn3Nir)VKpE?{6Bpt}daoW5LW>pH_{XHLUh7ybW zC(BnJCbykfJB~f-tez*dO^O|VI`eNFT3+~9Rk^afj$3<(zVb+=4n1&td)F6h;%~Ih zRpj9ht}Dm>%BcmYtt5|Z*0l?J=2li2`qn)6Fu4fh0~qUEUY)PSa>_U4FLG;Q^Ifxu zD>DKJ>zSUm*PYMtGR8y-l4Xy*B78!(P(OK->6)13 z)#s+PpjYgoXv5}74)omwM0z}^`;J0&H{Z6A> z8MwB#J(AZ{MnxQRP~6-r$$&umS2<;?+Qt+~GH&UDYOT(=jd_G{RCVUK{-rp*Mw7LU zl53@j89~cpsoGq;Y{iErxr?6?#Il??+zv6CuAU&cGAj}Sllh9?I9a4O26_w^OgTOJ zRk?0d#q$trn6|(3Vp14x$3SUrH6aEJj&bQ+btqI_1e0vBHlpcvxIZtct5a$Usy<># zJXa}ot*gt3fp2~wS8zm#@$#dGPXI$ai&oM*YL*4HM9%AE7X zXe>*2ZXDrUj&oZmzHNwYlIkrD*bJ?Yaa8`t98qN#bK^YKJDb?7K~mXoK}l_|B+`XS z=!_adY^f+^nWTKKIuA;c*IW+U9kP20(T*rDjD}JH9Q#)>`!QX{3#73*WONS5>ZfcIIhfk&a>qJk%PYmevIkt`rP$TSC$JUaW2OMO{0=wsTzX znnhp_Tvp|ef;9NAcd9EP_3v0ZJT4Mk|(8 zDaqO>tDae__?9_~h{kewtXU^{a7g6(R=0~hEHo>^0R(4^Rw$O%A3d4#b0;X1V1`bG(_FQr(`D;hhfd z;`TV?Pu+v}x@NsTO%-j@BfO3PVn#Fdu3O>ep>wF}>$nKxJs6Cd_IvwHI_}KG`$fjy zGI&2q@ajs{6Pb;hdYnz<_O_5LAc2wGaz2%(;q5ur(2qBCEOW@n{3>l5;Y|AMrbBYT zWR+a!1KO`@9v8dtx%)J87sqag@~*1bgwo~G#oL+Nu(x_ig+q>1bBt9DOGaypZR&Pp za7xyDYWj>KSm#ngbj?ep_^tJ&HjIrC=yTG!9x|hgk5gAGXj;*QhAT9{2 z^6SrGGOLF~QNeNgb*ZiHC)2HpZZD3Q>s9r>DJJu<V=MeX@I`alhPxf2nPNtbi2J?kl)Lft zkwqhr2s~id94R!~8h6#2RyVQui^Y;Arx<1N$iu5aR>!pM!v>Uuc=ROBETADwUb z9`@e%%(#^cG_CUv;Ck13`Y3xhjv2zn!;nTtbmt4|sEuK`2je)R2`qbJ9gjzH+!pk8$cYlR#R&q}K+86B- z(X9sEX`@=5R?jLk*V3PL;kjXNC5hdRY6p3|JE|i_cf}#^!LHs5i+i||S8ya@+|d^0 zuQr7#(`!_5x=LEwU45EH86zB@=T-bc;rL~_W@$qJG5|fjYHt?k>uY|ODBQ8?D;rm} zxsanrDLi!))TI||iAon~tqK+zl)8P($DPsV88z8Mqd}iw3A6D?2brmf<5W`PI&XKgvmRdP5FHe zS7KcZjCTeZ2i#OQMoXrGRAX|!fc30j7Nun?j?=kIDCV( z*N>%gs5h$6db8EE*!1h`5p6sz6xiS#kJG(Y*Yt>V3nYImc{v9mGsk{wF89Rux>QkJ zOJT7)vOYln0P9xfm*XoB7h1Kw!xUv)@Ok`eTiPw#VO{8+$I@uc+NDCnuQgp~BBT=% zEA&I8vAvtEAvhd$sC?RAFi-@)XmuDIQ#|Pj^`u8qYCyoAl!hmq=h~6WJ~L7RJt^59 zl)#KGMmkh&Y9IKj$mWy*Nr6lIE;4@cG{4y~G31)NkxD26y6JH!;2hGM1UzP}hB)a- zmh_+qR?$>o8k@=+aY_O7rN(FivstSidQdDQA6m1FQA`TyXpy#g#X3tUBpBQI)Vpa2 z08lcz>2MCU47xN(a}0JPMShHe9gs5%s}AM24O%Am&5S5;QqA1 z;rIgMH7UGUhb>u`{vb*=wmG`C>f#Q*_S-ZULkjHPhL6avNYiP%%`Tg!xfk z&f%mWi1GMV(nzH+$;}CFkqiI@KWh3=K#L+M`=Y7c+l!Nh09D^C9@K^)DU7RcYOt;k zTACz|HY`Owlwz8xlS~Il>e=~!3T%6GihCecrofw=Q6+6gk6-Z~fey1~>dFgZyd%UKESfd*#Nh4E2im@hwU|!= zusO)CBjP`Y7WUDnjXrhfilj@^Q^knpqj<79RjDE<#1Voigl2+_x#04_!tPVmO?jWi zKZ80q#9bm(mId?hO1KzhKA_jF$fLNd+o+12@%HLHYbnL?&ik?dLMf2JSXvT-&BbsnS#H6TKfM0;s?X6C*m%PHJ#W=a zYvEq0EYKv9SneeyQPbGhD^Zct8OjH~>8P5lLR642BRLfX^hP%+x37Bn@4+7zZ}b;f zu9%qfj%(fgJ>xAm#8#^?kvzv7{M>_BI&Exr#qMziM5YTE6e;#@Xqf|khQX%y|G_W$zraA z)-CRolNM5o&umuFsL_P!MV~8K>pI4PJ{9BvPB3~`dEuXpR~Bxob`IY8$jm?ir&yZDeGPzl~PF>RbI!asdS?)gW5_uNc$0NEz-+#j!$aH zNNvNjakN*K_;=&ouB#G5cy=~1&j!60P1ZE+PfsmvIx{fn4>+z0m?%ql+_dS;*R|8_ zwMEK44n1nE{{V*B0T4`c>sau+>CDU=qV^>AtJ;3B^6rqyoN@ztR}0IiOL&B+!Rm=^ zY_GKbrI-#fE12>3k2Sp#!OgY1I2q0X;=4HfM;1!C1&45PRP`H+4P}L-ima?Y^=7h+ z6q=OdaEvDv?z88cFOA+Lv$~RI1(QE?=ZfzPgY1)dYX%uJQBD$M<-78m*A){>i8u-2|d2QG|o!KAt&A+8>>E1Zi z^tMsvnE?C^RiQnMoFyI4t8aWIrr#+5DbJ|Qa~i+F`%CypiA-ekl&><-{xsa$h5JvK zgZ-hA`PX}*{BN|lWl}-Ubv4UV2S!nnao=$%JENY|{t{kTM8XI2J(zP`bp8v~?Jhx< z)%Is3jzxVFr}*nj)WFQBN$l0EtES(l0Wf=t`S*}ejYU$6YRu^N?W;)ndsMWPMzILa zao)35#$*@^gI`kLcn?j~V=d&PA6!=%tb8U%W;WZSKHQ4=eA^_l*oyiKFUoC6_a?_Wmvm*JMbZZQmEWCu7L8u1SmXczi_j&zj1 zwRli&!!Y2VO76+<*t{lRiu%NDCbS}~sm`o9UWcaX@{3z2)s9Zloc5`j{B7DmH5Arv zv8Fg&3ZW(1z~yA)-oHJJ>(PtnPVDq#<0qph^T8(o3R7^!21f#!AC$v8hCa057GTP! zj{MeDF*P8QO2HT=-Pv*r=wOR*0Jo(p>T%36d!CrAXbMV>Fpwcc7v8ao$6JE3|~LWE0tBK>Nq4{ zDz)1!&hcE^vnu6?^shJgpoKg$c3C!jr;}cXZ+&YJ0eLmXd~3Xi{t(-y7zD;^+QX?z zv^k!)MtXEUE!Hs4_}4-3LfI$yhX`&!8U1UV*4%C%TIzpitCg250?v3 z`4!}S%ctqEJOGj~1ysF?1Y(MFQ^t0{0-o6GRi4gPV(O=w{Bosgb!F`14N;e@^u@>cu`=Tuv`?+)F*H0L_&> z&1p#}meb`Ubz#SSEbL1km$9eAd9q9v#w%KLrj(;7iQja~Vl%h*glD#DrQ8f5a;|!0 zRll?eusZwVnR@~)o49aJKPu#P5^;|$wKP$`TbY*HB$p7EWq0R-yw!W{25U$pa*kIA zf-7Ic+PPSaZ?%XxtJT*73MFbVV&_-BR{ z+UOLK*17|6XKVtvAC+0sbeKFtcCcF7ndD=PB4?V;oe9-^wB>v4VxPOKIZJqAy1Nj- zjWmov2%{wCy}RM}z<7)csCbq&w~L34+c+#cZuB12*?d3vZ=`q=H&P-^skhEsA1r)! zt-V)NGpUk!0*~Rz<-GLg4i$*nV~P8)#sWR%qh4 zWPWf?8=RBhn$NkJ(l(LM6)nT(pHM3N_OOUrK_(yE@;;S=sY)&YEa75Ile?VI2DH8) zd#hPwwvi)f*KXtO*ZG>`HGOh>wfj1=2o&1E6$w;xB z1IVhltV|{$o;D<892H)_kNN9R-d#Ll79qXHa_lfZl|ahiiFYxOoB(?tVNqPkBS{*h zi<8ulc;k=P`BJ%7EjOO=ko!PmkDIPNez_)+DWljU0EpBcqZ_gBRp*jnxGzn-J9Qm_ zKd)M^=Db$f7#VB=$BbwEC~OBc%SRwFoU)vd$Jej;R(PIxt`$n8i~%H;>5Hyj?>BiFGNlhmX|dvq@yi9TKc z8}ZXCjAuTXs#j9(l^vueHqIT}kKo7isi(!f9$%itnSpF_GC>Ew(xn!Dd^>mKWDFkU z08R#f*{rNx>}Ez|l?05~L6s~zwm~`lO(b_8X@rozQ#52g?x27gGcayEJhm5X^SGT!X?PstgN*d(2>$?q zde#SwJVmB>8V0<)xI1OwLaUc^$KB6=zs`G#ukk11{+rs1(Ae7TM7?g1`h+%zpZpao%J!C?V)4G9yZjxX>%lvy57NC zG1{vf4tk$c&*5BDgK0S*QCs&H5t2koV-3oj=O65v#JCM4u0S9I&2=P^hUIqoxE0j= zJ@}EV{5REB>rI%v4aC-xa~!MO5nRsApc-q8=7y72V@;#&6L;W$+RMYk?c`{_D7K6w z8nF50ivVFR6nxUd*A2^{{_q4>%)b)88u*9dcZgp~@eQGha)L-M6}-r9V(79%AmPyC zf;x0KAd2O*9e+^pwy6%Grd++P)J?fv4m0e1YwNFu{{R_0EAiLD>EPcS*`xJjh%iYZ zkoB6@L-!xm56a!gddBXa`xT_UPmzSU!|pqQ0APD}tCly!Hw;`iE}j1X3iLmX-?PrO z@Q&bW5I^?cgzhBSYpq+M3A_GzOuzEVQT@}`s3yFjW%Bv-&(^lR_9n-xcz0a3yD4gI zIUgxd4*dTBcb~$&bK#%t`0{*2e-U_&!1!-M(e}vji&-Iii5O*3BXUn5 z{RdOVGv}WGeiiGt7ZCWy`CzcoY}urP?a`L|WPwf=H5ku0JGu_O$LQ~lpBrvID*n%Q zwtjuJo}~~2O}nyuyTsB2mKN?Z7e1qIIulvSX=qep_dJ{S&-nKr$6twhR5~P4%NC8N zCYp~B&nnDV1Ly$*-v+b33jWUbI_1oAUBkZR!Ey>`X!ak0{D-Yx_(AYcLj|izZ|7cI zI)V-l8U9%Qb@p$=?+odl7_&(Pdv1ycEg2l+8%J+d`g2h!Sy<9B)arg8_!~p`W8wC; zwzP$AJdDXYe9q0;cs(!=Zo}5ME;TuwtrA2{$r&%Wat;m#@4$e4g=5|LgvoIdt*hmk zRg0(G2Lu7sdVao@LLE+R@`sIKwrLea?g1roFhLzS@9Ga~<$9Z~4yw-QW~%n_N*NYB zl@G}+)p4HwgVv9=XYyrta00dg3NjBM{YmNl?sJUSE2T{x-mFY#YA$1#sW}In zj1IUZhx`O$qSQ4hAiEJPd#y{d`Hlfsec1VVAAzQjn>rR`iWqS#u?Glz&KKpY-``qZX5H5FT! zTuroFR?YxOZdAbV8+Zf32*ltpAM*&7Nn&~aB3fdjP z7z{9skO0rFI^Y}+dgN{H;Je%tYLfm@bdc>(r;l6?KPC64S!#=>NF&Ht)r$tnz~`Rl zra|Y7nl0Ezc?7H>Ss1mno?AOSLkgqQuQ=!rCxcgPHNz@11uqd$OUseZay`19odt6i z9w3bpC7xiEEYZQrl`OrP1Ob$TBveI! z@FU{|afR%Cxc>kO$n*S|T2Uhgi;^Neaoevv{(UHd{aSilaV$YHkf`xW|UW57Ki-@{`Kr%-mSeLNpKD_?`GgHGinz4l;SE(a{eTF-G z)>=$arNXC|knF5}`u9G=+NQR-j&j~;XaG&X203N-$3gAhox!7IOXsi|+Jl^vjF0gC zbu%KeZ(;x)2V+_BNfI<*%a#L(oB&NP+5)lOPU6^A1CQ|hYLg=2c=3QZI}cHJ#)|sp&m8ym-cP&r^XE`aXqwf-@IiO z_8e~m(>|Z)t$uENaQ%*aQ}9>MzXDBHNLAd|aKe9g$>Fh{nB?^2ejl(iM)6I#8~0;^ z2*?NPnu`9$&sMdT+Vb5l?c^AAkpn9aaZ=Kfvn8YX`-<{tW|2|0oYc|k6S@_WO~mnE zr9ZU~>=CE<*7p0v-V>3mH7$jn$s+|H89XTNbJ+IiYxAD}0K#|v8P@M~y;j;wTia(T zBvPqTKRWa4Qsq}NX_@zeeM$t6c?vrNQNf}&+7TK~Gsz~k~Nj2JdZ$h`0 z(H3Fzfr2Y)Qb%xb&*2T|!*ZSFw*Xy~#BH02X;sga<4*BB^U$E0lwf zPDdQoGiWDgxIu&`H28G?0JP(3ha-$p^|cr9?oyqK-X8HK+?Q+`Cfa*fW?kfuesP|0 zR4nwAv9&Jf6!y(NTaeJ@Se`MDO5wy!&PlW`cG*0#qLeLybKb9BYJv+L*5{BqX1O`; z*c0X+PX`97zNsy#&PxO9&2qKO^b?k)p*_XHY3>x22fw9WiB%9>LfF9RSo7~P5y~HGB z7RO9hE~AUl1X^33W3FHM5QyF*pHWNU$=Jff1S@pNuBXHrL@uBd4UUzPw##a&5N*d( zT`IpcEiKEGlh}&o9Ll3_1oMGfv%RzyYGh%(ed{k=)Dj3IXwK*DR3fvQ{uX%&3yuY4 zetpTgcTn*Z654E2&!ur1mb)aED+6%3;E{^!H17-vLlOo@LMxK-PJwp~>19F`bDHbJ zs(kiiR$~3G3po--Y%jHHOX8@mElS2qDDDqR^X)`j0%KrvT6#nz*_h02=5`{xWZ>%?C-Qc5nEbWG~34R{{S~M%YTWY8-^GqbJSO#+*-_vRGp{Nvg2tITy??kT~Wi( za?xCV>slVlJZ}ZbR}I(jHD6TmCdmBMlLOMc!F3jhsO?(Tvc9Pv&BQOIWboAH?`r~4 zGJJ8VeZEy}e-(9W(5vTzfht$hRFtv1DN zWQzSp0QpR#~bs2sZQFhg&%i9Q!G~(jIKUY!LEB>xr0N! zMu~Bgo+{!^r|dWkCYxqYG3VJ%P3I64nY)o? z;C_{3!@8^KH-Begn8CmxbgNp`{{Wu8ViT6?F<92KPT_$M(j5p&C8aqugI+LZcbL&(@!4@Z8%dDh1NuV?5{9twSQc@><>~gtmrNgG*NBx~P!mE-C1_S6vYOQ(~M!A;W$d`?m zmF=40WYjLLZ>0i8Q_};dBkgtKn&!Xa5T6SjfwyZdKzi# zPFS*O%&Qp78UT+Oq#yyBhJ8vHvNAJR_x>PA!TIR{tu@L;oV8@%>**4lHFBDViJE3B z9$56^szayV>W%YdRQ44-#)>`5xBe%0VyJRYVO3zXzSUcjLZ3?C(!3&wL3PQlvcpG? z-9QQe6j{B(>1=Y^M}vSNr5QEXS?Lj4r~v@0=^Dm36r|NHHYK*m{{YqSqZHunN<}*q z$q+Xj(VWul%{@R`07^nLO2;OU5yb#EZ8;L27y&_$0YDH<=qb?+gEYe1+N3T3#Q;bi zkiKb)%|8o@1~K1?f!MIXsijusjKYF{fR-?BrI5nTNk8=4~!HSj% z3{I>#Am)Q;!k)IQ2U=dz9mAEL(cpb#YC3WPa=>8MMR{zua5QW)k&5!Khd0e>e9*Ie zt;nxiL%Biqr3RkB*K@->Z{fz$Z<<70M&`LT1bu7WynCXH{WaJRm<-p6%Vi?S!1V_e zZc00eCiEye=dD$dIXqT`*0KttJaQ_NijQd>u2(BFZY@ebn->f^k6O<07lkzc02^rX z+TFsASxCbQ)GqCuRcY31bLPd@xD^wH^^W6=t)o5$`04vQUieE;n&QS6YeK|=2i^MD zjA@##so`6o*>qJo!RcSCdX|l8;~g?cE@D=42*VDw@xR9Z0DxynxSmKNA{HcqIuB~* zjP0b3g&XX0o(TBA7NCg*+XZfw>2|lVUaGt@1`ImpzCzYCi@y%t1=ku4_Q?hxWwK7-bEU$m~UT z_ff|!yl1J#d9G&{4bHg9OJk7KE?Vh;NcbJ`R4?p})wo6+dz@EP+EirZ5D&ShPo+mB zJ2nD)5Gs>TPKJBo);@YHf!mLMMc zsEpcSDruwSU01^w8fj+$k}ppTG|VdCgvecr5LN ztofLB#xw0+IpH6VR~CC<)Ke+YxaPexO4sxs7VMTAg-Jb|yIX`>s75T~7g4rOGB~KG@id8UJ@Jlu)kdRF zLM2UX&z^iy@WSrK?o_pnrNTD4N}Y&lUE*lD0FWO*#f=9r~Ke)Vv9% z_=4fgmZ^^9DEup-R8rDMJEYdBpDpR16g)?vvJbSouc19_(L6c(K+6)Z_KYEia%-;E zz5-ZZ%mNkw9=)rU@jt+sY%C=EGjBjR1#m$6(r|;=6sEU5JH!6~6tr&?BF7U5*|_Un zOnNf}^I(&9c?C`@ltF^cr!V z==Ezm&0fInS8NaOb6VD)7w>dg0!<-OJsULZYtObs3Sg=4T=$8*8y2nvpLK!GSBy~_ zsqRdu_CAjA2gU)ZX^PSUazBVx^~c0$fh+(O;9eBCx6!nOfnRH=+k$yDc1>UeXO?^~ zpfn`qv5Sq5X-|q)?Ui*_{438sEL`dO?ULMtK`eN6IOH7HoL_jJ7})u9{zj-=>Q`6s zkKQw4G?$Y_a}h+~k&Y{o9w>~!2zo8NRSNQXIIZd7 zXEfZSsGWE%o`+v&r>s_lu;<>qkK>u14-LzbRyyquj?sQlcpjDI{{R_$QgwYD;R%TP z=DiHR3sGZXDf}o-y*C>tsqY8rh(JO)0>2@K z9=$8_M)w=534Bb4U-2|LZLGHsgir~|ubuo+DKZ%khElQ3F%r|mxwJQ0N|GO#!X}D+Q;^tgo};`>s-|6R;x7@ zv__oJPRnwyg>4+4K3CwjKqrdp?!*mh;IJGXrnqZedOHm{Ly;Hjb~C)lF-g`f_$jxv~4yrk}muW)uJ>7hc1u0xjRo0#~Qka$2k}^vt#1S0Du=K zpdILz7F8-YCAki)R>t+Og&SMAjuhO}G2ky+_dfz?T7QD{^nwKssYt)Pllk-MT!)5W zT^~w@>EkP?+$KOHCNO&uTUPh~0A)pyr!O-$dUy2wYxF#qD2@s~-lF&3-b?(>I<1L;6!~R_1s{ z-GK5!Dd+s+zNo;^mF0#e1ff8{xz0b&dd$1K5=fINP|SI5xF6^F)EB{;5~ZED{G)0A z06DC=u7#|sByTPxz!`4mwm%Aij?{H4t)#?akdv{9``wS>)K@L6YBHO5MkFG(4hJW% z>HZa^t7^g~X%&?euN-vzYmd2_;`VkRZ9|g9x?}12(1DGFNDA$ZcprX4>)M>o@Q@0j zAZI7Pzw@L&yJh1gfF$Gcq#;(|vpG9dbU7XPs}UorO(yY$;N+iNb5wlcy+nUF&sIHu z&oyoCLPn&=%N|J?+CHC^RagMd)Cx#BY;(;ZAfDyRu_zHxk)K?3$G1wM6iv&#*paXs z9RSZtyEH7Us~R+mf=DN!?@`{vuq(Ul!5Cb3=rj1521gWcBsfRh*yIz>UZ?!_sBa`_ zoxpsKfpOE*^Qo0&HpSFn=V3m+pZ=<@(-^JXfT~Mv`EYtK_3DMroY#b_%vn{JcGe?>=hxPxWi>J0 zW>rO4-AH0NIQ;m*&*x9Mv4vDHSLQtJCy-cwOm(Y1Q?zdccI5~gPSMzto^wuHd1R2v z!>>|Xf)5Aze>zrUGoZ6bJi{ZX`HL3LNKi)~n9WZFJEoCNBaKed2_%+0_4;J~HMW{G zELbT(jlja^C!W8j-bU@)-SVq>92g&@HLS{C~Cl+%sU$g zk~vFrZcpC?jynPE{S7|qSnREetb#QzBR=X0-hU9S`3f(!LuV32xmRNowSZ7S%Mt?b&F5dXa#ZCI5<26l!mkyb@mJ#%XeF@G-*oK6Nj`T7y6`yb$ogPch7x9C?oLU` zCz4OCX-=K>W^^Wl=ggCmPrWj0m1V-l)^%V;_FN20W@t?g* z9D6xqxMPoTT}A@!Wo`0s81+&)qHo@kTjhLYWOX0bpCc|5WD*a{kK+2&4KXSdlB9Iw zl{5iHLPKDF0MkD2UTN|WNjS%~Hw1P60QJxzxX*9GmKmkDoh61wic~w6L^vS&iaPYA z+nOvrkEQ+${?vlr&QA|`$s@bd?xPm-Nje9H;y><8hlA{TjtC&u<-fu|h8EiK*CK-E zT{t6Ry^d)Lc)PLVFBI7C8Fed0frdZ&iG6?U;AED~)+-HZ|k zU+_Peu4#Lp3pS3rv(UaP{7<{_p*lW~{*9zYoZ2bmL;a>INPX^lQHul#9t8GP) zG05bwAZPRM(2nM_*wEehap7w%2HsSXWS-^0MGiqRe3{#gr<`yJ<2Byey`(J>^7FeZ zpH6YN0Q)vQIIML@tmI`y5xWv|v*p|m-r72KAJ4s3wYnnIz-2I|K35p-c*aLi2Bs%@DF>l@NWT8go+%@Cg4fR* zq?85RpnRtX^ZZR{-|8u0M1}AOIcN_)Dj{? z6z))l;hPEw&m#k&Kg-^^nYBfiPx~$O?G%p8MZ%1))DhbukGCGR1%|b!TT3#sdBw1X zVTX~3;{f{fQ=jhAu*K5bKajV@?2RmfxbvpfRbqk zJoU#I{`ckUTs)ey+QOn3-b-*)BC~Mq-#P2lkAEU@LD$S#>nEjtLG%9lXXnNzOs*lffsCQBYDlt9@CM<}x9- zfp-*B^Aa*!cj?=bb5`TKnllqBpWgk%d=*?|^Vosw+?-btdwFSNfAg!zNx_MtVloCv z&s>ZX_}0CarD<<#B#y>FAN6*2*+SJHP6ea{k0+=D2;;*smMJ6ZM^m40OP-l{0u6JyIoxb>aGBP`!oG8iZ*BR!mG($}qi*vZH z6y1Ri$xOD(lsX=fUfS7ojBL|HC0K5J*T3O=0 zmRMtUNaJC-fa8wBo$aYM=v$iLz7`eSxdf;jW9viOt1oDohgCSHMyeTASfCyKKN_)d zZnDRfJ6Lm(*F7lQHZo+mmd--1v&b?&WI);c1$^iGS^mztSH+JGzPV*>3_AUi?(>%@ z&Yjfodi(xjzMv>$jYv5p4o_2A_uxqrnN!T%3Xn%5G@Nd%_9d=mWAX;$;k>>ck*#Nm zm6eJTM?wxOBT(=|SW1l&ef}F2_E+sI@V?{2(%frMMdxY92XtwThdmhQ-#t5Z74tpa z=J{8C8@R8UukA4P8tBezIJ+KU<9!-kI@&p3gm$S&*+g)bcC4@kNl;Eu}B_ zHsk}y`d5^ATIyXF#O{&6%NcBApsgs*Go;hpwDdg##C8u9URuYO#sT%OHM}=gI<#=i z`3%_r*Ro#8_WOAA!=8lptc_E^*6z{VlbKf-1k_Tl;qh!&HHh?kzaq~Lx%p{e3v(+t zRwY}osUwB$7-VijF~w`x+*&~!Wj=Gk6`a~d8F!ZP-rG5RZb6Q`R}*nKwewhylyvW1 z4~q3UY+ZygmW{c{70Fy(wceX9*o!ge0CcTr!AV|1OR0@7jooBxc){Ao)1`KP5!3~` z@13!pes0yq_kTL@stuDDOhpo zSs&WVk+7D}Vrz;Q*7F>P8;4Qawlt{|cxJ(0t$4GI+eAxqM^ky6sp+1zm3en8TSjtg zR{HudGB5|R>sjj(UO8fLb6G(o?97_fh~A$oa}G^HEj8L1O?M z@O^7@M4IFxp;7_w=~etmq{ti0RsqTU>LAxPrANr)S3(R-*IRvR>*^X!ouY_>nK}?U z=hm}z8+}6NLYv0g=TlFX-v0pRo( zZ?PjPagM&ViDkY?iC{>s+AxeXfuoNu=&$x7Mo((c((VK;w-_DhyeqJU;MP0cn{1Az ztuA!d#!4i9C%Rc~di1VZ;j;Wzj;PNw7d4XE-OXzV*;vzIK_;IYVA5kNnsvIDkPlN@ zi1r_a_flHv=V;rW_3avM@7wg84HIb#??nc0?t`Fg!CONX8Q6gi;Qj?4{E1+V@S%z1{if6MR2OJ zlCw1B(7h;&P`BXn4m#Feuck4#F@*(4cj}Jz$**+UAYel4P$b0B{{DCsL+dIvI?b5m_)%RV>(4w=`Wk)=1fj+rRI2{OgyoyAF`QKsx#w--A?#C1PM0{{RhTC?~DObuC%aSj>Do zF8g&7BYoxVOt`*-S-c=ewTb9Ctm{UW72i4e3E&#L;rqz#HAaxdm1BZOZ*f_|5`yJy zcTu}WlvYtdR7jw&zgnL2PP3BHop3NZRWA|h%e|cOlgAh}S46!RF_Cb@FKp79W~r-O z%7Vx3(mDWmG+sp|v;|^}EUU&%YQ5ZWUIm44KfEg^#NTX)iKEUBT1xk_1pAcqbacG) zrXWZHW!x>%^@RU;DOC^ZDV~jNh&#SP%Bcxdxdcg+A^>3xb0OZb!DLzNoZ)z zJP`$$6TFNN$04hU)NSr0)EZcjl_t79N@(GoK~1CAoEl`7*AqZwjRps`RXIv4T}GqI zW7^n<-b}&C&oI88bpj_n#;M>_K%nO)*be~v1Ggc8KUJRbXR(~h+%7<)Vx4OcS(Wl zYn#6DB)2S56)m3PtHYyR>L+xCuzOTq`xc>X$!|PCB(7E>So>5^Y1g`&g6zRhYUwnu z38XkKHyY|J^puGJ+65e~?mlF;Ih`-UsSpL%Cc1k)F(FU_fIgLZEyQDiQmPug5uNTN zP^5hYO}iA)8KIP#1TOrF6r9kjflmr?KngNxz)~uaP6mJ+1}TMi9<&^ew9?c7tfH7! zft=G`L(p}g2NwWTY{kwg6&ReFonzvF8ysOp4nQ8Xq*F-E05x9((wP|arjdh48y#q{ z$K}ml(kiS<3P(&qm|mGq_?q=21%){*Z7;0Rs^)fLSkXY zX?&KzsW;O3gYl#S2>xDbDPRt`sdr>`qz5K|2nmTc=B%aD#xM<5axyVaQ&~DueG5~O zYwd1DJuhD!YOpvMrB=YB*+Z~%vwOq3i$SWuOJEa<_l-VpHq{s$W1mst~?cmpzd{WV|il88>TGd86I2>rhE4Wgz#bJ}M?~4NtOt4|tfPYlYfAzUAN(Rjh@RCmdzT?r7MFFgBKHClJ~mgcaPv}eX&9)1b7 zlF#MBHZl2J4xYxoYt}p=ccL>hDJl*)9V_*Z#oiUN@xF^7Xw~G~$j9qn9sEZ4QE_Xj zO=~P9$CI(~*Xvx$ZaZvsq^G0Y`G><^F}(2o(zJ3PEFZc}d*6h9C@#4aXwnV%$0r0= zi}rxhE5@Xv=YT7l()B6y>yXjAMs+1n>{VRevtp^{{&qde^XN+M?K8oLX04}3ESrV9r@lJZb!BB0ugxkh82+^_-K=wNkVdM5(vEepT#|a8U3sG=+$JWB zl|9I>Ht|=(WRgi5H2{;l8*Au$ojqg>M0*8eUwC>M!*2P3?LwPQgrsFD~@kkoNM)1d4kcSJs+`gJ71@K&XUr0rWNII?uvnia8|O2|VNq>5XO7 z<&_7}#_(^)tw%*_?zM17(%GC#~jC~&KMu1e5tJXM(<6L#BsAO zdhOz{#M5c>ua@rw!1YstE2jL)&s1_*!Rev;116aqmO#NExR0m+)p>OICK0R0uqnu0 zyo&id!M`3g?+VErcP?+B1Y|k+fcn?a9uoNH;qM#5kWVVx+>wHk9j*9QKE^lGLtkwz znma90$SNbiKngN*Ot;mgNYeug-HGQk>9pBzEwf>ACXDhFo^e?U*A^$qolHa?gjY34 z&MxvtO*uuYMV;n~_V-AlL6^a+8t#uAwnaGkhp$TFbgg0SX4(mJoaVYge?Fj8GXMeX zD>T`oNi7dH*FG3SdFC=iH=Lc=uLbdMhP8hO>n}VIOay0kZ5TwOk)BOO?;cUKuXD_-uOnin zSunkUuBHpuh9zhSWg@s=6Zlt9(q{5y&eb^#J5_xvU!K9dspSP%v95IIN>;Veqfwf= zJ4v-`xgFObL8xN2EQ}xKCbQx33=TtZK=tcg4v(#A*Q0Q>pZ)@b2Lz9ZHq21ZZ3nYp2W4(Dba>{bqXi9_^LywD1 zcP<0$b?ePyT*-GO`oI;R2dJ*@<4jpKCS`qy=e1J5u(r}}qmgj#f4$bZ7F|yETazeL zeG1UWED@^6yGGocoYhNha^7p1VnPcqZ1Y=i+{u4>k+cpVBOAhTpRHu--Uf~v_PVx| z#^ij&ahmJH;i)%y+Q^w&IwT}|&9cZ+RRHI`VSG!xvriAPR$at&&2$lXMmv~`wApdo zSCxEG(+0A`JQP|$VzsqE$`GB+Ua?_1WXPK+Gt{3oGRIYP+&0AJbi&Ev?Ci1&J_ zC&2qPe=M^SKiaNW!#}hY^cLnjut{8uuOhZI?~V{(Uiq>%)$fy7dwjM@a>ZQn`C77P zk$%=c3hZ=0hPs8y60$=c;B%gRE8_2j8cOS)G19E0IF4D>Ptv~K{i}W=S!-Vm^%#}Z z$uvYL&vI+x{{Vw~to(7MNOGlTQV6eBpRrWGbd`#NvuEk&hW-g@f7o_-i9X=Z&08(- zLrX*iM7jFYydC0KlS;G(L4bpd*IOruBib`6kH)i6!rNFYhbFg2BEJN5wgYr3Pp)e_ zUHC<%=~{Hs2+?plgIT8XLBB3vgWg{^*^-TA}D=?^R>5RqXD$lyOX*gvM<&fA@-`^hfaZ2Vg z$UrB8!>Q_V_|(i{jU+;$mpz9knvs;*%(3i7&PgK)z#TcLW1c)1k|O1J3{NK~OF z>oi}vU)>HdoSwX6`O_`*;Sn-qEWg2zPT#I+SY>;5Yv|fA3Wg+=83bUS{e?O0HkD5- z5r7!u9CbgPYFb)HWQxS@XBgZ^K~|Q;Tn2sKSR<$(uh*qjg>s5om5c%bBx4}wp7{P$ zsb(Tk$7~+>HK!aaYR!?k0`fuR)Hhea1dbE5mH?b|rt}d~D@BYkW(qUF>GZ04rnhYj zklXo~a=-uvLFfMft%_y!`#gY1%&|UpfH~+0{{Y#AW$Fsdj~SgqjA4o7^*+Dsul@Db zvvRR%UvkaO^9W>ErchiLQl}*2Bw!B2?fmNtSig;83k!U)4bG}^NEsuXal$4)`t=^6 zda=fljIdvn@_E|-08U0DKBwzkea5z^pxmfM2ov{tVYg}w@za2ED<=7kQnD@G>Jvb& zUSP3+L2~%r!h(JHR{sF&*MfXd_@_O@_Znr4t(EyDnOpMxTYp54^?QpqV8;DCDL`Tn%VU_c~g#yA7@sP_lPNhkTx1g|J{Cjc-% zH>vtmQpjG*!MlLb;v2^r{mieNxE1B{Y*S7e7!?D}Lc9Xu32LRaHNsRJPZIpJaok{U!z74fFJILKnMT~f^mW}azEfh)~BGy z-#{jVc+8KI`P={mbM4SEAMg+(F)}nuYZi^VK9~XE;O$kN_J-bNF-Vii&Hrx|$;tte#oi26!BBNIg0!`iiQNNhQ-1 z0k$c1=ik0N{LT4#)3Ap{s7Uu4*}UzHQAB`XDCjUfa(^1tveo|4aTH2J?{Ae^Lg%T* zIpC4ov8_54TcR&8xkc@|}i1&{Ypf=Fc_he40aZ6WAyM}CVM z#z1KIWt~UxfJ zLJh%&I-GaT)j9MPnRR;<*2P%5`DztGP3$=C4{`@kanIvVKsCIGWw&MC0vsw9a?Cgx z=K!4iqZ#L#%(=LICS-wBtTCsVC~`aG@sJKM7>;_=;V`|jLXyWCrctB=ameU>bN7$8 z6_P53jXa(skhsMp;$hQq19j z2&y>fIq0Bgf%mJMf+0FMTtK3N(X5~ay@A4uk#_&#Y!N|$aTyc?4)Ajg7lPeidmgI$Og(?mh=aMo=9eQ-{ zQp!hrZLY}n=@e}2fCC(XdgrMlsU3$s>#EW2R$DlWPKcyBg;SD%X9J$N;9&aZxEODY zO9Zy&G~FXGa~@Z4$Oq=&;GLrf-nR6};TI9IDFh#v?Gl2FeL(i)4D*pmhUaMnfJR+i z<(w|xE=Jl{9Ffns$v&fsp2Jx4l@?hO&vn}DN!&T$f$8Wg5ke#(T5Ypryk<4tJxIwJ zJqKP%@5N~>DzbTz#L7zW;Yn6K*EuIVV4QF%pf!%W6fuz^EK#m-M9u4HPnY0#{Z0e^4HXCX+&bCKJx`Oi9WY7pvBB(~ezjIKChKe~Tk%9>=fXxdC} zBxqT&BL4t*{{Sys)}WKfUCW$f7(J_kL_(%ST;%b$+*X`7=uqrFVv>0Wl{IOS z(WJp%J>+0FQR`4TM)6>ggVDQFE$?HVLlT3zMoKWoKDB9MT=e-*7(G7C!BN8?=e=&I4P+=)i|pO>))TW2nz(DpS= zbUi-(3y6Y94+M;0`d3-we*kO#3D&OcFQW<~asfRU1B{Bqk4&7v9dVL*2fcigoGDas zo3)O28FVtG(;WaIumR(am0j(w^$URnQV`h9b?K!u+pgwO-=A8?(_os%#0Epmc>|7X zwuJEYrOKYb<2c6b$37C&?IsOzCiM5>uAL%QRr2E8;B$)V^^Iydq*V%A9@P$?s05po z2Pcfx)pXqS*c6&MiL@)r$jV7?$6~^qf!anqe%|6G-AMl7=X|RWy2UhjR6{V(H%mz$n zZ>B5VwToMQUK1I&3VV_|))lvfV?tNU1bPbj`uM0_@;j4vyF8-mA2rGVLH8AuMb*6I zDv|;1Uf*-zyL4eGToc-o4+TKS%n^qjdRLh&WMjB*vEuSgER4I6f%L^VTTZLF5&7;b z+@kP?lFgY>0}oNspp(P4O3mfQyL)j>W8nSNhSN&y@=JD9zSs<_R{RF`BiDP3z+T53VHPv?7D}CZRWSz zuvT223W9hD3N!Skv5{+Gsib*rrNpSa%j4R$Ebq*pGJtX4713XK5BFpzPU5O3h9$Fr zq+>bbkyh~#sqmJjx|(`Nh~wUozBdlFFNi!t1m_EeWgONfo8fzvouzE?+a0Rqo{ybD z)>Xhgc&l8o*m0HhIIT}sy?dP7jDygDRN~TgTf46{!fKG;L1GhNAb0evQ>>ji0C@6!tFG0xIa^L}ASO>tX1w`) z`L9D1 zO5CK;kN_2XM}$56O2hbtF=ET~;8p!57W;BA90OWQ;bLdez8cbP?zCtkL&;IW;}xIc zO$uElyu@PO*{*v>@dUBJf;@tw9ctF0uiag!S&3|RCz|-GkgBTRp#*Viw*o=CcHZ9A zbNf})hRGtc+VB*^FJAblt!GA%qkYnNt(7JTD;*5xJyzH@0pps?(}=dZDjO<&4P8r7 z4YBgrV2t9q=erP0!*Iwv(t^9P6^@qfRd-blf@`6%+iPdMascFa6~o(K+uTZlk0kZa zO6YC16v>0k1QCj-7qK?G)Tgd%M)h7edRIB8UyFH2nXnY}?OhJ3Zw8eE%t$-CR~xCc zck&M;K`iFq4uyR>g*n*I8yvFKn9V zvbEVsJ6V}NYg)ju01kWisqCPTKHx|vk_n?_QN zv>Sa4*HgsO|`wx_fEc9oVJhC6i?pK)aXg-W)4j}w$o0MtsFlvC!rK6TU3OGQ-l6AuYYk3zm%(-3=`g^{{V!V19nxR9%CMOsOKhGw`TuGJ)QK2*a9CDFXrTQUWnR#_cqt zD@r*ysTFb7fFn`3^U|I`9jQwy@=aE_)FX&+MrZ=Va5*@t(_N%_=QWdetdpOcX!oo; z?-D_54qtP9YFn{MHgs1v#eu=VtSkL;3tX3w7WA%O_r%v1tX2?kX)JUbok{n~Pc@UB z_BK@Qt0uhhB-d@S6+F^e=r?+tfu$z~x_u|ZFx%rQ8LOtZvJt2OKpxa6x2qeRVyzRJ z(>y61xEq&ou8z}3RRe&d(yv0HJ5=1BoK~qMV%vL+ip>yosYFyOW4%3EnIeQVEN48^ zx8j@}PykTkqwAH2^hY^`~PL9z`_$XaV^Yhl*7L88nVS??4E|8g3V^YBwP8 z4r)lP$>h)ieeMN0Vgs6;VpX81%>yFXK9u6P6yh;WX275b%4V8YoYN@pQ5nJapawb~ z)dQo0Q%N@*3aD-$co^zv0{)q9(%b^Wit6p{i{sE%c8O?OFyv!3yq_mdC_pckLei=Q z88oHvC?_I-6adtL05pnmNZ_8*2Chn=SgiRE~&9nKFG+@@%uZ_y#oB1p zbg5LXPSab8Hz*>KXoRsck--?IOVs&__T8p$#V_N zc)8v}e0OS%F3i+b*z^V3`p}e;M=L9!W zYZyLFj;s4kCAslbH!p848!@_{#=S4VzY}gWhmISW36D4pn%nrj@V?gBjM{oEZVpb` z@rewUGZ?1fg>|b-W1XiLsrE*R;@EXdG-zcGNazoG*N*Z;ky>IEdvVgfOz@wMF8n7JGE{u}s#Z{oc)N4!TV1D?FsH0bj^4w`k;cRdt zkI~xZ7m!H*0J|sU_pX}C@+l%@-GlY-TunGVPW3Kzp){g75X1;4vCU!6r^)6Kl2<%) z(yq=XwUkH{vge@msAa#B;nZv(b|7`CzJYB@^68VMzF2^@i+!a{eGyT}Jaxr&T8rFV z*_B>0J8@OCmP-Z2$lQBmW~DymHQ4iwTfn>RTY7>I7$&^q#Xk!zMY~TB{qIcf&P{y{ ztXqv#VlovEY*#U=Xz|;sAw_W96I({7F3jegK5fzS4ab14Es|M_XJF3US27Xeoroqj zQ^Dz9Ror-5(UhwJht5|#SDbje;fh5ZjckfHXSHt%x7_EQ9>*)-uZ`X!@QkRdaBnRX zfSkHyryK`7>0}uC$Le88{qtsuAHL-cHx9wDi#A zYRBkIIyIH-Yc8L19Z376{{SOR{?wO4xCtaog}nwwYvP{3oCv~Iz4I@>@NotQxgHX7;ylGZVihqRH zOQmX2&Za4D4ngjJO3u;kbj@NvKToryvMR5wWY^lxh2WqgAP1g%*Opsrms+9nG~R#P#}x*zec~M?C!HtA zPdN1Ut<)se#%@uIvEJ)i6gK%b@{XKykyzSYgf|!8>3}k?Ad%EoW9t$dSmZJskTcC) zvee@!OOf@jHoh6Q>Ot9=$~SjR-nrDQ^y1M&9zYxrcppm2)wLKkJ4Q(Oaxe%TD-QEh zfvy=rq=sNgE8nN3d_th9)N_k>zjGS6nLlxpY5p42ZEfD*%4ClpcRYbyFOR%GHmeCS z^~WZ?M$=Nb7G@@3V(d+D{x!aPIAjpyF6P@Jb~*tnOO?6WJE3xh^ zs`(SNXyhq9GgBqg2|jXq2F^u%lS(pCJQaCG zzQ;N7w@^1aG*L#y&fqazM}jPkmaSzgDOnY}itKfrHMKH^P)d$)YbwgpX!VGhW5Oxp z74PAyx^%e_wK?B&>dy}Nk5L+2UR1kws2z9*(w%YRy=4`aM<}C?E6)5g;%Byax1KS` z0=nHpQ?}Hs*o+4%a&wM;mGbWsil>m*5xLY2=?G9JXcJyb*a5%>}3VbWS*zR9yO4+ zh;Lk+lOZ|$YuJBfe;K!f{AV4&jJT0De4{6>Ysr}$9M`V?%N`7q zSMlY%cTl=43>m=$6xwo0{IU4g=x}nL88~jzD{UG23vuIny;H;S+)Rxhm@=yVo~F2n zW_$fW;kY?F{W?>;Rjnw@DV>T6q-*JltE9HuHkE-w-4Car72gEnlv}-t>2k)Ys3n@b zOToeUhpkfZ>&rf%M4Jl#01vONVfdF*5ZkuWRr)S^k?ES~JPTwlqZ60I1?98QpL%z@ z9ke?iv_)$hOb|8~o|Vq(`qLuJv9|S2di5VqYM)rUo;{J|?gtrMjGlAexvR^?mT4i% zux3;8t}qW?wGVR0Af1fOEbLxFn|g79{{ZW#rXUmwyGbR_J$?TGompbS5)+1zv7bRz z?re~z31fmXTabHo{OQr}@w6Od)*2p^gvn8g#N4k%@9QkfU!WKjc(w zk1Gw_D*VNI6OVdg68>nFw*AxxfDSXB{{YUZK&c}s3|cYweKz&~01B7vPkyE31ql3j z^yAv5`z%)E!g5XlIPH#<42o>;j~iS@ayNA!g+*}+%3ETUQZ|;xGoQw!Xk%3@<%>5) z{zjZFjlu*6bZ7g+1E2Hy(gF*3Q6tK@a7NG+W1sRW+;(pxET;ntw6k^kRk-Y-fT#({ z%MwpN=cPQvV?sHAxS?^{=FKRU*{)EWpTnc-zcVgb%L&ukN)yID7L zM1+<}Z$8KwiUnn0%-Idd&T;I==}}(1jd>Hh8488S$I62VlhdbP&Zxe$k8oNcw8jWj z9)O-Rj^Tewj_T?=XlHkSFCRC~N2%wYxCvR?p;t36wJDz5Gao7_)k83Tx!MmWulmO3 zyc6Pg#bc-+?EM;dNbp4Sp~iEZs-H}g&%Hn5*Tm+yn&U>&r!8-fF5-23hamJ^9CjSn zkhAle-km#Y%qKhOf!{yYqurCu8Qgg0m2#&es6A_>$dP_tnJ4;GiW#I-Lzm70&tGbU zHXnB!oYF7~q%irj%>YR2fE*s3c*fIBTn0G@{3(hH`nCsZvRNWo6flvSqx1b}0mfk& ze0dc^$k6T1PzbkO!?U zm!;3EUPo_krKEBOalrc5(!UBm7~AQVMtR^?B|c{gOCCsWo&HuH*{GDPTw`*#!%v2G z`c;%~EM=$RnX&hCfIpf1tJ-wEE-QEb$MQA+7X&Y1(=dCpU0Ex8me7h!yHma z1Dk|b0b?oyWMBeG{{VpgUiBf7Y}BIiF}o6;6m$okdyh_3R5EUr44zYMk$!ZEaKVo` z&N0SM{qsx-CrJcPDUimcR3s|6!TYBki7 zi@`c1XKKFBGk0a|y$?CbIUbc-X1IngDHAfV+#G-hUYz=T-%12Q9B*(wVU}JTMhct^ zp1!{`b@r*%J7RU4)XlU3b@N|C2{ULuhRyglK9Nie61X(bY5huou`4j9>ljE z)t@%3er1h9&A2y|&N%&m6|}xyQ9R4sir?hSeU?2<5z;&B9Q11h!&T>2B!9Y{6MXxft|5@#^M0}YM{`H%3BKqMainPWp9 z=cU+dM&9UKn4Mu<9qI-~anmCQo}KwMq`I6^?uqVp1o=?h9jXrQnLUTE2Q|mVt7-FE ztg%Qu_1ot|Du8ze+DSMa2OrL+zPN{0jYK58tg0tf19B%DM(4oY#~k+hRM=?fZ0;Xi z-4jm?7KmGY!w{xoGDuQJ;5h0t$79xu+XyuIysHN-Ya$k009ZE}0Oy`aIsSPVz_`?6 z3XwU)4ht-b2;9Vg7=S)gka9aWvsBtnqZGPQDS1{`%tW#IhE(k!V2!!`Gg31`&s&ts zGN$WUSxG6l?PHJO=zTvgYU#W$;u$8D)uBJURw3Vyn>>O$44$9;YG;$HsM1=ppTQ()Grt>xflk<0};XcRNIQe z0`T3G{{W3yCysn__%UtqFF}x7D1%T=W0^-M{PeGc{88bpPr*0B%Tk4{%C^$7e?#B; zSL!XasdF27XCovZsIMCRp#A};#Qh`f8d!qgT8AZCNR)|24pbA-j~w^MHRI#5_+sPD z9VA4PPU!eT_UR*lY?x$>9CS5K&fy<(xxpM{S0V8N$5{AnuUzRmt)0cZ&^8;*iK7`k zFbO<*b6mmkoYJWZO6Snm!MrVMGH{czo2hvw&s?^e+U+D51;P9G0QeC9}l}&X?Mdk##4e!NyW~Jjf z)li1y4)s>s$J0jTo9|V|H92=;l-hPZqR&*8;^swp303!|T}uv09Gu|un)01L$Fgsb zhT2=UD_2DEj76XA4l~qb)>WrgF-x(mXB%jGD_KS4?*kbeky(&=Ycobj&!O*F*8V%S zy&@vPK;t0wshai&V(B2q*0QBiaa^-RPNZ~b+rHDmfH5N;gw(ck!)Ip5$`2VB=QYnw zsyT@iN(!m<=B1ZY5}3mD?@-*P^&hpSwT^@mS+(uM?Q9J66?Q8~-~kUUkEs=@V;!zk zk^v(*HA7J;4a+b&1D*vCuW52ve#_nFxN1)w#7i2CA8}c-+DQf(vA5cs*I#LuIVuNp zQ`(2r|Dl6x3{z)2R|lY^(^JU~&gqks!k0@DHUr;EN<^_#|{SEJizsMi_4E z!L8#cwW2YU6kVR=6TuvC?clXhg2pKc-C9yYAsJ(yIv#3`#kq00ax+4ddJ0KBEN5OK z+BwECRbq`Mee1(|)$5BHBpian9MwSyg}zP=TAydBoweAuZ4sdPz+>xAOL(3=jTmLd z2*oVTHMZ#U*jE0T;VlALLrrXe`Y@{y z>GNA$d6Gsjc^=h&P=X&MIt{F&IImL=pH!tK8(kVt4%*R{ZvGp1cUOs4I1x{50h;Hv zkA+%AsGO^r&^e63uZF@^S@z8qTQAd&^UeMo9VN$5tz6txFPp z)i|zB<~;P`y1y6QdHSryxg^&yHUPzULP~3ybv-!jh#`mNuCKw~9c^M`5}Y@!bC9yf z_p7k@eW)94TuB)i9ctw4uE~?Kx;j+w%=%2lWCW4l)|+`^&YQYdTY0Ia@yHo!$-0JF zNedbLvtKh(y)`FoSuu;b6Qn{r7JRS_bS7tJ-yePC*JFdttO>%x6C$Vb~U+uC)y_6 zowyxqIv9n;?$*iY(vp?qsiK#2ItgVLuQMU~RBx;mc@{**cp0vrQ?-sba;i5DeKTC} zhAmB%b{*<|Vcw}Yb}37#ll`LB`<7_V(s(^R1%xoRZT&^K}SSE(JCT<$73-TpNH00oZ?%pZgPhYK3X(N&eFa{4?);_m#3EqBI>6*-aS>uextPXk_ z&C`1tt62=cv$nRn5;OChk7{%wudV?{;e8KU&X-HMp5a;Y!M*EKPSal2=gVd&KU&qL zVM(NQwzszSRvD9NkPh_5)c*jr;__mVW0TlbbD>3h2nESF&sxud(k&BFT)P#|Iqg_D zyIm0$kGoXospg&u&nBw^)g*g}uecFlNzFUW1CI3yqZ)d~Luai6CIfd`3`ZSlM;_Gt z@z#NiSZU#KDXlufIW=12P#bZd#`b6m+BnP^RClTUXmq zo;p-UM$G_Od8#Iuij2KSB!toeQ*cc%xhJheWyLhjiUvMKC#j|ltJKmnz?@{jkeZlcRmROlcKz%guO%ps6FcuckF?VRd6F5uA$o+r)Mz z$5fs?U~VR@YEM%noYNoXr?CQyRo5BXMRYHR=BV68t3v)t+qOQb!rvit$hP_N^qySUz&^DS zry1!lytq`9HHqvH-wD1$GL-}Kt4VQd9G^2F9;2mj5qM`%d%-QO+qJU*yg)<0bGNN- zNu`*P1I#yrlU!4z;VT{V>hs3uT`lw`0fL})=hCvCcy1p#U6p}(6t@v15YM-9t(df* zu;@)3t%6e-BdPVxWhk!Z%5K{mNo{KO3|3$p85pct3@s6Nkq>?=65qquHxRNxbt9hp zPkO%>f$od}W|i=Nx@weHLR_WQ6kqI`jQd20q#SdKpX?fWC1;X0;~e#@>HH;cWqQ#^ zE5`j#b4`B=wbY7QSH%uJE=*;u+BqK;ct1_OnsXY)M?8x0&k}eYVrK}-Fn9_LeOjLm z)YQNZpwt_x7`#iZJwlPF@jIU|bN5^&tca8ubIEb12W+D21rU>s)^2vm*$*>+he634S4yiEb2?H-6X4&8ULx>xsV1L&AcP$G zE^>$PucJO6{?*!Utf^(<2!*VtSN? zE2`4Gb0m?03KJphIjff58Sux8Exy;I%?g8~Al){rDRI&3V7X?}O{(DPfw*;o&j1eqM&O;l7!z zV|YrKalsiCtD*S9814n8)8-TRYT+jqXE-LbId2O1a(@XxB52FHaAaY@HE&$8lUoY1 zeZqMgYr58MQVVr=j|GPrHI-*(FCZ?sQPgI-J)&A1&Xl(srg$R4=Ef-9M*wuH+V8_# zaco-Awz&T3t&3wNv@!rjSGH?U!w}7>mS>Zp`=+&8s~9_`cs1sYJ&oy(WNd@f)wp5_ z5XT4Jy`RQj2shB~g-}X42fcaLvEkWt)>M&j!>&8m$m4JoDO8l=v^eTga`&QTTVH`6 zm*1vq&i*T3{gt6b7~FB1?Fx%~;<@1SUTg7hREBwDjdqys)5Fe9_vs&Cc5N4}jAdE#x`tUqOy)ID4J-n^9+d zCx^;yZ|b?*qLSwqb9Xg9>Hh2E!b&Nc?%+P+;N(@9MVN`T#!TWY3p;MW&;{>(lHo59`$xz_bNa|X4kw!mfk!X-R@eQU;k8vHnK8GJ{ziKETBv655$)g0!& zx!0vjYelk!Hb(-5U8kTOtMr@{{iP)?z@IVA>US?S>~X7n&O(gilhU^JCyP(9ir8}F zXgED913|KT?R4D8!PX;?I&?8G9{xim#Ap`)f%m&} z>0Qo%>t&_eB9gB=U~S=4bJz0yYtAFP7rL|%B!D|M+48{Gi1C&$wVZ7v41ESZl}byAq;l*`$2bEy zBd^zw@u}f|A}q*8*6EYev7rMj!yZ&N+=b`nO z%w5jx6ZroCQCDI}nou^Kx!Mj%7#$5zi9G4Np<;IboPD$@iblE5c zSg7PPbUgI^e_B}7%QG-Q0`a(>y!EOil(NPB(%9T;uyEuMG3Y_+I%D-UD~zZdf(c*; ze_|=NHj*r>B&+~lG27aP0=a3X2^z2=K+bs2Z|PA*4AO5>cXwt}-_U2<6?WjWOrRlQ zpPO$SVyB4}R2+<+02Be09fLcnspIUneg5?k$>^@`Ao}YzeU)@L?GNu3-$^3^NoRjzpO-EB{3$TTo1LZ7x zXP?ruCX~E!2l@B0}xfrN;ngB`Rr;ad3Brb4sxaL0J_t$FYFIIWwjJvFg6k;YBJf}i&(=Y4kR#_6?%84D0(s|xV zI5`LZ03G`Etc^x@vy{w2!iq3(aDH589QvK)P6z+(=L$&Pxn09FNcE9-Td_ z=YNa87F$)CeJ@Ix*4LDpP~CD#DnIX{390@nd|{S&B++zRgB)LS;#kS;!Bsi@$gdW6 z+;UI<0A9Lj!>cfy@1hmhjtxY|G&4{K0=f)=N9W#@p2MvLuy~{#9;1#%XaN|Lftq_W zNadM}yK|G&{b{T)dh^zvTg%)C6)aCByD0ambPo?+c#lwy&c+s&SM(e&sWtU4!!LtzczzpMC4{`J zce}a4Zg}JCx7!5zR7zGZF}~(^!e4}NX<;s9jb)jBX2{PV@;LAR0L2RS_%!(Kn25qg zi@+O)Es>Au-}sLe99l?~@LP0ca?7_E$AA3<`i^Tx3na60tTN0*hXCVuY~#}_{{Vc} z7d5c9)}k!Jsw7d4RA6WD&N;#SO>b$I5kYYr((NkDs-{dHNgNF0JYzn!pKh{5@-oIH zK!!pX?$a&`PVz>nFkXI z8OJ4teZ4BYw~^%-E=+7m1mSWC4Uk4TJO2R5rw=S_GvvHU$Q)$z*B$=%ZfIbIxVCLT zWzhhcPna77fypDUyAJ)TFYOe2krOcJc=i%pP1D^flBk4fWmf|={$dX(z$P6;g z*Pm4ZijS()vB0+$f-)2{ksr*eK?51-#t+TMwK^EyHIoFLIK;bR{#&OjuBbJ0NK`_(dP1-6A<%rdGR@;Es>=dzLSyWXke5g9IByrpc$ zROAuc(-|9ol}?st$y00h(Cq_uK|k)Caq?$5?r8xkNe#47nUibJwk!tY86%wMpxob$ zMyuz%lE%f6o8(ZW;0{Jd91s(qb56I4E8uN`3*`Z{sr5T^fzzW9b5-WBbRu&m<^Z`< z@`28J5^?+k(~S3~1MZ@hI2A&P5x6+^BxDR{pl1APappl8kYmhWkZu{rV!)H?TkDFe z1dRw;JkvLpNy%;w4hA}ZbaCp{u^2ZH#_TqgUBmztnL*@$J%J8SyYS@wQ$|A0W_IOb~{+zP>AhO8C7u}8!UT&5$CI(-Ky4`t=!w% zMLWiP#eJn#FxUWOg1xx;ay!={49N4xB1|JJcLW#&;~3q6fIjHs*WR_Qbzk1Rh1bm^ z_ii{D$=Z5-Pv9tQ4w5}q>hBH9%H(Z~l_!EvudYAugIxxbd~IWgay7imk{!P1d~Lz( za(VR?z((z3b~AG;BQV-rkW}DxwvJp(6aeN&7zz$pdxA(`r7%4T z-L1TYmIq@k#@(^)V7>S_&IUO?wb0n4a4N+pSuQ4B#!Gx{B!R#goDwAtLpZb)JGK;RC%*F&l5_Yp(28Cn@1F&&v@B=+bIPjQYxSa(Wh;G z?m%;vclL5Ps@@?>w-A?f;g_jPL!KT)*B%upbPg7;~M87xWG8=&m9dzDKdlK!x*_s z%UIH6CRM@g2^qk~GuVAW?NooaEo}|C5Ei)3?=kU$e;zr`KSP?6SBYb`&)QDl`$?4; zf;bsDJo;nX9cv2m(mT1MYg?owks*U{AmC>pKvHra8C+w(`TqdxeD7}TmuVBXnz1)P&I=4@r&2lm zaq2N%m*LHK>@q4^$(4{2T0l#6AAueHd-csLw8L}IX0?Li1GQBdR{*9NPv_iIA(12> zy?Ih~9HU^C;PdV~)H+V2lPsH*hGzTAkU!5rfBjjS?&dio`Q|AY`CDKihf)dW*RNW& zXQ?|fWxU-cLlAORzF(A|%c1qHdwFvj!v6q!r{2#av959pcOmg#Ct*7psEDMt6;Dhz6(IfUY?A=?Bc)fixmgD)7#@eY z=hmmgp$?d3Jy$%M(HXPPeklAP(f%rEw-!2`v{Fl)$0-;khfJTx`Sk>f{G<52@NZQ3 zPveb8O1-h3+SWOL(dB=cT}a5oV+V}>Rr@_CUB4&*8uIUszXkNKjQ$U})2`xJwHU{l zZ*rbGF(R(!RSe=a#}J#HxO8kpx0~hFX2w5 z@YlsRHWz5yW00!KK;(AMzCV$w+Fph(P?u6$*>WrM>`Rsv^2utAAxoXKaWPs+D-GW; z&qG!}viC@S#l&~OlHPITfl2K1nDNBTDnyc z?mt>twn(Me^Xhq~!xFdzbshUwu2)|1gQKsJVr^>a0R84T?cS_d_^xP&%-P3G)>YlR zN(lzD)6S7rMm+kO;$qWSFPV|YV^PYD zkjudpo2Lmq3$(dURIPD!cr~=w-c7I)ah~;s`D}-2 zy%~Nfr1Ct+&fl#NUL>Wr9lZB79QuvCx_T-y=hwYt&3SJMHdqH8iRk~nCRo+iBo4$^HFx4iVt#IYb6r&M)g>nT zkvfr4OR7C4J!93%o2RQa3dK9$0- zHE8aRxmSftaW2 zJ*$2=AyBBXW$}v3)AeX3Fvt!;1040Pn!;;YFHy^2FRgx0R;^F8ilqk`Xv~;AKG)a2 zREvbiezi+i_;`Xx5U4D9;=8-aAPz1ek#eKC?O67@_St1-!6f8Y3~SYs=Z8bF(}ZrP ztq$GczFok%3t^J_@+9x$=Usk3Df-qS}ltdFDvlIphOctE_2qC=LV0d~ z`t5p8U039Ddn$8UX=BDE@cgz!U_S3maw(SfS1#w|Y;@#TuHD>ek2ngTgV6fcQ^{i- zXX0XnI zWgW`OjHBkw)ag8YW%4Kp%v&KV6baV%&Ja# z_N*OqOtgDUL_)F88U9rivyN$d@fA!uO6i;)v8fxWFizw2to6NkxW_ft>6#pGDUL(S zat~UL_rtMUTx>WwJ!`UgnyWh;vZncYk;%RM%lC%|rCQQw#M{^qbDHYk!SUQ%?4f+Sdu*{ zWYOI@ImL85RAZqHrf%O|TVJ4!a0v9Q`6G!+s{zNSdaq-ryT~@V2Cd#{HwgR=yw-H_ z(5CFz?|q44Xw_Lz0syR;*hM&(k_pCY)OPbg%&aky)~R`JrMIaooY$jI8%f$jaSPL)-AhqTb6G|soM z#JK=f^|p7INc`i{wDheS9ZbnHovsf9)~~^0i*kxc3J+Y?u9Z6p%H!;A0xDuZZ2HxG zUrvSRNgD$_^WL}hJDB5vBep=&0n}GDe;o55^LTGc&Qxf{XvG_!YXAtTMi6G9RAWwX zabH4gP9y|z)`e^yYO6?*4qKXrThe$=Xc>N6gkDL-R+~`@4%*7OzDRP?$N(L)T+XxO z2$LypcOOw%%4$287&&Z?lJ8UilJ9|7I+u#R&Ipf_?OfEF^p^(&o_h+C*H52PaqoIP%+pFf~h#rEhSm~En#Akt9`e%k=fCA$tx+^_7QE;n)O;WzH2V0j& z7}{Tkp|=5?ZffZ*Y(QU?LXT>(1)`@~wYLj_fm^7k>~l&^TaZU+pz~5}3&8142tcI^ zo~Edf29)!PaZm+021NoQIW()m#Yu%zLTzTC10V`F=Zb5xhQOxho+tufc%&==q|N}Q zxd3K>CEO3C9&lQ%=89{~i|%O*xF-N))NOOW?(%Avn9{dSD$EKa`p^T!Z2tgzrA)Ey zriq0-PBDy71d61JU8Ih*izvk-$V~tzBi@67+LSP)b_7r|HhPKJQ=24IWaFuzMR7Yc zyGY`m#eHaQO+zGj$;|*crVH1lR+i;h?OLyMa=&zSsq~#K@26Y?w=@ji&~&kI>gSs5 zV?h#y9jdOCri&;5?^m|tni2*-cJ47v3yM&{QrW^SCXlLB9&qlAY9Vz#RC;mrA6CJL(M#bXaNfDJ!nvK zNDe#Fv*2+^4{P{wbLQzWu5*E1pGxx|g*UsPXvyen(?>OmDTw285!$>@;%=SxZAZ;j z;j7z-uRi#nrTO}KlrBp1REcMcGG?Q3ikX`XMI&vh84+4Xj1f{f0C7#oBA5{}06J4o zBY{%`gMuhKMtGzJ3374>;I5ljID=eJjmz zv*l-OWoLAJS!1C>!^ych-dFRBRge!QBbEl(V0!re&%f&tjo5Q!W`I#y*RQp#f z+N8oMVEZ{}&lxTH)^z0J&dDWFT=?!-CeiLCNmPbXK?bf_UBAmZIY%6fSFd>A;l0+R zlitH-%^xgTM-}2Xi9MCUhhr`eBE1y(k>^QryB_oKx8nm_x>)KGaDGtict2Y9JAEi? zmq~F9;6!=C*Tu11fK;j4_3Qrt3qCH*q0bei{Diz1?;78pVr`XnZg#-H>T8^9`60DeWn%r!Zg_iCUCPrTW7KD@ zayFAXQf(QUmYWr{{(OsvJ)4TmN!?{2MTPaPUlmT*_gjz@QPU@yqh}$uP15i)(3*VL zDMgT7Yu7Nhlbwl-bgGt-Tgy8$Dw5sE&1&4)jZz~dKrjP19qSFJTVf-|*62n#r_G?b zUCO$hlUz(v-9Tb^IO4E%uMf_U5i9Rg&7?`@^Fme7V!M&=x2>0Gvvny3ntSd0!`9Ij)$=OLLk~aoA4`_~TyiJnKH2e=ImW#!giJ74%=jpW5Qm^hamn zNCYf?Q!p7r^&P9_TmJw(WE;?hrCW4Zyv6{1YL(-vGI31(5M49Fem%C1^Gvvldklt+ zfd;u>8F*6v08K?{B4>d|-j9H5;~xt6{{UR@UE>s{{WMDEN)!Iw?8joS~fCGHK!91 z5Fedn{ojbvHmCn*}8lDH^O*ZvHve~23?EGSyw96lw0S5;no#Guf((d1JbuW&9*PC4G zQEBoij5_Sd>2e%`An$TiQ0qNvJJT})LSQ$A_4 z@Gha^8)-{JEO;1PuN^DV{sQ=3^2)+>xwm*(NnE<)y?X_%u+q>Lu~v_P@~w37Yx*9Y zp}gKo!uZJqVAgo5ZlpOI(Cw5VRy?alb0*STShwxTs&{&vk8VS8oQkihd{5K7ldx_~ z)1%aFHM=CZg9pDA;a0#(G3QR`^J-yTH0;WfL$=tlA2W5TcFJIrBz5Ms*q3EMK3vt? zy*($50;mKW^yyw&(Ht%E&6&zyX z&q4SZr7oJfrRi1NBM2KD@_JWAtm@4oyN1s4RD;-aQFsc;w4VuYxLvYc$XPv<4nM7B z>o>0?Qs9+Ap4IobD7aywp8K7Y)zUgY2BzyP$=!nIfCsf=_=Z-R;aEOVaxss7wRghk z_Wlwwv$B?vk31Iith=T&Omh2B9E4$xtLxsox+6uncr(M%Cb=EsE5DKZ!y^&S2OrL~ zb*)-U%gGeD*}ESvr>E;vY0CBGhv zV1jpc4tKYHnD+dt_}dNwl0YMH^`x608OZ0q`TVOoeL*BfSfnO4k}wu%!IJ$bCI4F8ci87FP$<5CRd?lb`mF zQ&DD7V)s^#0Vr}6fp+H~FwB?-^!2X+_`C6u?~M9hl|EUWyz98w_bu`-;M|&T#vh9& zNhZ;Bzm>7J;^kW>oD!?loun|sv^)!Oy9Opghxh!+qo)_^w z#Q->bhqxcsw6r}2@5DFBYiAL87=TYliAu%BH`JHmFT%Tj3TbQmp!d?ocS=-(3k(uZwnx(j zy*(p^uEKJz;HWG!?th>DJMB~bjqRQ@^2s8`TgwbEGJ0o@+l4;Wyv8K5$VxWiILXgI zKBfJ8S3c&T$YTaH{m@~zJC6eyKabx2RbNhu;_i8d(6N?b=LX2yGm*jUbM(hbyX6&P z$q+doGL`Got~zw|=QVo5!QODOaOWVX=L^Zt(;58f43ABc^51;oH7Lu=F(-qa%Zz8P z@2+cEWivx7EJ86OZjr-m+M%#pzde4r=Bq<))-WVxo>39OA@PC-2PcklJ#omX7HHWE zK_ZCb`BC-~8$Ct`VgmNYO)C!MjpXl;nF8`#a5>29!Su*Kon`7%J-cQh=JhSO{o)DW z1I}=#f!8%^_9$YEzW)F+;xx_)$!rnF*8p+fHCoL;w<#fFKmks0ILIA+$G_g9!YJHI zlZ>_^UB`aT7@q$CmOXjgX|kB6QZu|3AweH_DfT|9fA6Y{+(Bt^JRzD{yw8;2kCgQ5 z>$HA!qUsy;{nSj}Ncll4k}!DS{{Xr5prWua38C6pHa<}2fB^?M>)A)=Q%P*oDu|n4 zZRjZhvxR7U_a9%Jkz0zf~iSqMa3YTdkh-jpe6G*83~&i2j=%5m`BQK2Jjr6%fDM3ePnWL* z1JwQD>583-v0%oAL69E|HWeKXI%n7CKb0xES>c^l5FJiqQ^4KH9QFS1LB&$CdwC)) z7GQZva^G~2bIHfmY0V}emR~Q*l167~2n2b|$?_|;hFX{3oD$Pn}jdV%ubW1r#uDp~Pi3rNHk zJ7ec0fV|)l&+xWBv|K|Ci`oeb{`Gvlguf)50h7}l@6YE~8tw1lSd~m{3g8k4a6riV zfzPE=n*Eg;MMlbHTOemYcY=EV02!p3X(qLKmNr|QWQ=5I2OMVveE$HDs<>Ev$d)O= zNJMLcwC!A#Bx5-zJrnUAD#5&-2b6hW#kY>E4ms)kKX>)V6(8FnXmUpBKse`)$Lo@I zkHUnS*3#6<)18}h^X0c-_0MhqeZm*)B!9 z2_8pX*a3h$NZ^bP$__o+rj^3^Z*FqzLV`+$W#j>$u2@vEque){3J9YGRaa@;a#Z)n zKnF@q+!lsgqF*~faS=&JBLs|K6M%lDyLJ_RGb}R6I>t+eQcw~BCmdrw%0C9IrnrLM z{eeaI;1bzE-F1{bHgfPKwb((eqC zCZ&06=1B+$s~%+B#Es+y^vD_ZHFr#%k7&`gxhIJM21bYga5AnjgPwgpU&@nE)F!>Z zduZezWl}$Qt;P=|dV&rJ_XnP8UjgZ#+g7g?#LH}|RC!MsJCu$yfu6(LB-WpdbhOfM zp-Al&W(%Fr{L1T&x$o2*9Ovs$^=0fq4%<7CbhDOCp_uI@8y(0TgTTo3864MX;qMbL zksw(=cP<#0U}IoLFiAfAde@H~Y4r<;qDUSLKH_2}M$GjGJdc;^3CBw8H2r8>Dn%?v z@SeV629wtW08T;29S>1UaC#m4LvMd)J-p7!+sdCPAC&IncN~MjA53)_t`_6N*Opqk zM5!xzExEQa$sIB*_1D@aDH2+>dUp62#yP90u*&o^mtS9V%}b8(B(TS+a>x zoR?5Y^~qjxIqE;HJM<4UdD`5|Ybs3O$V-Rv)B?-NBye~cAmi7O*A=s%_^#sGNbaJ` zp#VHv*LF8{2cZWaPh1*h;7Q~wGx;p!WT6{a=LbAsdguC9UZ1L4XjbCl%PiJaGH$j6dD;=yj;aeOYN#yzw$gfE7UF7$WrIpKO;xybBILY-V z7|+n-kbBhZ$I$2%X12WB6s;UB!t7J|4EE>nsbfYGhh}LCj&=?KMZf^R|Q6K$n~$3en0#x zhSOX+)wP;Q6zQ@?$W{-Y3H9{p>0dpZVAV){Vmqz<2Nv&R@L9aM+effyg}d#crCL7Z8-n{b6=JFSSp_N z&hL4`=<)05<# z+f5~uOgPwfra||vBKY0IV9R=}vP5uq3=%)BZ45-KCZhEGMJOn>%(XFf$W|+l^l+sV zbF}rW7r#b0#sI7BsL68^M-qt!agsT#i_I!%)NV#n-3@y*7b@kM!BWzE(JsEAJgulp zaa3Tsl39xO2CV6x7`^kArG<<~y<51`4xgwfG35__)vKvZHwe3up(d1`fXyq$2u=lD zgtXDAU~;{yMhloCh_1kR>57iiEpQvjCN16guRYXm`fPP_MRgeOBylT8!5ymA&ZjlZ zN}1X~tzCI+yqk1`1^oczRy?|Uq~j!n$5Jbn6O7W6RyCD7Jqi|g_X{kcoRsc6R$cz1 zB2L&ObBq&R&X)y(TFQ=8$NM4kdYE;~bk0uZ{fn?C z1l0*HROh*^ZBt5+%9vBMo=z&K_B%s!9|Y&9uX+=w%9-WVr0&WB>9=hJjMB6?=eeyr z-7K`}g&+?2#%niGEo|7&6|5$v*C~{tBsa-+18Jw5OM!;meW-%zRvh=JrqtziAx1~7 zU%uUvGPIEKc`d7M-a+=P>#q^Y%#f`)`RJW5s}vwpFA=L>73WAPZF8dt1A#JB#>)L$}cKJewZ}KBOGq)SNxy?f#0F0 zJXCGU!ZlOS?DXAblHCA)eKT6tz9P61XUuE?>s%a0OJx8Y)%#shif!*-D_0JiZ5-B` zc1Lgj012(!F*Hi#sq5=hlf@To!0tE|iKkAITm_VlYoY$nid+b}t|>y5FLlRoPOQ3( zpI(|^8z(-Zqk~$L_?Y9jHDRqIgoP`bqj3yq8e`r)(g^Sd zJJm~u^2XL8u}Qy)Y9}VX7onvVzj3o~m{<;+)Kcpc+@xJlL3OK1EQ50rRQ0SmHDyppYFj&zcEz`GPuSbuXr(zzM9!oB5;>X` zjJE^ys;zmsxX;$G=asy`6!0nos5A_6cogADFNFlEN$AABAPzUV(5~8zVgP zL^-0`Y|>3MnXaA}TjF*%Bb-!`czb%Zaj;fi#Qy+F$hFqxwUuOz&$vAeS(994pU+n@ zvFn3Fc%FMkS{lN1d39Qmvp$=0(X$MWxTk%;GK@A4wNSmeTbYZqmS*Z|lRBiJs}`=v zRjQSxEleb}yjF)vZ+c*T!HMU+B>IY6OP0W_3yb!NK{*57sL81@IUHuUjafdS&X$cI zde5py06#D$vu4(v$=Weo-PWxgwoATPRt@iqi6vnf_pj5O(mNvuEsokvRTLJMOnYXq zH6I%UESAH0^&Kman)-Xw`^gCh_5qjRY-^Q0ty zbX2ywL){PpkUo{Wrg(KCP|^&yrF0hBYR02#Z627WsbAs;Sw~2idS8Yjh=zVmboP2! zj17ta_Nx}wfjP%YyB)}gV-?VnTO87pmg2!^6b;p7071a2g6xw{X~`8t7X+B3Gwn52 zId^rbcxnKU-4np16PiF2REx5J1)tPXnU6T>M$mbn$e?2shDP^f4wTsL7@m~<%0~-H z!uFsAHw2skPgZPZpk^7!rStZRU`^&8^$fF-O=(Hs4ARE|W0OFJERQEaijg8D<%L)Z z6krN+k7@=n2RsZ^!81vMPXiR};(#8g0HbI%9!_~Q@gNk2OrQZx{wf5(4wW0vj?@7& z5Tc?jiigiEI#PMNhe`mMnAA+Ak6KXUZ#3XCGeC&SAFWlro63xi^=4_pDXjH^O+s*> za7_as(=1y4=KvGUdNz-xM_~y0er!}eAJ9_9C1y}ww#tmq14DC)mjPEMnj^{fsTd8o zrUL;CeX0AFkSGHbqzq6Y*axK{BycG};*@jRfDuMI(lF+p1vLHY0BbG zOh?SRowwOuI-Elu1uWpDuh>MG<05-GXMoKm>wt@8iOS% zQbsB0LUgC6%sHS6!8oYp;Cj@z1flk(Z$@8Q0LRs>%SI%NiC2+Zo)gx^+yV)Y&N#uU za&0H2U}`>Qk94<@60zsz1NqlIYJBSJbZH54y>>LdA$S505?enQz|YIpzFhI9nJm^sj~g02Xe%BX*Y8Ow!pCf(hk*mGthBbEf#J#V@SgUD#*kJ!|0m zTa$K4UcIZ(J{VBdXwIhM!0P` z-Wg9LzqMZQw}|xL9O-f0T1=u=9Y;`o4PkhuX|yYa%CV5QP`L)VD#5K*sO_aSE!~;c zNRZqqW*KZ`0otoYq^6-Ujz%cC>E5&KH6?p7EP$Mjhl+V8S#I{sp=0)316H*=D|pv1zd7hB zMy1}Ya-@>b;B|@h9m))WM?uABY90}NUKBE6i0VT1uHNTIOV?JJ*kh$tyOKL2}z<{Yjc)Vli2wl(hZW7e$>mn88(1H9qZJtyf36!_=$I6q6Y`k zvpy+WX*T{x_Iz6#jFDYj>AM`R4JYJtz7X-phN`@DVN>H)eaejIPi>Ct;l0dSWu*TAY?!N@u~IMx*0J@U5!_np zj`p_CEvO`upOl*P8N4~+Pl=X4YtnBLIV2ed2{G)%2#vSe?T!JJer`UM z%Pc#J=31{KrZv>GdK{JZt*T!%cOoSbM%g33HLqnfx5Xwf`H?DMw_508n@fE>TTa3( zji+z}70#x+ABW{@J5_6#2_u3qqOem^dc97GLB(mYTTSs2+xV5*D9mZVZO4zox(^cg z!tU7=+maQBBy(8v+e3Dudq~2}JE-R!=)0aJ(_LH#bQmmKns-fHgqmk-;r&%+(ZtsP zGZB&q!K!iCS$K-(NF0TaJYeu^4%<nOTu0n)b#6SwK0MR8-e1zV?}!{R?}aZ{$^WhKt+*@+dE^e(}z+=c2u;8p17D+?2y*y&x~iLF`O-g#ve_l|bf z#NHCpuGz4P81u&lzH#Muf4i67VN!&nA0xwcM|M^leq-&_RyUFk6pWtr>)O}DIpSxQ z2i${@4SDs>iFK#lIGzSko(?#!TDUsYpS=^$l{=aI!w6DNJJtUH3|SptShTc_L#xSx z4@%6tk%g!nG8Pa%xKE-bg8;;nJD8~hluk)-!6ift)NC1P+psTvo+g#l= zjKMaX>^;VKthlaO+=gO`3CgODdH(?GQg2XO8j^g7!>B~gNyoQ7^xXp8?%a^0Ad%BJ z=A*P@G=-34IqJu+Jby~*wEG3MwQa=ja8Kb>mBheF8W9|yIo-H{?N2jEW%FHe4^54{S8B6kJuq>{UfIQ0xV`%_vTY7_ zvljy&?GDv$dz)eAIQhx~L|_bOs2<#meg>%CNeqCfRSSa=9>fvr=uJy06fY)@*5!~9 z8?<;_4nL1P;;Y`p=SeJ*vNQ;+0FNB~{!gw?*Xd8bk}&a2w}9$5InGHcNbA#{^_wl^ zz-%b0GD%$FcKoLYpZ166S(jrv>r;vkv^bQGtFYrATxb2R{?*|h7rrYh$1ahk%qC-$Qdf9=~V6~-x?e;tBu1X;A6MA;d}E-KBWHuW=ZEH462oL z&|qW`NBiGeiuuHh@8yW3RSKUz6;41sbH+*RKJRLF5nk>nVi8%`V4_0u>`pUG z9H;A4q|+cVsze$guqu$F0JXF^rMuD8}Ss8M@$l&9qf4a4k zJnAR%%Mh-NN6WjF$m1RG7wei$p(~d5g|xU4ws&%h!#O`TIP1_a=TQh^w`rmX&nDlI zK>(Z{I&q(od(@w4OKTF0ra+(}D09=E{{Zg&dH13(Ep5YK1~+(PZ1^NUM*O46rJD^y=S@FG2c~86Gx=em3Mg2IPKYAKq@c>6(@+ z!8TmTtYZM+oZ|o!&#x`{ipIIs(Ib*kxs`G^kUmk)FnV>{{c3wv5yr*UU8Y=aC$Tur zdz?4)sJQHDD@$&yR0a+JlW72gbDUsf``ziG;wV-`EhMElRryq&y?YLSDvIk-l7G7! zDo2gjAA6=pV1D;na>)t^isUIF9wi_WK>(jo$u!i3W;P@@Eb_(`k#meT6c4@Fd!VST z?aP8+5;8t`P#c5tkI{chb?KVnTw2Z|bx|jj0Xw=JbJy=L6j)jdJH@zttP6k(92XpN zN6}N7y~AR28^=T?FgQ?)>anEs3UdOsG-3a``FhF1rJqCH}g{GE-+{S58UJ@JU0IKuX zB!Q3zBkulw)otz+I>~V+^(Bic=YTqY?7VxQTF=(ukln_h7ywKb$;%Q5$4q|+=lp5f zed407=#<2{8*W2w~Em%k|GG& zRC$BuAfAUkeqNrn#_7fx_0bZ!!mBijxFBHQ40a@zKY^~I$VF?YS$(chEkoi(WaMQ^ z=h1m5^7f~D3dV)4_OW92svJR59wVLo+rEURlE@0d7us$rbam) zp19{74Q}Wf6^+W>pR^#B3^KfDAOoBO&m*7LrD5Ibwt8jN*B`t9`H{B+9;9a@p8c{q zidI*-TAIsjFSj_9pDl*LDdmPX^Xrq454SZAy?J$|tTKdbD`BHSoG8XmKEQF?=~OiB zN^<^e3MB;PVrS$xaykM|PDewJ!nKk$*6pHsV3HD#k>#LbnBZftZimw#)!yXn%H9{( zCQVW}JoQ+2F(H*fIXDF15(zDyxE*WS;DXv%g1h-n$0gTx%=3c&{14AQqP!ySPiuSl z4jMEv0t`*q=bz8FZk61_;swyGnMTWrBSKO0m2?B4$?MdQ#8kDY(=TfF-??~D6i`aY ztQa^L03LddzPucBfm{}=V&>swx{^5`aAt5qvjND@Jx?Dn@6USl-7mzJ`rd?6NY)#L zB&!euY|eUvla86rc^-neZxlxqO(e)Z>*6M61d*PH0M|e$zXOgsW88PAxL(0w;-|Do z-(gf%`8JWcuzM5G=NKNKjPqW(;O`vAd2tr`2n-dWZUAG@ckAi-SIw7b_S@O!Gd@XB z!#s==jyV4S4speHo*N%JNb;-*Q+Le!R506vo}07&d92#kLhg^O;M5}4EH_$!W;`@y zzVRNMaqCfPb`qHJD{NjdxMv5PV;_}qUI_6sC8C*S{p{doK#EJAfc+0}Iv=fe(dx}| z?-j=1Ey)T>{Jz-dka8)en$%Wz(7>|QB{u@zB?yH4!dD@^n~})l{PA6Frmq~ZN9N8} zLU8#!5->jxt!CWVTf*gbrpHW}$Rr&1AMFm+nHHX6joFLAbiX!RgDCE}F&dHSy1gG>iQkSC>oF;cIJ! zB!p~o2Nn5_ae(!_3El*(6pn@G3d9i^Z z7&XcGm*L)%tidBppt~+WW7p|aFEx!yF%mp}S$@sVK$D zicTm!tX-o$8Rhf*Dv}$iKFGV^Q@MVgl=%J~OQ}y1l-Swe4naQk=y7W8rP~yIJ03wJ zk@!@aPl#16k=7PCIUsbeI)!T0sy=sQx|&W@smD$G7|{43tf7wDc*g8yNF0iYd@{6} z<&DQXx&{~-uT^bI-&h080ay+)xXp7HuruC}vba!xD%vxlMpKks-$Pr@QCetuUbpc5 zEiXdCH%FeB=}$fwxobldHszlf&roaCLfgjbBp}Rq$r-I%3s`iwS*1Yedhyg(7qqP_ z^K6RuIkf70)qADSqh0O1h2zIf!x%M-ajQJ~fJnn0!*4mSth`O6=$&-4UhP}2VZwpZlLYJ;Jy{U_n@y}d>0? zaUwE|atW_r>kgt)i#VKN2WE^Ln^>3q?&BQQt6Nz9&Rr0e9)g{BXCza!q!|?cl>IXE z?AHZmk1@YuI#$w?aJ*g2(~5f;R|q9yvCLFDZm z8k}ms=SS`B)Fu@)3#dKP07fkSQd0LBE zOLriUGu&dE#LiOWW}e0ok1{Z>=U+5!>C&FC2-D01t!S-{t;M0nH;SIhC}gxT9Bv$E z9cXn@S`w+<-b}y_UVa-NO5M`+wzS9xc0WqWxX|YpB*qCO@l#o8H!#RnMIfHyuBWq{ zb!R+Nz0x)l#M@n-Ku^-B&8-W`_nd|Is<*mr)Ol2e*}IHY7@?QW+Q`a5!30)tqf6q5 zNl9qVs>4zUa9b-{?Rgx4d1^`Z70SahTFDx?ED6ElyAKcO_Zp12NUMA4 zpyNf&+9VIF$8QNtZGY!kt#ob)EZ;S1>iRod&e2M^!R#s0_!8}`KHUnijB}l*^{!~u zr3H5FbEa5nH)OUje$p^dj(uv8LoDBW0<~>4^2aoJkvbBmkzCQo z(r=fV=Uc+*ep?)ln=F$_{r)N&jq}~SV}t2k{{V;lF9n^1mnJ;64+p5OKK{~Jb%StJ z`DF3NGgnU$3Y8?I(873U7%521itV(?iXMKos~)cu@G@)yPSj6n9o5R9jO3hFq@EUs zPgrJ?BR#81m1(rO_Y^5K-z(6@4EUC2G6Zeb7ggI z%M@US9oD(Mv?XPIOs9tBcUu+j<}o*xSOPr{TBjU~EQc+M>EiG$)&83IGsNalI`lt< zV=sqiw6`o!oF4U*aWtoOeNameI9g9)v3TwAxw0y)%#6&gr}smiwYA|*3O!q07WbS) zcm;<_+VQV}EcCb>+DrMRr72@6!lI)s*}Xg)sRvO#5yp$_V}!`fRGL#2zdiM8>D<8kM7per z58TQ7-Hl(k@a@&4Tb&EX*LEuQou`W{H~Uq&Sr?Gbrn)^HF8ohm&_>F!uNi(w`d2Mn zOQr8a;ai)>4yr3pc6uDzl$S0`5_9WQ*x5^V{3#yhwRGo>&+lexis>DMK=O~ z1z;(%Fz#ux%BVd}Rc2|A9Vi0HbORmf6$3VDA-5e#$*KIWN(MPm2faTabg0!i>r*P` zfEo!=nnO9xF;8QjF;S6@)Bz&CY4{oIRo6MEmOZHfF&W@ihE5fIDmFk*N>8)_)|zheXb|OGwlPvW1YA@NbFp((Maxen1prFX znO`TRZuoY=ONJ}cxfPcjWbIHgN#?sp+PM13?+@QIo|z z8v~kS9Jm9TQp2@E$0nXSQUGoRAYu+_g^qdRoTh*!4UtK>=M*adDZmC9padY|ftq%B z$9gzkv<$bRNMY5j-~Fok8%UFVlxNz$akiJsx{b$X74#2&TqxyDc`K0h74uul$IB<>&!u`5<&tVPY^Mwuaa?unubK0x!>=HU+wkVM z=f~v8aKnykf~+}Z%#Mgk>df#ziQWvl(zQ317)gRd&N?l4?~JsT(k)hOva59&>tAvB zn?#RRvXE>H_~VNCd*UyIZhqM%z1PbIeo{Rv2M&Ev)lR1_jPlP9OKmcFV1*~R>s)ul zPlt9B8E&(>LNW;z==OdUhR#NKhRhy2=Bw(hZ1(aABQ1bND-_%%q1k0pI-eumDrvVf zgd298b4|CL-vWF3*P-~o!nU{XJkZ8aCR2Calq9|r+xb8p z_{X(!vRmE7a8cxCQh43ak4oSE&AEc$%O-rXIvU5->~F4T5&&b29t$bKs!>EaHeQOr z8(os;C$T+$8o}`oh0Vewh{uD`PBB|IGf5;dMo!YC9!K5!R2rSZQvfaU1C!VqofF)y zR@TQSZ{dc5P4WgQo{UXsjUL4iL}UxN5Aa|U*Y=&xkk5(a6XG&5Us75gy?C^j}z1`hnf&@Jt{S~G7wX}cUs4V?XMz|ND%G= zfs9uhX2RB2Nk-DAy>up;xy>Zgvo^dnP`i|5|LVp^w?uMl}Z0?H|{w=hE28v=Kxg%*!xH>sk)wDfWv*7+F)21#?dgDC-?j)eJ;sq_ir`gHmJC>2S zC67bexxc#iH@&^(vD|1eTA-fgCvZ<72E}zA8M%t)!sG2bN#p|EYt1|;mimsaV|$?# zP0rPB^>{@03RH4&1iTZLTwMi^8+u*b0Ls6Iw<2G&av-rC4%14+EQhfM^#K@ zl25I5ej%61w~Em}b|Z`?JLmrZ*HuQ0eXq5#$5IiEk}@vuZRV0lpaA(Q183{cTIKa% z(^(_=TZCCVN3pHd3vXhuO6b=UK6_;FYbx#5)^>=HOO3z|p7q$@a#4Fioc{pAKQqhn zvYp#O_NDOO?j^sv2s0iK6aLZMYcs=h#dmS3SjfgnOhMQ&{vMq_8t7so!$D1`0hE$h z4!mRhX|CY=9Nqob+U~sMLm&Z2MLh>fb+pD%iV(-W^1$`MKmB^GEwcvPBrVe;rbc=H z02;Za+BC948NncMee+PYWjztr=$b$wC6weS-~(E7k1}9D1OwRiq_t@6ZA@+(aK}&5 zq=5M`@Cf7#p7qj<7?K3HgM66^dmr<~BsU=j_WRB_Uc#F^jWcxM4CA#n*%2m2Ck2i% z-=;s6Fci!p4)UhM$5Ym`-sR?BmA7Y|qm23r(3*JURxB1ZUdQW-qY+=3w`^7iqWA5J zmc~-@2KIRsn5%Uyj!DV>pOs4u+l&M_!Ta5KJ%?XPt#u^ji9kZ+?ObqAzxnS|THBJx z%qkF(gitlA-aF#+09~HYtJ4L ze92oQ9B`-Q1a$YOYEz3-yZ41jT$TIZ!gKj!tz^wLv|)*t__9bG=jG??$Gv3PqDY~2 ztjLKPGAcs2eWYWjmM}kB@z07s7^Sg^>~z^kyODOY1OB9756_O2{{V`A5|cxUT{_NB zHtpAj4WBRW@_#Du3Fdj_cae*`9J4XWCbg#v`^?UB=!d)c>{zkhNhGn(Pu8Jqslgb< zCUHSx-Fg9CXE+S!+MFprl_@j;6G#;GpmnEopa5_^DLFq%LUYebcpjhrxcIZ8OOatV`DY_%y#f0mRC3mE9!58zY3u6uSQCBYfB=}^W5VeKmwpni_87$xe$CKakuW5lLhSCCLJMo597~8--yZ8JmoLX*W zTrbR93R5^x1_1BS=Cq+>cI>zyhCB{Q;~)>iisx?T$StFd438wBw2~2#&<~sG(*#wk ziDH^Zkh>rDKsXrVfPHvBLsVVd+$?|9sy+Cr{y2LKP} z`cmpKk;ih^%z!$qjPi0ialzx+y5sn2^wLWVO(AuWk5mVcdmqCs`BhsOZh~f6wlkgE zaz5&UThoDt{VQVT(hHP^DVbc!w2pWuxyC)4w|Zb^TU}f`i2x#K!632e_lf*CVb-Rz zS?#%$g6zA>4uhazamP^S@u$abwoP=#bYhG!3m$%Kf9$y)pw-)p8+SzViVdYpCN`6U zxbi(uKky?);K-UW42-}Luw!d-ql^=fdXb*PJF1=3t@ddoBY7EF2^r&(O8b0=udOWi z7iLKikt8BO+W`c!cFzO2#yf5m7U`poK%UGBV1oj&d`M40UEa^~QZ_+>py+lSe9mNhGsy#{gt= zlhIiE9o3mN%#%b+{2G*a!UlZ?8kF50yi(s>5tQC z=dNiq2!`S{p8&`_%$}QwIc$y(JPo-A98e<=f@1;}+71W+o}?3wKZSomO_J4RJEM@I zC?Flcj04ABI)%kZtF{sX?s$|14UjMgZ^?MadWMR*PAhwet~}_^nHd{!=8N#)O9LDIRa+oqkwMm8$@h}biZG6x-q zZ_<>Og+=OgS~b~d!IWW`?IFO&Q-O+E)qX zwmK42PdR`yH#@&#L&UH)O_v>8@8vUg6Oo}|!0Yef&UPt~q zM(@Y@L8DqHl!kRVeauJzf(~#GuLOQoP8*mkW|z#iFJ#2Xl8zi?XP_N{z#V>C0NB#a z{k-=VI$Jz@&c&|vf+;MVP><)k(VG)!cS zg=M(TcY&_)(B z+>X3tgX%HHYtXzc6e)0G7T$O}fL;89j4(L^gN8jYa1UzYv~h0*v{F7{g?RHz7t3Jd zl6V}9eF!z#Xry_ti%rFt0*o`tli1^d{D{RnS!gTWn;PDgr(IjAS(RmFE#;`osT|{+ zgVX9qxU5re1aLK_!CdWSS49UrV?SK?`WouyxwoCs+A|HqE*StM9-II_+8=@THG`{I z8;I6tK2*^@RabFcrAR74=ln89YMZ@>WN}ko-B~1-@NIY*wy0M-Rk6Xxzo$%OcBaX3 zJ;k|++2jttFv)YCI47@9UOEw3GOVy)6<}hC{$B*&95`JKjJcqgV$2R#Sj-mGbwyqbC}b4s#XhQhRYE006$ zdwyN3CTp0ai3FdEO7Z@V^R+E z`F{h?Jx}T@-MkO2{kFr&ySyv3gjZjee;gjU9CxU>N3FA4HMnTqQb@72%KW3yoOS%V zR1E(BX_Xm)1&ALgABf$@ALp%QLv<=#$z)lYR8mk(xLu?Y0ALTl9;4}7Ix&J+Ct^e) zuyXhWH@~MMkoGa|BA(Y#wnqS}xysCbLZooWNa{2C{cA>6mRQ8L;acuImOD;Qs2umL zSqn)TwbsO7z!t~Lp2Svt&9t&g(pn^H%D*}?kj?n?#}#%YuW8~Gnm_?DI*_D>#(VO6 z{{Z^yw$n8z?hqZ}@HsW+nvr=41C7Ht}G4h_2RHq8?bmp#^m8^bmc*DXvr-l4REw3PG9YAb0cAspYp{Gf% zTN`4gD8$GxP`6*DeZBEl;XRkceKof*ivB)fl|VbV=zT}yUl91y;r6HCpA^k!sX|gY zK4{&S0Q1|eeo>v|4-VZ}YfthvrBTy*Zp>{>E+5OfcTj+jm(*3rb&ETDJ*8EoJn%Uc zPh7BhtQQgxJ1=U)iV>p2=Fc`%^MX28je*2_7;-167@BR%n#Fx;Lvwb84naMAtE2Go zjtJvP6b2(0KhC)Oi|;p3SyPzFbSJs_xbpyoCvJ&KQPa?8kOSqQKH@YG5)PaNfRcjVVUEu|{V~mVf9XANg$!dBN zl$uGCH0J7Z%HJ?NW34#rcUxXL`6@67s6Vjgw}MNtBW@=+9Vxm(KD5udcF4ZGSD{5h zvXmh1dG#eaElNnUq^s&7_Blo;80lE|x>DNfF#V*K1oBwsx(z#3k3+aI$bb-WkTNRv zwFQmoTdm3o865FM=}Ip8SudEQHBuJqbCc9`%Q%Lrq!m;Q@AMlT9i)H89gj3%KJu2PZ^b^B3+c6yM zKR;^XA=ZYEJdq@fZP@2;TJS4iT)C=Ios)YVYZ#!^YA>0asd!a&Jw{1UM;vtKxvMXQ zH`>8Mqu7a%8}GoaKz$a2kchbY7>nY zCG91?rBU#=N49|Pff=!!k;8i$<$PPlr#^&|>u@fx4 zK5B+Z=6e!+vSx4YsTirF^_V!+oZbCRWnP4ngcgUJXul3DbqzXGJ0CJLh9R+!!m{<> zhK&`Xn;_CLKf}l(y<0`_e6g&Pmd5dx2d!ArG`XR@kv6Qb6UR8OOY8HeIZib$mqVFB zPAW2mu6Q8ucB!Mr9qrxJ@r)2bt0Td;H`X#-NegZRKQPDTUsyMU?eBDu<~7}nbL;T8TGG5y3!%N)Y;KKaqcSinW2>PC34Wn zy*pOY%qKpwGXxCnRAo`qksi}!om$Rz<4XHU(T<}{xPDjK(7uF}8K#$BU;|#s4 zydP@Qd_N70kYSm2vuCAW&~=z~2T0`F@~O_=go?l7XKg`IU>hVsg*g6o=hm+}(uEq4 zNh8pv)MF};dz{CId?jV)x?aT?4bhK(tzWqKdj_2`xwU*KJAmo|^sK2aH7L)MI&Q(p zWn3EAk5`xMMGT~je;DuSMM&0iyl21MX9~2R#T`)uZ*g&{LZIwmFi7BiD|1lN?cT;k zC=2c9Jmmdrm3?)h!{qsjahzmVSEo%Dt!S(#{p;{~{&kgDI#E)Vi5k^ewsJQW>GiGKtM{J9R0Vv(xIXpA+-n#5MX8L&+kyF991;FC%R>)1&Q2{| z`JGi~9#o}!BfGTteWwk#C6y&iFxm2-!m|8F;TW~$c`fBE$fRxulk97gxAArD;0Yze zZTjGf=xjB}tnEsyz!u~%JrB66cx+`4-b#0U1sd3Ti;^+2>SB0*O}y~q$t-`oBZ4;Y zYrW7sQ61D03%g`5&t8@1m)XgcC3eqxtt6y2(aix}+lsLi2dNy>8Ch-1oV84l>=ignQs=fQ0UAYvkZM#M z)6i`kij*kefj|urcc-jebf>7|oS=h15tzNHrW~5GTOCC)j%X28;S2SnX3_6bH$7>k zaw&|D1d5BxEZo!NB~P_9OWKePZ!wxuu$vomc|SM6<9821rXEUlXvV^-X=GRD14A(}cG8=JmYWZgWUu40=#kBbopch6cUQ;r-8_q{cJQ zSB4PT;=Om_WW}sDlhU)6=%jieT3SWvOH4&wLIFLir>L)T|793Baw2=m>*Af#vZ^&n<`60;K`F_g1qX2i zQpgV(=7hrWPjYe6fGer_xu@~mW;E@pIz1l!H49~6L2PqeN5x+N9}(&9@V3_+f;xj%bUi@nSKd)S zAv{-f3f)85m4$h-i-T#MDc@7$Jy*lGnmWlDU7JoDY2?;)S~N36?Q($Rb;W%d@gu=2 zZnxjbkAdv6IGYmZjlq9+fFZqIWp$Yelh&DH1Dut92o3#C&P+ z;M_|jmg+`HKU(_6U0+SN(^eLX68dAB;5Fv7jF7Rbd4%JR^{gs#YMB#tWvv;27wR%6qzXV9k*HFi>KPMe4&Y;qy(-^xpNaq#kMoLQO1ft^XZg_jd zH~tsYW4gAHqIEe09<}w~!f%WEZ;$ll)AcQjcee#!ztX-Z{?hwPlsFiz9T#1?(C^~8 zww0oh4nrxWtR2v-rK3L7@qUkc;aUFKWdWYd@4!egHTj0OP zJ3kiMCY7ud7dv+R{TjPXYrxjJbnmFx#x^%NO2VxLQ{Sie9W-mWdzB7TUbmj{))keP zJnja%JvP9_WRUsHSYUOpHq`ujx@N5;Q$~0@RiC|e8YZzWt72!3b^y44tH`+dQqso`ctW8tG9%b;J2^uhZfzq^v?bWlzn0(9*PfB*9 zb$xj>W;nK>bOX)GnY;C4e{? zJu_Lb=@&5{-_8?0)hg?9xnlN3Q}Eu-&LKWmXH!*g?DX9}26v4lOk@x%thqyTVl9Qw z1B`=Q-PeawXxb?*OQ}6c=qj7+$mQu{4#v|))Y-%lE?cMqxPKUYJkl<%CJ@N6$Od>7 z>RL~SEOd?K31WH9YYO*B(qB?}9Frp)V<(EzGiqDtWjH4tR;SJSpM#ppX+l2joafrJ z?HEJ3WjJN8rF=!<-4+WnB2V79 zRQ*MLL-4=$&9=QrtUOT&jgAz|22}lhE92|Cku0TH=M`O$gOSA%ZEA$lZ2c~q!#)l8 znP>LhHb^|_21CTcyer}_z&&ciRa=Nx&9w(R*ZSAZz7hC~;vWNCr21{_&?q_CleGR7 z^#1_EPum*TQAn(OO$dpP%4P#9ezZwKrm|Lj#~IF=ve@Qi(c|#t)H2H>2g2uX6!<)H zZ2Ul?J7Xkm{7ue1>)tgV3iwyzU6{PnZesHoWm+}_SC)9I;m)<;X_`c|7Z&6A&}WL~ zmKIB0&Y0p?O$svW1{?3TT*6w}`l_5`@T}coG`&uCxwe^Okbej~=eHHl#i>50s5}~g zFshssZYp`SjXTX(wYm)5IBfnE%>B(SZxrY68k$Y7i0_a+w4dne!x?R){x$6W8q>8o zE$x!!9L7h?`OR@Q_7~Rv8%5JwX#f@8GAnOQ_>Xy{cxj=#gqhTB8&?@WTEBJfN4~Z_ zKHpA-^}7Ux#HJ!0vU7}cM!wHA#D!EDI_EgADEJ@Z%}2yv5bu`dq!#OL?X`y;Ko#lQ z<;2$#Ifw-~Bc7GjNm?f*M|m8~RyP+{Pj_;_2$u*+$JVp2CXCxhI!lQ>&KRBu^dINe zrPt-Sy+yW+?N&cKjsO_x?^*XkI~eUPWGl3sE>1Ze5BSi;i@Fk}zlaG|1l&N#Up(ip z^sbl0FFaPzLm31rfq-x`Tqc_KY?fe)TB$3KNeg_d6}->N=d7npAmYAd*xNa1S~4{{TLfopmC_HtsA{8vtbV z{JR>Fl`kIR*o55JC__j+2y7fKZ48d_?keSoO!^XktzzVAk)?Hbg(60ftW1PwJY%MRmum6<0E<39 z9vQNGXk<_A2~=!ecXcC4B!}-F zaqKHvaOTyS&Q>71yqfyvN#~HsE1a`8Qfd-uGfnGVXE3?XwI~>%3{jlsm;p2nl$4-% zpa-bOG?^@E3C{+Vc%TIyodsC6wUX|5;e`v!A;PE}lT3m(mBJ#Hb~p+LQ(s7Y3ivkg zd0MuoY+B`m^CtXDJz;^2R;kKq}fG(dl-{ak%!8|DhF}-ALU--q-g1BA!goW zRU8s=oMRpP3cX`$w!la0#sSCE`2qMMg8 z5};W@*c`CQB#v?Q!Tf0rgiRdoaOW}u0bkQgq zljbDx>(u8Q`V&?(`*-qTDXp z?eFheIPC6nImQhy$4)p9Znn5wP#Oej-f*dB$0!bQ@L2@BPXvoLDPeZ zb^^Q2{-3qZ+lb=c?tq>F93J^0KU%ia3veCVaYfkACn3~vz&)@Vss1DNsP6AP!504j z-n;z7FacS6@zjDNUfs<>e>8CP$fv~ounWLQ;*&djblbwBssGf+<) z#|;{Z71Rvis2l)E#(T4M=tTnvVR<~MV+tdYmwOMr$UAZLW*Fn0w6_<{rbXv$K?(Vp zq&XPmk8n6a)A`g;tES~vF{`%b2muIB&D*}__3ctRMR9Q_nSw_|z&YTM5B>6^lhTmJ z+TO+H#zxbhkqZvI=b`7SFXvK4dmI-+Ffy#e13P#JuO7;K)fnvXeB_Wnmf7;q;3)@d zb>kl=;Z~LUdK48TGUUvHUTlTD-aoWhWtAx z>p&dj4#|4RfCfh2v>bxDU^veh2nSlfEz{acgrEw*fa9RR1cEwrM(^dxci$pCi^@{;fpWt2HrE32P3B^ck`&? z{{TjeLf4>@$!^YOP$0`>XVU~^ z9-njYp=tvb*-R{06-~u}E!1w{jC(JCrBt5RbW!COYDu?wUq(ZYKOd*#Rvo_C2!=V# z1P(wPDfv`;cQv1Tx#!3)EK&m84guQDxF5wwO0OXy5+K(svS5@@3aH2=?a0qg+5Bot z8D@=9{IK96fr1Ymb6L|xC8g3Nhi(Q$r;vX3I`T1&-6|VRS)HQt&ea)FpKOkE-{e1? za?3_)wK^E&D&pgD4C=9+q?`=#$Nl%sS(FnT4rU>?V>?e$Hyo0Ck}9mSH_7tuSwD6N z;1Y9ydFjZZ3{XPyw(|R&p&$$>EJt7WSMn6%>EPd*O0%3DxWEw zG)3WN`Hld>aHk;WKPYqbKD5aomfpaICR8j27pma%>HX8vv#%$)Y}=AnFuPa<;c`_@ zanE!3)`_BQ$?xa;8_3MwbZ%7_aLLAf`OnP5k4l2_?WNP6XhW%CxlZn*uNWON{XMBA zktdcPF%%uH+@9Yy2nU`rDl6rRA!lx~VmUUJ-p4<9wmCh(=}m#Mmkk!0R3pFcwiZ^~ zkT}OZ&T7^SlibA_GD?G(k3ukTN59?8R5#I1vcO|j45VjnSa;x_{EBQ|B3oIO2~d~d zLp$MI_G@4%^^p@&G=BV<6+{*WS9#KFu!ORu?1pd@%WP zLFh-PUYvtiH+L&_a$%q3^A`=XZy6a4?Z7AV6>>?Wh8V(-B3uP@IXEXLzDWZZ^#|Ii zTcJ9ev+EK01UBedRHg<(lhfuLV;tv>xHZveTEusdScjHdCP_niqpD!wmN^;5NIY^5 zed~al-R_x(o#v~kaC)%$cmU^~GuNm%Jc`lLrx4vRcvM=m1zKX?mbAY3mt~do@GNSuO*7)bHN$Ue&hKX;xv6l;=Yd5 zCnJ+0O0q};a#_ftR=s+bd<6zib0Lkj(TKv1D~!wl`JjP;k0rT04=ULh|P3;_(7PVvO*|s`1}A?bp|+?N!aS zq!$eGZdXzl%^xv5ebbS^$;aes_*Rfl5|ZH<$*{2v*zuoS410nqjlP~Hj#T83rNX{G zVe6caQ^(eqkjFjal2Il*a3od09CR4mKEFf9dh{Oy_^7Or!7G)8Rf6xqA9sZxhDiF6 zUTYn`<|-Y4k1LK!^T5X^jCJ+k)t?SKS^$%o8G!-On-Xrx3Rgbf-F~$WJxWaa>qd~@ z!)bkIJZh-8^1}i)_rWdb20gLpabdM->@NKFwmwXsB+)Y-Sa3lHk&(#jUPs^`7TrMh z=uz6-fwhxvPv#if;c?>hf5#I6QRFI4iIKk=b!T$gnUZdFRbldo+zD9yX zk_Q-Nak+>+1_&6gf(2W)HqxrcAjwdET>5^M!+37$Dae+2Om|4Qk9asM=x})hj(YU> zuDagsH7Jx@6-$UnERqBAk^K124jF;k4p`!jBv*AA&TI&&{Z0ffIgS*(^kLCH&mn`Dx)K^SSF5JlY zZ{iPz-@-RHHaGE@rA8p3IQ+j1de@v=X><6F;i7q1!h<1AeuR8m_&KF~MYr?hw^!6r zNJ$49vCtD=5O}9RyznQ9u5Fqpw~{8ojnf@JpH8*;j%$-Vy~?E*?!CN;okup5)}2lc zeHMK`TaMM$jA4cksIBi2ve~Q)4q8Am4mlpxe_qrD?TmL&!-<#X=cqNx-d)_v!s1Aq zXB^lIPeq~KUlw}w_{{SNOuZ*OWELR5`I4a$0{pG^nv@+Xga67(g<1{;% zq}1*{*r7KMlW@rTR=hXD&O-2lA`Qkl#cMir)lObp8A7bwFMIxHVQ%*f>LwduK9y?L z$!w>2V+BKYHOfij31*rYg5e7QPfG13U7A`;hbJ9PbYRr!Ce$@9tl?SwTNI#z)@zd` z$y{fXO}fyH)%qJp1`*Xk;MOhdcQ+6-sZ<`_>gR)QujiY{f%4ndW6^|UDP~?X zTm4o~-jcnxH;mKwR);B|cs}1(x-v+=BX(n&=wk3CrjU&4KX=z_9s#UdZ9+{jw$}L& z^v!KS;_H1=PLU*KQaC3y)lO8Vo07DbaOH8gW^=lRkEP$;9Izx0$kzeleG=U+{{VL$ z66suPj{9c$vN*M8DU8u_Erbd;dEv>=~P zvHs0Xpcf;I`qnIZ7;W+xfKka%e^F6ePc^or5!-Y*z#0BkudUB?$rz3>Q2ziD^~H00 zIYFh(xg5}%ZLNyhUxjV8Q|6-&F%AZQt#yrU2A8KFIX4wvLX6|-Tt%c;+GOHuQcmx@ zr@z!z?T)TmaJr12D|Ym*d{r8SuT8EQ@xBSFe3uIPN#omClI)amEE zmrJ#EjP6o1x45b>$9dv?IILg0&jp&R_={6PsGDf_V;vas54AHzms7Pzjs{FQ$UN6A zzjN)9N?JWmhTEUBz0qb523=_SbNTXb2arIjz8q+*qLw*hR6CB-jtyMab-hL#5e&{5 z*kCq${VRpkuk~wNSxO-wj@^Z8P1MA~N~2eAp)-srG~k|xW2jx2azO$Y9D+H|sIErp z$8Gs*Swfi)Pg=*1#M8|JTg@qR*ptYr*80eYPy$(S6YlQmUY;KfIx%wondjE43XMho z0K*+#nc?fJElFmR=0p0|S17Q$k6{8Q1Lg$gxhoGF#`gj#8ZxJVdV@x(=WiF5@+w2z zfzRV!eP~pxQ}@2>>29ZW7{UQ8kN1&s~`$Wec|g~FE*)hb$X#E%bo@*=9wEA1 zJt}C@R3munp;al$qqK@p+!k{a4b7Z$TAF-M1j~mJ0yDv^U2Z8fd-&WiWG99lzO`dj z)Y&XjRhP>kZ~(7DP1KBec4rMb9?iaO(YwWIGZX4I6NQDx=FPyLr}5;-bLVY zTy?J~vDXdLe)aOlfK6{juU+Y}4=P+QKnTt&hQ1B^s>)m0%`$?Mo2YT&+}?Ki+qKDq~MVdbOj2T@X6>sJ;xECXSC0x?}O!o5=5&N72aOz7WLW^o*musOpXwWK^dG?4wF zO8F#bEOA^_#;#enAqR2%tF6-Y-#bBTb-41|7#;rr3g@j#r8ucUTe-b2XHrfr+|2t- z+9m%0n-cK-sMT!#l8&N!>zX0e}0moonSKJu{XTsy?KGdhMCUWYwvriD6n zn{ryM468p}eosr9!yosick7&IL}tH%k3vz?~!mpr@;rZkQBA!A3EYN?RV( z0Wy+JI4NUL2Vy!@(Qd^6P9qq>r>tr_W|+Chsi_bV)KD?Y8lG`Z2nT8o>~JYJmCk4a zQ~(}n?{J7erBgGrHU%o%v$jnDILc%=6*N}-WSV!Bs0IZp?x12mBk50!vvsDFElxn# z=QMzmIpUnL^OH=#U#&RojCG_kk;MQ{xOAt7UX@%)knMO0~2DRW9b+!ir#5ySXdC6j{O_=5Dmu<7uBPD%gam>w!oK3#tq$ ztz8F9Gt1_<%8JUhuzRW386!2^=~l}ODxQLYmJ|gT0~D(n&U;g)8(0OUP{4Cc1uh2| z%_As11sENA(~bb7193@#-lYl%$TZ(8CYXRQ0~w~59XrypVAN#}b3hA|p0zUL8K@+T zmEx8%RABX>2|)q5r?xRr<8jSAazy|PLem+tc&AE)(gomB7?~aD3C=}5R0heRxnYU` zd~5-yNO97mBA4-?2JSh@r3_6o2RzjNSPBgQDr5@u&xJQTx2K`6F*5%E4SEN{sW#q7 zJxxT4N3kiVQx}n%a3d64Kt^lN{wY{}qf2KClDyZTWL6i8twqLZ^*Z$%e@4YGv9_KdnAZqa08K2^nnU)NXqkd$|o!oStz&8QP_`V=kOH zO|-{si^dH!sFOJr%j*`+rd^BcbF_o=DDEo?wE5N6<;GmB^*j4i)GeMT z0EQLwm&D%!E`xmcXrMsHa|6&HTK8`Y>xrz{BL)S)=9%Lk3diD2Drg-+B}lJ5Yoj`@ zr#SG%96S3^{;607lQ4z2u`J@H!L?5UO}v? zQ}(Nx8}>G(Q`!5n*x(*WtY*y3v^nJG71h~&jx9Z8`$FZr6V|wmcSQSS3@&6bvW|q+ zJsQ>&WQ}fGSjPb~z^^t@Z)SQ?leMgOQ(4B*G?6aydIQ$E7x4wh_P^O)+(rS$<{fLS zvKKa}B#r{nfsFO4S7j%>T*M)INiVcr=WlhAxJ#>F+=Xd?=~*&dNTjTQhR5BKK4k|9GJ^xPvKus{4)KpEcF$N z%fwNLnEa+g%AfG2`6_&B!cI{5Sh`1wFZA0cw7IrqC@@J=%|SnktX!Wx30(Elov$nYj510rfIOe$OVdouVsynGyjI@@6z6amhYF;qZ zXSBpoi&8M7gUGJ`0L2#{WWa0%>T%F#rFk#x+u_;#KdktsTf-u}5s0D%eqF3{pRX0` zn)K1#>84;YApjf>c&*~OVsXi-O6L=)>T6=9nHllZJZ<-`5=Oh#H7~b-@~mU`WB5lu zuWIjSR49>3H-`s%x4%x^IW>vm4R#G9N|9~i`S3!VWDdfmyY5ocVVVGGwQDJ-$dM%o zc;h+b{XhEkzvDSnYHh!BsmNfX{QFlW;Jdeu{>5gHmUmV;J;|=0#f(zsT!wNRoxQ%b z8$^F-&e2v&-9jiMLb)r;eR0#*iuOpMRgD(_st@H}Yv5Z}pI4ISq%ol&XFoBoM@b$+ z4gpd)2DYW}+|H)s8BDVmz}Pwg)}fO9qm2U-=DGP-91l$Y0G{onh7JC|sHAd!L2dH(?QQYjFkN)lEIcY}m3bCL&oQ7qvBnRreWamH{zsjD!!kx(|* z+H;Oa;ZR)ag_<-)VYQV`J@d!tDK}w}-QGMm0zIZREHRApm9ARu>14dvvWZ;~?i}&T zDgH;>n%2M77s!>}zj!$thg_)RpLP|?YdXAhOK~N;{KYu?WFNp3uNvb{7!xBE~E^-xXB%I@n8f_^f zJXdN~(Hy&poYH|wN@<7>N+_TV@jw6{g()L67RMBVfD{UPg2ZE~=}4lzgW$KqS$s`) znvLX7_GCFlAmi#yOLiJpHU0$rCl~sJTAr$gGN3#$u;bYO080AHNz>!g?Bi7+o2bJ(6T00)8p0M@J7$5=q8nYZE!n^)iAGikt{{YlL{0&mOz49RkV;#eWJNZArfHj<#K@~)PyW4GR!5ad1ga=fpb&dx`gb3d09S%V!ysj4C!+d#0pG4GLfZAV z1Lg3f1Ch9~>wtQWcaQQbHqOTv2uT5VWt3oKsn2h4ewnQcJv$cY#fd<76T5eQr}9#I zVr*_vD5A5jhH^|yL~|?IRyF-yV9U&#A^b(kCgJn z^fkBQdpqBs6Dho|z!?#|MM@RHb3Pi5}fd$s{ufg&HAJMuwM zk_XCp&-%Ykl`o$)>!KZ-}wLQS%a@V+0a-C!r($`ON@lLT)Fu^PM5d9(qcnA={Qwo;$uXRuQ9_ z&|DH@Ld0P1Q|Z^A-~*3bj#%f`0A~ z=C9w6)}@q2lS>rdN;0H-kIF|R=dV3;wZ6Hc8@Uo$EvH?Rlnh!RM_xMpU9f$sH@Jyl zZN^CEAc7S1Cm@b^>R9#T=}(647$QkSYz1;!MZpIJhH=MM0)dV5)u!GhW0SNwO}n^b zoR4K({{Z#qS++R~nE?4RdhWm-di5{*)Pnq6%+W%sin4iZ`%c!w0l^;1-%71=s?JPq zOOKtx9Oog=ILG&widG%U*H-{QW|58=TLstDv*#zA9zK-m)o^DDBXg4K#F7T%kTc&1 ze<4D7f{~BY=nkcPbz=96-Pb$_4?DNk}2Yu!iPBdNnS|>+n>wvt4y02`mCuc;fZE3 z{DpgN2ftt96@x9*YVI9)AgCjra>tJS$LCuYEg{(wU}P%D1bHeloqO;GI^=Ow))--U z<6KMVI;i168%N_=OwuNXn|fHKzJ6uoH&O>`y|zdaJ>(f24W~aTCusgz{Og>xxRTN1 zk`Ruia6)4s@zeADYokV2i_9UKB?skS<|_rcOh2@~(=-VrU%P%A%tOE+06E8IH5A2s zkCb`QWH}58BLR)I=qrhzB1Lf`i z0NJZeiQJ>IF{#HE6=NhvupIIV=chsPnwIFT)!ZIw-vV{W83ZWD^FN(fhA|7bnxWG< zP{5KoesXcnGyY9uUQWXDBO3WpMx|s{$jae=4&A7|#%sZE3>uQja^E8Z99x?kTN|^F zeWHcX5FPidvqvFiET@tW0r(!n{Bw${8nxOp?PC`6j19dp&O79OxuZzbB}Pb!w2`SU zgn-9yLOr?uRjPI~X1%Ne5UQumc+iFO8yl2%=l%oFZaY?$yfDKP8Hjf$=Tp?K?u2B4 z>FjEyt^5$Pzsjh<`DlZY#zz_Fxg2!JrY@;Ip&U{ORn?IH0Jzxq0QJvq-%8YtOL1HY z5=i1DBjn^{V?R^D$j7lB^!TQ@j!4m+naAE`9Gr8EXM>)fh^h@ddA-N8M(k}>Wp#HG|OnbH($iz4S5sU>UTB z108--j=3E@c<)xO$Y(1R^s4TxtuK}evqlDS+;;XE`WmBgF|<~W-He5X~nRkliaF zbS#*35sVc+#Pl5Z&JVR{&uIYLDR~#l0d__XF_FpVkUpNCmCW5;%-8FQnOFkg1Jrx* z&(M3*?e3cPAhOD!ApPP2f(QfY>H+q_sM(D4p9}bb(sq(5nM$ZWW(w{E=YiPtqjJG`V^}r*s9`)-HR1ztc(6_qTbOWTXpYjSk=LdP1ZTIV4SKGJ zdl9-um`596Zeg{sdB#XS$LaVS{PCvUv>J-t*{r@^0g^53PXm#Xc^}LlYV>U*Sen}6 zIVFkhZJdTiljSON*Esx$=b@--%)QTR`%H47lG(#K9I4>AwGv+mTm$ne0IzLBS)gef=wf`0wym zFNpeL-do}=PTP~T0AycG`qx6%a`<~#S#6ct2Rn}A!sp+(L`uD;(AZacw=4i9d2TJ_w7m~{jRmu#uXCc{@ql$6CTmwOe+M-a@;F%%IeEGRq1)V+^gxC#W^k8kMLf zqV9*yPHs9`^(MO2AMDbq$&Pwrs^~X*mX&;x!npHJIqgm&5&$RX&mfGN>9m{cHZd0n zWRC~Yu~CS|RE0Im6M7hU&E3fAZS`s9NJY~C$DVp-pRRb0Sfdff+$iguisbd3M*8A^ zI^7gR20(FwYn#?QLg@x~VTi^>cj2+JuSG_BKA~C)oZDL+YTej3&$iq=ONA-eO|@U81zFI!(Qs--E~mW-zky+8JZQHYB~P6HmIyZg&qH`5kZ zk94JaGUSTmo_OpX2#H*w=L3=}snPW-i?t-c-br7VaIT72CyK8X70VU7MJnFHoVnfG zI88%QHkT4CBr3NAV}dHanSFIVhyR>2bdV!whdgimiE(Ajxi%NEsQb82D3C1CFRkM z;F!c@61#cFt#?|*y@Arj#rPD zIIO*9@_i@^XHPs6!vXUTW9?mTp)L8-pen)GV*?-7xou`!v3~^8#$;yWD7Y$r8sx)5 zrFNq1?WK{~TBKG-0R7{@uHJhMX72aSx3u|3 z@QyP{cYUc@M(HJkM#q9k;=T0@Mja_~{pXh{(W=^P;9kk>t`uB8!Jc`>4R=}~8jhDF zQclt!9d~xF4^y+h)F#^|<{8d0$Q8Y#>6f}CugVO8hDv0NRpKf8SS!hM1sd^$tr)u; z{{V>IT{7gwYdL%#J-&vw?7TYuB(aKpLT~~u;kCIxTD@hXE$mMumgO08M)dwwE`a-z z?%q{nvp67Q@~o=WYMr5^qtxkyuPeQoz(=G?y6wl<*t$a4-UjO5)HM^RY2Y|m=ZlPm z`{tLzm(b}N_1rfj%UKxhEN}?-uC9L$!LCT+(3sOXCvHdKSBS(YR9?|&lCvETeLhFm zW6dFwZD!#kx_>QD_dJ?k7TldS7?Kj;kNIo5o#I~)>Yg9Ie=0VWN&Cn$4Q5_n{{U%e zrWqo1lyR0ABE4E_GjOQ}oO=^Fa;FJyT!+Ll>e?#{nR9U%z{wwlRyxdjg`!%S8CY?G zbDD=l@FQOo63S!U(2g=IO!#io!q@vIb17rPFv+bX@bHt29p32~LDgwFEeqOThNCw7 zyB&l@zve7xqcS6PzXOcJ1pLBOq+@k_=T$YUQpYjicwF6`mTD=Gv>ba;j8OSB~MT!!7m7tXox2JF`{pyft;S$OvEt zPc>Unn(ETs861Z0I?-jRYG&PvF*}DUeJk9IYDOu+s~l2P=P!LT9VC|4XC7GvPin9g zwLo@{oDM*ytQSpoeE9IJdG@WVtLsY}c;bREmpu+gUwqe8=VrN8+c{%NJFDn(60Ekb zvPH#dSlq^903D6rnyWR_CBwDCs{_*qrBR0VH)kCVc&?5|QaYmr6;4_m441$MMJIMX z_G_G3rMH=wax;<*Uq?5w4=V`cf(>V~%-1UsT;$;5icnFyHK})IkI~Gloz-R>1v`OpTDok75<5@DQGIMe3G zTC|b#Kog0M?kaCPj(DoVMT@UAhHo(NF-!^G@bm(sUGp&Xr$GjJBCRTI98fWl+wD2c zP6@{pBrM08vmAIGDFFa{jAE2-Cmkxn#sM_OUTFZ`y9d2JbJwj%k%k$k5*C4wo_dN^ zDh>@ig52Vntk4gZL0gqaZhG`piIHn^NW1eUb{y@O% zO;%+*(9e_7kx4nt06ezpTwqgCaA<7ifr=X(8h!&*I}0Cbb0#IHm<|am6 z%EG)a;`hVo;7Kp7;mZzKDCCOdma6M>u9U3o_B;c|{s=n1huv*{N885M{Hx9UJ9(}6 za!;~fMqNh=`QsnsUfwR{iWEmiMLc5_M)yXGSh$D?m7hHT&0wd^x;xxldY)T;KDG4UiZu9qGb+n9q>4!I8O3?;i7)g`W(Qd!3o-uq zu9!6ksm(Rcv}etiH%kOcsz_l|*}1wv0L^qBC-6hVaU}655cL3hRt1DjYFU)v3iK0A zT^@T)J2K2O&86I{s}&=VMSVZ;6ZV69Lk^X!OTH6@Ss3*C*UK$=_QoNw2;!{S&n2vi z$VkVfLrr_p+H3YFlLZPnAXUY-g!wxhV2aTqA{fYQAy!Mj(jfn~#Lv^i_a5UMZg)R4~<28>q zm2o`g;ZzOBAQ94+Q%xGZi9IGH=v39o(I&z`Pq@G$sak7t-Unt15F7%>Jl8|5>1nCNRLHp_ zs_|JCo(_r#qy}@A~4S~^vM;mZEvRAUqx+lBiiE&k<|KC#aZ1M$vat|6XI6AxP-@VXx#VP(!96C8Wq*N z?KJVQf2Dnk;$1q^NZ&GBD?_&lvC? zO+K3T(FsG3!lu*Lb-`Ii!JhSBS(L>gM3Ax$fSS9j*o2*~bUqIFp|AKN<@m0G#xya(D3dq^yRV&A0ETn#+*&$3#o;&<=AD5k%5f&{cE<< zuHm|k!ELPgI6bSL)^zfhlCtdx6b;;G8Txuw3QXF@W|)ho>l%EdsbM+>Rp*S1{{TAa zJa4d0@)E;)=W3EO?0?VluQ}GQq+5@2?-qwors_`?;s zx??|x&$^S!PzxQa)DPq5aedscewZNqNV2LO80 zWTFea1px{LZN$FLG!VKn83~$@=4>0y*1QLACu*j zBOn~$!)zh8SF=Ouyb7 zVE+K$Bl8u?>bjg-eX&C-h=5?k{Hw?R09X&ov~_K2J47gw2O|tSagqK5^{)Z=uj9wN zo=q;<$Cv*AElT$P0A`e8tMSdDQ*~K zk@u-Kmg7q1=fUrU@_5fsN$(Y-vQzSd!GC)C>%%@5gTvZ%Hqa&`AZ0)!1LhO+${Jiz_JXdNIG0GO2u@xB4kp?%=|GuN$cOXfBjVz z#kIm+JfXT25gomUUjF|8tzDY#DBxwoA#X-G!1T|4X|Wj|V$!gTd3+`gM?CUB57L2= z;7V7_Ic9CRVZyJkw_nKA`yi56c|eInFUn4G!zA_kk@!_6pMBh9t3J)#g!{+P_vB>$ z7^mJug6y-!xtNT$I2_}@zdicXxQVVK5*){Hkp^xH@J9m#=cn+|Y90vIJ_Klf_{bdd z&*0vjsan~lK+S-p{DDCqFFfby2h$XiJhDbsCLUwpx5>xeIp}yK?jKr1A&foDlF0-n zVqAf{=F4M|*QP-0jOMix@La<^uFbK(9#{7gdGg`(x!MqkH%L62UK*z6T z=qfn2-c0Qxl?Q_vUtID59B@zNNM!dgEbSsH2$fM|OmXuZ=km|DN{7g~g55+UtXOQ| zpSpT_^v(}Xl?+q)Fx*9tA(%IwB#R4Rg z658CXfbW?&3_!+CI*#~1r`D_8mzlwh!$#QvAq2ByE1Zv@&o!YO_L`(H%22NL8#0|T zdXbI88~w0WvMz2`*~gN|;DRGn#zt}h+Ic**f6uiGP!Z9iiYZZv@_?$B*}0ss5Eh*sj)MSqKh@8A_et=O=@YbCx|h#XcP^npBXuksLCxCnM$r z{{S~Z(~M%6mg>epeqH3OlBgi<#s^M#F5i)^l0X%cjJ$v&|TwF%!7FPsii8&c=q#wpX#(2jRG&C~cs$1Pmq$?yLvx2*h2RZc2 zop{AdrQE_JbdoKsfZ@Q%VY{XQIN?1$l_N!%gwX>m8Q-)V1_yBiJq~ccrB#DUSl&q1 zb}D1?T}dA}45^=&fz{~%PqAJ#nf8Ge)!FI*!&0)(~{w@Ax(<0?v%2Dz;!N2;P=|UtyZ(x zvd*^vu2c`7xDofxf9Ik8RIEFh6I$F%#SUYQkOc#SmIvna7~Vd$71gUl9CE_U>Ws{% zcXccWJrCVIe;VD?Ms5N|ghWXkDF7Yn2mXWU+ls@Nd)bkIh|#kr;=M+BC-i)RDF@{yrNKXo!gZB$^riXK9vdCjrk9|K+xR0Qiptr84!cOEHn7+#d3F$ z`6n_)$mF+|*QhRfAFsb^+qgvYBxEJOx&!iay#8F0K9wBTA|VWn!c1X^VmKUUlkHT& z7>jS@Zjn`HJU5gNBOSjX)7r0CU9pW~kmcBfPg{Pf^pisgHnqhjJwBm@`6MnJ*m0gofUYM}&oHgb~Sh~!U{9!@}yu6g77 zQ$@s}c~U5inab}tAdH?W^isH%-J71rjQ;={?)>Od3l*MQnZi2~ISb3@s=uvDHpi$= zo?c{PcRQyCIl=z`KD57YwT9R{oaArFBn<6f0m0h;->>73V_QMKrcy}0*0EZPb!gKBZBkn#9=_uvx48GJNg7+9 z^kNZaCDB0`$vhA}xj6cYjjxd}B#D?hOTiJ5kaORr4tV;3>rPgqFto)71b z`{)|mauTo@1aFB@@8bx(;{cK0k&Ka!+4Q9{N#(V&GqdtjBjqC;FW32wYRpcC(=#Dy zqv^OGo304YL&5qHj`ak$Ne$$2h{8zO+B%SW@yF2MdXY?JE9-FzqsiuEjqX*BdFl^8 zfyaCv^|7Ptb67>VF_SD0%beq={QG-?Gf^voNR~BX%2cGBFFX;PamfJw2BH^8j?lb8 zR1JXR1^E~rnaKRW^{Ca2d7hDB;sms^NhFaSWWx+GI}Qo^xj6^W`-+OsRyRANDjM5( z8(8Ea80SCds5Qhi#sG|r=H7MOM*|%?3~}7^(1Yt!*vufeDLGiuGEj}#Ty($~!5GKj zX{TUj--x4Ir!mV6*k#}5C<=P(F!8@vAoWrLS4$JDkQ2>@W@21bPmCERNM;=(}y+Q)Y3$a)$Kj$9!@-f$LSL zxMhYY;#BhbSpe*;~HkEvZ*B8Fz2 znKm>a1`fUW`u?DL*8>c*Tai3dZiTb7w%`Hu?mPZR+O)0Yo#c7^@Kf&~X5@~U>Bf2= z!1k(04^8l|ic-zQb6GT~S1GVzhoR5cr__!szJUJ#ZfSAE@`l(8BPqiUNx=2>AN^|a zp9{$ayDX1A!xBq{W?ZT654b&jz%}SL5~M2?$aO^pRh$914#ym1WRvVc>6(YROGD87 z8LYUGwEOgxrRj-?1pAUlUI*rDw$r>q@j(`2^AQ_qP!3}}h5(*&2JMFiQ@{jO2UL*k@4p@y>)o?7>JmKPdq7 zoRh%d)DzmtG|c;!We4X*#uKMQ-#j1AqPL1G!0<+|6i%cZ@*6#muUfTlYyF*b6sSxR z1PI4JEQ$f(XVQRL6mDX-vyaRRy*CCxiU{k-KA1g^=jqef-MET3^0wfNvJ!iH_3u<} z>>^AumR-ko)fmq?JG&mAT12^;-Qn{KJTLpV2s5?2V;zoYS_STE>XvP&N9S1u7fJJN zkZ?zT&a&da22_!jYk3v%DyruPq0MbtPl8EiU=A?NhhI#ON~f*q(a9W_5i2uvaJ_m~ zja^*LXzW?Lw1ZW)ni&X^8I*!IarxKHUlslz>RL+Nt*LLbHcW4xqx?mC)|sfw6GIe% zNpX$+f%O^x02;Zh=@$CkgWBH4vc&7dgSh9`xiJ(Wil@mTIN1E=@pb063~||Af2lk) ziaq<*eA+xSSw{`I{qrw#kZa%mG5k1x47JIc-I~~smf&)v9+mUuww-eg>7L3(4H@Hc z;Me2WtQ@eDoH=T1_Fy><5(LqNT<)r1ZAq#0HRioK}W-RSsPmxtsq=~r*H z3z2-c335NLxhLQyxkxGPBpA&Pg<-iNg$Yky{!> zL`C+4A$C*WpU$-)dq}NWSvVtx3zapCpPx{92bxFm>kC-KPg_umHbDn=+mq>2&zv4MeZtRCs}e)wfi$@#Z!FM zZ*Gkpu9TL#a;#USWRo~KUjCxDW!G)3!oraSjE}vJDwl=)Hx|2Kw|7!*Y-bJI@uq93 zY>p$3X(_?OX0yX$o(1wkN=@!|RHyCZcC5M>SGrZ5{<$2VC?&r4TvtWn3m>uD!}1A0 z7}_#H_o|ZGqS_BCFWwQy82xH1oo?pa$Vp;pO7KWItIR6L6)JI#&wl974-a6bDSBQIK%4h%_9mmRpjbxc5t2(xRUYZj^WwkLyR8PPsX~e7I&}^5P-lo2TJTT z$ShLXYdHugewhLGNRtva9TG(VeZQh%I2# zgz+qF+j#(2GBqiDU2`-G2#BfbIjeRW2(;3R$PNJHXCVD5rmL!1X*MYKimP&X8%7Rm zY*u4DOnsd=zthyho*7eWQ{&lr^Z)3M=l_5DXhR7d7T;8*+ z-Lz0oB%9daWMJ<4inJk$=H519?p$=QB2bjMXHnVt8^TeKG+?f`)HOd6B3m>zs0^L+ z+v!W;%~lqOiK5G%PDci?CA2mg$dWiq!Jn9Q6}5M+*;_nrqYKw1a5Ly@O0*XzELQzR zO10$WDO%kOZye}$t#t*>q(IA^!~u>gqS3rnWu@s~Wg(!sD}-Vzlhk$A)Ng~@CQx(_ z{Jxc1CQF;q_LcJe2Vq-%QP!avb-HR~@oJSR_rdS^KmfnllKXxDd1_oI;Ds61x5SG8AgwbtL{ zcFwFKlb+9WjPU;ehOYHFU3{hs6JUin=jl^xeh|5qRSOHc9t&Xnwc6vab_dL2WyvGj ztV!_V&&8U2a=`(#<0mogYVM-Ad)Pd<=HD8ekPjI8RqL%{AF`|#_>Ip8)K+g5i{?>J z-cNroL!v&$O7CNd)BYJ-T4`q1DQ0P#g<^BhxUV_!cYw9u4BV@TT1c~zBIh5CeII0y zTgz_k8@U)K89#`qe0gy9@x&vD4xG5){Y83NeQN3ZTC%#AbYopplzA47c0O#e`(~*V z!j|kLLCT)F_BExTcvDf;VVlf?SQ#_?IL&*Jv$E5y?e3wmji%#rD&*Hdh8wuzjypC& zCou6r~r{J-e5NqN*#+*`F!N@bgi+nsWyE=ZuhI1E@*!x8>yD! z32oXwv9f21`lnOyWS$?reOBH>%KXu>$UfPuEf2&NSJPg}bz!z;$l!GU02)-Y`n4&! zLJCo`^-r;L!p1U6PR#lC-%FcRxbqSM+c;sg=BVqQ44+bvJ)^8_zr%x?`ZvScwWZwG z5v7tuyNVIBIUc<@tPdA_J{B!5qi4T)`HX6Ik@$D6x;f0FTb4_e^y+6kEL<)sB@ciK2fT4%*n$3+Sy3`3oXFz`N z74M!d_;j}_g2qO@AYcM=SK7SZUkPfuRn(D3YzZWSI#;8G%<1AG&2`Q98Pvl%Z6&ex z>RQGILgdw`UrWBjXFO6FWn>B}MU+)&<1%|x%7Hk>O#niwSRUq@ zA9n_vs^IZJ#Z@CbQ%@$I*&R(HD4;}qnm35*O`|l82L6VC7_MCN(x&4SDhS3XIHWPk zxg6As7{x}XaK%c4Z(0ChO#4$BH67}9=cPd@2oJ3>6|N=`8qSh$K1?X7?l(&O42pa< z+j+()7?46E0FhEiPg;~O9Vy9f*AfL);*b;Q`f}VzBw<}jMYTXtfmO8YA!!ieuL%x% zVuY+VDxupFR~>qrNy3{sW`qG7a}XeFo_Ivj!p1Z*Dl5|&f%O0s_NZZrS} zB%ITgMrqPGZ@Wl}e)ebq`P^|xVj0OaicWJ&jonQE1%@$5MV{;JJYk1=|PKY?xcJUMKOv93gR=gL-=zA zrL6O=BgRh^bN@1Dtw_`q#%E9{%3arHm2@1RPh)ULx?x&@No`>Tfh@KnQbXJG#;pHo|qs9$<$>JY}XJ5a2t9aTN#{iLz zE3$vKT3w)$E%1|_!=d!8%}2$M$ESUYD|YjkVxAp9UPaH1an8o^flmL1O7YScqaZUYnfV079bU4 z(!RgDhfDae;h#3jW%C^}3Z8RSrF|Zf{J}}l*K~QEwf(w)?29g8S#UW z)YfK`YYvlaAh)@hQ>MjkD`>bz&FW_*R#!_ygTB?TG;Lk2?xYT?C)Jj-=Csn{nI!Udxcj_Pe3!T-Q7c@@@pg%-O`{~p%EkKZ z&lSqsMX2~@+t2c3xn}G}4SGhQ;@GX>NT)`1#{+FaXRcf7o0Tok%h{HPQFK}fQj*on zQ-Ce1_>Mm^D`vKrmR@PrJ`vaT3&ooD;em_hLAZhV*Pz_riwMj4Xo@{5mCmzqEw`T$ z3c0~Fl&!KVP+Q5I_3VBo)MSp*RR+~t8;2ZLo}=M+vC+zZ*1}zvyoLiN8sHzQH#lo zXqb-Ot4m1m(T2?Vm#+u|B}-O)z1Ep)t!CoybZT%xeh0m6W}b#xHLBS1jdS4@=$YEw z@O`+hE5yGJwH*@Q?Guct^zC0*>ROJMb8Q&3W%-X$(zCUXhjVz-OL%RUe!$XG9!r;am=Eq-Z=X#@EosL$|Q=SW^a4@RJ7#tiL=`Nlv zdrb3VA2?n|O6IQ6$1J~kKKb;fX&U#~t~{g#qh{LVo~OSRh3w0*g{ax07V{GXHa3zm z_q%_e&bxaVUr_LMq`?0Gq{4_-DNnc^E5=8{PYf{lz3%{##QfQ|1o_CULbn7g`? z2?Tyr?$|TZ{vO64(QV5%=XYi}^{&2PC6FBLRUP}9<$Mvk4LfTo+Om+pL(O$p&avCO zH{IaGSL`>jCfU0@idJk&Pp5i9jz!9^Nx~G_8W)To0AbV#W>puE;+Aul- zHslJ1%1B$O5=jJVGBOAFjw(CJ77|7TUnw0wA;xNyJKi|X{{S$fbpvl4{{Z!=HC;wD zak*K~U8*``9e)x(8j_MRb(s=)Jkuj^2rtuc9sZrirZZd~zpKRdl7Gu4i0vD=!tsth zxc>mYYj4Ci$md{e$GfRGIQ0HsnXf4Ej=2r2R}#-AQ3oXV9e>ZhY7)CGyCaqH_l$qB zY^4#l>#0da{{R~C8D@FqX&sBZ9F{%JUDvgVwarRfnHZ2y$_eNzKD(hFRC3B(%rnI% zJJ5R4)`SbtP-&#*ot~ZO5S_j0R~KS3%(~30`=!QWo~eb^(`g zI8jNvZZwy4M(!RO)dEjeJ2F~1U+Uj;L2RZ52@%<}1;opQT z{3)kJ0D~Dt-obrxGIP&dSEy*V&_!(|er8z)8JP7S*R6B6c50Q2c2*54`J3`{z#L_B zjDI@2C^oQ$KpO`nj=1Ch0M+=^O3xE{fPuFoapx=tL;ig!=TVMpbVXof+A?xG`x=sp zLBpq*c9vW@8%Qd8?fz92tc9mWQ?;|TvN#@x+aP~ByX7R&4Y8bnHx*Jlb^O1Ws`ge$ z0hi3m%hP@d$3gGc1J;2S5+%8kXWRmg5cS+~?f6q8lwgUuKQj%-*kd{RgV(iBr{)V| z3^A*^rX$GDT;s2&O04t6B(lRO@?Ajv@64mcz+A(h9lb@TRLZOQ6N#iKJ%Rj2=K49DjJ#Jx@!TbcMze zAlW4Ix1h)7Sn@d(2%g&N-b;2wcJjC%Dcy|Y-_ex*6-xEv4J(L44S+_#g1POC@OrQ1 zRpyV%F>QB^noI+c(+Ag{u0EKhk`sGuQ0|Ci$`?5&01?6UJ2?8#GPDYseEwWSnmYV%*~C1835$u014!FJI@1=`mtn+XqMw(*hrPRBa@cflgCn+$4Y=(r1Bya zBPy|Zsn?%T*OJZOj8m-1mPpb!AaC8Yk@Dp4AdjG5&ZU$-OPDn1lmOd6B)>)(PVs~| z8-T#aKFQM@^WLaE^G_F;g_c&tjggQJ((UtoT|ncvHDc#UmG;W~%HJquC2|Pc+n>EB z;Z=XLSI!E8MGnIoSEk}r=NUXA9<@HBOI-#@d2pc+kkH7%6_3r1RdI|CxNb4@tH7az zNTe)J^OKz5l4K|8+dlPVM;g2gAy$<9z&Q419CiLNPQHv#olb&44y z1{@vDxNYB(Tlp{RP(gCy-4&D*vm~GQN$b<^KU!Dr7VKTRxPfDNBarX%{N4aR-fSFw zM-`ntymEPAolMaTfC%|UR1xZWF#RaFD-trKY6Ox9vOqhs%AVbUH3PVwIb>B}>YJ1? z`@`ow_~fwuv^8)>T=QEb%zo_B!WD8b7071KuU4%a1`lSk5wo-u`}?e1PV+8_*ojBU@$oB@&Vmi;T9UPh?ZwbPt=BnV94l7^~d?^QAxEXmPaN+AKWm(V85O#7Ey7m5km)1 z@$E#x=tdYfA4662*>=q8&44)ofsnZ1=RWmf*7;sivJagkECzdIkL%L1CU$K`Hva%r zV;KX3xkyv#(t+-DS}fpPvuEXOt0+8!pZ>LIWuyfNAsaa@&OIxa)8vre+)ALU9zvdT zj--Bd(_4kPu`&lcWE)Br$KmZ-!RTc7Gj8mi7m-m(Va{?vZ-2yN@dl(YeWViKD{x5%ARKPo4m~-?u0?3IBVwG<=6|(sVHx}T zaq=Gd2dEsMaD9bcSk~?&4$jSz6__4W@qv$SGydtP%oZzb#)?&bQkWPXxChfbbI_66 ztCeWtcwGZH`{OIdLJwd9|T{Jfcv2cylpg25q z=lOblDnz|VwAmw4g+p&gZgK06f8zWNXHL<}BW!_8B$Fczqz`gEy8REePUTqA)En(L z1Vs=@kOowZi8#hO{sd?J+Rb}L6UQp4Zo_go=ra=)~#(y;#f`083@)x1c zQaa%N2enN-q>p4?B3fa9T;W*{W*=Tp*XvceI~kW(al*wU3?d-yZ=2TuH>XS=z|`_8 zd2peSJB)4lvxA?fwt4Od?^(-e$9$41NHRpA1t4dyApFB=AA$C*D_iJ_h}1cJo>_B{ zeGhL>s2-x0qb8kD0*Z?RlPb>X(s1)WWWJHY@s{=$DT96`sTBm zIMR6IxgnL8nL#Q*>+k&iMO}_hC4oj(Aac$|4t|*3fycN$)PU>sE7%_KeEG`THWZEk z$iNMpb;!Z4tHYY{j_vKQR7)B8RzmxUIl<0-aruvW^8G&jVzoy|%3LvEra(%b2po^g zKET&u;p>Z=$m5Zje6|5)4&*a`y`1y?MH;Zt9_^+y)7m;lQfqu{4xcgwBZ3Zi>yOH` zp!-*bQaNrdR&)m*WJ+0+9=sfS{{WL*M~8eue7CoYY;O?ZAAyW>x71^|ryZ-Zu(^&a zIb?Ki-hA6o@VVrSb;fxgUrLJ>ndp{s!>K5^Syj=|UuZo&c+V$~(zL`Ydj?&JX!sI+ z(~jBnt{X+v=CHOeG;&-(0RXdt6m$d(@H+nhp1n?$c*`#M+&ClVOn^%9gVTaNs6uGc zoC{SzRb3Q-Li2&oUrNl?6vR~{1tXM@B+gnV_Fh31xgG3x0|VtCkavCF^&FZ)T-(aC zIFL#ATOB^1PwQ1{i92p{wzoHWWz%`i>{JgiSZ!hta!wbHPI2|eHPTq>>v;$}f!aVU z1_#iCSQmBz(lw0EB!mK>HhCED^!zG~mDJj9s5Z^!#~@`A73F&L$5Ef_=xJS{yECoU zbXK{8&bOGPfQB4oDf(7^op&HRSgOc?B%Wv9Z$no!y=kPJq`QD`m=e7{r@dO#v}mv5 zHx|woQZw@RHEmy1LUz%Zz9{g`my9$y^xMchwUJ22_Yc?7z6AJ<;2me-UcYk_F?&Mq z^UE1fS3F?!JY&=RKKrxPCx-t3%AO~Iy6t`x9+?NHHO_os_;YXZ55o6W?+Tld8$1&M z$zjL@cL(zo<>T-avkFcVTCI%d7N0bCKRm9r0WuP}W;~n@l$S2v@qaf zs~&57>gg5Sa7fLA@`fiSx*ra}v0jD2{mhE-dw6+-E6r-yD013rg zTd4d^GMQ6oQJuNRZ~eF9b~y? zYqbe8ecZ1V!A(+)S6h4jCuFBNN7-7|+tBnaH&(a4xLaJ{V44E?1@FJ(CI)abk` zVP&bu8<3_)IUz?+t#^8cn`s7~B66rPgXvt3nRTY=uq?1_V7&%<)m?MN?Q-f)L}X(F zn)(iBMxE_+bHkDExw)rk*1|Uy?egc9SN&@r#a8fHK&%l=ndOxK05MF`JW~(Z*+XoQ zbq<|t6T~;SI)ep_EYXfm!CrKIjWp_V{AWvYoK#}=Cl?~_53$6{y@y5WYYOv4n%-EW zy^QQ9JNEVVsr1cGIPMU}F(ME$Mi0=}qYVkQ`!teO9FM}eWmgXva_ez&RI4M0)I2R} zVuDyuGcE}L{{Tv_tbLx*BUO(MKZJ}N`&8GDKZkYy0JA^(lfv%lk4jG(F>N=^Op*q6 zp4HFwE_zC$la{5rsyxcpVWntS7qCe)#1%;SaCsG%ec`eqadx0aPYf!Rmyhpb)5WAw zlH-8GuhO)SizdI)+Sc;j(oA$K!wU17#L}JR9Y3v0jHpzCv(!s}16k?%f7%jL$mcjU zg>PdO#-Ji)BopbDIm;oDfb}{HJz7_BDkJY~fZ=oA;i` z(xw&?gk=?EjSE{iv`Zf>kch(|gSQ`A#94G$+F0%yKQX!)4>|hP{dY#x_4@!IK2l?X zPJde9Q?*+hisq$8^_qjcy7o1dTT@M|N1?Z;_>$t<=_E)z$brevLG`O% zCh;Y%w`;N?HcZb7bnEN|>|@3k{?j`$$^5nRG*4{v|w&lyjfJuzOyRcop;c8YiN zIVDv>JodY1py(Qf%s2M%&xunb2mEW&wOjjkf;iGOifjyS!2FGP)!wp+5?oujb|WJl zzY2=m#5$I^>j;<0bo-1&MSL_>CgTNfKk_>1Vl6ILCv)0nh`yZ7GnZh$Hr#XgSDN^i z^4i89HVvRNZEUZ~f56n98S!k|e6rhWQVI4BqtoeFpAhf#?M}?SfdTW96yWFFSIS`U zl__F58oXa^k50ZKGNsJ4Yrf{Uf;3oQ)t+`{Xy@dqA1!oxh31^MZDnvkP;#o={#DC( zBVOHO8~JM61{-n6{JU2>;y(~YsQ8dBe5D6&dyl1cJS9wCDqQ+menx7%Xwgzy-JRyQ zr&wy%!YEQCWf|NF(ck!s_~TKr_1*o&xgD{s9N92F^+M!{#g;j4{GUj z=ycoLsg~;8MJo&zkuXJ9xA=v7XyVrX$L#Zt3G98r?OGS|U22+h-Tjn>3y{i2Y1Vb8 zKi;le=$c_k#V>K*-5Na;?c3J@Y6-6794O+XS5`Pt#VEJ)4=0NLr#@7QCYIr_p#5sh zI&_TLW;J327T{y8PLh+!;7|jiuw_hUr;5{zQ{t2r=cP`vfG8Olfq=r)o?D3r;T z>rPP3%>XI`oSv0xC`5~#@k~Ya6+C0tfj|z94sZ=jmf?9OgamY_mC3<0hBQaG_2QI7 z26@d$paG22#B0|y0Sd)VUMgG)Z_2%B0zW9p$>~p30AN&$DuLRY<|rnR5V{a}Jk*gX z1DbjjEt*%9b`-#gqb}5|Zda+NhXa~(Oc-^fFbJwCz>b-y41k(OkRT^C2%1MksuNG< zJ{F+5yDz{rwsDd{G{$LKS_c4;R$9T>{G*C=R{;sEA=9RC12fm-6>W8r#IT873;M99D}z^6VHc&k@TCgcjH$Y=o+9!*ahfWEZF3KyDG zP+J`-0OKc_+LUrB#x-7Z%^+cpC;j zj`W5+Hp9m>*CZU%P?1D{vkF5V?h0|%mK9;i=}^0cIH{qK_ux|y`95%Q){;IKlS?60 z98^OreW(Ha9`rMeU{G+i8!+lR&;!*@c<)^of{2G*hn}_0D}EKV;aLFI?aq3diEL8b z`YO!k1o~9@=M`5@Ik%7LR_P%H6uWrqO((SgbG|gS7dkw{8Tn0o^DqlDD|H7I^v<&Y zmc~^)r!n(pEn-as^VtjH1`HT2>hr5IT1lD zIjFa8=qk%8z{sd%J9-KLjaWv0?Ljkn(qV@cYy!*3#Y5ztSoWX{ZF5Rnn6M5A`y9?UDaR(6F*Al$2Q|X$&wHU?E%ZuCq4|_|70*_in!4Q55>aQpZ4REG*OdHU z@B!8=P0g-SWaJPlvG7-kBiFRZyb~^+eI@0$%BLlO73EiJJeLwiqjNV_1De95 z)wwOH-%c`isNRPKsF*by$t|v51$g9BVbQevSu!Wf_FUGSeg={)Rqk#l+Kh9zx%$%F z>AF>{re82P2l%-aafX+;I*#_S<$n=;Cuyv!%N`7fI(M%C)jT(Lw-W?~-B6s6I#<*l zF1)a?JFQh_XBY~+)^3;KnJ+Yn<(|=DBod*|t##9=)3em(sZBk!XUw`}h6zeI$2hIm zme1_xk>+FZsI|>3>3Y=bAR9xTm5ZrfMrQ>&4z<+vdK`;Ic3+O+qLXkquVwfx@y7eW zx|B%sG?r{YWGAI~oHG5QAV9@S12jwsIH;6HozK)ACsNVAD(DGuZt=9matP`Td8dgq z%g+j3$dW<5GnH^Uiuse_2gZB<003&SZJC1SlY8^AaROz zlxMn`1<=|610>g%I#Z`Mp2w*Qs&Tw`J1sxM)=Q_ErJHkspS_CQvY1|I@*yG7I&;l& z8pX7R+ikSK9B@~YSM)onY_#(WN(pYD)-y@lLujd|qa)QXG|PBQk}86&gX>xv4gQyU zsK~47x~R#d!F_2YbC5UoBQ*qiHLjm)<;N$Mag2(5@X=g7jaR9g@jt}tp@k4c&z_h7 zgIsNgiO#(u5gQ;<4@`6IUA4xEWql!Oe|~eGYP?!To2N_iMYXf(TRBsEBQ;K{e)B6q zr#7W`8Is&GFDE_CTYK0v-9@4MGbk&K!8pxpTHX0*OmW}==~OOtI9_eWFwfI9e9NI8 z$=_CSnx30`tLhUhWtJn)9dlW-=vu>;v;GhV&N2xe_1;gZeVB(40iK0NG`9Ei-lNEo ze86XsjM7rqL{oxGSsZ7Fd_SsLO3QS7$i`G>(zSH|01Ms6smVXev5){>l}lUkZO9VC z1`=dAA-h#=8^oHEL7SFh0l^?~NvAz*CCN`qoj3d%JNSw(v^cHlPjJplJRuX!*I~))2>{A%g}pOd~e=l z=}j(FYxs@yt#Wr;#YSxW#P%k<%U<|#rAX3GXCz>OoGIqIiM$c1*odxm3z*(1ut`?? zr?zX8*R+JvwIU+DX(N6}2Rzo4POwZk7WIld@%Y{ULv}dBvg#3~{1pVfD z-lXBbc_VzgOM{;Laa@(f=y}V>l_9rqwb|=1MI<|SmMWZ{gSKmy)M8lVbXEzGk%i84 zgZ%3TjnTWI>VAE?!zmK34=24;i6zo?Nc955Fnkmr-Odjc&)MERs9m7%4nvT7{VSyN z#-(OAq29c!8qZ)oi^CGBvR$MUEs%Xd=C$>^hKW49Zry{=OjjN7*tyW-M}5*H*!jB; zO6s+?QFh2?#&Po3V)#yWtjhPVBESgXgwIZfv6k4Yv6Wf)-JJLJ7_E8jWDzNmjzUw&K!Y9yezP>Fv~hb+fCy zaPJJ+b{+B4@cLH~;!Q^u&9o_C4)t!VI%NC*0G`zi-PqAtE1Z74;s7nBJD55GTX%nd z^X@C>--zBReM00~BjtL@@9AEH@dLyOX=^m9%Y)c+pGxqF<~K7mjB?C!O?1cOH?vS{+)+% zXddLc28VO6>Ji#oE?JM>JplKwuYMPNGPm%~nF<6~l;_NHM{MW%{#BjubKym{fnnxP z0?Bm5E4!|9++w|I*3-$1Kaq?A$gFw-GQ*nZl)0I*jgZ)_p|^$de7K1yRZbXjhCKS5 za4SwI7C7VBfEGDE**VF@R+`cR=+5k-MnAhhboL~X_*R{&h}4KwOu&`n9QuAWBPI}k zqZK4R2O#4IKmMw(9jqyIRTB(HAaUQCv2}JJn+k=qk+U7WDl0cwo@{`-h$FGa2qzx= zpU!|RD>bS}xy+d1x@X_ee~o9y6pvz>rv?_n@T08+$mAmC#?&r!fF z`BO?r3P(T6NeByY3ugy|?~l%z3=v#3j=*jkv$KLnCq9_u{-T-!&Kb8z${J-%0C?w~ zay{|+=A(Jzxs;&G~6rfAeO9@f*e(uhk$(&0OX zJ-zth@l>XUcU-jWitKQJkVbgN9f4-+(`{Q9vl!EJ?ed$E3R&YK*-2A{2dLBAQk8R%cEt&>4?z@>3qnu+n`)C^yBWT^WP$% z8goe%xsq6nN~(+y1_0$j$QZ%py?ts|SR`d)zHDKeaSMiFkU9Jmws!#L*@hFMsIi7bmY#{)TLQ~v;uFReoyaz(16M=2KIV_@KX%oCyG zg+uhInscVR#$CY9B$hP_k&wz(M9Kh1%B3(m54_##OZ#a=EH|WV%p)6y2^)g* z{{R6>%Lu`iN82y~m=+wiS=gN9AK@Li%}Xg7Ch|pijP?HL{cE6Gb1IUJ zo!d7I3@IcIFn+(4XX|#s517nYKi@)f0c;HR9bD8jicE$bRx5i^AC?|Xn?O_9LFzqn z-80^$nq`tE^ILLm;R)akz;^ai`qeGFaBMh8w8D_$k zAouD=KGlk5niI(z`EJvd8Bv8Nf-ox)ZDNXf!_T*9#Au}T!Q>ytw)F;U!8A(VWAnL) zJY$T0WAv;UYzjo|UlIe5&y1DHKA-0mOF@! z8pgO^l$^0Sayob9RS6h~)DjFWjIV3}Kl=4%%2YmcGKT;H6;C}fPwQOGSle=Im}c`B znN&P-0*#y=N|TzaDOhe&Nq|Qf`SJen!Tmov(32MhP!kqO%Y&2K*YK?C`!n--v+en} zVfiGJpI*oLia}!hS4(YqxllGnP6s%~595m8x3P+QTr7jjZb3bdP(^YL7y6migTxmB zhg|WD*7lPw`%f=+)p3=_@Sn!6EQupp5hQG|EWzgf@#&m%{(iJgGa@{I8Nek95sdfi zj=X+iptG@ck~sny3X-97g1^xE{xuckF^uH8VM?@P?>Byjx$EpjYK-5JHKwH$Q!pSgILA+$u0QXSSl5>~@k*!|CeEW6Bxj8JL01wnDtr8^Fw-Jv%S8ez_hEllixMX$5KU|8@v=DZ`Fd6YVM*)F4&*?#H41RVNf zIOKLe@Do~yuo%p4SjQj=Fi2ugJ$-S{)K+Y=+$0R~#8pmu=hJR5JND1I{b+&)yE*>= zR#;_pU$MB&4ev@;%VVqR>t_`N6t<;2cYSZ^dR=GvMo|CJ~J#! zy8&BgP)-5P57R#Qt~qa_S(*hvh?pB&ILJTKKljP@tz9W%k|)an8Y#k-0Pu0>IqmsT zaeAJy;cpZ`kG&Yn85l2?R*lL0a1K6zjKPL62wpCWQU{#I>?%R$?&Tu=C>z|{w^$m`@ z!agvxhIn3kz3@xYXE|g)#HZ8`ZonSZ*=a2np(`wM#tM>A7F;(2vt$v$2OS9ZHQ;)r zv*>b1EXgD#x3q3Sa8Ir|{{TF9<3~a9J>xn_93#t!AY&VRpb$woBd0uj@M>DIN!