diff --git a/conf/type/__key_value/explorer/state b/conf/type/__key_value/explorer/state
new file mode 100755
index 00000000..94a5ea7f
--- /dev/null
+++ b/conf/type/__key_value/explorer/state
@@ -0,0 +1,53 @@
+#!/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 .
+#
+
+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__")"
+
+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
diff --git a/conf/type/__key_value/explorer/value b/conf/type/__key_value/explorer/value
deleted file mode 100755
index 3afc7cc5..00000000
--- a/conf/type/__key_value/explorer/value
+++ /dev/null
@@ -1,37 +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 .
-#
-#
-# 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
-file="$(cat "$__object/parameter/file")"
-delimiter="$(cat "$__object/parameter/delimiter")"
-
-awk -F "$delimiter" '
-BEGIN { found=0 }
-/^'$key'/ { print $2; found=1 }
-END { if (found) exit 0; else exit 1 }' "$file" \
-|| echo "__NOTSET__"
-
diff --git a/conf/type/__key_value/gencode-remote b/conf/type/__key_value/gencode-remote
index eff0925c..0846dca1 100755
--- a/conf/type/__key_value/gencode-remote
+++ b/conf/type/__key_value/gencode-remote
@@ -18,35 +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
-awk -F "$delimiter" '
-/${key}${delimiter}*/{gsub("$value_is", "$value_should")};{print}' "$file" > "${file}+" \
-&& mv "${file}+" "$file"
+state_is="$(cat "$__object/explorer/state")"
+state_should="$(cat "$__object/parameter/state")"
-DONE
- fi
- ;;
- esac
+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 706b0b0d..2e75e175 100755
--- a/conf/type/__key_value/manifest
+++ b/conf/type/__key_value/manifest
@@ -18,9 +18,13 @@
# 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
+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