forked from ungleich-public/cdist
Merge branch 'master' into feature_init_process
Conflicts: doc/changelog doc/dev/todo/niconext doc/man/cdist-reference.text.sh lib/cdist/core/explorer.py doc/man/cdist-reference.text.sh documents better reachability of variables - also suitable for master? Signed-off-by: Nico Schottelius <nico@brief.schottelius.org>
This commit is contained in:
commit
2b380b7dc1
55 changed files with 921 additions and 360 deletions
15
README
15
README
|
@ -51,9 +51,10 @@ UNIX, simplicity, familar environment | cdist is configured in POSIX shell
|
||||||
### Documentation
|
### Documentation
|
||||||
|
|
||||||
The cdist documentation is included as manpages in the distribution.
|
The cdist documentation is included as manpages in the distribution.
|
||||||
|
You can browse the documentation online as well:
|
||||||
|
|
||||||
* You can [browse the documentation of the latest version online](man) as well.
|
* [latest version](man/latest)
|
||||||
* Have a look at the [given speeches](speeches)
|
* [all versions (>= 2.0.4)](man)
|
||||||
|
|
||||||
### OS support
|
### OS support
|
||||||
|
|
||||||
|
@ -88,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***).
|
||||||
|
@ -135,7 +136,13 @@ If you want to ensure nothing breaks you must set back the python version to wha
|
||||||
|
|
||||||
#### Max OS X
|
#### Max OS X
|
||||||
|
|
||||||
Ensure you have port installed and configured (http://www.macports.org/install.php).
|
You can choose between Homebrew and Macports, either way works:
|
||||||
|
|
||||||
|
[Homebrew](http://mxcl.github.com/homebrew/) variant:
|
||||||
|
|
||||||
|
brew install python3
|
||||||
|
|
||||||
|
[Macports](http://www.macports.org/install.php) variant:
|
||||||
|
|
||||||
port install python32
|
port install python32
|
||||||
ln -s /opt/local/bin/python3.2 /opt/local/bin/python3
|
ln -s /opt/local/bin/python3.2 /opt/local/bin/python3
|
||||||
|
|
9
build
9
build
|
@ -85,7 +85,7 @@ case "$1" in
|
||||||
;;
|
;;
|
||||||
|
|
||||||
release)
|
release)
|
||||||
"$0" clean && "$0" man && "$0" web
|
./doc/dev/releasechecklist
|
||||||
;;
|
;;
|
||||||
|
|
||||||
speeches)
|
speeches)
|
||||||
|
@ -99,7 +99,7 @@ case "$1" in
|
||||||
|
|
||||||
webmain)
|
webmain)
|
||||||
cp README ${WEBPAGE}
|
cp README ${WEBPAGE}
|
||||||
cd ${WEBDIR} && git commit -m "cdist update" ${WEBPAGE}
|
cd ${WEBDIR} && git commit -m "cdist main update" ${WEBPAGE}
|
||||||
cd ${WEBDIR} && make pub
|
cd ${WEBDIR} && make pub
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
@ -119,6 +119,11 @@ case "$1" in
|
||||||
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}
|
||||||
cd ${WEBDIR} && make pub
|
cd ${WEBDIR} && make pub
|
||||||
|
|
||||||
|
# Fix ikiwiki, which does not like symlinks for pseudo security
|
||||||
|
ssh tee.schottelius.org \
|
||||||
|
"cd /home/services/www/nico/www.nico.schottelius.org/www/software/cdist/man &&
|
||||||
|
rm -f latest && ln -sf "$version" latest"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
p|pu|pub)
|
p|pu|pub)
|
||||||
|
|
|
@ -18,13 +18,14 @@
|
||||||
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# All os variables are lower case
|
# All os variables are lower case. Keep this file in alphabetical
|
||||||
#
|
# order by os variable except in cases where order otherwise matters,
|
||||||
|
# in which case keep the primary os and its derivatives together in
|
||||||
|
# a block (see Debian and Redhat examples below).
|
||||||
#
|
#
|
||||||
|
|
||||||
# Ubuntu is also Debian, thus return if Ubuntu was found
|
if grep -q ^Amazon /etc/system-release 2>/dev/null; then
|
||||||
if grep -q ^DISTRIB_ID=Ubuntu /etc/lsb-release 2>/dev/null; then
|
echo amazon
|
||||||
echo ubuntu
|
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -33,45 +34,52 @@ if [ -f /etc/arch-release ]; then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -f /etc/cdist-preos ]; then
|
||||||
|
echo cdist-preos
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
### Debian and derivatives
|
||||||
|
if grep -q ^DISTRIB_ID=Ubuntu /etc/lsb-release 2>/dev/null; then
|
||||||
|
echo ubuntu
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -f /etc/debian_version ]; then
|
if [ -f /etc/debian_version ]; then
|
||||||
echo debian
|
echo debian
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
###
|
||||||
|
|
||||||
if [ -f /etc/gentoo-release ]; then
|
if [ -f /etc/gentoo-release ]; then
|
||||||
echo gentoo
|
echo gentoo
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Fedora is also Redhat, thus return before redhat!
|
|
||||||
if grep -q ^Fedora /etc/redhat-release 2>/dev/null; then
|
|
||||||
echo fedora
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# CentOS is also based on Redhat, thus return before redhat!
|
|
||||||
if grep -q ^CentOS /etc/redhat-release 2>/dev/null; then
|
|
||||||
echo centos
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f /etc/redhat-release ]; then
|
|
||||||
echo redhat
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f /etc/SuSE-release ]; then
|
|
||||||
echo suse
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f /etc/owl-release ]; then
|
if [ -f /etc/owl-release ]; then
|
||||||
echo owl
|
echo owl
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f /etc/cdist-preos ]; then
|
### Redhat and derivatives
|
||||||
echo cdist-preos
|
if grep -q ^CentOS /etc/redhat-release 2>/dev/null; then
|
||||||
|
echo centos
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q ^Fedora /etc/redhat-release 2>/dev/null; then
|
||||||
|
echo fedora
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f /etc/redhat-release ]; then
|
||||||
|
echo redhat
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
###
|
||||||
|
|
||||||
|
if [ -f /etc/SuSE-release ]; then
|
||||||
|
echo suse
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
case "$($__explorer/os)" in
|
case "$($__explorer/os)" in
|
||||||
|
amazon)
|
||||||
|
cat /etc/system-release
|
||||||
|
;;
|
||||||
archlinux)
|
archlinux)
|
||||||
# empty, but well...
|
# empty, but well...
|
||||||
cat /etc/arch-release
|
cat /etc/arch-release
|
||||||
|
|
|
@ -34,11 +34,6 @@ case "$state_should" in
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Mode settings
|
|
||||||
if [ -f "$__object/parameter/mode" ]; then
|
|
||||||
echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Group
|
# Group
|
||||||
if [ -f "$__object/parameter/group" ]; then
|
if [ -f "$__object/parameter/group" ]; then
|
||||||
echo chgrp \"$(cat "$__object/parameter/group")\" \"$destination\"
|
echo chgrp \"$(cat "$__object/parameter/group")\" \"$destination\"
|
||||||
|
@ -48,6 +43,12 @@ case "$state_should" in
|
||||||
if [ -f "$__object/parameter/owner" ]; then
|
if [ -f "$__object/parameter/owner" ]; then
|
||||||
echo chown \"$(cat "$__object/parameter/owner")\" \"$destination\"
|
echo chown \"$(cat "$__object/parameter/owner")\" \"$destination\"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Mode - needs to happen last as a chown/chgrp can alter mode by
|
||||||
|
# clearing S_ISUID and S_ISGID bits (see chown(2))
|
||||||
|
if [ -f "$__object/parameter/mode" ]; then
|
||||||
|
echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
absent)
|
absent)
|
||||||
|
|
|
@ -29,7 +29,7 @@ if grep -q "^${name}:" "$__object/explorer/group"; then
|
||||||
for property in $(ls .); do
|
for property in $(ls .); do
|
||||||
new_value="$(cat "$property")"
|
new_value="$(cat "$property")"
|
||||||
|
|
||||||
case "$key" in
|
case "$property" in
|
||||||
password)
|
password)
|
||||||
current_value="$(awk -F: '{ print $2 }' < "$__object/explorer/gshadow")"
|
current_value="$(awk -F: '{ print $2 }' < "$__object/explorer/gshadow")"
|
||||||
;;
|
;;
|
||||||
|
|
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
|
|
||||||
echo "echo \"${key}${delimiter}${value_should}\" >> \"$file\""
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if [ "$value_should" = '__NOTSET__' ]; then
|
|
||||||
# remove key and value
|
|
||||||
cat << DONE
|
|
||||||
sed -i '/^${key}/d' "$file"
|
|
||||||
DONE
|
|
||||||
else
|
|
||||||
# change value
|
|
||||||
cat << DONE
|
|
||||||
awk -F "$delimiter" '
|
|
||||||
/${key}${delimiter}*/{gsub("$value_is", "$value_should")};{print}' "$file" > "${file}+" \
|
|
||||||
&& mv "${file}+" "$file"
|
|
||||||
|
|
||||||
DONE
|
if [ "$state_is" = "$state_should" ]; then
|
||||||
fi
|
# nothing to do
|
||||||
;;
|
exit 0
|
||||||
esac
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
case "$state_should" in
|
||||||
|
absent)
|
||||||
|
# remove lines starting with key
|
||||||
|
echo "sed -i '/^$key\($delimiter\+\)/d' \"$file\""
|
||||||
|
;;
|
||||||
|
present)
|
||||||
|
case "$state_is" in
|
||||||
|
absent)
|
||||||
|
# add new key and value
|
||||||
|
echo "echo \"${key}${delimiter}${value}\" >> \"$file\""
|
||||||
|
;;
|
||||||
|
wrongvalue)
|
||||||
|
# change exisiting value
|
||||||
|
echo "sed -i \"s|^$key\($delimiter\+\).*|$key\1$value|\" \"$file\""
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown explorer state: $state_is" >&2
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown state: $state_should" >&2
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
|
|
|
@ -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
|
||||||
|
|
62
conf/type/__link/explorer/state
Executable file
62
conf/type/__link/explorer/state
Executable file
|
@ -0,0 +1,62 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# 2012 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/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
destination="/$__object_id"
|
||||||
|
type="$(cat "$__object/parameter/type")"
|
||||||
|
source="$(cat "$__object/parameter/source")"
|
||||||
|
|
||||||
|
# no destination? -> state is absent
|
||||||
|
if [ ! -e "$destination" ]; then
|
||||||
|
echo absent
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
destination_dir="${destination%/*}"
|
||||||
|
|
||||||
|
case "$type" in
|
||||||
|
symbolic)
|
||||||
|
cd "$destination_dir"
|
||||||
|
source_is=$(ls -l "$destination" | sed 's/.*-> //g')
|
||||||
|
if [ -h "$destination" -a "$source_is" = "$source" ]; then
|
||||||
|
echo present
|
||||||
|
else
|
||||||
|
echo absent
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
hard)
|
||||||
|
cd "$destination_dir"
|
||||||
|
# check source relative to destination_dir
|
||||||
|
if [ ! -e "$source" ]; then
|
||||||
|
echo sourcemissing
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
destination_inode=$(ls -i "$destination" | awk '{print $1}')
|
||||||
|
source_inode=$(ls -i "$source" | awk '{print $1}')
|
||||||
|
if [ "$destination_inode" -eq "$source_inode" ]; then
|
||||||
|
echo present
|
||||||
|
else
|
||||||
|
echo absent
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown type: $type" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
|
@ -39,7 +39,14 @@ case "$type" in
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
state_is="$(cat "$__object/explorer/state")"
|
||||||
state_should="$(cat "$__object/parameter/state")"
|
state_should="$(cat "$__object/parameter/state")"
|
||||||
|
|
||||||
|
if [ "$state_should" = "$state_is" ]; then
|
||||||
|
# nothing to do
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
case "$state_should" in
|
case "$state_should" in
|
||||||
present)
|
present)
|
||||||
echo ln ${lnopt} -f \"$source\" \"$destination\"
|
echo ln ${lnopt} -f \"$source\" \"$destination\"
|
||||||
|
|
|
@ -33,7 +33,7 @@ else
|
||||||
archlinux) type="pacman" ;;
|
archlinux) type="pacman" ;;
|
||||||
debian|ubuntu) type="apt" ;;
|
debian|ubuntu) type="apt" ;;
|
||||||
gentoo) type="emerge" ;;
|
gentoo) type="emerge" ;;
|
||||||
fedora|redhat|centos) type="yum" ;;
|
amazon|centos|fedora|redhat) type="yum" ;;
|
||||||
*)
|
*)
|
||||||
echo "Don't know how to manage packages on: $os" >&2
|
echo "Don't know how to manage packages on: $os" >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
|
49
conf/type/__package_pip/explorer/state
Normal file
49
conf/type/__package_pip/explorer/state
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#!/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/>.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Development supported by Local AG (www.local.ch)
|
||||||
|
#
|
||||||
|
|
||||||
|
nameparam="$__object/parameter/name"
|
||||||
|
if [ -f "$nameparam" ]; then
|
||||||
|
name=$(cat "$nameparam")
|
||||||
|
else
|
||||||
|
name="$__object_id"
|
||||||
|
fi
|
||||||
|
|
||||||
|
pipparam="$__object/parameter/pip"
|
||||||
|
if [ -f "$pipparam" ]; then
|
||||||
|
pip=$(cat "$pipparam")
|
||||||
|
else
|
||||||
|
pip="pip"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 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
|
||||||
|
echo absent
|
||||||
|
else
|
||||||
|
|
||||||
|
if "$pip" freeze | grep -i -q "^$name=="; then
|
||||||
|
echo present
|
||||||
|
else
|
||||||
|
echo absent
|
||||||
|
fi
|
||||||
|
fi
|
37
conf/type/__key_value/explorer/value → conf/type/__package_pip/gencode-remote
Executable file → Normal file
37
conf/type/__key_value/explorer/value → conf/type/__package_pip/gencode-remote
Executable file → Normal file
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# 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.
|
||||||
#
|
#
|
||||||
|
@ -18,20 +18,33 @@
|
||||||
# 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.
|
# Development supported by Local AG (www.local.ch)
|
||||||
#
|
#
|
||||||
|
|
||||||
if [ -f "$__object/parameter/key" ]; then
|
state_is=$(cat "$__object/explorer/state")
|
||||||
key="$(cat "$__object/parameter/key")"
|
state_should=$(cat "$__object/parameter/state")
|
||||||
|
|
||||||
|
[ "$state_is" = "$state_should" ] && exit 0
|
||||||
|
|
||||||
|
nameparam="$__object/parameter/name"
|
||||||
|
if [ -f "$nameparam" ]; then
|
||||||
|
name=$(cat "$nameparam")
|
||||||
else
|
else
|
||||||
key="$__object_id"
|
name="$__object_id"
|
||||||
fi
|
fi
|
||||||
file="$(cat "$__object/parameter/file")"
|
|
||||||
delimiter="$(cat "$__object/parameter/delimiter")"
|
|
||||||
|
|
||||||
awk -F "$delimiter" '
|
pipparam="$__object/parameter/pip"
|
||||||
BEGIN { found=0 }
|
if [ -f "$pipparam" ]; then
|
||||||
/^'$key'/ { print $2; found=1 }
|
pip=$(cat "$pipparam")
|
||||||
END { if (found) exit 0; else exit 1 }' "$file" \
|
else
|
||||||
|| echo "__NOTSET__"
|
pip="pip"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$state_should" in
|
||||||
|
present)
|
||||||
|
echo $pip install -q pyro
|
||||||
|
;;
|
||||||
|
absent)
|
||||||
|
echo $pip uninstall -q -y pyro
|
||||||
|
;;
|
||||||
|
esac
|
53
conf/type/__package_pip/man.text
Normal file
53
conf/type/__package_pip/man.text
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
cdist-type__package_pip(7)
|
||||||
|
==========================
|
||||||
|
Nico Schottelius <nico-cdist--@--schottelius.org>
|
||||||
|
|
||||||
|
|
||||||
|
NAME
|
||||||
|
----
|
||||||
|
cdist-type__package_pip - Manage packages with pip
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
-----------
|
||||||
|
Pip is used in Python environments to install packages.
|
||||||
|
It is also included in the python virtualenv environment.
|
||||||
|
|
||||||
|
|
||||||
|
REQUIRED PARAMETERS
|
||||||
|
-------------------
|
||||||
|
state::
|
||||||
|
Either "present" or "absent".
|
||||||
|
|
||||||
|
|
||||||
|
OPTIONAL PARAMETERS
|
||||||
|
-------------------
|
||||||
|
name::
|
||||||
|
If supplied, use the name and not the object id as the package name.
|
||||||
|
|
||||||
|
pip::
|
||||||
|
Instead of using pip from PATH, use the specific pip path.
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
|
--------
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
# Install a package
|
||||||
|
__package_pip pyro --state present
|
||||||
|
|
||||||
|
# Use pip in a virtualenv located at /root/shinken_virtualenv
|
||||||
|
__package_pip pyro --state present --pip /root/shinken_virtualenv/bin/pip
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
--------
|
||||||
|
- cdist-type(7)
|
||||||
|
- cdist-type__package(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
conf/type/__package_pip/parameter/optional
Normal file
1
conf/type/__package_pip/parameter/optional
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pip
|
1
conf/type/__package_pip/parameter/required
Normal file
1
conf/type/__package_pip/parameter/required
Normal file
|
@ -0,0 +1 @@
|
||||||
|
state
|
|
@ -29,7 +29,7 @@ fi
|
||||||
|
|
||||||
state="$(cat "$__object/parameter/state")"
|
state="$(cat "$__object/parameter/state")"
|
||||||
|
|
||||||
if grep -q -E "(centos|redhat)" "$__global/explorer/os"; then
|
if grep -q -E "(centos|redhat|amazon)" "$__global/explorer/os"; then
|
||||||
opts="-y --quiet"
|
opts="-y --quiet"
|
||||||
else
|
else
|
||||||
opts="--assumeyes --quiet"
|
opts="--assumeyes --quiet"
|
||||||
|
|
|
@ -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,13 +37,20 @@ 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)
|
||||||
field=3
|
field=2
|
||||||
file="$__object/explorer/shadow"
|
file="$__object/explorer/shadow"
|
||||||
;;
|
;;
|
||||||
comment) field=5 ;;
|
comment) field=5 ;;
|
||||||
|
@ -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\'
|
||||||
|
|
|
@ -1,15 +1,37 @@
|
||||||
2.0.6:
|
Changelog
|
||||||
|
---------
|
||||||
|
|
||||||
|
* Changes are always commented with their author in (braces)
|
||||||
|
* Exception: No braces means author == Nico Schottelius
|
||||||
|
|
||||||
|
2.0.8:
|
||||||
|
* Cleanup: Better hint to source of error
|
||||||
|
* Cleanup: Remove support for __debug variable in manifests (Type != Core
|
||||||
|
debugging)
|
||||||
|
|
||||||
|
2.0.7: 2012-02-13
|
||||||
|
* Bugfix __file: Use chmod after chown/chgrp (Matt Coddington)
|
||||||
|
* Bugfix __user: Correct shadow field in explorer (Matt Coddington)
|
||||||
|
* 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
|
||||||
|
* Bugfix/Cleanup: Correctly allow Object ID to start and end with /, but
|
||||||
|
not contain //.
|
||||||
|
|
||||||
|
2.0.6: 2012-01-28
|
||||||
* Bugfix __apt_ppa:
|
* Bugfix __apt_ppa:
|
||||||
Also remove the [ppa-name].list file, if empty. (Tim Kersten)
|
Also remove the [ppa-name].list file, if empty. (Tim Kersten)
|
||||||
|
* Bugfix __group:
|
||||||
|
Referenced wrong variable name (Matt Coddington)
|
||||||
* Feature __package_apt:
|
* Feature __package_apt:
|
||||||
Initial support for virtual packages (Evax Software)
|
Initial support for virtual packages (Evax Software)
|
||||||
|
* Feature Core: Added new dependency resolver (Steven Armstrong)
|
||||||
|
* Feature Explorer, __package_yum: Support Amazon Linux (Matt Coddington)
|
||||||
* New Type: __rvm (Evax Software)
|
* New Type: __rvm (Evax Software)
|
||||||
* New Type: __rvm_gem (Evax Software)
|
* New Type: __rvm_gem (Evax Software)
|
||||||
* New Type: __rvm_gemset (Evax Software)
|
* New Type: __rvm_gemset (Evax Software)
|
||||||
* New Type: __rvm_ruby (Evax Software)
|
* New Type: __rvm_ruby (Evax Software)
|
||||||
* New Explorer: runlevel
|
|
||||||
* Documentation: Update of reference (environment variables)
|
|
||||||
* Feature core: Added new dependency resolver (Steven Armstrong)
|
|
||||||
|
|
||||||
2.0.5: 2012-01-18
|
2.0.5: 2012-01-18
|
||||||
* Bugfix __key_value: Use correct delimiters
|
* Bugfix __key_value: Use correct delimiters
|
||||||
|
|
36
doc/dev/logs/2012-02-08.explorer-depends-on-another-type
Normal file
36
doc/dev/logs/2012-02-08.explorer-depends-on-another-type
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
If a type explorer depends on a command that will be generated by another type,
|
||||||
|
the operation fails, as can be seen below.
|
||||||
|
|
||||||
|
This may be a corner case, but is hapenning with __package_pip and
|
||||||
|
__python_virtualenv.
|
||||||
|
|
||||||
|
[19:10] brief:cdist% ./bin/cdist config -v loch
|
||||||
|
INFO: loch: Running global explorers
|
||||||
|
INFO: loch: Running initial manifest /home/users/nico/privat/firmen/local.ch/vcs/cdist/conf/manifest
|
||||||
|
INFO: loch: Running object manifests and type explorers
|
||||||
|
INFO: loch: Running manifest and explorers for __git/root/shinken
|
||||||
|
INFO: loch: Running manifest and explorers for __package_pip/pyro
|
||||||
|
/var/lib/cdist/conf/type/__package_pip/explorer/state: line 38: /root/shinken_virtualenv/bin/pip: No such file or directory
|
||||||
|
INFO: loch: Running manifest and explorers for __python_virtualenv/root/shinken_virtualenv
|
||||||
|
INFO: loch: Running manifest and explorers for __directory/pyro
|
||||||
|
INFO: loch: Running manifest and explorers for __directory/root/shinken
|
||||||
|
INFO: loch: Running manifest and explorers for __directory/root/shinken_virtualenv
|
||||||
|
INFO: loch: Running manifest and explorers for __package/git
|
||||||
|
INFO: loch: Running manifest and explorers for __package/python-virtualenv
|
||||||
|
INFO: loch: Running manifest and explorers for __package_pacman/git
|
||||||
|
INFO: loch: Running manifest and explorers for __package_pacman/python-virtualenv
|
||||||
|
INFO: loch: Generating and executing code
|
||||||
|
INFO: loch: Generating and executing code for __package_pacman/git
|
||||||
|
INFO: loch: Generating and executing code for __package/git
|
||||||
|
INFO: loch: Generating and executing code for __directory/root/shinken
|
||||||
|
INFO: loch: Generating and executing code for __git/root/shinken
|
||||||
|
fatal: write error: No space left on device
|
||||||
|
fatal: index-pack failed
|
||||||
|
ERROR: loch: Code that raised the error:
|
||||||
|
git clone --quiet "git://github.com/naparuba/shinken.git" "/root/shinken"
|
||||||
|
|
||||||
|
ERROR: Remote script execution failed: ssh -o User=root -q loch /bin/sh -e /var/lib/cdist/object/__git/root/shinken/.cdist/code-remote
|
||||||
|
WARNING: Failed to deploy to the following hosts: loch
|
||||||
|
INFO: Total processing time for 1 host(s): 340.62370681762695
|
||||||
|
[19:17] brief:cdist% ./bin/cdist config -v loch
|
||||||
|
|
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]]
|
|
@ -11,15 +11,25 @@ echo "Testing documentation..."
|
||||||
./build clean && ./build man || exit 1
|
./build clean && ./build man || exit 1
|
||||||
|
|
||||||
# get version
|
# get version
|
||||||
changelog_version=$(head -n1 doc/changelog | sed 's/:.*//')
|
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
|
||||||
|
|
|
@ -34,7 +34,6 @@ USER INTERFACE
|
||||||
|
|
||||||
TYPES
|
TYPES
|
||||||
------
|
------
|
||||||
|
- Add testing framework (proposed by Evax Software)
|
||||||
- __user
|
- __user
|
||||||
add option to include --create-home
|
add option to include --create-home
|
||||||
- ensure that all types, which support --state support
|
|
||||||
present and absent (consistent look and feel)
|
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
- __init_script?
|
2.0.8 features / cleanups:
|
||||||
to enable/disable startup of init stuff
|
|
||||||
http://linuxhelp.blogspot.com/2006/04/enabling-and-disabling-services-during_01.html
|
- cleanup object_id handling
|
||||||
|
- have a look at singletons
|
||||||
|
|
||||||
|
- remove useless
|
||||||
|
ERROR: monitoring02: Code that raised the error:
|
||||||
|
|
||||||
|
- ensure that all types, which support --state support
|
||||||
|
present and absent (consistent look and feel)
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
- update/create docs
|
- update/create docs
|
||||||
- document __remote_copy and __remote_exec
|
|
||||||
- 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]
|
||||||
- cdist-scaling-tuning::
|
- cdist-scaling-tuning::
|
||||||
|
@ -17,3 +25,4 @@
|
||||||
|
|
||||||
- exec flag is not true for manifest anymore
|
- exec flag is not true for manifest anymore
|
||||||
- SSH HINTS - ssh agent
|
- SSH HINTS - ssh agent
|
||||||
|
|
||||||
|
|
|
@ -180,7 +180,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.
|
||||||
|
|
|
@ -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
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
VERSION = "2.0.7"
|
||||||
|
|
||||||
BANNER = """
|
BANNER = """
|
||||||
.. . .x+=:. s
|
.. . .x+=:. s
|
||||||
dF @88> z` ^% :8
|
dF @88> z` ^% :8
|
||||||
|
@ -34,7 +36,6 @@ BANNER = """
|
||||||
"P' "" ""
|
"P' "" ""
|
||||||
"""
|
"""
|
||||||
DOT_CDIST = ".cdist"
|
DOT_CDIST = ".cdist"
|
||||||
VERSION = "2.0.5"
|
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
@ -43,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]
|
||||||
|
@ -84,7 +84,7 @@ class Type(object):
|
||||||
self.__optional_parameters = None
|
self.__optional_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
|
|
@ -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,9 +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,
|
||||||
}
|
}
|
||||||
# FIXME: remove soon with new logging infrastructure
|
|
||||||
if self.log.getEffectiveLevel() == logging.DEBUG:
|
|
||||||
self.env.update({'__debug': "yes" })
|
|
||||||
self._type_explorers_transferred = []
|
self._type_explorers_transferred = []
|
||||||
|
|
||||||
### global
|
### global
|
||||||
|
@ -122,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:
|
||||||
|
@ -150,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()
|
||||||
|
|
||||||
|
@ -113,20 +106,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 = {}
|
||||||
|
@ -143,6 +131,9 @@ class Emulator(object):
|
||||||
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 +142,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.
|
||||||
|
|
|
@ -143,7 +143,7 @@ class Local(object):
|
||||||
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)
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
# FIXME: common base class with Local?
|
|
||||||
|
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -148,18 +146,17 @@ 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
|
||||||
|
|
||||||
|
self.log.debug("Remote run script: %s", command)
|
||||||
|
|
||||||
# can't pass environment to remote side, so prepend command with
|
# can't pass environment to remote side, so prepend command with
|
||||||
# variable declarations
|
# variable declarations
|
||||||
if env:
|
if env:
|
||||||
|
self.log.debug("Remote run script env: %s", env)
|
||||||
command.extend(["%s=%s" % item for item in env.items()])
|
command.extend(["%s=%s" % item for item in env.items()])
|
||||||
|
|
||||||
command.extend(["/bin/sh", "-e"])
|
command.extend(["/bin/sh", "-e"])
|
||||||
command.append(script)
|
command.append(script)
|
||||||
|
|
||||||
self.log.debug("Remote run script: %s", command)
|
|
||||||
if env:
|
|
||||||
self.log.debug("Remote run script env: %s", env)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if return_output:
|
if return_output:
|
||||||
return subprocess.check_output(command, env=os_environ).decode()
|
return subprocess.check_output(command, env=os_environ).decode()
|
||||||
|
|
|
@ -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,8 +119,8 @@ 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))
|
||||||
|
@ -156,6 +156,6 @@ 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)
|
||||||
|
|
|
@ -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,115 @@ 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, [])
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
Description:
|
||||||
|
|
||||||
|
Type that supports transfer of huge data, which is a general problem in
|
||||||
|
configuration management systems.
|
||||||
|
|
||||||
|
Good solution using standardised rsync approach.
|
||||||
|
|
||||||
|
Problem:
|
||||||
|
|
||||||
|
Uses root@$__target_host:$destination notation for transfer.
|
||||||
|
This breaks the concept of being able to replace __remote_exec and
|
||||||
|
__remote_copy and then doing chroot or different stuff.
|
||||||
|
|
||||||
|
This breaks for instance, if __remote_copy = cp and the destination is
|
||||||
|
a local chroot.
|
||||||
|
|
||||||
|
Solutions:
|
||||||
|
|
||||||
|
- Have cdist provide support for rsync syntax?
|
||||||
|
- Integrate __rsyncer more in line with philosohpy of other components
|
||||||
|
- Think about the general way of __rsyncer and what cdist would need
|
||||||
|
to provide for general solution.
|
48
other/types_submitted_for_inclusion/__rsyncer/gencode-local
Executable file
48
other/types_submitted_for_inclusion/__rsyncer/gencode-local
Executable file
|
@ -0,0 +1,48 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (C) 2011 Daniel Maher (phrawzty+cdist at gmail.com)
|
||||||
|
#
|
||||||
|
# This file is part of cdist (https://github.com/telmich/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/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
source="$(cat "$__object/parameter/source")"
|
||||||
|
|
||||||
|
if [ -f "$__object/parameter/destination" ]; then
|
||||||
|
destination="$(cat "$__object/parameter/destination")"
|
||||||
|
else
|
||||||
|
destination="/$__object_id"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The system binary is probably ok, but if not...
|
||||||
|
if [ -f "$__object/parameter/rsyncbin" ]; then
|
||||||
|
rsyncbin="$(cat "$__object/parameter/rsyncbin")"
|
||||||
|
else
|
||||||
|
rsyncbin=`which rsync`
|
||||||
|
fi
|
||||||
|
|
||||||
|
args='-a'
|
||||||
|
|
||||||
|
# If the --delete argument should be passed to rsync.
|
||||||
|
if [ -f "$__object/parameter/delete" ]; then
|
||||||
|
args="$args --delete"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# FIXME:
|
||||||
|
# - using root@ may break - find a good way to avoid this
|
||||||
|
# - align with __remote_{exec,copy} variables?
|
||||||
|
|
||||||
|
# Run rsync (locally).
|
||||||
|
echo "$rsyncbin $args $source root@$__target_host:$destination"
|
62
other/types_submitted_for_inclusion/__rsyncer/man.text
Normal file
62
other/types_submitted_for_inclusion/__rsyncer/man.text
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
cdist-type__rsyncer(7)
|
||||||
|
======================
|
||||||
|
Daniel Maher <phrawzty+cdist at gmail.com>
|
||||||
|
|
||||||
|
|
||||||
|
NAME
|
||||||
|
----
|
||||||
|
cdist-type__rsyncer - Use rsync to copy files.
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
-----------
|
||||||
|
This type is used to trigger rsync to copy files from the machine running cdist
|
||||||
|
(source) to the target machine in question (destination). The likely usage is
|
||||||
|
the rapid deployment of full directory trees, the cohorency of which can be
|
||||||
|
guarunteed with the optional --delete argument, which will remove any files
|
||||||
|
from the destination which are not present on the source.
|
||||||
|
|
||||||
|
|
||||||
|
REQUIRED PARAMETERS
|
||||||
|
-------------------
|
||||||
|
source::
|
||||||
|
The full path of the source from which to copy. This is passed directly
|
||||||
|
to rsync.
|
||||||
|
|
||||||
|
|
||||||
|
OPTIONAL PARAMETERS
|
||||||
|
-------------------
|
||||||
|
destination::
|
||||||
|
The full path of the destination. This is passed directly to rsync.
|
||||||
|
Default: object_id
|
||||||
|
|
||||||
|
delete::
|
||||||
|
If true, remove files from destination which are not in source. This is
|
||||||
|
effectively the --delete argument of rsync.
|
||||||
|
Default: false
|
||||||
|
|
||||||
|
rsyncbin::
|
||||||
|
Specify the full path to the rsync binary.
|
||||||
|
Default: `which rsync`
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
|
--------
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
# Basic example
|
||||||
|
__rsyncer '/home/foo' --source '/opt/dist/foo'
|
||||||
|
|
||||||
|
# Fancier example
|
||||||
|
__rsyncer FOO --source '/opt/dist/foo' --destination '/home/foo/' --delete true
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
--------
|
||||||
|
- cdist-type(7)
|
||||||
|
|
||||||
|
|
||||||
|
COPYING
|
||||||
|
-------
|
||||||
|
Copyright \(C) 2011 Daniel Maher. Free use of this software is granted under
|
||||||
|
the terms of the GNU General Public License version 3 (GPLv3).
|
|
@ -0,0 +1,3 @@
|
||||||
|
destination
|
||||||
|
delete
|
||||||
|
rsyncbin
|
|
@ -0,0 +1 @@
|
||||||
|
source
|
Loading…
Reference in a new issue