diff --git a/README b/README
index 965138c4..e514df91 100644
--- a/README
+++ b/README
@@ -38,6 +38,7 @@ Design | Define target state, do not focus on methods or scripts
Design | Push architecture: Instantly apply your changes
Small core | cdist's core is very small - less code, less bugs
Fast development | Focus on straightforwardness of type creation is a main development objective
+Fast development | Batteries included: A lot of requirements can be solved using standard types
Modern Programming Language | cdist is written in Python
Requirements, Scalability | No central server needed, cdist operates in push mode and can be run from any computer
Requirements, Scalability, Upgrade | cdist only needs to be updated on the master, not on the target hosts
diff --git a/bin/cdist b/bin/cdist
index 5456b134..c6467477 100755
--- a/bin/cdist
+++ b/bin/cdist
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
-# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org)
+# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org)
#
# This file is part of cdist.
#
@@ -108,55 +108,48 @@ def configinstall(args, mode):
if args.manifest == '-':
# read initial manifest from stdin
import tempfile
- handle, initial_manifest_temp_path = tempfile.mkstemp(prefix='cdist.stdin.')
- with os.fdopen(handle, 'w') as fd:
- fd.write(sys.stdin.read())
+ try:
+ handle, initial_manifest_temp_path = tempfile.mkstemp(prefix='cdist.stdin.')
+ with os.fdopen(handle, 'w') as fd:
+ fd.write(sys.stdin.read())
+ except (IOError, OSError) as e:
+ raise cdist.Error("Creating tempfile for stdin data failed: %s" % e)
+
args.manifest = initial_manifest_temp_path
import atexit
atexit.register(lambda: os.remove(initial_manifest_temp_path))
- try:
- process = {}
- failed_hosts = []
- time_start = time.time()
-
- for host in args.host:
- if args.parallel:
- log.debug("Creating child process for %s", host)
- process[host] = multiprocessing.Process(target=configinstall_onehost, args=(host, args, mode, True))
- process[host].start()
- else:
- if not configinstall_onehost(host, args, mode, parallel=False):
- failed_hosts.append(host)
+ process = {}
+ failed_hosts = []
+ time_start = time.time()
+ for host in args.host:
if args.parallel:
- for p in process.keys():
- log.debug("Joining process %s", p)
- process[p].join()
+ log.debug("Creating child process for %s", host)
+ process[host] = multiprocessing.Process(target=configinstall_onehost, args=(host, args, mode, True))
+ process[host].start()
+ else:
+ try:
+ configinstall_onehost(host, args, mode, parallel=False)
+ except cdist.Error as e:
+ failed_hosts.append(host)
- if not process[p].exitcode == 0:
- failed_hosts.append(p)
+ # Catch errors in parallel mode when joining
+ if args.parallel:
+ for host in process.keys():
+ log.debug("Joining process %s", host)
+ process[host].join()
- if len(failed_hosts) > 0:
- log.warn("Failed to deploy to the following hosts: " +
- " ".join(failed_hosts))
+ if not process[host].exitcode == 0:
+ failed_hosts.append(host)
- time_end = time.time()
- log.info("Total processing time for %s host(s): %s", len(args.host),
- (time_end - time_start))
-
- except KeyboardInterrupt:
- if args.parallel:
- for p in process.keys():
- # NOT needed: KeyBoardInterrupet (aka SIGINT)
- # is forwarded to processes spawned by multiprocess!
- # pid = process[p].pid.__str__()
- #log.warn("Terminating deploy " + p + " (" + pid + ")")
- # process[p].terminate()
- pass
-
- sys.exit(0)
+ time_end = time.time()
+ log.info("Total processing time for %s host(s): %s", len(args.host),
+ (time_end - time_start))
+ if len(failed_hosts) > 0:
+ raise cdist.Error("Failed to deploy to the following hosts: " +
+ " ".join(failed_hosts))
def configinstall_onehost(host, args, mode, parallel):
"""Configure or install ONE remote system"""
@@ -176,33 +169,33 @@ def configinstall_onehost(host, args, mode, parallel):
context.cleanup()
except cdist.Error as e:
- log.error(e)
- return False
- except KeyboardInterrupt:
- # Do not care in sequential mode, catch in parallel mode
- if not parallel:
- raise
+ # We are running in our own process here, need to sys.exit!
+ if parallel:
+ log.error(e)
+ sys.exit(1)
else:
- # Catch here, above does not need to know about our errors
- return False
+ raise
- return True
+ except KeyboardInterrupt:
+ # Ignore in parallel mode, we are existing anyway
+ if parallel:
+ sys.exit(0)
+ # Pass back to controlling code in sequential mode
+ else:
+ raise
def emulator():
"""Prepare and run emulator"""
- try:
- import cdist.emulator
- emulator = cdist.emulator.Emulator(sys.argv)
- emulator.run()
-
- except cdist.Error as e:
- log.error(e)
- sys.exit(1)
+ import cdist.emulator
+ emulator = cdist.emulator.Emulator(sys.argv)
+ return emulator.run()
if __name__ == "__main__":
# Sys is needed for sys.exit()
import sys
+ exit_code = 0
+
try:
import logging
import os
@@ -210,9 +203,8 @@ if __name__ == "__main__":
cdistpythonversion = '3.2'
if sys.version < cdistpythonversion:
- print('Cdist requires Python >= ' + cdistpythonversion +
+ raise cdist.Error('Cdist requires Python >= ' + cdistpythonversion +
' on the source host.')
- sys.exit(1)
# Ensure our /lib/ is included into PYTHON_PATH
sys.path.insert(0, os.path.abspath(
@@ -230,7 +222,13 @@ if __name__ == "__main__":
else:
commandline()
- sys.exit(0)
-
except KeyboardInterrupt:
- sys.exit(0)
+ pass
+
+ except cdist.Error as e:
+ log.error(e)
+ exit_code = 1
+
+ # Determine exit code by return value of function
+
+ sys.exit(exit_code)
diff --git a/conf/type/__cron/man.text b/conf/type/__cron/man.text
index c4852b7f..47f47456 100644
--- a/conf/type/__cron/man.text
+++ b/conf/type/__cron/man.text
@@ -35,14 +35,25 @@ month::
See crontab(5). Defaults to *
day_of_week::
See crontab(5). Defaults to *
+raw::
+ Take whatever the user has given instead of time and date fields.
+ If given, all other time and date fields are ignored.
+ Can for example be used to specify cron EXTENSIONS like reboot, yearly etc.
+ See crontab(5) for the extensions if any that your cron implementation
+ implements.
EXAMPLES
--------
--------------------------------------------------------------------------------
-# add cronjob
-__cron some-id --user root --command "/path/to/script"
+# run Monday to Saturday at 23:15
+__cron some-id --user root --command "/path/to/script" \
+ --hour 23 --minute 15 --day_of_week 1-6
+
+# run on reboot
+__cron some-id --user root --command "/path/to/script" \
+ --raw @reboot
# remove cronjob
__cron some-id --user root --command "/path/to/script" --state absent
diff --git a/conf/type/__cron/manifest b/conf/type/__cron/manifest
index 01c4358c..7aca41ff 100755
--- a/conf/type/__cron/manifest
+++ b/conf/type/__cron/manifest
@@ -23,44 +23,23 @@ user="$(cat "$__object/parameter/user")"
command="$(cat "$__object/parameter/command")"
# set defaults
-if [ ! -f "$__object/parameter/state" ]; then
- echo "present" > "$__object/parameter/state"
-fi
-if [ -f "$__object/parameter/minute" ]; then
- minute="$(cat "$__object/parameter/minute")"
+test -f "$__object/parameter/state" || echo "present" > "$__object/parameter/state"
+
+if [ -f "$__object/parameter/raw" ]; then
+ raw="$(cat "$__object/parameter/raw")"
+ entry="$raw $command"
else
- minute="*"
- echo "$minute" > "$__object/parameter/minute"
-fi
-if [ -f "$__object/parameter/hour" ]; then
- hour="$(cat "$__object/parameter/hour")"
-else
- hour="*"
- echo "$hour" > "$__object/parameter/hour"
-fi
-if [ -f "$__object/parameter/day_of_month" ]; then
- day_of_month="$(cat "$__object/parameter/day_of_month")"
-else
- day_of_month="*"
- echo "$day_of_month" > "$__object/parameter/day_of_month"
-fi
-if [ -f "$__object/parameter/month" ]; then
- month="$(cat "$__object/parameter/month")"
-else
- month="*"
- echo "$month" > "$__object/parameter/month"
-fi
-if [ -f "$__object/parameter/day_of_week" ]; then
- day_of_week="$(cat "$__object/parameter/day_of_week")"
-else
- day_of_week="*"
- echo "$day_of_week" > "$__object/parameter/day_of_week"
+ minute="$(cat "$__object/parameter/minute" 2>/dev/null || echo "*")"
+ hour="$(cat "$__object/parameter/hour" 2>/dev/null || echo "*")"
+ day_of_month="$(cat "$__object/parameter/day_of_month" 2>/dev/null || echo "*")"
+ month="$(cat "$__object/parameter/month" 2>/dev/null || echo "*")"
+ day_of_week="$(cat "$__object/parameter/day_of_week" 2>/dev/null || echo "*")"
+ entry="$minute $hour $day_of_month $month $day_of_week $command"
fi
# NOTE: if changed, also change in explorers
prefix="#cdist:__cron/$name"
suffix="#/cdist:__cron/$name"
echo "$prefix" | tee "$__object/parameter/prefix" > "$__object/parameter/entry"
-echo "$minute $hour $day_of_month $month $day_of_week $command" >> "$__object/parameter/entry"
+echo "$entry" >> "$__object/parameter/entry"
echo "$suffix" | tee "$__object/parameter/suffix" >> "$__object/parameter/entry"
-
diff --git a/conf/type/__cron/parameter/optional b/conf/type/__cron/parameter/optional
index 1a4aae3d..517d821e 100644
--- a/conf/type/__cron/parameter/optional
+++ b/conf/type/__cron/parameter/optional
@@ -4,3 +4,4 @@ hour
day_of_month
month
day_of_week
+raw
diff --git a/conf/type/__group/explorer/gshadow b/conf/type/__group/explorer/gshadow
index 51d502a1..e3c2dd6c 100755
--- a/conf/type/__group/explorer/gshadow
+++ b/conf/type/__group/explorer/gshadow
@@ -22,6 +22,15 @@
#
name=$__object_id
+os_version="$($__explorer/os_version)"
-getent gshadow "$name" || true
+case "$os_version" in
+ "Red Hat Enterprise Linux Server release "[45]*|"CentOS release "[45]*)
+ # TODO: find a way to get this information
+ echo "$os_version does not have getent gshadow"
+ ;;
+ *)
+ getent gshadow "$name" || true
+ ;;
+esac
diff --git a/conf/type/__group/gencode-remote b/conf/type/__group/gencode-remote
index cf26a437..2b4774ab 100755
--- a/conf/type/__group/gencode-remote
+++ b/conf/type/__group/gencode-remote
@@ -23,23 +23,36 @@
#
name="$__object_id"
+os_version="$(cat "$__global/explorer/os_version")"
cd "$__object/parameter"
if grep -q "^${name}:" "$__object/explorer/group"; then
for property in $(ls .); do
new_value="$(cat "$property")"
+ # argument to pass the groupmod command for this property (exceptions
+ # are made in the case statement below)
+ proparg="--$property"
case "$property" in
password)
current_value="$(awk -F: '{ print $2 }' < "$__object/explorer/gshadow")"
+ case "$os_version" in
+ "Red Hat Enterprise Linux Server release "[45]*|"CentOS release "[45]*)
+ # TODO: Use gpasswd? Need to fix gshadow explorer first.
+ echo "group/$name: '$os_version' groupmod does not support password modification" >&2
+ exit 1
+ ;;
+ esac
;;
gid)
+ # set to -g to support older redhat/centos
+ proparg="-g"
current_value="$(awk -F: '{ print $3 }' < "$__object/explorer/group")"
;;
esac
if [ "$new_value" != "$current_value" ]; then
- set -- "$@" "--$property" \"$new_value\"
+ set -- "$@" "$proparg" \"$new_value\"
fi
done
diff --git a/conf/type/__mysql_database/gencode-remote b/conf/type/__mysql_database/gencode-remote
new file mode 100755
index 00000000..7cd32242
--- /dev/null
+++ b/conf/type/__mysql_database/gencode-remote
@@ -0,0 +1,55 @@
+#!/bin/sh
+#
+# 2012 Benedikt Koeppel (code@benediktkoeppel.ch)
+#
+# 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 .
+#
+#
+
+# if --database was specified
+if [ -f "$__object/parameter/name" ]; then
+ database="$(cat "$__object/parameter/name")"
+else # otherwise use the object id as database name
+ database="$__object_id"
+fi
+
+cat <<-EOFF
+mysql -u root <<-EOF
+ CREATE DATABASE IF NOT EXISTS $database
+EOF
+EOFF
+
+# if --user was specified
+if [ -f "$__object/parameter/user" ]; then
+ user="$(cat "$__object/parameter/user")"
+
+ # if --password was specified
+ if [ -f "$__object/parameter/password" ]; then
+ password="$(cat "$__object/parameter/password")"
+ cat <<-EOFF
+ mysql -u root <<-EOF
+ GRANT ALL PRIVILEGES ON $database.* to '$user'@'localhost' IDENTIFIED BY '$password';
+EOF
+EOFF
+ else
+ password=""
+ cat <<-EOFF
+ mysql -u root <<-EOF
+ GRANT ALL PRIVILEGES ON $database.* to '$user'@'localhost';
+EOF
+EOFF
+ fi
+fi
diff --git a/conf/type/__mysql_database/man.text b/conf/type/__mysql_database/man.text
new file mode 100644
index 00000000..f184a30e
--- /dev/null
+++ b/conf/type/__mysql_database/man.text
@@ -0,0 +1,49 @@
+cdist-type__mysql_database(7)
+=============================
+Benedikt Koeppel
+
+
+NAME
+----
+cdist-type__mysql_database - Manage a MySQL database
+
+
+DESCRIPTION
+-----------
+This cdist type allows you to install a MySQL database.
+
+
+REQUIRED PARAMETERS
+-------------------
+None.
+
+OPTIONAL PARAMETERS
+-------------------
+name::
+ The name of the database to install
+ defaults to the object id
+
+user::
+ A user that should have access to the database
+
+password::
+ The password for the user who manages the database
+
+
+EXAMPLES
+--------
+
+--------------------------------------------------------------------------------
+__mysql_database "cdist" --name "cdist" --user "myuser" --password "mypwd"
+--------------------------------------------------------------------------------
+
+
+SEE ALSO
+--------
+- cdist-type(7)
+
+
+COPYING
+-------
+Copyright \(C) 2012 Benedikt Koeppel. Free use of this software is
+granted under the terms of the GNU General Public License version 3 (GPLv3).
diff --git a/conf/type/__mysql_database/parameter/optional b/conf/type/__mysql_database/parameter/optional
new file mode 100644
index 00000000..756afee7
--- /dev/null
+++ b/conf/type/__mysql_database/parameter/optional
@@ -0,0 +1,3 @@
+name
+user
+password
diff --git a/conf/type/__package_pkg_freebsd/explorer/pkg_version b/conf/type/__package_pkg_freebsd/explorer/pkg_version
index 4bca24b6..1335ba79 100755
--- a/conf/type/__package_pkg_freebsd/explorer/pkg_version
+++ b/conf/type/__package_pkg_freebsd/explorer/pkg_version
@@ -30,6 +30,10 @@ fi
# Don't produce "no pkgs installed" output -- breaks things
PKG_OUTPUT=$(pkg_info 2>&1)
if [ ! "$PKG_OUTPUT" = "pkg_info: no packages installed" ]; then
- echo "$(echo "$PKG_OUTPUT" | grep "^$name-" | cut '-d ' -f1 | sed "s/$name-//g")"
+ echo -n "$(echo "$PKG_OUTPUT" \
+ | awk '{print $1}' \
+ | sed 's/^\(.*\)-\([^-]*\)$/name:\1 ver:\2/g' \
+ | grep "name:$name ver:" \
+ | sed 's/^.*ver:\(.*\)/\1/g')"
fi
diff --git a/conf/type/__start_on_boot/explorer/state b/conf/type/__start_on_boot/explorer/state
index ff092a65..bf24738a 100755
--- a/conf/type/__start_on_boot/explorer/state
+++ b/conf/type/__start_on_boot/explorer/state
@@ -44,14 +44,13 @@ case "$os" in
done
;;
- debian|ubuntu)
+ debian|ubuntu|openwrt)
state="present"
[ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent"
;;
- centos|fedora|owl|redhat)
- state="present"
- state=$(chkconfig --level "$runlevel" \"$name\" || echo absent)
+ amazon|centos|fedora|owl|redhat)
+ state=$(chkconfig --level "$runlevel" "$name" || echo absent)
[ "$state" ] || state="present"
;;
diff --git a/conf/type/__start_on_boot/gencode-remote b/conf/type/__start_on_boot/gencode-remote
index be2bd98b..974abb30 100755
--- a/conf/type/__start_on_boot/gencode-remote
+++ b/conf/type/__start_on_boot/gencode-remote
@@ -43,10 +43,17 @@ case "$state_should" in
# echo rc-update add \"$name\" default
# ;;
- centos|fedora|owl|redhat)
+ amazon|centos|fedora|owl|redhat)
echo chkconfig \"$name\" on
;;
+ openwrt)
+ # 'enable' can be successful and still return a non-zero exit
+ # code, deal with it by checking for success ourselves in that
+ # case (the || ... part).
+ echo "/etc/init.d/\"$name\" enable || [ -f /etc/rc.d/S??\"$name\" ]"
+ ;;
+
*)
echo "Unsupported os: $os" >&2
exit 1
@@ -74,6 +81,10 @@ case "$state_should" in
echo chkconfig \"$name\" off
;;
+ openwrt)
+ echo "\"/etc/init.d/$name\" disable"
+ ;;
+
*)
echo "Unsupported os: $os" >&2
exit 1
diff --git a/doc/changelog b/doc/changelog
index dc498b9e..ce9f798b 100644
--- a/doc/changelog
+++ b/doc/changelog
@@ -4,12 +4,23 @@ Changelog
* Changes are always commented with their author in (braces)
* Exception: No braces means author == Nico Schottelius
-2.0.9:
+2.0.10:
+ * Cleanup __group: No getent gshadow in old Redhat, use groupmod -g
+ (Matt Coddington)
+
+2.0.9: 2012-03-12
* Cleanup documentation: Fix environment variable list to be properly
displayed (Giel van Schijndel)
+ * Cleanup documentation: Some minor corrections
* New Type: __package_opkg (Giel van Schijndel)
* New Type: __package_pkg_freebsd (Jake Guffey)
- * Feature __package: Support OpenWRT (Giel van Schijndel)
+ * New Type: __mysql_database (Benedikt Koeppel)
+ * Feature __package: Support for OpenWRT (Giel van Schijndel)
+ * Feature __start_on_boot: Support for OpenWRT (Giel van Schijndel)
+ * Feature __start_on_boot: Support for Amazon Linux (Matt Coddington)
+ * New Example: Use rsync to backup files (Matt Coddington)
+ * Feature core: Exit non-zero, if configuration failed
+ * Documentation: Describe how to do templating (Aurélien Bondis)
2.0.8: 2012-02-20
* Bugfix core: Remove another nasty traceback when sending SIGINT (aka Ctrl-C)
diff --git a/doc/dev/logs/2012-02-20.debug-jake-deps b/doc/dev/logs/2012-02-20.debug-jake-deps
new file mode 100644
index 00000000..2ae39f50
--- /dev/null
+++ b/doc/dev/logs/2012-02-20.debug-jake-deps
@@ -0,0 +1,8 @@
+require="__package/pkg-config" \
+ __package libxml2 --version "2.7.8_1" --state installed --pkgsite http://192.168.196.70
+
+Kein
+ INFO: www: Generating and executing code for __package_pkg_freebsd/libxml2
+
+für
+ __package/libxml2
diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME
index 3007cedb..1dd73d87 100644
--- a/doc/dev/todo/TAKEME
+++ b/doc/dev/todo/TAKEME
@@ -3,6 +3,10 @@ UNASSIGNED TODOS
The following list of todos has not been assigned to any developer.
Feel free to pick one!
+CORE
+----
+- support default parameter
+
TESTS
-----
- multiple defines of object:
@@ -38,3 +42,8 @@ TYPES
- __user
add option to include --create-home
- Merge __addifnosuchline and __removeline into __line + --state present|absent
+- __cron: Support --file to be used instead of user cron (probably direct support
+ of /etc/cron.d)
+
+- Support uci from openwrt?
+ - http://wiki.openwrt.org/doc/uci
diff --git a/doc/man/man1/cdist.text b/doc/man/man1/cdist.text
index 99c28f8b..e46e84a3 100644
--- a/doc/man/man1/cdist.text
+++ b/doc/man/man1/cdist.text
@@ -90,10 +90,20 @@ TMPDIR, TEMP, TMP::
more information. This is rather useful, if the standard
directory used does not allow executables.
+
+EXIT STATUS
+-----------
+The following exit values shall be returned:
+
+0::
+ Successful completion
+1::
+ One or more host configuration failed.
+
+
SEE ALSO
--------
- cdist(7)
-- cdist-type-emulator(1)
- cdist-reference(7)
diff --git a/doc/man/man7/cdist-best-practice.text b/doc/man/man7/cdist-best-practice.text
index bbfd084a..a8851f7f 100644
--- a/doc/man/man7/cdist-best-practice.text
+++ b/doc/man/man7/cdist-best-practice.text
@@ -153,6 +153,40 @@ implement this scenario with a gateway host and sudo:
For more details consult sudoers(5)
+TEMPLATING
+----------
+* create directory templates/ in your type (convention)
+* create the template as an executable file like templates/basic.conf.sh, it will output text using shell variables for the values
+
+--------------------------------------------------------------------------------------
+#!/bin/sh
+# in the template, use cat << eof (here document) to output the text
+# and use standard shell variables in the template
+# output everything in the template script to stdout
+cat << EOF
+server {
+ listen 80;
+ server_name $SERVERNAME;
+ root $ROOT;
+
+ access_log /var/log/nginx/$SERVERNAME_access.log
+ error_log /var/log/nginx/$SERVERNAME_error.log
+}
+EOF
+--------------------------------------------------------------------------------------
+
+* in the manifest, export the relevant variables and add the following lines in your manifest:
+--------------------------------------------------------------------------------------
+# export variables needed for the template
+ export SERVERNAME='test"
+ export ROOT='/var/www/test'
+# render the template
+ mkdir -p "$__object/files"
+ "$__type/templates/basic.conf.sh" > "$__object/files/basic.conf"
+# send the rendered template
+ __file /etc/nginx/sites-available/test.conf --state present --source "$__object/files/basic.conf"
+--------------------------------------------------------------------------------------
+
SEE ALSO
--------
- cdist(1)
diff --git a/doc/man/man7/cdist-hacker.text b/doc/man/man7/cdist-hacker.text
index 646439a3..ee88ca29 100644
--- a/doc/man/man7/cdist-hacker.text
+++ b/doc/man/man7/cdist-hacker.text
@@ -54,9 +54,9 @@ work nor kill the authors brain:
seperate branches. This way one feature can already be included, even if
the other needs to be improved.
-As soon as your work meets these requirements, you can contact me
-(IRC, Mailinglist, Phone, RFC 1149) and I'll check your code before
-including it.
+As soon as your work meets these requirements, write a mail
+for inclusion to the mailinglist **cdist at cdist -- at -- l.schottelius.org**
+or open a pull request at http://github.com/telmich/cdist.
HOW TO SUBMIT A NEW TYPE
@@ -75,6 +75,8 @@ code and thus such a type introduces redundant functionality that is given by
core cdist already.
+
+
SEE ALSO
--------
- cdist(7)
diff --git a/doc/man/man7/cdist-stages.text b/doc/man/man7/cdist-stages.text
index c1b73a8d..fa5e28d1 100644
--- a/doc/man/man7/cdist-stages.text
+++ b/doc/man/man7/cdist-stages.text
@@ -27,7 +27,7 @@ The initial manifest, which should be used for mappings of hosts to types,
is executed. This stage creates objects in a cconfig database that contains
the objects as defined in the manifest for the specific host. In this stage,
no conflicts may occur, i.e. no object of the same type with the same id may
-be created.
+be created, if it has different parameters.
STAGE 3: OBJECT INFORMATION RETRIEVAL
@@ -44,7 +44,7 @@ Every object is checked whether its type has a executable manifest. The
manifest script may generate and change the created objects. In other words,
one type can reuse other types.
-For instance the object __apache/www.test.ch is of type __apache, which may
+For instance the object __apache/www.example.org is of type __apache, which may
contain a manifest script, which creates new objects of type __file.
The newly created objects are merged back into the existing tree. No conflicts
diff --git a/doc/man/man7/cdist-type.text b/doc/man/man7/cdist-type.text
index 1147511e..92a2b36d 100644
--- a/doc/man/man7/cdist-type.text
+++ b/doc/man/man7/cdist-type.text
@@ -139,8 +139,8 @@ Always ensure the manifest is executable, otherwise cdist will not be able
to execute it. For more information about manifests see cdist-manifest(7).
-SINGLETON - ONLY INSTANCE ONLY
-------------------------------
+SINGLETON - ONE INSTANCE ONLY
+-----------------------------
If you want to ensure that a type can only be used once per target, you can
mark it as a singleton: Just create the (empty) file "singleton" in your type
directory:
@@ -186,10 +186,8 @@ WRITING THE GENCODE SCRIPT
There are two gencode scripts: ***gencode-local*** and ***gencode-remote***.
The output of gencode-local is executed locally, whereas
the output of gencode-remote is executed on the target.
-
The gencode scripts can make use of the parameters, the global explorers
-and the type specific explorers. The output (stdout) of these script is
-saved by cdist and will be executed on the target.
+and the type specific explorers.
If the gencode scripts encounter an error, it should print diagnostic
messages to stderr and exit non-zero. If you need to debug the gencode
@@ -224,17 +222,13 @@ never ever touch this folder).
HOW TO INCLUDE A TYPE INTO UPSTREAM CDIST
-----------------------------------------
If you think your type may be useful for others, ensure it works with the
-current master branch of cdist and submit the git url containing the type for
-inclusion to the mailinglist **cdist at cdist -- at -- l.schottelius.org**
-or open a pull request at http://github.com/telmich/cdist.
-
-Ensure a corresponding manpage named man.text in asciidoc format with
-the manpage-name "cdist-type__NAME" is included in the type directory.
-
+current master branch of cdist and have a look at cdist-hacker(7) on
+how to submit it.
SEE ALSO
--------
- cdist-explorer(7)
+- cdist-hacker(7)
- cdist-stages(7)
- cdist-tutorial(7)
diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py
index c1e16ffb..bd8e6483 100644
--- a/lib/cdist/__init__.py
+++ b/lib/cdist/__init__.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org)
+# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org)
#
# This file is part of cdist.
#
@@ -19,7 +19,7 @@
#
#
-VERSION = "2.0.8"
+VERSION = "2.0.9"
BANNER = """
.. . .x+=:. s
diff --git a/lib/cdist/banner.py b/lib/cdist/banner.py
index 4148fa72..edfa72e8 100644
--- a/lib/cdist/banner.py
+++ b/lib/cdist/banner.py
@@ -1,6 +1,6 @@
# -*- 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.
#
diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py
index 124c1b4f..11b8c78e 100644
--- a/lib/cdist/exec/remote.py
+++ b/lib/cdist/exec/remote.py
@@ -77,7 +77,12 @@ class Remote(object):
self.log.debug("Remote transfer: %s -> %s", source, destination)
self.rmdir(destination)
command = self._copy.split()
- command.extend(["-r", source, self.target_host + ":" + destination])
+ # support rsync by appending a "/" to the source if it's a directory
+ if os.path.isdir(source):
+ command.extend(["-r", source + "/", self.target_host + ":" + destination])
+ else:
+ command.extend(["-r", source, self.target_host + ":" + destination])
+
self._run_command(command)
def run_script(self, script, env=None, return_output=False):
diff --git a/other/examples/remote/rsync/copy b/other/examples/remote/rsync/copy
new file mode 100755
index 00000000..f6b93c5c
--- /dev/null
+++ b/other/examples/remote/rsync/copy
@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# 2012 Matt Coddington (mcoddington at gmail.com)
+#
+# 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 .
+#
+#
+# Use rsync over ssh to copy files. This particular invocation of
+# rsync makes a backup of the file before overwriting it. For example,
+# if cdist overwrites /etc/passwd then you'll end up with the old copy
+# at /etc/passwd~cdist.
+#
+# Usage:
+# __remote_copy="/path/to/this/script" cdist config target_host
+#
+
+rsync --backup --suffix=~cdist -e 'ssh -o User=root' $@
diff --git a/other/types_submitted_for_inclusion/.readmes/README.inclusion.specific b/other/types_submitted_for_inclusion/.readmes/README.inclusion.specific
index 0a1eb22e..3afdb7b4 100644
--- a/other/types_submitted_for_inclusion/.readmes/README.inclusion.specific
+++ b/other/types_submitted_for_inclusion/.readmes/README.inclusion.specific
@@ -2,6 +2,7 @@ Description:
Type that will probably only work in a very specific environnment
(like a specific distribution only).
+ or has custom code that may not satisfy the "usual" or generic use case.
Problem:
diff --git a/other/types_submitted_for_inclusion/__mysql_server/README.inclusion b/other/types_submitted_for_inclusion/__mysql_server/README.inclusion
new file mode 120000
index 00000000..573e1f5f
--- /dev/null
+++ b/other/types_submitted_for_inclusion/__mysql_server/README.inclusion
@@ -0,0 +1 @@
+../.readmes/README.inclusion.specific
\ No newline at end of file
diff --git a/other/types_submitted_for_inclusion/__mysql_server/files/my.cnf b/other/types_submitted_for_inclusion/__mysql_server/files/my.cnf
new file mode 100644
index 00000000..bd651c46
--- /dev/null
+++ b/other/types_submitted_for_inclusion/__mysql_server/files/my.cnf
@@ -0,0 +1 @@
+[client]
diff --git a/other/types_submitted_for_inclusion/__mysql_server/gencode-remote b/other/types_submitted_for_inclusion/__mysql_server/gencode-remote
new file mode 100755
index 00000000..4c160671
--- /dev/null
+++ b/other/types_submitted_for_inclusion/__mysql_server/gencode-remote
@@ -0,0 +1,93 @@
+#!/bin/sh
+#
+# 2012 Benedikt Koeppel (code@benediktkoeppel.ch)
+#
+# 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 .
+#
+#
+
+if [ -f "$__object/parameter/no_my_cnf" ]; then
+ no_my_cnf="$(cat "$__object/parameter/no_my_cnf")"
+else
+ no_my_cnf="false"
+fi
+
+if [ -f "$__object/parameter/password" ]; then
+ rootpassword="$(cat "$__object/parameter/password")"
+else
+ rootpassword=""
+fi
+
+
+if [ "$rootpassword" != "" ]; then
+ # to the database without requiring a passwort input
+ # set root password
+ echo "mysqladmin -u root password $rootpassword"
+
+ # if we don't want to overwrite the .my.cnf, then take a backup now
+ if [ "$no_my_cnf" == "true" ]; then
+ mv /root/.my.cnf /root/.my.cnf.cdist.bkp
+ fi
+
+ # store the root password in /root/.my.cnf so that processes can connect
+ cat <<-EOFF
+ cat <<-EOF > /root/.my.cnf
+ [client]
+ password=$rootpassword
+EOF
+EOFF
+
+
+
+ # remove anonymous users
+ cat <<-EOFF
+ mysql -u root <<-EOF
+ DELETE FROM mysql.user WHERE User='';
+EOF
+EOFF
+
+ # remove remote-access for root
+ cat <<-EOFF
+ mysql -u root <<-EOF
+ DELETE FROM mysql.user WHERE User='root' AND Host!='localhost';
+EOF
+EOFF
+
+ # remove test database
+ cat <<-EOFF
+ mysql -u root <<-EOF
+ DROP DATABASE IF EXISTS test;
+EOF
+EOFF
+ cat <<-EOFF
+ mysql -u root <<-EOF
+ DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%'
+EOF
+EOFF
+
+ # flush privileges
+ cat <<-EOFF
+ mysql -u root <<-EOF
+ FLUSH PRIVILEGES;
+EOF
+EOFF
+
+ # if we don't want to overwrite the .my.cnf, then restore the backup now
+ if [ "$no_my_cnf" == "true" ]; then
+ mv /root/.my.cnf.cdist.bkp /root/.my.cnf
+ fi
+
+fi
diff --git a/other/types_submitted_for_inclusion/__mysql_server/man.text b/other/types_submitted_for_inclusion/__mysql_server/man.text
new file mode 100644
index 00000000..f8573051
--- /dev/null
+++ b/other/types_submitted_for_inclusion/__mysql_server/man.text
@@ -0,0 +1,60 @@
+cdist-type__mysql_server(7)
+===========================
+Benedikt Koeppel
+
+
+NAME
+----
+cdist-type__mysql_server - Manage a MySQL server
+
+
+DESCRIPTION
+-----------
+This cdist type allows you to install a MySQL database server. The
+__mysql_server type also takes care of a few basic security tweaks that are
+normally done by running the mysql_secure_installation script that is provided
+with MySQL.
+
+
+REQUIRED PARAMETERS
+-------------------
+password::
+ The root password to set.
+
+
+OPTIONAL PARAMETERS
+-------------------
+no_my_cnf::
+ The /root/.my.cnf file is used to temporary store the root password when doing
+ the mysql_secure_installation. If you want to have your own .my.cnf file, then
+ specify --no_my_cnf "true".
+ Cdist will then place your original /root/.my.cnf back once cdist has run.
+
+
+EXAMPLES
+--------
+
+--------------------------------------------------------------------------------
+# to install a MySQL server
+__mysql_server
+
+# to install a MySQL server, remove remote access, remove test databases
+# similar to mysql_secure_installation, specify the root password
+__mysql_server --password "Uu9jooKe"
+# this will also write a /root/.my.cnf file
+
+# if you don't want cdist to write a /root/.my.cnf file permanently, specify
+# the --no_my_cnf option
+__mysql_server --password "Uu9jooKe" --no_my_cnf
+--------------------------------------------------------------------------------
+
+
+SEE ALSO
+--------
+- cdist-type(7)
+
+
+COPYING
+-------
+Copyright \(C) 2012 Benedikt Koeppel. Free use of this software is
+granted under the terms of the GNU General Public License version 3 (GPLv3).
diff --git a/other/types_submitted_for_inclusion/__mysql_server/manifest b/other/types_submitted_for_inclusion/__mysql_server/manifest
new file mode 100755
index 00000000..ce331998
--- /dev/null
+++ b/other/types_submitted_for_inclusion/__mysql_server/manifest
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# 2012 Benedikt Koeppel (code@benediktkoeppel.ch)
+#
+# 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 .
+#
+#
+
+# install mysql-server
+__package mysql-server --state installed
+
+if [ -f "$__object/parameter/no_my_cnf" ]; then
+ no_my_cnf="$(cat "$__object/parameter/no_my_cnf")"
+else
+ no_my_cnf="false"
+fi
+
+if [ -f "$__object/parameter/password" ]; then
+ rootpassword="$(cat "$__object/parameter/password")"
+else
+ rootpassword=""
+fi
+
+if [ "$no_my_cnf" != "true" -a "$rootpassword" != "" ]; then
+ # store the root password in /root/.my.cnf so that processes can connect
+ # to the database without requiring a passwort input
+ __file "/root/.my.cnf" --group root --owner root --mode 600
+fi
diff --git a/other/types_submitted_for_inclusion/__mysql_server/parameter/optional b/other/types_submitted_for_inclusion/__mysql_server/parameter/optional
new file mode 100644
index 00000000..4c40596c
--- /dev/null
+++ b/other/types_submitted_for_inclusion/__mysql_server/parameter/optional
@@ -0,0 +1,2 @@
+no_my_cnf
+password
diff --git a/other/types_submitted_for_inclusion/__mysql_server/parameter/required b/other/types_submitted_for_inclusion/__mysql_server/parameter/required
new file mode 100644
index 00000000..e69de29b
diff --git a/other/types_submitted_for_inclusion/__mysql_server/singleton b/other/types_submitted_for_inclusion/__mysql_server/singleton
new file mode 100644
index 00000000..e69de29b