Initial commit
This commit is contained in:
36
roles/gekmihesg.openwrt/library/nohup.py
Normal file
36
roles/gekmihesg.openwrt/library/nohup.py
Normal file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/python
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.0',
|
||||
'status': ['preview'],
|
||||
'supported_by': '@gekmihesg'
|
||||
}
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: nohup
|
||||
short_description: Starts a command in background and returns
|
||||
description:
|
||||
- The M(nohup) module start runs a command in a shell using OpenWRTs C(start-stop-daemon).
|
||||
- The module will dispatch the command and return.
|
||||
author: Markus Weippert (@gekmihesg)
|
||||
options:
|
||||
command:
|
||||
description:
|
||||
- command to execute. Execution takes place in a shell.
|
||||
required: true
|
||||
aliases:
|
||||
- cmd
|
||||
delay:
|
||||
description:
|
||||
- seconds to wait, before command is run.
|
||||
default: 0
|
||||
note:
|
||||
- This module does not support check_mode.
|
||||
'''
|
||||
EXAMPLES = '''
|
||||
- name: wait 3 seconds, then restart network
|
||||
nohup:
|
||||
command: /etc/init.d/network restart
|
||||
delay: 3
|
||||
'''
|
||||
63
roles/gekmihesg.openwrt/library/openwrt_command.sh
Normal file
63
roles/gekmihesg.openwrt/library/openwrt_command.sh
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2021 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
PARAMS="
|
||||
cmd=raw_params=_raw_params/str/r
|
||||
uses_shell=_uses_shell/bool//false
|
||||
chdir/str
|
||||
executable/str
|
||||
creates/str
|
||||
removes/str
|
||||
"
|
||||
RESPONSE_VARS="
|
||||
start end delta cmd
|
||||
stdout/str/a stderr/str/a rc/int/a
|
||||
"
|
||||
SUPPORTS_CHECK_MODE=""
|
||||
|
||||
init() {
|
||||
stdout=""
|
||||
stderr=""
|
||||
start=""
|
||||
end=""
|
||||
delta=""
|
||||
rc="0"
|
||||
[ -n "$executable" ] || executable="/bin/sh"
|
||||
out="$(mktemp)" && err="$(mktemp)"
|
||||
}
|
||||
|
||||
main() {
|
||||
local ts_start ts_end s_delta
|
||||
[ -z "$chdir" ] || try cd "$chdir"
|
||||
|
||||
[ -z "$creates" ] || ! ls -d -- $creates >/dev/null 2>/dev/null || {
|
||||
stdout="skipped, since $creates exists"; exit 0
|
||||
}
|
||||
[ -z "$removes" ] || ls -d -- $removes >/dev/null 2>/dev/null || {
|
||||
stdout="skipped, since $removes does not exist"; exit 0
|
||||
}
|
||||
|
||||
ts_start="$(date +%s)"
|
||||
[ -z "$uses_shell" ] && {
|
||||
echo "$cmd" | xargs sh -c 'exec "$@"' -- >"$out" 2>"$err"; rc=$?; :
|
||||
} || {
|
||||
"$executable" -c "$cmd" >"$out" 2>"$err"; rc=$?; :
|
||||
}
|
||||
ts_end="$(date +%s)"
|
||||
s_delta=$((ts_end - ts_start))
|
||||
|
||||
start="$(date -d "@$ts_start" "+%Y-%m-%d %H:%M:%S").000000"
|
||||
end="$(date -d "@$ts_end" "+%Y-%m-%d %H:%M:%S").000000"
|
||||
delta="$(printf "%d:%.2d:%.2d.000000" \
|
||||
$((delta / 3600)) $((delta % 3600 / 60)) $((delta % 60)))"
|
||||
stdout="$(cat "$out")"
|
||||
stderr="$(cat "$err")"
|
||||
changed
|
||||
test "$rc" -eq 0 || fail "non-zero return code"
|
||||
return 0
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
rm -f -- "$out" "$err"
|
||||
}
|
||||
83
roles/gekmihesg.openwrt/library/openwrt_copy.sh
Normal file
83
roles/gekmihesg.openwrt/library/openwrt_copy.sh
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
PARAMS="
|
||||
backup/bool
|
||||
dest/str/r
|
||||
directory_mode/str
|
||||
force=thirsty/bool//true
|
||||
original_basename=_original_basename/str
|
||||
src/str
|
||||
validate/str
|
||||
$FILE_PARAMS
|
||||
"
|
||||
RESPONSE_VARS="src dest md5sum=md5sum_src checksum backup_file"
|
||||
|
||||
init() {
|
||||
md5sum_src=""
|
||||
checksum=""
|
||||
backup_file=""
|
||||
}
|
||||
|
||||
main() {
|
||||
local tmp _IFS
|
||||
[ -e "$src" ] || fail "Source $src not found"
|
||||
[ -r "$src" ] || fail "Source $src not readable"
|
||||
[ ! -d "$src" ] || fail "Remote copy does not support recursive copy of directory: $src"
|
||||
|
||||
checksum_src="$(dgst sha1 "$src")" || :
|
||||
md5sum_src="$(md5 "$src")"
|
||||
md5sum_dest=""
|
||||
|
||||
[ -z "$original_basename" -o "${dest%/}" = "$dest" ] || {
|
||||
dest="$dest/$original_basename"
|
||||
tmp="$(dirname -- "$dest")"
|
||||
[ -d "$tmp" ] || {
|
||||
_IFS="$IFS"; IFS="/"; set -- $tmp; IFS="$_IFS"
|
||||
tmp="$mode"; mode="$directory_mode"
|
||||
local d
|
||||
local p=""
|
||||
for d; do
|
||||
[ -n "$d" ] || continue
|
||||
p="$p/$d"
|
||||
[ ! -d "$p" ] || continue
|
||||
try mkdir "$p"
|
||||
set_file_attributes "$p"
|
||||
done
|
||||
mode="$tmp"
|
||||
}
|
||||
}
|
||||
|
||||
[ ! -d "$dest" ] || {
|
||||
dest="${dest%/}"
|
||||
[ -z "$original_basename" ] &&
|
||||
dest="$dest/$(basename -- "$src")" ||
|
||||
dest="$dest/$original_basename"
|
||||
}
|
||||
|
||||
tmp="$(dirname -- "$dest")"
|
||||
[ -e "$dest" ] && {
|
||||
[ ! -h "$dest" -o -z "$follow" ] || dest="$(realpath "$dest")"
|
||||
[ -n "$force" ] || fail "file already exists"
|
||||
[ ! -r "$dest" ] || md5sum_dest="$(md5 "$dest")"
|
||||
} || [ -d "$tmp" ] || fail "Destination directory $tmp does not exist"
|
||||
[ -w "$tmp" ] || fail "Destination $tmp not writeable"
|
||||
|
||||
[ "$md5sum_src" = "$md5sum_dest" -a ! -h "$dest" ] || {
|
||||
[ -n "$_ansible_check_mode" ] || {
|
||||
[ -z "$backup" ] || backup_file="$(backup_local "$dest")"
|
||||
[ ! -h "$dest" ] || { rm -f -- "$dest"; touch -- "$dest"; }
|
||||
[ -z "$validate" ] || {
|
||||
[ "${validate/%s/}" != "$validate" ] ||
|
||||
fail "validate must contain %s: $validate"
|
||||
tmp="$($(printf "$validate" "$src") 2>&1)" ||
|
||||
fail "failed to validate: $tmp"
|
||||
}
|
||||
try 'cat -- "$src" > "$dest"'
|
||||
}
|
||||
changed
|
||||
}
|
||||
|
||||
[ -n "$_ansible_check_mode" ] || set_file_attributes "$dest"
|
||||
}
|
||||
172
roles/gekmihesg.openwrt/library/openwrt_file.sh
Normal file
172
roles/gekmihesg.openwrt/library/openwrt_file.sh
Normal file
@@ -0,0 +1,172 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
PARAMS="
|
||||
diff_peek/str
|
||||
force/bool//false
|
||||
original_basename=_original_basename/str
|
||||
path=dest=name/str/r
|
||||
recurse/bool//false
|
||||
src/str
|
||||
state/str
|
||||
$FILE_PARAMS
|
||||
"
|
||||
RESPONSE_VARS="state path appears_binary/bool"
|
||||
|
||||
init() {
|
||||
appears_binary=""
|
||||
}
|
||||
|
||||
get_state() {
|
||||
local state
|
||||
state="$(ls -ld -- "$1" 2>/dev/null)" && {
|
||||
case "${state:0:1}" in
|
||||
l) state="link";;
|
||||
d) state="directory";;
|
||||
*) set -- $state; [ "$2" -gt 1 ] &&
|
||||
state="hard" || state="file";;
|
||||
esac
|
||||
echo "$state"
|
||||
} || { echo "absent"; }
|
||||
}
|
||||
|
||||
get_inode() {
|
||||
set -- $(ls -id -- "$1")
|
||||
echo "$1"
|
||||
}
|
||||
|
||||
main() {
|
||||
[ -z "$diff_peek" ] || {
|
||||
appears_binary="0"
|
||||
hexdump -e '16/1 " %02x" " \n"' -c 8192 -- "$path" 2>/dev/null |
|
||||
grep -q " 00 " && appears_binary="1" || :
|
||||
exit 0
|
||||
}
|
||||
|
||||
prev_state="$(get_state "$path")"
|
||||
[ -n "$state" ] ||
|
||||
case "$prev_state" in
|
||||
absent) [ -z "$recurse" ] && state="file" || state="directory";;
|
||||
*) state="$prev_state";;
|
||||
esac
|
||||
|
||||
[ -n "$src" -o "$state" != "link" -a "$state" != "hard" ] || {
|
||||
[ "$state" != "link" -o -z "$follow" ] ||
|
||||
fail "src and dest are required for creating links"
|
||||
src="$(realpath "$path")"
|
||||
}
|
||||
|
||||
[ "$state" = "link" -o "$state" = "absent" -o ! -d "$path" ] || {
|
||||
basename="$original_basename"
|
||||
[ -n "$basename" -o -z "$src" ] || basename="$(basename -- "$src")"
|
||||
[ -z "$basename" ] || {
|
||||
path="${path%/}/$basename"
|
||||
prev_state="$(get_state "$path")"
|
||||
}
|
||||
}
|
||||
|
||||
[ -z "$recurse" -o "$state" = "directory" ] ||
|
||||
fail "recurse options requires state to be directory"
|
||||
|
||||
[ "$state" = "$prev_state" ] && state_change="" || state_change="y"
|
||||
|
||||
case "$state" in
|
||||
absent)
|
||||
[ ! -e "$path" ] || changed
|
||||
[ -n "$_ansible_check_mode" ] ||
|
||||
result="$(rm -rf -- "$path" 2>&1)" ||
|
||||
fail "removing failed: $result";;
|
||||
file)
|
||||
[ -z "$state_change" -o -z "$follow" -o "$prev_state" != "link" ] || {
|
||||
path="$(realpath "$path")"
|
||||
prev_state="$(get_state "$path")"
|
||||
}
|
||||
|
||||
[ "$prev_state" = "file" -o "$prev_state" = "hard" ] ||
|
||||
fail "file ($path) is $prev_state, cannot continue"
|
||||
set_file_attributes "$path";;
|
||||
directory)
|
||||
[ -z "$follow" -o "$prev_state" != "link" ] || {
|
||||
path="$(realpath "$path")"
|
||||
prev_state="$(get_state "$path")"
|
||||
}
|
||||
|
||||
[ -e "$path" ] || changed
|
||||
case "$prev_state" in
|
||||
absent)
|
||||
[ -n "$_ansible_check_mode" ] || {
|
||||
oIFS="$IFS"; IFS="/"; set -- $path; IFS="$oIFS"
|
||||
path=""
|
||||
for p; do
|
||||
[ -n "$p" ] || continue
|
||||
path="$path/$p"
|
||||
[ ! -e "$path" ] || continue
|
||||
result="$(mkdir -p -- "$path" 2>&1)" ||
|
||||
fail "error creating $path: $result"
|
||||
changed
|
||||
set_file_attributes "$path"
|
||||
done
|
||||
};;
|
||||
directory) set_file_attributes "$path" "$recurse";;
|
||||
*) fail "$path already exists as a $prev_state";;
|
||||
esac;;
|
||||
link|hard)
|
||||
is_abs "$src" && abssrc="$src" || {
|
||||
[ ! -h "$path" -a -d "$path" ] && abs="$path/$src" ||
|
||||
abssrc="$(dirname "$path")/$src"
|
||||
}
|
||||
[ -e "$abssrc" ] && {
|
||||
[ ! -d "$abssrc" -o "$state" != "hard" ] ||
|
||||
fail "src is a directory, cannot hard link $abssrc"
|
||||
} || {
|
||||
[ "$state" != "hard" ] ||
|
||||
fail "src file does not exist, cannot hard link $abssrc"
|
||||
[ -n "$force" ] ||
|
||||
fail "src file does not exist, use force=yes if you want to link $abssrc"
|
||||
}
|
||||
|
||||
if [ "$prev_state" = "absent" ]; then
|
||||
changed
|
||||
elif [ "$prev_state" != "$state" -a -z "$force" ]; then
|
||||
fail "refusing to convert between $prev_state and $state for $path"
|
||||
elif [ "$prev_state" = "link" ]; then
|
||||
[ "$state" = "link" -a "$(readlink "$path")" = "$src" ] ||
|
||||
changed
|
||||
elif [ "$prev_state" = "hard" ]; then
|
||||
[ "$state" = "hard" -a "$(get_inode "$path")" = "$(get_inode "$abssrc")" ] || {
|
||||
[ -n "$force" ] ||
|
||||
fail "cannot link, different hard link exists at destination"
|
||||
changed
|
||||
}
|
||||
elif [ "$prev_state" = "directory" ]; then
|
||||
[ -z "$(find "$path" -mindepth 1 -maxdepth 1 2>/dev/null)" ] ||
|
||||
fail "the directory $path is not empty refusing to convert it"
|
||||
changed
|
||||
else
|
||||
changed
|
||||
fi
|
||||
|
||||
[ -n "$_ansible_check_mode" ] || {
|
||||
[ -z "$CHANGED" ] || {
|
||||
[ "$state" = "hard" ] && flags="" || flags="-s"
|
||||
[ "$prev_state" = "absent" ] ||
|
||||
result="$(rm -rf -- "$path" 2>&1)" ||
|
||||
fail "error replacing $path: $result"
|
||||
result="$(ln $flags -- "$src" "$path" 2>&1)" ||
|
||||
fail "error while linking $path to $src: $result"
|
||||
}
|
||||
set_file_attributes "$path"
|
||||
};;
|
||||
touch)
|
||||
[ -n "$follow" -a "$prev_state" = "link" ] || {
|
||||
path="$(realpath "$path")"
|
||||
[ -n "$_ansible_check_mode" ] || {
|
||||
result="$(touch -- "$path" 2>&1)" ||
|
||||
fail "error touching $path: $result"
|
||||
set_file_attributes "$path"
|
||||
}
|
||||
changed
|
||||
};;
|
||||
esac
|
||||
}
|
||||
122
roles/gekmihesg.openwrt/library/openwrt_lineinfile.sh
Normal file
122
roles/gekmihesg.openwrt/library/openwrt_lineinfile.sh
Normal file
@@ -0,0 +1,122 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
PARAMS="
|
||||
backrefs/bool//false
|
||||
create/bool//false
|
||||
insertafter/str
|
||||
insertbefore/str
|
||||
line=value/str
|
||||
path=dest=destfile=name/str/r
|
||||
regex=regexp/str
|
||||
state/str//present
|
||||
$FILE_PARAMS
|
||||
"
|
||||
RESPONSE_VARS=""
|
||||
|
||||
escape_slash() {
|
||||
echo "$1" | sed -e 's|^/|\\/|;:a;s|\([^\]\(\\\\\)*\)/|\1\\/|g;ta;q'
|
||||
}
|
||||
|
||||
escape_chars() {
|
||||
echo "$1" | sed 's|['"${2:-}"'\]|\\&|g;q'
|
||||
}
|
||||
|
||||
get_last_match() {
|
||||
echo "$2" | sed -nre "/$1/=" | sed '$!d'
|
||||
}
|
||||
|
||||
save_changes() {
|
||||
[ -n "$_ansible_check_mode" -o -z "$CHANGED" ] ||
|
||||
echo "$1" > "$path" 2>/dev/null ||
|
||||
fail "path $path not writeable"
|
||||
}
|
||||
|
||||
line_present() {
|
||||
local index old new mode tmp
|
||||
|
||||
[ -f "$path" ] && {
|
||||
old="$(cat "$path")" || fail "path $path not readable"
|
||||
} || {
|
||||
[ -n "$create" ] || fail "path $path does not exist"
|
||||
[ -n "$_ansible_check_mode" ] ||
|
||||
mkdir -p "$(dirname "$path")"
|
||||
old=""
|
||||
}
|
||||
|
||||
index="$(get_last_match "$line_match" "$old")"
|
||||
[ -n "$index" ] && {
|
||||
tmp="$(echo "$old" | sed -n "${index}{p;q}")"
|
||||
[ -z "$backrefs" ] || line="$(echo "$tmp" |
|
||||
sed -re "s/$line_match/$(escape_slash "$line")/")"
|
||||
[ "$tmp" = "$line" ] || {
|
||||
new="$(echo "$old" | sed "${index}c $(escape_chars "$line" |
|
||||
sed 's|^\s|\\&|;q')")"
|
||||
changed
|
||||
}
|
||||
} || [ -n "$backrefs" ] || {
|
||||
[ -n "${insertafter#[EB]OF}" ] && {
|
||||
index="$(get_last_match "$(escape_slash "$insertafter")" "$old")"
|
||||
mode="a"
|
||||
} || [ -z "${insertbefore#BOF}" ] || {
|
||||
index="$(get_last_match "$(escape_slash "$insertbefore")" "$old")"
|
||||
mode="i"
|
||||
}
|
||||
[ -n "$index" ] && {
|
||||
new="$(echo "$old" | sed "$index$mode $(escape_chars "$line" |
|
||||
sed 's|^\s|\\&|;q')")"
|
||||
} || {
|
||||
[ "$insertafter" = "BOF" -o "$insertbefore" = "BOF" ] &&
|
||||
new="$line$N$old" || {
|
||||
tmp="$(echo "$old" | sed '${/^$/d}')"
|
||||
new="$tmp${tmp:+$N}$line"
|
||||
}
|
||||
}
|
||||
changed
|
||||
}
|
||||
|
||||
[ -z "$CHANGED" ] || {
|
||||
[ -z "$_ansible_diff" ] || set_diff "$old" "$new" "$path" "$path"
|
||||
[ -n "$_ansible_check_mode" ] || save_changes "$new"
|
||||
}
|
||||
}
|
||||
|
||||
line_absent() {
|
||||
local index new old
|
||||
|
||||
[ -f "$path" ] || return 0
|
||||
|
||||
old="$(cat "$path")" || fail "path $path not readable"
|
||||
index="$(get_last_match "$line_match" "$old")"
|
||||
[ -z "$index" ] || {
|
||||
new="$(echo "$old" | sed -re "/$line_match/d")"
|
||||
changed
|
||||
}
|
||||
|
||||
[ -z "$_ansible_diff" ] || set_diff "$old" "$new" "$path" "$path"
|
||||
[ -n "$_ansible_check_mode" -o -z "$CHANGED" ] || save_changes "$new"
|
||||
}
|
||||
|
||||
main() {
|
||||
case "$state" in
|
||||
absent|present) :;;
|
||||
*) fail "state must be absent or present";;
|
||||
esac
|
||||
[ -n "$regex" ] &&
|
||||
line_match="$(escape_slash "$regex")" ||
|
||||
line_match="^$(escape_chars "$line" '/.[*^$()+?{|')\$"
|
||||
[ ! -d "$file" ] || fail "path $path is a directory"
|
||||
case "$state" in
|
||||
present)
|
||||
[ -z "$backrefs" -o -n "$regex" ] ||
|
||||
fail "regexp is required with backrefs"
|
||||
[ -n "$line" ] || fail "line is required with state present"
|
||||
line_present;;
|
||||
absent)
|
||||
[ -n "$line" -o -n "$regex" ] ||
|
||||
fail "line or regexp is required with state absent"
|
||||
line_absent;;
|
||||
esac
|
||||
set_file_attributes "$path" "" "y"
|
||||
}
|
||||
12
roles/gekmihesg.openwrt/library/openwrt_nohup.sh
Normal file
12
roles/gekmihesg.openwrt/library/openwrt_nohup.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
PARAMS="command=cmd/str/r delay/int//0"
|
||||
SUPPORTS_CHECK_MODE=""
|
||||
|
||||
main() {
|
||||
try /sbin/start-stop-daemon -Sbqp /dev/null -x /bin/sh -- -c \
|
||||
"sleep $delay; $command"
|
||||
changed
|
||||
}
|
||||
70
roles/gekmihesg.openwrt/library/openwrt_opkg.sh
Normal file
70
roles/gekmihesg.openwrt/library/openwrt_opkg.sh
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
PARAMS="
|
||||
name=pkg/str/r
|
||||
state/str//present
|
||||
force/str
|
||||
update_cache/bool
|
||||
autoremove/bool
|
||||
nodeps/bool
|
||||
"
|
||||
|
||||
query_package() {
|
||||
[ -n "$(opkg status "$1")" ]
|
||||
}
|
||||
|
||||
install_packages() {
|
||||
local _IFS pkg
|
||||
_IFS="$IFS"; IFS=","; set -- $name; IFS="$_IFS"
|
||||
for pkg; do
|
||||
! query_package "$pkg" || continue
|
||||
[ -n "$_ansible_check_mode" ] || {
|
||||
try opkg install$force $nodeps "$pkg"
|
||||
query_package "$pkg" || fail "failed to install $pkg: $_result"
|
||||
}
|
||||
changed
|
||||
done
|
||||
}
|
||||
|
||||
remove_packages() {
|
||||
local _IFS pkg
|
||||
_IFS="$IFS"; IFS=","; set -- $name; IFS="$_IFS"
|
||||
for pkg; do
|
||||
query_package "$pkg" || continue
|
||||
[ -n "$_ansible_check_mode" ] || {
|
||||
try opkg remove$force $autoremove $nodeps "$pkg"
|
||||
! query_package "$pkg" || fail "failed to remove $pkg: $_result"
|
||||
}
|
||||
changed
|
||||
done
|
||||
}
|
||||
|
||||
main() {
|
||||
case "$state" in
|
||||
present|installed|absent|removed) :;;
|
||||
*) fail "state must be present or absent";;
|
||||
esac
|
||||
[ -z "$force" ] || {
|
||||
case "$force" in
|
||||
depends|maintainer|reinstall|overwrite|downgrade|space) :;;
|
||||
postinstall|remove|checksum|removal-of-dependent-packages) :;;
|
||||
*) fail "unknown force option";;
|
||||
esac
|
||||
force=" --force-$force"
|
||||
}
|
||||
[ -z "$autoremove" ] || {
|
||||
autoremove=" --autoremove"
|
||||
}
|
||||
|
||||
[ -z "$nodeps" ] || {
|
||||
nodeps=" --nodeps"
|
||||
}
|
||||
|
||||
[ -z "$update_cache" -o -n "$_ansible_check_mode" ] || try opkg update
|
||||
case "$state" in
|
||||
present|installed) install_packages;;
|
||||
absent|removed) remove_packages;;
|
||||
esac
|
||||
}
|
||||
25
roles/gekmihesg.openwrt/library/openwrt_ping.sh
Normal file
25
roles/gekmihesg.openwrt/library/openwrt_ping.sh
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
PARAMS="data/any"
|
||||
RESPONSE_VARS="ping data"
|
||||
|
||||
__exit() {
|
||||
[ -z "$NO_EXIT_JSON" ] || return $?
|
||||
echo -n "{\"ping\":\"$ping\""
|
||||
[ -z "$data" ] || echo -n ",\"data\":\"${data//\"/\\\"}\""
|
||||
echo "}"
|
||||
}
|
||||
|
||||
main() {
|
||||
[ "$data" != "crash" ] ||
|
||||
{ NO_EXIT_JSON="y"; echo "boom"; exit 1; }
|
||||
ping="pong"
|
||||
}
|
||||
|
||||
[ -n "$_ANSIBLE_PARAMS" ] || {
|
||||
. "$1"
|
||||
trap __exit EXIT
|
||||
main
|
||||
}
|
||||
63
roles/gekmihesg.openwrt/library/openwrt_service.sh
Normal file
63
roles/gekmihesg.openwrt/library/openwrt_service.sh
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
PARAMS="
|
||||
enabled/bool
|
||||
name/str/r
|
||||
pattern/str
|
||||
state/str
|
||||
"
|
||||
RESPONSE_VARS="name enabled state"
|
||||
|
||||
is_running() {
|
||||
[ -z "$pattern" ] || { pgrep -f "$pattern" >/dev/null 2>&1; return $?; }
|
||||
"$init_script" running >/dev/null 2>&1
|
||||
}
|
||||
|
||||
is_enabled() {
|
||||
! "$init_script" enabled >/dev/null 2>&1 || echo 1
|
||||
}
|
||||
|
||||
set_enabled() {
|
||||
local status result
|
||||
status="$(is_enabled)"
|
||||
[ "$enabled" = "$status" ] || {
|
||||
changed
|
||||
[ -n "$_ansible_check_mode" ] || {
|
||||
[ -n "$enabled" ] && action="enable" || action="disable"
|
||||
result="$("$init_script" "$action" 2>&1)"
|
||||
status="$(is_enabled)"
|
||||
[ "$enabled" = "$status" ] ||
|
||||
fail "Unable to $action service $name: $result"
|
||||
}
|
||||
}
|
||||
case "$status" in
|
||||
1) enabled="yes";;
|
||||
*) enabled="no";;
|
||||
esac
|
||||
}
|
||||
|
||||
set_state() {
|
||||
local action result running
|
||||
is_running && running="y" || running=""
|
||||
case "$state" in
|
||||
started) [ -n "$running" ] || action="start";;
|
||||
stopped) [ -z "$running" ] || action="stop";;
|
||||
restarted|reloaded) action="${state%ed}";;
|
||||
*) fail "Unknown action $action";;
|
||||
esac
|
||||
[ -z "$action" ] || {
|
||||
changed
|
||||
[ -n "$_ansible_check_mode" ] ||
|
||||
result="$("$init_script" "$action" 2>&1)" ||
|
||||
fail "Unable to $action service $name: $result"
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
init_script="/etc/init.d/$name"
|
||||
[ -f "$init_script" ] || fail "service $name does not exist"
|
||||
[ -z "$_orig_enabled" ] || set_enabled
|
||||
[ -z "$state" ] || set_state
|
||||
}
|
||||
67
roles/gekmihesg.openwrt/library/openwrt_setup.sh
Normal file
67
roles/gekmihesg.openwrt/library/openwrt_setup.sh
Normal file
@@ -0,0 +1,67 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
NO_EXIT_JSON="1"
|
||||
|
||||
add_ubus_fact() {
|
||||
set -- ${1//!/ }
|
||||
ubus list "$2" > /dev/null 2>&1 || return
|
||||
local json="$($ubus call "$2" "$3" 2>/dev/null)"
|
||||
echo -n "$seperator\"$1\":$json"
|
||||
seperator=","
|
||||
}
|
||||
|
||||
main() {
|
||||
ubus="/bin/ubus"
|
||||
seperator=","
|
||||
echo '{"changed":false,"ansible_facts":'
|
||||
dist="OpenWRT"
|
||||
dist_version="NA"
|
||||
dist_release="NA"
|
||||
test -f /etc/openwrt_release && {
|
||||
. /etc/openwrt_release
|
||||
dist="${DISTRIB_ID:-$dist}"
|
||||
dist_version="${DISTRIB_RELEASE:-$dist_version}"
|
||||
dist_release="${DISTRIB_CODENAME:-$dist_release}"
|
||||
} || test ! -f /etc/os-release || {
|
||||
. /etc/os-release
|
||||
dist="${NAME:-$dist}"
|
||||
dist_version="${VERSION_ID:-$dist_version}"
|
||||
}
|
||||
dist_major="${dist_version%%.*}"
|
||||
json_set_namespace facts
|
||||
json_init
|
||||
json_add_string ansible_hostname "$(cat /proc/sys/kernel/hostname)"
|
||||
json_add_string ansible_distribution "$dist"
|
||||
json_add_string ansible_distribution_major_version "$dist_major"
|
||||
json_add_string ansible_distribution_release "$dist_release"
|
||||
json_add_string ansible_distribution_version "$dist_version"
|
||||
json_add_string ansible_os_family OpenWRT
|
||||
json_add_boolean ansible_is_chroot "$([ -r /proc/1/root/. ] &&
|
||||
{ [ / -ef /proc/1/root/. ]; echo $?; } ||
|
||||
{ [ "$(ls -di / | awk '{print $1}')" -eq 2 ]; echo $?; }
|
||||
)"
|
||||
dist_facts="$(json_dump)"
|
||||
json_cleanup
|
||||
json_set_namespace result
|
||||
echo "${dist_facts%\}*}"
|
||||
for fact in \
|
||||
info!system!info \
|
||||
devices!network.device!status \
|
||||
services!service!list \
|
||||
board!system!board \
|
||||
wireless!network.wireless!status \
|
||||
; do
|
||||
add_ubus_fact "openwrt_$fact"
|
||||
done
|
||||
echo "$seperator"'"openwrt_interfaces":{'
|
||||
seperator=""
|
||||
for net in $($ubus list); do
|
||||
[ "${net#network.interface.}" = "$net" ] ||
|
||||
add_ubus_fact "${net##*.}!$net!status"
|
||||
done
|
||||
echo '}}}'
|
||||
}
|
||||
|
||||
[ -n "$_ANSIBLE_PARAMS" ] || main
|
||||
21
roles/gekmihesg.openwrt/library/openwrt_slurp.sh
Normal file
21
roles/gekmihesg.openwrt/library/openwrt_slurp.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
PARAMS="
|
||||
src=path/str/r
|
||||
"
|
||||
RESPONSE_VARS="source=src content encoding"
|
||||
|
||||
init() {
|
||||
content=""
|
||||
encoding=""
|
||||
}
|
||||
|
||||
main() {
|
||||
[ -e "$src" ] || fail "file not found: $src"
|
||||
[ -r "$src" ] || fail "file not readable: $src"
|
||||
try base64 "$src"
|
||||
content="$_result"
|
||||
encoding="base64"
|
||||
}
|
||||
137
roles/gekmihesg.openwrt/library/openwrt_stat.sh
Normal file
137
roles/gekmihesg.openwrt/library/openwrt_stat.sh
Normal file
@@ -0,0 +1,137 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
PARAMS="
|
||||
checksum_algorithm=checksum_algo=checksum/str//sha1
|
||||
get_checksum/bool//true
|
||||
get_md5/bool//true
|
||||
get_mime/bool//true
|
||||
path/str/r
|
||||
"
|
||||
RESPONSE_VARS="
|
||||
charset/str
|
||||
checksum/str
|
||||
ctime/int
|
||||
dev/int
|
||||
executable/bool
|
||||
exists/bool
|
||||
gid/int
|
||||
gr_name/str
|
||||
inode/int
|
||||
isblk/bool
|
||||
ischr/bool
|
||||
isdir/bool
|
||||
isfifo/bool
|
||||
isgid/bool
|
||||
islnk/bool
|
||||
isreg/bool
|
||||
issock/bool
|
||||
isuid/bool
|
||||
lnk_source/str
|
||||
md5/str
|
||||
mime_type/str
|
||||
mode/str
|
||||
mtime/int
|
||||
nlink/int
|
||||
pw_name/str
|
||||
readable/bool
|
||||
rgrp/bool
|
||||
roth/bool
|
||||
rusr/bool
|
||||
size/int
|
||||
uid/int
|
||||
wgrp/bool
|
||||
woth/bool
|
||||
writeable/bool
|
||||
wusr/bool
|
||||
xgrp/bool
|
||||
xoth/bool
|
||||
xusr/bool
|
||||
"
|
||||
|
||||
init() {
|
||||
local var
|
||||
for var in $RESPONSE_VARS; do eval "${var%%/*}=\"\""; done
|
||||
RESPONSE_VARS="path/str $RESPONSE_VARS"
|
||||
}
|
||||
|
||||
parse_priv() {
|
||||
local priv="$1"
|
||||
local part="$2"
|
||||
local octal="0"
|
||||
[ -z "${priv#-??}" ] || { eval "r$part=\"1\""; octal=$((octal + 4)); }
|
||||
[ -z "${priv#?-?}" ] || { eval "w$part=\"1\""; octal=$((octal + 2)); }
|
||||
[ -z "${priv#??[-ST]}" ] || { eval "x$part=\"1\""; octal=$((octal + 1)); }
|
||||
mode="$mode$octal"
|
||||
[ -z "${priv#??[-x]}" ] || high=$((high + high_mod))
|
||||
high_mod=$((high_mod / 2))
|
||||
}
|
||||
|
||||
main() {
|
||||
local var privs _IFS tmp
|
||||
[ ! -h "$path" -o -z "$follow" ] || {
|
||||
lnk_source="$path"
|
||||
path="$(readlink -f "$path")" || :
|
||||
}
|
||||
[ -n "$path" -a -e "$path" -o -h "$path" ] || {
|
||||
exists="0"
|
||||
return 0
|
||||
}
|
||||
for var in $RESPONSE_VARS; do
|
||||
_IFS="$IFS"; IFS="/"; set -- $var; IFS="$_IFS"
|
||||
[ "${2#b}" = "$2" ] || eval "$1=\"0\""
|
||||
done
|
||||
exists="1"
|
||||
charset="unknown"
|
||||
mime_type="unknown"
|
||||
set -- $(ls -lid "$path")
|
||||
inode="$1"
|
||||
privs="$2"
|
||||
nlink="$3"
|
||||
pw_name="$4"
|
||||
gr_name="$5"
|
||||
size="$6"
|
||||
set -- $(ls -lidn "$path")
|
||||
uid="$4"
|
||||
gid="$5"
|
||||
[ ! -x "$path" ] || executable="1"
|
||||
[ ! -r "$path" ] || readable="1"
|
||||
[ ! -w "$path" ] || writeable="1"
|
||||
case "$privs" in
|
||||
d*) isdir="1";;
|
||||
l*) islnk="1";;
|
||||
s*) issock="1";;
|
||||
c*) ischr="1";;
|
||||
b*) isblk="1";;
|
||||
p*) isfifo="1";;
|
||||
-*)
|
||||
[ "$readable" != "1" ] || {
|
||||
[ -z "$get_md5" ] || md5="$(md5 "$path")"
|
||||
[ -z "$get_checksum" ] ||
|
||||
checksum="$(dgst "$checksum_algorithm" "$path")" ||
|
||||
[ "$checksum_algorithm" = "sha1" ] ||
|
||||
fail "Could not hash file '$path' with algorithm '$checksum_algorithm'."
|
||||
}
|
||||
isreg="1";;
|
||||
esac
|
||||
mtime="$(date -r "$path" +%s)"
|
||||
ctime="$mtime"
|
||||
atime="$mtime"
|
||||
[ "$(id -u)" -ne "$uid" ] || isuid="1"
|
||||
[ "$(id -g)" -ne "$gid" ] || isgid="1"
|
||||
high="0"; high_mod=4
|
||||
privs="${privs#?}"; parse_priv "${privs%??????}" usr
|
||||
privs="${privs#???}"; parse_priv "${privs%???}" grp
|
||||
privs="${privs#???}"; parse_priv "$privs" oth
|
||||
mode="$high$mode"
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
json_set_namespace result
|
||||
json_add_object stat
|
||||
_exit_add_vars $RESPONSE_VARS
|
||||
json_close_object
|
||||
json_set_namespace params
|
||||
RESPONSE_VARS=""
|
||||
}
|
||||
90
roles/gekmihesg.openwrt/library/openwrt_sysctl.sh
Normal file
90
roles/gekmihesg.openwrt/library/openwrt_sysctl.sh
Normal file
@@ -0,0 +1,90 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
PARAMS="
|
||||
ignore_errors=ignoreerrors/bool
|
||||
name=key/str/r
|
||||
reload/bool//true
|
||||
state/str//present
|
||||
sysctl_file/str
|
||||
sysctl_set/bool//false
|
||||
value=val/str
|
||||
"
|
||||
RESPONSE_VARS="name value"
|
||||
|
||||
init() {
|
||||
sysctl="/sbin/sysctl"
|
||||
default_sysctl_file="/etc/sysctl.conf"
|
||||
tmp_file=""
|
||||
}
|
||||
|
||||
sysctl_set() {
|
||||
local result
|
||||
[ "$(echo $($sysctl -n "$name"))" = "$value" ] || {
|
||||
changed
|
||||
[ -n "$_ansible_check_mode" ] ||
|
||||
result="$($sysctl -w "$name=$value" 2>/dev/null)" ||
|
||||
fail "failed to set $name to $value: $result"
|
||||
}
|
||||
}
|
||||
|
||||
sysctl_write() {
|
||||
local found line v k
|
||||
tmp_file="$(mktemp)"
|
||||
while read line; do
|
||||
set -- $line
|
||||
[ -z "$1" -o "${1:0:1}" = "#" -o "${1/=/}" = "$1" ] || {
|
||||
k="${1%%=*}"
|
||||
[ "$k" != "$name" ] || {
|
||||
found="1"
|
||||
[ "$state" = "present" ] || { changed; continue; }
|
||||
v="${1#*=}"
|
||||
shift; while [ $# -ge 1 ]; do
|
||||
[ "${1:0:1}" != "#" ] || break; v="$v $1"; shift
|
||||
done
|
||||
[ "$v" = "$value" ] || {
|
||||
line="$k=$value${1:+ $*}"
|
||||
changed
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "$line" >> "$tmp_file"
|
||||
done < "$sysctl_file"
|
||||
[ "$state" != "present" -o -n "$found" ] || {
|
||||
echo "$name=$value" >> "$tmp_file"
|
||||
changed
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
local result
|
||||
[ -n "$sysctl_file" ] || sysctl_file="$default_sysctl_file"
|
||||
case "$state" in
|
||||
absent) :;;
|
||||
present)
|
||||
[ -n "$value" ] ||
|
||||
fail "value must be given with state present";;
|
||||
*) fail "state must be present or absent";;
|
||||
esac
|
||||
|
||||
[ -w "$sysctl_file" ] || fail "sysctl file $sysctl_file not writeable"
|
||||
[ "$state" = "present" ] || ignore_errors="y"
|
||||
[ -n "$ignore_errors" -a -z "$sysctl_set" ] ||
|
||||
[ $($sysctl "$name" 2>/dev/null | wc -l) -eq 1 ] ||
|
||||
fail "unknown sysctl key $name"
|
||||
|
||||
[ -z "$sysctl_set" ] || sysctl_set
|
||||
sysctl_write
|
||||
|
||||
[ -z "$CHANGED" -o -n "$_ansible_check_mode" ] || {
|
||||
cat "$tmp_file" > "$sysctl_file"
|
||||
[ -z "$reload" -o "$state" != "present" ] ||
|
||||
result="$($sysctl -p "$sysctl_file" 2>&1)" ||
|
||||
fail "failed to reload: $result"
|
||||
}
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
[ -z "$tmp_file" ] || rm -f "$tmp_file"
|
||||
}
|
||||
384
roles/gekmihesg.openwrt/library/openwrt_uci.sh
Normal file
384
roles/gekmihesg.openwrt/library/openwrt_uci.sh
Normal file
@@ -0,0 +1,384 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
WANT_JSON="1"
|
||||
PARAMS="
|
||||
autocommit/bool
|
||||
command=cmd/str
|
||||
config/str
|
||||
find=find_by=search/any
|
||||
keep_keys=keep/any
|
||||
key/str
|
||||
merge/bool//false
|
||||
name/str
|
||||
option/str
|
||||
replace/bool//false
|
||||
section/str
|
||||
set_find/bool//true
|
||||
type/str
|
||||
unique/bool//false
|
||||
value/any
|
||||
"
|
||||
RESPONSE_VARS="result=_result command config section option"
|
||||
|
||||
init() {
|
||||
state_path=""
|
||||
[ -z "$_ansible_check_mode" ] || state_path="$(mktemp -d)" ||
|
||||
fail "could not create state path"
|
||||
changes="$(uci_change_hash)"
|
||||
case "$_type_keep_keys" in
|
||||
object) fail "keep_keys must be list or string";;
|
||||
array) json_get_values keep_keys "$_keep_keys" || :;;
|
||||
esac
|
||||
[ -z "$key" ] &&
|
||||
key="${config:+$config${section:+.$section${option:+.$option}}}" ||
|
||||
{ oIFS="$IFS"; IFS="."; set -- $key; IFS="$oIFS"
|
||||
config="$1"; section="$2"; option="$3"; }
|
||||
[ -z "$_ansible_diff" -o -z "$config" ] ||
|
||||
set_diff "$(uci export "$config")"
|
||||
[ -n "$command" ] || { [ -z "$value" ] && command="get" || command="set"; }
|
||||
}
|
||||
|
||||
uci() {
|
||||
[ -z "$state_path" ] || set -- -P "$state_path" "$@"
|
||||
command uci "$@"
|
||||
}
|
||||
|
||||
uci_change_hash() {
|
||||
uci changes | md5
|
||||
}
|
||||
|
||||
uci_result_do() {
|
||||
json_set_namespace result
|
||||
"$@"
|
||||
json_set_namespace params
|
||||
}
|
||||
|
||||
uci_get_safe() {
|
||||
local tmp opts
|
||||
while [ "${1#-}" != "$1" ]; do opts="$opts $1"; shift; done
|
||||
tmp="$(uci $opts show "$1")" || return $?
|
||||
echo "${tmp#*=}"
|
||||
}
|
||||
|
||||
uci_check_type() {
|
||||
local key="$1"; local type="$2"; local t
|
||||
t="$(uci -q get "$key")" || return 1
|
||||
[ -n "$type" -a "$t" != "$type" ] || return 0
|
||||
fail "$key exists with $t instead of $type"
|
||||
}
|
||||
|
||||
uci_compare_list() {
|
||||
local k="${1:-$key}"
|
||||
local match="1"
|
||||
local keys values v i
|
||||
json_get_keys keys
|
||||
! values="$(uci_get_safe -q "$k")" || {
|
||||
eval "set -- $values"
|
||||
for i in $keys; do
|
||||
json_get_var v "$i"
|
||||
[ $# -gt 0 -a "$v" = "$1" ] || { match=""; break; }
|
||||
shift
|
||||
done
|
||||
[ $# -eq 0 ] || match=""
|
||||
[ -z "$match" ] || return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
uci_add() {
|
||||
section="${section:-$value}"
|
||||
[ -n "$name" -o -z "$type" ] || name="$section"
|
||||
type="${type:-$section}"
|
||||
[ -n "$type" ] || fail "type required for $command"
|
||||
[ -n "$name" ] && {
|
||||
uci_check_type "$config.$name" "$type" || {
|
||||
try uci add "$config" "$type"
|
||||
try uci rename "$config.$_result=$name"
|
||||
}
|
||||
} || try uci add "$config" "$type"
|
||||
}
|
||||
|
||||
uci_set_list() {
|
||||
local k="${1:-$key}"
|
||||
local keys v i
|
||||
! uci_compare_list "$k" || return 0
|
||||
uci -q delete "$k" || :
|
||||
json_get_keys keys
|
||||
for i in $keys; do
|
||||
json_get_var v "$i"
|
||||
try uci add_list "$k=$v"
|
||||
done
|
||||
}
|
||||
|
||||
uci_set_dict() {
|
||||
local keys k v t
|
||||
json_get_keys keys
|
||||
keep_keys="$keep_keys $keys"
|
||||
for k in $keys; do
|
||||
json_get_type t "$k"
|
||||
case "$t" in
|
||||
array)
|
||||
json_select "$k"
|
||||
uci_set_list "$key.$k"
|
||||
json_select ..;;
|
||||
object) fail "cannot set $k to dict";;
|
||||
*)
|
||||
json_get_var v "$k"
|
||||
try uci set "$key.$k=$v";;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
uci_set() {
|
||||
local var="${1:-value}"
|
||||
local var_type
|
||||
eval "var_type=\"\$_type_$var\""
|
||||
[ -z "$option" ] || keep_keys="$keep_keys $option"
|
||||
case "$var_type" in
|
||||
array)
|
||||
[ -n "$config" -a -n "$section" -a -n "$option" ] ||
|
||||
fail "config, section and option required for $command"
|
||||
json_select_real "$var"
|
||||
uci_set_list
|
||||
json_select ..;;
|
||||
object)
|
||||
[ -n "$config" -a -n "$section" -a -z "$option" ] ||
|
||||
fail "config and section but not option required for $command"
|
||||
json_select_real "$var"
|
||||
uci_set_dict
|
||||
json_select ..;;
|
||||
*) try "uci set \"\$key=\$$var\"";;
|
||||
esac
|
||||
}
|
||||
|
||||
uci_get() {
|
||||
local entry
|
||||
try uci get "$key"
|
||||
eval "set -- $(uci_get_safe -q "$key")"
|
||||
json_set_namespace result
|
||||
json_add_array result_list
|
||||
for entry; do json_add_string . "$entry"; done
|
||||
json_close_array
|
||||
json_set_namespace params
|
||||
}
|
||||
|
||||
uci_find() {
|
||||
local keys i c v k tmp
|
||||
case "$_type_find" in
|
||||
array|object)
|
||||
[ -n "$config" -a -n "$type" ] ||
|
||||
fail "config and type required for $command"
|
||||
json_select_real find
|
||||
json_get_keys keys;;
|
||||
*)
|
||||
[ -n "$config" -a -n "$type" ] &&
|
||||
[ -n "$option" -o "$command" = find_all ] ||
|
||||
fail "config, type and option required for $command";;
|
||||
esac
|
||||
[ "$command" != "find_all" ] || uci_result_do json_add_array result
|
||||
type="${type:-$section}"
|
||||
section=""; i=0
|
||||
while [ -n "$(uci -q get "$config.@$type[$i]")" ]; do
|
||||
c="@$type[$((i++))]"
|
||||
case "$_type_find" in
|
||||
array)
|
||||
[ -z "$option" ] && {
|
||||
for k in $keys; do
|
||||
json_get_var v "$k"
|
||||
uci -q get "$config.$c.$v" >/dev/null || continue 2
|
||||
done
|
||||
} || {
|
||||
uci_compare_list "$config.$c.$option" || continue
|
||||
};;
|
||||
object)
|
||||
for k in $keys; do
|
||||
json_get_type tmp "$k"
|
||||
case "$tmp" in
|
||||
array)
|
||||
json_select "$k"
|
||||
uci_compare_list "$config.$c.$k" &&
|
||||
tmp="1" || tmp=""
|
||||
json_select ..
|
||||
[ -n "$tmp" ] || continue 2;;
|
||||
object)
|
||||
fail "cannot compare $k with dict";;
|
||||
*)
|
||||
json_get_var v "$k"
|
||||
tmp="$(uci -q get "$config.$c.$k")" &&
|
||||
[ "$tmp" = "$v" ] || continue 2
|
||||
esac
|
||||
done;;
|
||||
*)
|
||||
[ -z "$option" ] || {
|
||||
v="$(uci -q get "$config.$c.$option")" &&
|
||||
[ -z "$find" -o "$find" = "$v" ] || continue
|
||||
};;
|
||||
esac
|
||||
[ "$command" = "find_all" ] || { section="$c"; break; }
|
||||
uci_result_do json_add_string . "$c"
|
||||
done
|
||||
case "$_type_find" in
|
||||
array|object) json_select ..;;
|
||||
esac
|
||||
case "$command" in
|
||||
find_all)
|
||||
uci_result_do json_close_array
|
||||
_result="";;
|
||||
*)
|
||||
_result="$section"
|
||||
[ -n "$section" ] && return 0 || return 1;;
|
||||
esac
|
||||
}
|
||||
|
||||
uci_ensure() {
|
||||
local keys k v
|
||||
[ -n "$name" -o -z "$type" ] || name="$section"
|
||||
type="${type:-$section}"
|
||||
[ -n "$config" -a -n "$type" ] ||
|
||||
fail "config, type and name required for $command"
|
||||
[ -n "$name" ] && uci_check_type "$config.$name" "$type" || {
|
||||
[ "$_type_find" = "object" -o -n "$option" ] && uci_find && {
|
||||
[ -z "$name" ] || try uci rename "$config.$section=$name"
|
||||
} || {
|
||||
[ "$command" = absent ] && return 0 || uci_add
|
||||
}
|
||||
}
|
||||
section="${name:-$_result}"
|
||||
key="$config.$section${option:+.$option}"
|
||||
[ "$command" = "absent" ] && {
|
||||
[ -z "$_defined_value" ] &&
|
||||
{ uci -q delete "$key" || :; } ||
|
||||
case "$_type_value" in
|
||||
array|object)
|
||||
json_select_real value
|
||||
json_get_keys keys
|
||||
for k in $keys; do
|
||||
json_get_var v "$k"
|
||||
case "$_type_value" in
|
||||
array) uci -q delete "$config.$section.$v";;
|
||||
object) uci -q delete "$config.$section.$k=$v";;
|
||||
esac
|
||||
done
|
||||
json_select ..;;
|
||||
*) uci -q delete "$config.$section.$value";;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
[ -z "$set_find" -o "$_type_find" != "object" -a -z "$option" ] || {
|
||||
uci_set find
|
||||
[ "$_type_value" != "object" ] || {
|
||||
key="$config.$section"
|
||||
option=""
|
||||
}
|
||||
}
|
||||
[ -z "$_defined_value" ] || uci_set
|
||||
_result="$section"
|
||||
}
|
||||
|
||||
uci_cleanup_section() {
|
||||
case "$command" in
|
||||
set|ensure|section) :;;
|
||||
*) return 0;;
|
||||
esac
|
||||
local k v
|
||||
[ -n "$replace" -a -n "$config" -a -n "$section" ] || return 0
|
||||
for k in $(uci -q show "$config.$section" |
|
||||
sed -n 's/^..*\...*\.\([^.][^.]*\)=.*$/\1/p')
|
||||
do
|
||||
for v in $keep_keys; do
|
||||
[ "$k" != "$v" ] || continue 2
|
||||
done
|
||||
uci -q delete "$config.$section.$k"
|
||||
done
|
||||
}
|
||||
|
||||
uci_revert() {
|
||||
[ -z "$key" ] && rm -f -- "/tmp/.uci"/* 2>/dev/null || uci revert "$key"
|
||||
}
|
||||
|
||||
uci_autocommit() {
|
||||
[ -n "$autocommit" ] || return 0
|
||||
case "$command" in
|
||||
commit|revert) return 0;;
|
||||
esac
|
||||
[ "$1" -eq 0 ] && {
|
||||
[ -n "$config" ] && uci commit "$config" || uci commit
|
||||
} || uci_revert
|
||||
}
|
||||
|
||||
main() {
|
||||
case "$command" in
|
||||
batch|import)
|
||||
[ -n "$value" ] || fail "value required for $command";;
|
||||
add_list|del_list|rename|reorder)
|
||||
[ -n "$key" -a -n "$value" ] ||
|
||||
fail "key and value required for $command";;
|
||||
add|get|delete|ensure|absent)
|
||||
[ -n "$key" ] || fail "key required for $command";;
|
||||
esac
|
||||
case "$command" in
|
||||
batch)
|
||||
echo "$value" | final uci $command;;
|
||||
export|changes|show|commit)
|
||||
local cmd="final uci $command"
|
||||
[ -z "$key" ] && $cmd || $cmd "$key";;
|
||||
import)
|
||||
local cmd="final uci ${merge:+-m }$command"
|
||||
[ -z "$key" ] && echo "$value" | $cmd ||
|
||||
echo "$value" | $cmd "$key";;
|
||||
add)
|
||||
uci_add; exit 0;;
|
||||
add_list)
|
||||
[ -z "$unique" ] || {
|
||||
eval "set -- $(uci_get_safe -q "$key")"
|
||||
for entry; do [ "$entry" = "$value" ] && exit 0; done
|
||||
}
|
||||
final uci add_list "$key=$value";;
|
||||
del_list|reorder)
|
||||
final uci $command "$key=$value";;
|
||||
get)
|
||||
uci_get; exit 0;;
|
||||
delete)
|
||||
final uci $command "$key${value:+=$value}";;
|
||||
rename)
|
||||
final uci $command "$key=${name:-$value}";;
|
||||
revert)
|
||||
final uci_revert;;
|
||||
set)
|
||||
uci_set; exit 0;;
|
||||
find|find_all)
|
||||
uci_find; exit $?;;
|
||||
ensure|section)
|
||||
uci_ensure; exit 0;;
|
||||
absent)
|
||||
[ -n "$_defined_find" ] || {
|
||||
uci -q delete "$key${value:+=$value}"; exit 0
|
||||
}
|
||||
uci_ensure; exit 0;;
|
||||
*) fail "unknown command: $command";;
|
||||
esac
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
local ec="$1"
|
||||
[ "$ec" -ne 0 ] || uci_cleanup_section
|
||||
[ "$changes" = "$(uci_change_hash)" ] || {
|
||||
changed
|
||||
[ "$_ansible_verbosity" -lt 2 ] || {
|
||||
local _IFS line
|
||||
_IFS="$IFS"; IFS="$N"; set -- $(uci changes); IFS="$_IFS"
|
||||
json_set_namespace result
|
||||
json_add_array changes
|
||||
for line; do json_add_string . "$line"; done
|
||||
json_close_array
|
||||
json_set_namespace params
|
||||
}
|
||||
uci_autocommit "$ec"
|
||||
}
|
||||
[ -z "$_ansible_diff" -o -z "$config" ] ||
|
||||
set_diff "" "$(uci export "$config")"
|
||||
[ -z "$_ansible_check_mode" -o -z "$state_path" -o ! -d "$state_path" ] ||
|
||||
rm -rf "$state_path"
|
||||
}
|
||||
190
roles/gekmihesg.openwrt/library/uci.py
Normal file
190
roles/gekmihesg.openwrt/library/uci.py
Normal file
@@ -0,0 +1,190 @@
|
||||
#!/usr/bin/python
|
||||
# Copyright (c) 2017 Markus Weippert
|
||||
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.0',
|
||||
'status': ['preview'],
|
||||
'supported_by': '@gekmihesg'
|
||||
}
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: uci
|
||||
short_description: Controls OpenWRTs UCI
|
||||
description:
|
||||
- The M(uci) module is a Ansible wrapper for OpenWRTs C(uci).
|
||||
- It supports all the command line functionality plus some extra commands.
|
||||
author: Markus Weippert (@gekmihesg)
|
||||
options:
|
||||
autocommit:
|
||||
description:
|
||||
- Whether to automatically commit changes
|
||||
type: bool
|
||||
default: false
|
||||
command:
|
||||
description:
|
||||
- Command to execute. Execution takes place in a shell.
|
||||
default: set if value else get
|
||||
choices:
|
||||
- absent
|
||||
- add
|
||||
- add_list
|
||||
- batch
|
||||
- changes
|
||||
- commit
|
||||
- del_list
|
||||
- export
|
||||
- find
|
||||
- get
|
||||
- import
|
||||
- rename
|
||||
- reorder
|
||||
- revert
|
||||
- section
|
||||
- set
|
||||
- show
|
||||
aliases:
|
||||
- cmd
|
||||
config:
|
||||
description:
|
||||
- Config part of the I(key).
|
||||
default: extracted from I(key)
|
||||
find:
|
||||
description:
|
||||
- Value(s) to match sections against.
|
||||
- Option value to find if I(option) is set. May be list.
|
||||
- Dict of options/values if I(option) is not set. Values may be list.
|
||||
- Lists are compared in order.
|
||||
- Required when I(command=find) or I(command=section)
|
||||
aliases:
|
||||
- find_by
|
||||
- search
|
||||
keep_keys:
|
||||
description:
|
||||
- Space seperated list or list of keys not in I(value) or I(find) to
|
||||
keep when I(replace=yes).
|
||||
aliases:
|
||||
- keep
|
||||
key:
|
||||
description:
|
||||
- The C(uci) key to operate on.
|
||||
- Takes precedence over I(config), I(section) and I(option)
|
||||
default: I(config).I(section).I(option)
|
||||
merge:
|
||||
description:
|
||||
- Whether to merge or replace when I(command=import)
|
||||
type: bool
|
||||
default: false
|
||||
name:
|
||||
description:
|
||||
- New name when I(command=rename) or I(command=add).
|
||||
- Desired name when I(command=section). If a matching section is
|
||||
found it is renamed, if not it is created with that name.
|
||||
option:
|
||||
description:
|
||||
- Option part of the I(key).
|
||||
default: extracted from I(key)
|
||||
replace:
|
||||
description:
|
||||
- When I(command=set) or I(command=section), whether to delete all
|
||||
options not mentioned in I(keep_keys), I(value) or find when
|
||||
I(set_find=true).
|
||||
type: bool
|
||||
default: false
|
||||
section:
|
||||
description:
|
||||
- Section part of the I(key).
|
||||
default: extracted from I(key)
|
||||
set_find:
|
||||
description:
|
||||
- When I(command=section) whether to set the options used to search
|
||||
a matching section in the newly created section when no match was
|
||||
found.
|
||||
type: bool
|
||||
default: false
|
||||
type:
|
||||
description:
|
||||
- Section type for I(command=section), I(command=find) and
|
||||
I(command=add).
|
||||
default: I(section)
|
||||
unique:
|
||||
description:
|
||||
- When I(command=add_list), whether to add the value if it is already
|
||||
contained in the list.
|
||||
type: bool
|
||||
default: false
|
||||
value:
|
||||
description:
|
||||
- The value for various commands.
|
||||
'''
|
||||
EXAMPLES = '''
|
||||
# Find a section of type wifi-iface with matching name or matching attributes.
|
||||
# If not found create it and set the attributes from find.
|
||||
# Unconditionally set the attributes from value and delete all other options.
|
||||
- uci:
|
||||
command: section
|
||||
config: wireless
|
||||
type: wifi-iface
|
||||
name: ap0
|
||||
find:
|
||||
device: radio0
|
||||
ssid: My SSID
|
||||
value:
|
||||
encryption: none
|
||||
replace: yes
|
||||
|
||||
# Find a matching wifi-iface and delete it.
|
||||
- uci:
|
||||
command: absent
|
||||
config: wireless
|
||||
type: wifi-iface
|
||||
find:
|
||||
ssid: My SSID broken
|
||||
|
||||
# Find a matching wifi-iface and delete the options key and encryption.
|
||||
- uci:
|
||||
command: absent
|
||||
config: wireless
|
||||
type: wifi-iface
|
||||
find:
|
||||
ssid: My SSID public
|
||||
value:
|
||||
- key
|
||||
- encryption
|
||||
|
||||
# commit changes and notify
|
||||
- uci: cmd=commit
|
||||
notify: restart wifi
|
||||
'''
|
||||
RETURN = '''
|
||||
result:
|
||||
description: output of the C(uci) command
|
||||
returned: always
|
||||
type: string
|
||||
sample: cfg12523
|
||||
result_list:
|
||||
description: the list form of result
|
||||
returned: when I(command=get)
|
||||
type: list of string
|
||||
sample: ['0.pool.ntp.org','1.pool.ntp.org']
|
||||
config:
|
||||
description: config part of I(key)
|
||||
returned: when given
|
||||
type: string
|
||||
sample: wireless
|
||||
section:
|
||||
description: section part of I(key)
|
||||
returned: when given
|
||||
type: string
|
||||
sample: '@wifi-iface[0]'
|
||||
option:
|
||||
description: option part of I(key)
|
||||
returned: when given
|
||||
type: string
|
||||
sample: ssid
|
||||
command:
|
||||
description: command executed
|
||||
returned: always
|
||||
type: string
|
||||
sample: section
|
||||
'''
|
||||
|
||||
Reference in New Issue
Block a user