Merge branch 'master' into __package_absent_present
This commit is contained in:
commit
605eaeb039
51 changed files with 1002 additions and 427 deletions
2
README
2
README
|
@ -89,7 +89,7 @@ cdist was tested or is know to run on at least
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Preperation
|
### Preparation
|
||||||
|
|
||||||
Ensure you have Python 3.2 installed on the machine you use to **deploy to the targets**
|
Ensure you have Python 3.2 installed on the machine you use to **deploy to the targets**
|
||||||
(the ***source host***).
|
(the ***source host***).
|
||||||
|
|
8
build
8
build
|
@ -85,7 +85,7 @@ case "$1" in
|
||||||
;;
|
;;
|
||||||
|
|
||||||
release)
|
release)
|
||||||
"$0" clean && "$0" man && "$0" web
|
./doc/dev/releasechecklist
|
||||||
;;
|
;;
|
||||||
|
|
||||||
speeches)
|
speeches)
|
||||||
|
@ -113,8 +113,8 @@ case "$1" in
|
||||||
# cp ${SPEECHESDIR}/*.pdf ${WEBDIR}/${WEBBASE}/speeches
|
# cp ${SPEECHESDIR}/*.pdf ${WEBDIR}/${WEBBASE}/speeches
|
||||||
# git describe > ${WEBDIR}/${WEBBASE}/man/VERSION
|
# git describe > ${WEBDIR}/${WEBBASE}/man/VERSION
|
||||||
|
|
||||||
cp ${MAN1DSTDIR}/*.html ${WEBMAN}/man1
|
cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${WEBMAN}/man1
|
||||||
cp ${MAN7DSTDIR}/*.html ${WEBMAN}/man7
|
cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${WEBMAN}/man7
|
||||||
|
|
||||||
cd ${WEBDIR} && git add ${WEBBASE}
|
cd ${WEBDIR} && git add ${WEBBASE}
|
||||||
cd ${WEBDIR} && git commit -m "cdist update" ${WEBBASE} ${WEBPAGE}
|
cd ${WEBDIR} && git commit -m "cdist update" ${WEBBASE} ${WEBPAGE}
|
||||||
|
@ -123,7 +123,7 @@ case "$1" in
|
||||||
# Fix ikiwiki, which does not like symlinks for pseudo security
|
# Fix ikiwiki, which does not like symlinks for pseudo security
|
||||||
ssh tee.schottelius.org \
|
ssh tee.schottelius.org \
|
||||||
"cd /home/services/www/nico/www.nico.schottelius.org/www/software/cdist/man &&
|
"cd /home/services/www/nico/www.nico.schottelius.org/www/software/cdist/man &&
|
||||||
ln -sf "$version" latest"
|
rm -f latest && ln -sf "$version" latest"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
p|pu|pub)
|
p|pu|pub)
|
||||||
|
|
26
conf/explorer/runlevel
Executable file
26
conf/explorer/runlevel
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# 2012 Nico Schottelius (nico-cdist at schottelius.org)
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
set +e
|
||||||
|
executable=$(which runlevel 2>/dev/null)
|
||||||
|
if [ -x "$executable" ]; then
|
||||||
|
"$executable" | awk '{ print $2 }'
|
||||||
|
fi
|
53
conf/type/__key_value/explorer/state
Executable file
53
conf/type/__key_value/explorer/state
Executable file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
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
|
|
@ -18,35 +18,40 @@
|
||||||
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
value_is="$(cat "$__object/explorer/value")"
|
|
||||||
value_should="$(cat "$__object/parameter/value")"
|
|
||||||
|
|
||||||
key="$(cat "$__object/parameter/key")"
|
key="$(cat "$__object/parameter/key")"
|
||||||
file="$(cat "$__object/parameter/file")"
|
file="$(cat "$__object/parameter/file")"
|
||||||
delimiter="$(cat "$__object/parameter/delimiter")"
|
delimiter="$(cat "$__object/parameter/delimiter")"
|
||||||
|
value="$(cat "$__object/parameter/value")"
|
||||||
|
|
||||||
if [ "$value_is" != "$value_should" ]; then
|
state_is="$(cat "$__object/explorer/state")"
|
||||||
case "$value_is" in
|
state_should="$(cat "$__object/parameter/state")"
|
||||||
__NOTSET__)
|
|
||||||
# add key and value
|
if [ "$state_is" = "$state_should" ]; then
|
||||||
echo "echo \"${key}${delimiter}${value_should}\" >> \"$file\""
|
# 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\""
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
if [ "$value_should" = '__NOTSET__' ]; then
|
echo "Unknown explorer state: $state_is" >&2
|
||||||
# remove key and value
|
exit 1
|
||||||
cat << DONE
|
esac
|
||||||
sed -i '/^${key}/d' "$file"
|
;;
|
||||||
DONE
|
*)
|
||||||
else
|
echo "Unknown state: $state_should" >&2
|
||||||
# change value
|
exit 1
|
||||||
cat << DONE
|
|
||||||
awk -F "$delimiter" '
|
|
||||||
/${key}${delimiter}*/{gsub("$value_is", "$value_should")};{print}' "$file" > "${file}+" \
|
|
||||||
&& mv "${file}+" "$file"
|
|
||||||
|
|
||||||
DONE
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,6 @@ file.
|
||||||
|
|
||||||
REQUIRED PARAMETERS
|
REQUIRED PARAMETERS
|
||||||
-------------------
|
-------------------
|
||||||
value::
|
|
||||||
The value for the key. Setting the value to `__NOTSET__` will remove the key
|
|
||||||
from the file.
|
|
||||||
file::
|
file::
|
||||||
The file to operate on.
|
The file to operate on.
|
||||||
delimiter::
|
delimiter::
|
||||||
|
@ -27,8 +24,13 @@ delimiter::
|
||||||
|
|
||||||
OPTIONAL PARAMETERS
|
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::
|
key::
|
||||||
The key to change. Defaults to object_id.
|
The key to change. Defaults to object_id.
|
||||||
|
value::
|
||||||
|
The value for the key. Optional if state=absent, required otherwise.
|
||||||
|
|
||||||
|
|
||||||
EXAMPLES
|
EXAMPLES
|
||||||
|
@ -45,6 +47,9 @@ __key_value my-fancy-id --file /etc/login.defs --key SYS_UID_MAX --value 666 \
|
||||||
# Enable packet forwarding
|
# Enable packet forwarding
|
||||||
__key_value net.ipv4.ip_forward --file /etc/sysctl.conf --value 1 \
|
__key_value net.ipv4.ip_forward --file /etc/sysctl.conf --value 1 \
|
||||||
--delimiter '='
|
--delimiter '='
|
||||||
|
|
||||||
|
# Remove existing key/value
|
||||||
|
__key_value LEGACY_KEY --file /etc/somefile --state absent --delimiter '='
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,13 @@
|
||||||
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
if [ -f "$__object/parameter/key" ]; then
|
# set defaults
|
||||||
key="$(cat "$__object/parameter/key")"
|
key="$(cat "$__object/parameter/key" 2>/dev/null \
|
||||||
else
|
|| echo "$__object_id" | tee "$__object/parameter/key")"
|
||||||
echo "$__object_id" > "$__object/parameter/key"
|
state="$(cat "$__object/parameter/state" 2>/dev/null \
|
||||||
fi
|
|| echo "present" | tee "$__object/parameter/state")"
|
||||||
|
|
||||||
|
if [ "$state" = "present" -a ! -f "$__object/parameter/value" ]; then
|
||||||
|
echo "Missing required parameter 'value'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
key
|
key
|
||||||
|
value
|
||||||
|
state
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
value
|
|
||||||
file
|
file
|
||||||
delimiter
|
delimiter
|
||||||
|
|
|
@ -35,14 +35,15 @@ else
|
||||||
pip="pip"
|
pip="pip"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# which is not posix, but command is :-)
|
# If there is no pip, it may get created from somebody else.
|
||||||
|
# If it will be created, there is probably no package installed.
|
||||||
if ! command -v "$pip" >/dev/null 2>&1; then
|
if ! command -v "$pip" >/dev/null 2>&1; then
|
||||||
echo "No usable pip found at path \"$pip\"" >&2
|
echo absent
|
||||||
exit 1
|
else
|
||||||
fi
|
|
||||||
|
|
||||||
if "$pip" freeze | grep -i -q "^$name=="; then
|
if "$pip" freeze | grep -i -q "^$name=="; then
|
||||||
echo present
|
echo present
|
||||||
else
|
else
|
||||||
echo absent
|
echo absent
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
cdist-type__package_pip(7)
|
cdist-type__package_pip(7)
|
||||||
=============================
|
==========================
|
||||||
Nico Schottelius <nico-cdist--@--schottelius.org>
|
Nico Schottelius <nico-cdist--@--schottelius.org>
|
||||||
|
|
||||||
|
|
||||||
|
|
64
conf/type/__start_on_boot/explorer/state
Executable file
64
conf/type/__start_on_boot/explorer/state
Executable file
|
@ -0,0 +1,64 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# 2012 Nico Schottelius (nico-cdist at schottelius.org)
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Check whether the given name will be started on boot or not
|
||||||
|
#
|
||||||
|
|
||||||
|
os=$("$__explorer/os")
|
||||||
|
runlevel=$("$__explorer/runlevel")
|
||||||
|
name="$__object_id"
|
||||||
|
|
||||||
|
|
||||||
|
case "$os" in
|
||||||
|
archlinux)
|
||||||
|
# convert bash array to shell
|
||||||
|
daemons=$(grep ^DAEMONS /etc/rc.conf | sed -e 's/^.*=(//' -e 's/)$//')
|
||||||
|
|
||||||
|
# absent, as long as not found
|
||||||
|
state="absent"
|
||||||
|
|
||||||
|
# iterate, last one wins.
|
||||||
|
for daemon in $daemons; do
|
||||||
|
if [ "$daemon" = "$name" -o "$daemon" = "@${name}" ]; then
|
||||||
|
state="present"
|
||||||
|
elif [ "$daemon" = "!${name}" ]; then
|
||||||
|
state="absent"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
|
||||||
|
debian|ubuntu)
|
||||||
|
state="present"
|
||||||
|
[ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent"
|
||||||
|
;;
|
||||||
|
|
||||||
|
centos|fedora|owl|redhat)
|
||||||
|
state="present"
|
||||||
|
state=$(chkconfig --level "$runlevel" \"$name\" || echo absent)
|
||||||
|
[ "$state" ] || state="present"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "Unsupported os: $os" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo $state
|
89
conf/type/__start_on_boot/gencode-remote
Executable file
89
conf/type/__start_on_boot/gencode-remote
Executable file
|
@ -0,0 +1,89 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# 2012 Nico Schottelius (nico-cdist at schottelius.org)
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
state_should="$(cat "$__object/parameter/state")"
|
||||||
|
state_is=$(cat "$__object/explorer/state")
|
||||||
|
|
||||||
|
# Nothing todo, go away
|
||||||
|
[ "$state_should" = "$state_is" ] && exit 0
|
||||||
|
|
||||||
|
os=$(cat "$__global/explorer/os")
|
||||||
|
name="$__object_id"
|
||||||
|
|
||||||
|
case "$state_should" in
|
||||||
|
present)
|
||||||
|
case "$os" in
|
||||||
|
archlinux)
|
||||||
|
echo "sed -i /etc/rc.conf \'s/^\\(DAEMONS=.*\\))/\\1 $name)/\'"
|
||||||
|
;;
|
||||||
|
debian|ubuntu)
|
||||||
|
echo "update-rc.d \"$name\" defaults >/dev/null"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# FIXME: Disabled until the explorer is checked
|
||||||
|
# gentoo)
|
||||||
|
# echo rc-update add \"$name\" default
|
||||||
|
# ;;
|
||||||
|
|
||||||
|
centos|fedora|owl|redhat)
|
||||||
|
echo chkconfig \"$name\" on
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "Unsupported os: $os" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
|
||||||
|
absent)
|
||||||
|
case "$os" in
|
||||||
|
archlinux)
|
||||||
|
# Replace a) at the beginning b) in the middle c) end d) only
|
||||||
|
# Support @name as well...makes it more ugly, but well...
|
||||||
|
echo "sed -i /etc/rc.conf -e 's/^\\(DAEMONS=(\\)@\\{0,1\\}$name /\\1/' -e 's/^\\(DAEMONS=(.* \\)@\\{0,1\\}$name \\(.*\\)/\\1\\2/' -e 's/^\\(DAEMONS=(.*\\) @\\{0,1\\}$name)/\\1)/' -e 's/^\\(DAEMONS=(\\)@\\{0,1\\}$name)/\\1)/'"
|
||||||
|
;;
|
||||||
|
debian|ubuntu)
|
||||||
|
echo update-rc.d -f \"$name\" remove
|
||||||
|
;;
|
||||||
|
|
||||||
|
# FIXME: Disabled until the explorer is checked
|
||||||
|
# gentoo)
|
||||||
|
# echo rc-update del \"$name\"
|
||||||
|
# ;;
|
||||||
|
|
||||||
|
centos|fedora|owl|redhat)
|
||||||
|
echo chkconfig \"$name\" off
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "Unsupported os: $os" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "Unknown state: $state_should" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
53
conf/type/__start_on_boot/man.text
Normal file
53
conf/type/__start_on_boot/man.text
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
cdist-type__start_on_boot(7)
|
||||||
|
============================
|
||||||
|
Nico Schottelius <nico-cdist--@--schottelius.org>
|
||||||
|
|
||||||
|
|
||||||
|
NAME
|
||||||
|
----
|
||||||
|
cdist-type__start_on_boot - Manage stuff to be started at boot
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
-----------
|
||||||
|
This cdist type allows you to enable or disable stuff to be started
|
||||||
|
at boot of your operating system.
|
||||||
|
|
||||||
|
Warning: This type has not been tested intensively and is not fully
|
||||||
|
supported (i.e. gentoo and *bsd are not implemented).
|
||||||
|
|
||||||
|
|
||||||
|
REQUIRED PARAMETERS
|
||||||
|
-------------------
|
||||||
|
None.
|
||||||
|
|
||||||
|
OPTIONAL PARAMETERS
|
||||||
|
-------------------
|
||||||
|
state::
|
||||||
|
'present' or 'absent', defaults to 'present'
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
|
--------
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
# Ensure snmpd is started at boot
|
||||||
|
__start_on_boot snmpd
|
||||||
|
|
||||||
|
# Same, but more explicit
|
||||||
|
__start_on_boot snmpd --state present
|
||||||
|
|
||||||
|
# Ensure legacy configuration management will not be started
|
||||||
|
__start_on_boot puppet --state absent
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
--------
|
||||||
|
- cdist-type(7)
|
||||||
|
|
||||||
|
|
||||||
|
COPYING
|
||||||
|
-------
|
||||||
|
Copyright \(C) 2012 Nico Schottelius. Free use of this software is
|
||||||
|
granted under the terms of the GNU General Public License version 3 (GPLv3).
|
|
@ -1,6 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# 2011 Steven Armstrong (steven-cdist at armstrong.cc)
|
# 2011 Steven Armstrong (steven-cdist at armstrong.cc)
|
||||||
|
# 2012 Nico Schottelius (nico-cdist at schottelius.org)
|
||||||
#
|
#
|
||||||
# This file is part of cdist.
|
# This file is part of cdist.
|
||||||
#
|
#
|
||||||
|
@ -17,21 +18,7 @@
|
||||||
# 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/>.
|
||||||
#
|
#
|
||||||
#
|
|
||||||
# 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__"
|
|
||||||
|
|
||||||
|
# set default: present, if not setup
|
||||||
|
statefile="$__object/parameter/state"
|
||||||
|
[ -f "$statefile" ] || echo present > "$statefile"
|
1
conf/type/__start_on_boot/parameter/optional
Normal file
1
conf/type/__start_on_boot/parameter/optional
Normal file
|
@ -0,0 +1 @@
|
||||||
|
state
|
|
@ -28,6 +28,7 @@ cd "$__object/parameter"
|
||||||
if grep -q "^${name}:" "$__object/explorer/passwd"; then
|
if grep -q "^${name}:" "$__object/explorer/passwd"; then
|
||||||
for property in $(ls .); do
|
for property in $(ls .); do
|
||||||
new_value="$(cat "$property")"
|
new_value="$(cat "$property")"
|
||||||
|
unset current_value
|
||||||
|
|
||||||
file="$__object/explorer/passwd"
|
file="$__object/explorer/passwd"
|
||||||
|
|
||||||
|
@ -36,9 +37,16 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then
|
||||||
if $(echo "$new_value" | grep -q '^[0-9][0-9]*$'); then
|
if $(echo "$new_value" | grep -q '^[0-9][0-9]*$'); then
|
||||||
field=4
|
field=4
|
||||||
else
|
else
|
||||||
# group name
|
# We were passed a group name. Compare the gid in
|
||||||
file="$__object/explorer/group"
|
# the user's /etc/passwd entry with the gid of the
|
||||||
field=1
|
# group returned by the group explorer.
|
||||||
|
gid_from_group=$(awk -F: '{ print $3 }' "$__object/explorer/group")
|
||||||
|
gid_from_passwd=$(awk -F: '{ print $4 }' "$file")
|
||||||
|
if [ "$gid_from_group" != "$gid_from_passwd" ]; then
|
||||||
|
current_value="$gid_from_passwd"
|
||||||
|
else
|
||||||
|
current_value="$new_value"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
password)
|
password)
|
||||||
|
@ -51,8 +59,12 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then
|
||||||
uid) field=3 ;;
|
uid) field=3 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
# If we haven't already set $current_value above, pull it from the
|
||||||
|
# appropriate file/field.
|
||||||
|
if [ -z "$current_value" ]; then
|
||||||
export field
|
export field
|
||||||
current_value="$(awk -F: '{ print $ENVIRON["field"] }' < "$file")"
|
current_value="$(awk -F: '{ print $ENVIRON["field"] }' < "$file")"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$new_value" != "$current_value" ]; then
|
if [ "$new_value" != "$current_value" ]; then
|
||||||
set -- "$@" "--$property" \'$new_value\'
|
set -- "$@" "--$property" \'$new_value\'
|
||||||
|
|
|
@ -4,11 +4,22 @@ Changelog
|
||||||
* Changes are always commented with their author in (braces)
|
* Changes are always commented with their author in (braces)
|
||||||
* Exception: No braces means author == Nico Schottelius
|
* Exception: No braces means author == Nico Schottelius
|
||||||
|
|
||||||
2.0.7:
|
2.0.8:
|
||||||
|
* Cleanup: Better hint to source of error
|
||||||
|
* Cleanup: Do not output failing script, but path to script only
|
||||||
|
* Cleanup: Remove support for __debug variable in manifests (Type != Core
|
||||||
|
debugging)
|
||||||
|
* Feature Core: Support boolean parameters (Steven Armstrong)
|
||||||
|
|
||||||
|
2.0.7: 2012-02-13
|
||||||
* Bugfix __file: Use chmod after chown/chgrp (Matt Coddington)
|
* Bugfix __file: Use chmod after chown/chgrp (Matt Coddington)
|
||||||
* Bugfix __user: Correct shadow field in explorer (Matt Coddington)
|
* Bugfix __user: Correct shadow field in explorer (Matt Coddington)
|
||||||
* Bugfix __link: Properly handle existing links (Steven Armstrong)
|
* Bugfix __link: Properly handle existing links (Steven Armstrong)
|
||||||
|
* Bugfix __key_value: More robust implementation (Steven Armstrong)
|
||||||
|
* Bugfix __user: Fix for changing a user's group by name (Matt Coddington)
|
||||||
* New Type: __package_pip
|
* New Type: __package_pip
|
||||||
|
* Bugfix/Cleanup: Correctly allow Object ID to start and end with /, but
|
||||||
|
not contain //.
|
||||||
|
|
||||||
2.0.6: 2012-01-28
|
2.0.6: 2012-01-28
|
||||||
* Bugfix __apt_ppa:
|
* Bugfix __apt_ppa:
|
||||||
|
|
18
doc/dev/logs/2012-02-10.object_id-and-slashes
Normal file
18
doc/dev/logs/2012-02-10.object_id-and-slashes
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
__typename /foo/bar # possible, usual use case
|
||||||
|
require="__a//b" __typename /foo/bar # possible and happens often for __a/$id in loops
|
||||||
|
|
||||||
|
__typename /foo/bar/ # trailing slash will be stripped, can be documented
|
||||||
|
|
||||||
|
__typename /foo//bar//baz # // will be converted to / implicitly through fs; error prone; disallow
|
||||||
|
|
||||||
|
require="__a//b//c" __typename # // will be converted to / implicitly through fs; error prone; disallow
|
||||||
|
|
||||||
|
|
||||||
|
Solution:
|
||||||
|
|
||||||
|
1) allow require __a//b: type __a, object id /b
|
||||||
|
=> strip first slash of object id, as we do in non-dep-mode
|
||||||
|
2) allow _one_ trailing /: __type /foo/bar/ and require="__foo/abc/"
|
||||||
|
=> strip one leading slash of object id
|
||||||
|
3) disallow // within object id
|
||||||
|
4) disallow starting or ending / after 1) and 2)
|
23
doc/dev/logs/2012-02-13.dependencies
Normal file
23
doc/dev/logs/2012-02-13.dependencies
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
possible dependencies:
|
||||||
|
|
||||||
|
- unix pattern __foo/*
|
||||||
|
- object: __foo//bar, __foo/bar
|
||||||
|
- singleton with object_id: __foo/singleton
|
||||||
|
- singleton without object_id: __foo/
|
||||||
|
|
||||||
|
solving dependencies:
|
||||||
|
|
||||||
|
solve_dep(object, run_list):
|
||||||
|
- list = [me]
|
||||||
|
- if status == IN_DEPENDENCY:
|
||||||
|
fail: circular dependency
|
||||||
|
- status = IN_DEPENDENCY
|
||||||
|
- create_list_of_deps(object)
|
||||||
|
- try pattern expansion
|
||||||
|
- for each dependency:
|
||||||
|
if object does not exist:
|
||||||
|
fail
|
||||||
|
else:
|
||||||
|
list.append(solve_dep(object, run_list)):
|
||||||
|
- status == IN_LIST
|
||||||
|
- return [me, dependencies [, dependencies of dependencies]]
|
132
doc/dev/logs/2012-02-15.steven
Normal file
132
doc/dev/logs/2012-02-15.steven
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
- parameter/setting default from manifest
|
||||||
|
==> BRANCH[feature_default_parameters],
|
||||||
|
==> PERSON[Steven or Nico]
|
||||||
|
==> PROPOSAL(1)
|
||||||
|
- current bug
|
||||||
|
- proposal 1: parameter/default/$name (for optional ones)
|
||||||
|
- new way
|
||||||
|
- catches --state absent|present
|
||||||
|
- needs changes of types
|
||||||
|
- also possible for explorer
|
||||||
|
- support for it in core?
|
||||||
|
- handling of ${o} $o "$o" ?
|
||||||
|
- handling which variables?
|
||||||
|
- introduction of "templating language"
|
||||||
|
- aka macros
|
||||||
|
- possible problems:
|
||||||
|
- inconsistency
|
||||||
|
- redoing shell functionality
|
||||||
|
- raising expectations for more templating from users
|
||||||
|
- possible benefit
|
||||||
|
- no need for eval
|
||||||
|
- once in core, not everytime in type
|
||||||
|
- OTOH: one extra word.
|
||||||
|
- a=$(cat $__object/parameter/name) vs. $(eval $(cat $__object/parameter/name))
|
||||||
|
- only possible for static defaults
|
||||||
|
- --name overrides name not possible vs. object_id
|
||||||
|
- Is this the only case????
|
||||||
|
- if yes: don't care.
|
||||||
|
- possible solution:
|
||||||
|
- echo '/$__object_id' > typename/parameter/default/name
|
||||||
|
- eval $(cat $__object/parameter/name)
|
||||||
|
- probably allows code injection
|
||||||
|
- is possible anyway???
|
||||||
|
- $(cat /etc/shadow)
|
||||||
|
- other eval side effects???
|
||||||
|
- none: go for it
|
||||||
|
- some: have headache
|
||||||
|
- many: don't do
|
||||||
|
- proposal 2: 2 dbs (user input vs. stuff changable by type)
|
||||||
|
- explicit 2nd db [parameter_user and parameter/]
|
||||||
|
- not very clean (both agreed)
|
||||||
|
- proposal 3: parameter are read-only
|
||||||
|
- breaks current types (in core probably elsewhere)
|
||||||
|
- can't enforce, but user is on his own => breaks, her problem
|
||||||
|
+ clean seperation between core and type (nico)
|
||||||
|
- parameter belongs to type not core (steven)
|
||||||
|
- proposal 4: core ignores changes in parameter/* of object
|
||||||
|
- implicit 2nd db [see automagic below]
|
||||||
|
- steven+++
|
||||||
|
- does not work with divergent emulator not being in core
|
||||||
|
- because emulators primary db __is__ fs.
|
||||||
|
|
||||||
|
1 manifest:
|
||||||
|
|
||||||
|
__foo bar == emulator
|
||||||
|
echo present > $__global/object/__foo/bar/parameter/state
|
||||||
|
|
||||||
|
# fails
|
||||||
|
__foo bar == emulator
|
||||||
|
|
||||||
|
! automagic / filesystem
|
||||||
|
! fsproperty:
|
||||||
|
- kill, write explicitly to disk
|
||||||
|
==> BRANCH[cleanup_fsproperty]
|
||||||
|
==> PERSON[Steven]
|
||||||
|
==> PROPOSAL(just cleanup)
|
||||||
|
|
||||||
|
- implicit/automatic writes/read to fs
|
||||||
|
- explicit interfaces are better then implicit
|
||||||
|
- same problems as in cdist 1.x to 2.x move! (environment!)
|
||||||
|
- format on disk should not change/dictate code flow
|
||||||
|
- degrade python to shell (nico++! steven--)
|
||||||
|
- user should not care about python, ruby, .net or ASM implementation (steven++ nico++)
|
||||||
|
|
||||||
|
? proposal 1: diverge emulator / core
|
||||||
|
- emulator verifies input
|
||||||
|
- emulator writes to fs
|
||||||
|
- core reads/syncs from/to fs before passing control to user
|
||||||
|
|
||||||
|
? proposal 2: emulator is dumb and passes data to core
|
||||||
|
- core creates objects
|
||||||
|
- no fs involved
|
||||||
|
- core reads/syncs from/to fs before passing control to user
|
||||||
|
- passing:
|
||||||
|
- full objects via pickle
|
||||||
|
- parameters only
|
||||||
|
- how???
|
||||||
|
- unix socket?
|
||||||
|
- not everywhere possible?
|
||||||
|
- tcp / ip
|
||||||
|
- not everywhere possible
|
||||||
|
- chroot / local only
|
||||||
|
- rfc 1149
|
||||||
|
- not everywhere possible
|
||||||
|
- missing avian carriers
|
||||||
|
- 0mq
|
||||||
|
- not everywhere possible
|
||||||
|
- not installed
|
||||||
|
- shm (ipcs and friends)
|
||||||
|
- not everywhere possible
|
||||||
|
- no /dev/shm, different libraries? cleanups needed...
|
||||||
|
- what speaks against FS?
|
||||||
|
- emulator_input/.../
|
||||||
|
|
||||||
|
- nico: to fancy probably
|
||||||
|
|
||||||
|
! boolean implementation
|
||||||
|
==> BRANCH[feature_boolean_parameter]
|
||||||
|
==> PERSON[Steven]
|
||||||
|
- nico:
|
||||||
|
- parameters/boolean: document
|
||||||
|
- argparse changes (consider parameters/boolean)
|
||||||
|
- create
|
||||||
|
- can be implemented with changes in emulator
|
||||||
|
- use store_true, del if false => never seen by core
|
||||||
|
- INDEPENDENT INDEPENDT OF FS.PROPERTIES!!111111!
|
||||||
|
|
||||||
|
- emulator:
|
||||||
|
- how much integrated into core
|
||||||
|
- also: using CdistObject????
|
||||||
|
- dependency on filesystem: good (nico) | bad (steven)
|
||||||
|
|
||||||
|
- singleton / support without object_id
|
||||||
|
- not discussed
|
||||||
|
|
||||||
|
- __apt_ppa:
|
||||||
|
==> BRANCH[bugfix_do_not_change_state_in_manifest]
|
||||||
|
==> PERSON[Nico]
|
||||||
|
|
||||||
|
- logging divergent between emulator / core
|
||||||
|
- no problem (nico)
|
||||||
|
- may be helpful (steven)
|
|
@ -15,11 +15,21 @@ changelog_version=$(grep '^[[:digit:]]' doc/changelog | head -n1 | sed 's/:.*//'
|
||||||
#git_version=$(git describe)
|
#git_version=$(git describe)
|
||||||
lib_version=$(grep ^VERSION lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g')
|
lib_version=$(grep ^VERSION lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g')
|
||||||
|
|
||||||
|
# get date
|
||||||
|
date_today="$(date +%Y-%m-%d)"
|
||||||
|
date_changelog=$(grep '^[[:digit:]]' doc/changelog | head -n1 | sed 's/.*: //')
|
||||||
|
|
||||||
echo "Ensure you fixed/prepared version files: $files"
|
echo "Ensure you fixed/prepared version files: $files"
|
||||||
echo "changelog: $changelog_version"
|
echo "changelog: $changelog_version"
|
||||||
#echo "git: $git_version"
|
#echo "git: $git_version"
|
||||||
echo "lib: $lib_version"
|
echo "lib: $lib_version"
|
||||||
|
|
||||||
|
if [ "$date_today" != "$date_changelog" ]; then
|
||||||
|
echo "Messed up date, not releasing:"
|
||||||
|
echo "Changelog: $date_changelog"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$lib_version" != "$changelog_version" ]; then
|
if [ "$lib_version" != "$changelog_version" ]; then
|
||||||
echo "Messed up versions, not releasing"
|
echo "Messed up versions, not releasing"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -35,3 +35,5 @@ USER INTERFACE
|
||||||
TYPES
|
TYPES
|
||||||
------
|
------
|
||||||
- Add testing framework (proposed by Evax Software)
|
- Add testing framework (proposed by Evax Software)
|
||||||
|
- __user
|
||||||
|
add option to include --create-home
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
- __file/foo/bar//bar
|
- introduce default parameters
|
||||||
- fails later
|
|
||||||
|
- cleanup object_id handling
|
||||||
|
- have a look at singletons
|
||||||
|
|
||||||
- __user
|
|
||||||
add option to include --create-home
|
|
||||||
- ensure that all types, which support --state support
|
- ensure that all types, which support --state support
|
||||||
present and absent (consistent look and feel)
|
present and absent (consistent look and feel)
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
- update/create docs
|
- update/create docs
|
||||||
- cdist-cache::
|
- cdist-cache::
|
||||||
How to get use information about the hosts we have been working on [advanced]
|
How to get use information about the hosts we have been working on [advanced]
|
||||||
|
|
|
@ -101,12 +101,15 @@ conf/type/<name>/gencode-local::
|
||||||
conf/type/<name>/gencode-remote::
|
conf/type/<name>/gencode-remote::
|
||||||
Used to generate code to be executed on the client.
|
Used to generate code to be executed on the client.
|
||||||
|
|
||||||
conf/type/<name>/parameters/required::
|
conf/type/<name>/parameter/required::
|
||||||
Parameters required by type, \n seperated list.
|
Parameters required by type, \n seperated list.
|
||||||
|
|
||||||
conf/type/<name>/parameters/optional::
|
conf/type/<name>/parameter/optional::
|
||||||
Parameters optionally accepted by type, \n seperated list.
|
Parameters optionally accepted by type, \n seperated list.
|
||||||
|
|
||||||
|
conf/type/<name>/parameter/boolean::
|
||||||
|
Boolean parameters accepted by type, \n seperated list.
|
||||||
|
|
||||||
conf/type/<name>/explorer::
|
conf/type/<name>/explorer::
|
||||||
Location of the type specific explorers.
|
Location of the type specific explorers.
|
||||||
This directory is referenced by the variable __type_explorer (see below).
|
This directory is referenced by the variable __type_explorer (see below).
|
||||||
|
@ -167,7 +170,7 @@ ENVIRONMENT VARIABLES
|
||||||
---------------------
|
---------------------
|
||||||
__explorer::
|
__explorer::
|
||||||
Directory that contains all global explorers.
|
Directory that contains all global explorers.
|
||||||
Available for: explorer
|
Available for: explorer, type explorer
|
||||||
__manifest::
|
__manifest::
|
||||||
Directory that contains the initial manifest.
|
Directory that contains the initial manifest.
|
||||||
Available for: initial manifest
|
Available for: initial manifest
|
||||||
|
@ -180,7 +183,11 @@ __object::
|
||||||
__object_id::
|
__object_id::
|
||||||
The type unique object id.
|
The type unique object id.
|
||||||
Available for: type manifest, type explorer, type gencode
|
Available for: type manifest, type explorer, type gencode
|
||||||
Note: The leading "/" will always be stripped.
|
|
||||||
|
Note: The leading and the trailing "/" will always be stripped (caused by
|
||||||
|
the filesystem database and ensured by the core).
|
||||||
|
|
||||||
|
Note: Double slashes ("//") will not be fixed and result in an error.
|
||||||
__self::
|
__self::
|
||||||
DEPRECATED: Same as __object_name, do not use anymore, use __object_name instead.
|
DEPRECATED: Same as __object_name, do not use anymore, use __object_name instead.
|
||||||
Will be removed in cdist 3.x.
|
Will be removed in cdist 3.x.
|
||||||
|
@ -189,7 +196,7 @@ __object_name::
|
||||||
Available for: type manifest, type explorer, type gencode
|
Available for: type manifest, type explorer, type gencode
|
||||||
__target_host::
|
__target_host::
|
||||||
The host we are deploying to.
|
The host we are deploying to.
|
||||||
Available for: initial manifest, type manifest, type gencode
|
Available for: explorer, initial manifest, type explorer, type manifest, type gencode
|
||||||
__type::
|
__type::
|
||||||
Path to the current type.
|
Path to the current type.
|
||||||
Available for: type manifest, type gencode
|
Available for: type manifest, type gencode
|
||||||
|
|
|
@ -61,12 +61,19 @@ including it.
|
||||||
|
|
||||||
HOW TO SUBMIT A NEW TYPE
|
HOW TO SUBMIT A NEW TYPE
|
||||||
------------------------
|
------------------------
|
||||||
|
For detailled information about types, see cdist-type(7).
|
||||||
|
|
||||||
Submitting a type works as described above, with the additional requirement
|
Submitting a type works as described above, with the additional requirement
|
||||||
that a corresponding manpage named man.text in asciidoc format with
|
that a corresponding manpage named man.text in asciidoc format with
|
||||||
the manpage-name "cdist-type__NAME" is included in the type directory
|
the manpage-name "cdist-type__NAME" is included in the type directory
|
||||||
AND asciidoc is able to compile it (i.e. do NOT have to many "=" in the second
|
AND asciidoc is able to compile it (i.e. do NOT have to many "=" in the second
|
||||||
line).
|
line).
|
||||||
|
|
||||||
|
Warning: Submitting "exec" or "run" types that simply echo their parameter in
|
||||||
|
gencode* will not be accepted, because they are of no use. Every type can output
|
||||||
|
code and thus such a type introduces redundant functionality that is given by
|
||||||
|
core cdist already.
|
||||||
|
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -72,15 +72,42 @@ To begin a new type, just create the directory **conf/type/__NAME**.
|
||||||
|
|
||||||
DEFINING PARAMETERS
|
DEFINING PARAMETERS
|
||||||
-------------------
|
-------------------
|
||||||
Every type consists of optional and required parameters, which must
|
Every type consists of required, optional and boolean parameters, which must
|
||||||
be created in a newline seperated file in ***parameters/required*** and
|
be created in a newline seperated file in ***parameter/required***,
|
||||||
***parameters/optional***. If either or both missing, the type will have
|
***parameter/optional*** and ***parameter/boolean***. If either is missing,
|
||||||
no required, no optional or no parameters at all.
|
the type will have no required, no optional, no boolean or no parameters at
|
||||||
|
all.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
echo servername >> conf/type/__nginx_vhost/parameter/required
|
echo servername >> conf/type/__nginx_vhost/parameter/required
|
||||||
echo logdirectory >> conf/type/__nginx_vhost/parameter/optional
|
echo logdirectory >> conf/type/__nginx_vhost/parameter/optional
|
||||||
|
echo use_ssl >> conf/type/__nginx_vhost/parameter/boolean
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
USING PARAMETERS
|
||||||
|
----------------
|
||||||
|
The parameters given to a type can be accessed and used in all type scripts
|
||||||
|
(e.g manifest, gencode-*, explorer/*). Note that boolean parameters are
|
||||||
|
represented by file existence. File exists -> True,
|
||||||
|
file does not exist -> False
|
||||||
|
|
||||||
|
Example: (e.g. in conf/type/__nginx_vhost/manifest)
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
# required parameter
|
||||||
|
servername="$(cat "$__object/parameter/servername")"
|
||||||
|
|
||||||
|
# optional parameter
|
||||||
|
if [ -f "$__object/parameter/logdirectory" ]; then
|
||||||
|
logdirectory="$(cat "$__object/parameter/logdirectory")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# boolean parameter
|
||||||
|
if [ -f "$__object/parameter/use_ssl" ]; then
|
||||||
|
# file exists -> True
|
||||||
|
# do some fancy ssl stuff
|
||||||
|
fi
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
VERSION = "2.0.6"
|
VERSION = "2.0.7"
|
||||||
|
|
||||||
BANNER = """
|
BANNER = """
|
||||||
.. . .x+=:. s
|
.. . .x+=:. s
|
||||||
|
@ -44,15 +44,17 @@ class Error(Exception):
|
||||||
"""Base exception class for this project"""
|
"""Base exception class for this project"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class CdistObjectError(Error):
|
||||||
|
"""Something went wrong with an object"""
|
||||||
|
|
||||||
class MissingEnvironmentVariableError(Error):
|
def __init__(self, cdist_object, message):
|
||||||
"""Raised when a required environment variable is not set."""
|
self.name = cdist_object.name
|
||||||
|
self.source = " ".join(cdist_object.source)
|
||||||
|
self.message = message
|
||||||
|
|
||||||
def __init__(self, name):
|
|
||||||
self.name = name
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Missing required environment variable: ' + str(self.name)
|
return '%s: %s (defined at %s)' % (self.name, self.message, self.source)
|
||||||
|
|
||||||
def file_to_list(filename):
|
def file_to_list(filename):
|
||||||
"""Return list from \n seperated file"""
|
"""Return list from \n seperated file"""
|
||||||
|
|
|
@ -89,9 +89,9 @@ class ConfigInstall(object):
|
||||||
new_objects_created = True
|
new_objects_created = True
|
||||||
while new_objects_created:
|
while new_objects_created:
|
||||||
new_objects_created = False
|
new_objects_created = False
|
||||||
for cdist_object in core.Object.list_objects(self.local.object_path,
|
for cdist_object in core.CdistObject.list_objects(self.local.object_path,
|
||||||
self.local.type_path):
|
self.local.type_path):
|
||||||
if cdist_object.state == core.Object.STATE_PREPARED:
|
if cdist_object.state == core.CdistObject.STATE_PREPARED:
|
||||||
self.log.debug("Skipping re-prepare of object %s", cdist_object)
|
self.log.debug("Skipping re-prepare of object %s", cdist_object)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
@ -103,16 +103,16 @@ class ConfigInstall(object):
|
||||||
self.log.info("Running manifest and explorers for " + cdist_object.name)
|
self.log.info("Running manifest and explorers for " + cdist_object.name)
|
||||||
self.explorer.run_type_explorers(cdist_object)
|
self.explorer.run_type_explorers(cdist_object)
|
||||||
self.manifest.run_type_manifest(cdist_object)
|
self.manifest.run_type_manifest(cdist_object)
|
||||||
cdist_object.state = core.Object.STATE_PREPARED
|
cdist_object.state = core.CdistObject.STATE_PREPARED
|
||||||
|
|
||||||
def object_run(self, cdist_object):
|
def object_run(self, cdist_object):
|
||||||
"""Run gencode and code for an object"""
|
"""Run gencode and code for an object"""
|
||||||
self.log.debug("Trying to run object " + cdist_object.name)
|
self.log.debug("Trying to run object " + cdist_object.name)
|
||||||
if cdist_object.state == core.Object.STATE_DONE:
|
if cdist_object.state == core.CdistObject.STATE_DONE:
|
||||||
# TODO: remove once we are sure that this really never happens.
|
# TODO: remove once we are sure that this really never happens.
|
||||||
raise cdist.Error("Attempting to run an already finished object: %s", cdist_object)
|
raise cdist.Error("Attempting to run an already finished object: %s", cdist_object)
|
||||||
|
|
||||||
cdist_type = cdist_object.type
|
cdist_type = cdist_object.cdist_type
|
||||||
|
|
||||||
# Generate
|
# Generate
|
||||||
self.log.info("Generating and executing code for " + cdist_object.name)
|
self.log.info("Generating and executing code for " + cdist_object.name)
|
||||||
|
@ -130,13 +130,13 @@ class ConfigInstall(object):
|
||||||
|
|
||||||
# Mark this object as done
|
# Mark this object as done
|
||||||
self.log.debug("Finishing run of " + cdist_object.name)
|
self.log.debug("Finishing run of " + cdist_object.name)
|
||||||
cdist_object.state = core.Object.STATE_DONE
|
cdist_object.state = core.CdistObject.STATE_DONE
|
||||||
|
|
||||||
def stage_run(self):
|
def stage_run(self):
|
||||||
"""The final (and real) step of deployment"""
|
"""The final (and real) step of deployment"""
|
||||||
self.log.info("Generating and executing code")
|
self.log.info("Generating and executing code")
|
||||||
|
|
||||||
objects = core.Object.list_objects(
|
objects = core.CdistObject.list_objects(
|
||||||
self.local.object_path,
|
self.local.object_path,
|
||||||
self.local.type_path)
|
self.local.type_path)
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,11 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
from cdist.core.type import Type
|
from cdist.core.cdist_type import CdistType
|
||||||
from cdist.core.type import NoSuchTypeError
|
from cdist.core.cdist_type import NoSuchTypeError
|
||||||
from cdist.core.object import Object
|
from cdist.core.cdist_object import CdistObject
|
||||||
from cdist.core.object import IllegalObjectIdError
|
from cdist.core.cdist_object import IllegalObjectIdError
|
||||||
from cdist.core.object import OBJECT_MARKER
|
from cdist.core.cdist_object import OBJECT_MARKER
|
||||||
from cdist.core.explorer import Explorer
|
from cdist.core.explorer import Explorer
|
||||||
from cdist.core.manifest import Manifest
|
from cdist.core.manifest import Manifest
|
||||||
from cdist.core.code import Code
|
from cdist.core.code import Code
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# 2011 Steven Armstrong (steven-cdist at armstrong.cc)
|
# 2011 Steven Armstrong (steven-cdist at armstrong.cc)
|
||||||
# 2011 Nico Schottelius (nico-cdist at schottelius.org)
|
# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
|
||||||
#
|
#
|
||||||
# This file is part of cdist.
|
# This file is part of cdist.
|
||||||
#
|
#
|
||||||
|
@ -42,7 +42,7 @@ class IllegalObjectIdError(cdist.Error):
|
||||||
return '%s: %s' % (self.message, self.object_id)
|
return '%s: %s' % (self.message, self.object_id)
|
||||||
|
|
||||||
|
|
||||||
class Object(object):
|
class CdistObject(object):
|
||||||
"""Represents a cdist object.
|
"""Represents a cdist object.
|
||||||
|
|
||||||
All interaction with objects in cdist should be done through this class.
|
All interaction with objects in cdist should be done through this class.
|
||||||
|
@ -61,7 +61,7 @@ class Object(object):
|
||||||
"""Return a list of object instances"""
|
"""Return a list of object instances"""
|
||||||
for object_name in cls.list_object_names(object_base_path):
|
for object_name in cls.list_object_names(object_base_path):
|
||||||
type_name, object_id = cls.split_name(object_name)
|
type_name, object_id = cls.split_name(object_name)
|
||||||
yield cls(cdist.core.Type(type_base_path, type_name), object_base_path, object_id=object_id)
|
yield cls(cdist.core.CdistType(type_base_path, type_name), object_base_path, object_id=object_id)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def list_type_names(cls, object_base_path):
|
def list_type_names(cls, object_base_path):
|
||||||
|
@ -96,30 +96,58 @@ class Object(object):
|
||||||
"""
|
"""
|
||||||
return os.path.join(type_name, object_id)
|
return os.path.join(type_name, object_id)
|
||||||
|
|
||||||
@staticmethod
|
def validate_object_id(self):
|
||||||
def validate_object_id(object_id):
|
# FIXME: also check that there is no object ID when type is singleton?
|
||||||
|
|
||||||
"""Validate the given object_id and raise IllegalObjectIdError if it's not valid.
|
"""Validate the given object_id and raise IllegalObjectIdError if it's not valid.
|
||||||
"""
|
"""
|
||||||
if object_id:
|
if self.object_id:
|
||||||
if object_id.startswith('/'):
|
if OBJECT_MARKER in self.object_id.split(os.sep):
|
||||||
raise IllegalObjectIdError(object_id, 'object_id may not start with /')
|
raise IllegalObjectIdError(self.object_id, 'object_id may not contain \'%s\'' % OBJECT_MARKER)
|
||||||
if OBJECT_MARKER in object_id.split(os.sep):
|
if '//' in self.object_id:
|
||||||
raise IllegalObjectIdError(object_id, 'object_id may not contain \'%s\'' % OBJECT_MARKER)
|
raise IllegalObjectIdError(self.object_id, 'object_id may not contain //')
|
||||||
|
|
||||||
|
# If no object_id and type is not singleton => error out
|
||||||
|
if not self.object_id and not self.cdist_type.is_singleton:
|
||||||
|
raise IllegalObjectIdError(self.object_id,
|
||||||
|
"Missing object_id and type is not a singleton.")
|
||||||
|
|
||||||
def __init__(self, cdist_type, base_path, object_id=None):
|
def __init__(self, cdist_type, base_path, object_id=None):
|
||||||
self.validate_object_id(object_id)
|
self.cdist_type = cdist_type # instance of Type
|
||||||
self.type = cdist_type # instance of Type
|
|
||||||
self.base_path = base_path
|
self.base_path = base_path
|
||||||
self.object_id = object_id
|
self.object_id = object_id
|
||||||
self.name = self.join_name(self.type.name, self.object_id)
|
|
||||||
self.path = os.path.join(self.type.path, self.object_id, OBJECT_MARKER)
|
self.validate_object_id()
|
||||||
|
self.sanitise_object_id()
|
||||||
|
|
||||||
|
self.name = self.join_name(self.cdist_type.name, self.object_id)
|
||||||
|
self.path = os.path.join(self.cdist_type.path, self.object_id, OBJECT_MARKER)
|
||||||
self.absolute_path = os.path.join(self.base_path, self.path)
|
self.absolute_path = os.path.join(self.base_path, self.path)
|
||||||
self.code_local_path = os.path.join(self.path, "code-local")
|
self.code_local_path = os.path.join(self.path, "code-local")
|
||||||
self.code_remote_path = os.path.join(self.path, "code-remote")
|
self.code_remote_path = os.path.join(self.path, "code-remote")
|
||||||
self.parameter_path = os.path.join(self.path, "parameter")
|
self.parameter_path = os.path.join(self.path, "parameter")
|
||||||
|
|
||||||
|
def object_from_name(self, object_name):
|
||||||
|
"""Convenience method for creating an object instance from an object name.
|
||||||
|
|
||||||
|
Mainly intended to create objects when resolving requirements.
|
||||||
|
|
||||||
|
e.g:
|
||||||
|
<CdistObject __foo/bar>.object_from_name('__other/object') -> <CdistObject __other/object>
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
base_path = self.base_path
|
||||||
|
type_path = self.cdist_type.base_path
|
||||||
|
|
||||||
|
type_name, object_id = self.split_name(object_name)
|
||||||
|
|
||||||
|
cdist_type = self.cdist_type.__class__(type_path, type_name)
|
||||||
|
|
||||||
|
return self.__class__(cdist_type, base_path, object_id=object_id)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<Object %s>' % self.name
|
return '<CdistObject %s>' % self.name
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
"""define equality as 'name is the same'"""
|
"""define equality as 'name is the same'"""
|
||||||
|
@ -128,23 +156,23 @@ class Object(object):
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash(self.name)
|
return hash(self.name)
|
||||||
|
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
return isinstance(other, self.__class__) and self.name < other.name
|
return isinstance(other, self.__class__) and self.name < other.name
|
||||||
|
|
||||||
def object_from_name(self, object_name):
|
def sanitise_object_id(self):
|
||||||
"""Convenience method for creating an object instance from an object name.
|
|
||||||
|
|
||||||
Mainly intended to create objects when resolving requirements.
|
|
||||||
|
|
||||||
e.g:
|
|
||||||
<Object __foo/bar>.object_from_name('__other/object') -> <Object __other/object>
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
type_path = self.type.base_path
|
Remove leading and trailing slash (one only)
|
||||||
base_path = self.base_path
|
"""
|
||||||
type_name, object_id = self.split_name(object_name)
|
|
||||||
return self.__class__(self.type.__class__(type_path, type_name), base_path, object_id=object_id)
|
# Allow empty object id for singletons
|
||||||
|
if self.object_id:
|
||||||
|
# Remove leading slash
|
||||||
|
if self.object_id[0] == '/':
|
||||||
|
self.object_id = self.object_id[1:]
|
||||||
|
|
||||||
|
# Remove trailing slash
|
||||||
|
if self.object_id[-1] == '/':
|
||||||
|
self.object_id = self.object_id[:-1]
|
||||||
|
|
||||||
# FIXME: still needed?
|
# FIXME: still needed?
|
||||||
@property
|
@property
|
|
@ -34,7 +34,7 @@ class NoSuchTypeError(cdist.Error):
|
||||||
return "Type '%s' does not exist at %s" % (self.type_path, self.type_absolute_path)
|
return "Type '%s' does not exist at %s" % (self.type_path, self.type_absolute_path)
|
||||||
|
|
||||||
|
|
||||||
class Type(object):
|
class CdistType(object):
|
||||||
"""Represents a cdist type.
|
"""Represents a cdist type.
|
||||||
|
|
||||||
All interaction with types in cdist should be done through this class.
|
All interaction with types in cdist should be done through this class.
|
||||||
|
@ -61,7 +61,7 @@ class Type(object):
|
||||||
# name is second argument
|
# name is second argument
|
||||||
name = args[1]
|
name = args[1]
|
||||||
if not name in cls._instances:
|
if not name in cls._instances:
|
||||||
instance = super(Type, cls).__new__(cls)
|
instance = super(CdistType, cls).__new__(cls)
|
||||||
cls._instances[name] = instance
|
cls._instances[name] = instance
|
||||||
# return instance so __init__ is called
|
# return instance so __init__ is called
|
||||||
return cls._instances[name]
|
return cls._instances[name]
|
||||||
|
@ -82,9 +82,10 @@ class Type(object):
|
||||||
self.__explorers = None
|
self.__explorers = None
|
||||||
self.__required_parameters = None
|
self.__required_parameters = None
|
||||||
self.__optional_parameters = None
|
self.__optional_parameters = None
|
||||||
|
self.__boolean_parameters = None
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<Type %s>' % self.name
|
return '<CdistType %s>' % self.name
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return isinstance(other, self.__class__) and self.name == other.name
|
return isinstance(other, self.__class__) and self.name == other.name
|
||||||
|
@ -144,3 +145,19 @@ class Type(object):
|
||||||
finally:
|
finally:
|
||||||
self.__optional_parameters = parameters
|
self.__optional_parameters = parameters
|
||||||
return self.__optional_parameters
|
return self.__optional_parameters
|
||||||
|
|
||||||
|
@property
|
||||||
|
def boolean_parameters(self):
|
||||||
|
"""Return a list of boolean parameters"""
|
||||||
|
if not self.__boolean_parameters:
|
||||||
|
parameters = []
|
||||||
|
try:
|
||||||
|
with open(os.path.join(self.absolute_path, "parameter", "boolean")) as fd:
|
||||||
|
for line in fd:
|
||||||
|
parameters.append(line.strip())
|
||||||
|
except EnvironmentError:
|
||||||
|
# error ignored
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
self.__boolean_parameters = parameters
|
||||||
|
return self.__boolean_parameters
|
|
@ -92,17 +92,14 @@ class Code(object):
|
||||||
'__global': self.local.out_path,
|
'__global': self.local.out_path,
|
||||||
}
|
}
|
||||||
|
|
||||||
if log.getEffectiveLevel() == logging.DEBUG:
|
|
||||||
self.env.update({'__debug': "yes" })
|
|
||||||
|
|
||||||
def _run_gencode(self, cdist_object, which):
|
def _run_gencode(self, cdist_object, which):
|
||||||
cdist_type = cdist_object.type
|
cdist_type = cdist_object.cdist_type
|
||||||
script = os.path.join(self.local.type_path, getattr(cdist_type, 'gencode_%s_path' % which))
|
script = os.path.join(self.local.type_path, getattr(cdist_type, 'gencode_%s_path' % which))
|
||||||
if os.path.isfile(script):
|
if os.path.isfile(script):
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env.update(self.env)
|
env.update(self.env)
|
||||||
env.update({
|
env.update({
|
||||||
'__type': cdist_object.type.absolute_path,
|
'__type': cdist_object.cdist_type.absolute_path,
|
||||||
'__object': cdist_object.absolute_path,
|
'__object': cdist_object.absolute_path,
|
||||||
'__object_id': cdist_object.object_id,
|
'__object_id': cdist_object.object_id,
|
||||||
'__object_name': cdist_object.name,
|
'__object_name': cdist_object.name,
|
||||||
|
|
|
@ -73,8 +73,6 @@ class Explorer(object):
|
||||||
'__target_host': self.target_host,
|
'__target_host': self.target_host,
|
||||||
'__explorer': self.remote.global_explorer_path,
|
'__explorer': self.remote.global_explorer_path,
|
||||||
}
|
}
|
||||||
if self.log.getEffectiveLevel() == logging.DEBUG:
|
|
||||||
self.env.update({'__debug': "yes" })
|
|
||||||
self._type_explorers_transferred = []
|
self._type_explorers_transferred = []
|
||||||
|
|
||||||
### global
|
### global
|
||||||
|
@ -121,15 +119,28 @@ class Explorer(object):
|
||||||
in the object.
|
in the object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.log.debug("Transfering type explorers for type: %s", cdist_object.type)
|
self.log.debug("Transfering type explorers for type: %s", cdist_object.cdist_type)
|
||||||
self.transfer_type_explorers(cdist_object.type)
|
self.transfer_type_explorers(cdist_object.cdist_type)
|
||||||
self.log.debug("Transfering object parameters for object: %s", cdist_object.name)
|
self.log.debug("Transfering object parameters for object: %s", cdist_object.name)
|
||||||
self.transfer_object_parameters(cdist_object)
|
self.transfer_object_parameters(cdist_object)
|
||||||
for explorer in self.list_type_explorer_names(cdist_object.type):
|
for explorer in self.list_type_explorer_names(cdist_object.cdist_type):
|
||||||
output = self.run_type_explorer(explorer, cdist_object)
|
output = self.run_type_explorer(explorer, cdist_object)
|
||||||
self.log.debug("Running type explorer '%s' for object '%s'", explorer, cdist_object.name)
|
self.log.debug("Running type explorer '%s' for object '%s'", explorer, cdist_object.name)
|
||||||
cdist_object.explorers[explorer] = output
|
cdist_object.explorers[explorer] = output
|
||||||
|
|
||||||
|
def run_type_explorer(self, explorer, cdist_object):
|
||||||
|
"""Run the given type explorer for the given object and return it's output."""
|
||||||
|
cdist_type = cdist_object.cdist_type
|
||||||
|
env = self.env.copy()
|
||||||
|
env.update({
|
||||||
|
'__object': os.path.join(self.remote.object_path, cdist_object.path),
|
||||||
|
'__object_id': cdist_object.object_id,
|
||||||
|
'__object_fq': cdist_object.path,
|
||||||
|
'__type_explorer': os.path.join(self.remote.type_path, cdist_type.explorer_path)
|
||||||
|
})
|
||||||
|
script = os.path.join(self.remote.type_path, cdist_type.explorer_path, explorer)
|
||||||
|
return self.remote.run_script(script, env=env, return_output=True)
|
||||||
|
|
||||||
def transfer_type_explorers(self, cdist_type):
|
def transfer_type_explorers(self, cdist_type):
|
||||||
"""Transfer the type explorers for the given type to the remote side."""
|
"""Transfer the type explorers for the given type to the remote side."""
|
||||||
if cdist_type.explorers:
|
if cdist_type.explorers:
|
||||||
|
@ -149,16 +160,3 @@ class Explorer(object):
|
||||||
destination = os.path.join(self.remote.object_path, cdist_object.parameter_path)
|
destination = os.path.join(self.remote.object_path, cdist_object.parameter_path)
|
||||||
self.remote.mkdir(destination)
|
self.remote.mkdir(destination)
|
||||||
self.remote.transfer(source, destination)
|
self.remote.transfer(source, destination)
|
||||||
|
|
||||||
def run_type_explorer(self, explorer, cdist_object):
|
|
||||||
"""Run the given type explorer for the given object and return it's output."""
|
|
||||||
cdist_type = cdist_object.type
|
|
||||||
env = self.env.copy()
|
|
||||||
env.update({
|
|
||||||
'__object': os.path.join(self.remote.object_path, cdist_object.path),
|
|
||||||
'__object_id': cdist_object.object_id,
|
|
||||||
'__object_fq': cdist_object.path,
|
|
||||||
'__type_explorer': os.path.join(self.remote.type_path, cdist_type.explorer_path)
|
|
||||||
})
|
|
||||||
script = os.path.join(self.remote.type_path, cdist_type.explorer_path, explorer)
|
|
||||||
return self.remote.run_script(script, env=env, return_output=True)
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ class Manifest(object):
|
||||||
self.local.run_script(script, env=env)
|
self.local.run_script(script, env=env)
|
||||||
|
|
||||||
def run_type_manifest(self, cdist_object):
|
def run_type_manifest(self, cdist_object):
|
||||||
script = os.path.join(self.local.type_path, cdist_object.type.manifest_path)
|
script = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path)
|
||||||
if os.path.isfile(script):
|
if os.path.isfile(script):
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env.update(self.env)
|
env.update(self.env)
|
||||||
|
@ -96,7 +96,7 @@ class Manifest(object):
|
||||||
'__object_id': cdist_object.object_id,
|
'__object_id': cdist_object.object_id,
|
||||||
'__object_name': cdist_object.name,
|
'__object_name': cdist_object.name,
|
||||||
'__self': cdist_object.name,
|
'__self': cdist_object.name,
|
||||||
'__type': cdist_object.type.absolute_path,
|
'__type': cdist_object.cdist_type.absolute_path,
|
||||||
'__cdist_manifest': script,
|
'__cdist_manifest': script,
|
||||||
})
|
})
|
||||||
self.local.run_script(script, env=env)
|
self.local.run_script(script, env=env)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# 2011 Nico Schottelius (nico-cdist at schottelius.org)
|
# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
|
||||||
#
|
#
|
||||||
# This file is part of cdist.
|
# This file is part of cdist.
|
||||||
#
|
#
|
||||||
|
@ -26,29 +26,22 @@ import os
|
||||||
import cdist
|
import cdist
|
||||||
from cdist import core
|
from cdist import core
|
||||||
|
|
||||||
|
|
||||||
class IllegalRequirementError(cdist.Error):
|
|
||||||
def __init__(self, requirement, message=None):
|
|
||||||
self.requirement = requirement
|
|
||||||
self.message = message or 'Illegal requirement'
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '%s: %s' % (self.message, self.requirement)
|
|
||||||
|
|
||||||
class Emulator(object):
|
class Emulator(object):
|
||||||
def __init__(self, argv):
|
def __init__(self, argv):
|
||||||
self.argv = argv
|
self.argv = argv
|
||||||
self.object_id = False
|
self.object_id = False
|
||||||
|
|
||||||
self.global_path = os.environ['__global']
|
self.global_path = os.environ['__global']
|
||||||
self.object_source = os.environ['__cdist_manifest']
|
|
||||||
self.target_host = os.environ['__target_host']
|
self.target_host = os.environ['__target_host']
|
||||||
|
|
||||||
|
# Internally only
|
||||||
|
self.object_source = os.environ['__cdist_manifest']
|
||||||
self.type_base_path = os.environ['__cdist_type_base_path']
|
self.type_base_path = os.environ['__cdist_type_base_path']
|
||||||
|
|
||||||
self.object_base_path = os.path.join(self.global_path, "object")
|
self.object_base_path = os.path.join(self.global_path, "object")
|
||||||
|
|
||||||
self.type_name = os.path.basename(argv[0])
|
self.type_name = os.path.basename(argv[0])
|
||||||
self.cdist_type = core.Type(self.type_base_path, self.type_name)
|
self.cdist_type = core.CdistType(self.type_base_path, self.type_name)
|
||||||
|
|
||||||
self.__init_log()
|
self.__init_log()
|
||||||
|
|
||||||
|
@ -94,7 +87,7 @@ class Emulator(object):
|
||||||
def commandline(self):
|
def commandline(self):
|
||||||
"""Parse command line"""
|
"""Parse command line"""
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(add_help=False)
|
parser = argparse.ArgumentParser(add_help=False, argument_default=argparse.SUPPRESS)
|
||||||
|
|
||||||
for parameter in self.cdist_type.optional_parameters:
|
for parameter in self.cdist_type.optional_parameters:
|
||||||
argument = "--" + parameter
|
argument = "--" + parameter
|
||||||
|
@ -102,6 +95,9 @@ class Emulator(object):
|
||||||
for parameter in self.cdist_type.required_parameters:
|
for parameter in self.cdist_type.required_parameters:
|
||||||
argument = "--" + parameter
|
argument = "--" + parameter
|
||||||
parser.add_argument(argument, dest=parameter, action='store', required=True)
|
parser.add_argument(argument, dest=parameter, action='store', required=True)
|
||||||
|
for parameter in self.cdist_type.boolean_parameters:
|
||||||
|
argument = "--" + parameter
|
||||||
|
parser.add_argument(argument, dest=parameter, action='store_const', const='')
|
||||||
|
|
||||||
# If not singleton support one positional parameter
|
# If not singleton support one positional parameter
|
||||||
if not self.cdist_type.is_singleton:
|
if not self.cdist_type.is_singleton:
|
||||||
|
@ -113,20 +109,15 @@ class Emulator(object):
|
||||||
|
|
||||||
|
|
||||||
def setup_object(self):
|
def setup_object(self):
|
||||||
# FIXME: verify object id
|
# Setup object_id - FIXME: unset / do not setup anymore!
|
||||||
|
|
||||||
# Setup object_id
|
|
||||||
if self.cdist_type.is_singleton:
|
if self.cdist_type.is_singleton:
|
||||||
self.object_id = "singleton"
|
self.object_id = "singleton"
|
||||||
else:
|
else:
|
||||||
self.object_id = self.args.object_id[0]
|
self.object_id = self.args.object_id[0]
|
||||||
del self.args.object_id
|
del self.args.object_id
|
||||||
|
|
||||||
# strip leading slash from object_id
|
|
||||||
self.object_id = self.object_id.lstrip('/')
|
|
||||||
|
|
||||||
# Instantiate the cdist object we are defining
|
# Instantiate the cdist object we are defining
|
||||||
self.cdist_object = core.Object(self.cdist_type, self.object_base_path, self.object_id)
|
self.cdist_object = core.CdistObject(self.cdist_type, self.object_base_path, self.object_id)
|
||||||
|
|
||||||
# Create object with given parameters
|
# Create object with given parameters
|
||||||
self.parameters = {}
|
self.parameters = {}
|
||||||
|
@ -137,12 +128,15 @@ class Emulator(object):
|
||||||
if self.cdist_object.exists:
|
if self.cdist_object.exists:
|
||||||
if self.cdist_object.parameters != self.parameters:
|
if self.cdist_object.parameters != self.parameters:
|
||||||
raise cdist.Error("Object %s already exists with conflicting parameters:\n%s: %s\n%s: %s"
|
raise cdist.Error("Object %s already exists with conflicting parameters:\n%s: %s\n%s: %s"
|
||||||
% (self.cdist_object, " ".join(self.cdist_object.source), self.cdist_object.parameters, self.object_source, self.parameters)
|
% (self.cdist_object.name, " ".join(self.cdist_object.source), self.cdist_object.parameters, self.object_source, self.parameters)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.cdist_object.create()
|
self.cdist_object.create()
|
||||||
self.cdist_object.parameters = self.parameters
|
self.cdist_object.parameters = self.parameters
|
||||||
|
|
||||||
|
# Record / Append source
|
||||||
|
self.cdist_object.source.append(self.object_source)
|
||||||
|
|
||||||
def record_requirements(self):
|
def record_requirements(self):
|
||||||
"""record requirements"""
|
"""record requirements"""
|
||||||
|
|
||||||
|
@ -151,25 +145,17 @@ class Emulator(object):
|
||||||
self.log.debug("reqs = " + requirements)
|
self.log.debug("reqs = " + requirements)
|
||||||
for requirement in requirements.split(" "):
|
for requirement in requirements.split(" "):
|
||||||
# Ignore empty fields - probably the only field anyway
|
# Ignore empty fields - probably the only field anyway
|
||||||
if len(requirement) == 0:
|
if len(requirement) == 0: continue
|
||||||
continue
|
|
||||||
|
|
||||||
requirement_type_name, requirement_object_id = core.Object.split_name(requirement)
|
# Raises an error, if object cannot be created
|
||||||
# Instantiate type which fails if type does not exist
|
cdist_object = self.cdist_object.object_from_name(requirement)
|
||||||
requirement_type = core.Type(self.type_base_path, requirement_type_name)
|
|
||||||
|
|
||||||
if requirement_object_id:
|
|
||||||
# Validate object_id if any
|
|
||||||
core.Object.validate_object_id(requirement_object_id)
|
|
||||||
elif not requirement_type.is_singleton:
|
|
||||||
# Only singeltons have no object_id
|
|
||||||
raise IllegalRequirementError(requirement, "Missing object_id and type is not a singleton.")
|
|
||||||
|
|
||||||
self.log.debug("Recording requirement: " + requirement)
|
self.log.debug("Recording requirement: " + requirement)
|
||||||
self.cdist_object.requirements.append(requirement)
|
|
||||||
|
|
||||||
# Record / Append source
|
# Save the sanitised version, not the user supplied one
|
||||||
self.cdist_object.source.append(self.object_source)
|
# (__file//bar => __file/bar)
|
||||||
|
# This ensures pattern matching is done against sanitised list
|
||||||
|
self.cdist_object.requirements.append(cdist_object.name)
|
||||||
|
|
||||||
def record_auto_requirements(self):
|
def record_auto_requirements(self):
|
||||||
"""An object shall automatically depend on all objects that it defined in it's type manifest.
|
"""An object shall automatically depend on all objects that it defined in it's type manifest.
|
||||||
|
|
|
@ -32,18 +32,6 @@ import logging
|
||||||
import cdist
|
import cdist
|
||||||
from cdist import core
|
from cdist import core
|
||||||
|
|
||||||
|
|
||||||
class LocalScriptError(cdist.Error):
|
|
||||||
def __init__(self, script, command, script_content):
|
|
||||||
self.script = script
|
|
||||||
self.command = command
|
|
||||||
self.script_content = script_content
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
plain_command = " ".join(self.command)
|
|
||||||
return "Local script execution failed: %s" % plain_command
|
|
||||||
|
|
||||||
|
|
||||||
class Local(object):
|
class Local(object):
|
||||||
"""Execute commands locally.
|
"""Execute commands locally.
|
||||||
|
|
||||||
|
@ -119,35 +107,16 @@ class Local(object):
|
||||||
command = ["/bin/sh", "-e"]
|
command = ["/bin/sh", "-e"]
|
||||||
command.append(script)
|
command.append(script)
|
||||||
|
|
||||||
self.log.debug("Local run script: %s", command)
|
return self.run(command, env, return_output)
|
||||||
|
|
||||||
if env is None:
|
|
||||||
env = os.environ.copy()
|
|
||||||
# Export __target_host for use in __remote_{copy,exec} scripts
|
|
||||||
env['__target_host'] = self.target_host
|
|
||||||
|
|
||||||
self.log.debug("Local run script env: %s", env)
|
|
||||||
|
|
||||||
try:
|
|
||||||
if return_output:
|
|
||||||
return subprocess.check_output(command, env=env).decode()
|
|
||||||
else:
|
|
||||||
subprocess.check_call(command, env=env)
|
|
||||||
except subprocess.CalledProcessError as error:
|
|
||||||
script_content = self.run(["cat", script], return_output=True)
|
|
||||||
self.log.error("Code that raised the error:\n%s", script_content)
|
|
||||||
raise LocalScriptError(script, command, script_content)
|
|
||||||
except EnvironmentError as error:
|
|
||||||
raise cdist.Error(" ".join(command) + ": " + error.args[1])
|
|
||||||
|
|
||||||
def link_emulator(self, exec_path):
|
def link_emulator(self, exec_path):
|
||||||
"""Link emulator to types"""
|
"""Link emulator to types"""
|
||||||
src = os.path.abspath(exec_path)
|
src = os.path.abspath(exec_path)
|
||||||
for cdist_type in core.Type.list_types(self.type_path):
|
for cdist_type in core.CdistType.list_types(self.type_path):
|
||||||
dst = os.path.join(self.bin_path, cdist_type.name)
|
dst = os.path.join(self.bin_path, cdist_type.name)
|
||||||
self.log.debug("Linking emulator: %s to %s", src, dst)
|
self.log.debug("Linking emulator: %s to %s", src, dst)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.symlink(src, dst)
|
os.symlink(src, dst)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise cdist.Error("Linking emulator from " + src + " to " + dst + " failed: " + e.__str__())
|
raise cdist.Error("Linking emulator from %s to %s failed: %s" % (src, dst, e.__str__()))
|
||||||
|
|
|
@ -20,8 +20,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
# FIXME: common base class with Local?
|
|
||||||
|
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -30,17 +28,6 @@ import logging
|
||||||
|
|
||||||
import cdist
|
import cdist
|
||||||
|
|
||||||
|
|
||||||
class RemoteScriptError(cdist.Error):
|
|
||||||
def __init__(self, script, command, script_content):
|
|
||||||
self.script = script
|
|
||||||
self.command = command
|
|
||||||
self.script_content = script_content
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
plain_command = " ".join(self.command)
|
|
||||||
return "Remote script execution failed: %s" % plain_command
|
|
||||||
|
|
||||||
class DecodeError(cdist.Error):
|
class DecodeError(cdist.Error):
|
||||||
def __init__(self, command):
|
def __init__(self, command):
|
||||||
self.command = command
|
self.command = command
|
||||||
|
@ -93,6 +80,17 @@ class Remote(object):
|
||||||
command.extend(["-r", source, self.target_host + ":" + destination])
|
command.extend(["-r", source, self.target_host + ":" + destination])
|
||||||
self._run_command(command)
|
self._run_command(command)
|
||||||
|
|
||||||
|
def run_script(self, script, env=None, return_output=False):
|
||||||
|
"""Run the given script with the given environment on the remote side.
|
||||||
|
Return the output as a string.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
command = ["/bin/sh", "-e"]
|
||||||
|
command.append(script)
|
||||||
|
|
||||||
|
return self.run(command, env, return_output)
|
||||||
|
|
||||||
def run(self, command, env=None, return_output=False):
|
def run(self, command, env=None, return_output=False):
|
||||||
"""Run the given command with the given environment on the remote side.
|
"""Run the given command with the given environment on the remote side.
|
||||||
Return the output as a string.
|
Return the output as a string.
|
||||||
|
@ -101,7 +99,15 @@ class Remote(object):
|
||||||
# prefix given command with remote_exec
|
# prefix given command with remote_exec
|
||||||
cmd = self._exec.split()
|
cmd = self._exec.split()
|
||||||
cmd.append(self.target_host)
|
cmd.append(self.target_host)
|
||||||
|
|
||||||
|
# can't pass environment to remote side, so prepend command with
|
||||||
|
# variable declarations
|
||||||
|
if env:
|
||||||
|
remote_env = ["%s=%s" % item for item in env.items()]
|
||||||
|
cmd.extend(remote_env)
|
||||||
|
|
||||||
cmd.extend(command)
|
cmd.extend(command)
|
||||||
|
|
||||||
return self._run_command(cmd, env=env, return_output=return_output)
|
return self._run_command(cmd, env=env, return_output=return_output)
|
||||||
|
|
||||||
def _run_command(self, command, env=None, return_output=False):
|
def _run_command(self, command, env=None, return_output=False):
|
||||||
|
@ -115,14 +121,6 @@ class Remote(object):
|
||||||
os_environ = os.environ.copy()
|
os_environ = os.environ.copy()
|
||||||
os_environ['__target_host'] = self.target_host
|
os_environ['__target_host'] = self.target_host
|
||||||
|
|
||||||
# can't pass environment to remote side, so prepend command with
|
|
||||||
# variable declarations
|
|
||||||
if env:
|
|
||||||
cmd = ["%s=%s" % item for item in env.items()]
|
|
||||||
cmd.extend(command)
|
|
||||||
else:
|
|
||||||
cmd = command
|
|
||||||
|
|
||||||
self.log.debug("Remote run: %s", command)
|
self.log.debug("Remote run: %s", command)
|
||||||
try:
|
try:
|
||||||
if return_output:
|
if return_output:
|
||||||
|
@ -135,39 +133,3 @@ class Remote(object):
|
||||||
raise cdist.Error(" ".join(*args) + ": " + error.args[1])
|
raise cdist.Error(" ".join(*args) + ": " + error.args[1])
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
raise DecodeError(command)
|
raise DecodeError(command)
|
||||||
|
|
||||||
def run_script(self, script, env=None, return_output=False):
|
|
||||||
"""Run the given script with the given environment on the remote side.
|
|
||||||
Return the output as a string.
|
|
||||||
|
|
||||||
"""
|
|
||||||
command = self._exec.split()
|
|
||||||
command.append(self.target_host)
|
|
||||||
|
|
||||||
# export target_host for use in __remote_{exec,copy} scripts
|
|
||||||
os_environ = os.environ.copy()
|
|
||||||
os_environ['__target_host'] = self.target_host
|
|
||||||
|
|
||||||
# can't pass environment to remote side, so prepend command with
|
|
||||||
# variable declarations
|
|
||||||
if env:
|
|
||||||
command.extend(["%s=%s" % item for item in env.items()])
|
|
||||||
|
|
||||||
command.extend(["/bin/sh", "-e"])
|
|
||||||
command.append(script)
|
|
||||||
|
|
||||||
self.log.debug("Remote run script: %s", command)
|
|
||||||
if env:
|
|
||||||
self.log.debug("Remote run script env: %s", env)
|
|
||||||
|
|
||||||
try:
|
|
||||||
if return_output:
|
|
||||||
return subprocess.check_output(command, env=os_environ).decode()
|
|
||||||
else:
|
|
||||||
subprocess.check_call(command, env=os_environ)
|
|
||||||
except subprocess.CalledProcessError as error:
|
|
||||||
script_content = self.run(["cat", script], return_output=True)
|
|
||||||
self.log.error("Code that raised the error:\n%s", script_content)
|
|
||||||
raise RemoteScriptError(script, command, script_content)
|
|
||||||
except EnvironmentError as error:
|
|
||||||
raise cdist.Error(" ".join(command) + ": " + error.args[1])
|
|
||||||
|
|
|
@ -125,7 +125,7 @@ class DependencyResolver(object):
|
||||||
resolved.append(cdist_object)
|
resolved.append(cdist_object)
|
||||||
unresolved.remove(cdist_object)
|
unresolved.remove(cdist_object)
|
||||||
except RequirementNotFoundError as e:
|
except RequirementNotFoundError as e:
|
||||||
raise cdist.Error(cdist_object.name + " requires non-existing " + e.requirement)
|
raise cdist.CdistObjectError(cdist_object, "requires non-existing " + e.requirement)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"""Iterate over all unique objects while resolving dependencies.
|
"""Iterate over all unique objects while resolving dependencies.
|
||||||
|
|
|
@ -54,8 +54,8 @@ class CodeTestCase(test.CdistTestCase):
|
||||||
|
|
||||||
self.code = code.Code(self.target_host, self.local, self.remote)
|
self.code = code.Code(self.target_host, self.local, self.remote)
|
||||||
|
|
||||||
self.cdist_type = core.Type(self.local.type_path, '__dump_environment')
|
self.cdist_type = core.CdistType(self.local.type_path, '__dump_environment')
|
||||||
self.cdist_object = core.Object(self.cdist_type, self.local.object_path, 'whatever')
|
self.cdist_object = core.CdistObject(self.cdist_type, self.local.object_path, 'whatever')
|
||||||
self.cdist_object.create()
|
self.cdist_object.create()
|
||||||
|
|
||||||
self.log = logging.getLogger("cdist")
|
self.log = logging.getLogger("cdist")
|
||||||
|
|
|
@ -79,7 +79,7 @@ class EmulatorTestCase(test.CdistTestCase):
|
||||||
os.environ.update(self.env)
|
os.environ.update(self.env)
|
||||||
os.environ['require'] = '__file'
|
os.environ['require'] = '__file'
|
||||||
emu = emulator.Emulator(argv)
|
emu = emulator.Emulator(argv)
|
||||||
self.assertRaises(emulator.IllegalRequirementError, emu.run)
|
self.assertRaises(core.IllegalObjectIdError, emu.run)
|
||||||
|
|
||||||
def test_singleton_object_requirement(self):
|
def test_singleton_object_requirement(self):
|
||||||
argv = ['__file', '/tmp/foobar']
|
argv = ['__file', '/tmp/foobar']
|
||||||
|
@ -119,14 +119,14 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase):
|
||||||
def test_autorequire(self):
|
def test_autorequire(self):
|
||||||
initial_manifest = os.path.join(self.local.manifest_path, "init")
|
initial_manifest = os.path.join(self.local.manifest_path, "init")
|
||||||
self.manifest.run_initial_manifest(initial_manifest)
|
self.manifest.run_initial_manifest(initial_manifest)
|
||||||
cdist_type = core.Type(self.local.type_path, '__saturn')
|
cdist_type = core.CdistType(self.local.type_path, '__saturn')
|
||||||
cdist_object = core.Object(cdist_type, self.local.object_path, 'singleton')
|
cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'singleton')
|
||||||
self.manifest.run_type_manifest(cdist_object)
|
self.manifest.run_type_manifest(cdist_object)
|
||||||
expected = ['__planet/Saturn', '__moon/Prometheus']
|
expected = ['__planet/Saturn', '__moon/Prometheus']
|
||||||
self.assertEqual(sorted(cdist_object.requirements), sorted(expected))
|
self.assertEqual(sorted(cdist_object.requirements), sorted(expected))
|
||||||
|
|
||||||
|
|
||||||
class ArgumentsWithDashesTestCase(test.CdistTestCase):
|
class ArgumentsTestCase(test.CdistTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.temp_dir = self.mkdtemp()
|
self.temp_dir = self.mkdtemp()
|
||||||
|
@ -156,6 +156,62 @@ class ArgumentsWithDashesTestCase(test.CdistTestCase):
|
||||||
emu = emulator.Emulator(argv)
|
emu = emulator.Emulator(argv)
|
||||||
emu.run()
|
emu.run()
|
||||||
|
|
||||||
cdist_type = core.Type(self.local.type_path, '__arguments_with_dashes')
|
cdist_type = core.CdistType(self.local.type_path, '__arguments_with_dashes')
|
||||||
cdist_object = core.Object(cdist_type, self.local.object_path, 'some-id')
|
cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'some-id')
|
||||||
self.assertTrue('with-dash' in cdist_object.parameters)
|
self.assertTrue('with-dash' in cdist_object.parameters)
|
||||||
|
|
||||||
|
def test_boolean(self):
|
||||||
|
type_name = '__arguments_boolean'
|
||||||
|
object_id = 'some-id'
|
||||||
|
argv = [type_name, object_id, '--boolean1']
|
||||||
|
os.environ.update(self.env)
|
||||||
|
emu = emulator.Emulator(argv)
|
||||||
|
emu.run()
|
||||||
|
|
||||||
|
cdist_type = core.CdistType(self.local.type_path, type_name)
|
||||||
|
cdist_object = core.CdistObject(cdist_type, self.local.object_path, object_id)
|
||||||
|
self.assertTrue('boolean1' in cdist_object.parameters)
|
||||||
|
self.assertFalse('boolean2' in cdist_object.parameters)
|
||||||
|
# empty file -> True
|
||||||
|
self.assertTrue(cdist_object.parameters['boolean1'] == '')
|
||||||
|
|
||||||
|
def test_required(self):
|
||||||
|
type_name = '__arguments_required'
|
||||||
|
object_id = 'some-id'
|
||||||
|
value = 'some value'
|
||||||
|
argv = [type_name, object_id, '--required1', value, '--required2', value]
|
||||||
|
os.environ.update(self.env)
|
||||||
|
emu = emulator.Emulator(argv)
|
||||||
|
emu.run()
|
||||||
|
|
||||||
|
cdist_type = core.CdistType(self.local.type_path, type_name)
|
||||||
|
cdist_object = core.CdistObject(cdist_type, self.local.object_path, object_id)
|
||||||
|
self.assertTrue('required1' in cdist_object.parameters)
|
||||||
|
self.assertTrue('required2' in cdist_object.parameters)
|
||||||
|
self.assertEqual(cdist_object.parameters['required1'], value)
|
||||||
|
self.assertEqual(cdist_object.parameters['required2'], value)
|
||||||
|
|
||||||
|
# def test_required_missing(self):
|
||||||
|
# type_name = '__arguments_required'
|
||||||
|
# object_id = 'some-id'
|
||||||
|
# value = 'some value'
|
||||||
|
# argv = [type_name, object_id, '--required1', value]
|
||||||
|
# os.environ.update(self.env)
|
||||||
|
# emu = emulator.Emulator(argv)
|
||||||
|
#
|
||||||
|
# self.assertRaises(SystemExit, emu.run)
|
||||||
|
|
||||||
|
def test_optional(self):
|
||||||
|
type_name = '__arguments_optional'
|
||||||
|
object_id = 'some-id'
|
||||||
|
value = 'some value'
|
||||||
|
argv = [type_name, object_id, '--optional1', value]
|
||||||
|
os.environ.update(self.env)
|
||||||
|
emu = emulator.Emulator(argv)
|
||||||
|
emu.run()
|
||||||
|
|
||||||
|
cdist_type = core.CdistType(self.local.type_path, type_name)
|
||||||
|
cdist_object = core.CdistObject(cdist_type, self.local.object_path, object_id)
|
||||||
|
self.assertTrue('optional1' in cdist_object.parameters)
|
||||||
|
self.assertFalse('optional2' in cdist_object.parameters)
|
||||||
|
self.assertEqual(cdist_object.parameters['optional1'], value)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
boolean1
|
||||||
|
boolean2
|
|
@ -0,0 +1 @@
|
||||||
|
optional1
|
|
@ -0,0 +1,2 @@
|
||||||
|
required1
|
||||||
|
required2
|
|
@ -83,19 +83,19 @@ class ExplorerClassTestCase(test.CdistTestCase):
|
||||||
shutil.rmtree(out_path)
|
shutil.rmtree(out_path)
|
||||||
|
|
||||||
def test_list_type_explorer_names(self):
|
def test_list_type_explorer_names(self):
|
||||||
cdist_type = core.Type(self.local.type_path, '__test_type')
|
cdist_type = core.CdistType(self.local.type_path, '__test_type')
|
||||||
expected = cdist_type.explorers
|
expected = cdist_type.explorers
|
||||||
self.assertEqual(self.explorer.list_type_explorer_names(cdist_type), expected)
|
self.assertEqual(self.explorer.list_type_explorer_names(cdist_type), expected)
|
||||||
|
|
||||||
def test_transfer_type_explorers(self):
|
def test_transfer_type_explorers(self):
|
||||||
cdist_type = core.Type(self.local.type_path, '__test_type')
|
cdist_type = core.CdistType(self.local.type_path, '__test_type')
|
||||||
self.explorer.transfer_type_explorers(cdist_type)
|
self.explorer.transfer_type_explorers(cdist_type)
|
||||||
source = os.path.join(self.local.type_path, cdist_type.explorer_path)
|
source = os.path.join(self.local.type_path, cdist_type.explorer_path)
|
||||||
destination = os.path.join(self.remote.type_path, cdist_type.explorer_path)
|
destination = os.path.join(self.remote.type_path, cdist_type.explorer_path)
|
||||||
self.assertEqual(os.listdir(source), os.listdir(destination))
|
self.assertEqual(os.listdir(source), os.listdir(destination))
|
||||||
|
|
||||||
def test_transfer_type_explorers_only_once(self):
|
def test_transfer_type_explorers_only_once(self):
|
||||||
cdist_type = core.Type(self.local.type_path, '__test_type')
|
cdist_type = core.CdistType(self.local.type_path, '__test_type')
|
||||||
# first transfer
|
# first transfer
|
||||||
self.explorer.transfer_type_explorers(cdist_type)
|
self.explorer.transfer_type_explorers(cdist_type)
|
||||||
source = os.path.join(self.local.type_path, cdist_type.explorer_path)
|
source = os.path.join(self.local.type_path, cdist_type.explorer_path)
|
||||||
|
@ -109,8 +109,8 @@ class ExplorerClassTestCase(test.CdistTestCase):
|
||||||
self.assertFalse(os.listdir(destination))
|
self.assertFalse(os.listdir(destination))
|
||||||
|
|
||||||
def test_transfer_object_parameters(self):
|
def test_transfer_object_parameters(self):
|
||||||
cdist_type = core.Type(self.local.type_path, '__test_type')
|
cdist_type = core.CdistType(self.local.type_path, '__test_type')
|
||||||
cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever')
|
cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever')
|
||||||
cdist_object.create()
|
cdist_object.create()
|
||||||
cdist_object.parameters = {'first': 'first value', 'second': 'second value'}
|
cdist_object.parameters = {'first': 'first value', 'second': 'second value'}
|
||||||
self.explorer.transfer_object_parameters(cdist_object)
|
self.explorer.transfer_object_parameters(cdist_object)
|
||||||
|
@ -119,15 +119,15 @@ class ExplorerClassTestCase(test.CdistTestCase):
|
||||||
self.assertEqual(sorted(os.listdir(source)), sorted(os.listdir(destination)))
|
self.assertEqual(sorted(os.listdir(source)), sorted(os.listdir(destination)))
|
||||||
|
|
||||||
def test_run_type_explorer(self):
|
def test_run_type_explorer(self):
|
||||||
cdist_type = core.Type(self.local.type_path, '__test_type')
|
cdist_type = core.CdistType(self.local.type_path, '__test_type')
|
||||||
cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever')
|
cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever')
|
||||||
self.explorer.transfer_type_explorers(cdist_type)
|
self.explorer.transfer_type_explorers(cdist_type)
|
||||||
output = self.explorer.run_type_explorer('world', cdist_object)
|
output = self.explorer.run_type_explorer('world', cdist_object)
|
||||||
self.assertEqual(output, 'hello\n')
|
self.assertEqual(output, 'hello\n')
|
||||||
|
|
||||||
def test_run_type_explorers(self):
|
def test_run_type_explorers(self):
|
||||||
cdist_type = core.Type(self.local.type_path, '__test_type')
|
cdist_type = core.CdistType(self.local.type_path, '__test_type')
|
||||||
cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever')
|
cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever')
|
||||||
cdist_object.create()
|
cdist_object.create()
|
||||||
self.explorer.run_type_explorers(cdist_object)
|
self.explorer.run_type_explorers(cdist_object)
|
||||||
self.assertEqual(cdist_object.explorers, {'world': 'hello'})
|
self.assertEqual(cdist_object.explorers, {'world': 'hello'})
|
||||||
|
|
|
@ -79,8 +79,8 @@ class ManifestTestCase(test.CdistTestCase):
|
||||||
self.assertEqual(output_dict['__manifest'], self.local.manifest_path)
|
self.assertEqual(output_dict['__manifest'], self.local.manifest_path)
|
||||||
|
|
||||||
def test_type_manifest_environment(self):
|
def test_type_manifest_environment(self):
|
||||||
cdist_type = core.Type(self.local.type_path, '__dump_environment')
|
cdist_type = core.CdistType(self.local.type_path, '__dump_environment')
|
||||||
cdist_object = core.Object(cdist_type, self.local.object_path, 'whatever')
|
cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever')
|
||||||
handle, output_file = self.mkstemp(dir=self.temp_dir)
|
handle, output_file = self.mkstemp(dir=self.temp_dir)
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
os.environ['__cdist_test_out'] = output_file
|
os.environ['__cdist_test_out'] = output_file
|
||||||
|
|
|
@ -25,6 +25,8 @@ import shutil
|
||||||
from cdist import test
|
from cdist import test
|
||||||
from cdist import core
|
from cdist import core
|
||||||
|
|
||||||
|
import cdist
|
||||||
|
|
||||||
import os.path as op
|
import os.path as op
|
||||||
my_dir = op.abspath(op.dirname(__file__))
|
my_dir = op.abspath(op.dirname(__file__))
|
||||||
fixtures = op.join(my_dir, 'fixtures')
|
fixtures = op.join(my_dir, 'fixtures')
|
||||||
|
@ -34,48 +36,48 @@ type_base_path = op.join(fixtures, 'type')
|
||||||
class ObjectClassTestCase(test.CdistTestCase):
|
class ObjectClassTestCase(test.CdistTestCase):
|
||||||
|
|
||||||
def test_list_object_names(self):
|
def test_list_object_names(self):
|
||||||
object_names = list(core.Object.list_object_names(object_base_path))
|
object_names = list(core.CdistObject.list_object_names(object_base_path))
|
||||||
self.assertEqual(object_names, ['__first/man', '__second/on-the', '__third/moon'])
|
self.assertEqual(object_names, ['__first/man', '__second/on-the', '__third/moon'])
|
||||||
|
|
||||||
def test_list_type_names(self):
|
def test_list_type_names(self):
|
||||||
type_names = list(core.Object.list_type_names(object_base_path))
|
type_names = list(cdist.core.CdistObject.list_type_names(object_base_path))
|
||||||
self.assertEqual(type_names, ['__first', '__second', '__third'])
|
self.assertEqual(type_names, ['__first', '__second', '__third'])
|
||||||
|
|
||||||
def test_list_objects(self):
|
def test_list_objects(self):
|
||||||
objects = list(core.Object.list_objects(object_base_path, type_base_path))
|
objects = list(core.CdistObject.list_objects(object_base_path, type_base_path))
|
||||||
objects_expected = [
|
objects_expected = [
|
||||||
core.Object(core.Type(type_base_path, '__first'), object_base_path, 'man'),
|
core.CdistObject(core.CdistType(type_base_path, '__first'), object_base_path, 'man'),
|
||||||
core.Object(core.Type(type_base_path, '__second'), object_base_path, 'on-the'),
|
core.CdistObject(core.CdistType(type_base_path, '__second'), object_base_path, 'on-the'),
|
||||||
core.Object(core.Type(type_base_path, '__third'), object_base_path, 'moon'),
|
core.CdistObject(core.CdistType(type_base_path, '__third'), object_base_path, 'moon'),
|
||||||
]
|
]
|
||||||
self.assertEqual(objects, objects_expected)
|
self.assertEqual(objects, objects_expected)
|
||||||
|
|
||||||
|
|
||||||
class ObjectIdTestCase(test.CdistTestCase):
|
class ObjectIdTestCase(test.CdistTestCase):
|
||||||
def test_object_id_starts_with_slash(self):
|
def test_object_id_contains_double_slash(self):
|
||||||
cdist_type = core.Type(type_base_path, '__third')
|
cdist_type = core.CdistType(type_base_path, '__third')
|
||||||
illegal_object_id = '/object_id/may/not/start/with/slash'
|
illegal_object_id = '/object_id//may/not/contain/double/slash'
|
||||||
with self.assertRaises(core.IllegalObjectIdError):
|
with self.assertRaises(core.IllegalObjectIdError):
|
||||||
core.Object(cdist_type, object_base_path, illegal_object_id)
|
core.CdistObject(cdist_type, object_base_path, illegal_object_id)
|
||||||
|
|
||||||
def test_object_id_contains_object_marker(self):
|
def test_object_id_contains_object_marker(self):
|
||||||
cdist_type = core.Type(type_base_path, '__third')
|
cdist_type = core.CdistType(type_base_path, '__third')
|
||||||
illegal_object_id = 'object_id/may/not/contain/%s/anywhere' % core.OBJECT_MARKER
|
illegal_object_id = 'object_id/may/not/contain/%s/anywhere' % core.OBJECT_MARKER
|
||||||
with self.assertRaises(core.IllegalObjectIdError):
|
with self.assertRaises(core.IllegalObjectIdError):
|
||||||
core.Object(cdist_type, object_base_path, illegal_object_id)
|
core.CdistObject(cdist_type, object_base_path, illegal_object_id)
|
||||||
|
|
||||||
def test_object_id_contains_object_marker_string(self):
|
def test_object_id_contains_object_marker_string(self):
|
||||||
cdist_type = core.Type(type_base_path, '__third')
|
cdist_type = core.CdistType(type_base_path, '__third')
|
||||||
illegal_object_id = 'object_id/may/contain_%s_in_filename' % core.OBJECT_MARKER
|
illegal_object_id = 'object_id/may/contain_%s_in_filename' % core.OBJECT_MARKER
|
||||||
core.Object(cdist_type, object_base_path, illegal_object_id)
|
core.CdistObject(cdist_type, object_base_path, illegal_object_id)
|
||||||
# if we get here, the test passed
|
# if we get here, the test passed
|
||||||
|
|
||||||
|
|
||||||
class ObjectTestCase(test.CdistTestCase):
|
class ObjectTestCase(test.CdistTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.cdist_type = core.Type(type_base_path, '__third')
|
self.cdist_type = core.CdistType(type_base_path, '__third')
|
||||||
self.cdist_object = core.Object(self.cdist_type, object_base_path, 'moon')
|
self.cdist_object = core.CdistObject(self.cdist_type, object_base_path, 'moon')
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.cdist_object.changed = False
|
self.cdist_object.changed = False
|
||||||
|
@ -159,16 +161,16 @@ class ObjectTestCase(test.CdistTestCase):
|
||||||
self.assertEqual(self.cdist_object.state, '')
|
self.assertEqual(self.cdist_object.state, '')
|
||||||
|
|
||||||
def test_state_prepared(self):
|
def test_state_prepared(self):
|
||||||
self.cdist_object.state = core.Object.STATE_PREPARED
|
self.cdist_object.state = core.CdistObject.STATE_PREPARED
|
||||||
self.assertEqual(self.cdist_object.state, core.Object.STATE_PREPARED)
|
self.assertEqual(self.cdist_object.state, core.CdistObject.STATE_PREPARED)
|
||||||
|
|
||||||
def test_state_running(self):
|
def test_state_running(self):
|
||||||
self.cdist_object.state = core.Object.STATE_RUNNING
|
self.cdist_object.state = core.CdistObject.STATE_RUNNING
|
||||||
self.assertEqual(self.cdist_object.state, core.Object.STATE_RUNNING)
|
self.assertEqual(self.cdist_object.state, core.CdistObject.STATE_RUNNING)
|
||||||
|
|
||||||
def test_state_done(self):
|
def test_state_done(self):
|
||||||
self.cdist_object.state = core.Object.STATE_DONE
|
self.cdist_object.state = core.CdistObject.STATE_DONE
|
||||||
self.assertEqual(self.cdist_object.state, core.Object.STATE_DONE)
|
self.assertEqual(self.cdist_object.state, core.CdistObject.STATE_DONE)
|
||||||
|
|
||||||
def test_source(self):
|
def test_source(self):
|
||||||
self.assertEqual(list(self.cdist_object.source), [])
|
self.assertEqual(list(self.cdist_object.source), [])
|
||||||
|
@ -195,6 +197,6 @@ class ObjectTestCase(test.CdistTestCase):
|
||||||
self.cdist_object.code_remote = 'Hello World'
|
self.cdist_object.code_remote = 'Hello World'
|
||||||
other_name = '__first/man'
|
other_name = '__first/man'
|
||||||
other_object = self.cdist_object.object_from_name(other_name)
|
other_object = self.cdist_object.object_from_name(other_name)
|
||||||
self.assertTrue(isinstance(other_object, core.Object))
|
self.assertTrue(isinstance(other_object, core.CdistObject))
|
||||||
self.assertEqual(other_object.type.name, '__first')
|
self.assertEqual(other_object.cdist_type.name, '__first')
|
||||||
self.assertEqual(other_object.object_id, 'man')
|
self.assertEqual(other_object.object_id, 'man')
|
||||||
|
|
|
@ -37,7 +37,7 @@ type_base_path = op.join(fixtures, 'type')
|
||||||
class ResolverTestCase(test.CdistTestCase):
|
class ResolverTestCase(test.CdistTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.objects = list(core.Object.list_objects(object_base_path, type_base_path))
|
self.objects = list(core.CdistObject.list_objects(object_base_path, type_base_path))
|
||||||
self.object_index = dict((o.name, o) for o in self.objects)
|
self.object_index = dict((o.name, o) for o in self.objects)
|
||||||
self.dependency_resolver = resolver.DependencyResolver(self.objects)
|
self.dependency_resolver = resolver.DependencyResolver(self.objects)
|
||||||
|
|
||||||
|
|
|
@ -33,115 +33,126 @@ class TypeTestCase(test.CdistTestCase):
|
||||||
|
|
||||||
def test_list_type_names(self):
|
def test_list_type_names(self):
|
||||||
base_path = op.join(fixtures, 'list_types')
|
base_path = op.join(fixtures, 'list_types')
|
||||||
type_names = core.Type.list_type_names(base_path)
|
type_names = core.CdistType.list_type_names(base_path)
|
||||||
self.assertEqual(type_names, ['__first', '__second', '__third'])
|
self.assertEqual(type_names, ['__first', '__second', '__third'])
|
||||||
|
|
||||||
def test_list_types(self):
|
def test_list_types(self):
|
||||||
base_path = op.join(fixtures, 'list_types')
|
base_path = op.join(fixtures, 'list_types')
|
||||||
types = list(core.Type.list_types(base_path))
|
types = list(core.CdistType.list_types(base_path))
|
||||||
types_expected = [
|
types_expected = [
|
||||||
core.Type(base_path, '__first'),
|
core.CdistType(base_path, '__first'),
|
||||||
core.Type(base_path, '__second'),
|
core.CdistType(base_path, '__second'),
|
||||||
core.Type(base_path, '__third'),
|
core.CdistType(base_path, '__third'),
|
||||||
]
|
]
|
||||||
self.assertEqual(types, types_expected)
|
self.assertEqual(types, types_expected)
|
||||||
|
|
||||||
def test_only_one_instance(self):
|
def test_only_one_instance(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type1 = core.Type(base_path, '__name_path')
|
cdist_type1 = core.CdistType(base_path, '__name_path')
|
||||||
cdist_type2 = core.Type(base_path, '__name_path')
|
cdist_type2 = core.CdistType(base_path, '__name_path')
|
||||||
self.assertEqual(id(cdist_type1), id(cdist_type2))
|
self.assertEqual(id(cdist_type1), id(cdist_type2))
|
||||||
|
|
||||||
def test_nonexistent_type(self):
|
def test_nonexistent_type(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
self.assertRaises(core.NoSuchTypeError, core.Type, base_path, '__i-dont-exist')
|
self.assertRaises(core.NoSuchTypeError, core.CdistType, base_path, '__i-dont-exist')
|
||||||
|
|
||||||
def test_name(self):
|
def test_name(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__name_path')
|
cdist_type = core.CdistType(base_path, '__name_path')
|
||||||
self.assertEqual(cdist_type.name, '__name_path')
|
self.assertEqual(cdist_type.name, '__name_path')
|
||||||
|
|
||||||
def test_path(self):
|
def test_path(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__name_path')
|
cdist_type = core.CdistType(base_path, '__name_path')
|
||||||
self.assertEqual(cdist_type.path, '__name_path')
|
self.assertEqual(cdist_type.path, '__name_path')
|
||||||
|
|
||||||
def test_base_path(self):
|
def test_base_path(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__name_path')
|
cdist_type = core.CdistType(base_path, '__name_path')
|
||||||
self.assertEqual(cdist_type.base_path, base_path)
|
self.assertEqual(cdist_type.base_path, base_path)
|
||||||
|
|
||||||
def test_absolute_path(self):
|
def test_absolute_path(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__name_path')
|
cdist_type = core.CdistType(base_path, '__name_path')
|
||||||
self.assertEqual(cdist_type.absolute_path, os.path.join(base_path, '__name_path'))
|
self.assertEqual(cdist_type.absolute_path, os.path.join(base_path, '__name_path'))
|
||||||
|
|
||||||
def test_manifest_path(self):
|
def test_manifest_path(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__name_path')
|
cdist_type = core.CdistType(base_path, '__name_path')
|
||||||
self.assertEqual(cdist_type.manifest_path, os.path.join('__name_path', 'manifest'))
|
self.assertEqual(cdist_type.manifest_path, os.path.join('__name_path', 'manifest'))
|
||||||
|
|
||||||
def test_explorer_path(self):
|
def test_explorer_path(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__name_path')
|
cdist_type = core.CdistType(base_path, '__name_path')
|
||||||
self.assertEqual(cdist_type.explorer_path, os.path.join('__name_path', 'explorer'))
|
self.assertEqual(cdist_type.explorer_path, os.path.join('__name_path', 'explorer'))
|
||||||
|
|
||||||
def test_gencode_local_path(self):
|
def test_gencode_local_path(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__name_path')
|
cdist_type = core.CdistType(base_path, '__name_path')
|
||||||
self.assertEqual(cdist_type.gencode_local_path, os.path.join('__name_path', 'gencode-local'))
|
self.assertEqual(cdist_type.gencode_local_path, os.path.join('__name_path', 'gencode-local'))
|
||||||
|
|
||||||
def test_gencode_remote_path(self):
|
def test_gencode_remote_path(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__name_path')
|
cdist_type = core.CdistType(base_path, '__name_path')
|
||||||
self.assertEqual(cdist_type.gencode_remote_path, os.path.join('__name_path', 'gencode-remote'))
|
self.assertEqual(cdist_type.gencode_remote_path, os.path.join('__name_path', 'gencode-remote'))
|
||||||
|
|
||||||
def test_singleton_is_singleton(self):
|
def test_singleton_is_singleton(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__singleton')
|
cdist_type = core.CdistType(base_path, '__singleton')
|
||||||
self.assertTrue(cdist_type.is_singleton)
|
self.assertTrue(cdist_type.is_singleton)
|
||||||
|
|
||||||
def test_not_singleton_is_singleton(self):
|
def test_not_singleton_is_singleton(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__not_singleton')
|
cdist_type = core.CdistType(base_path, '__not_singleton')
|
||||||
self.assertFalse(cdist_type.is_singleton)
|
self.assertFalse(cdist_type.is_singleton)
|
||||||
|
|
||||||
def test_install_is_install(self):
|
def test_install_is_install(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__install')
|
cdist_type = core.CdistType(base_path, '__install')
|
||||||
self.assertTrue(cdist_type.is_install)
|
self.assertTrue(cdist_type.is_install)
|
||||||
|
|
||||||
def test_not_install_is_install(self):
|
def test_not_install_is_install(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__not_install')
|
cdist_type = core.CdistType(base_path, '__not_install')
|
||||||
self.assertFalse(cdist_type.is_install)
|
self.assertFalse(cdist_type.is_install)
|
||||||
|
|
||||||
def test_with_explorers(self):
|
def test_with_explorers(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__with_explorers')
|
cdist_type = core.CdistType(base_path, '__with_explorers')
|
||||||
self.assertEqual(cdist_type.explorers, ['whatever'])
|
self.assertEqual(cdist_type.explorers, ['whatever'])
|
||||||
|
|
||||||
def test_without_explorers(self):
|
def test_without_explorers(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__without_explorers')
|
cdist_type = core.CdistType(base_path, '__without_explorers')
|
||||||
self.assertEqual(cdist_type.explorers, [])
|
self.assertEqual(cdist_type.explorers, [])
|
||||||
|
|
||||||
def test_with_required_parameters(self):
|
def test_with_required_parameters(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__with_required_parameters')
|
cdist_type = core.CdistType(base_path, '__with_required_parameters')
|
||||||
self.assertEqual(cdist_type.required_parameters, ['required1', 'required2'])
|
self.assertEqual(cdist_type.required_parameters, ['required1', 'required2'])
|
||||||
|
|
||||||
def test_without_required_parameters(self):
|
def test_without_required_parameters(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__without_required_parameters')
|
cdist_type = core.CdistType(base_path, '__without_required_parameters')
|
||||||
self.assertEqual(cdist_type.required_parameters, [])
|
self.assertEqual(cdist_type.required_parameters, [])
|
||||||
|
|
||||||
def test_with_optional_parameters(self):
|
def test_with_optional_parameters(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__with_optional_parameters')
|
cdist_type = core.CdistType(base_path, '__with_optional_parameters')
|
||||||
self.assertEqual(cdist_type.optional_parameters, ['optional1', 'optional2'])
|
self.assertEqual(cdist_type.optional_parameters, ['optional1', 'optional2'])
|
||||||
|
|
||||||
def test_without_optional_parameters(self):
|
def test_without_optional_parameters(self):
|
||||||
base_path = fixtures
|
base_path = fixtures
|
||||||
cdist_type = core.Type(base_path, '__without_optional_parameters')
|
cdist_type = core.CdistType(base_path, '__without_optional_parameters')
|
||||||
self.assertEqual(cdist_type.optional_parameters, [])
|
self.assertEqual(cdist_type.optional_parameters, [])
|
||||||
|
|
||||||
|
def test_with_boolean_parameters(self):
|
||||||
|
base_path = fixtures
|
||||||
|
cdist_type = core.CdistType(base_path, '__with_boolean_parameters')
|
||||||
|
self.assertEqual(cdist_type.boolean_parameters, ['boolean1', 'boolean2'])
|
||||||
|
|
||||||
|
def test_without_boolean_parameters(self):
|
||||||
|
base_path = fixtures
|
||||||
|
cdist_type = core.CdistType(base_path, '__without_boolean_parameters')
|
||||||
|
self.assertEqual(cdist_type.boolean_parameters, [])
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
boolean1
|
||||||
|
boolean2
|
Loading…
Reference in a new issue