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/>.
|
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
file="$(cat "$__object/parameter/file")"
|
remove_line() {
|
||||||
state="$(cat "$__object/parameter/state")"
|
|
||||||
mkdir "$__object/files"
|
|
||||||
|
|
||||||
_cksum() {
|
|
||||||
echo "$1" | cksum | cut -d' ' -f 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_do_line() {
|
|
||||||
file="$1"
|
file="$1"
|
||||||
line="$2"
|
line="$2"
|
||||||
state="$3"
|
cat << DONE
|
||||||
line_id="$(_cksum "$file")-$(_cksum "$line")"
|
tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX)
|
||||||
|
# preserve ownership and permissions of existing file
|
||||||
set -- "$line_id"
|
if [ -f "$file" ]; then
|
||||||
set -- "$@" --file "$file"
|
cp -p "$file" "\$tmpfile"
|
||||||
set -- "$@" --line "$line"
|
fi
|
||||||
set -- "$@" --state "$state"
|
grep -v -F -x '$line' '$file' > \$tmpfile || true
|
||||||
# Ensure __line does not read stdin
|
mv -f "\$tmpfile" "$file"
|
||||||
__line "$@" < /dev/null
|
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
|
# Generate the entry as it should be
|
||||||
(
|
(
|
||||||
if [ -f "$__object/parameter/option" ]; then
|
if [ -f "$__object/parameter/option" ]; then
|
||||||
|
# comma seperated list of options
|
||||||
options="$(cat "$__object/parameter/option" | tr '\n' ',')"
|
options="$(cat "$__object/parameter/option" | tr '\n' ',')"
|
||||||
printf '%s ' "${options%*,}"
|
printf '%s ' "${options%*,}"
|
||||||
fi
|
fi
|
||||||
|
@ -56,20 +61,37 @@ _do_line() {
|
||||||
fi
|
fi
|
||||||
) > "$__object/files/should"
|
) > "$__object/files/should"
|
||||||
|
|
||||||
# Check for existing and conflicting entries and remove them
|
# Remove conflicting entries if any
|
||||||
if [ -s "$__object/explorer/entry" ]; then
|
if [ -s "$__object/explorer/entry" ]; then
|
||||||
# We have existing entries for this key.
|
# Note that the files have to be sorted for comparison with `comm`.
|
||||||
# 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`.
|
|
||||||
sort "$__object/explorer/entry" > "$__object/files/is"
|
sort "$__object/explorer/entry" > "$__object/files/is"
|
||||||
comm -13 "$__object/files/should" "$__object/files/is" | {
|
comm -13 "$__object/files/should" "$__object/files/is" | {
|
||||||
# Remove conflicting entries
|
|
||||||
while read entry; do
|
while read entry; do
|
||||||
_do_line "$file" "$entry" absent
|
remove_line "$file" "$entry"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
fi
|
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
|
# 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")"
|
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