diff --git a/README b/README index 1c2139cc..ff1293e8 100644 --- a/README +++ b/README @@ -53,8 +53,6 @@ UNIX, simplicity, familar environment | cdist is configured in POSIX shell The cdist documentation is included as manpages in the distribution. * You can [browse the documentation of the latest version online](man) as well. - * Or you can watch the youtube **video** -[cdist installation and first usage in less than 60 seconds][http://www.youtube.com/watch?v=PRMjzy48eTI). * Have a look at the [given speeches](speeches) ### OS support @@ -133,7 +131,7 @@ To install cdist, execute the following commands: export PATH=$PATH:$(pwd -P)/bin # If you want the manpages - ./build.sh man + ./build man export MANPATH=$MANPATH:$(pwd -P)/doc/man @@ -180,7 +178,7 @@ To upgrade cdist in the current branch use git pull # Also update the manpages - ./build.sh man + ./build man export MANPATH=$MANPATH:$(pwd -P)/doc/man If you stay on a version branche (i.e. 1.0, 1.1., ...), nothing should break. diff --git a/build b/build index 38fdac07..e3a6e7f9 100755 --- a/build +++ b/build @@ -26,13 +26,16 @@ # exit on any error #set -e +version=$(git describe) + # Manpage and HTML A2XM="a2x -f manpage --no-xmllint -a encoding=UTF-8" A2XH="a2x -f xhtml --no-xmllint -a encoding=UTF-8" # Developer webbase WEBDIR=$HOME/niconetz -WEBBASE=software/cdist +WEBBASE=$WEBDIR/software/cdist +WEBMAN=$WEBBASE/man/$version WEBPAGE=${WEBBASE}.mdwn # Documentation @@ -95,17 +98,18 @@ case "$1" in ;; web) - cp README ${WEBDIR}/${WEBPAGE} - rm -rf ${WEBDIR}/${WEBBASE}/man - mkdir -p ${WEBDIR}/${WEBBASE}/man/man1 ${WEBDIR}/${WEBBASE}/man/man7 + cp README ${WEBPAGE} + rm -rf ${WEBMAN} + mkdir -p ${WEBMAN}/man1 ${WEBMAN}/man7 - rm -rf ${WEBDIR}/${WEBBASE}/speeches && mkdir ${WEBDIR}/${WEBBASE}/speeches + # old stuff + # rm -rf ${WEBDIR}/${WEBBASE}/speeches && mkdir ${WEBDIR}/${WEBBASE}/speeches + # cp ${SPEECHESDIR}/*.pdf ${WEBDIR}/${WEBBASE}/speeches + # git describe > ${WEBDIR}/${WEBBASE}/man/VERSION - cp ${MAN1DSTDIR}/*.html ${WEBDIR}/${WEBBASE}/man/man1 - cp ${MAN7DSTDIR}/*.html ${WEBDIR}/${WEBBASE}/man/man7 - cp ${SPEECHESDIR}/*.pdf ${WEBDIR}/${WEBBASE}/speeches + cp ${MAN1DSTDIR}/*.html ${WEBMAN}/man1 + cp ${MAN7DSTDIR}/*.html ${WEBMAN}/man7 - git describe > ${WEBDIR}/${WEBBASE}/man/VERSION cd ${WEBDIR} && git add ${WEBBASE} cd ${WEBDIR} && git commit -m "cdist update" ${WEBBASE} ${WEBPAGE} cd ${WEBDIR} && make pub diff --git a/conf/explorer/os b/conf/explorer/os index e59301e7..1aafb468 100755 --- a/conf/explorer/os +++ b/conf/explorer/os @@ -49,7 +49,7 @@ if grep -q ^Fedora /etc/redhat-release 2>/dev/null; then exit 0 fi -# CentOS is also based on Redhat, this return before redhat! +# 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 diff --git a/conf/type/__addifnosuchline/explorer/findline b/conf/type/__addifnosuchline/explorer/findline index ac69a827..b45bd6ea 100755 --- a/conf/type/__addifnosuchline/explorer/findline +++ b/conf/type/__addifnosuchline/explorer/findline @@ -26,12 +26,18 @@ else file="/$__object_id" fi -regex=$(cat "$__object/parameter/line") +if [ -f "$__object/parameter/regex" ]; then + regex=$(cat "$__object/parameter/regex") +else + wrap=$(cat "$__object/parameter/line") + regex="^$wrap\$" +fi + if [ -f "$file" ]; then # sh -e is our environment, we know what we do, # skip error detection for now set +e - grep -q "^$regex\$" "$file" + grep -q "$regex" "$file" if [ $? -eq 1 ]; then echo "NOTFOUND" else diff --git a/conf/type/__addifnosuchline/man.text b/conf/type/__addifnosuchline/man.text index 722a3080..3051ff36 100644 --- a/conf/type/__addifnosuchline/man.text +++ b/conf/type/__addifnosuchline/man.text @@ -25,7 +25,9 @@ OPTIONAL PARAMETERS file:: If supplied, use this as the destination file. Otherwise the object_id is used. - +regex:: + If supplied, search for this regex. + Otherwise entire line must be matched. EXAMPLES -------- diff --git a/conf/type/__addifnosuchline/parameter/optional b/conf/type/__addifnosuchline/parameter/optional index f73f3093..7ecfcde9 100644 --- a/conf/type/__addifnosuchline/parameter/optional +++ b/conf/type/__addifnosuchline/parameter/optional @@ -1 +1,2 @@ file +regex diff --git a/conf/type/__apt_ppa/manifest b/conf/type/__apt_ppa/manifest index 5aa84931..04c66ce0 100755 --- a/conf/type/__apt_ppa/manifest +++ b/conf/type/__apt_ppa/manifest @@ -27,4 +27,4 @@ require="__package/python-software-properties" \ --source "$__type/files/remove-apt-repository" \ --mode 0755 -require="$__self" __apt_update_index +require="$__object_name" __apt_update_index diff --git a/conf/type/__autofs_map/manifest b/conf/type/__autofs_map/manifest index 74672e46..d86ea799 100755 --- a/conf/type/__autofs_map/manifest +++ b/conf/type/__autofs_map/manifest @@ -38,5 +38,5 @@ if [ -f "$__object/parameter/comment" ]; then fi echo "$entry" >> "$__object/parameter/entry" -require="$__self" __autofs_master +require="$__object_name" __autofs_master diff --git a/conf/type/__autofs_master/manifest b/conf/type/__autofs_master/manifest index e37a5d34..e429842e 100755 --- a/conf/type/__autofs_master/manifest +++ b/conf/type/__autofs_master/manifest @@ -24,7 +24,7 @@ if [ ! -f "$__object/parameter/header" ]; then fi [ -d "$__object/files" ] || mkdir "$__object/files" -require="$__self" __file /etc/auto.master --source "$__object/files/auto.master" \ +require="$__object_name" __file /etc/auto.master --source "$__object/files/auto.master" \ --mode 644 \ --owner root \ --group root diff --git a/conf/type/__package/manifest b/conf/type/__package/manifest index b331d32d..765ece36 100755 --- a/conf/type/__package/manifest +++ b/conf/type/__package/manifest @@ -49,4 +49,4 @@ for property in $(ls .); do fi done -require="$__self" __package_$type "$@" +require="$__object_name" __package_$type "$@" diff --git a/conf/type/__package_luarocks/explorer/pkg_status b/conf/type/__package_luarocks/explorer/pkg_status new file mode 100755 index 00000000..3eb73298 --- /dev/null +++ b/conf/type/__package_luarocks/explorer/pkg_status @@ -0,0 +1,31 @@ +#!/bin/sh +# +# 2012 SwellPath, Inc. +# Christian G. Warden +# +# 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 . +# +# Retrieve the status of a rock +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +# Accept luarocks failing if package is not known/installed +luarocks list "$name" | egrep -A1 "^$name$" || exit 0 diff --git a/conf/type/__package_luarocks/gencode-remote b/conf/type/__package_luarocks/gencode-remote new file mode 100755 index 00000000..179022b1 --- /dev/null +++ b/conf/type/__package_luarocks/gencode-remote @@ -0,0 +1,52 @@ +#!/bin/sh +# +# 2012 SwellPath, Inc. +# Christian G. Warden +# +# 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 . +# +# +# Manage LuaRocks packages +# + + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +state="$(cat "$__object/parameter/state")" +is_installed="$(grep "(installed)" "$__object/explorer/pkg_status" || true)" + +case "$state" in + installed) + # Install only if non-existent + if [ -z "$is_installed" ]; then + echo luarocks install \"$name\" + fi + ;; + removed) + # Remove only if existent + if [ -n "$is_installed" ]; then + echo luarocks remove \"$name\" + fi + ;; + *) + echo "Unknown state: $state" >&2 + exit 1 + ;; +esac diff --git a/conf/type/__package_luarocks/man.text b/conf/type/__package_luarocks/man.text new file mode 100644 index 00000000..6c1e6734 --- /dev/null +++ b/conf/type/__package_luarocks/man.text @@ -0,0 +1,49 @@ +cdist-type__package_luarocks(7) +============================== +Christian G. Warden + + +NAME +---- +cdist-type__package_luarocks - Manage luarocks packages + + +DESCRIPTION +----------- +LuaRocks is a deployment and management system for Lua modules. + + +REQUIRED PARAMETERS +------------------- +state:: + Either "installed" or "removed". + + +OPTIONAL PARAMETERS +------------------- +name:: + If supplied, use the name and not the object id as the package name. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure luasocket is installed +__package_luarocks luasocket --state installed + +# Remove package +__package_luarocks luasocket --state removed +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__package(7) + + +COPYING +------- +Copyright \(C) 2012 SwellPath, Inc. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/conf/type/__package_luarocks/manifest b/conf/type/__package_luarocks/manifest new file mode 100644 index 00000000..8e626714 --- /dev/null +++ b/conf/type/__package_luarocks/manifest @@ -0,0 +1,23 @@ +#!/bin/sh +# +# 2012 SwellPath, Inc. +# Christian G. Warden +# +# 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 . +# + +__package luarocks --state installed +__package make --state installed diff --git a/conf/type/__package_luarocks/parameter/optional b/conf/type/__package_luarocks/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/conf/type/__package_luarocks/parameter/optional @@ -0,0 +1 @@ +name diff --git a/conf/type/__package_luarocks/parameter/required b/conf/type/__package_luarocks/parameter/required new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/conf/type/__package_luarocks/parameter/required @@ -0,0 +1 @@ +state diff --git a/conf/type/__partition_msdos/manifest b/conf/type/__partition_msdos/manifest index 0d73c405..21e43856 100755 --- a/conf/type/__partition_msdos/manifest +++ b/conf/type/__partition_msdos/manifest @@ -38,4 +38,4 @@ if [ ! -f "$__object/parameter/size" ]; then fi # pull in the type that actually does something with the above parameters -require="$__self" __partition_msdos_apply +require="$__object_name" __partition_msdos_apply diff --git a/conf/type/__process/explorer/runs b/conf/type/__process/explorer/runs index 2bfa8f84..240ebef9 100755 --- a/conf/type/__process/explorer/runs +++ b/conf/type/__process/explorer/runs @@ -24,7 +24,7 @@ if [ -f "$__object/parameter/name" ]; then name="$(cat "$__object/parameter/name")" else - name="/$__object_id" + name="$__object_id" fi pgrep -x -f "$name" || true diff --git a/conf/type/__process/man.text b/conf/type/__process/man.text index fd3bcf49..065beeef 100644 --- a/conf/type/__process/man.text +++ b/conf/type/__process/man.text @@ -50,6 +50,10 @@ __process /usr/sbin/sshd --state stopped --stop "/etc/rc.d/sshd stop" # Ensure cups is running, which runs with -C ...: __process cups --start "/etc/rc.d/cups start" --state running \ --name "/usr/sbin/cupsd -C /etc/cups/cupsd.conf" + +# Ensure rpc.statd is running (which usually runs with -L) using a regexp +__process rpcstatd --state running --start "/etc/init.d/statd start" \ + --name "rpc.statd.*" -------------------------------------------------------------------------------- diff --git a/doc/changelog b/doc/changelog index 7217a6f2..7164e939 100644 --- a/doc/changelog +++ b/doc/changelog @@ -1,8 +1,16 @@ -2.0.4: +2.0.5: + * New Type: __package_luarocks (Christian G. Warden) + * Feature: __addifnosuchline supports matching on regular expressions (dan) + * Documentation: (Re)write of the tutorial + +2.0.4: 2011-11-18 * Bugfix core: Remove traceback when sending SIGINT (aka Ctrl-C) + * Bugfix core: Accept parameters with - in the name (Steven Armstrong) * Cleanup: __object_fq variable removed (never used) * Cleanup: Environment variable __self DEPRECATED, use __object_name instead * Cleanup: Environment variable __self scheduled for removal in cdist 2.1 + * Documentation: Many examples for use of __remote_* (Steven Armstrong) + * Feature: Automatically require all used objects (Steven Armstrong) * New Type: __cron (Steven Armstrong) 2.0.3: 2011-10-18 diff --git a/doc/dev/releasechecklist b/doc/dev/releasechecklist index fef1f53b..55d6221b 100755 --- a/doc/dev/releasechecklist +++ b/doc/dev/releasechecklist @@ -1,35 +1,50 @@ -#!/bin/sh -e +#!/bin/sh +# Nico Schottelius -files="bin/cdist-config doc/changelog" +files="doc/changelog lib/cdist/__init__.py" # Stuff to take care of when doing a release echo "Preparing next release" # Ensure documentation builds cleanly -./build.sh clean && ./build.sh man +echo "Testing documentation..." +./build clean && ./build man || exit 1 # get version -version=$(awk -F'=' '/^__cdist_version/ { print $2 }' bin/cdist-config | sed 's/"//g') +changelog_version=$(head -n1 doc/changelog | sed 's/:.*//') +#git_version=$(git describe) +lib_version=$(grep ^VERSION lib/cdist/__init__.py | sed -e 's/.*= //' -e 's/"//g') + +echo "Ensure you fixed/prepared version files: $files" +echo "changelog: $changelog_version" +#echo "git: $git_version" +echo "lib: $lib_version" + +if [ "$lib_version" != "$changelog_version" ]; then + echo "Messed up versions, not releasing" + exit 1 +else + echo "Versions are sane, continuing" +fi +echo "Press enter to continue" +read wait +version=$lib_version # get target branch branch=${version%.?} -# adjust version and release date -vi $files - -# Commit stuff -git commit $files - # add tag -printf "Enter description for %s>" "$version" +printf "Enter tag description for %s> " "$version" read tagmessage git tag "$version" -m "$tagmessage" # Import into current version branch +echo "git merge into $branch" git checkout $branch git merge master git checkout master # Publish manpages and sourcecode -./build.sh web -./build.sh pub +echo "publising doc/ and code/" +./build web +./build pub diff --git a/doc/dev/todo/TAKEME b/doc/dev/todo/TAKEME index f424a81d..be76b040 100644 --- a/doc/dev/todo/TAKEME +++ b/doc/dev/todo/TAKEME @@ -13,6 +13,10 @@ TESTS - multiple defines of object: - fail if different parameters - succeed if same parameters +- verify that all env variables in doc/man/cdist-reference.text.sh + exist in the right stages +- test DependencyResolver + USER INTERFACE -------------- diff --git a/doc/dev/todo/niconext b/doc/dev/todo/niconext index 2f9bb844..f8c2d6da 100644 --- a/doc/dev/todo/niconext +++ b/doc/dev/todo/niconext @@ -1,6 +1,10 @@ +- check speech publishing + - and speeches, which may be outdated as well + +- write tutorial + - Fix / rewrite cdist-quickstart -- write tutorial!!!!!!!!! - like ccollect! - include ssh control master! - add local/ hint (and add to git) diff --git a/doc/dev/todo/steven b/doc/dev/todo/steven index f8e13a45..2aacaa42 100644 --- a/doc/dev/todo/steven +++ b/doc/dev/todo/steven @@ -1,3 +1,10 @@ +autorequire: + - objects defined in type manifests should be automatically prerequisites of the current object + - __foo/some-id + __other other-id --state present + => require="__other/other-id" __foo/some-id + + metaparameters: - steal the metaparameters from puppet: diff --git a/doc/man/cdist-reference.text.sh b/doc/man/cdist-reference.text.sh index 9127096c..0a7b551e 100755 --- a/doc/man/cdist-reference.text.sh +++ b/doc/man/cdist-reference.text.sh @@ -188,9 +188,6 @@ __object_name:: __target_host:: The host we are deploying to. Available for: initial manifest, type manifest, type gencode -__target_user:: - User to use for authentication on remote host. - Currently static in core. __type:: Path to the current type. Available for: type manifest, type gencode diff --git a/doc/man/man7/cdist-tutorial.text b/doc/man/man7/cdist-tutorial.text index 65f3811c..577d633a 100644 --- a/doc/man/man7/cdist-tutorial.text +++ b/doc/man/man7/cdist-tutorial.text @@ -8,38 +8,137 @@ NAME cdist-tutorial - a guided introduction into cdist +INTRODUCTION +------------ +This tutorial is aimed at people learning cdist and shows +typical approaches as well as gives an easy start into +the world of configuration management. -PREPARING YOUR MACHINE / SETUP ------------------------------- - -- ensure sshd is running on the target host: - -ssh target_host - -- ensure you can login as root - -ssh root@target host - -- ensure login as root works without keys -(see ssh... manpage) - -cdist will do a lot of requests to the target -host, thus you'll have to enter your password -many times, if you don't do this :-) - -- speedup processing with ControlMaster option of -ssh +This tutorial assumes you are configuring **localhost**, because +it is always available. Just replace **localhost** with your target +host for real life usage. -YOUR FIRST CONFIGURATION ------------------------- + +QUICK START - GET YOUR HANDS DIRTY NOW +-------------------------------------- +For those who just want to configure a system with the +cdist configuration management and do not need (or want) +to understand everything. + +Cdist uses **ssh** for communication and transportation +and usually logs into the **target host** as the +**root** user. So you need to configure the **ssh server** +of the target host to allow root logins: Edit +the file **/etc/ssh/sshd_config** and add one of the following +lines: + +-------------------------------------------------------------------------------- +# Allow login only via public key +PermitRootLogin without-password + +# Allow login via password and public key +PermitRootLogin yes +-------------------------------------------------------------------------------- + +As cdist uses ssh intensively, it is recommended to setup authentication +with public keys: + +-------------------------------------------------------------------------------- +# Generate pubkey pair as a normal user +ssh-keygen + +# Copy pubkey over to target host +ssh-copy-id root@localhost +-------------------------------------------------------------------------------- + +Have a look at ssh-agent(1) and ssh-add(1) on how to cache the password for +your public key. Usually it looks like this: + +-------------------------------------------------------------------------------- +# Start agent and export variables +eval `ssh-agent` + +# Add keys (requires password for every identity file) +ssh-add +-------------------------------------------------------------------------------- + +At this point you should be able to ***ssh root@localhost*** without +re-entering the password. If something failed until here, ensure that +all steps went successfully and you have read and understood the +documentation. + +As soon as you are able to login without passwort to the target host, +we can use cdist to configure it. You can copy and paste the following +code into your shell to get started and configure localhost: + +-------------------------------------------------------------------------------- +# Get cdist +git clone git://git.schottelius.org/cdist + +# Create manifest (maps configuration to host(s) +cd cdist +echo '__file /etc/cdist-configured' > conf/manifest/init + +# Configure localhost in verbose mode +./bin/cdist config -v localhost + +# Find out that cdist created /etc/cdist-configured +ls -l /etc/cdist-configured +-------------------------------------------------------------------------------- + +That's it, you've successfully used cdist to configure your first host! +Continue reading the next sections, to understand what you did and how +to create a more sophisticated configuration. + +The file 'conf/manifest/init' is usually the entry point for cdist, +to find out what to configure on which host. All manifests are +essentially shell scripts. Every manifest can use the types known to +cdist, which are usually underline prefixed (__). -DEFINE STATE IN THE INITAL MANIFEST ------------------------------------ -The initial manifest is used to map -configurations to a host. +DEFINE STATE IN THE INITIAL MANIFEST +------------------------------------ +The **initial manifest** is the entry point for cdist to find out, which +**objects** to configure on the selected host. Objects are instances of +**types**, like in object orientated programming. An object is represented +by the type + slash + object name: ***__file/etc/cdist-configured*** is an +object of the type ***__file*** with the name ***etc/cdist-configured***. + +Cdist searches for the initial manifest at **conf/manifest/init** and +executes it as a shell script using **/bin/sh -e**. + +Within this initial manifest, you define, which objects should be +created on which host. To distinguish between hosts, you can use the +environment variable **__target_host**. Let's have a look at a simple +example: + +-------------------------------------------------------------------------------- +__file /etc/cdist-configured + +case "$__target_host" in + localhost) + __directory /home/services/kvm-vm --parents yes + ;; +esac +-------------------------------------------------------------------------------- + +This manifest says: Independent of the host, always create the (empty) file +***/etc/cdist-configured***, but create the directory ***/home/services/kvm-vm***, +including all parent directories, only on the host ***localhost***. + +As you can see, there is no magic involved, the manifest is simple shell code that +utilises cdist types. + + +PARTS BELOW HERE ARE TO-BE-DONE + + +MORE ABOUT TYPES AND OBJECTS +---------------------------- +All available types in cdist can be called like normal executables. + USING SOME BASIC TYPES ---------------------- @@ -71,128 +170,14 @@ __debug:: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -INTRODUCTION +BRANCHES IN HERE? ------------ -This tutorial is aimed at people learning cdist and shows -typical approaches as well as gives an easy start into -the world of configuration management. -This tutorial assumes you are configuring **localhost**, because -it is always available. Just repace **localhost** with your target -host for real life usage. +TUNING CDIST +------------ - - -QUICK START ------------ -For those who just want to configure a system with the -cdist configuration management and do not need (or want) -to understand everything. - -Cdist uses **ssh** for communication and transportation -and usually logs into the **target host** as the -**root** user. So you need to configure the **ssh server** -of the target host to allow root logins: Edit -the file **/etc/ssh/sshd_config** and add one of the following -lines: - --------------------------------------------------------------------------------- -# Allow login only via public key -PermitRootLogin without-password - -# Allow login via password and public key -PermitRootLogin yes --------------------------------------------------------------------------------- - -As cdist uses ssh intensively, it is recommended to setup authentication -with public keys: - --------------------------------------------------------------------------------- -# Generate pubkey pair as a normal user -ssh-keygen - -# Copy pubkey over to target host -ssh-copy-id root@localhost --------------------------------------------------------------------------------- - -As soon as you are able to login without passwort to the target host, -we can use cdist, to configure it. You can copy and paste the following -code into your shell to get started and configure localhost: - --------------------------------------------------------------------------------- -# Get cdist -git clone git://git.schottelius.org/cdist - -# Create manifest (maps configuration to host(s) -cd cdist -echo '__file /etc/cdist-configured' > conf/manifest/init -chmod 0700 conf/manifest/init - -# Configure localhost -./bin/cdist config localhost - -# Find out that cdist created /etc/cdist-configured -ls -l /etc/cdist-configured --------------------------------------------------------------------------------- - -The file 'conf/manifest/init' is usually the entry point for cdist, -to find out what to configure on which host. All manifests are -essentially shell scripts. Every manifest can use the types known to -cdist, which are usually underline prefixed (__). +- speedup processing with ControlMaster option of +ssh SEE ALSO diff --git a/lib/cdist/__init__.py b/lib/cdist/__init__.py index abdadf62..85892fec 100644 --- a/lib/cdist/__init__.py +++ b/lib/cdist/__init__.py @@ -34,7 +34,7 @@ BANNER = """ "P' "" "" """ DOT_CDIST = ".cdist" -VERSION = "2.0.3" +VERSION = "2.0.4" import os diff --git a/lib/cdist/emulator.py b/lib/cdist/emulator.py index 7ae89294..bb67e7ee 100644 --- a/lib/cdist/emulator.py +++ b/lib/cdist/emulator.py @@ -75,6 +75,7 @@ class Emulator(object): self.commandline() self.setup_object() self.record_requirements() + self.record_auto_requirements() self.log.debug("Finished %s %s" % (self.cdist_object.path, self.parameters)) def __init_log(self): @@ -97,10 +98,10 @@ class Emulator(object): for parameter in self.cdist_type.optional_parameters: argument = "--" + parameter - parser.add_argument(argument, action='store', required=False) + parser.add_argument(argument, dest=parameter, action='store', required=False) for parameter in self.cdist_type.required_parameters: argument = "--" + parameter - parser.add_argument(argument, action='store', required=True) + parser.add_argument(argument, dest=parameter, action='store', required=True) # If not singleton support one positional parameter if not self.cdist_type.is_singleton: @@ -181,3 +182,14 @@ class Emulator(object): # Record / Append source self.cdist_object.source.append(self.object_source) + + def record_auto_requirements(self): + """An object shall automatically depend on all objects that it defined in it's type manifest. + """ + # __object_name is the name of the object whose type manifest is currenlty executed + __object_name = os.environ.get('__object_name', None) + if __object_name: + _object = self.cdist_object.object_from_name(__object_name) + # prevent circular dependencies + if not _object.name in self.cdist_object.requirements: + _object.requirements.append(self.cdist_object.name) diff --git a/lib/cdist/exec/local.py b/lib/cdist/exec/local.py index 41094faa..613f5cf2 100644 --- a/lib/cdist/exec/local.py +++ b/lib/cdist/exec/local.py @@ -95,6 +95,12 @@ class Local(object): """ assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %s" % command self.log.debug("Local run: %s", command) + + if env is None: + env = os.environ.copy() + # Export __target_host for use in __remote_{copy,exec} scripts + env['__target_host'] = self.target_host + try: if return_output: return subprocess.check_output(command, env=env).decode() @@ -114,8 +120,13 @@ class Local(object): command.append(script) self.log.debug("Local run script: %s", command) - if env: - self.log.debug("Local run script env: %s", env) + + if env is None: + env = os.environ.copy() + # Export __target_host for use in __remote_{copy,exec} scripts + env['__target_host'] = self.target_host + + self.log.debug("Local run script env: %s", env) try: if return_output: diff --git a/lib/cdist/exec/remote.py b/lib/cdist/exec/remote.py index 433f4cbc..87db7273 100644 --- a/lib/cdist/exec/remote.py +++ b/lib/cdist/exec/remote.py @@ -91,7 +91,7 @@ class Remote(object): self.rmdir(destination) command = self._copy.split() command.extend(["-r", source, self.target_host + ":" + destination]) - self.run_command(command) + self._run_command(command) def run(self, command, env=None, return_output=False): """Run the given command with the given environment on the remote side. @@ -102,9 +102,9 @@ class Remote(object): cmd = self._exec.split() cmd.append(self.target_host) cmd.extend(command) - return self.run_command(cmd, env=env, return_output=return_output) + return self._run_command(cmd, env=env, return_output=return_output) - def run_command(self, command, env=None, return_output=False): + def _run_command(self, command, env=None, return_output=False): """Run the given command with the given environment. Return the output as a string. diff --git a/lib/cdist/test/emulator/__init__.py b/lib/cdist/test/emulator/__init__.py index 8f1b9776..5a660755 100644 --- a/lib/cdist/test/emulator/__init__.py +++ b/lib/cdist/test/emulator/__init__.py @@ -22,6 +22,7 @@ import os import shutil +import cdist from cdist import test from cdist.exec import local from cdist import emulator @@ -29,7 +30,6 @@ from cdist import core local_base_path = test.cdist_base_path - class EmulatorTestCase(test.CdistTestCase): def setUp(self): @@ -88,3 +88,67 @@ class EmulatorTestCase(test.CdistTestCase): emu = emulator.Emulator(argv) emu.run() # if we get here all is fine + + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') + +class AutoRequireEmulatorTestCase(test.CdistTestCase): + + def setUp(self): + self.temp_dir = self.mkdtemp() + self.target_host = 'localhost' + out_path = self.temp_dir + _local_base_path = fixtures + self.local = local.Local(self.target_host, _local_base_path, out_path) + self.local.create_directories() + self.local.link_emulator(cdist.test.cdist_exec_path) + self.manifest = core.Manifest(self.target_host, self.local) + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_autorequire(self): + initial_manifest = os.path.join(self.local.manifest_path, "init") + self.manifest.run_initial_manifest(initial_manifest) + cdist_type = core.Type(self.local.type_path, '__saturn') + cdist_object = core.Object(cdist_type, self.local.object_path, 'singleton') + self.manifest.run_type_manifest(cdist_object) + expected = ['__planet/Saturn', '__moon/Prometheus'] + self.assertEqual(sorted(cdist_object.requirements), sorted(expected)) + + +class ArgumentsWithDashesTestCase(test.CdistTestCase): + + def setUp(self): + self.temp_dir = self.mkdtemp() + self.target_host = 'localhost' + out_path = self.temp_dir + handle, self.script = self.mkstemp(dir=self.temp_dir) + os.close(handle) + _local_base_path = fixtures + self.local = local.Local(self.target_host, _local_base_path, out_path) + self.local.create_directories() + self.local.link_emulator(test.cdist_exec_path) + self.env = { + 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), + '__target_host': self.target_host, + '__global': self.local.out_path, + '__cdist_type_base_path': self.local.type_path, # for use in type emulator + '__manifest': self.local.manifest_path, + '__cdist_manifest': self.script, + } + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_arguments_with_dashes(self): + argv = ['__arguments_with_dashes', 'some-id', '--with-dash', 'some value'] + os.environ.update(self.env) + emu = emulator.Emulator(argv) + emu.run() + + cdist_type = core.Type(self.local.type_path, '__arguments_with_dashes') + cdist_object = core.Object(cdist_type, self.local.object_path, 'some-id') + self.assertTrue('with-dash' in cdist_object.parameters) diff --git a/lib/cdist/test/emulator/fixtures/conf/manifest/init b/lib/cdist/test/emulator/fixtures/conf/manifest/init new file mode 100755 index 00000000..9fa1aa53 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/manifest/init @@ -0,0 +1,3 @@ +#!/bin/sh + +__saturn diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__arguments_with_dashes/parameter/required b/lib/cdist/test/emulator/fixtures/conf/type/__arguments_with_dashes/parameter/required new file mode 100644 index 00000000..02fabce1 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__arguments_with_dashes/parameter/required @@ -0,0 +1 @@ +with-dash diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__moon/manifest b/lib/cdist/test/emulator/fixtures/conf/type/__moon/manifest new file mode 100755 index 00000000..362be5a1 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__moon/manifest @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ -f "$__object/parameter/name" ]; then + name="(cat "$__object/parameter/name")" +else + name="$__object_id" + echo "$name" > "$__object/parameter/name" +fi diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/optional b/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/optional @@ -0,0 +1 @@ +name diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/required b/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/required new file mode 100644 index 00000000..729a5167 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__moon/parameter/required @@ -0,0 +1 @@ +planet diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__planet/manifest b/lib/cdist/test/emulator/fixtures/conf/type/__planet/manifest new file mode 100755 index 00000000..362be5a1 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__planet/manifest @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ -f "$__object/parameter/name" ]; then + name="(cat "$__object/parameter/name")" +else + name="$__object_id" + echo "$name" > "$__object/parameter/name" +fi diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__planet/parameter/optional b/lib/cdist/test/emulator/fixtures/conf/type/__planet/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__planet/parameter/optional @@ -0,0 +1 @@ +name diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__saturn/manifest b/lib/cdist/test/emulator/fixtures/conf/type/__saturn/manifest new file mode 100755 index 00000000..38b8cbf3 --- /dev/null +++ b/lib/cdist/test/emulator/fixtures/conf/type/__saturn/manifest @@ -0,0 +1,4 @@ +#!/bin/sh + +__planet Saturn +require="__planet/Saturn" __moon Prometheus --planet Saturn diff --git a/lib/cdist/test/emulator/fixtures/conf/type/__saturn/singleton b/lib/cdist/test/emulator/fixtures/conf/type/__saturn/singleton new file mode 100644 index 00000000..e69de29b diff --git a/other/examples/remote/schroot-uri b/other/examples/remote/schroot-uri index 06dce369..a23277ec 100755 --- a/other/examples/remote/schroot-uri +++ b/other/examples/remote/schroot-uri @@ -49,7 +49,7 @@ my_name="${0##*/}" mode="$1"; shift log() { - #echo "$@" | logger -t "cdist-$my_name-$mode" + echo "$@" | logger -t "cdist-$my_name-$mode" : } @@ -112,7 +112,9 @@ fi case "$mode" in exec) - code="$exec_prefix schroot -c $schroot_name -- $@" + # In exec mode the first argument is the __target_host which we already got from env. Get rid of it. + shift + code="$exec_prefix schroot -c $schroot_name -- sh -c '$@'" ;; copy) # get directory for given chroot_name diff --git a/other/examples/types/__ethz_dinfk_ldap/README b/other/examples/types/__ethz_dinfk_ldap/README new file mode 100644 index 00000000..18c1574b --- /dev/null +++ b/other/examples/types/__ethz_dinfk_ldap/README @@ -0,0 +1,2 @@ +This type is used in production in the ETH and utilises a template to generate +the config file. diff --git a/other/examples/types/__ethz_dinfk_ldap/files/nslcd.conf.template b/other/examples/types/__ethz_dinfk_ldap/files/nslcd.conf.template new file mode 100755 index 00000000..d5b41c24 --- /dev/null +++ b/other/examples/types/__ethz_dinfk_ldap/files/nslcd.conf.template @@ -0,0 +1,46 @@ +#!/bin/sh +cat << DONE +# +# D-INFK SANS MANAGED FILE +# ======================== +# +# Do not change this file. Changes will be overwritten. +# + +# /etc/nslcd.conf +# nslcd configuration file. See nslcd.conf(5) +# for details. + +# The user and group nslcd should run as. +uid nslcd +gid nslcd + +# The location at which the LDAP server(s) should be reachable. +uri ldaps://ldaps01.ethz.ch +uri ldaps://ldaps02.ethz.ch +uri ldaps://ldaps03.ethz.ch + + +# The search base +base ou=${ou},ou=inf,ou=auth,o=ethz,c=ch +base passwd ou=users,ou=${ou},ou=inf,ou=auth,o=ethz,c=ch +base group ou=Group,ou=inf,ou=auth,o=ethz,c=ch +base netgroup ou=netgroup,ou=inf,ou=auth,o=ethz,c=ch + +binddn cn=REPLACE,ou=ME,ou=WITH,ou=YOUR,o=DETAILS,c=ch +bindpw VERYSECRETPASSWORD + +# The LDAP protocol version to use. +#ldap_version 3 + +# The DN to bind with for normal lookups. +#binddn cn=annonymous,dc=example,dc=net +#bindpw secret + +# SSL options +ssl on +tls_reqcert never + +# The search scope. +#scope sub +DONE diff --git a/other/examples/types/__ethz_dinfk_ldap/files/nsswitch.conf b/other/examples/types/__ethz_dinfk_ldap/files/nsswitch.conf new file mode 100644 index 00000000..f4185a86 --- /dev/null +++ b/other/examples/types/__ethz_dinfk_ldap/files/nsswitch.conf @@ -0,0 +1,22 @@ +# +# D-INFK SANS MANAGED FILE +# ======================== +# +# Do not change this file. Changes will be overwritten. +# +# /etc/nsswitch.conf +# + +passwd: files ldap +group: files ldap +shadow: files ldap + +hosts: files dns +networks: files + +services: db files +protocols: db files +rpc: db files +ethers: db files + +netgroup: files ldap diff --git a/other/examples/types/__ethz_dinfk_ldap/manifest b/other/examples/types/__ethz_dinfk_ldap/manifest new file mode 100755 index 00000000..c31d765d --- /dev/null +++ b/other/examples/types/__ethz_dinfk_ldap/manifest @@ -0,0 +1,39 @@ +#!/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 . +# +# +# Configure nss_ldap for a machine at DINFK. +# + +ou="$(cat "$__object/parameter/ou")" + +ldap_config="/etc/nslcd.conf" +ldap_package="libnss-ldapd" + +# Install required packages +__package "$ldap_package" --state installed + +# Generate nss-ldap config file from template +mkdir "$__object/files" +. "$__type/files/nslcd.conf.template" > "$__object/files/nslcd.conf" +__file "$ldap_config" --source "$__object/files/nslcd.conf" + +# Configure nsswitch to use ldap +require="__package/$ldap_package __file/$ldap_config" \ + __file /etc/nsswitch.conf --source "$__type/files/nsswitch.conf" diff --git a/other/examples/types/__ethz_dinfk_ldap/parameter/required b/other/examples/types/__ethz_dinfk_ldap/parameter/required new file mode 100644 index 00000000..d96c19d8 --- /dev/null +++ b/other/examples/types/__ethz_dinfk_ldap/parameter/required @@ -0,0 +1 @@ +ou diff --git a/other/examples/types/__ethz_dinfk_ldap/singleton b/other/examples/types/__ethz_dinfk_ldap/singleton new file mode 100644 index 00000000..e69de29b