From b17a1f0edbfc189c0eac47e94a08f763a2405834 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 27 Sep 2014 11:40:06 +0200 Subject: [PATCH] removing and adding keys must be atomic If we delegate this to multiple seprarate objects (e.g. using __line) and the config run is interrupted after applying only some of them we may leave the target in some random state. We may have even locked ourself out of the target. So remove and add keys ourself so either none are all changes are applied. Signed-off-by: Steven Armstrong --- .../{manifest => gencode-remote} | 72 ++++++++++++------- 1 file changed, 47 insertions(+), 25 deletions(-) rename cdist/conf/type/__ssh_authorized_key/{manifest => gencode-remote} (63%) diff --git a/cdist/conf/type/__ssh_authorized_key/manifest b/cdist/conf/type/__ssh_authorized_key/gencode-remote similarity index 63% rename from cdist/conf/type/__ssh_authorized_key/manifest rename to cdist/conf/type/__ssh_authorized_key/gencode-remote index eb7ae859..478826db 100755 --- a/cdist/conf/type/__ssh_authorized_key/manifest +++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote @@ -18,31 +18,36 @@ # along with cdist. If not, see . # -file="$(cat "$__object/parameter/file")" -state="$(cat "$__object/parameter/state")" -mkdir "$__object/files" - -_cksum() { - echo "$1" | cksum | cut -d' ' -f 1 -} - -_do_line() { +remove_line() { file="$1" line="$2" - state="$3" - line_id="$(_cksum "$file")-$(_cksum "$line")" - - set -- "$line_id" - set -- "$@" --file "$file" - set -- "$@" --line "$line" - set -- "$@" --state "$state" - # Ensure __line does not read stdin - __line "$@" < /dev/null + cat << DONE +tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) +# preserve ownership and permissions of existing file +if [ -f "$file" ]; then + cp -p "$file" "\$tmpfile" +fi +grep -v -F -x '$line' '$file' > \$tmpfile || true +mv -f "\$tmpfile" "$file" +DONE } +add_line() { + file="$1" + line="$2" + # escape single quotes + line_sanitised=$(echo "$line" | sed -e "s/'/'\"'\"'/g") + printf '%s' "printf '%s\n' '$line_sanitised' >> $file" +} + + +file="$(cat "$__object/parameter/file")" +mkdir "$__object/files" + # Generate the entry as it should be ( if [ -f "$__object/parameter/option" ]; then + # comma seperated list of options options="$(cat "$__object/parameter/option" | tr '\n' ',')" printf '%s ' "${options%*,}" fi @@ -56,20 +61,37 @@ _do_line() { fi ) > "$__object/files/should" -# Check for existing and conflicting entries and remove them +# Remove conflicting entries if any if [ -s "$__object/explorer/entry" ]; then - # We have existing entries for this key. - # Check if any of them are in conflict to how the entry should be. - # Note that the file has to be sorted for comparison with `comm`. + # Note that the files have to be sorted for comparison with `comm`. sort "$__object/explorer/entry" > "$__object/files/is" comm -13 "$__object/files/should" "$__object/files/is" | { - # Remove conflicting entries while read entry; do - _do_line "$file" "$entry" absent + remove_line "$file" "$entry" done } fi +# Determine the current state +state_should="$(cat "$__object/parameter/state")" +if grep -q -F -x "$entry" "$__object/explorer/entry"; then + state_is="present" +else + state_is="absent" +fi + # Manage the actual entry as it should be +if [ "$state_should" = "$state_is" ]; then + # Nothing to do + exit 0 +fi + entry="$(cat "$__object/files/should")" -_do_line "$file" "$entry" "$state" +case "$state_should" in + present) + add_line "$file" "$entry" + ;; + absent) + remove_line "$file" "$entry" + ;; +esac