From db29ea8e7020b0850671aac9b8e9e142e7b0e960 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 12 Sep 2013 14:02:33 +0200 Subject: [PATCH] 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