forked from ungleich-public/cdist
Merge pull request #663 from asteven/type/__line
RFC: rewrite __line type for --before and --after support
This commit is contained in:
commit
f75af95bda
5 changed files with 228 additions and 116 deletions
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh -e
|
||||||
#
|
#
|
||||||
# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org)
|
# 2018 Steven Armstrong (steven-cdist at armstrong.cc)
|
||||||
#
|
#
|
||||||
# This file is part of cdist.
|
# This file is part of cdist.
|
||||||
#
|
#
|
||||||
|
@ -17,26 +17,74 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
#
|
|
||||||
|
|
||||||
file="/$__object_id"
|
if [ -f "$__object/parameter/before" ]; then
|
||||||
[ -f "$__object/parameter/file" ] && file=$(cat "$__object/parameter/file")
|
position="before"
|
||||||
|
elif [ -f "$__object/parameter/after" ]; then
|
||||||
|
position="after"
|
||||||
|
else
|
||||||
|
# By default we append to the end of the file.
|
||||||
|
position="end"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -f "$__object/parameter/regex" ]; then
|
if [ -f "$__object/parameter/regex" ]; then
|
||||||
regex=$(cat "$__object/parameter/regex")
|
needle="regex"
|
||||||
greparg=""
|
|
||||||
else
|
else
|
||||||
if [ ! -f "$__object/parameter/line" ]; then
|
needle="line"
|
||||||
echo "Parameter line and regex missing - cannot explore" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
regex="$(cat "$__object/parameter/line")"
|
|
||||||
greparg="-F -x"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Allow missing file - thus 2>/dev/null
|
if [ -f "$__object/parameter/file" ]; then
|
||||||
if grep -q $greparg -- "$regex" "$file" 2>/dev/null; then
|
file="$(cat "$__object/parameter/file")"
|
||||||
echo present
|
|
||||||
else
|
else
|
||||||
echo absent
|
file="/$__object_id"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
awk -v position="$position" -v needle="$needle" '
|
||||||
|
function _find(_text, _pattern) {
|
||||||
|
if (needle == "regex") {
|
||||||
|
return match(_text, _pattern)
|
||||||
|
} else {
|
||||||
|
return index(_text, _pattern)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BEGIN {
|
||||||
|
getline anchor < (ENVIRON["__object"] "/parameter/" position)
|
||||||
|
getline pattern < (ENVIRON["__object"] "/parameter/" needle)
|
||||||
|
state = "absent"
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if (position == "after") {
|
||||||
|
if (match($0, anchor)) {
|
||||||
|
getline
|
||||||
|
if (_find($0, pattern)) {
|
||||||
|
state = "present"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state = "wrongposition"
|
||||||
|
}
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (position == "before") {
|
||||||
|
if (_find($0, pattern)) {
|
||||||
|
getline
|
||||||
|
if (match($0, anchor)) {
|
||||||
|
state = "present"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state = "wrongposition"
|
||||||
|
}
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (_find($0, pattern)) {
|
||||||
|
state = "present"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END {
|
||||||
|
print state
|
||||||
|
}
|
||||||
|
' "$file"
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#!/bin/sh -e
|
#!/bin/sh -e
|
||||||
#
|
#
|
||||||
# 2012 Nico Schottelius (nico-cdist at schottelius.org)
|
# 2018 Steven Armstrong (steven-cdist at armstrong.cc)
|
||||||
# 2014 Steven Armstrong (steven-cdist at armstrong.cc)
|
|
||||||
#
|
#
|
||||||
# This file is part of cdist.
|
# This file is part of cdist.
|
||||||
#
|
#
|
||||||
|
@ -18,76 +17,108 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
#
|
|
||||||
|
|
||||||
file="/$__object_id"
|
if [ -f "$__object/parameter/before" -a -f "$__object/parameter/after" ]; then
|
||||||
regex=""
|
echo "Use either --before OR --after but not both." >&2
|
||||||
state_should="present"
|
exit 1
|
||||||
[ -f "$__object/parameter/file" ] && file=$(cat "$__object/parameter/file")
|
fi
|
||||||
[ -f "$__object/parameter/regex" ] && regex=$(cat "$__object/parameter/regex")
|
|
||||||
[ -f "$__object/parameter/state" ] && state_should=$(cat "$__object/parameter/state")
|
|
||||||
[ -f "$__object/parameter/line" ] && line=$(cat "$__object/parameter/line")
|
|
||||||
|
|
||||||
|
state_should="$(cat "$__object/parameter/state")"
|
||||||
state_is="$(cat "$__object/explorer/state")"
|
state_is="$(cat "$__object/explorer/state")"
|
||||||
|
|
||||||
[ "$state_should" = "$state_is" ] && exit 0
|
if [ "$state_should" = "$state_is" ]; then
|
||||||
|
# nothing to do
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$__object/parameter/before" ]; then
|
||||||
|
position="before"
|
||||||
|
elif [ -f "$__object/parameter/after" ]; then
|
||||||
|
position="after"
|
||||||
|
else
|
||||||
|
# By default we append to the end of the file.
|
||||||
|
position="end"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$__object/parameter/regex" ]; then
|
||||||
|
needle="regex"
|
||||||
|
else
|
||||||
|
needle="line"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$__object/parameter/file" ]; then
|
||||||
|
file="$(cat "$__object/parameter/file")"
|
||||||
|
else
|
||||||
|
file="/$__object_id"
|
||||||
|
fi
|
||||||
|
|
||||||
|
add=0
|
||||||
|
remove=0
|
||||||
case "$state_should" in
|
case "$state_should" in
|
||||||
present)
|
present)
|
||||||
if [ ! "$line" ]; then
|
if [ "$state_is" = "wrongposition" ]; then
|
||||||
echo "Required parameter \"line\" is missing" >&2
|
echo updated >> "$__messages_out"
|
||||||
exit 1
|
remove=1
|
||||||
fi
|
else
|
||||||
|
echo added >> "$__messages_out"
|
||||||
|
fi
|
||||||
|
add=1
|
||||||
|
;;
|
||||||
|
absent)
|
||||||
|
echo removed >> "$__messages_out"
|
||||||
|
remove=1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
#echo "echo \"$line\" >> $file"
|
cat << DONE
|
||||||
#line_sanitised=$(cat "$__object/parameter/line" | sed 's/"/\"/g')
|
|
||||||
# Idea: replace ' in the string:
|
|
||||||
# '"'"'
|
|
||||||
# |------> ': end the string
|
|
||||||
# |-|---> "'": create ' in the output string
|
|
||||||
# |--> ': continue the string
|
|
||||||
#
|
|
||||||
# Replace all \ so \t and other combinations are not interpreted
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
# line_sanitised=$(cat "$__object/parameter/line" | sed -e "s/'/'\"'\"'/g" -e 's/\\/\\\\/g')
|
|
||||||
# The one above does not work:
|
|
||||||
# --line "PS1='[\t] \[\033[1m\]\h\[\033[0m\]:\w\\$ '"
|
|
||||||
# becomes
|
|
||||||
# PS1='[\\t] \\[\\033[1m\\]\\h\\[\\033[0m\\]:\\w\\$ '
|
|
||||||
|
|
||||||
# Only replace ' with '"'"' and keep \ as they are
|
|
||||||
line_sanitised=$(cat "$__object/parameter/line" | sed -e "s/'/'\"'\"'/g")
|
|
||||||
printf '%s' "printf '%s\n' '$line_sanitised' >> $file"
|
|
||||||
echo "added" >> "$__messages_out"
|
|
||||||
|
|
||||||
;;
|
|
||||||
absent)
|
|
||||||
if [ "$regex" -a "$line" ]; then
|
|
||||||
echo "Mutally exclusive parameters regex and line given for state absent" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
greparg=""
|
|
||||||
if [ "$line" ]; then
|
|
||||||
regex="$line"
|
|
||||||
greparg="-F -x"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat << eof
|
|
||||||
tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX)
|
tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX)
|
||||||
# preserve ownership and permissions of existing file
|
# preserve ownership and permissions of existing file
|
||||||
if [ -f "$file" ]; then
|
if [ -f "$file" ]; then
|
||||||
cp -p "$file" "\$tmpfile"
|
cp -p "$file" "\$tmpfile"
|
||||||
fi
|
fi
|
||||||
grep -v $greparg "$regex" '$file' > \$tmpfile || true
|
|
||||||
|
awk -v position="$position" -v needle="$needle" -v remove=$remove -v add=$add '
|
||||||
|
function _find(_text, _pattern) {
|
||||||
|
if (needle == "regex") {
|
||||||
|
return match(_text, _pattern)
|
||||||
|
} else {
|
||||||
|
return index(_text, _pattern)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BEGIN {
|
||||||
|
line_file = ENVIRON["__object"] "/parameter/line"
|
||||||
|
getline line < line_file
|
||||||
|
# Need to close line file as it may be re-read as pattern below.
|
||||||
|
close(line_file)
|
||||||
|
getline pattern < (ENVIRON["__object"] "/parameter/" needle)
|
||||||
|
getline anchor < (ENVIRON["__object"] "/parameter/" position)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if (remove) {
|
||||||
|
if (_find(\$0, pattern)) {
|
||||||
|
# skip over this line -> remove it
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (add) {
|
||||||
|
if (anchor && match(\$0, anchor)) {
|
||||||
|
if (position == "before") {
|
||||||
|
print line
|
||||||
|
print
|
||||||
|
} else if (position == "after") {
|
||||||
|
print
|
||||||
|
print line
|
||||||
|
}
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print
|
||||||
|
}
|
||||||
|
END {
|
||||||
|
if (add && position == "end") {
|
||||||
|
print line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "$file" > "\$tmpfile"
|
||||||
mv -f "\$tmpfile" "$file"
|
mv -f "\$tmpfile" "$file"
|
||||||
eof
|
DONE
|
||||||
echo "removed" >> "$__messages_out"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown state: $state_should" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
|
@ -13,72 +13,102 @@ This cdist type allows you to add lines and remove lines from files.
|
||||||
|
|
||||||
REQUIRED PARAMETERS
|
REQUIRED PARAMETERS
|
||||||
-------------------
|
-------------------
|
||||||
|
None.
|
||||||
|
|
||||||
|
|
||||||
OPTIONAL PARAMETERS
|
OPTIONAL PARAMETERS
|
||||||
-------------------
|
-------------------
|
||||||
state
|
after
|
||||||
'present' or 'absent', defaults to 'present'
|
Insert the given line after this pattern.
|
||||||
|
|
||||||
line
|
before
|
||||||
Specifies the line which should be absent or present
|
Insert the given line before this pattern.
|
||||||
|
|
||||||
Must be present, if state is present.
|
|
||||||
Must not be combined with regex, if state is absent.
|
|
||||||
|
|
||||||
regex
|
|
||||||
If state is present, search for this pattern and add
|
|
||||||
given line, if the given regular expression does not match.
|
|
||||||
|
|
||||||
In case of absent, ensure all lines matching the
|
|
||||||
regular expression are absent.
|
|
||||||
|
|
||||||
The regular expression is interpreted by grep.
|
|
||||||
|
|
||||||
Must not be combined with line, if state is absent.
|
|
||||||
|
|
||||||
file
|
file
|
||||||
If supplied, use this as the destination file.
|
If supplied, use this as the destination file.
|
||||||
Otherwise the object_id is used.
|
Otherwise the object_id is used.
|
||||||
|
|
||||||
|
line
|
||||||
|
Specifies the line which should be absent or present.
|
||||||
|
|
||||||
|
Must be present, if state is 'present'.
|
||||||
|
Ignored if regex is given and state is 'absent'.
|
||||||
|
|
||||||
|
regex
|
||||||
|
If state is 'present', search for this pattern and if it matches add
|
||||||
|
the given line.
|
||||||
|
|
||||||
|
If state is 'absent', ensure all lines matching the regular expression
|
||||||
|
are absent.
|
||||||
|
|
||||||
|
The regular expression is interpreted by awk's match function.
|
||||||
|
|
||||||
|
state
|
||||||
|
'present' or 'absent', defaults to 'present'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BOOLEAN PARAMETERS
|
||||||
|
------------------
|
||||||
|
None.
|
||||||
|
|
||||||
|
|
||||||
MESSAGES
|
MESSAGES
|
||||||
--------
|
--------
|
||||||
added
|
added
|
||||||
The line was added.
|
The line was added.
|
||||||
|
|
||||||
|
updated
|
||||||
|
The line or its position was changed.
|
||||||
|
|
||||||
removed
|
removed
|
||||||
The line was removed.
|
The line was removed.
|
||||||
|
|
||||||
|
|
||||||
EXAMPLES
|
EXAMPLES
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. code-block:: sh
|
.. code-block:: sh
|
||||||
|
|
||||||
# Manage the DAEMONS line in rc.conf
|
# Manage a hosts entry for www.example.com.
|
||||||
__line daemons --file /etc/rc.conf --line 'DAEMONS=(hwclock !network sshd crond postfix)'
|
__line /etc/hosts \
|
||||||
|
--line '127.0.0.2 www.example.com'
|
||||||
|
|
||||||
# Ensure the home mount is present in /etc/fstab - explicitly make it present
|
# Manage another hosts entry for test.example.com.
|
||||||
__line home-fstab \
|
__line hosts:test.example.com \
|
||||||
--file /etc/fstab \
|
--file /etc/hosts \
|
||||||
--line 'filer.fs:/vol/home /home nfs defaults 0 0' \
|
--line '127.0.0.3 test.example.com'
|
||||||
--state present
|
|
||||||
|
|
||||||
# Removes the line specifiend in "include_www" from the file "lighttpd.conf"
|
# Remove the line starting with TIMEZONE from the /etc/rc.conf file.
|
||||||
__line legacy_timezone --file /etc/rc.conf --regex 'TIMEZONE=.*' --state absent
|
__line legacy_timezone \
|
||||||
|
--file /etc/rc.conf \
|
||||||
|
--regex 'TIMEZONE=.*' \
|
||||||
|
--state absent
|
||||||
|
|
||||||
|
# Insert a line before another one.
|
||||||
|
__line password-auth-local:classify \
|
||||||
|
--file /etc/pam.d/password-auth-local \
|
||||||
|
--line '-session required pam_exec.so debug log=/tmp/classify.log /usr/local/libexec/classify' \
|
||||||
|
--before '^session[[:space:]]+include[[:space:]]+password-auth-ac$'
|
||||||
|
|
||||||
|
# Insert a line after another one.
|
||||||
|
__line password-auth-local:classify \
|
||||||
|
--file /etc/pam.d/password-auth-local \
|
||||||
|
--line '-session required pam_exec.so debug log=/tmp/classify.log /usr/local/libexec/classify' \
|
||||||
|
--after '^session[[:space:]]+include[[:space:]]+password-auth-ac$'
|
||||||
|
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
:strong:`grep`\ (1)
|
:strong:`cdist-type`\ (7)
|
||||||
|
|
||||||
|
|
||||||
AUTHORS
|
AUTHORS
|
||||||
-------
|
-------
|
||||||
Nico Schottelius <nico-cdist--@--schottelius.org>
|
Steven Armstrong <steven-cdist--@--armstrong.cc>
|
||||||
|
|
||||||
|
|
||||||
COPYING
|
COPYING
|
||||||
-------
|
-------
|
||||||
Copyright \(C) 2012-2013 Nico Schottelius. You can redistribute it
|
Copyright \(C) 2018 Steven Armstrong. Free use of this software is
|
||||||
and/or modify it under the terms of the GNU General Public License as
|
granted under the terms of the GNU General Public License version 3 (GPLv3).
|
||||||
published by the Free Software Foundation, either version 3 of the
|
|
||||||
License, or (at your option) any later version.
|
|
||||||
|
|
1
cdist/conf/type/__line/parameter/default/state
Normal file
1
cdist/conf/type/__line/parameter/default/state
Normal file
|
@ -0,0 +1 @@
|
||||||
|
present
|
|
@ -1,4 +1,6 @@
|
||||||
state
|
after
|
||||||
regex
|
before
|
||||||
file
|
file
|
||||||
line
|
line
|
||||||
|
regex
|
||||||
|
state
|
||||||
|
|
Loading…
Reference in a new issue