forked from ungleich-public/cdist
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 <steven@icarus.ethz.ch>
This commit is contained in:
parent
eed058426a
commit
b17a1f0edb
1 changed files with 47 additions and 25 deletions
|
@ -18,31 +18,36 @@
|
|||
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
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
|
Loading…
Reference in a new issue