diff --git a/.gitignore b/.gitignore index 6e2d4437..baf9b6f2 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,8 @@ cdist/version.py /cdist-*.tar.gz /pkg /src +build +.lock-* +.git-current-branch +.lock* +.pypi-release diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..1962c96e --- /dev/null +++ b/Makefile @@ -0,0 +1,254 @@ +# +# 2013 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 . +# +# + +A2XM=a2x -f manpage --no-xmllint -a encoding=UTF-8 +A2XH=a2x -f xhtml --no-xmllint -a encoding=UTF-8 +helper=./bin/build-helper + +MANDIR=docs/man +SPEECHDIR=docs/speeches +TYPEDIR=cdist/conf/type + +WEBSRCDIR=docs/web + +WEBDIR=$$HOME/www.nico.schottelius.org +WEBBLOG=$(WEBDIR)/blog +WEBBASE=$(WEBDIR)/software/cdist +WEBPAGE=$(WEBBASE).mdwn + +CHANGELOG_VERSION=$(shell $(helper) changelog-version) +CHANGELOG_FILE=docs/changelog + +PYTHON_VERSION=cdist/version.py + +################################################################################ +# Manpages +# +MAN1DSTDIR=$(MANDIR)/man1 +MAN7DSTDIR=$(MANDIR)/man7 + +# Manpages #1: Types +# Use shell / ls to get complete list - $(TYPEDIR)/*/man.text does not work +MANTYPESRC=$(shell ls $(TYPEDIR)/*/man.text) + +# replace first path component +MANTYPEPREFIX=$(subst $(TYPEDIR)/,$(MAN7DSTDIR)/cdist-type,$(MANTYPESRC)) + +# replace man.text with .7 or .html +MANTYPEMAN=$(subst /man.text,.7,$(MANTYPEPREFIX)) +MANTYPEHTML=$(subst /man.text,.html,$(MANTYPEPREFIX)) +MANTYPEALL=$(MANTYPEMAN) $(MANTYPEHTML) + +# Link manpage so A2XH does not create man.html but correct named file +$(MAN7DSTDIR)/cdist-type%.text: $(TYPEDIR)/%/man.text + ln -sf "../../../$^" $@ + +# Manpages #2: reference +MANREF=$(MAN7DSTDIR)/cdist-reference.text +MANREFSH=$(MANDIR)/cdist-reference.text.sh +MANREFMAN=$(MANREF:.text=.7) +MANREFHTML=$(MANREF:.text=.html) +MANREFALL=$(MANREFMAN) $(MANREFHTML) + +$(MANREF): $(MANREFSH) + $(MANREFSH) + +# Manpages #3: static pages +MAN1STATIC=$(shell ls $(MAN1DSTDIR)/*.text) +MAN7STATIC=$(shell ls $(MAN7DSTDIR)/*.text) +MANSTATICMAN=$(MAN1STATIC:.text=.1) $(MAN7STATIC:.text=.7) +MANSTATICHTML=$(MAN1STATIC:.text=.html) $(MAN7STATIC:.text=.html) +MANSTATICALL=$(MANSTATICMAN) $(MANSTATICHTML) + +# Manpages #4: generic part + +# Creating the type manpage +%.1 %.7: %.text + $(A2XM) $^ + +# Creating the type html page +%.html: %.text + $(A2XH) $^ + +man: $(MANTYPEALL) $(MANREFALL) $(MANSTATICALL) + +# Manpages #5: release part +MANWEBDIR=$(WEBBASE)/man/$(CHANGELOG_VERSION) + +man-dist: man check-date + rm -rf "${MANWEBDIR}" + mkdir -p "${MANWEBDIR}/man1" "${MANWEBDIR}/man7" + cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${MANWEBDIR}/man1 + cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${MANWEBDIR}/man7 + cd ${MANWEBDIR} && git add . && git commit -m "cdist manpages update: $(CHANGELOG_VERSION)" || true + +man-fix-link: web-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 "$(CHANGELOG_VERSION)" latest" + +################################################################################ +# Speeches +# +SPEECHESOURCES=$(SPEECHDIR)/*.tex +SPEECHES=$(SPEECHESOURCES:.tex=.pdf) +SPEECHESWEBDIR=$(WEBBASE)/speeches + +# Create speeches and ensure Toc is up-to-date +$(SPEECHDIR)/%.pdf: $(SPEECHDIR)/%.tex + pdflatex -output-directory $(SPEECHDIR) $^ + pdflatex -output-directory $(SPEECHDIR) $^ + pdflatex -output-directory $(SPEECHDIR) $^ + +speeches: $(SPEECHES) + +speeches-dist: speeches + rm -rf "${SPEECHESWEBDIR}" + mkdir -p "${SPEECHESWEBDIR}" + cp ${SPEECHES} "${SPEECHESWEBDIR}" + cd ${SPEECHESWEBDIR} && git add . && git commit -m "cdist speeches updated" || true + +################################################################################ +# Website +# + +BLOGFILE=$(WEBBLOG)/cdist-$(CHANGELOG_VERSION)-released.mdwn + +$(BLOGFILE): $(CHANGELOG_FILE) + $(helper) blog $(CHANGELOG_VERSION) $(BLOGFILE) + +web-blog: $(BLOGFILE) + +web-doc: + # Go to top level, because of cdist.mdwn + rsync -av "$(WEBSRCDIR)/" "${WEBBASE}/.." + cd "${WEBBASE}/.." && git add cdist* && git commit -m "cdist doc update" cdist* || true + +web-dist: web-blog web-doc + +web-pub: web-dist man-dist speeches-dist + cd "${WEBDIR}" && make pub + +web-release-all: man-fix-link + +################################################################################ +# Release: Mailinglist +# +ML_FILE=.lock-ml + +# Only send mail once - lock until new changelog things happened +$(ML_FILE): $(CHANGELOG_FILE) + $(helper) ml-release $(CHANGELOG_VERSION) + touch $@ + +ml-release: $(ML_FILE) + + +################################################################################ +# Release: Freecode +# +FREECODE_FILE=.lock-freecode + +$(FREECODE_FILE): $(CHANGELOG_FILE) + $(helper) freecode-release $(CHANGELOG_VERSION) + touch $@ + +freecode-release: $(FREECODE_FILE) + +################################################################################ +# pypi +# +PYPI_FILE=.pypi-release +$(PYPI_FILE): man $(PYTHON_VERSION) + python3 setup.py sdist upload + touch $@ + +pypi-release: $(PYPI_FILE) +################################################################################ +# archlinux +# +ARCHLINUX_FILE=.lock-archlinux +ARCHLINUXTAR=cdist-$(CHANGELOG_VERSION)-1.src.tar.gz + +$(ARCHLINUXTAR): PKGBUILD + makepkg -c --source + +PKGBUILD: PKGBUILD.in $(PYTHON_VERSION) + ./PKGBUILD.in $(CHANGELOG_VERSION) + +$(ARCHLINUX_FILE): $(ARCHLINUXTAR) $(PYTHON_VERSION) + burp -c system $(ARCHLINUXTAR) + touch $@ + +archlinux-release: $(ARCHLINUX_FILE) + +################################################################################ +# Release +# + +$(PYTHON_VERSION): .git/refs/heads/master + $(helper) version + +# Code that is better handled in a shell script +check-%: + $(helper) $@ + +release: + $(helper) $@ + +################################################################################ +# Cleanup +# + +clean: + rm -f $(MAN7DSTDIR)/cdist-reference.text + + find "$(MANDIR)" -mindepth 2 -type l \ + -o -name "*.1" \ + -o -name "*.7" \ + -o -name "*.html" \ + -o -name "*.xml" \ + | xargs rm -f + + find * -name __pycache__ | xargs rm -rf + + # Archlinux + rm -f cdist-*.pkg.tar.xz cdist-*.tar.gz + rm -rf pkg/ src/ + + rm -f MANIFEST PKGBUILD + rm -rf dist/ + +distclean: clean + rm -f cdist/version.py + +################################################################################ +# Misc +# + +# The pub is Nico's "push to all git remotes" way ("make pub") +pub: + for remote in "" github sf; do \ + echo "Pushing to $$remote"; \ + git push --mirror $$remote; \ + done + +test: + $(helper) $@ diff --git a/PKGBUILD.in b/PKGBUILD.in index 68bd6add..e3ae4619 100755 --- a/PKGBUILD.in +++ b/PKGBUILD.in @@ -1,6 +1,6 @@ #!/bin/sh -version=$(git describe) +version="$1" outfile=${0%.in} cat << eof > "${outfile}" diff --git a/bin/build-helper b/bin/build-helper new file mode 100755 index 00000000..bfd7d31c --- /dev/null +++ b/bin/build-helper @@ -0,0 +1,311 @@ +#!/bin/sh +# +# 2011-2013 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 . +# +# +# This file contains the heavy lifting found usually in the Makefile +# + +basedir=${0%/*}/../ +# Change to checkout directory +cd "$basedir" + +version=$(git describe) + +option=$1; shift + +case "$option" in + changelog-changes) + if [ "$#" -eq 1 ]; then + start=$1 + else + start="[[:digit:]]" + fi + + end="[[:digit:]]" + + awk -F: "BEGIN { start=0 } + { + if(start == 0) { + if (\$0 ~ /^$start/) { + start = 1 + } + } else { + if (\$0 ~ /^$end/) { + exit + } else { + print \$0 + } + } + }" "$basedir/docs/changelog" + ;; + + changelog-version) + # get version from changelog + grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/:.*//' + ;; + + check-date) + # verify date in changelog is today + date_today="$(date +%Y-%m-%d)" + date_changelog=$(grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/.*: //') + + if [ "$date_today" != "$date_changelog" ]; then + echo "Date in changelog is not today" + echo "Changelog: $date_changelog" + exit 1 + fi + ;; + + check-unittest) + "$0" test + ;; + + blog) + version=$1; shift + blogfile=$1; shift + dir=${blogfile%/*} + file=${blogfile##*/} + + + cat << eof > "$blogfile" +[[!meta title="Cdist $version released"]] + +Here's a short overview about the changes found in version ${version}: + +eof + + $0 changelog-changes "$version" >> "$blogfile" + + cat << eof >> "$blogfile" +For more information visit the [[cdist homepage|software/cdist]]. + +[[!tag cdist config unix]] +eof + cd "$dir" + git add "$file" + # Allow git commit to fail if there are no changes + git commit -m "cdist blog update: $version" "$blogfile" || true + ;; + + ml-release) + version=$1; shift + + to_a=cdist + to_d=l.schottelius.org + to=${to_a}@${to_d} + + from_a=nico-cdist + from_d=schottelius.org + from=${from_a}@${from_d} + + ( + cat << eof +From: Nico -telmich- Schottelius <$from> +To: cdist mailing list <$to> +Subject: cdist $version released + +Hello .*, + +cdist $version has been released with the following changes: + +eof + + "$0" changelog-changes "$version" + cat << eof + +Cheers, + +Nico + +-- +Automatisation at its best level. With cdist. +eof + ) | /usr/sbin/sendmail -f "$from" "$to" + ;; + + + freecode-release) + version=$1; shift + api_token=$(awk '/machine freecode login/ { print $8 }' ~/.netrc) + + printf "Enter tag list for freecode release %s> " "$version" + read taglist + + printf "Enter changelog for freecode release %s> " "$version" + read changelog + + echo "Submit preview" + cat << eof +tag_list = $taglist +changelog = $changelog +version = $version +eof + printf "Press enter to submit to freecode> " + read dummy + + cat << eof | cfreecode-api release-add cdist + { + "auth_code": "$api_token", + "release": { + "tag_list": "$taglist", + "version": "$version", + "changelog": "$changelog", + "hidden_from_frontpage": false + } + } +eof + + ;; + + release-git-tag) + target_version=$($0 changelog-version) + if git rev-parse --verify refs/tags/$target_version; then + echo "Tag for $target_version exists, aborting" + exit 1 + fi + printf "Enter tag description for ${target_version}: " + read tagmessage + git tag "$target_version" -m "$$tagmessage" + ;; + + release) + set -e + target_version=$($0 changelog-version) + target_branch=$($0 version-branch) + + echo "Beginning release process for $target_version" + + # First check everything is sane + "$0" check-date + "$0" check-unittest + + # Generate version file to be included in packaging + "$0" version + + # Ensure the git status is clean, else abort + if ! git diff-index --name-only --exit-code HEAD ; then + echo "Unclean tree, see files above, aborting" + exit 1 + fi + + # Ensure we are on the master branch + masterbranch=yes + if [ "$(git rev-parse --abbrev-ref HEAD)" != "master" ]; then + echo "Releases are happening from the master branch, aborting" + + echo "Enter the magic word to release anyway" + read magicword + + if [ "$magicword" = "iknowwhatido" ]; then + masterbranch=no + else + exit 1 + fi + fi + + if [ "$masterbranch" = yes ]; then + # Ensure version branch exists + if ! git rev-parse --verify refs/heads/$target_branch 2>/dev/null; then + git branch "$target_branch" + fi + + # Merge master branch into version branch + git checkout "$target_branch" + git merge master + fi + + # Verify that after the merge everything works + "$0" check-date + "$0" check-unittest + + # Generate man pages (indirect check if they build) + make man + + # Generate speeches (indirect check if they build) + make speeches + + ############################################################# + # Everything green, let's do the release + + # Tag the current commit + "$0" release-git-tag + + # Also merge back the version branch + if [ "$masterbranch" = yes ]; then + git checkout master + git merge "$target_branch" + fi + + # Publish git changes + make pub + + # publish man, speeches, website + make web-release-all + + # Ensure that pypi release has the right version + "$0" version + + # Create and publish package for pypi + make pypi-release + + # Archlinux release is based on pypi + make archlinux-release + + # Announce change on Freecode + make freecode-release + + # Announce change on ML + make ml-release + + cat << eof +Manual steps post release: + + - linkedin + - hackernews + - reddit + - twitter + +eof + + ;; + + test) + export PYTHONPATH="$(pwd -P)" + + if [ $# -lt 1 ]; then + python3 -m cdist.test + else + python3 -m unittest "$@" + fi + ;; + + version-branch) + "$0" changelog-version | cut -d. -f '1,2' + ;; + + version) + echo "VERSION = \"$(git describe)\"" > cdist/version.py + ;; + + *) + echo "Unknown helper target $@ - aborting" + exit 1 + ;; + +esac diff --git a/bin/cdist b/bin/cdist index dfe4fa00..645020a1 100755 --- a/bin/cdist +++ b/bin/cdist @@ -25,7 +25,7 @@ dir=${0%/*} # Ensure version is present - the bundled/shipped version contains a static version, # the git version contains a dynamic version -"$dir/../build" version +"$dir/build-helper" version libdir=$(cd "${dir}/../" && pwd -P) export PYTHONPATH="${libdir}" diff --git a/build b/build deleted file mode 100755 index 1f408b94..00000000 --- a/build +++ /dev/null @@ -1,414 +0,0 @@ -#!/bin/sh -# -# 2011-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 . -# -# -# Push a directory to a target, both sides have the same name (i.e. explorers) -# or -# Pull a directory from a target, both sides have the same name (i.e. explorers) -# - -# exit on any error -#set -e - -basedir=${0%/*} -version=$(cd "$basedir" && 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/www.nico.schottelius.org -WEBBLOG=$WEBDIR/blog -WEBTOPDIR=$WEBDIR/software -WEBBASE=$WEBTOPDIR/cdist -WEBMAN=$WEBBASE/man/$version -WEBPAGE=${WEBBASE}.mdwn - -# Documentation -MANDIR=docs/man -MAN1DSTDIR=${MANDIR}/man1 -MAN7DSTDIR=${MANDIR}/man7 -SPEECHESDIR=docs/speeches - -# Change to checkout directory -cd "$basedir" - -case "$1" in - man) - set -e - "$0" mangen - "$0" mantype - "$0" manbuild - ;; - - manbuild) - trap abort INT - abort() { - kill 0 - } - for section in 1 7; do - for src in ${MANDIR}/man${section}/*.text; do - manpage="${src%.text}.$section" - if [ ! -f "$manpage" -o "$manpage" -ot "$src" ]; then - echo "Compiling man page for $src" - $A2XM "$src" - fi - htmlpage="${src%.text}.html" - if [ ! -f "$htmlpage" -o "$htmlpage" -ot "$src" ]; then - echo "Compiling html page for $src" - $A2XH "$src" - fi - done - done - ;; - - mantype) - for mansrc in cdist/conf/type/*/man.text; do - dst="$(echo $mansrc | sed -e 's;cdist/conf/;cdist-;' -e 's;/;;' -e 's;/man;;' -e 's;^;docs/man/man7/;')" - ln -sf "../../../$mansrc" "$dst" - done - ;; - - mangen) - ${MANDIR}/cdist-reference.text.sh - ;; - - man-pub) - $0 man - - version=$($0 changelog-version) - - rm -rf "${WEBMAN}" - mkdir -p "${WEBMAN}/man1" "${WEBMAN}/man7" - cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${WEBMAN}/man1 - cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${WEBMAN}/man7 - cd ${WEBMAN} && git add . && git commit -m "Cdist Manpage update: $version" - ;; - - dist) - set -e - # Do the checks - $0 dist-check - - # Git changes - everything depends on this - $0 dist-tag - $0 dist-branch-merge - - # Pypi first - is the base for others - $0 dist-pypi - - # Archlinux depends on successful pypi ;-) - $0 dist-archlinux - - # Update website (includes documentation) - $0 web - - # Update manpages on website - $0 man-pub - - # update git repos - $0 pub - - $0 dist-blog - $0 dist-freecode - $0 dist-ml - $0 dist-manual - ;; - - changelog-changes) - awk -F: 'BEGIN { start=0 } { if ($0 ~ /^[[:digit:]]/) { if(start == 0) {start = 1 } else { exit } } else { if(start==1) {print $0 }} }' "$basedir/docs/changelog" - ;; - - changelog-version) - # get version from changelog and ensure it's not already present - grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/:.*//' - ;; - - dist-check) - set -e - echo "Verifying documentation building works ..." - $0 clean - $0 man - - changelog_version=$($0 changelog-version) - echo "Target version from changelog: $changelog_version" - - if git show --quiet $changelog_version >/dev/null 2>&1; then - echo "Version $changelog_version already exists, aborting." - exit 1 - fi - - # verify date in changelog - date_today="$(date +%Y-%m-%d)" - date_changelog=$(grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/.*: //') - - if [ "$date_today" != "$date_changelog" ]; then - echo "Date in changelog is not today" - echo "Changelog: $date_changelog" - exit 1 - fi - - ;; - - blog) - version=$($0 changelog-version) - blogfile=$WEBBLOG/cdist-${version}-released.mdwn - cat << eof > "$blogfile" -[[!meta title="Cdist $version released"]] - -Here's a short overview about the changes found in this release: - -eof - - $0 changelog-changes >> "$blogfile" - - cat << eof >> "$blogfile" -For more information visit the [[cdist homepage|software/cdist]]. - -[[!tag cdist config unix]] -eof - ;; - - dist-blog) - $0 blog - version=$($0 changelog-version) - file=cdist-${version}-released.mdwn - cd "$WEBBLOG" - git add "$file" - git commit -m "New cdist version (blogentry): $version" "$file" - git push - ;; - - dist-ml) - $0 blog - version=$($0 changelog-version) - to_a=cdist - to_d=l.schottelius.org - to=${to_a}@${to_d} - - from_a=nico-cdist - from_d=schottelius.org - from=${from_a}@${from_d} - - ( - cat << eof -From: Nico -telmich- Schottelius <$from> -To: cdist mailing list <$to> -Subject: cdist $version released - -Hello .*, - -cdist $version has been released with the following changes: - -eof - - "$0" changelog-changes - cat << eof - -Cheers, - -Nico - --- -Automatisation at its best level. With cdist. -eof - ) | /usr/sbin/sendmail -f "$from" "$to" - ;; - - - dist-manual) - cat << notes - - To be done manually... - - - linkedin entry -notes - - ;; - - dist-tag) - version=$($0 changelog-version) - # add tag - printf "Enter tag description for %s> " "$version" - read tagmessage - git tag "$version" -m "$tagmessage" - ;; - - dist-branch-merge) - version=$($0 changelog-version) - target_branch=${version%\.*} - current_branch=$(git rev-parse --abbrev-ref HEAD) - - if [ "$target_branch" = "$current_branch" ]; then - echo "Skipping merge, already on destination branch" - else - printf "Press enter to git merge $current_branch into \"$target_branch\" > " - read prompt - git checkout "$target_branch" - git merge "$current_branch" - git checkout "$current_branch" - fi - ;; - - dist-archlinux) - $0 dist-archlinux-makepkg - $0 dist-archlinux-aur-upload - ;; - - dist-archlinux-makepkg) - ./PKGBUILD.in - makepkg -c --source - ;; - - dist-archlinux-aur-upload) - version=$($0 changelog-version) - tar=cdist-${version}-1.src.tar.gz - burp -c system "$tar" - ;; - - dist-freecode) - version=$($0 changelog-version) - api_token=$(awk '/machine freecode login/ { print $8 }' ~/.netrc) - - printf "Enter tag list for freecode release %s> " "$version" - read taglist - - printf "Enter changelog for freecode release %s> " "$version" - read changelog - - echo "Submit preview" - cat << eof -tag_list = $taglist -changelog = $changelog -version = $version -eof - printf "Press enter to submit to freecode> " - read dummy - - cat << eof | cfreecode-api release-add cdist - { - "auth_code": "$api_token", - "release": { - "tag_list": "$taglist", - "version": "$version", - "changelog": "$changelog", - "hidden_from_frontpage": false - } - } -eof - - ;; - - dist-pypi) - $0 man - $0 version - python3 setup.py sdist upload - ;; - - speeches) - cd "$SPEECHESDIR" - for speech in *tex; do - pdflatex "$speech" - pdflatex "$speech" - pdflatex "$speech" - done - ;; - - web-doc) - rsync -av "${basedir}/docs/web/" "${WEBTOPDIR}" - - cd "${WEBDIR}" && git add "${WEBBASE}" - cd "${WEBDIR}" && git commit -m "cdist update" "${WEBBASE}" "${WEBPAGE}" - cd "${WEBDIR}" && make pub - ;; - - web) - set -e - "$0" web-doc - # 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) - for remote in "" github sf; do - echo "Pushing to $remote" - git push --mirror $remote - done - ;; - - clean) - rm -f ${MAN7DSTDIR}/cdist-reference.text - - find "${MANDIR}" -mindepth 2 -type l \ - -o -name "*.1" \ - -o -name "*.7" \ - -o -name "*.html" \ - -o -name "*.xml" \ - | xargs rm -f - - find * -name __pycache__ | xargs rm -rf - ;; - clean-dist) - rm -f cdist/version.py MANIFEST PKGBUILD - rm -rf cache/ dist/ - - # Archlinux - rm -f cdist-*.pkg.tar.xz cdist-*.tar.gz - rm -rf pkg/ src/ - ;; - - very-clean) - $0 clean - $0 clean-dist - ;; - - test) - shift # skip t - export PYTHONPATH="$(pwd -P)" - - if [ $# -lt 1 ]; then - python3 -m cdist.test - else - python3 -m unittest "$@" - fi - ;; - - version) - echo "VERSION=\"$version\"" > cdist/version.py - ;; - - *) - echo '' - echo 'Welcome to cdist!' - echo '' - echo 'Here are the possible targets:' - echo '' - echo ' clean: Remove build stuff' - echo ' man: Build manpages (requires Asciidoc)' - echo ' test: Run tests' - echo '' - echo '' - echo "Unknown target, \"$1\"" >&2 - exit 1 - ;; - -esac diff --git a/cdist/__init__.py b/cdist/__init__.py index 02d708b1..20c76b31 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -40,13 +40,20 @@ BANNER = """ "8888P' `"888*"" R888" ` ^"F 'Y" "P' "" "" """ + DOT_CDIST = ".cdist" +REMOTE_COPY = "scp -o User=root -q" +REMOTE_EXEC = "ssh -o User=root -q" class Error(Exception): """Base exception class for this project""" pass +class UnresolvableRequirementsError(cdist.Error): + """Resolving requirements failed""" + pass + class CdistObjectError(Error): """Something went wrong with an object""" diff --git a/cdist/conf/explorer/hostname b/cdist/conf/explorer/hostname index 2ae23759..7715c6b0 100755 --- a/cdist/conf/explorer/hostname +++ b/cdist/conf/explorer/hostname @@ -1,6 +1,6 @@ #!/bin/sh # -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2014 Nico Schottelius (nico-cdist at schottelius.org) # 2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. @@ -20,6 +20,6 @@ # # -if command -v hostname; then - hostname +if command -v uname >/dev/null; then + uname -n fi diff --git a/cdist/conf/explorer/machine b/cdist/conf/explorer/machine index bb6e0beb..d4a0e106 100755 --- a/cdist/conf/explorer/machine +++ b/cdist/conf/explorer/machine @@ -22,6 +22,6 @@ # # -if command -v uname; then +if command -v uname 2>&1 >/dev/null; then uname -m fi diff --git a/cdist/conf/explorer/os b/cdist/conf/explorer/os index e67d87ab..053177eb 100755 --- a/cdist/conf/explorer/os +++ b/cdist/conf/explorer/os @@ -88,6 +88,11 @@ if [ -f /etc/SuSE-release ]; then exit 0 fi +if [ -f /etc/slackware-version ]; then + echo slackware + exit 0 +fi + uname_s="$(uname -s)" # Assume there is no tr on the client -> do lower case ourselves diff --git a/cdist/conf/explorer/os_version b/cdist/conf/explorer/os_version index 8e6d37d3..50889429 100755 --- a/cdist/conf/explorer/os_version +++ b/cdist/conf/explorer/os_version @@ -54,6 +54,9 @@ case "$($__explorer/os)" in redhat|centos) cat /etc/redhat-release ;; + slackware) + cat /etc/slackware-version + ;; suse) cat /etc/SuSE-release ;; diff --git a/cdist/conf/type/__apt_key/explorer/state b/cdist/conf/type/__apt_key/explorer/state new file mode 100755 index 00000000..f7940741 --- /dev/null +++ b/cdist/conf/type/__apt_key/explorer/state @@ -0,0 +1,32 @@ +#!/bin/sh +# +# 2011-2014 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 . +# +# +# Get the current state of the apt key. +# + +if [ -f "$__object/parameter/keyid" ]; then + keyid="$(cat "$__object/parameter/keyid")" +else + keyid="$__object_id" +fi + +apt-key export "$keyid" | head -n 1 | grep -Fqe "BEGIN PGP PUBLIC KEY BLOCK" \ + && echo present \ + || echo absent diff --git a/cdist/conf/type/__apt_key/gencode-remote b/cdist/conf/type/__apt_key/gencode-remote new file mode 100755 index 00000000..c6ead91c --- /dev/null +++ b/cdist/conf/type/__apt_key/gencode-remote @@ -0,0 +1,42 @@ +#!/bin/sh +# +# 2011-2014 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 . +# + +if [ -f "$__object/parameter/keyid" ]; then + keyid="$(cat "$__object/parameter/keyid")" +else + keyid="$__object_id" +fi +state_should="$(cat "$__object/parameter/state")" +state_is="$(cat "$__object/explorer/state")" + +if [ "$state_should" = "$state_is" ]; then + # nothing to do + exit 0 +fi + +case "$state_should" in + present) + keyserver="$(cat "$__object/parameter/keyserver")" + echo "apt-key adv --keyserver \"$keyserver\" --recv-keys \"$keyid\"" + ;; + absent) + echo "apt-key del \"$keyid\"" + ;; +esac diff --git a/cdist/conf/type/__apt_key/man.text b/cdist/conf/type/__apt_key/man.text new file mode 100644 index 00000000..1a33e732 --- /dev/null +++ b/cdist/conf/type/__apt_key/man.text @@ -0,0 +1,61 @@ +cdist-type__apt_key(7) +====================== +Steven Armstrong + + +NAME +---- +cdist-type__apt_key - manage the list of keys used by apt + + +DESCRIPTION +----------- +Manages the list of keys used by apt to authenticate packages. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent'. Defaults to 'present' + +keyid:: + the id of the key to add. Defaults to __object_id + +keyserver:: + the keyserver from which to fetch the key. If omitted the default set in + ./parameter/default/keyserver is used. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Add Ubuntu Archive Automatic Signing Key +__apt_key 437D05B5 +# Same thing +__apt_key 437D05B5 --state present +# Get rid of it +__apt_key 437D05B5 --state absent + +# same thing with human readable name and explicit keyid +__apt_key UbuntuArchiveKey --keyid 437D05B5 + +# same thing with other keyserver +__apt_key UbuntuArchiveKey --keyid 437D05B5 --keyserver keyserver.ubuntu.com +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011-2014 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__apt_key/parameter/default/keyserver b/cdist/conf/type/__apt_key/parameter/default/keyserver new file mode 100644 index 00000000..f851282c --- /dev/null +++ b/cdist/conf/type/__apt_key/parameter/default/keyserver @@ -0,0 +1 @@ +subkeys.pgp.net diff --git a/cdist/conf/type/__apt_key/parameter/default/state b/cdist/conf/type/__apt_key/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__apt_key/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__apt_key/parameter/optional b/cdist/conf/type/__apt_key/parameter/optional new file mode 100644 index 00000000..18cf2586 --- /dev/null +++ b/cdist/conf/type/__apt_key/parameter/optional @@ -0,0 +1,3 @@ +state +keyid +keyserver diff --git a/cdist/conf/type/__apt_key_uri/explorer/state b/cdist/conf/type/__apt_key_uri/explorer/state new file mode 100755 index 00000000..15d6e653 --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/explorer/state @@ -0,0 +1,32 @@ +#!/bin/sh +# +# 2011-2014 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 . +# +# +# Get the current state of the apt key. +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +apt-key list | grep -Fqe "$name" \ + && echo present \ + || echo absent diff --git a/cdist/conf/type/__apt_key_uri/gencode-remote b/cdist/conf/type/__apt_key_uri/gencode-remote new file mode 100755 index 00000000..078b8695 --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/gencode-remote @@ -0,0 +1,45 @@ +#!/bin/sh +# +# 2011-2014 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 . +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi +state_should="$(cat "$__object/parameter/state")" +state_is="$(cat "$__object/explorer/state")" + +if [ "$state_should" = "$state_is" ]; then + # nothing to do + exit 0 +fi + +case "$state_should" in + present) + uri="$(cat "$__object/parameter/uri")" + printf 'curl -s -L "%s" | apt-key add -\n' "$uri" + ;; + absent) + cat << DONE +keyid=\$(apt-key list | grep -B1 "$name" | awk '/pub/ { print \$2 }' | cut -d'/' -f 2) +apt-key del \$keyid +DONE + ;; +esac diff --git a/cdist/conf/type/__apt_key_uri/man.text b/cdist/conf/type/__apt_key_uri/man.text new file mode 100644 index 00000000..fe9c3a25 --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/man.text @@ -0,0 +1,51 @@ +cdist-type__apt_key_uri(7) +========================== +Steven Armstrong + + +NAME +---- +cdist-type__apt_key_uri - add apt key from uri + + +DESCRIPTION +----------- +Download a key from an uri and add it to the apt keyring. + + +REQUIRED PARAMETERS +------------------- +uri:: + the uri from which to download the key + + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent', defaults to 'present' + +name:: + a name for this key, used when testing if it is already installed. + Defaults to __object_id + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__apt_key_uri rabbitmq \ + --name 'RabbitMQ Release Signing Key ' \ + --uri http://www.rabbitmq.com/rabbitmq-signing-key-public.asc \ + --state present +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011-2014 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__apt_key_uri/manifest b/cdist/conf/type/__apt_key_uri/manifest new file mode 100755 index 00000000..8dddde56 --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/manifest @@ -0,0 +1,21 @@ +#!/bin/sh +# +# 2013-2014 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 . +# + +__package curl diff --git a/cdist/conf/type/__apt_key_uri/parameter/default/state b/cdist/conf/type/__apt_key_uri/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__apt_key_uri/parameter/optional b/cdist/conf/type/__apt_key_uri/parameter/optional new file mode 100644 index 00000000..72c84b88 --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/parameter/optional @@ -0,0 +1,2 @@ +state +name diff --git a/cdist/conf/type/__apt_key_uri/parameter/required b/cdist/conf/type/__apt_key_uri/parameter/required new file mode 100644 index 00000000..c7954952 --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/parameter/required @@ -0,0 +1 @@ +uri diff --git a/cdist/conf/type/__apt_norecommends/man.text b/cdist/conf/type/__apt_norecommends/man.text new file mode 100644 index 00000000..3b65e72f --- /dev/null +++ b/cdist/conf/type/__apt_norecommends/man.text @@ -0,0 +1,42 @@ +cdist-type__apt_norecommends(7) +=============================== +Steven Armstrong + + +NAME +---- +cdist-type__apt_norecommends - configure apt to not install recommended packages + + +DESCRIPTION +----------- +Configure apt to not install any recommended or suggested packages. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__apt_norecommends +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2014 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__apt_norecommends/manifest b/cdist/conf/type/__apt_norecommends/manifest new file mode 100755 index 00000000..881c2427 --- /dev/null +++ b/cdist/conf/type/__apt_norecommends/manifest @@ -0,0 +1,42 @@ +#!/bin/sh +# +# 2014 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 . +# + + +os=$(cat "$__global/explorer/os") + +case "$os" in + ubuntu|debian) + # No stinking recommends thank you very much. + # If I want something installed I will do so myself. + __file /etc/apt/apt.conf.d/99-no-recommends \ + --owner root --group root --mode 644 \ + --source - << DONE +APT::Install-Recommends "0"; +APT::Install-Suggests "0"; +DONE + ;; + *) + cat >&2 << DONE +The developer of this type (${__type##*/}) did not think your operating system +($os) would have any use for it. If you think otherwise please submit a patch. +DONE + exit 1 + ;; +esac diff --git a/cdist/test/type/fixtures/__singleton/singleton b/cdist/conf/type/__apt_norecommends/singleton similarity index 100% rename from cdist/test/type/fixtures/__singleton/singleton rename to cdist/conf/type/__apt_norecommends/singleton diff --git a/cdist/conf/type/__apt_ppa/gencode-remote b/cdist/conf/type/__apt_ppa/gencode-remote index 0ea8011c..300a0e1e 100755 --- a/cdist/conf/type/__apt_ppa/gencode-remote +++ b/cdist/conf/type/__apt_ppa/gencode-remote @@ -22,7 +22,7 @@ name="$__object_id" state_should="$(cat "$__object/parameter/state")" state_is="$(cat "$__object/explorer/state")" -if [ "$state_should" == "$state_is" ]; then +if [ "$state_should" = "$state_is" ]; then # Nothing to do, move along exit 0 fi diff --git a/cdist/conf/type/__apt_ppa/man.text b/cdist/conf/type/__apt_ppa/man.text index 6a5990d5..da18e9f0 100644 --- a/cdist/conf/type/__apt_ppa/man.text +++ b/cdist/conf/type/__apt_ppa/man.text @@ -16,7 +16,8 @@ This cdist type allows manage ubuntu ppa repositories. REQUIRED PARAMETERS ------------------- state:: - The state the ppa should be in, either "present" or "absent". + The state the ppa should be in, either 'present' or 'absent'. + Defaults to 'present' OPTIONAL PARAMETERS @@ -29,6 +30,8 @@ EXAMPLES -------------------------------------------------------------------------------- # Enable a ppa repository +__apt_ppa ppa:sans-intern/missing-bits +# same as __apt_ppa ppa:sans-intern/missing-bits --state present # Disable a ppa repository @@ -43,5 +46,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is +Copyright \(C) 2011-2014 Steven Armstrong. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__apt_ppa/manifest b/cdist/conf/type/__apt_ppa/manifest index e7ad0c26..1d90e9c4 100755 --- a/cdist/conf/type/__apt_ppa/manifest +++ b/cdist/conf/type/__apt_ppa/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2014 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -20,9 +20,10 @@ name="$__object_id" -__package python-software-properties --state present +__package software-properties-common +__package python-software-properties -require="__package/python-software-properties" \ +require="__package/software-properties-common __package/python-software-properties" \ __file /usr/local/bin/remove-apt-repository \ --source "$__type/files/remove-apt-repository" \ --mode 0755 diff --git a/cdist/conf/type/__apt_ppa/parameter/default/state b/cdist/conf/type/__apt_ppa/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__apt_ppa/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__apt_ppa/parameter/required b/cdist/conf/type/__apt_ppa/parameter/optional similarity index 100% rename from cdist/conf/type/__apt_ppa/parameter/required rename to cdist/conf/type/__apt_ppa/parameter/optional diff --git a/cdist/conf/type/__apt_source/files/source.list.template b/cdist/conf/type/__apt_source/files/source.list.template new file mode 100755 index 00000000..d4420e96 --- /dev/null +++ b/cdist/conf/type/__apt_source/files/source.list.template @@ -0,0 +1,15 @@ +#!/bin/sh +set -u + +entry="$uri $distribution $component" +cat << DONE +# Created by cdist ${__type##*/} +# Do not change. Changes will be overwritten. +# + +# $name +deb ${forcedarch} $entry +DONE +if [ -f "$__object/parameter/include-src" ]; then + echo "deb-src $entry" +fi diff --git a/cdist/conf/type/__apt_source/man.text b/cdist/conf/type/__apt_source/man.text new file mode 100644 index 00000000..03b2b311 --- /dev/null +++ b/cdist/conf/type/__apt_source/man.text @@ -0,0 +1,69 @@ +cdist-type__apt_source(7) +========================= +Steven Armstrong + + +NAME +---- +cdist-type__apt_source - manage apt sources + + +DESCRIPTION +----------- +This cdist type allows you to manage apt sources. + + +REQUIRED PARAMETERS +------------------- +uri:: + the uri to the apt repository + + +OPTIONAL PARAMETERS +------------------- +arch:: + set this if you need to force and specific arch (ubuntu specific) + +state:: + 'present' or 'absent', defaults to 'present' + +distribution:: + the distribution codename to use. Defaults to DISTRIB_CODENAME from + the targets /etc/lsb-release + +component:: + space delimited list of components to enable. Defaults to an empty string. + + +BOOLEAN PARAMETERS +------------------ +include-src:: + include deb-src entries + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__apt_source rabbitmq \ + --uri http://www.rabbitmq.com/debian/ \ + --distribution testing \ + --component main \ + --include-src \ + --state present + +__apt_source canonical_partner \ + --uri http://archive.canonical.com/ \ + --component partner --state present +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2011-2014 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__apt_source/manifest b/cdist/conf/type/__apt_source/manifest new file mode 100755 index 00000000..0e782716 --- /dev/null +++ b/cdist/conf/type/__apt_source/manifest @@ -0,0 +1,56 @@ +#!/bin/sh +# +# 2011-2013 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 . +# + +name="$__object_id" +state="$(cat "$__object/parameter/state")" +uri="$(cat "$__object/parameter/uri")" + +if [ -f "$__object/parameter/distribution" ]; then + distribution="$(cat "$__object/parameter/distribution")" +else + distribution="$(cat "$__global/explorer/lsb_codename")" +fi +if [ -f "$__object/parameter/component" ]; then + component="$(cat "$__object/parameter/component")" +else + component="" +fi +if [ -f "$__object/parameter/arch" ]; then + forcedarch="[arch=$(cat "$__object/parameter/arch")]" +else + forcedarch="" +fi + +# export variables for use in template +export name +export uri +export distribution +export component +export forcedarch + +# generate file from template +mkdir "$__object/files" +"$__type/files/source.list.template" > "$__object/files/source.list" +__file "/etc/apt/sources.list.d/${name}.list" \ + --source "$__object/files/source.list" \ + --owner root --group root --mode 0644 \ + --state "$state" + +require="$__object_name" __apt_update_index diff --git a/cdist/conf/type/__apt_source/parameter/boolean b/cdist/conf/type/__apt_source/parameter/boolean new file mode 100644 index 00000000..8fa49177 --- /dev/null +++ b/cdist/conf/type/__apt_source/parameter/boolean @@ -0,0 +1 @@ +include-src diff --git a/cdist/conf/type/__apt_source/parameter/default/state b/cdist/conf/type/__apt_source/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__apt_source/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__apt_source/parameter/optional b/cdist/conf/type/__apt_source/parameter/optional new file mode 100644 index 00000000..87537335 --- /dev/null +++ b/cdist/conf/type/__apt_source/parameter/optional @@ -0,0 +1,4 @@ +state +distribution +component +arch \ No newline at end of file diff --git a/cdist/conf/type/__apt_source/parameter/required b/cdist/conf/type/__apt_source/parameter/required new file mode 100644 index 00000000..c7954952 --- /dev/null +++ b/cdist/conf/type/__apt_source/parameter/required @@ -0,0 +1 @@ +uri diff --git a/cdist/conf/type/__block/explorer/block b/cdist/conf/type/__block/explorer/block new file mode 100755 index 00000000..6c35bc46 --- /dev/null +++ b/cdist/conf/type/__block/explorer/block @@ -0,0 +1,21 @@ +#!/bin/sh +# 2013 Steven Armstrong (steven-cdist at armstrong.cc) + +file="$(cat "$__object/parameter/file" 2>/dev/null || echo "/$__object_id")" + +# file does not exist, nothing we could do +[ -f "$file" ] || exit 0 + +prefix=$(cat "$__object/parameter/prefix" 2>/dev/null || echo "#cdist:__block/$__object_id") +suffix=$(cat "$__object/parameter/suffix" 2>/dev/null || echo "#/cdist:__block/$__object_id") +awk -v prefix="$prefix" -v suffix="$suffix" '{ + if (index($0,prefix)) { + triggered=1 + } + if (triggered) { + if (index($0,suffix)) { + triggered=0 + } + print + } +}' "$file" diff --git a/cdist/conf/type/__block/gencode-remote b/cdist/conf/type/__block/gencode-remote new file mode 100755 index 00000000..0a5eea18 --- /dev/null +++ b/cdist/conf/type/__block/gencode-remote @@ -0,0 +1,84 @@ +#!/bin/sh +# +# 2013 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 . +# + +file="$(cat "$__object/parameter/file" 2>/dev/null || echo "/$__object_id")" +state_should=$(cat "$__object/parameter/state") +prefix=$(cat "$__object/parameter/prefix" 2>/dev/null || echo "#cdist:__block/$__object_id") +suffix=$(cat "$__object/parameter/suffix" 2>/dev/null || echo "#/cdist:__block/$__object_id") + +block="$__object/files/block" +if [ ! -s "$__object/explorer/block" ]; then + state_is='absent' +else + state_is=$(diff -q "$block" "$__object/explorer/block" >/dev/null \ + && echo present \ + || echo changed + ) +fi + +state_should="$(cat "$__object/parameter/state")" +if [ "$state_should" = "$state_is" ]; then + # Nothing to do, move along + exit 0 +fi + +remove_block() { + cat << DONE +tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) +# preserve ownership and permissions of existing file +if [ -f "$file" ]; then + cp -p "$file" "\$tmpfile" +fi +awk -v prefix="$prefix" -v suffix="$suffix" ' +{ + if (index(\$0,prefix)) { + triggered=1 + } + if (triggered) { + if (index(\$0,suffix)) { + triggered=0 + } + } else { + print + } +}' "$file" > "\$tmpfile" +mv -f "\$tmpfile" "$file" +DONE +} + +case "$state_should" in + present) + if [ "$state_is" = "changed" ]; then + echo update >> "$__messages_out" + remove_block + else + echo add >> "$__messages_out" + fi + cat << DONE +cat >> "$file" << ${__type##*/}_DONE +$(cat "$block") +${__type##*/}_DONE +DONE + ;; + absent) + echo remove >> "$__messages_out" + remove_block + ;; +esac diff --git a/cdist/conf/type/__block/man.text b/cdist/conf/type/__block/man.text new file mode 100644 index 00000000..2312d293 --- /dev/null +++ b/cdist/conf/type/__block/man.text @@ -0,0 +1,82 @@ +cdist-type__block(7) +==================== +Steven Armstrong + + +NAME +---- +cdist-type__block - Manage blocks of text in files + + +DESCRIPTION +----------- +Manage a block of text in an existing file. +The block is identified using the prefix and suffix parameters. +Everything between prefix and suffix is considered to be a managed block +of text. + + +REQUIRED PARAMETERS +------------------- +text:: + the text to manage. + If text is '-' (dash), take what was written to stdin as the text. + + +OPTIONAL PARAMETERS +------------------- +file:: + the file in which to manage the text block. + Defaults to object_id. + +prefix:: + the prefix to add before the text. + Defaults to #cdist:__block/$__object_id + +suffix:: + the prefix to add after the text. + Defaults to #/cdist:__block/$__object_id + +state:: + 'present' or 'absent', defaults to 'present' + + +MESSAGES +-------- +add:: + block was added +update:: + block was updated/changed +remove:: + block was removed + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# text from argument +__block /path/to/file \ + --prefix '#start' \ + --suffix '#end' \ + --text 'some\nblock of\ntext' + +# text from stdin +__block some-id \ + --file /path/to/file \ + --text - << DONE +here some block +of text +DONE +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2013 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__block/manifest b/cdist/conf/type/__block/manifest new file mode 100755 index 00000000..1fc9ec79 --- /dev/null +++ b/cdist/conf/type/__block/manifest @@ -0,0 +1,36 @@ +#!/bin/sh +# +# 2013-2014 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 . +# + + +file="$(cat "$__object/parameter/file" 2>/dev/null || echo "/$__object_id")" +prefix=$(cat "$__object/parameter/prefix" 2>/dev/null || echo "#cdist:__block/$__object_id") +suffix=$(cat "$__object/parameter/suffix" 2>/dev/null || echo "#/cdist:__block/$__object_id") +text=$(cat "$__object/parameter/text") + +mkdir "$__object/files" +# Generate text block for inclusion in file +block="$__object/files/block" +echo "$prefix" > "$block" +if [ "$text" = "-" ]; then + cat "$__object/stdin" >> "$block" +else + cat "$text" >> "$block" +fi +echo "$suffix" >> "$block" diff --git a/cdist/conf/type/__block/parameter/default/state b/cdist/conf/type/__block/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__block/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__block/parameter/optional b/cdist/conf/type/__block/parameter/optional new file mode 100644 index 00000000..fa3abebf --- /dev/null +++ b/cdist/conf/type/__block/parameter/optional @@ -0,0 +1,4 @@ +file +prefix +state +suffix diff --git a/cdist/conf/type/__block/parameter/required b/cdist/conf/type/__block/parameter/required new file mode 100644 index 00000000..8e27be7d --- /dev/null +++ b/cdist/conf/type/__block/parameter/required @@ -0,0 +1 @@ +text diff --git a/cdist/conf/type/__ccollect_source/explorer/cksum b/cdist/conf/type/__ccollect_source/explorer/cksum new file mode 100755 index 00000000..335e4e7a --- /dev/null +++ b/cdist/conf/type/__ccollect_source/explorer/cksum @@ -0,0 +1,34 @@ +#!/bin/sh +# +# 2011-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 . +# +# +# Retrieve the md5sum of a file to be created, if it is already existing. +# + +destination="/$__object_id" + +if [ -e "$destination" ]; then + if [ -f "$destination" ]; then + cksum < "$destination" + else + echo "NO REGULAR FILE" + fi +else + echo "NO FILE FOUND, NO CHECKSUM CALCULATED." +fi diff --git a/cdist/conf/type/__ccollect_source/explorer/stat b/cdist/conf/type/__ccollect_source/explorer/stat new file mode 100755 index 00000000..298221b7 --- /dev/null +++ b/cdist/conf/type/__ccollect_source/explorer/stat @@ -0,0 +1,47 @@ +#!/bin/sh +# +# 2013 Steven Armstrong (steven-cdist 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 . +# + +destination="/$__object_id" + +# nothing to work with, nothing we could do +[ -e "$destination" ] || exit 0 + +os=$("$__explorer/os") +case "$os" in + "freebsd") + # FIXME: should be something like this based on man page, but can not test + stat -f "type: %ST +owner: %Du %Su +group: %Dg %Sg +mode: %Op %Sp +size: %Dz +links: %Dl +" "$destination" + ;; + *) + stat --printf="type: %F +owner: %u %U +group: %g %G +mode: %a %A +size: %s +links: %h +" "$destination" + ;; +esac diff --git a/cdist/conf/type/__ccollect_source/explorer/type b/cdist/conf/type/__ccollect_source/explorer/type new file mode 100755 index 00000000..e723047c --- /dev/null +++ b/cdist/conf/type/__ccollect_source/explorer/type @@ -0,0 +1,33 @@ +#!/bin/sh +# +# 2013 Steven Armstrong (steven-cdist 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 . +# + +destination="/$__object_id" + +if [ ! -e "$destination" ]; then + echo none +elif [ -h "$destination" ]; then + echo symlink +elif [ -f "$destination" ]; then + echo file +elif [ -d "$destination" ]; then + echo directory +else + echo unknown +fi diff --git a/cdist/conf/type/__ccollect_source/gencode-remote b/cdist/conf/type/__ccollect_source/gencode-remote new file mode 100755 index 00000000..c41b5179 --- /dev/null +++ b/cdist/conf/type/__ccollect_source/gencode-remote @@ -0,0 +1,93 @@ +#!/bin/sh +# +# 2014 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 . +# + +destination="/$__object_id" +state_should="$(cat "$__object/parameter/state")" +type="$(cat "$__object/explorer/type")" +stat_file="$__object/explorer/stat" + + +get_current_value() { + if [ -s "$stat_file" ]; then + _name="$1" + _value="$2" + case "$_value" in + [0-9]*) + _index=2 + ;; + *) + _index=3 + ;; + esac + awk '/'"$_name"':/ { print $'$_index' }' "$stat_file" + unset _name _value _index + fi +} + +set_group() { + echo chgrp \"$1\" \"$destination\" + echo chgrp $1 >> "$__messages_out" +} + +set_owner() { + echo chown \"$1\" \"$destination\" + echo chown $1 >> "$__messages_out" +} + +set_mode() { + echo chmod \"$1\" \"$destination\" + echo chmod $1 >> "$__messages_out" +} + +set_attributes= +case "$state_should" in + present|exists) + # Note: Mode - needs to happen last as a chown/chgrp can alter mode by + # clearing S_ISUID and S_ISGID bits (see chown(2)) + for attribute in group owner mode; do + if [ -f "$__object/parameter/$attribute" ]; then + value_should="$(cat "$__object/parameter/$attribute")" + + # change 0xxx format to xxx format => same as stat returns + if [ "$attribute" = mode ]; then + value_should="$(echo $value_should | sed 's/^0\(...\)/\1/')" + fi + + value_is="$(get_current_value "$attribute" "$value_should")" + if [ -f "$__object/files/set-attributes" -o "$value_should" != "$value_is" ]; then + "set_$attribute" "$value_should" + fi + fi + done + + ;; + + absent) + if [ "$type" = "file" ]; then + echo rm -f \"$destination\" + echo remove >> "$__messages_out" + fi + ;; + + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__ccollect_source/man.text b/cdist/conf/type/__ccollect_source/man.text new file mode 100644 index 00000000..32a7467e --- /dev/null +++ b/cdist/conf/type/__ccollect_source/man.text @@ -0,0 +1,64 @@ +cdist-type__ccollect_source(7) +============================== +Nico Schottelius + + +NAME +---- +cdist-type__ccollect_source - Manage ccollect sources + + +DESCRIPTION +----------- +This cdist type allows you to create or delete ccollect sources. + +REQUIRED PARAMETERS +------------------- +source:: + The source from which to backup +destination:: + The destination directory + + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent', defaults to 'present' +ccollectconf:: + The CCOLLECT_CONF directory. Defaults to /etc/ccollect. + + +OPTIONAL MULTIPLE PARAMETERS +---------------------------- +exclude:: + Paths to exclude of backup + +BOOLEAN PARAMETERS +------------------ +verbose:: + Whether to report backup verbosely + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__ccollect_source doc.ungleich.ch \ + --source doc.ungleich.ch:/ \ + --destination /backup/doc.ungleich.ch \ + --exclude '/proc/*' --exclude '/sys/*' \ + --verbose + +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- ccollect(1) +- http://www.nico.schottelius.org/software/ccollect/ + + +COPYING +------- +Copyright \(C) 2014 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__ccollect_source/manifest b/cdist/conf/type/__ccollect_source/manifest new file mode 100755 index 00000000..89c2ef2b --- /dev/null +++ b/cdist/conf/type/__ccollect_source/manifest @@ -0,0 +1,53 @@ +#!/bin/sh +# +# 2014 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 . +# + +name="$__object_id" +state="$(cat "$__object/parameter/state")" +source="$(cat "$__object/parameter/source")" +destination="$(cat "$__object/parameter/destination")" +ccollectconf="$(cat "$__object/parameter/ccollectconf" | sed 's,/$,,')" + +sourcedir="$ccollectconf/sources" +basedir="$sourcedir/$name" + +destination_file="$basedir/destination" +source_file="$basedir/source" +exclude_file="$basedir/exclude" +verbose_file="$basedir/verbose" + +__directory "$basedir" --state "$state" + +export require="__directory$basedir" +echo "$destination" | __file "$destination_file" --source - --state "$state" +echo "$source" | __file "$source_file" --source - --state "$state" + +################################################################################ +# Booleans +if [ -f "$__object/parameter/verbose" ]; then + verbosestate="present" +else + verbosestate="absent" +fi +__file "$verbose_file" --state "$verbosestate" + +if [ -f "$__object/parameter/exclude" ]; then + __file "$exclude_file" --source - --state "$state" \ + < "$__object/parameter/exclude" +fi diff --git a/cdist/conf/type/__ccollect_source/parameter/boolean b/cdist/conf/type/__ccollect_source/parameter/boolean new file mode 100644 index 00000000..c00ee94a --- /dev/null +++ b/cdist/conf/type/__ccollect_source/parameter/boolean @@ -0,0 +1 @@ +verbose diff --git a/cdist/conf/type/__ccollect_source/parameter/default/ccollectconf b/cdist/conf/type/__ccollect_source/parameter/default/ccollectconf new file mode 100644 index 00000000..a9fda009 --- /dev/null +++ b/cdist/conf/type/__ccollect_source/parameter/default/ccollectconf @@ -0,0 +1 @@ +/etc/ccollect diff --git a/cdist/conf/type/__ccollect_source/parameter/default/state b/cdist/conf/type/__ccollect_source/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__ccollect_source/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__ccollect_source/parameter/optional b/cdist/conf/type/__ccollect_source/parameter/optional new file mode 100644 index 00000000..0249d11e --- /dev/null +++ b/cdist/conf/type/__ccollect_source/parameter/optional @@ -0,0 +1,2 @@ +ccollectconf +state diff --git a/cdist/conf/type/__ccollect_source/parameter/optional_multiple b/cdist/conf/type/__ccollect_source/parameter/optional_multiple new file mode 100644 index 00000000..9ba870ea --- /dev/null +++ b/cdist/conf/type/__ccollect_source/parameter/optional_multiple @@ -0,0 +1 @@ +exclude diff --git a/cdist/conf/type/__ccollect_source/parameter/required b/cdist/conf/type/__ccollect_source/parameter/required new file mode 100644 index 00000000..9239646e --- /dev/null +++ b/cdist/conf/type/__ccollect_source/parameter/required @@ -0,0 +1,2 @@ +source +destination diff --git a/cdist/conf/type/__cdist/man.text b/cdist/conf/type/__cdist/man.text new file mode 100644 index 00000000..0805598e --- /dev/null +++ b/cdist/conf/type/__cdist/man.text @@ -0,0 +1,63 @@ +cdist-type__cdist(7) +==================== +Nico Schottelius + + +NAME +---- +cdist-type__cdist - Manage cdist installations + + +DESCRIPTION +----------- +This cdist type allows you to easily setup cdist +on another box, to allow the other box to configure +systems. + +This type is *NOT* required by target hosts. +It is only helpful to build FROM which you configure +other hosts. + +This type will use git to clone + + +REQUIRED PARAMETERS +------------------- + +OPTIONAL PARAMETERS +------------------- +username:: + Select the user to create for the cdist installation. + Defaults to "cdist". + +source:: + Select the source from which to clone cdist from. + Defaults to "git://github.com/telmich/cdist.git". + + +branch:: + Select the branch to checkout from. + Defaults to "master". + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Install cdist for user cdist in her home as subfolder cdist +__cdist /home/cdist/cdist + +# Use alternative source +__cdist --source "git://git.schottelius.org/cdist" /home/cdist/cdist +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2013 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__cdist/manifest b/cdist/conf/type/__cdist/manifest new file mode 100755 index 00000000..7c0ae60e --- /dev/null +++ b/cdist/conf/type/__cdist/manifest @@ -0,0 +1,47 @@ +#!/bin/sh +# +# 2013 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 . +# +# + +directory="$__object_id" + +if [ -f "$__object/parameter/shell" ]; then + shell="--shell $(cat "$__object/parameter/shell")" +else + shell="" +fi + +username="$(cat "$__object/parameter/username")" + +branch="$(cat "$__object/parameter/branch")" + +source="$(cat "$__object/parameter/source")" + +# Currently hardcoded - if anyone cares, make a parameter +# out of it +home=/home/$username + +__user "$username" --home "$home" $shell + +require="__user/$username" __directory "$home" \ + --owner "$username" + +require="__user/$username __directory/$home" __git "$directory" \ + --source "$source" \ + --owner "$username" --branch "$branch" diff --git a/cdist/conf/type/__cdist/parameter/default/branch b/cdist/conf/type/__cdist/parameter/default/branch new file mode 100644 index 00000000..1f7391f9 --- /dev/null +++ b/cdist/conf/type/__cdist/parameter/default/branch @@ -0,0 +1 @@ +master diff --git a/cdist/conf/type/__cdist/parameter/default/source b/cdist/conf/type/__cdist/parameter/default/source new file mode 100644 index 00000000..d669308f --- /dev/null +++ b/cdist/conf/type/__cdist/parameter/default/source @@ -0,0 +1 @@ +git://github.com/telmich/cdist.git diff --git a/cdist/conf/type/__cdist/parameter/default/username b/cdist/conf/type/__cdist/parameter/default/username new file mode 100644 index 00000000..a585e141 --- /dev/null +++ b/cdist/conf/type/__cdist/parameter/default/username @@ -0,0 +1 @@ +cdist diff --git a/cdist/conf/type/__cdist/parameter/optional b/cdist/conf/type/__cdist/parameter/optional new file mode 100644 index 00000000..a5f14343 --- /dev/null +++ b/cdist/conf/type/__cdist/parameter/optional @@ -0,0 +1,4 @@ +branch +source +username +shell diff --git a/cdist/conf/type/__cron/explorer/entry b/cdist/conf/type/__cron/explorer/entry old mode 100755 new mode 100644 index 1b4bec42..c3bf02d2 --- a/cdist/conf/type/__cron/explorer/entry +++ b/cdist/conf/type/__cron/explorer/entry @@ -1,6 +1,7 @@ #!/bin/sh # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) +# 2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,22 +19,7 @@ # along with cdist. If not, see . # -name="$__object_id" +name="$__object_name" user="$(cat "$__object/parameter/user")" -prefix="#cdist:__cron/$name" -suffix="#/cdist:__cron/$name" - -crontab -u $user -l 2>/dev/null | awk -v prefix="$prefix" -v suffix="$suffix" ' -{ - if (index($0,prefix)) { - triggered=1 - } - if (triggered) { - if (index($0,suffix)) { - triggered=0 - } - print - } -} -' +crontab -u $user -l 2>/dev/null | grep "# $name\$" || true diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote index 37e0dc15..77a63b9b 100755 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -1,6 +1,8 @@ #!/bin/sh # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Thomas Oettli (otho at sfs.biz) # # This file is part of cdist. # @@ -18,40 +20,47 @@ # along with cdist. If not, see . # -os="$(cat "$__global/explorer/os")" +name="$__object_name" user="$(cat "$__object/parameter/user")" -state_should="$(cat "$__object/parameter/state")" -state_is=$(diff -q "$__object/parameter/entry" "$__object/explorer/entry" \ - && echo present \ - || echo absent -) +command="$(cat "$__object/parameter/command")" -# FreeBSD mktemp doesn't allow execution without at least one param -if [ "$os" = "freebsd" ]; then - mktemp="mktemp -t tmp" +if [ -f "$__object/parameter/raw" ]; then + raw="$(cat "$__object/parameter/raw")" + entry="$raw $command" +elif [ -f "$__object/parameter/raw_command" ]; then + entry="$command" else - mktemp="mktemp" + 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 -if [ "$state_is" != "$state_should" ]; then - case "$state_should" in - present) - cat << DONE -tmp=\$($mktemp) -crontab -u $user -l > \$tmp -cat >> \$tmp << EOC -$(cat "$__object/parameter/entry") -EOC -crontab -u $user \$tmp -rm \$tmp -DONE - ;; - absent) - # defined in type manifest - prefix="$(cat "$__object/parameter/prefix")" - suffix="$(cat "$__object/parameter/suffix")" - cat << DONE -crontab -u $user -l | awk -v prefix="$prefix" -v suffix="$suffix" ' +entry="$entry # $name" +mkdir "$__object/files" +echo "$entry" > "$__object/files/entry" + +if diff -q "$__object/files/entry" "$__object/explorer/entry" >/dev/null; then + state_is=present +else + state_is=absent +fi + +state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" + +[ "$state_is" = "$state_should" ] && exit 0 + +# If anything is going to change, ensure the old entries are +# not present anymore + +# These are the old markers +prefix="#cdist:__cron/$__object_id" +suffix="#/cdist:__cron/$__object_id" +filter="^# DO NOT EDIT THIS FILE|^# \(.* installed on |^# \(Cron version V" +cat << DONE +crontab -u $user -l 2>/dev/null | grep -v -E "$filter" | awk -v prefix="$prefix" -v suffix="$suffix" ' { if (index(\$0,prefix)) { triggered=1 @@ -66,6 +75,17 @@ crontab -u $user -l | awk -v prefix="$prefix" -v suffix="$suffix" ' } ' | crontab -u $user - DONE - ;; - esac -fi + +case "$state_should" in + present) + # if we insert new entry, filter also all entrys out with the same id + echo "(" + echo "crontab -u $user -l 2>/dev/null | grep -v -E \"$filter\" | grep -v \"# $name\\$\" 2>/dev/null || true" + echo "echo '$entry'" + echo ") | crontab -u $user -" + ;; + absent) + echo "( crontab -u $user -l 2>/dev/null | grep -v -E \"$filter\" 2>/dev/null || true ) | \\" + echo "grep -v \"# $name\\$\" | crontab -u $user -" + ;; +esac diff --git a/cdist/conf/type/__cron/man.text b/cdist/conf/type/__cron/man.text index 47f47456..f4e80a08 100644 --- a/cdist/conf/type/__cron/man.text +++ b/cdist/conf/type/__cron/man.text @@ -41,6 +41,10 @@ raw:: 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. +raw_command:: + Take whatever the user has given in the commmand and ignore everything else. + If given, the command will be added to crontab. + Can for example be used to define variables like SHELL or MAILTO. EXAMPLES @@ -57,6 +61,10 @@ __cron some-id --user root --command "/path/to/script" \ # remove cronjob __cron some-id --user root --command "/path/to/script" --state absent + +# define default shell +__cron some-id --user root --raw_command --command "SHELL=/bin/bash" \ + --state present -------------------------------------------------------------------------------- @@ -68,5 +76,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is +Copyright \(C) 2011-2013 Steven Armstrong. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__cron/manifest b/cdist/conf/type/__cron/manifest old mode 100755 new mode 100644 index 7aca41ff..9992df25 --- a/cdist/conf/type/__cron/manifest +++ b/cdist/conf/type/__cron/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2013 Thomas Oettli (otho at sfs.biz) # # This file is part of cdist. # @@ -18,28 +18,7 @@ # along with cdist. If not, see . # -name="$__object_id" -user="$(cat "$__object/parameter/user")" -command="$(cat "$__object/parameter/command")" - -# set defaults -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="$(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" +if [ -f "$__object/parameter/raw" ] && [ -f "$__object/parameter/raw_command" ]; then + echo "ERROR: both raw and raw_command specified" >&2 + exit 1 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 "$entry" >> "$__object/parameter/entry" -echo "$suffix" | tee "$__object/parameter/suffix" >> "$__object/parameter/entry" diff --git a/cdist/conf/type/__cron/parameter/boolean b/cdist/conf/type/__cron/parameter/boolean new file mode 100644 index 00000000..54cfb0b3 --- /dev/null +++ b/cdist/conf/type/__cron/parameter/boolean @@ -0,0 +1 @@ +raw_command diff --git a/cdist/conf/type/__debconf_set_selections/gencode-remote b/cdist/conf/type/__debconf_set_selections/gencode-remote index 62be6a12..bb719c46 100755 --- a/cdist/conf/type/__debconf_set_selections/gencode-remote +++ b/cdist/conf/type/__debconf_set_selections/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -21,6 +21,12 @@ # Setup selections # +filename="$(cat "$__object/parameter/file")" + +if [ "$filename" = "-" ]; then + filename="$__object/stdin" +fi + echo "debconf-set-selections << __file-eof" -cat "$(cat "$__object/parameter/file")" +cat "$filename" echo "__file-eof" diff --git a/cdist/conf/type/__debconf_set_selections/man.text b/cdist/conf/type/__debconf_set_selections/man.text index b6b2ad18..e36ebaa3 100644 --- a/cdist/conf/type/__debconf_set_selections/man.text +++ b/cdist/conf/type/__debconf_set_selections/man.text @@ -17,7 +17,8 @@ to setup configuration parameters. REQUIRED PARAMETERS ------------------- file:: - If supplied, use the given filename as input for debconf-set-selections(1) + Use the given filename as input for debconf-set-selections(1) + If filename is "-", read from stdin. EXAMPLES @@ -29,15 +30,21 @@ __debconf_set_selections nslcd --file /path/to/file # Setup configuration for nslcd from another type __debconf_set_selections nslcd --file "$__type/files/preseed/nslcd" + +__debconf_set_selections nslcd --file - << eof +gitolite gitolite/gituser string git +eof -------------------------------------------------------------------------------- SEE ALSO -------- - cdist-type(7) +- cdist-type__update_alternatives(7) +- debconf-set-selections(1) COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is +Copyright \(C) 2011-2014 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat new file mode 100755 index 00000000..d8cdbb9e --- /dev/null +++ b/cdist/conf/type/__directory/explorer/stat @@ -0,0 +1,43 @@ +#!/bin/sh +# +# 2013 Steven Armstrong (steven-cdist 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 . +# + +destination="/$__object_id" + +# nothing to work with, nothing we could do +[ -e "$destination" ] || exit 0 + +os=$("$__explorer/os") +case "$os" in + "freebsd") + # FIXME: should be something like this based on man page, but can not test + stat -f "type: %ST +owner: %Du %Su +group: %Dg %Sg +mode: %Op %Sp +" "$destination" + ;; + *) + stat --printf="type: %F +owner: %u %U +group: %g %G +mode: %a %A +" "$destination" + ;; +esac diff --git a/cdist/conf/type/__directory/explorer/type b/cdist/conf/type/__directory/explorer/type new file mode 100755 index 00000000..e723047c --- /dev/null +++ b/cdist/conf/type/__directory/explorer/type @@ -0,0 +1,33 @@ +#!/bin/sh +# +# 2013 Steven Armstrong (steven-cdist 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 . +# + +destination="/$__object_id" + +if [ ! -e "$destination" ]; then + echo none +elif [ -h "$destination" ]; then + echo symlink +elif [ -f "$destination" ]; then + echo file +elif [ -d "$destination" ]; then + echo directory +else + echo unknown +fi diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index 21f4c5b6..aba618ac 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -1,6 +1,8 @@ #!/bin/sh # -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Steven Armstrong (steven-cdist armstrong.cc) +# 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -18,42 +20,97 @@ # along with cdist. If not, see . # -state_should="present" -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" -state_is="$(cat "$__object/explorer/state")" -[ "$state_should" = "$state_is" ] && exit 0 - destination="/$__object_id" +state_should="$(cat "$__object/parameter/state")" +type="$(cat "$__object/explorer/type")" +stat_file="$__object/explorer/stat" + +# variable to keep track if we have to set directory attributes +set_attributes= mkdiropt="" [ -f "$__object/parameter/parents" ] && mkdiropt="-p" + recursive="" -[ -f "$__object/parameter/recursive" ] && recursive="-R" +if [ -f "$__object/parameter/recursive" ]; then + recursive="-R" + # need to allways set attributes when recursive is given + # as we don't want to check all subfolders/files + set_attributes=1 +fi + +get_current_value() { + if [ -s "$stat_file" ]; then + _name="$1" + _value="$2" + case "$_value" in + [0-9]*) + _index=2 + ;; + *) + _index=3 + ;; + esac + awk '/'"$_name"':/ { print $'$_index' }' "$stat_file" + unset _name _value _index + fi +} + +set_group() { + echo chgrp $recursive \"$1\" \"$destination\" + echo chgrp $recursive $1 >> "$__messages_out" +} + +set_owner() { + echo chown $recursive \"$1\" \"$destination\" + echo chown $recursive $1 >> "$__messages_out" +} + +set_mode() { + echo chmod $recursive \"$1\" \"$destination\" + echo chmod $recursive $1 >> "$__messages_out" +} case "$state_should" in - present) - echo mkdir $mkdiropt \"$destination\" + present) + if [ "$type" != "directory" ]; then + set_attributes=1 + if [ "$type" != "none" ]; then + # our destination is not a directory, remove whatever is there + # and then create our directory and set all attributes + echo rm -f "\"$destination\"" + echo "remove non directory" >> "$__messages_out" + fi + echo "mkdir $mkdiropt \"$destination\"" + echo "create" >> "$__messages_out" + fi - # Mode settings - if [ -f "$__object/parameter/mode" ]; then - echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" - fi + # Note: Mode - needs to happen last as a chown/chgrp can alter mode by + # clearing S_ISUID and S_ISGID bits (see chown(2)) + for attribute in group owner mode; do + if [ -f "$__object/parameter/$attribute" ]; then + value_should="$(cat "$__object/parameter/$attribute")" + value_is="$(get_current_value "$attribute" "$value_should")" - # Group - if [ -f "$__object/parameter/group" ]; then - echo chgrp $recursive \"$(cat "$__object/parameter/group")\" \"$destination\" - fi + # change 0xxx format to xxx format => same as stat returns + if [ "$attribute" = mode ]; then + value_should="$(echo $value_should | sed 's/^0\(...\)/\1/')" + fi - # Owner - if [ -f "$__object/parameter/owner" ]; then - echo chown $recursive \"$(cat "$__object/parameter/owner")\" \"$destination\" + if [ "$set_attributes" = 1 ] || [ "$value_should" != "$value_is" ]; then + "set_$attribute" "$value_should" + fi + fi + done + ;; + absent) + if [ "$type" = "directory" ]; then + echo rm -rf \"$destination\" + echo remove >> "$__messages_out" fi - ;; - absent) - echo rm -rf \"$destination\" - ;; - *) - echo "Unknown state: $state_should" >&2 - exit 1 - ;; + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; esac diff --git a/cdist/conf/type/__directory/man.text b/cdist/conf/type/__directory/man.text index 1f4def7d..a0bf8062 100644 --- a/cdist/conf/type/__directory/man.text +++ b/cdist/conf/type/__directory/man.text @@ -36,12 +36,31 @@ owner:: BOOLEAN PARAMETERS ------------------ parents:: - Whether to create parents as well (mkdir -p behaviour) + Whether to create parents as well (mkdir -p behaviour). + Warning: all intermediate directory permissions default + to whatever mkdir -p does. + + Usually this means root:root, 0700. recursive:: If supplied the chgrp and chown call will run recursively. This does *not* influence the behaviour of chmod. +MESSAGES +-------- +chgrp :: + Changed group membership +chown :: + Changed owner +chmod :: + Changed mode +create:: + Empty directory was created +remove:: + Directory exists, but state is absent, directory will be removed by generated code. +remove non directory:: + Someting other than a directory with the same name exists and was removed prior to create. + EXAMPLES -------- diff --git a/cdist/conf/type/__directory/parameter/default/state b/cdist/conf/type/__directory/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__directory/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__file/explorer/stat b/cdist/conf/type/__file/explorer/stat new file mode 100755 index 00000000..298221b7 --- /dev/null +++ b/cdist/conf/type/__file/explorer/stat @@ -0,0 +1,47 @@ +#!/bin/sh +# +# 2013 Steven Armstrong (steven-cdist 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 . +# + +destination="/$__object_id" + +# nothing to work with, nothing we could do +[ -e "$destination" ] || exit 0 + +os=$("$__explorer/os") +case "$os" in + "freebsd") + # FIXME: should be something like this based on man page, but can not test + stat -f "type: %ST +owner: %Du %Su +group: %Dg %Sg +mode: %Op %Sp +size: %Dz +links: %Dl +" "$destination" + ;; + *) + stat --printf="type: %F +owner: %u %U +group: %g %G +mode: %a %A +size: %s +links: %h +" "$destination" + ;; +esac diff --git a/cdist/conf/type/__file/explorer/type b/cdist/conf/type/__file/explorer/type new file mode 100755 index 00000000..e723047c --- /dev/null +++ b/cdist/conf/type/__file/explorer/type @@ -0,0 +1,33 @@ +#!/bin/sh +# +# 2013 Steven Armstrong (steven-cdist 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 . +# + +destination="/$__object_id" + +if [ ! -e "$destination" ]; then + echo none +elif [ -h "$destination" ]; then + echo symlink +elif [ -f "$destination" ]; then + echo file +elif [ -d "$destination" ]; then + echo directory +else + echo unknown +fi diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index 087011c4..601705c8 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Steven Armstrong (steven-cdist armstrong.cc) # # This file is part of cdist. # @@ -17,34 +18,61 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# -# __file is a very basic type, which will probably be reused quite often -# destination="/$__object_id" -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" -exists="$(cat "$__object/explorer/exists")" +state_should="$(cat "$__object/parameter/state")" +type="$(cat "$__object/explorer/type")" -[ "$state_should" = "exists" -a "$exists" = "yes" ] && exit 0 # nothing to do +[ "$state_should" = "exists" -a "$type" = "file" ] && exit 0 # nothing to do +upload_file= +create_file= if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then - if [ -f "$__object/parameter/source" ]; then + if [ ! -f "$__object/parameter/source" ]; then + create_file=1 + echo create >> "$__messages_out" + else source="$(cat "$__object/parameter/source")" if [ "$source" = "-" ]; then source="$__object/stdin" fi - - if [ -f "$source" ]; then - local_cksum="$(cksum < "$source")" - remote_cksum="$(cat "$__object/explorer/cksum")" - - if [ "$local_cksum" != "$remote_cksum" ]; then - echo "$__remote_copy" "$source" "${__target_host}:${destination}" - fi - else + if [ ! -f "$source" ]; then echo "Source \"$source\" does not exist." >&2 exit 1 + else + if [ "$type" != "file" ]; then + # destination is not a regular file, upload source to replace it + upload_file=1 + else + local_cksum="$(cksum < "$source")" + remote_cksum="$(cat "$__object/explorer/cksum")" + if [ "$local_cksum" != "$remote_cksum" ]; then + # destination is a regular file, but not the right one + upload_file=1 + fi + fi fi fi + if [ "$create_file" -o "$upload_file" ]; then + # tell gencode-remote that we created or uploaded a file and that it must + # set all attributes no matter what the explorer retreived + mkdir "$__object/files" + touch "$__object/files/set-attributes" + + # upload file to temp location + tempfile_template="${destination}.cdist.XXXXXXXXXX" + cat << DONE +destination_upload="\$($__remote_exec $__target_host "mktemp $tempfile_template")" +DONE + if [ "$upload_file" ]; then + echo upload >> "$__messages_out" + cat << DONE +$__remote_copy $source ${__target_host}:\$destination_upload +DONE + fi +# move uploaded file into place +cat << DONE +$__remote_exec $__target_host "rm -rf \"$destination\"; mv \"\$destination_upload\" \"$destination\"" +DONE + fi fi diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index 8b03e919..dcf3857b 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Steven Armstrong (steven-cdist armstrong.cc) # # This file is part of cdist. # @@ -17,52 +18,77 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# -# __file is a very basic type, which will probably be reused quite often -# destination="/$__object_id" -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" -exists="$(cat "$__object/explorer/exists")" +state_should="$(cat "$__object/parameter/state")" +type="$(cat "$__object/explorer/type")" +stat_file="$__object/explorer/stat" + +get_current_value() { + if [ -s "$stat_file" ]; then + _name="$1" + _value="$2" + case "$_value" in + [0-9]*) + _index=2 + ;; + *) + _index=3 + ;; + esac + awk '/'"$_name"':/ { print $'$_index' }' "$stat_file" + unset _name _value _index + fi +} + +set_group() { + echo chgrp \"$1\" \"$destination\" + echo chgrp $1 >> "$__messages_out" +} + +set_owner() { + echo chown \"$1\" \"$destination\" + echo chown $1 >> "$__messages_out" +} + +set_mode() { + echo chmod \"$1\" \"$destination\" + echo chmod $1 >> "$__messages_out" +} + +set_attributes= case "$state_should" in - present|exists) - # No source? Create empty file - if [ ! -f "$__object/parameter/source" ]; then - if [ "$exists" = "no" ]; then - echo touch \"$destination\" - fi - fi + present|exists) + # Note: Mode - needs to happen last as a chown/chgrp can alter mode by + # clearing S_ISUID and S_ISGID bits (see chown(2)) + for attribute in group owner mode; do + if [ -f "$__object/parameter/$attribute" ]; then + value_should="$(cat "$__object/parameter/$attribute")" - # Group - if [ -f "$__object/parameter/group" ]; then - echo chgrp \"$(cat "$__object/parameter/group")\" \"$destination\" - fi + # change 0xxx format to xxx format => same as stat returns + if [ "$attribute" = mode ]; then + value_should="$(echo $value_should | sed 's/^0\(...\)/\1/')" + fi + + value_is="$(get_current_value "$attribute" "$value_should")" + if [ -f "$__object/files/set-attributes" -o "$value_should" != "$value_is" ]; then + "set_$attribute" "$value_should" + fi + fi + done - # Owner - if [ -f "$__object/parameter/owner" ]; then - echo chown \"$(cat "$__object/parameter/owner")\" \"$destination\" - 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) - - if [ "$exists" = "yes" ]; then - echo rm -f \"$destination\" - fi - - ;; - - *) - echo "Unknown state: $state_should" >&2 - exit 1 - ;; + absent) + if [ "$type" = "file" ]; then + echo rm -f \"$destination\" + echo remove >> "$__messages_out" + fi + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; esac diff --git a/cdist/conf/type/__file/man.text b/cdist/conf/type/__file/man.text index 1c61fd51..a582b27b 100644 --- a/cdist/conf/type/__file/man.text +++ b/cdist/conf/type/__file/man.text @@ -13,6 +13,15 @@ DESCRIPTION This cdist type allows you to create files, remove files and set file attributes on the target. +If the file already exists on the target, then if it is a: +- regular file, and state is: + present: replace it with the source file if they are not equal + exists: do nothing +- symlink: replace it with the source file +- directory: replace it with the source file + +In any case, make sure that the file attributes are as specified. + REQUIRED PARAMETERS ------------------- @@ -41,6 +50,21 @@ source:: If not supplied, an empty file or directory will be created. If source is '-' (dash), take what was written to stdin as the file content. +MESSAGES +-------- +chgrp :: + Changed group membership +chown :: + Changed owner +chmod :: + Changed mode +create:: + Empty file was created (no --source specified) +remove:: + File exists, but state is absent, file will be removed by generated code. +upload:: + File was uploaded + EXAMPLES -------- @@ -81,5 +105,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__file/parameter/default/state b/cdist/conf/type/__file/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__file/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__git/explorer/group b/cdist/conf/type/__git/explorer/group new file mode 100644 index 00000000..1308c710 --- /dev/null +++ b/cdist/conf/type/__git/explorer/group @@ -0,0 +1,5 @@ +#!/bin/sh + +destination="/$__object_id/.git" + +stat --print "%G" ${destination} 2>/dev/null || exit 0 diff --git a/cdist/conf/type/__git/explorer/owner b/cdist/conf/type/__git/explorer/owner new file mode 100644 index 00000000..8c36b035 --- /dev/null +++ b/cdist/conf/type/__git/explorer/owner @@ -0,0 +1,5 @@ +#!/bin/sh + +destination="/$__object_id/.git" + +stat --print "%U" ${destination} 2>/dev/null || exit 0 diff --git a/cdist/conf/type/__git/gencode-remote b/cdist/conf/type/__git/gencode-remote index 0f665d59..c4fc1ef2 100644 --- a/cdist/conf/type/__git/gencode-remote +++ b/cdist/conf/type/__git/gencode-remote @@ -20,21 +20,39 @@ # state_is="$(cat "$__object/explorer/state")" -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" +owner_is="$(cat "$__object/explorer/owner")" +group_is="$(cat "$__object/explorer/group")" -branch=master -[ -f "$__object/parameter/branch" ] && branch="$(cat "$__object/parameter/branch")" +state_should="$(cat "$__object/parameter/state")" + +branch="$(cat "$__object/parameter/branch")" source="$(cat "$__object/parameter/source")" destination="/$__object_id" -[ "$state_should" = "$state_is" ] && exit 0 +owner="$(cat "$__object/parameter/owner")" +group="$(cat "$__object/parameter/group")" +mode="$(cat "$__object/parameter/mode")" + +[ "$state_should" = "$state_is" -a \ + "$owner" = "$owner_is" -a \ + "$group" = "$group_is" -a \ + -n "$mode" ] && exit 0 case $state_should in present) - echo git clone --quiet --branch "$branch" "$source" "$destination" + + if [ "$state_should" != "$state_is" ]; then + echo git clone --quiet --branch "$branch" "$source" "$destination" + fi + if [ \( -n "$owner" -a "$owner_is" != "$owner" \) -o \ + \( -n "$group" -a "$group_is" != "$group" \) ]; then + echo chown -R "${owner}:${group}" "$destination" + fi + if [ -n "$mode" ]; then + echo chmod -R "$mode" "$destination" + fi ;; # Handled in manifest absent) diff --git a/cdist/conf/type/__git/man.text b/cdist/conf/type/__git/man.text index 5597a52d..5f74108b 100644 --- a/cdist/conf/type/__git/man.text +++ b/cdist/conf/type/__git/man.text @@ -26,6 +26,16 @@ state:: branch:: Create this branch by checking out the remote branch of this name + Default branch is "master" + +group:: + Group to chgrp to. + +mode:: + Unix permissions, suitable for chmod. + +owner:: + User to chown to. EXAMPLES diff --git a/cdist/conf/type/__git/manifest b/cdist/conf/type/__git/manifest index e8c9b233..7f6fee84 100644 --- a/cdist/conf/type/__git/manifest +++ b/cdist/conf/type/__git/manifest @@ -23,17 +23,13 @@ __package git --state present -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" - -[ -f "$__object/parameter/owner" ] && dirparams="$dirparams --owner $(cat "$__object/parameter/owner")" -[ -f "$__object/parameter/group" ] && dirparams="$dirparams --group $(cat "$__object/parameter/group")" +state_should="$(cat "$__object/parameter/state")" # Let __directory handle removal of git repos case "$state_should" in present) - __directory "$__object_id" --state present $dirparams --recursive + : ;; absent) diff --git a/cdist/conf/type/__git/parameter/default/branch b/cdist/conf/type/__git/parameter/default/branch new file mode 100644 index 00000000..1f7391f9 --- /dev/null +++ b/cdist/conf/type/__git/parameter/default/branch @@ -0,0 +1 @@ +master diff --git a/cdist/conf/type/__git/parameter/default/group b/cdist/conf/type/__git/parameter/default/group new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__git/parameter/default/group @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__git/parameter/default/mode b/cdist/conf/type/__git/parameter/default/mode new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__git/parameter/default/mode @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__git/parameter/default/owner b/cdist/conf/type/__git/parameter/default/owner new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__git/parameter/default/owner @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__git/parameter/default/state b/cdist/conf/type/__git/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__git/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__git/parameter/optional b/cdist/conf/type/__git/parameter/optional index d9684aaa..3c409162 100644 --- a/cdist/conf/type/__git/parameter/optional +++ b/cdist/conf/type/__git/parameter/optional @@ -2,3 +2,4 @@ state branch group owner +mode diff --git a/cdist/conf/type/__group/gencode-remote b/cdist/conf/type/__group/gencode-remote index bb6797c2..1cffa8d4 100755 --- a/cdist/conf/type/__group/gencode-remote +++ b/cdist/conf/type/__group/gencode-remote @@ -58,10 +58,12 @@ if grep -q "^${name}:" "$__object/explorer/group"; then if [ "$new_value" != "$current_value" ]; then set -- "$@" "$proparg" \"$new_value\" + echo change $property $new_value $current_value >> "$__messages_out" fi done if [ $# -gt 0 ]; then + echo mod >> "$__messages_out" case $os in freebsd) echo pw group mod "$@" "$name" @@ -72,6 +74,7 @@ if grep -q "^${name}:" "$__object/explorer/group"; then esac fi else + echo add >> "$__messages_out" for property in $(ls .); do new_value="$(cat "$property")" if [ "$os" = "freebsd" ]; then @@ -95,6 +98,7 @@ else fi set -- "$@" "$proparg" \"$new_value\" + echo set $property $new_value >> "$__messages_out" done case $os in diff --git a/cdist/conf/type/__group/man.text b/cdist/conf/type/__group/man.text index c57ae337..def0232f 100644 --- a/cdist/conf/type/__group/man.text +++ b/cdist/conf/type/__group/man.text @@ -26,6 +26,18 @@ password:: see above +MESSAGES +-------- +mod:: + group is modified +add:: + New group added +change :: + Changed group property from current_value to new_value +set :: + set property to new value, property was not set bevore + + EXAMPLES -------- diff --git a/cdist/conf/type/__hostname/explorer/has_hostnamectl b/cdist/conf/type/__hostname/explorer/has_hostnamectl new file mode 100755 index 00000000..9040023d --- /dev/null +++ b/cdist/conf/type/__hostname/explorer/has_hostnamectl @@ -0,0 +1,24 @@ +#!/bin/sh +# +# 2014 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 . +# +# +# Check whether system has hostnamectl +# + +command -v hostnamectl || true diff --git a/cdist/conf/type/__file/explorer/exists b/cdist/conf/type/__hostname/explorer/hostname_file similarity index 78% rename from cdist/conf/type/__file/explorer/exists rename to cdist/conf/type/__hostname/explorer/hostname_file index c319cb5d..ed28c8a8 100755 --- a/cdist/conf/type/__file/explorer/exists +++ b/cdist/conf/type/__hostname/explorer/hostname_file @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,13 +18,9 @@ # along with cdist. If not, see . # # -# Check whether file exists or not +# Retrieve the contents of /etc/hostname # -destination="/$__object_id" - -if [ -e "$destination" ]; then - echo yes -else - echo no +if [ -f /etc/hostname ]; then + cat /etc/hostname fi diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote new file mode 100755 index 00000000..3d208cbe --- /dev/null +++ b/cdist/conf/type/__hostname/gencode-remote @@ -0,0 +1,50 @@ +#!/bin/sh +# +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2014 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 . +# + +if [ -f "$__object/parameter/name" ]; then + name_should="$(cat "$__object/parameter/name")" +else + name_should="$(echo "${__target_host%%.*}")" +fi + +os=$(cat "$__global/explorer/os") +name_running=$(cat "$__global/explorer/hostname") +name_config=$(cat "$__object/explorer/hostname_file") +has_hostnamectl=$(cat "$__object/explorer/has_hostnamectl") + +################################################################################ +# If everything is ok -> exit +# +if [ "$name_config" = "$name_should" -a "$name_running" = "$name_should" ]; then + exit 0 +fi + +################################################################################ +# Setup hostname +# +echo changed >> "$__messages_out" + +if [ "$has_hostnamectl" ]; then + echo "hostnamectl set-hostname '$name_should'" +else + echo "hostname '$name_should'" + echo "printf '%s\n' '$name_should' > /etc/hostname" +fi diff --git a/cdist/conf/type/__hostname/man.text b/cdist/conf/type/__hostname/man.text new file mode 100644 index 00000000..ac44d426 --- /dev/null +++ b/cdist/conf/type/__hostname/man.text @@ -0,0 +1,52 @@ +cdist-type__hostname(7) +======================= +Steven Armstrong + + +NAME +---- +cdist-type__hostname - set the hostname + + +DESCRIPTION +----------- +Set's the hostname on various operating systems. + + +REQUIRED PARAMETERS +------------------- +None. + +OPTIONAL PARAMETERS +------------------- +name:: + The hostname to set. Defaults to the first segment of __target_host + (${__target_host%%.*}) + + +MESSAGES +-------- +changed:: + Changed the hostname + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# take hostname from __target_host +__hostname + +# set hostname explicitly +__hostname --name some-static-hostname +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2012 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest new file mode 100755 index 00000000..0544a6f9 --- /dev/null +++ b/cdist/conf/type/__hostname/manifest @@ -0,0 +1,38 @@ +#!/bin/sh +# +# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2014 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 . +# + +os=$(cat "$__global/explorer/os") + +not_supported() { + echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 +} + +case "$os" in + archlinux|debian|ubuntu) + # handled in gencode-remote + : + ;; + *) + not_supported + ;; +esac diff --git a/cdist/conf/type/__hostname/parameter/optional b/cdist/conf/type/__hostname/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/cdist/conf/type/__hostname/parameter/optional @@ -0,0 +1 @@ +name diff --git a/cdist/test/autorequire/fixtures/conf/explorer/.keep b/cdist/conf/type/__hostname/singleton similarity index 100% rename from cdist/test/autorequire/fixtures/conf/explorer/.keep rename to cdist/conf/type/__hostname/singleton diff --git a/cdist/conf/type/__iptables_apply/files/init-script b/cdist/conf/type/__iptables_apply/files/init-script new file mode 100644 index 00000000..2dc952e9 --- /dev/null +++ b/cdist/conf/type/__iptables_apply/files/init-script @@ -0,0 +1,48 @@ +#!/bin/sh +# Nico Schottelius +# Zürisee, Mon Sep 2 18:38:27 CEST 2013 +# +### BEGIN INIT INFO +# Provides: iptables +# Required-Start: $local_fs $remote_fs +# Required-Stop: $local_fs $remote_fs +# X-Start-Before: fail2ban +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Applies iptables ruleset +# Description: Applies all rules found in /etc/iptables.d +# and saves/restores previous status +### END INIT INFO + + +basedir=/etc/iptables.d +status="${basedir}/.pre-start" + +case $1 in + start) + # Save status + iptables-save > "$status" + + # Apply our ruleset + cd "$basedir" + count="$(ls -1 | wc -l)" + + # Only do something if there are rules + if [ "$count" -ge 1 ]; then + for rule in *; do + echo "Applying iptables rule $rule ..." + iptables $(cat "$rule") + done + fi + ;; + + stop) + # Restore from status before, if there is something to restore + if [ -f "$status" ]; then + iptables-restore < "$status" + fi + ;; + restart) + "$0" stop && "$0" start + ;; +esac diff --git a/cdist/conf/type/__iptables_apply/gencode-remote b/cdist/conf/type/__iptables_apply/gencode-remote new file mode 100644 index 00000000..9cdf28cf --- /dev/null +++ b/cdist/conf/type/__iptables_apply/gencode-remote @@ -0,0 +1,3 @@ +if grep -q "^__file/etc/iptables.d/" "$__messages_in"; then + echo /etc/init.d/iptables restart +fi diff --git a/cdist/conf/type/__iptables_apply/man.text b/cdist/conf/type/__iptables_apply/man.text new file mode 100644 index 00000000..87f4b4ee --- /dev/null +++ b/cdist/conf/type/__iptables_apply/man.text @@ -0,0 +1,42 @@ +cdist-type__iptables_apply(7) +============================= +Nico Schottelius + + +NAME +---- +cdist-type__iptables_apply - Apply the rules + + +DESCRIPTION +----------- +This cdist type deploys an init script that triggers +the configured rules and also re-applies them on +configuration. + + +REQUIRED PARAMETERS +------------------- +None + +OPTIONAL PARAMETERS +------------------- +None + +EXAMPLES +-------- + +None (__iptables_apply is used by __iptables_rule) + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__iptables_rule(7) +- iptables(8) + + +COPYING +------- +Copyright \(C) 2013 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__iptables_apply/manifest b/cdist/conf/type/__iptables_apply/manifest new file mode 100644 index 00000000..a22901ba --- /dev/null +++ b/cdist/conf/type/__iptables_apply/manifest @@ -0,0 +1,26 @@ +# +# 2013 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 . +# +# + +__file /etc/init.d/iptables \ + --source "$__type/files/init-script" \ + --state present \ + --mode 0755 + +require="__file/etc/init.d/iptables" __start_on_boot iptables diff --git a/cdist/test/autorequire/fixtures/conf/type/__addifnosuchline/.keep b/cdist/conf/type/__iptables_apply/singleton similarity index 100% rename from cdist/test/autorequire/fixtures/conf/type/__addifnosuchline/.keep rename to cdist/conf/type/__iptables_apply/singleton diff --git a/cdist/conf/type/__iptables_rule/man.text b/cdist/conf/type/__iptables_rule/man.text new file mode 100644 index 00000000..eb230093 --- /dev/null +++ b/cdist/conf/type/__iptables_rule/man.text @@ -0,0 +1,64 @@ +cdist-type__iptables_rule(7) +============================ +Nico Schottelius + + +NAME +---- +cdist-type__iptables_rule - Deploy iptable rulesets + + +DESCRIPTION +----------- +This cdist type allows you to manage iptable rules +in a distribution independent manner. + + +REQUIRED PARAMETERS +------------------- +rule:: + The rule to apply. Essentially an iptables command + line without iptables in front of it. + + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent', defaults to 'present' + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Deploy some policies +__iptables_rule policy-in --rule "-P INPUT DROP" +__iptables_rule policy-out --rule "-P OUTPUT ACCEPT" +__iptables_rule policy-fwd --rule "-P FORWARD DROP" + +# The usual established rule +__iptables_rule established --rule "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT" + +# Some service rules +__iptables_rule http --rule "-A INPUT -p tcp --dport 80 -j ACCEPT" +__iptables_rule ssh --rule "-A INPUT -p tcp --dport 80 -j ACCEPT" +__iptables_rule https --rule "-A INPUT -p tcp --dport 443 -j ACCEPT" + +# Ensure some rules are not present anymore +__iptables_rule munin --rule "-A INPUT -p tcp --dport 4949 -j ACCEPT" \ + --state absent + +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__iptables_apply(7) +- iptables(8) + + +COPYING +------- +Copyright \(C) 2013 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__iptables_rule/manifest b/cdist/conf/type/__iptables_rule/manifest new file mode 100644 index 00000000..f02ab18b --- /dev/null +++ b/cdist/conf/type/__iptables_rule/manifest @@ -0,0 +1,41 @@ +# +# 2013 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 . +# +# + +base_dir=/etc/iptables.d + +name="$__object_id" +state="$(cat "$__object/parameter/state")" + +################################################################################ +# Basic setup +# + +__directory "$base_dir" --state present + +# Have apply do the real job +require="$__object_name" __iptables_apply + +################################################################################ +# The rule +# + +require="__directory/$base_dir" __file "$base_dir/${name}" \ + --source "$__object/parameter/rule" \ + --state "$state" diff --git a/cdist/conf/type/__iptables_rule/parameter/default/state b/cdist/conf/type/__iptables_rule/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__iptables_rule/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__jail/parameter/required b/cdist/conf/type/__iptables_rule/parameter/optional similarity index 100% rename from cdist/conf/type/__jail/parameter/required rename to cdist/conf/type/__iptables_rule/parameter/optional diff --git a/cdist/conf/type/__iptables_rule/parameter/required b/cdist/conf/type/__iptables_rule/parameter/required new file mode 100644 index 00000000..2b254dff --- /dev/null +++ b/cdist/conf/type/__iptables_rule/parameter/required @@ -0,0 +1 @@ +rule diff --git a/cdist/conf/type/__jail/gencode-local b/cdist/conf/type/__jail/gencode-local index 075a6ef1..08c7b7bf 100755 --- a/cdist/conf/type/__jail/gencode-local +++ b/cdist/conf/type/__jail/gencode-local @@ -22,17 +22,9 @@ # virtual machines. # -if [ -f "$__object/parameter/jaildir" ]; then - jaildir="$(cat "$__object/parameter/name")" -else - jaildir="/usr/jail" -fi +jaildir="$(cat "$__object/parameter/jaildir")" -if [ -f "$__object/parameter/jailbase" ]; then - jailbase="$(cat "$__object/parameter/jailbase")" -else - jailbase="" -fi +jailbase="$(cat "$__object/parameter/jailbase")" state="$(cat "$__object/parameter/state")" diff --git a/cdist/conf/type/__jail/gencode-remote b/cdist/conf/type/__jail/gencode-remote index 7491754c..141c8150 100755 --- a/cdist/conf/type/__jail/gencode-remote +++ b/cdist/conf/type/__jail/gencode-remote @@ -66,11 +66,7 @@ else devfsenable="true" fi -if [ -f "$__object/parameter/devfs-ruleset" ]; then - devfsruleset="$(cat "$__object/parameter/devfs-ruleset")" -else - devfsruleset="jailrules" -fi +devfsruleset="$(cat "$__object/parameter/devfs-ruleset")" # devfs_ruleset being defined without devfs_enable being true # is pointless. Treat this as an error. @@ -84,15 +80,26 @@ if [ -f "$__object/parameter/onboot" ]; then onboot="true" fi -if [ -f "$__object/parameter/jaildir" ]; then - jaildir="$(cat "$__object/parameter/name")" -else - jaildir="/usr/jail" -fi +jaildir="$(cat "$__object/parameter/jaildir")" present="$(cat "$__object/explorer/present")" status="$(cat "$__object/explorer/status")" +# Handle ip="iface|addr, iface|addr" format +if [ $(expr "${ip}" : ".*|.*") -gt "0" ]; then + # If we have multiple IPs defined, $interface doesn't make sense because ip="iface|addr, iface|addr" implies it + interface="" + SAVE_IFS="$IFS" + IFS=", " + for cur_ip in ${ip}; do + # Just get the last IP address for SSH to listen on + mgmt_ip=$(echo "${ip}" | sed -E -e 's/^.*\|(.*)\/[0-9]+$/\1/') + done + IFS="$SAVE_IFS" +else + mgmt_ip=$(echo "${ip}" | cut '-d ' -f1) +fi + stopJail() { # Check $status before issuing command if [ "$status" = "STARTED" ]; then @@ -160,10 +167,10 @@ EOF createJail() { # Create the jail directory cat <>/etc/rc.conf <>"${jaildir}/rw/${name}/etc/rc.conf" EOF # Configure SSHd's listening address cat < \"$file.cdist-tmp\"" - echo "mv \"$file.cdist-tmp\" \"$file\"" + cat << DONE +tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) +# preserve ownership and permissions by copying existing file over tmpfile +cp -p "$file" "\$tmpfile" +sed '/^$key\($delimiter\+\)/d' "$file" > "\$tmpfile" +mv -f "\$tmpfile" "$file" +DONE ;; present) case "$state_is" in absent) # add new key and value - echo "echo \"${key}${delimiter}${value}\" >> \"$file\"" + printf 'echo "%s%s%s" >> "%s"' "$key" "$delimiter" "$value_escaped" "$file" ;; wrongvalue) # change exisiting value - echo "sed \"s|^$key\($delimiter\+\).*|$key\1$value|\" \"$file\" > \"$file.cdist-tmp\"" - echo "mv \"$file.cdist-tmp\" \"$file\"" + cat << DONE +tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) +# preserve ownership and permissions by copying existing file over tmpfile +cp -p "$file" "\$tmpfile" +sed "s|^$key\($delimiter\+\).*|$key\\1$value_escaped|" "$file" > "\$tmpfile" +mv -f "\$tmpfile" "$file" +DONE ;; *) echo "Unknown explorer state: $state_is" >&2 @@ -57,4 +67,4 @@ case "$state_should" in *) echo "Unknown state: $state_should" >&2 exit 1 -esac +esac diff --git a/cdist/conf/type/__key_value/manifest b/cdist/conf/type/__key_value/manifest index 8ed9cc9c..56f4c874 100755 --- a/cdist/conf/type/__key_value/manifest +++ b/cdist/conf/type/__key_value/manifest @@ -19,8 +19,7 @@ # along with cdist. If not, see . # -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" if [ "$state_should" = "present" -a ! -f "$__object/parameter/value" ]; then echo "Missing required parameter 'value'" >&2 diff --git a/cdist/conf/type/__key_value/parameter/default/state b/cdist/conf/type/__key_value/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__key_value/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__line/explorer/state b/cdist/conf/type/__line/explorer/state index d240bf4d..d04d5d09 100755 --- a/cdist/conf/type/__line/explorer/state +++ b/cdist/conf/type/__line/explorer/state @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -24,16 +24,18 @@ file="/$__object_id" if [ -f "$__object/parameter/regex" ]; then regex=$(cat "$__object/parameter/regex") + greparg="" else if [ ! -f "$__object/parameter/line" ]; then echo "Parameter line and regex missing - cannot explore" >&2 exit 1 fi - regex="^$(cat "$__object/parameter/line")\$" + regex="$(cat "$__object/parameter/line")" + greparg="-F -x" fi # Allow missing file - thus 2>/dev/null -if grep -q "$regex" "$file" 2>/dev/null; then +if grep -q $greparg "$regex" "$file" 2>/dev/null; then echo present else echo absent diff --git a/cdist/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote index 8ac273e2..1fadf454 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -38,7 +38,27 @@ case "$state_should" in exit 1 fi - echo "echo \"$line\" >> $file" + #echo "echo \"$line\" >> $file" + #line_sanitised=$(cat "$__object/parameter/line" | sed 's/"/\"/g') + # Idea: replace ' in the string: + # '"'"' + # |------> ': end the string + # |-|---> "'": create ' in the output string + # |--> ': continue the string + # + # Replace all \ so \t and other combinations are not interpreted + # + + + # line_sanitised=$(cat "$__object/parameter/line" | sed -e "s/'/'\"'\"'/g" -e 's/\\/\\\\/g') + # The one above does not work: + # --line "PS1='[\t] \[\033[1m\]\h\[\033[0m\]:\w\\$ '" + # becomes + # PS1='[\\t] \\[\\033[1m\\]\\h\\[\\033[0m\\]:\\w\\$ ' + + # Only replace ' with '"'"' and keep \ as they are + line_sanitised=$(cat "$__object/parameter/line" | sed -e "s/'/'\"'\"'/g") + printf '%s' "printf '%s\n' '$line_sanitised' >> $file" ;; absent) @@ -47,13 +67,16 @@ case "$state_should" in exit 1 fi - [ "$line" ] && regex="^$line\$" + greparg="" + if [ "$line" ]; then + regex="$line" + greparg="-F -x" + fi cat << eof tmp=\$(mktemp) -sed '/$regex/d' "$file" > \$tmp && cat "\$tmp" > "$file" && rm -f "\$tmp" +grep -v $greparg '$regex' '$file' > \$tmp && cat "\$tmp" > '$file' && rm -f "\$tmp" eof - #echo "echo q | ex -c \"/${line}/d|w|q\" \"${file}\"" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__line/man.text b/cdist/conf/type/__line/man.text index e1a5941c..f39ee929 100644 --- a/cdist/conf/type/__line/man.text +++ b/cdist/conf/type/__line/man.text @@ -32,11 +32,11 @@ regex:: given line, if the given regular expression does not match. In case of absent, ensure all lines matching the - regular expression are absent (cannot be combined with - the line parameter, if state is absent). + regular expression are absent. - If the regular expression contains / (slashes), they need - to be escaped with \ (backslash): / becomes \/. + The regular expression is interpreted by grep. + + Must not be combined with line, if state is absent. file:: If supplied, use this as the destination file. @@ -64,9 +64,10 @@ __line legacy_timezone --file /etc/rc.conf --regex 'TIMEZONE=.*' --state absent SEE ALSO -------- - cdist-type(7) +- grep(1) COPYING ------- -Copyright \(C) 2012 Nico Schottelius. Free use of this software is +Copyright \(C) 2012-2013 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__link/explorer/type b/cdist/conf/type/__link/explorer/type new file mode 100755 index 00000000..579fd081 --- /dev/null +++ b/cdist/conf/type/__link/explorer/type @@ -0,0 +1,46 @@ +#!/bin/sh +# +# 2013 Steven Armstrong (steven-cdist 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 . +# +# +# Mostly a wrapper for ln +# + +destination="/$__object_id" + +if [ ! -e "$destination" ]; then + echo none +elif [ -h "$destination" ]; then + echo symlink +elif [ -f "$destination" ]; then + type="$(cat "$__object/parameter/type")" + case "$type" in + hard) + link_count=$(ls -l "$destination" | awk '{ print $2 }') + if [ $link_count -gt 1 ]; then + echo hardlink + exit 0 + fi + ;; + esac + echo file +elif [ -d "$destination" ]; then + echo directory +else + echo unknown +fi diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote index 2975ef69..cbdfd30f 100755 --- a/cdist/conf/type/__link/gencode-remote +++ b/cdist/conf/type/__link/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -40,17 +41,30 @@ case "$type" in esac state_is="$(cat "$__object/explorer/state")" -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" [ "$state_should" = "$state_is" ] && exit 0 +file_type="$(cat "$__object/explorer/type")" case "$state_should" in present) - echo ln ${lnopt} -f \"$source\" \"$destination\" + if [ "$file_type" = "directory" ]; then + # our destination is currently a directory, delete it + cat << DONE +rm -rf "$destination" +DONE + fi + + # create our link + cat << DONE +ln ${lnopt} -f "$source" "$destination" +DONE ;; absent) - echo rm -f \"$destination\" + # only delete if it is a sym/hard link + if [ "$file_type" = "symlink" -o "$file_type" = "hardlink" ]; then + echo rm -f \"$destination\" + fi ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__link/parameter/default/state b/cdist/conf/type/__link/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__link/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__locale/files/locale.gen b/cdist/conf/type/__locale/files/locale.gen new file mode 100644 index 00000000..cf8e8651 --- /dev/null +++ b/cdist/conf/type/__locale/files/locale.gen @@ -0,0 +1,3 @@ +de_CH.UTF-8 UTF-8 +de_DE.UTF-8 UTF-8 +en_US.UTF-8 UTF-8 diff --git a/cdist/conf/type/__locale/gencode-remote b/cdist/conf/type/__locale/gencode-remote new file mode 100644 index 00000000..538ce2cd --- /dev/null +++ b/cdist/conf/type/__locale/gencode-remote @@ -0,0 +1,51 @@ +#!/bin/sh +# +# 2013 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 . +# +# +# Let localedef do the magic +# + +locale="$__object_id" + +# Hardcoded, create a pull request with +# branching on $os in case it is at another location +alias=/usr/share/locale/locale.alias + +input=$(echo "$locale" | cut -d . -f 1) +charmap=$(echo "$locale" | cut -d . -f 2) + +# Adding locale? The name is de_CH.UTF-8 +# Removing locale? The name is de_CH.utf8. +# W-T-F! +locale_remove=$(echo "$locale" | sed 's/UTF-8/utf8/') + +state=$(cat "$__object/parameter/state") + +case "$state" in + present) + echo localedef -A "$alias" -f "$charmap" -i "$input" "$locale" + ;; + absent) + echo localedef --delete-from-archive "$locale_remove" + ;; + *) + echo "Unsupported state: $state" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__locale/man.text b/cdist/conf/type/__locale/man.text new file mode 100644 index 00000000..5ccd3eab --- /dev/null +++ b/cdist/conf/type/__locale/man.text @@ -0,0 +1,47 @@ +cdist-type__locale(7) +===================== +Nico Schottelius + + +NAME +---- +cdist-type__locale - Configure locales + + +DESCRIPTION +----------- +This cdist type allows you to setup locales. + + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent', defaults to present + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Add locale de_CH.UTF-8 +__locale de_CH.UTF-8 + +# Same as above, but more explicit +__locale de_CH.UTF-8 --state present + +# Remove colourful British English +__locale en_GB.UTF-8 --state absent +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- locale(1) +- localedef(1) +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2013-2014 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__locale/manifest b/cdist/conf/type/__locale/manifest new file mode 100644 index 00000000..f3d75d59 --- /dev/null +++ b/cdist/conf/type/__locale/manifest @@ -0,0 +1,37 @@ +#!/bin/sh +# +# 2013-2014 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 . +# +# +# Install required packages +# + +os=$(cat "$__global/explorer/os") + + +case "$os" in + debian) + # Debian needs a seperate package + __package locales --state present + ;; + *) + echo "Sorry, do not know how to handle os: $os" >&2 + echo "Please edit the type ${__type##*/} to fix this." >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__locale/parameter/default/state b/cdist/conf/type/__locale/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__locale/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__pf_ruleset/parameter/required b/cdist/conf/type/__locale/parameter/optional similarity index 100% rename from cdist/conf/type/__pf_ruleset/parameter/required rename to cdist/conf/type/__locale/parameter/optional diff --git a/cdist/conf/type/__motd/gencode-remote b/cdist/conf/type/__motd/gencode-remote new file mode 100755 index 00000000..2aa84902 --- /dev/null +++ b/cdist/conf/type/__motd/gencode-remote @@ -0,0 +1,33 @@ +# 2013 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 . +# +# + +os=$(cat "$__global/explorer/os") + +case "$os" in + debian|ubuntu) + + # Debian and Ubuntu need to be updated, + # as seen in /etc/init.d/bootlogs + echo "uname -snrvm > /var/run/motd" + echo "cat /etc/motd.tail >> /var/run/motd" + ;; + *) + exit 0 + ;; +esac diff --git a/cdist/conf/type/__directory/explorer/state b/cdist/conf/type/__mount/explorer/mounted similarity index 78% rename from cdist/conf/type/__directory/explorer/state rename to cdist/conf/type/__mount/explorer/mounted index 9bdd9024..81f8e454 100755 --- a/cdist/conf/type/__directory/explorer/state +++ b/cdist/conf/type/__mount/explorer/mounted @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -17,14 +17,11 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# -# Check whether file exists or not -# -destination="/$__object_id" +path="$(cat "$__object/parameter/path" 2>/dev/null || echo "/$__object_id")" -if [ -e "$destination" ]; then - echo present +if mountpoint -q "$path"; then + echo yes else - echo absent + echo no fi diff --git a/cdist/conf/type/__mount/gencode-remote b/cdist/conf/type/__mount/gencode-remote new file mode 100755 index 00000000..2626f3de --- /dev/null +++ b/cdist/conf/type/__mount/gencode-remote @@ -0,0 +1,51 @@ +#!/bin/sh +# +# 2014 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 . +# + +path="$(cat "$__object/parameter/path" 2>/dev/null || echo "/$__object_id")" +state_should="$(cat "$__object/parameter/state")" +state_is="$(grep -q -x yes "$__object/explorer/mounted" && echo present || echo absent)" + +if [ "$state_should" = "$state_is" ]; then + # nothing to do + exit 0 +fi + +case "$state_should" in + present) + if [ -f "$__object/parameter/nofstab" ]; then + # mount manually + printf 'mount' + if [ -f "$__object/parameter/type" ]; then + printf ' -t %s' "$(cat "$__object/parameter/type")" + fi + if [ -f "$__object/parameter/options" ]; then + printf ' -o %s' "$(cat "$__object/parameter/options")" + fi + printf ' %s' "$(cat "$__object/parameter/device")" + printf " %s\n" "$path" + else + # mount using existing fstab entry + printf 'mount "%s"\n' "$path" + fi + ;; + absent) + printf 'umount "%s"\n' "$path" + ;; +esac diff --git a/cdist/conf/type/__mount/man.text b/cdist/conf/type/__mount/man.text new file mode 100644 index 00000000..7299bdf3 --- /dev/null +++ b/cdist/conf/type/__mount/man.text @@ -0,0 +1,84 @@ +cdist-type__mount(7) +==================== +Steven Armstrong + + +NAME +---- +cdist-type__mount - manage filesystem mounts + + +DESCRIPTION +----------- +Manage filesystem mounts either via /etc/fstab or manually. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +device:: + device to mount at path, defaults to 'none'. see mount(8) + +dump:: + value for the dump field in fstab. see fstab(5) + defaults to 0. + + This parameter is ignored, if the nofstab parameter is given. + +options:: + comma separated string of options, see mount(8) + +pass:: + value for the pass field in fstab. see fstab(5) + defaults to 0. + + This parameter is ignored, if the nofstab parameter is given. + +path:: + mount point where to mount the device, see mount(8). + Defaults to __object_id + +state:: + either present or absent. Defaults to present. + +type:: + vfstype, see mount(8) + + +BOOLEAN PARAMETERS +------------------ +nofstab:: + do not manage an entry in /etc/fstab + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__mount /some/dir \ + --device /dev/sdc3 \ + --type xfs \ + --options "defaults,ro" + --dump 0 \ + --pass 1 + +__mount /var/lib/one \ + --device mfsmount \ + --type fuse \ + --options "mfsmaster=mfsmaster.domain.tld,mfssubfolder=/one,nonempty,_netdev" +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2014 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__mount/manifest b/cdist/conf/type/__mount/manifest new file mode 100755 index 00000000..8a1fa234 --- /dev/null +++ b/cdist/conf/type/__mount/manifest @@ -0,0 +1,42 @@ +#!/bin/sh +# +# 2014 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 . +# + +path="$(cat "$__object/parameter/path" 2>/dev/null || echo "/$__object_id")" +state="$(cat "$__object/parameter/state")" + +if [ ! -f "$__object/parameter/nofstab" ]; then + # Generate an entry for /etc/fstab + ( +printf "%s" "$(cat "$__object/parameter/device")" +printf " %s" "$path" +type="$(cat "$__object/parameter/type" 2>/dev/null || echo "auto")" +printf " %s" "$type" +options="$(cat "$__object/parameter/options" 2>/dev/null || echo "defaults")" +printf " %s" "$options" +printf " %s" "$(cat "$__object/parameter/dump")" +printf " %s\n" "$(cat "$__object/parameter/pass")" +) | \ +__block "$__object_name" \ + --file "/etc/fstab" \ + --prefix "#cdist:$__object_name" \ + --suffix "#/cdist:$__object_name" \ + --state "$state" \ + --text - +fi diff --git a/cdist/conf/type/__mount/parameter/boolean b/cdist/conf/type/__mount/parameter/boolean new file mode 100644 index 00000000..ac6f41a8 --- /dev/null +++ b/cdist/conf/type/__mount/parameter/boolean @@ -0,0 +1 @@ +nofstab diff --git a/cdist/conf/type/__mount/parameter/default/device b/cdist/conf/type/__mount/parameter/default/device new file mode 100644 index 00000000..621e94f0 --- /dev/null +++ b/cdist/conf/type/__mount/parameter/default/device @@ -0,0 +1 @@ +none diff --git a/cdist/conf/type/__mount/parameter/default/dump b/cdist/conf/type/__mount/parameter/default/dump new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/cdist/conf/type/__mount/parameter/default/dump @@ -0,0 +1 @@ +0 diff --git a/cdist/conf/type/__mount/parameter/default/pass b/cdist/conf/type/__mount/parameter/default/pass new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/cdist/conf/type/__mount/parameter/default/pass @@ -0,0 +1 @@ +0 diff --git a/cdist/conf/type/__mount/parameter/default/state b/cdist/conf/type/__mount/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__mount/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__mount/parameter/optional b/cdist/conf/type/__mount/parameter/optional new file mode 100644 index 00000000..29d3e5ef --- /dev/null +++ b/cdist/conf/type/__mount/parameter/optional @@ -0,0 +1,7 @@ +device +dump +options +pass +path +state +type diff --git a/cdist/conf/type/__package/manifest b/cdist/conf/type/__package/manifest index 6a84cb7f..0ebf0099 100755 --- a/cdist/conf/type/__package/manifest +++ b/cdist/conf/type/__package/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -44,10 +44,12 @@ else esac fi -set -- "$@" "$__object_id" +state="$(cat "$__object/parameter/state")" + +set -- "$@" "$__object_id" "--state" "$state" cd "$__object/parameter" for property in $(ls .); do - if [ "$property" != "type" ]; then + if [ "$property" != "type" -a "$property" != "state" ]; then set -- "$@" "--$property" "$(cat "$property")" fi done diff --git a/cdist/conf/type/__package/parameter/default/state b/cdist/conf/type/__package/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__package/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__package/parameter/optional b/cdist/conf/type/__package/parameter/optional index 9982507e..d674f32e 100644 --- a/cdist/conf/type/__package/parameter/optional +++ b/cdist/conf/type/__package/parameter/optional @@ -3,3 +3,4 @@ version type pkgsite state +ptype diff --git a/cdist/conf/type/__package_apt/gencode-remote b/cdist/conf/type/__package_apt/gencode-remote index a80d707e..57339db3 100755 --- a/cdist/conf/type/__package_apt/gencode-remote +++ b/cdist/conf/type/__package_apt/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -42,7 +42,9 @@ case "$state_is" in ;; esac -aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes" +# Hint if we need to avoid questions at some point: +# DEBIAN_PRIORITY=critical can reduce the number of questions +aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes --no-install-recommends -o DPkg::Options::=\"--force-confold\"" [ "$state_is" = "$state_should" ] && exit 0 diff --git a/cdist/conf/type/__package_emerge/explorer/pkg_version b/cdist/conf/type/__package_emerge/explorer/pkg_version new file mode 100644 index 00000000..7053eaff --- /dev/null +++ b/cdist/conf/type/__package_emerge/explorer/pkg_version @@ -0,0 +1,35 @@ +#!/bin/sh +# +# 2013 Thomas Oettli (otho at sfs.biz) +# +# 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 package +# + +if [ ! -x /usr/bin/equery ]; then + echo "gentoolkit not installed!" 1>&2 + exit 1 +fi + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +equery -q l -F '$cp $fullversion' "$name" || true diff --git a/cdist/conf/type/__package_emerge/gencode-remote b/cdist/conf/type/__package_emerge/gencode-remote new file mode 100644 index 00000000..d4cee37e --- /dev/null +++ b/cdist/conf/type/__package_emerge/gencode-remote @@ -0,0 +1,72 @@ +#!/bin/sh +# +# 2013 Thomas Oettli (otho at sfs.biz) +# +# 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 packages with Portage (mostly gentoo) +# + +if [ -f "$__object/parameter/name" ]; then + name="$__object/parameter/name" +else + name="$__object_id" +fi + +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi + +pkg_version="$(cat "$__object/explorer/pkg_version")" +if [ -z "$pkg_version" ]; then + state_is="absent" +elif [ $(echo "$pkg_version" | wc -l) -gt 1 ]; then + echo "Package name is not unique! The following packages are installed:" + echo "$pkg_version" + exit 1 +else + state_is="present" + installed_version="$(echo "$pkg_version" | cut -d " " -f 2)" +fi + +if [ -f "$__object/parameter/version" ]; then + version="$(cat "$__object/parameter/version")" + if [ ! -z "$version" ]; then + name="=$name-$version" + fi +else + version="" +fi + +# Exit if nothing is needed to be done +[ "$state_is" = "$state_should" ] && ( [ -z "$version" ] || [ "$installed_version" = "$version" ] ) && exit 0 +[ "$state_should" = "absent" ] && [ ! -z "$version" ] && [ "$installed_version" != "$version" ] && exit 0 + +case "$state_should" in + present) + echo "emerge \"$name\" &>/dev/null || exit 1" + ;; + absent) + echo "emerge -C \"$name\" &>/dev/null || exit 1" + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__package_emerge/man.text b/cdist/conf/type/__package_emerge/man.text new file mode 100644 index 00000000..983b49a8 --- /dev/null +++ b/cdist/conf/type/__package_emerge/man.text @@ -0,0 +1,60 @@ +cdist-type__package_emerge(7) +============================= +Thomas Oettli + + +NAME +---- +cdist-type__package_emerge - Manage packages with portage + + +DESCRIPTION +----------- +Portage is usually used on the gentoo distribution to manage packages. +This type requires app-portage/gentoolkit installed on the target host. +cdist-type__package_emerge_dependencies is supposed to install the needed +packages on the target host. + + +REQUIRED PARAMETERS +------------------- +None + + +OPTIONAL PARAMETERS +------------------- +name:: + If supplied, use the name and not the object id as the package name. + +state:: + Either "present" or "absent", defaults to "present". + +version:: + If supplied, use to install or uninstall a specific version of the package named. + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure sys-devel/gcc is installed +__package_emerge sys-devel/gcc --state present + +# If you want a specific version of a package +__package_emerge app-portage/gentoolkit --state present --version 0.3.0.8-r2 + +# Remove package +__package_emerge sys-devel/gcc --state absent +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__package(7) +- cdist-type__package_emerge_dependencies(7) + + +COPYING +------- +Copyright \(C) 2013 Thomas Oettli. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__package_emerge/parameter/optional b/cdist/conf/type/__package_emerge/parameter/optional new file mode 100644 index 00000000..f5c897df --- /dev/null +++ b/cdist/conf/type/__package_emerge/parameter/optional @@ -0,0 +1,3 @@ +name +state +version diff --git a/cdist/conf/type/__package_emerge_dependencies/explorer/flaggie_installed b/cdist/conf/type/__package_emerge_dependencies/explorer/flaggie_installed new file mode 100644 index 00000000..1652ffc3 --- /dev/null +++ b/cdist/conf/type/__package_emerge_dependencies/explorer/flaggie_installed @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ -x /usr/bin/flaggie ]; then + echo "true" +else + echo "false" +fi diff --git a/cdist/conf/type/__package_emerge_dependencies/explorer/gentoolkit_installed b/cdist/conf/type/__package_emerge_dependencies/explorer/gentoolkit_installed new file mode 100644 index 00000000..74c2378d --- /dev/null +++ b/cdist/conf/type/__package_emerge_dependencies/explorer/gentoolkit_installed @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ -x /usr/bin/q ]; then + echo "true" +else + echo "false" +fi diff --git a/cdist/conf/type/__package_emerge_dependencies/gencode-remote b/cdist/conf/type/__package_emerge_dependencies/gencode-remote new file mode 100644 index 00000000..0c84e53d --- /dev/null +++ b/cdist/conf/type/__package_emerge_dependencies/gencode-remote @@ -0,0 +1,15 @@ +#!/bin/sh + +gentoolkit_installed="$(cat "$__object/explorer/gentoolkit_installed")" +flaggie_installed="$(cat "$__object/explorer/flaggie_installed")" + +if [ "${gentoolkit_installed}" != "true" ]; then + # emerge app-portage/gentoolkit + echo "emerge app-portage/gentoolkit &> /dev/null || exit 1" +fi + +if [ "${flaggie_installed}" != "true" ]; then + # emerge app-portage/flaggie + echo "emerge app-portage/flaggie &> /dev/null || exit 1" +fi + diff --git a/cdist/conf/type/__package_emerge_dependencies/man.text b/cdist/conf/type/__package_emerge_dependencies/man.text new file mode 100644 index 00000000..0862256b --- /dev/null +++ b/cdist/conf/type/__package_emerge_dependencies/man.text @@ -0,0 +1,48 @@ +cdist-type__package_emerge_dependencies(7) +========================================== +Thomas Oettli + + +NAME +---- +cdist-type__package_emerge_dependencies - Install dependencies for __package_emerge + + +DESCRIPTION +----------- +Portage is usually used on the gentoo distribution to manage packages. +This type installs the following tools which are required by __package_emerge to work: +app-portage/flaggie +app-portage/gentoolkit + + +REQUIRED PARAMETERS +------------------- +None + + +OPTIONAL PARAMETERS +------------------- +None + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure app-portage/flaggie and app-portage/gentoolkit are installed +__package_emerge_dependencies +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__package(7) +- cdist-type__package_emerge(7) + + +COPYING +------- +Copyright \(C) 2013 Thomas Oettli. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/test/autorequire/fixtures/conf/type/__directory/.keep b/cdist/conf/type/__package_emerge_dependencies/singleton similarity index 100% rename from cdist/test/autorequire/fixtures/conf/type/__directory/.keep rename to cdist/conf/type/__package_emerge_dependencies/singleton diff --git a/cdist/conf/type/__package_opkg/gencode-remote b/cdist/conf/type/__package_opkg/gencode-remote index 43f1ad8a..1fb78fbe 100755 --- a/cdist/conf/type/__package_opkg/gencode-remote +++ b/cdist/conf/type/__package_opkg/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011,2013 Nico Schottelius (nico-cdist at schottelius.org) # 2012 Giel van Schijndel (giel plus cdist at mortis dot eu) # # This file is part of cdist. @@ -42,20 +42,20 @@ case "$state_is" in ;; esac -if [ "$state_is" != "$state_should" ]; then - case "$state_should" in - present) - if [ "$present" = "notpresent" ]; then +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + if [ "$present" = "notpresent" ]; then echo opkg --verbosity=0 update - fi - echo opkg --verbosity=0 install \"$name\" - ;; - absent) - echo opkg --verbosity=0 remove \"$name\" - ;; - *) - echo "Unknown state: $state" >&2 - exit 1 - ;; - esac -fi + fi + echo opkg --verbosity=0 install \"$name\" + ;; + absent) + echo opkg --verbosity=0 remove \"$name\" + ;; + *) + echo "Unknown state: $state" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__package_yum/gencode-remote b/cdist/conf/type/__package_yum/gencode-remote index 9c98c257..5f0e8ac8 100755 --- a/cdist/conf/type/__package_yum/gencode-remote +++ b/cdist/conf/type/__package_yum/gencode-remote @@ -27,11 +27,7 @@ else name="$__object_id" fi -if [ -f "$__object/parameter/state" ]; then - state_should="$(cat "$__object/parameter/state")" -else - state_should="present" -fi +state_should="$(cat "$__object/parameter/state")" if grep -q -E "(centos|redhat|amazon)" "$__global/explorer/os"; then opts="-y --quiet" diff --git a/cdist/conf/type/__package_yum/parameter/default/state b/cdist/conf/type/__package_yum/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__package_yum/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__package_zypper/explorer/pkg_version b/cdist/conf/type/__package_zypper/explorer/pkg_version old mode 100755 new mode 100644 index fb3b7753..7f203067 --- a/cdist/conf/type/__package_zypper/explorer/pkg_version +++ b/cdist/conf/type/__package_zypper/explorer/pkg_version @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -18,7 +19,7 @@ # along with cdist. If not, see . # # -# Retrieve the status of a package +# Retrieve the status of a package of different types # if [ -f "$__object/parameter/name" ]; then @@ -27,4 +28,21 @@ else name="$__object_id" fi -rpm -q --whatprovides "$name" 2>/dev/null || true +if [ -f "$__object/parameter/ptype" ]; then + ptype="$(cat "$__object/parameter/ptype")" +else + ptype="package" +fi + +case "$ptype" in + package) + zypper search --details --match-exact --installed-only --type "$ptype" "$name" | grep -E '^i' | cut -d " " -f 3,7 || true + ;; + patch|pattern|product|srcpackage) + zypper search --match-exact --installed-only --type "$ptype" "$name" | grep -E '^i' | cut -d " " -f 3 || true + ;; + *) + echo "unknown ptype in __package_zypper explorer" &>2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__package_zypper/gencode-remote b/cdist/conf/type/__package_zypper/gencode-remote old mode 100755 new mode 100644 index ca9aec33..d9f16f8d --- a/cdist/conf/type/__package_zypper/gencode-remote +++ b/cdist/conf/type/__package_zypper/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -28,29 +29,50 @@ globalopts="--quiet --non-interactive" if [ -f "$__object/parameter/name" ]; then - name="$__object/parameter/name" + name="$__object/parameter/name" else - name="$__object_id" + name="$__object_id" fi -if [ -f "$__object/parameter/state" ]; then - state_should="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" +ptype="$(cat "$__object/parameter/ptype")" + +if [ -f "$__object/parameter/version" ]; then + version_should="$(cat "$__object/parameter/version")" + if [ "$ptype" != "package" ]; then + echo "version support only for type package implemented" >&2 + exit 2 + fi else - state_should="present" + version_should="" +fi + +pkg_version="$(cat "$__object/explorer/pkg_version")" +if [ -z "$pkg_version" ]; then + state_is="absent" + version_is="" +else + state_is="present" + version_is=${pkg_version##* } fi -# Exit if nothing is needed to be done -[ "$state_is" = "$state_should" ] && exit 0 case "$state_should" in - present) - echo zypper "$globalopts" install --auto-agree-with-licenses \"$name\" - ;; - absent) - echo pacman "$globalopts" remove \"$name\" - ;; - *) - echo "Unknown state: $state_should" >&2 - exit 1 - ;; + present) + if [ -z "$version_should" ]; then + [ "$state_is" = "present" ] && exit 0 # if state is present, we dont need to do anything + echo zypper $globalopts install --type \"$ptype\" --auto-agree-with-licenses \"$name\" ">/dev/null" + else + [ "$state_is" = "present" ] && [ "$version_should" = "$version_is" ] && exit 0 # if state is present and version is correct, we dont need to do anything + echo zypper $globalopts install --oldpackage --type \"$ptype\" --auto-agree-with-licenses \"$name\" = \"$version_should\" ">/dev/null" + fi + ;; + absent) + [ "$state_is" = "absent" ] && exit 0 # if state is absent, we dont need to do anything + echo zypper $globalopts remove --type \"$ptype\" \"$name\" ">/dev/null" + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; esac diff --git a/cdist/conf/type/__package_zypper/man.text b/cdist/conf/type/__package_zypper/man.text index e2261d33..104d3a7a 100644 --- a/cdist/conf/type/__package_zypper/man.text +++ b/cdist/conf/type/__package_zypper/man.text @@ -1,6 +1,6 @@ cdist-type__package_zypper(7) ============================= -Nico Schottelius +Daniel Heule NAME @@ -26,19 +26,33 @@ name:: state:: Either "present" or "absent", defaults to "present" +version:: + The version of the package to install. Default is to install the version + choosen by the local package manager. For a list of available versions, + have a look at the output of "zypper se -s packagename" + +ptype:: + Either "package", "patch", "pattern", "product" or "srcpackage", defaults to "package". For a description see man zypper. + EXAMPLES -------- -------------------------------------------------------------------------------- -# Ensure zsh in installed +# Ensure zsh is installed __package_zypper zsh --state present # If you don't want to follow pythonX packages, but always use python __package_zypper python --state present --name python2 +# Ensure binutils is installed and the version is forced to be 2.23.1-0.19.2 +__package_zypper binutils --state present --version 2.23.1-0.19.2 + # Remove package __package_zypper cfengine --state absent + +# install all packages which belongs to pattern x11 +__package_zypper x11 --ptype pattern --state present -------------------------------------------------------------------------------- @@ -50,5 +64,6 @@ SEE ALSO 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). +Copyright \(C) 2012 Nico Schottelius. +Copyright \(C) 2013 Daniel Heule. +Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__package_zypper/parameter/default/ptype b/cdist/conf/type/__package_zypper/parameter/default/ptype new file mode 100644 index 00000000..ba3bd787 --- /dev/null +++ b/cdist/conf/type/__package_zypper/parameter/default/ptype @@ -0,0 +1 @@ +package diff --git a/cdist/conf/type/__package_zypper/parameter/default/state b/cdist/conf/type/__package_zypper/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__package_zypper/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__package_zypper/parameter/optional b/cdist/conf/type/__package_zypper/parameter/optional index 1b423dc4..bc8565fc 100644 --- a/cdist/conf/type/__package_zypper/parameter/optional +++ b/cdist/conf/type/__package_zypper/parameter/optional @@ -1,2 +1,4 @@ name state +ptype +version diff --git a/cdist/conf/type/__pf_ruleset/man.text b/cdist/conf/type/__pf_ruleset/man.text index 0dc07f71..29efe065 100644 --- a/cdist/conf/type/__pf_ruleset/man.text +++ b/cdist/conf/type/__pf_ruleset/man.text @@ -16,7 +16,7 @@ This type is used on *BSD systems to manage the pf firewall's ruleset. REQUIRED PARAMETERS ------------------- state:: - Either "absent" (no ruleset at all) or "present" + Either "absent" (no ruleset at all) or "present", defaults to "present". OPTIONAL PARAMETERS diff --git a/cdist/conf/type/__pf_ruleset/parameter/default/state b/cdist/conf/type/__pf_ruleset/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__pf_ruleset/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__pf_ruleset/parameter/optional b/cdist/conf/type/__pf_ruleset/parameter/optional index 5a18cd2f..d77f3048 100644 --- a/cdist/conf/type/__pf_ruleset/parameter/optional +++ b/cdist/conf/type/__pf_ruleset/parameter/optional @@ -1 +1,2 @@ source +state diff --git a/cdist/conf/type/__postfix/man.text b/cdist/conf/type/__postfix/man.text new file mode 100644 index 00000000..1a91723a --- /dev/null +++ b/cdist/conf/type/__postfix/man.text @@ -0,0 +1,42 @@ +cdist-type__postfix(7) +====================== +Steven Armstrong + + +NAME +---- +cdist-type__postfix - install postfix + + +DESCRIPTION +----------- +This space intentionally left blank. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__postfix +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2012 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__postfix/manifest b/cdist/conf/type/__postfix/manifest new file mode 100755 index 00000000..52a13919 --- /dev/null +++ b/cdist/conf/type/__postfix/manifest @@ -0,0 +1,33 @@ +#!/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 . +# + + +os=$(cat "$__global/explorer/os") + +case "$os" in + ubuntu|debian|archlinux|suse) + __package postfix --state present + ;; + *) + echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 + ;; +esac diff --git a/cdist/test/autorequire/fixtures/conf/type/__package_special/.keep b/cdist/conf/type/__postfix/singleton similarity index 100% rename from cdist/test/autorequire/fixtures/conf/type/__package_special/.keep rename to cdist/conf/type/__postfix/singleton diff --git a/cdist/conf/type/__ssh_authorized_keys/explorer/entry b/cdist/conf/type/__postfix_master/explorer/entry similarity index 66% rename from cdist/conf/type/__ssh_authorized_keys/explorer/entry rename to cdist/conf/type/__postfix_master/explorer/entry index 9992d32d..9d6b1514 100755 --- a/cdist/conf/type/__ssh_authorized_keys/explorer/entry +++ b/cdist/conf/type/__postfix_master/explorer/entry @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011 - 2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -18,18 +18,12 @@ # along with cdist. If not, see . # -owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" -if [ -f "$__object/parameter/file" ]; then - file="$(cat "$__object/parameter/file")" -else - home="$("$__type_explorer/passwd" | cut -d':' -f 6)" - file="$home/.ssh/authorized_keys" -fi +config="/etc/postfix/master.cf" -# no authorized_keys file, nothing we could do -[ -f "$file" ] || exit 0 +# no master.cf, nothing we could do +[ -f "$config" ] || exit 0 -# NOTE: keep variables in sync in manifest/explorer/gencode-* +# NOTE: keep variables in sync in manifest,explorer,gencode-* prefix="#cdist:$__object_name" suffix="#/cdist:$__object_name" awk -v prefix="$prefix" -v suffix="$suffix" '{ @@ -42,4 +36,4 @@ awk -v prefix="$prefix" -v suffix="$suffix" '{ } print } -}' "$file" +}' "$config" diff --git a/cdist/conf/type/__ssh_authorized_keys/gencode-remote b/cdist/conf/type/__postfix_master/gencode-remote similarity index 78% rename from cdist/conf/type/__ssh_authorized_keys/gencode-remote rename to cdist/conf/type/__postfix_master/gencode-remote index cc86cc19..51edc668 100755 --- a/cdist/conf/type/__ssh_authorized_keys/gencode-remote +++ b/cdist/conf/type/__postfix_master/gencode-remote @@ -18,15 +18,9 @@ # along with cdist. If not, see . # -owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" -if [ -f "$__object/parameter/file" ]; then - file="$(cat "$__object/parameter/file")" -else - home="$(cut -d':' -f 6 "$__object/explorer/passwd")" - file="$home/.ssh/authorized_keys" -fi - +config="/etc/postfix/master.cf" entry="$__object/files/entry" +state_should="$(cat "$__object/parameter/state")" if [ ! -s "$__object/explorer/entry" ]; then state_is='absent' else @@ -36,18 +30,20 @@ else ) fi -state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo present)" if [ "$state_should" = "$state_is" ]; then # Nothing to do, move along exit 0 fi + remove_entry() { # NOTE: keep variables in sync in manifest/explorer/gencode-* prefix="#cdist:$__object_name" suffix="#/cdist:$__object_name" cat << DONE -tmpfile=\$(mktemp) +tmpfile=\$(mktemp ${config}.cdist.XXXXXXXXXX) +# preserve ownership and permissions of existing file +cp -p "$config" "\$tmpfile" awk -v prefix="$prefix" -v suffix="$suffix" ' { if (index(\$0,prefix)) { @@ -60,8 +56,8 @@ awk -v prefix="$prefix" -v suffix="$suffix" ' } else { print } -}' "$file" > "\$tmpfile" -mv -f "\$tmpfile" "$file" +}' "$config" > "\$tmpfile" +mv -f "\$tmpfile" "$config" DONE } @@ -71,7 +67,7 @@ case "$state_should" in remove_entry fi cat << DONE -cat >> "$file" << ${__type##*/}_DONE +cat >> "$config" << ${__type##*/}_DONE $(cat "$entry") ${__type##*/}_DONE DONE diff --git a/cdist/conf/type/__postfix_master/man.text b/cdist/conf/type/__postfix_master/man.text new file mode 100644 index 00000000..0ec78752 --- /dev/null +++ b/cdist/conf/type/__postfix_master/man.text @@ -0,0 +1,73 @@ +cdist-type__postfix_master(7) +============================= +Steven Armstrong + + +NAME +---- +cdist-type__postfix_master - configure postfix master.cf + + +DESCRIPTION +----------- +See master(5) for more information. + + +REQUIRED PARAMETERS +------------------- +type:: + See master(5) +command:: + See master(5) + + +BOOLEAN PARAMETERS +------------------ +noreload:: + don't reload postfix after changes + + +OPTIONAL PARAMETERS +------------------- +state:: + present or absent, defaults to present +service:: +private:: +unpriv:: +chroot:: +wakeup:: +maxproc:: +option:: + Pass an option to a service. Same as using -o in master.cf. + Can be specified multiple times. +comment:: + a textual comment to add with the master.cf entry + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__postfix_master smtp --type inet --command smtpd + +__postfix_master smtp --type inet --chroot y --command smtpd \ + --option smtpd_enforce_tls=yes \ + --option smtpd_sasl_auth_enable=yes \ + --option smtpd_client_restrictions=permit_sasl_authenticated,reject + +__postfix_master submission --type inet --command smtpd \ + --comment "Run alternative smtp on submission port" +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- master(5) + + +COPYING +------- +Copyright \(C) 2012 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). + diff --git a/cdist/conf/type/__postfix_master/manifest b/cdist/conf/type/__postfix_master/manifest new file mode 100755 index 00000000..87e2329b --- /dev/null +++ b/cdist/conf/type/__postfix_master/manifest @@ -0,0 +1,82 @@ +#!/bin/sh +# +# 2012 - 2013 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 . +# + + +os=$(cat "$__global/explorer/os") + +case "$os" in + ubuntu|debian|archlinux) + : + ;; + *) + echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 + ;; +esac + +__postfix + +# Default to object_id +service="$(cat "$__object/parameter/service" 2>/dev/null || echo "$__object_id")" +state="$(cat "$__object/parameter/state")" + +# NOTE: keep variables in sync in manifest,explorer,gencode-* +prefix="#cdist:$__object_name" +suffix="#/cdist:$__object_name" + +# Generate entry for inclusion in master.cf +mkdir "$__object/files" +entry="$__object/files/entry" +( + echo "$prefix" + if [ -f "$__object/parameter/comment" ]; then + echo "# $(cat "$__object/parameter/comment")" + fi + printf "%s " "$service" + printf "%s " "$type" + for parameter in type private unpriv chroot wakeup maxproc; do + printf "%s " "$(cat "$__object/parameter/$parameter")" + done + command="$(cat "$__object/parameter/command")" + # ensure we have a trailing newline + echo "$command" + options="$(cat "$__object/parameter/option" 2>/dev/null || true)" + for option in $options; do + echo " -o $option" + done + echo "$suffix" +) > "$entry" + +# Reload postfix after changes +if [ ! -f "$__object/parameter/noreload" ]; then + state_should="$(cat "$__object/parameter/state")" + if [ ! -s "$__object/explorer/entry" ]; then + state_is='absent' + else + state_is=$(diff -q "$entry" "$__object/explorer/entry" >/dev/null \ + && echo present \ + || echo changed + ) + fi + if [ "$state_is" != "$state_should" ]; then + require="$__object_name" __postfix_reload + fi +fi diff --git a/cdist/conf/type/__postfix_master/parameter/boolean b/cdist/conf/type/__postfix_master/parameter/boolean new file mode 100644 index 00000000..862edc87 --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/boolean @@ -0,0 +1 @@ +noreload diff --git a/cdist/conf/type/__postfix_master/parameter/default/chroot b/cdist/conf/type/__postfix_master/parameter/default/chroot new file mode 100644 index 00000000..39cdd0de --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/default/chroot @@ -0,0 +1 @@ +- diff --git a/cdist/conf/type/__postfix_master/parameter/default/maxproc b/cdist/conf/type/__postfix_master/parameter/default/maxproc new file mode 100644 index 00000000..39cdd0de --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/default/maxproc @@ -0,0 +1 @@ +- diff --git a/cdist/conf/type/__postfix_master/parameter/default/private b/cdist/conf/type/__postfix_master/parameter/default/private new file mode 100644 index 00000000..39cdd0de --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/default/private @@ -0,0 +1 @@ +- diff --git a/cdist/conf/type/__postfix_master/parameter/default/state b/cdist/conf/type/__postfix_master/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__postfix_master/parameter/default/unpriv b/cdist/conf/type/__postfix_master/parameter/default/unpriv new file mode 100644 index 00000000..39cdd0de --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/default/unpriv @@ -0,0 +1 @@ +- diff --git a/cdist/conf/type/__postfix_master/parameter/default/wakeup b/cdist/conf/type/__postfix_master/parameter/default/wakeup new file mode 100644 index 00000000..39cdd0de --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/default/wakeup @@ -0,0 +1 @@ +- diff --git a/cdist/conf/type/__postfix_master/parameter/optional b/cdist/conf/type/__postfix_master/parameter/optional new file mode 100644 index 00000000..792b42c5 --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/optional @@ -0,0 +1,9 @@ +service +private +unpriv +chroot +wakeup +maxproc +option +comment +state diff --git a/cdist/conf/type/__postfix_master/parameter/required b/cdist/conf/type/__postfix_master/parameter/required new file mode 100644 index 00000000..24c14146 --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/required @@ -0,0 +1,2 @@ +type +command diff --git a/cdist/conf/type/__postfix_postconf/explorer/value b/cdist/conf/type/__postfix_postconf/explorer/value new file mode 100755 index 00000000..e08c6da6 --- /dev/null +++ b/cdist/conf/type/__postfix_postconf/explorer/value @@ -0,0 +1,37 @@ +#!/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 . +# + + +os=$("$__explorer/os") + +case "$os" in + ubuntu|debian|archlinux|suse) + : + ;; + *) + echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 + ;; +esac + +key="$(cat "$__object/parameter/key" 2>/dev/null || echo "$__object_id")" + +postconf -h "$key" diff --git a/cdist/conf/type/__postfix_postconf/gencode-remote b/cdist/conf/type/__postfix_postconf/gencode-remote new file mode 100755 index 00000000..43c0482e --- /dev/null +++ b/cdist/conf/type/__postfix_postconf/gencode-remote @@ -0,0 +1,60 @@ +#!/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 . +# + +os=$(cat "$__global/explorer/os") + +case "$os" in + ubuntu|debian|archlinux|suse) + : + ;; + *) + echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 + ;; +esac + +state_should="$(cat "$__object/parameter/state")" +if [ ! -s "$__object/explorer/value" ]; then + state_is='absent' +else + state_is=$(diff -q "$__object/parameter/value" "$__object/explorer/value" >/dev/null \ + && echo present \ + || echo changed + ) +fi + +if [ "$state_should" = "$state_is" ]; then + # Nothing to do, move along + exit 0 +fi + +key="$(cat "$__object/parameter/key" 2>/dev/null || echo "$__object_id")" +value="$(cat "$__object/parameter/value")" + +case "$state_should" in + absent) + # revert parameter to its default value + echo "postconf -# $key" + ;; + present) + echo "postconf -e '$key=$value'" + ;; +esac diff --git a/cdist/conf/type/__postfix_postconf/man.text b/cdist/conf/type/__postfix_postconf/man.text new file mode 100644 index 00000000..727637b1 --- /dev/null +++ b/cdist/conf/type/__postfix_postconf/man.text @@ -0,0 +1,51 @@ +cdist-type__postfix_postconf(7) +=============================== +Steven Armstrong + + +NAME +---- +cdist-type__postfix_postconf - configure postfix main.cf + + +DESCRIPTION +----------- +See postconf(5) for possible keys and values. + +Note that this type directly runs the postconf executable. +It does not make changes to /etc/postfix/main.cf itself. + + +REQUIRED PARAMETERS +------------------- +value:: + the value for the postfix parameter + + +OPTIONAL PARAMETERS +------------------- +key:: + the name of the parameter. Defaults to __object_id + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__postfix_postconf mydomain --value somedomain.com + +__postfix_postconf bind-to-special-ip --key smtp_bind_address --value 127.0.0.5 + +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- postconf(5) + + +COPYING +------- +Copyright \(C) 2012 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__postfix_postconf/manifest b/cdist/conf/type/__postfix_postconf/manifest new file mode 100755 index 00000000..0dde64e9 --- /dev/null +++ b/cdist/conf/type/__postfix_postconf/manifest @@ -0,0 +1,21 @@ +#!/bin/sh +# +# 2012 - 2013 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 . +# + +__postfix diff --git a/cdist/conf/type/__postfix_postconf/parameter/default/state b/cdist/conf/type/__postfix_postconf/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__postfix_postconf/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__rvm/parameter/required b/cdist/conf/type/__postfix_postconf/parameter/optional similarity index 60% rename from cdist/conf/type/__rvm/parameter/required rename to cdist/conf/type/__postfix_postconf/parameter/optional index ff72b5c7..6ada755a 100644 --- a/cdist/conf/type/__rvm/parameter/required +++ b/cdist/conf/type/__postfix_postconf/parameter/optional @@ -1 +1,2 @@ +key state diff --git a/cdist/conf/type/__postfix_postconf/parameter/required b/cdist/conf/type/__postfix_postconf/parameter/required new file mode 100644 index 00000000..6d4e1507 --- /dev/null +++ b/cdist/conf/type/__postfix_postconf/parameter/required @@ -0,0 +1 @@ +value diff --git a/cdist/conf/type/__postfix_postmap/gencode-remote b/cdist/conf/type/__postfix_postmap/gencode-remote new file mode 100755 index 00000000..1b370001 --- /dev/null +++ b/cdist/conf/type/__postfix_postmap/gencode-remote @@ -0,0 +1,21 @@ +#!/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 . +# + +echo "postmap /$__object_id" diff --git a/cdist/conf/type/__postfix_postmap/man.text b/cdist/conf/type/__postfix_postmap/man.text new file mode 100644 index 00000000..37060d04 --- /dev/null +++ b/cdist/conf/type/__postfix_postmap/man.text @@ -0,0 +1,42 @@ +cdist-type__postfix_postmap(7) +============================== +Steven Armstrong + + +NAME +---- +cdist-type__postfix_postmap - run postmap on the given file + + +DESCRIPTION +----------- +This space intentionally left blank. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__postfix_postmap /etc/postfix/generic +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2012 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__postfix_postmap/manifest b/cdist/conf/type/__postfix_postmap/manifest new file mode 100755 index 00000000..0dde64e9 --- /dev/null +++ b/cdist/conf/type/__postfix_postmap/manifest @@ -0,0 +1,21 @@ +#!/bin/sh +# +# 2012 - 2013 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 . +# + +__postfix diff --git a/cdist/conf/type/__postfix_reload/gencode-remote b/cdist/conf/type/__postfix_reload/gencode-remote new file mode 100755 index 00000000..5822f1e3 --- /dev/null +++ b/cdist/conf/type/__postfix_reload/gencode-remote @@ -0,0 +1,33 @@ +#!/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 . +# + + +os=$(cat "$__global/explorer/os") + +case "$os" in + ubuntu|debian|archlinux) + echo "postfix reload" + ;; + *) + echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__postfix_reload/man.text b/cdist/conf/type/__postfix_reload/man.text new file mode 100644 index 00000000..c63356b5 --- /dev/null +++ b/cdist/conf/type/__postfix_reload/man.text @@ -0,0 +1,42 @@ +cdist-type__postfix_reload(7) +============================= +Steven Armstrong + + +NAME +---- +cdist-type__postfix_reload - tell postfix to reload its configuration + + +DESCRIPTION +----------- +This space intentionally left blank. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__postfix_reload +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2012 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__postfix_reload/manifest b/cdist/conf/type/__postfix_reload/manifest new file mode 100755 index 00000000..0dde64e9 --- /dev/null +++ b/cdist/conf/type/__postfix_reload/manifest @@ -0,0 +1,21 @@ +#!/bin/sh +# +# 2012 - 2013 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 . +# + +__postfix diff --git a/cdist/test/autorequire/fixtures/conf/type/__user/.keep b/cdist/conf/type/__postfix_reload/singleton similarity index 100% rename from cdist/test/autorequire/fixtures/conf/type/__user/.keep rename to cdist/conf/type/__postfix_reload/singleton diff --git a/cdist/conf/type/__postgres_database/man.text b/cdist/conf/type/__postgres_database/man.text index d01ca8f6..c7c0d3cd 100644 --- a/cdist/conf/type/__postgres_database/man.text +++ b/cdist/conf/type/__postgres_database/man.text @@ -13,14 +13,11 @@ DESCRIPTION This cdist type allows you to create or drop postgres databases. -REQUIRED PARAMETERS -------------------- -state:: - either 'present' or 'absent' - - OPTIONAL PARAMETERS ------------------- +state:: + either 'present' or 'absent', defaults to 'present'. + owner:: the role owning this database @@ -29,7 +26,7 @@ EXAMPLES -------- -------------------------------------------------------------------------------- -__postgres_database mydbname --state present --owner mydbusername +__postgres_database mydbname --owner mydbusername -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__postgres_database/parameter/default/state b/cdist/conf/type/__postgres_database/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__postgres_database/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__postgres_database/parameter/optional b/cdist/conf/type/__postgres_database/parameter/optional index 7ee3bde8..d86b6469 100644 --- a/cdist/conf/type/__postgres_database/parameter/optional +++ b/cdist/conf/type/__postgres_database/parameter/optional @@ -1 +1,2 @@ +state owner diff --git a/cdist/conf/type/__postgres_role/gencode-remote b/cdist/conf/type/__postgres_role/gencode-remote index c9de4707..0230e48e 100755 --- a/cdist/conf/type/__postgres_role/gencode-remote +++ b/cdist/conf/type/__postgres_role/gencode-remote @@ -27,7 +27,7 @@ state_should="$(cat "$__object/parameter/state")" case "$state_should" in present) if [ -f "$__object/parameter/password" ]; then - password="$(cat "$__object/parameter/$parameter")" + password="$(cat "$__object/parameter/password")" fi booleans="" for boolean in login createdb createrole superuser; do diff --git a/cdist/conf/type/__postgres_role/man.text b/cdist/conf/type/__postgres_role/man.text index 904f0831..ac87754b 100644 --- a/cdist/conf/type/__postgres_role/man.text +++ b/cdist/conf/type/__postgres_role/man.text @@ -13,15 +13,12 @@ DESCRIPTION This cdist type allows you to create or drop postgres roles. -REQUIRED PARAMETERS +OPTIONAL PARAMETERS ------------------- state:: Either "present" or "absent", defaults to "present" - -OPTIONAL PARAMETERS -------------------- -All parameter map directly to the corresponding postgres createrole +All other parameters map directly to the corresponding postgres createrole parameters. password:: @@ -41,13 +38,13 @@ EXAMPLES -------- -------------------------------------------------------------------------------- -__postgres_role myrole --state present +__postgres_role myrole -__postgres_role myrole --state present --password 'secret' +__postgres_role myrole --password 'secret' -__postgres_role admin --state present --password 'very-secret' --superuser +__postgres_role admin --password 'very-secret' --superuser -__postgres_role dbcustomer --state present --password 'bla' --createdb +__postgres_role dbcustomer --password 'bla' --createdb -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__postgres_role/parameter/default/state b/cdist/conf/type/__postgres_role/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__postgres_role/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__postgres_role/parameter/optional b/cdist/conf/type/__postgres_role/parameter/optional index f3097ab1..cb9b2c48 100644 --- a/cdist/conf/type/__postgres_role/parameter/optional +++ b/cdist/conf/type/__postgres_role/parameter/optional @@ -1 +1,2 @@ +state password diff --git a/cdist/conf/type/__process/gencode-remote b/cdist/conf/type/__process/gencode-remote index fdb6033a..639940d9 100755 --- a/cdist/conf/type/__process/gencode-remote +++ b/cdist/conf/type/__process/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -17,7 +18,6 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# if [ -f "$__object/parameter/name" ]; then name="$(cat "$__object/parameter/name")" @@ -27,14 +27,16 @@ fi state_should="$(cat "$__object/parameter/state")" -runs="$(cat "$__object/explorer/runs")" -if [ "$runs" ]; then +if [ -s "$__object/explorer/runs" ]; then state_is="present" else state_is="absent" fi -[ "$state_is" = "$state_should" ] && exit 0 +if [ "$state_is" = "$state_should" ]; then + # nothing to do + exit 0 +fi case "$state_should" in present) diff --git a/cdist/conf/type/__process/man.text b/cdist/conf/type/__process/man.text index 0d457ead..2fdd27aa 100644 --- a/cdist/conf/type/__process/man.text +++ b/cdist/conf/type/__process/man.text @@ -13,14 +13,11 @@ DESCRIPTION This cdist type allows you to define the state of a process. -REQUIRED PARAMETERS +OPTIONAL PARAMETERS ------------------- state:: Either "present" or "absent", defaults to "present" - -OPTIONAL PARAMETERS -------------------- name:: Process name to match on when using pgrep -f -x. diff --git a/cdist/conf/type/__process/parameter/default/state b/cdist/conf/type/__process/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__process/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__process/parameter/optional b/cdist/conf/type/__process/parameter/optional index 3411afb4..85fe8805 100644 --- a/cdist/conf/type/__process/parameter/optional +++ b/cdist/conf/type/__process/parameter/optional @@ -1,3 +1,4 @@ name stop start +state diff --git a/cdist/conf/type/__qemu_img/gencode-remote b/cdist/conf/type/__qemu_img/gencode-remote index 2a76cf8f..6e4bb4d0 100644 --- a/cdist/conf/type/__qemu_img/gencode-remote +++ b/cdist/conf/type/__qemu_img/gencode-remote @@ -2,8 +2,7 @@ # State: absent is handled by manifest - we need only to do stuff if image is # not existing and state != absent # -state="present" -[ -f "$__object/parameter/state" ] && state="$(cat "$__object/parameter/state")" +state="$(cat "$__object/parameter/state")" [ "$state" = "absent" ] && exit 0 exists="$(cat "$__object/explorer/exists")" @@ -13,8 +12,7 @@ exists="$(cat "$__object/explorer/exists")" # Still there? Create image # -format=qcow2 -[ -f "$__object/parameter/format" ] && format="$(cat "$__object/parameter/format")" +format="$(cat "$__object/parameter/format")" size="$(cat "$__object/parameter/size")" diskimage="/$__object_id" diff --git a/cdist/conf/type/__qemu_img/manifest b/cdist/conf/type/__qemu_img/manifest index b835301d..6d50037f 100644 --- a/cdist/conf/type/__qemu_img/manifest +++ b/cdist/conf/type/__qemu_img/manifest @@ -2,10 +2,8 @@ # Default settings # -format=qcow2 -state=present -[ -f "$__object/parameter/format" ] && format="$(cat "$__object/parameter/format")" -[ -f "$__object/parameter/state" ] && state="$(cat "$__object/parameter/state")" +format="$(cat "$__object/parameter/format")" +state="$(cat "$__object/parameter/state")" diskimage="/$__object_id" diff --git a/cdist/conf/type/__qemu_img/parameter/default/format b/cdist/conf/type/__qemu_img/parameter/default/format new file mode 100644 index 00000000..e0a90ab9 --- /dev/null +++ b/cdist/conf/type/__qemu_img/parameter/default/format @@ -0,0 +1 @@ +qcow2 diff --git a/cdist/conf/type/__qemu_img/parameter/default/state b/cdist/conf/type/__qemu_img/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__qemu_img/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__qemu_img/parameter/optional b/cdist/conf/type/__qemu_img/parameter/optional index 0e8469e7..71b9a32b 100644 --- a/cdist/conf/type/__qemu_img/parameter/optional +++ b/cdist/conf/type/__qemu_img/parameter/optional @@ -1 +1,2 @@ format +state diff --git a/cdist/conf/type/__rvm/man.text b/cdist/conf/type/__rvm/man.text index c1f83e60..0408d125 100644 --- a/cdist/conf/type/__rvm/man.text +++ b/cdist/conf/type/__rvm/man.text @@ -16,7 +16,7 @@ RVM is the Ruby enVironment Manager for the Ruby programming language. REQUIRED PARAMETERS ------------------- state:: - Either "present" or "absent". + Either "present" or "absent", defaults to "present". EXAMPLES diff --git a/cdist/conf/type/__rvm/parameter/default/state b/cdist/conf/type/__rvm/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__rvm/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__postgres_database/parameter/required b/cdist/conf/type/__rvm/parameter/optional similarity index 100% rename from cdist/conf/type/__postgres_database/parameter/required rename to cdist/conf/type/__rvm/parameter/optional diff --git a/cdist/conf/type/__rvm_gem/man.text b/cdist/conf/type/__rvm_gem/man.text index 2b72e7ae..d7eff3be 100644 --- a/cdist/conf/type/__rvm_gem/man.text +++ b/cdist/conf/type/__rvm_gem/man.text @@ -20,7 +20,7 @@ user:: gemset:: The gemset to use state:: - Either "present" or "absent" + Either "present" or "absent", defaults to "present". OPTIONAL PARAMETERS ------------------- diff --git a/cdist/conf/type/__rvm_gem/parameter/default/state b/cdist/conf/type/__rvm_gem/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__rvm_gem/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__rvm_gem/parameter/optional b/cdist/conf/type/__rvm_gem/parameter/optional index 4ad96d51..96983811 100644 --- a/cdist/conf/type/__rvm_gem/parameter/optional +++ b/cdist/conf/type/__rvm_gem/parameter/optional @@ -1 +1,2 @@ default +state diff --git a/cdist/conf/type/__rvm_gem/parameter/required b/cdist/conf/type/__rvm_gem/parameter/required index 75f60bb8..58243a95 100644 --- a/cdist/conf/type/__rvm_gem/parameter/required +++ b/cdist/conf/type/__rvm_gem/parameter/required @@ -1,3 +1,2 @@ -state gemset user diff --git a/cdist/conf/type/__rvm_gemset/man.text b/cdist/conf/type/__rvm_gemset/man.text index 44c0c555..e85425f3 100644 --- a/cdist/conf/type/__rvm_gemset/man.text +++ b/cdist/conf/type/__rvm_gemset/man.text @@ -18,7 +18,7 @@ REQUIRED PARAMETERS user:: The remote user account to use state:: - Either "present" or "absent". + Either "present" or "absent", defaults to "present". BOOLEAN PARAMETERS ------------------- diff --git a/cdist/conf/type/__rvm_gemset/parameter/default/state b/cdist/conf/type/__rvm_gemset/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__rvm_gemset/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__postgres_role/parameter/required b/cdist/conf/type/__rvm_gemset/parameter/optional similarity index 100% rename from cdist/conf/type/__postgres_role/parameter/required rename to cdist/conf/type/__rvm_gemset/parameter/optional diff --git a/cdist/conf/type/__rvm_gemset/parameter/required b/cdist/conf/type/__rvm_gemset/parameter/required index 5aea6f1e..4eb8387f 100644 --- a/cdist/conf/type/__rvm_gemset/parameter/required +++ b/cdist/conf/type/__rvm_gemset/parameter/required @@ -1,2 +1 @@ -state user diff --git a/cdist/conf/type/__rvm_ruby/man.text b/cdist/conf/type/__rvm_ruby/man.text index dbbab85e..6419a4d4 100644 --- a/cdist/conf/type/__rvm_ruby/man.text +++ b/cdist/conf/type/__rvm_ruby/man.text @@ -18,7 +18,7 @@ REQUIRED PARAMETERS user:: The remote user account to use state:: - Either "present" or "absent". + Either "present" or "absent", defaults to "present". BOOLEAN PARAMETERS ------------------ diff --git a/cdist/conf/type/__rvm_ruby/parameter/default/state b/cdist/conf/type/__rvm_ruby/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__rvm_ruby/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__process/parameter/required b/cdist/conf/type/__rvm_ruby/parameter/optional similarity index 100% rename from cdist/conf/type/__process/parameter/required rename to cdist/conf/type/__rvm_ruby/parameter/optional diff --git a/cdist/conf/type/__rvm_ruby/parameter/required b/cdist/conf/type/__rvm_ruby/parameter/required index 5aea6f1e..4eb8387f 100644 --- a/cdist/conf/type/__rvm_ruby/parameter/required +++ b/cdist/conf/type/__rvm_ruby/parameter/required @@ -1,2 +1 @@ -state user diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 268b1fbe..5a9cfbb3 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -19,7 +19,7 @@ # owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" -state="$(cat "$__object/parameter/present" 2>/dev/null || echo "present")" +state="$(cat "$__object/parameter/state" 2>/dev/null)" if [ -f "$__object/parameter/file" ]; then file="$(cat "$__object/parameter/file")" else @@ -39,7 +39,7 @@ if [ ! -f "$__object/parameter/noparent" -o ! -f "$__object/parameter/nofile" ]; fi if [ ! -f "$__object/parameter/noparent" ]; then - # Ensure that the directory in which the authorized_keys shall be exists and + # Ensure that the directory in which the authorized_keys shall be exists and # has the right permissions. ssh_directory="${file%/*}" __directory "$ssh_directory" --state present --parents \ @@ -56,19 +56,16 @@ if [ ! -f "$__object/parameter/noparent" -o ! -f "$__object/parameter/nofile" ]; fi fi -# NOTE: keep variables in sync in manifest/explorer/gencode-* -prefix="#cdist:$__object_name" -suffix="#/cdist:$__object_name" - -mkdir "$__object/files" - # Generate entry for inclusion in authorized_keys file -entry="$__object/files/entry" -echo "$prefix" > "$entry" +( if [ -f "$__object/parameter/comment" ]; then - echo "# $(cat "$__object/parameter/comment")" >> "$entry" + echo "# $(cat "$__object/parameter/comment")" fi -cat "$__object/parameter/key" >> "$entry" -# ensure we have a newline after keys -echo >> "$entry" -echo "$suffix" >> "$entry" +cat "$__object/parameter/key" +) | \ +__block "$__object_name" \ + --file "$file" \ + --prefix "#cdist:$__object_name" \ + --suffix "#/cdist:$__object_name" \ + --state "$state" \ + --text - diff --git a/cdist/conf/type/__ssh_authorized_keys/parameter/default/state b/cdist/conf/type/__ssh_authorized_keys/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_keys/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index 6fd0ea92..e9e4318e 100755 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -1,6 +1,7 @@ #!/bin/sh # -# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -23,25 +24,14 @@ os=$("$__explorer/os") runlevel=$("$__explorer/runlevel") +target_runlevel="$(cat "$__object/parameter/target_runlevel")" name="$__object_id" - case "$os" in archlinux) - # convert bash array to shell - daemons=$(grep ^DAEMONS /etc/rc.conf | sed -e 's/^.*=(//' -e 's/)$//') - - # absent, as long as not found - state="absent" - - # iterate, last one wins. - for daemon in $daemons; do - if [ "$daemon" = "$name" -o "$daemon" = "@${name}" ]; then - state="present" - elif [ "$daemon" = "!${name}" ]; then - state="absent" - fi - done + state=$(systemctl is-enabled "$name" >/dev/null 2>&1 \ + && echo present \ + || echo absent) ;; debian|ubuntu|openwrt) @@ -49,12 +39,24 @@ case "$os" in [ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent" ;; - amazon|centos|fedora|owl|redhat|suse) + amazon|centos|fedora|owl|redhat) state=$(chkconfig --level "$runlevel" "$name" || echo absent) [ "$state" ] || state="present" ;; - - *) + suse) + # check for target if set, usable for boot. services in runlevel B + if [ "$target_runlevel" != 'default' ]; then + runlevel="$target_runlevel" + fi + # suses chkconfig has the same name, but works different ... + state=$(chkconfig --check "$name" "$runlevel" || echo absent) + [ "$state" ] || state="present" + ;; + gentoo) + state="present" + [ -f "/etc/runlevels/${target_runlevel}/${name}" ] || state="absent" + ;; + *) echo "Unsupported os: $os" >&2 exit 1 ;; diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index 7724e8c7..61b2b9fe 100755 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # -# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -19,8 +20,9 @@ # # -state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo present)" +state_should="$(cat "$__object/parameter/state")" state_is=$(cat "$__object/explorer/state") +target_runlevel="$(cat "$__object/parameter/target_runlevel")" # Short circuit if nothing is to be done [ "$state_should" = "$state_is" ] && exit 0 @@ -32,17 +34,15 @@ case "$state_should" in present) case "$os" in archlinux) - echo "sed 's/^\\(DAEMONS=.*\\))/\\1 $name)/' /etc/rc.conf > /etc/rc.conf.cdist-tmp" - echo "mv /etc/rc.conf.cdist-tmp /etc/rc.conf" + echo "systemctl enable \"$name\"" ;; debian|ubuntu) echo "update-rc.d \"$name\" defaults >/dev/null" ;; -# FIXME: Disabled until the explorer is checked -# gentoo) -# echo rc-update add \"$name\" default -# ;; + gentoo) + echo rc-update add \"$name\" \"$target_runlevel\" + ;; amazon|centos|fedora|owl|redhat|suse) echo chkconfig \"$name\" on @@ -65,19 +65,15 @@ case "$state_should" in absent) case "$os" in archlinux) - # Replace a) at the beginning b) in the middle c) end d) only - # Support @name as well...makes it more ugly, but well... - echo "sed /etc/rc.conf -e 's/^\\(DAEMONS=(\\)@\\{0,1\\}$name /\\1/' -e 's/^\\(DAEMONS=(.* \\)@\\{0,1\\}$name \\(.*\\)/\\1\\2/' -e 's/^\\(DAEMONS=(.*\\) @\\{0,1\\}$name)/\\1)/' -e 's/^\\(DAEMONS=(\\)@\\{0,1\\}$name)/\\1)/' > /etc/rc.conf.cdist-tmp" - echo "mv /etc/rc.conf.cdist-tmp /etc/rc.conf" + echo "systemctl disable \"$name\"" ;; debian|ubuntu) echo update-rc.d -f \"$name\" remove ;; -# FIXME: Disabled until the explorer is checked -# gentoo) -# echo rc-update del \"$name\" -# ;; + gentoo) + echo rc-update del \"$name\" \"$target_runlevel\" + ;; centos|fedora|owl|redhat|suse) echo chkconfig \"$name\" off diff --git a/cdist/conf/type/__start_on_boot/man.text b/cdist/conf/type/__start_on_boot/man.text index 6d804884..dfada6d8 100644 --- a/cdist/conf/type/__start_on_boot/man.text +++ b/cdist/conf/type/__start_on_boot/man.text @@ -14,7 +14,7 @@ This cdist type allows you to enable or disable stuff to be started at boot of your operating system. Warning: This type has not been tested intensively and is not fully -supported (i.e. gentoo and *bsd are not implemented). +supported (i.e. *bsd are not implemented). REQUIRED PARAMETERS @@ -25,6 +25,8 @@ OPTIONAL PARAMETERS ------------------- state:: Either "present" or "absent", defaults to "present" +target_runlevel:: + Runlevel which should be modified, defaults to "default" (only used on gentoo systems). EXAMPLES diff --git a/cdist/conf/type/__start_on_boot/parameter/default/state b/cdist/conf/type/__start_on_boot/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__start_on_boot/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__start_on_boot/parameter/default/target_runlevel b/cdist/conf/type/__start_on_boot/parameter/default/target_runlevel new file mode 100644 index 00000000..4ad96d51 --- /dev/null +++ b/cdist/conf/type/__start_on_boot/parameter/default/target_runlevel @@ -0,0 +1 @@ +default diff --git a/cdist/conf/type/__start_on_boot/parameter/optional b/cdist/conf/type/__start_on_boot/parameter/optional index ff72b5c7..91685caf 100644 --- a/cdist/conf/type/__start_on_boot/parameter/optional +++ b/cdist/conf/type/__start_on_boot/parameter/optional @@ -1 +1,2 @@ state +target_runlevel diff --git a/cdist/conf/type/__update_alternatives/gencode-remote b/cdist/conf/type/__update_alternatives/gencode-remote new file mode 100755 index 00000000..19ea9968 --- /dev/null +++ b/cdist/conf/type/__update_alternatives/gencode-remote @@ -0,0 +1,26 @@ +#!/bin/sh +# +# 2013 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 . +# +# +# Setup alternative - no standard way to create, always set +# + +path="$(cat "$__object/parameter/path")" +name="$__object_id" +echo "update-alternatives --quiet --set '$name' '$path'" diff --git a/cdist/conf/type/__update_alternatives/man.text b/cdist/conf/type/__update_alternatives/man.text new file mode 100644 index 00000000..2bcc1874 --- /dev/null +++ b/cdist/conf/type/__update_alternatives/man.text @@ -0,0 +1,43 @@ +cdist-type__update_alternatives(7) +================================== +Nico Schottelius + + +NAME +---- +cdist-type__update_alternatives - Configure alternatives + + +DESCRIPTION +----------- +On Debian and alike systems update-alternatives(1) can be used +to setup alternatives for various programs. +One of the most common used targets is the "editor". + + +REQUIRED PARAMETERS +------------------- +path:: + Use this path for the given alternative + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Setup vim as the default editor +__update_alternatives editor --path /usr/bin/vim.basic +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__debconf_set_selections(7) +- update-alternatives(8) + + +COPYING +------- +Copyright \(C) 2013 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__update_alternatives/parameter/required b/cdist/conf/type/__update_alternatives/parameter/required new file mode 100644 index 00000000..e7a8fd4d --- /dev/null +++ b/cdist/conf/type/__update_alternatives/parameter/required @@ -0,0 +1 @@ +path diff --git a/cdist/conf/type/__user/TODO b/cdist/conf/type/__user/TODO deleted file mode 100644 index fa6aeee7..00000000 --- a/cdist/conf/type/__user/TODO +++ /dev/null @@ -1,2 +0,0 @@ -- delete users - diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index baa6f354..463fbe49 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -2,6 +2,7 @@ # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -21,11 +22,14 @@ # # Manage users. # +#set -x name="$__object_id" os="$(cat "$__global/explorer/os")" +state=$(cat "$__object/parameter/state") + # We need to shorten options for both usermod and useradd since on some # systems (such as *BSD, Darwin) those commands do not handle GNU style long # options. @@ -39,75 +43,100 @@ shorten_property() { password) ret="-p";; shell) ret="-s";; uid) ret="-u";; + create-home) ret="-m";; + system) ret="-r";; esac echo "$ret" } -cd "$__object/parameter" -if grep -q "^${name}:" "$__object/explorer/passwd"; then - for property in $(ls .); do - new_value="$(cat "$property")" - unset current_value +if [ "$state" = "present" ]; then + cd "$__object/parameter" + if grep -q "^${name}:" "$__object/explorer/passwd"; then + for property in $(ls .); do + new_value="$(cat "$property")" + unset current_value - file="$__object/explorer/passwd" + file="$__object/explorer/passwd" - case "$property" in - gid) - if $(echo "$new_value" | grep -q '^[0-9][0-9]*$'); then - field=4 + case "$property" in + gid) + if $(echo "$new_value" | grep -q '^[0-9][0-9]*$'); then + field=4 + else + # We were passed a group name. Compare the gid in + # the user's /etc/passwd entry with the gid of the + # 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 + ;; + password) + field=2 + file="$__object/explorer/shadow" + ;; + comment) field=5 ;; + home) field=6 ;; + shell) field=7 ;; + uid) field=3 ;; + create-home) continue;; # Does not apply to user modification + system) continue;; # Does not apply to user modification + state) continue;; # Does not apply to user modification + remove-home) continue;; # Does not apply to user modification + esac + + # If we haven't already set $current_value above, pull it from the + # appropriate file/field. + if [ -z "$current_value" ]; then + export field + current_value="$(awk -F: '{ print $ENVIRON["field"] }' < "$file")" + fi + + if [ "$new_value" != "$current_value" ]; then + set -- "$@" "$(shorten_property $property)" \'$new_value\' + fi + done + + if [ $# -gt 0 ]; then + echo mod >> "$__messages_out" + if [ "$os" = "freebsd" ]; then + echo pw usermod "$@" "$name" + else + echo usermod "$@" "$name" + fi + else + true + fi + else + echo add >> "$__messages_out" + for property in $(ls .); do + [ "$property" = "state" ] && continue + [ "$property" = "remove-home" ] && continue + new_value="$(cat "$property")" + if [ -z "$new_value" ];then # Boolean values have no value + set -- "$@" "$(shorten_property $property)" else - # We were passed a group name. Compare the gid in - # the user's /etc/passwd entry with the gid of the - # 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 + set -- "$@" "$(shorten_property $property)" \'$new_value\' fi - ;; - password) - field=2 - file="$__object/explorer/shadow" - ;; - comment) field=5 ;; - home) field=6 ;; - shell) field=7 ;; - uid) field=3 ;; - esac + done - # If we haven't already set $current_value above, pull it from the - # appropriate file/field. - if [ -z "$current_value" ]; then - export field - current_value="$(awk -F: '{ print $ENVIRON["field"] }' < "$file")" - fi - - if [ "$new_value" != "$current_value" ]; then - set -- "$@" "$(shorten_property $property)" \'$new_value\' - fi - done - - if [ $# -gt 0 ]; then - if [ "$os" = "freebsd" ]; then - echo pw usermod "$@" "$name" - else - echo usermod "$@" "$name" - fi - else - true - fi + if [ "$os" = "freebsd" ]; then + echo pw useradd "$@" "$name" + else + echo useradd "$@" "$name" + fi + fi else - for property in $(ls .); do - new_value="$(cat "$property")" - set -- "$@" "$(shorten_property $property)" \'$new_value\' - done - - if [ "$os" = "freebsd" ]; then - echo pw useradd "$@" "$name" - else - echo useradd "$@" "$name" - fi + if grep -q "^${name}:" "$__object/explorer/passwd"; then + #user exists, but state != present, so delete it + if [ -f "$__object/parameter/remove-home" ]; then + echo userdel -r "${name}" + else + echo userdel "${name}" + fi + fi fi diff --git a/cdist/conf/type/__user/man.text b/cdist/conf/type/__user/man.text index 9db4a9f0..be70ec12 100644 --- a/cdist/conf/type/__user/man.text +++ b/cdist/conf/type/__user/man.text @@ -20,18 +20,37 @@ None. OPTIONAL PARAMETERS ------------------- +state:: + absent or present, defaults to present comment:: - see usermod(8) + see usermod(8) home:: - see above + see above gid:: - see above + see above password:: - see above + see above shell:: - see above + see above uid:: - see above + see above + +BOOLEAN PARAMETERS +------------------ +system:: + see useradd(8), apply only on user create +create-home:: + see useradd(8), apply only on user create +remove-home:: + see userdel(8), apply only on user delete + + +MESSAGES +-------- +mod:: + User is modified +add:: + New user added EXAMPLES @@ -44,8 +63,14 @@ __user foobar # Same but with a different shell __user foobar --shell /bin/zsh +# Same but for a system account +__user foobar --system + # Set explicit uid and home __user foobar --uid 1001 --shell /bin/zsh --home /home/foobar + +# Drop user if exists +__user foobar --state absent -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__user/parameter/boolean b/cdist/conf/type/__user/parameter/boolean new file mode 100644 index 00000000..83afdebe --- /dev/null +++ b/cdist/conf/type/__user/parameter/boolean @@ -0,0 +1,3 @@ +create-home +remove-home +system diff --git a/cdist/conf/type/__user/parameter/default/state b/cdist/conf/type/__user/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__user/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__user/parameter/optional b/cdist/conf/type/__user/parameter/optional index e3cf52d5..de6c3838 100644 --- a/cdist/conf/type/__user/parameter/optional +++ b/cdist/conf/type/__user/parameter/optional @@ -1,3 +1,4 @@ +state comment home gid diff --git a/cdist/conf/type/__user_groups/gencode-remote b/cdist/conf/type/__user_groups/gencode-remote index c5e4a35e..9f11dd16 100755 --- a/cdist/conf/type/__user_groups/gencode-remote +++ b/cdist/conf/type/__user_groups/gencode-remote @@ -19,7 +19,7 @@ # user="$(cat "$__object/parameter/user" 2>/dev/null || echo "$__object_id")" -state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" +state_should="$(cat "$__object/parameter/state")" mkdir "$__object/files" # file has to be sorted for comparison with `comm` diff --git a/cdist/conf/type/__user_groups/parameter/default/state b/cdist/conf/type/__user_groups/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__user_groups/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__zypper_repo/explorer/all_repo_ids b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids new file mode 100644 index 00000000..b37d8ac5 --- /dev/null +++ b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids @@ -0,0 +1,24 @@ +#!/bin/sh +# +# 2013 Daniel Heule (hda at sfs.biz) +# +# 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 all repo id nummbers - parsed zypper output +# +# +echo $(zypper lr | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids new file mode 100644 index 00000000..2dfb946f --- /dev/null +++ b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids @@ -0,0 +1,26 @@ +#!/bin/sh +# +# 2013 Daniel Heule (hda at sfs.biz) +# +# 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 all repo id nummbers from enabled repos - parsed zypper output +# +# +# simpler command which works only on SLES11 SP3 or newer: +# echo $(zypper lr -E | cut -d'|' -f 1 | grep -E '^[0-9]') +echo $(zypper lr | grep -E '^[0-9]([^|]+\|){3,3} Yes' | cut -d'|' -f 1) diff --git a/cdist/conf/type/__zypper_repo/explorer/repo_id b/cdist/conf/type/__zypper_repo/explorer/repo_id new file mode 100644 index 00000000..83a698b7 --- /dev/null +++ b/cdist/conf/type/__zypper_repo/explorer/repo_id @@ -0,0 +1,29 @@ +#!/bin/sh +# +# 2013 Daniel Heule (hda at sfs.biz) +# +# 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 id from the repo with the uri from parameter repo_uri - parsed zypper output +# +# +if [ -f "$__object/parameter/repo_uri" ]; then + uri="$(cat "$__object/parameter/repo_uri")" +else + uri="$__object_id" +fi +echo $(zypper lr -u | grep -E "\<$uri\>" | cut -d'|' -f 1 | grep -E '^[0-9]' ) diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote new file mode 100644 index 00000000..f678552b --- /dev/null +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -0,0 +1,98 @@ +#!/bin/sh +# +# 2013 Daniel Heule (hda at sfs.biz) +# +# 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 repo services with Zypper (mostly suse) +# + +# Debug +#exec >&2 +#set -x + +zypper_def_opts=" -q " + +if [ -f "$__object/parameter/repo_desc" ]; then + desc="$(cat "$__object/parameter/repo_desc")" +else + desc="$__object_id" +fi + +if [ -f "$__object/parameter/repo_uri" ]; then + uri="$(cat "$__object/parameter/repo_uri")" +else + uri="$__object_id" +fi + +if [ -f "$__object/parameter/repo_id" ]; then + id="$(cat "$__object/parameter/repo_id")" +else + id="$__object_id" +fi + +state="$(cat "$__object/parameter/state")" + +repo_id="$(cat "$__object/explorer/repo_id")" + +act_id="" +if grep -q "$id" "$__object/explorer/all_repo_ids"; then + act_id="$id" +elif grep -q "$repo_id" "$__object/explorer/all_repo_ids"; then + act_id="$repo_id" +fi + +repostate="disabled" +if grep -q "$act_id" "$__object/explorer/enabled_repo_ids"; then + repostate="enabled" +fi + + +case "$state" in + present) + if [ -z "$desc" ] || [ -z "$uri" ]; then + echo "parameter repo_desc and repo_uri for $state needed" >&2 + exit 4 + fi + if [ -z "$repo_id" ]; then + # Repo not present, so we need to create it + echo zypper $zypper_def_opts addrepo "'$uri'" "'$desc'" + fi + ;; + absent) + if [ ! -z "$act_id" ]; then + # Repo present (act_id not ""), so we ned to delete it + echo zypper $zypper_def_opts removerepo "$act_id" + fi + ;; + enabled) + if [ ! -z "$act_id" ] && [ "$repostate" = "disabled" ]; then + # Repo present (act_id not "") and repostate not enabled, so a enable call is needed + echo zypper $zypper_def_opts modifyrepo -e "$act_id" + fi + ;; + disabled) + if [ ! -z "$act_id" ] && [ "$repostate" = "enabled" ]; then + # Repo present (act_id not "") and repostate enabled, so a disable call is needed + echo zypper $zypper_def_opts modifyrepo -d "$act_id" + fi + ;; + *) + echo "Unknown state: $state" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__zypper_repo/man.text b/cdist/conf/type/__zypper_repo/man.text new file mode 100644 index 00000000..6ea88f16 --- /dev/null +++ b/cdist/conf/type/__zypper_repo/man.text @@ -0,0 +1,73 @@ +cdist-type__zypper_repo(7) +========================== +Daniel Heule + + +NAME +---- +cdist-type__zypper_repo - repository management with zypper + + +DESCRIPTION +----------- +zypper is usually used on the SuSE distribution to manage repositories. + + +REQUIRED PARAMETERS +------------------- +None + + +OPTIONAL PARAMETERS +------------------- +state:: + Either "present" or "absent" or "enabled" or "disabled", defaults to "present" + + #present# - make sure that the repo is aviable, needs repo_uri and repo_desc + + for all following states, the repo can be searched via repo_id or repo_uri + + #absent# - drop the repo if found + + #enabled# - a repo can have state disabled if installed via zypper service (ris), in this case, you can enable the repo + + #disabled# - instead of absent (drop), a repo can also set to disabled, wich makes it inaccessible + + +repo_uri:: + If supplied, use the uri and not the object id as repo uri. + +repo_desc:: + If supplied, use the description and not the object id as repo description, only used if the state is present and the repo has to be created + +repo_id:: + If supplied, use the id and not the object id as repo id, can be used with state absent, enabled and disabled + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure testrepo in installed +__zypper_repo testrepo --state present --repo_uri http://url.to.your.repo/with/path + +# Drop repo by repo uri +__zypper_repo testrepo --state absent --repo_uri http://url.to.your.repo/with/path + +# Drop repo by id number (attention: repos are always numbered from 1 to max) +__zypper_repo testrepo --state absent --repo_id 1 + +# enable repo by id +__zypper_repo testrepo2 --state enabled --repo_id 2 + +# enable repo by uri +__zypper_repo testrepo3 --state enabled --repo_uri http://url.to.your.repo/with/path + +# disable a repo works like enabling it +__zypper_repo testrepo4 --state disabled --repo_id 4 +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2013 Daniel Heule. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__zypper_repo/parameter/default/state b/cdist/conf/type/__zypper_repo/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__zypper_repo/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__zypper_repo/parameter/optional b/cdist/conf/type/__zypper_repo/parameter/optional new file mode 100644 index 00000000..6f5a8325 --- /dev/null +++ b/cdist/conf/type/__zypper_repo/parameter/optional @@ -0,0 +1,4 @@ +state +repo_uri +repo_desc +repo_id diff --git a/cdist/conf/type/__zypper_service/explorer/repo_ids b/cdist/conf/type/__zypper_service/explorer/repo_ids new file mode 100644 index 00000000..e831b76c --- /dev/null +++ b/cdist/conf/type/__zypper_service/explorer/repo_ids @@ -0,0 +1,27 @@ +#!/bin/sh +# +# 2013 Daniel Heule (hda at sfs.biz) +# +# 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 services with Zypper (mostly suse) +# +# +# simpler command which works only on SLES11 SP3 or newer: +# echo $(zypper lr -u -E | cut -d'|' -f 1 | grep -E '^[0-9]') +# on older systems, zypper doesn't know the parameter -E +echo $(zypper lr -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_service/explorer/service_id b/cdist/conf/type/__zypper_service/explorer/service_id new file mode 100644 index 00000000..9c3d3a2d --- /dev/null +++ b/cdist/conf/type/__zypper_service/explorer/service_id @@ -0,0 +1,30 @@ +#!/bin/sh +# +# 2013 Daniel Heule (hda at sfs.biz) +# +# 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 services with Zypper (mostly suse) +# +if [ -f "$__object/parameter/service_uri" ]; then + uri="$(cat "$__object/parameter/service_uri")" +else + uri="/$__object_id" +fi +# simpler command which works only on SLES11 SP3 or newer: +# echo $(zypper ls -u -E | grep -E "\<$uri\>" | cut -d'|' -f 1 ) +echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | grep -E "\<$uri\>" | cut -d'|' -f 1 ) diff --git a/cdist/conf/type/__zypper_service/explorer/service_ids b/cdist/conf/type/__zypper_service/explorer/service_ids new file mode 100644 index 00000000..0f1f4186 --- /dev/null +++ b/cdist/conf/type/__zypper_service/explorer/service_ids @@ -0,0 +1,25 @@ +#!/bin/sh +# +# 2013 Daniel Heule (hda at sfs.biz) +# +# 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 services with Zypper (mostly suse) +# +# simpler command which works only on SLES11 SP3 or newer: +# echo $(zypper ls -u -E | cut -d'|' -f 1 | grep -E '^[0-9]') +echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_service/explorer/service_uri b/cdist/conf/type/__zypper_service/explorer/service_uri new file mode 100644 index 00000000..2f4f8960 --- /dev/null +++ b/cdist/conf/type/__zypper_service/explorer/service_uri @@ -0,0 +1,30 @@ +#!/bin/sh +# +# 2013 Daniel Heule (hda at sfs.biz) +# +# 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 services with Zypper (mostly suse) +# +if [ -f "$__object/parameter/service_uri" ]; then + uri="$(cat "$__object/parameter/service_uri")" +else + uri="/$__object_id" +fi +# simpler command which works only on SLES11 SP3 or newer: +# echo $(zypper ls -u -E | grep -E "\<$uri\>" | cut -d'|' -f 7) +echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | grep -E "\<$uri\>" | cut -d'|' -f 7 ) diff --git a/cdist/conf/type/__zypper_service/gencode-remote b/cdist/conf/type/__zypper_service/gencode-remote new file mode 100644 index 00000000..df8d1660 --- /dev/null +++ b/cdist/conf/type/__zypper_service/gencode-remote @@ -0,0 +1,85 @@ +#!/bin/sh +# +# 2013 Daniel Heule (hda at sfs.biz) +# +# 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 services with Zypper (mostly suse) +# + +# Debug +#exec >&2 +#set -x + +zypper_def_opts=" -q " + +if [ -f "$__object/parameter/service_desc" ]; then + desc="$(cat "$__object/parameter/service_desc")" +else + desc="$__object_id" +fi + +if [ -f "$__object/parameter/service_uri" ]; then + uri="$(cat "$__object/parameter/service_uri")" +else + uri="$__object_id" +fi + +state_should="$(cat "$__object/parameter/state")" +stype="$(cat "$__object/parameter/type")" + +exp_uri="$(cat "$__object/explorer/service_uri")" +exp_id="$(cat "$__object/explorer/service_id")" + +# we need this list to remove ids, but we must do this in reverse order +exp_ids="$(cat "$__object/explorer/service_ids" | rev)" + +if [ "$uri" = "$exp_uri" ] ; then + state_is="present" +else + state_is="absent" +fi + +# remove all other services if needed ... +if [ -f "$__object/parameter/remove-all-other-services" ]; then + # file exists -> True + for i in $exp_ids; do + if [ "$i" != "$exp_id" ] ; then + echo zypper $zypper_def_opts removeservice "$i" "&>/dev/null" + fi + done + echo zypper $zypper_def_opts refs "&>/dev/null" +fi + + +# Exit if nothing is needed to be done +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + echo zypper $zypper_def_opts addservice -t "$stype" "$uri" \"$desc\" + echo zypper $zypper_def_opts refs + ;; + absent) + echo zypper $zypper_def_opts removeservice "$service_id" + echo zypper $zypper_def_opts refs + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__zypper_service/man.text b/cdist/conf/type/__zypper_service/man.text new file mode 100644 index 00000000..31543d93 --- /dev/null +++ b/cdist/conf/type/__zypper_service/man.text @@ -0,0 +1,67 @@ +cdist-type__zypper_service(7) +============================= +Daniel Heule + + +NAME +---- +cdist-type__zypper_service - service management with zypper + + +DESCRIPTION +----------- +zypper is usually used on SuSE systems to manage services. + + +REQUIRED PARAMETERS +------------------- +service_uri:: + Uri of the service + + +OPTIONAL PARAMETERS +------------------- +service_desc:: + If supplied, use the service_desc and not the object id as descritpion for the service. + +state:: + Either "present" or "absent", defaults to "present" + +type:: + Defaults to "ris", the standard type of services at SLES11. For other values, see manpage of zypper. + + +BOOLEAN PARAMETERS +------------------ +remove-all-other-services:: + Drop all other services found on the target host before adding the new one. + +remove-all-repos:: + If supplied, remove all existing repos prior to setup the new service. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure that internal SLES11 SP3 RIS is in installed and all other services and repos are discarded +__zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --service_uri "http://path/to/your/ris/dir" --remove-all-other-services --remove-all-repos + +# Ensure that internal SLES11 SP3 RIS is in installed, no changes to ohter services or repos +__zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --service_uri "http://path/to/your/ris/dir" + +# Drop service by uri, no changes to ohter services or repos +__zypper_service INTERNAL_SLES11_SP3 --state absent --service_uri "http://path/to/your/ris/dir" + +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2013 Daniel Heule. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__zypper_service/manifest b/cdist/conf/type/__zypper_service/manifest new file mode 100644 index 00000000..aa4a39a3 --- /dev/null +++ b/cdist/conf/type/__zypper_service/manifest @@ -0,0 +1,59 @@ +#!/bin/sh +# +# 2013 Daniel Heule (hda at sfs.biz) +# +# 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 services with Zypper (mostly suse) +# + +# Debug +#exec >&2 +#set -x + +zypper_def_opts=" -q " + +if [ -f "$__object/parameter/service_uri" ]; then + uri="$(cat "$__object/parameter/service_uri")" +else + uri="$__object_id" +fi + +state_should="$(cat "$__object/parameter/state")" + +exp_uri="$(cat "$__object/explorer/service_uri")" + +if [ "$uri" = "$exp_uri" ] ; then + state_is="present" +else + state_is="absent" +fi + + +# Exit if nothing is needed to be done +[ "$state_is" = "$state_should" ] && exit 0 + +# we need this list to remove ids, but we must do this in reverse order +exp_repos="$(cat "$__object/explorer/repo_ids" | rev)" + +# boolean parameter +if [ -f "$__object/parameter/remove-all-repos" ]; then + # file exists -> True + for i in $exp_repos; do + __zypper_repo "droprepo${i}" --state absent --repo_id "${i}" + done +fi diff --git a/cdist/conf/type/__zypper_service/parameter/boolean b/cdist/conf/type/__zypper_service/parameter/boolean new file mode 100644 index 00000000..ca711ded --- /dev/null +++ b/cdist/conf/type/__zypper_service/parameter/boolean @@ -0,0 +1,2 @@ +remove-all-other-services +remove-all-repos diff --git a/cdist/conf/type/__zypper_service/parameter/default/state b/cdist/conf/type/__zypper_service/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__zypper_service/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__zypper_service/parameter/default/type b/cdist/conf/type/__zypper_service/parameter/default/type new file mode 100644 index 00000000..b928830f --- /dev/null +++ b/cdist/conf/type/__zypper_service/parameter/default/type @@ -0,0 +1 @@ +ris diff --git a/cdist/conf/type/__zypper_service/parameter/optional b/cdist/conf/type/__zypper_service/parameter/optional new file mode 100644 index 00000000..b26c78d8 --- /dev/null +++ b/cdist/conf/type/__zypper_service/parameter/optional @@ -0,0 +1,3 @@ +service_desc +state +type diff --git a/cdist/conf/type/__zypper_service/parameter/required b/cdist/conf/type/__zypper_service/parameter/required new file mode 100644 index 00000000..2b4645ee --- /dev/null +++ b/cdist/conf/type/__zypper_service/parameter/required @@ -0,0 +1 @@ +service_uri diff --git a/cdist/config.py b/cdist/config.py index 9af25b75..73ba4710 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -20,7 +20,258 @@ # # -import cdist.config_install +import logging +import os +import shutil +import sys +import time +import pprint -class Config(cdist.config_install.ConfigInstall): - pass +import cdist + +import cdist.exec.local +import cdist.exec.remote + +from cdist import core + +class Config(object): + """Cdist main class to hold arbitrary data""" + + def __init__(self, local, remote, dry_run=False): + + self.local = local + self.remote = remote + self.log = logging.getLogger(self.local.target_host) + self.dry_run = dry_run + + self.explorer = core.Explorer(self.local.target_host, self.local, self.remote) + self.manifest = core.Manifest(self.local.target_host, self.local) + self.code = core.Code(self.local.target_host, self.local, self.remote) + + def _init_files_dirs(self): + """Prepare files and directories for the run""" + self.local.create_files_dirs() + self.remote.create_files_dirs() + + @classmethod + def commandline(cls, args): + """Configure remote system""" + import multiprocessing + + # FIXME: Refactor relict - remove later + log = logging.getLogger("cdist") + + initial_manifest_tempfile = None + if args.manifest == '-': + # read initial manifest from stdin + import tempfile + 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)) + + 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=cls.onehost, args=(host, args, True)) + process[host].start() + else: + try: + cls.onehost(host, args, parallel=False) + except cdist.Error as e: + failed_hosts.append(host) + + # 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 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)) + + if len(failed_hosts) > 0: + raise cdist.Error("Failed to configure the following hosts: " + + " ".join(failed_hosts)) + + @classmethod + def onehost(cls, host, args, parallel): + """Configure ONE system""" + + log = logging.getLogger(host) + + try: + local = cdist.exec.local.Local( + target_host=host, + initial_manifest=args.manifest, + base_path=args.out_path, + add_conf_dirs=args.conf_dir) + + remote = cdist.exec.remote.Remote( + target_host=host, + remote_exec=args.remote_exec, + remote_copy=args.remote_copy) + + c = cls(local, remote, dry_run=args.dry_run) + c.run() + + except cdist.Error as e: + log.error(e) + if parallel: + # We are running in our own process here, need to sys.exit! + sys.exit(1) + else: + raise + + 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 run(self): + """Do what is most often done: deploy & cleanup""" + start_time = time.time() + + self._init_files_dirs() + + self.explorer.run_global_explorers(self.local.global_explorer_out_path) + self.manifest.run_initial_manifest(self.local.initial_manifest) + self.iterate_until_finished() + + self.local.save_cache() + self.log.info("Finished successful run in %s seconds", time.time() - start_time) + + + def object_list(self): + """Short name for object list retrieval""" + for cdist_object in core.CdistObject.list_objects(self.local.object_path, + self.local.type_path): + if cdist_object.cdist_type.is_install: + self.log.debug("Running in config mode, ignoring install object: {0}".format(cdist_object)) + else: + yield cdist_object + + + def iterate_once(self): + """ + Iterate over the objects once - helper method for + iterate_until_finished + """ + objects_changed = False + + for cdist_object in self.object_list(): + if cdist_object.requirements_unfinished(cdist_object.requirements): + """We cannot do anything for this poor object""" + continue + + if cdist_object.state == core.CdistObject.STATE_UNDEF: + """Prepare the virgin object""" + + self.object_prepare(cdist_object) + objects_changed = True + + if cdist_object.requirements_unfinished(cdist_object.autorequire): + """The previous step created objects we depend on - wait for them""" + continue + + if cdist_object.state == core.CdistObject.STATE_PREPARED: + self.object_run(cdist_object) + objects_changed = True + + return objects_changed + + + def iterate_until_finished(self): + """ + Go through all objects and solve them + one after another + """ + + objects_changed = True + + while objects_changed: + objects_changed = self.iterate_once() + + # Check whether all objects have been finished + unfinished_objects = [] + for cdist_object in self.object_list(): + if not cdist_object.state == cdist_object.STATE_DONE: + unfinished_objects.append(cdist_object) + + if unfinished_objects: + info_string = [] + + for cdist_object in unfinished_objects: + + requirement_names = [] + autorequire_names = [] + + for requirement in cdist_object.requirements_unfinished(cdist_object.requirements): + requirement_names.append(requirement.name) + + for requirement in cdist_object.requirements_unfinished(cdist_object.autorequire): + autorequire_names.append(requirement.name) + + requirements = ", ".join(requirement_names) + autorequire = ", ".join(autorequire_names) + info_string.append("%s requires: %s autorequires: %s" % (cdist_object.name, requirements, autorequire)) + + raise cdist.UnresolvableRequirementsError("The requirements of the following objects could not be resolved: %s" % + ("; ".join(info_string))) + + def object_prepare(self, cdist_object): + """Prepare object: Run type explorer + manifest""" + self.log.info("Running manifest and explorers for " + cdist_object.name) + self.explorer.run_type_explorers(cdist_object) + self.manifest.run_type_manifest(cdist_object) + cdist_object.state = core.CdistObject.STATE_PREPARED + + def object_run(self, cdist_object): + """Run gencode and code for an object""" + + self.log.debug("Trying to run object %s" % (cdist_object.name)) + if cdist_object.state == core.CdistObject.STATE_DONE: + raise cdist.Error("Attempting to run an already finished object: %s", cdist_object) + + cdist_type = cdist_object.cdist_type + + # Generate + self.log.info("Generating code for %s" % (cdist_object.name)) + cdist_object.code_local = self.code.run_gencode_local(cdist_object) + cdist_object.code_remote = self.code.run_gencode_remote(cdist_object) + if cdist_object.code_local or cdist_object.code_remote: + cdist_object.changed = True + + # Execute + if not self.dry_run: + if cdist_object.code_local or cdist_object.code_remote: + self.log.info("Executing code for %s" % (cdist_object.name)) + if cdist_object.code_local: + self.code.run_code_local(cdist_object) + if cdist_object.code_remote: + self.code.transfer_code_remote(cdist_object) + self.code.run_code_remote(cdist_object) + else: + self.log.info("Skipping code execution due to DRY RUN") + + + # Mark this object as done + self.log.debug("Finishing run of " + cdist_object.name) + cdist_object.state = core.CdistObject.STATE_DONE diff --git a/cdist/config_install.py b/cdist/config_install.py deleted file mode 100644 index f1529cc1..00000000 --- a/cdist/config_install.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 2010-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 . -# -# - -import logging -import os -import stat -import shutil -import sys -import tempfile -import time -import itertools -import pprint - -import cdist -from cdist import core -from cdist import resolver - - -class ConfigInstall(object): - """Cdist main class to hold arbitrary data""" - - def __init__(self, context): - - self.context = context - self.log = logging.getLogger(self.context.target_host) - - # Initialise local directory structure - self.context.local.create_files_dirs() - # Initialise remote directory structure - self.context.remote.create_files_dirs() - - self.explorer = core.Explorer(self.context.target_host, self.context.local, self.context.remote) - self.manifest = core.Manifest(self.context.target_host, self.context.local) - self.code = core.Code(self.context.target_host, self.context.local, self.context.remote) - - # Add switch to disable code execution - self.dry_run = False - - def cleanup(self): - # FIXME: move to local? - destination = os.path.join(self.context.local.cache_path, self.context.target_host) - self.log.debug("Saving " + self.context.local.out_path + " to " + destination) - if os.path.exists(destination): - shutil.rmtree(destination) - shutil.move(self.context.local.out_path, destination) - - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" - self.stage_prepare() - self.stage_run() - - def deploy_and_cleanup(self): - """Do what is most often done: deploy & cleanup""" - start_time = time.time() - self.deploy_to() - self.cleanup() - self.log.info("Finished successful run in %s seconds", - time.time() - start_time) - - def stage_prepare(self): - """Do everything for a deploy, minus the actual code stage""" - self.explorer.run_global_explorers(self.context.local.global_explorer_out_path) - self.manifest.run_initial_manifest(self.context.initial_manifest) - - self.log.info("Running object manifests and type explorers") - - # Continue process until no new objects are created anymore - new_objects_created = True - while new_objects_created: - new_objects_created = False - for cdist_object in core.CdistObject.list_objects(self.context.local.object_path, - self.context.local.type_path): - if cdist_object.state == core.CdistObject.STATE_PREPARED: - self.log.debug("Skipping re-prepare of object %s", cdist_object) - continue - else: - self.object_prepare(cdist_object) - new_objects_created = True - - def object_prepare(self, cdist_object): - """Prepare object: Run type explorer + manifest""" - self.log.info("Running manifest and explorers for " + cdist_object.name) - self.explorer.run_type_explorers(cdist_object) - self.manifest.run_type_manifest(cdist_object) - cdist_object.state = core.CdistObject.STATE_PREPARED - - def object_run(self, cdist_object, dry_run=False): - """Run gencode and code for an object""" - self.log.debug("Trying to run object " + cdist_object.name) - if cdist_object.state == core.CdistObject.STATE_DONE: - raise cdist.Error("Attempting to run an already finished object: %s", cdist_object) - - cdist_type = cdist_object.cdist_type - - # Generate - self.log.info("Generating and executing code for " + cdist_object.name) - cdist_object.code_local = self.code.run_gencode_local(cdist_object) - cdist_object.code_remote = self.code.run_gencode_remote(cdist_object) - if cdist_object.code_local or cdist_object.code_remote: - cdist_object.changed = True - - # Execute - if not dry_run: - if cdist_object.code_local: - self.code.run_code_local(cdist_object) - if cdist_object.code_remote: - self.code.transfer_code_remote(cdist_object) - self.code.run_code_remote(cdist_object) - - # Mark this object as done - self.log.debug("Finishing run of " + cdist_object.name) - cdist_object.state = core.CdistObject.STATE_DONE - - def stage_run(self): - """The final (and real) step of deployment""" - self.log.info("Generating and executing code") - - # FIXME: think about parallel execution (same for stage_prepare) - self.all_resolved = False - while not self.all_resolved: - self.stage_run_iterate() - - def stage_run_iterate(self): - """ - Run one iteration of the run - - To be repeated until all objects are done - """ - objects = list(core.CdistObject.list_objects(self.context.local.object_path, self.context.local.type_path)) - object_state_list=' '.join('%s:%s:%s:%s' % (o, o.state, o.all_requirements, o.satisfied_requirements) for o in objects) - - self.log.debug("Object state (name:state:requirements:satisfied): %s" % object_state_list) - - objects_changed = False - self.all_resolved = True - for cdist_object in objects: - if not cdist_object.state == cdist_object.STATE_DONE: - self.all_resolved = False - self.log.debug("Object %s not done" % cdist_object.name) - if cdist_object.satisfied_requirements: - self.log.debug("Running object %s with satisfied requirements" % cdist_object.name) - self.object_run(cdist_object, self.dry_run) - objects_changed = True - - self.log.debug("All resolved: %s Objects changed: %s" % (self.all_resolved, objects_changed)) - - # Not all are resolved, but nothing has been changed => bad dependencies! - if not objects_changed and not self.all_resolved: - # Create list of unfinished objects + their requirements for print - - evil_objects = [] - good_objects = [] - for cdist_object in objects: - if not cdist_object.state == cdist_object.STATE_DONE: - evil_objects.append("%s: required: %s, autorequired: %s" % - (cdist_object.name, cdist_object.requirements, cdist_object.autorequire)) - else: - evil_objects.append("%s (%s): required: %s, autorequired: %s" % - (cdist_object.state, cdist_object.name, - cdist_object.requirements, cdist_object.autorequire)) - - errormessage = "Cannot solve requirements for the following objects: %s - solved: %s" % (",".join(evil_objects), ",".join(good_objects)) - raise cdist.Error(errormessage) diff --git a/cdist/context.py b/cdist/context.py deleted file mode 100644 index e0391be8..00000000 --- a/cdist/context.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 2010-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 . -# -# - -import logging -import os -import sys -import tempfile -import shutil - -from cdist.exec import local -from cdist.exec import remote - - -class Context(object): - """Hold information about current context""" - - def __init__(self, - target_host, - remote_copy, - remote_exec, - initial_manifest=False, - add_conf_dirs=None, - exec_path=sys.argv[0], - debug=False): - - self.debug = debug - self.target_host = target_host - self.exec_path = exec_path - - # Context logging - self.log = logging.getLogger(self.target_host) - self.log.addFilter(self) - - # Local temp directory - # FIXME: if __cdist_out_dir can be given from the outside, the same directory will be used for all hosts - if '__cdist_out_dir' in os.environ: - self.out_path = os.environ['__cdist_out_dir'] - self.temp_dir = None - else: - self.temp_dir = tempfile.mkdtemp() - self.out_path = os.path.join(self.temp_dir, "out") - - self.local = local.Local(self.target_host, self.out_path, self.exec_path, add_conf_dirs=add_conf_dirs) - - self.initial_manifest = (initial_manifest or - os.path.join(self.local.manifest_path, "init")) - - self._init_remote(remote_copy, remote_exec) - - # Remote stuff - def _init_remote(self, remote_copy, remote_exec): - - self.remote_base_path = os.environ.get('__cdist_remote_out_dir', "/var/lib/cdist") - self.remote_copy = remote_copy - self.remote_exec = remote_exec - - os.environ['__remote_copy'] = self.remote_copy - os.environ['__remote_exec'] = self.remote_exec - - self.remote = remote.Remote(self.target_host, self.remote_base_path, - self.remote_exec, self.remote_copy) - - def cleanup(self): - """Remove temp stuff""" - if self.temp_dir: - shutil.rmtree(self.temp_dir) - - def filter(self, record): - """Add hostname to logs via logging Filter""" - - record.msg = self.target_host + ": " + str(record.msg) - - return True diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 7beea130..e8c58a67 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -42,6 +43,13 @@ class IllegalObjectIdError(cdist.Error): def __str__(self): return '%s: %s' % (self.message, self.object_id) +class MissingObjectIdError(cdist.Error): + def __init__(self, type_name): + self.type_name = type_name + self.message = "Type %s requires object id (is not a singleton type)" % self.type_name + + def __str__(self): + return '%s' % (self.message) class CdistObject(object): """Represents a cdist object. @@ -53,11 +61,12 @@ class CdistObject(object): """ # Constants for use with Object.state + STATE_UNDEF = "" STATE_PREPARED = "prepared" STATE_RUNNING = "running" STATE_DONE = "done" - def __init__(self, cdist_type, base_path, object_id=None): + def __init__(self, cdist_type, base_path, object_id=''): self.cdist_type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id @@ -99,7 +108,6 @@ class CdistObject(object): """ type_name = object_name.split(os.sep)[0] - # FIXME: allow object without object_id? e.g. for singleton object_id = os.sep.join(object_name.split(os.sep)[1:]) return type_name, object_id @@ -113,7 +121,8 @@ class CdistObject(object): return os.path.join(type_name, object_id) def validate_object_id(self): - # FIXME: also check that there is no object ID when type is singleton? + if self.cdist_type.is_singleton and self.object_id: + raise IllegalObjectIdError('singleton objects can\'t have a object_id') """Validate the given object_id and raise IllegalObjectIdError if it's not valid. """ @@ -122,11 +131,17 @@ class CdistObject(object): raise IllegalObjectIdError(self.object_id, 'object_id may not contain \'%s\'' % OBJECT_MARKER) if '//' in self.object_id: raise IllegalObjectIdError(self.object_id, 'object_id may not contain //') + if self.object_id == '.': + raise IllegalObjectIdError(self.object_id, 'object_id may not be a .') # 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.") + raise MissingObjectIdError(self.cdist_type.name) + + # Does not work: AttributeError: 'CdistObject' object has no attribute 'parameter_path' + + #"Type %s is not a singleton type - missing object id (parameters: %s)" % + # (self.cdist_type.name, self.parameters)) def object_from_name(self, object_name): """Convenience method for creating an object instance from an object name. @@ -190,7 +205,6 @@ class CdistObject(object): autorequire = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'autorequire')) parameters = fsproperty.DirectoryDictProperty(lambda obj: os.path.join(obj.base_path, obj.parameter_path)) explorers = fsproperty.DirectoryDictProperty(lambda obj: os.path.join(obj.base_path, obj.explorer_path)) - changed = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "changed")) state = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.absolute_path, "state")) source = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, "source")) code_local = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.base_path, obj.code_local_path)) @@ -201,76 +215,25 @@ class CdistObject(object): """Checks wether this cdist object exists on the file systems.""" return os.path.exists(self.absolute_path) - def create(self): + def create(self, allow_overwrite=False): """Create this cdist object on the filesystem. """ try: - os.makedirs(self.absolute_path, exist_ok=False) + os.makedirs(self.absolute_path, exist_ok=allow_overwrite) absolute_parameter_path = os.path.join(self.base_path, self.parameter_path) - os.makedirs(absolute_parameter_path, exist_ok=False) + os.makedirs(absolute_parameter_path, exist_ok=allow_overwrite) except EnvironmentError as error: raise cdist.Error('Error creating directories for cdist object: %s: %s' % (self, error)) - @property - def satisfied_requirements(self): - """Return state whether all of our dependencies have been resolved already""" + def requirements_unfinished(self, requirements): + """Return state whether requirements are satisfied""" - satisfied = True + object_list = [] - for requirement in self.all_requirements: - log.debug("%s: Checking requirement %s (%s) .." % (self.name, requirement.name, requirement.state)) - if not requirement.state == self.STATE_DONE: - satisfied = False - break - log.debug("%s is satisfied: %s" % (self.name, satisfied)) + for requirement in requirements: + cdist_object = self.object_from_name(requirement) - return satisfied + if not cdist_object.state == self.STATE_DONE: + object_list.append(cdist_object) - - def find_requirements_by_name(self, requirements): - """Takes a list of requirement patterns and returns a list of matching object instances. - - Patterns are expected to be Unix shell-style wildcards for use with fnmatch.filter. - - find_requirements_by_name(['__type/object_id', '__other_type/*']) -> - [, , ] - """ - - - # FIXME: think about where/when to store this - probably not here - self.objects = dict((o.name, o) for o in self.list_objects(self.base_path, self.cdist_type.base_path)) - object_names = self.objects.keys() - - for pattern in requirements: - found = False - for requirement in fnmatch.filter(object_names, pattern): - found = True - yield self.objects[requirement] - if not found: - # FIXME: get rid of the singleton object_id, it should be invisible to the code -> hide it in Object - singleton = os.path.join(pattern, 'singleton') - if singleton in self.objects: - yield self.objects[singleton] - else: - raise RequirementNotFoundError(pattern) - - @property - def all_requirements(self): - """ - Return resolved autorequirements and requirements so that - a complete list of requirements is returned - """ - - all_reqs= [] - all_reqs.extend(self.find_requirements_by_name(self.requirements)) - all_reqs.extend(self.find_requirements_by_name(self.autorequire)) - - return set(all_reqs) - - -class RequirementNotFoundError(cdist.Error): - def __init__(self, requirement): - self.requirement = requirement - - def __str__(self): - return 'Requirement could not be found: %s' % self.requirement + return object_list diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index 0efb10f4..ff1ebaec 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -25,7 +25,8 @@ import os import cdist class NoSuchTypeError(cdist.Error): - def __init__(self, type_path, type_absolute_path): + def __init__(self, name, type_path, type_absolute_path): + self.name = name self.type_path = type_path self.type_absolute_path = type_absolute_path @@ -48,7 +49,7 @@ class CdistType(object): self.path = self.name self.absolute_path = os.path.join(self.base_path, self.path) if not os.path.isdir(self.absolute_path): - raise NoSuchTypeError(self.path, self.absolute_path) + raise NoSuchTypeError(self.name, self.path, self.absolute_path) self.manifest_path = os.path.join(self.name, "manifest") self.explorer_path = os.path.join(self.name, "explorer") self.gencode_local_path = os.path.join(self.name, "gencode-local") @@ -61,6 +62,7 @@ class CdistType(object): self.__optional_parameters = None self.__optional_multiple_parameters = None self.__boolean_parameters = None + self.__parameter_defaults = None @classmethod def list_types(cls, base_path): @@ -194,3 +196,19 @@ class CdistType(object): finally: self.__boolean_parameters = parameters return self.__boolean_parameters + + @property + def parameter_defaults(self): + if not self.__parameter_defaults: + defaults = {} + try: + defaults_dir = os.path.join(self.absolute_path, "parameter", "default") + for name in os.listdir(defaults_dir): + with open(os.path.join(defaults_dir, name)) as fd: + defaults[name] = fd.read().strip() + except EnvironmentError: + # error ignored + pass + finally: + self.__parameter_defaults = defaults + return self.__parameter_defaults diff --git a/cdist/core/code.py b/cdist/core/code.py index fa1ed3c1..f128697f 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -89,7 +89,7 @@ class Code(object): self.remote = remote self.env = { '__target_host': self.target_host, - '__global': self.local.out_path, + '__global': self.local.base_path, } def _run_gencode(self, cdist_object, which): @@ -104,7 +104,8 @@ class Code(object): '__object_id': cdist_object.object_id, '__object_name': cdist_object.name, }) - return self.local.run_script(script, env=env, return_output=True) + message_prefix=cdist_object.name + return self.local.run_script(script, env=env, return_output=True, message_prefix=message_prefix) def run_gencode_local(self, cdist_object): """Run the gencode-local script for the given cdist object.""" @@ -119,9 +120,6 @@ class Code(object): source = os.path.join(self.local.object_path, cdist_object.code_remote_path) destination = os.path.join(self.remote.object_path, cdist_object.code_remote_path) # FIXME: BUG: do not create destination, but top level of destination! - # FIXME: BUG2: we are called AFTER the code-remote has been transferred already: - # mkdir: cannot create directory `/var/lib/cdist/object/__directory/etc/acpi/actions/.cdist/code-remote': File exists - # OR: this is from previous run -> cleanup missing! self.remote.mkdir(destination) self.remote.transfer(source, destination) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index d926552a..41851bd6 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -22,6 +22,7 @@ import logging import os +import glob import cdist @@ -79,7 +80,7 @@ class Explorer(object): def list_global_explorer_names(self): """Return a list of global explorer names.""" - return os.listdir(self.local.global_explorer_path) + return glob.glob1(self.local.global_explorer_path, '*') def run_global_explorers(self, out_path): """Run global explorers and save output to files in the given @@ -111,7 +112,7 @@ class Explorer(object): """Return a list of explorer names for the given type.""" source = os.path.join(self.local.type_path, cdist_type.explorer_path) try: - return os.listdir(source) + return glob.glob1(source, '*') except EnvironmentError: return [] diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 19639618..95bf4c25 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -94,7 +94,7 @@ class Manifest(object): self.env = { 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), '__cdist_type_base_path': self.local.type_path, # for use in type emulator - '__global': self.local.out_path, + '__global': self.local.base_path, '__target_host': self.target_host, } if self.log.getEffectiveLevel() == logging.DEBUG: @@ -106,6 +106,7 @@ class Manifest(object): env.update(self.env) env['__cdist_manifest'] = initial_manifest env['__manifest'] = self.local.manifest_path + env['__explorer'] = self.local.global_explorer_out_path return env @@ -121,7 +122,8 @@ class Manifest(object): if not os.path.isfile(initial_manifest): raise NoInitialManifestError(initial_manifest, user_supplied) - self.local.run_script(initial_manifest, env=self.env_initial_manifest(initial_manifest)) + message_prefix="initialmanifest" + self.local.run_script(initial_manifest, env=self.env_initial_manifest(initial_manifest), message_prefix=message_prefix) def env_type_manifest(self, cdist_object): type_manifest = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) @@ -140,5 +142,6 @@ class Manifest(object): def run_type_manifest(self, cdist_object): type_manifest = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) + message_prefix = cdist_object.name if os.path.isfile(type_manifest): self.local.run_script(type_manifest, env=self.env_type_manifest(cdist_object)) diff --git a/cdist/emulator.py b/cdist/emulator.py index a9c760cb..41834fbf 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- # -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -28,48 +29,59 @@ import sys import cdist from cdist import core +class MissingRequiredEnvironmentVariableError(cdist.Error): + def __init__(self, name): + self.name = name + self.message = "Emulator requires the environment variable %s to be setup" % self.name + + def __str__(self): + return self.message + + +class DefaultList(list): + """Helper class to allow default values for optional_multiple parameters. + + @see https://groups.google.com/forum/#!msg/comp.lang.python/sAUvkJEDpRc/RnRymrzJVDYJ + """ + def __copy__(self): + return [] + + @classmethod + def create(cls, initial=None): + if initial: + return cls(initial.split('\n')) + + class Emulator(object): def __init__(self, argv, stdin=sys.stdin.buffer, env=os.environ): self.argv = argv self.stdin = stdin self.env = env - self.object_id = False + self.object_id = '' - self.global_path = self.env['__global'] - self.target_host = self.env['__target_host'] + try: + self.global_path = self.env['__global'] + self.target_host = self.env['__target_host'] - # Internally only - self.object_source = self.env['__cdist_manifest'] - self.type_base_path = self.env['__cdist_type_base_path'] + # Internally only + self.object_source = self.env['__cdist_manifest'] + self.type_base_path = self.env['__cdist_type_base_path'] + + except KeyError as e: + raise MissingRequiredEnvironmentVariableError(e.args[0]) self.object_base_path = os.path.join(self.global_path, "object") + self.typeorder_path = os.path.join(self.global_path, "typeorder") self.type_name = os.path.basename(argv[0]) self.cdist_type = core.CdistType(self.type_base_path, self.type_name) self.__init_log() - def filter(self, record): - """Add hostname and object to logs via logging Filter""" - - prefix = self.target_host + ": (emulator)" - - if self.object_id: - prefix = prefix + " " + self.type_name + "/" + self.object_id - - record.msg = prefix + ": " + record.msg - - return True - def run(self): """Emulate type commands (i.e. __file and co)""" - if '__install' in self.env: - if not self.cdist_type.is_install: - self.log.debug("Running in install mode, ignoring non install type") - return True - self.commandline() self.setup_object() self.save_stdin() @@ -79,16 +91,13 @@ class Emulator(object): def __init_log(self): """Setup logging facility""" - logformat = '%(levelname)s: %(message)s' - logging.basicConfig(format=logformat) if '__cdist_debug' in self.env: logging.root.setLevel(logging.DEBUG) else: logging.root.setLevel(logging.INFO) - self.log = logging.getLogger(__name__) - self.log.addFilter(self) + self.log = logging.getLogger(self.target_host) def commandline(self): """Parse command line""" @@ -103,10 +112,12 @@ class Emulator(object): parser.add_argument(argument, dest=parameter, action='append', required=True) for parameter in self.cdist_type.optional_parameters: argument = "--" + parameter - parser.add_argument(argument, dest=parameter, action='store', required=False) + parser.add_argument(argument, dest=parameter, action='store', required=False, + default=self.cdist_type.parameter_defaults.get(parameter, None)) for parameter in self.cdist_type.optional_multiple_parameters: argument = "--" + parameter - parser.add_argument(argument, dest=parameter, action='append', required=False) + parser.add_argument(argument, dest=parameter, action='append', required=False, + default=DefaultList.create(self.cdist_type.parameter_defaults.get(parameter, None))) for parameter in self.cdist_type.boolean_parameters: argument = "--" + parameter parser.add_argument(argument, dest=parameter, action='store_const', const='') @@ -119,12 +130,9 @@ class Emulator(object): self.args = parser.parse_args(self.argv[1:]) self.log.debug('Args: %s' % self.args) - def setup_object(self): # Setup object_id - FIXME: unset / do not setup anymore! - if self.cdist_type.is_singleton: - self.object_id = "singleton" - else: + if not self.cdist_type.is_singleton: self.object_id = self.args.object_id[0] del self.args.object_id @@ -135,18 +143,23 @@ class Emulator(object): self.parameters = {} for key,value in vars(self.args).items(): if value is not None: - if isinstance(value, list): - value = '\n'.join(value) self.parameters[key] = value - if self.cdist_object.exists: + if self.cdist_object.exists and not 'CDIST_OVERRIDE' in self.env: if self.cdist_object.parameters != self.parameters: raise cdist.Error("Object %s already exists with conflicting parameters:\n%s: %s\n%s: %s" % (self.cdist_object.name, " ".join(self.cdist_object.source), self.cdist_object.parameters, self.object_source, self.parameters) ) else: - self.cdist_object.create() + if self.cdist_object.exists: + self.log.debug('Object %s override forced with CDIST_OVERRIDE',self.cdist_object.name) + self.cdist_object.create(True) + else: + self.cdist_object.create() self.cdist_object.parameters = self.parameters + # record the created object in typeorder file + with open(self.typeorder_path, 'a') as typeorderfile: + print(self.cdist_object.name, file=typeorderfile) # Record / Append source self.cdist_object.source.append(self.object_source) @@ -176,6 +189,24 @@ class Emulator(object): def record_requirements(self): """record requirements""" + # Inject the predecessor, but not if its an override (this would leed to an circular dependency) + if "CDIST_ORDER_DEPENDENCY" in self.env and not 'CDIST_OVERRIDE' in self.env: + # load object name created bevor this one from typeorder file ... + with open(self.typeorder_path, 'r') as typecreationfile: + typecreationorder = typecreationfile.readlines() + # get the type created bevore this one ... + try: + lastcreatedtype = typecreationorder[-2].strip() + if 'require' in self.env: + self.env['require'] += " " + lastcreatedtype + else: + self.env['require'] = lastcreatedtype + self.log.debug("Injecting require for CDIST_ORDER_DEPENDENCY: %s for %s", lastcreatedtype, self.cdist_object.name) + except IndexError: + # if no second last line, we are on the first type, so do not set a requirement + pass + + if "require" in self.env: requirements = self.env['require'] self.log.debug("reqs = " + requirements) @@ -184,9 +215,16 @@ class Emulator(object): if len(requirement) == 0: continue # Raises an error, if object cannot be created - cdist_object = self.cdist_object.object_from_name(requirement) + try: + cdist_object = self.cdist_object.object_from_name(requirement) + except core.cdist_type.NoSuchTypeError as e: + self.log.error("%s requires object %s, but type %s does not exist. Defined at %s" % (self.cdist_object.name, requirement, e.name, self.object_source)) + raise + except core.cdist_object.MissingObjectIdError as e: + self.log.error("%s requires object %s without object id. Defined at %s" % (self.cdist_object.name, requirement, self.object_source)) + raise - self.log.debug("Recording requirement: " + requirement) + self.log.debug("Recording requirement: %s", requirement) # Save the sanitised version, not the user supplied one # (__file//bar => __file/bar) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 7f640411..2f75ffd4 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -27,8 +27,10 @@ import re import subprocess import shutil import logging +import tempfile import cdist +import cdist.message from cdist import core class Local(object): @@ -38,20 +40,35 @@ class Local(object): Directly accessing the local side from python code is a bug. """ - def __init__(self, target_host, out_path, exec_path, add_conf_dirs=None, cache_dir=None): + def __init__(self, + target_host, + exec_path=sys.argv[0], + initial_manifest=None, + base_path=None, + add_conf_dirs=None): self.target_host = target_host - self.out_path = out_path + + # FIXME: stopped: create base that does not require moving later + if base_path: + self.base_path = base_path + else: + self.base_path = tempfile.mkdtemp() + + # FIXME: as well + self._init_cache_dir(None) + self.exec_path = exec_path + self.custom_initial_manifest = initial_manifest self._add_conf_dirs = add_conf_dirs self._init_log() self._init_permissions() self._init_paths() - self._init_cache_dir(cache_dir) self._init_conf_dirs() + @property def dist_conf_dir(self): return os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), "conf")) @@ -72,22 +89,24 @@ class Local(object): def _init_paths(self): # Depending on out_path - self.bin_path = os.path.join(self.out_path, "bin") - self.conf_path = os.path.join(self.out_path, "conf") - self.global_explorer_out_path = os.path.join(self.out_path, "explorer") - self.object_path = os.path.join(self.out_path, "object") + self.bin_path = os.path.join(self.base_path, "bin") + self.conf_path = os.path.join(self.base_path, "conf") + self.global_explorer_out_path = os.path.join(self.base_path, "explorer") + self.object_path = os.path.join(self.base_path, "object") + self.messages_path = os.path.join(self.base_path, "messages") # Depending on conf_path self.global_explorer_path = os.path.join(self.conf_path, "explorer") self.manifest_path = os.path.join(self.conf_path, "manifest") + self.initial_manifest = (self.custom_initial_manifest or + os.path.join(self.manifest_path, "init")) + self.type_path = os.path.join(self.conf_path, "type") def _init_conf_dirs(self): self.conf_dirs = [] - # Comes with the distribution - system_conf_dir = os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), "conf")) - self.conf_dirs.append(system_conf_dir) + self.conf_dirs.append(self.dist_conf_dir) # Is the default place for user created explorer, type and manifest if self.home_dir: @@ -99,10 +118,22 @@ class Local(object): cdist_path_dirs.reverse() self.conf_dirs.extend(cdist_path_dirs) - # Add user supplied directories + # Add command line supplied directories if self._add_conf_dirs: self.conf_dirs.extend(self._add_conf_dirs) + def _init_directories(self): + self.mkdir(self.conf_path) + self.mkdir(self.global_explorer_out_path) + self.mkdir(self.bin_path) + + def create_files_dirs(self): + self._init_directories() + self._create_conf_path_and_link_conf_dirs() + self._create_messages() + self._link_types_for_emulator() + + def _init_cache_dir(self, cache_dir): if cache_dir: self.cache_path = cache_dir @@ -122,19 +153,23 @@ class Local(object): self.log.debug("Local mkdir: %s", path) os.makedirs(path, exist_ok=True) - def run(self, command, env=None, return_output=False): + def run(self, command, env=None, return_output=False, message_prefix=None): """Run the given command with the given environment. Return the output as a string. """ - assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %s" % command self.log.debug("Local run: %s", command) + assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %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 + if message_prefix: + message = cdist.message.Message(message_prefix, self.messages_path) + env.update(message.env) + try: if return_output: return subprocess.check_output(command, env=env).decode() @@ -144,28 +179,41 @@ class Local(object): raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: raise cdist.Error(" ".join(*args) + ": " + error.args[1]) + finally: + if message_prefix: + message.merge_messages() - def run_script(self, script, env=None, return_output=False): + def run_script(self, script, env=None, return_output=False, message_prefix=None): """Run the given script with the given environment. Return the output as a string. """ - command = ["/bin/sh", "-e"] + command = [ os.environ.get('CDIST_LOCAL_SHELL',"/bin/sh") , "-e"] command.append(script) - return self.run(command, env, return_output) + return self.run(command=command, env=env, return_output=return_output, message_prefix=message_prefix) - def create_files_dirs(self): - self._create_context_dirs() - self._create_conf_path_and_link_conf_dirs() - self._link_types_for_emulator() + def save_cache(self): + if os.path.isabs(self.target_host): + hostdir = self.target_host[1:] + else: + hostdir = self.target_host - def _create_context_dirs(self): - self.mkdir(self.out_path) + destination = os.path.join(self.cache_path, hostdir) + self.log.debug("Saving " + self.base_path + " to " + destination) - self.mkdir(self.conf_path) - self.mkdir(self.global_explorer_out_path) - self.mkdir(self.bin_path) + try: + if os.path.exists(destination): + shutil.rmtree(destination) + except PermissionError as e: + raise cdist.Error("Cannot delete old cache %s: %s" % (destination, e)) + + shutil.move(self.base_path, destination) + + def _create_messages(self): + """Create empty messages""" + with open(self.messages_path, "w"): + pass def _create_conf_path_and_link_conf_dirs(self): # Link destination directories @@ -184,7 +232,7 @@ class Local(object): for entry in os.listdir(current_dir): rel_entry_path = os.path.join(sub_dir, entry) - src = os.path.join(conf_dir, sub_dir, entry) + src = os.path.abspath(os.path.join(conf_dir, sub_dir, entry)) dst = os.path.join(self.conf_path, sub_dir, entry) # Already exists? remove and link diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index d4d2cb2b..9b7d5d1c 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -23,6 +23,7 @@ import io import os import sys +import glob import subprocess import logging @@ -43,12 +44,20 @@ class Remote(object): Directly accessing the remote side from python code is a bug. """ - def __init__(self, target_host, remote_base_path, remote_exec, remote_copy): + def __init__(self, + target_host, + remote_exec, + remote_copy, + base_path=None): self.target_host = target_host - self.base_path = remote_base_path self._exec = remote_exec self._copy = remote_copy + if base_path: + self.base_path = base_path + else: + self.base_path = "/var/lib/cdist" + self.conf_path = os.path.join(self.base_path, "conf") self.object_path = os.path.join(self.base_path, "object") @@ -57,9 +66,19 @@ class Remote(object): self.log = logging.getLogger(self.target_host) + self._init_env() + + def _init_env(self): + """Setup environment for scripts - HERE????""" + # FIXME: better do so in exec functions that require it! + os.environ['__remote_copy'] = self._copy + os.environ['__remote_exec'] = self._exec + + def create_files_dirs(self): self.rmdir(self.base_path) self.mkdir(self.base_path) + self.run(["chmod", "0700", self.base_path]) self.mkdir(self.conf_path) def rmdir(self, path): @@ -76,9 +95,17 @@ class Remote(object): """Transfer a file or directory to the remote side.""" self.log.debug("Remote transfer: %s -> %s", source, destination) self.rmdir(destination) - command = self._copy.split() - command.extend(["-r", source, self.target_host + ":" + destination]) - self._run_command(command) + if os.path.isdir(source): + self.mkdir(destination) + for f in glob.glob1(source, '*'): + command = self._copy.split() + path = os.path.join(source, f) + command.extend([path, '{0}:{1}'.format(self.target_host, destination)]) + self._run_command(command) + else: + command = self._copy.split() + command.extend([source, '{0}:{1}'.format(self.target_host, destination)]) + self._run_command(command) def run_script(self, script, env=None, return_output=False): """Run the given script with the given environment on the remote side. @@ -86,7 +113,7 @@ class Remote(object): """ - command = ["/bin/sh", "-e"] + command = [ os.environ.get('CDIST_REMOTE_SHELL',"/bin/sh") , "-e"] command.append(script) return self.run(command, env, return_output) @@ -100,9 +127,6 @@ class Remote(object): cmd = self._exec.split() cmd.append(self.target_host) - # Always call umask before actual call to ensure proper file permissions - cmd.append("umask 077;") - # FIXME: replace this by -o SendEnv name -o SendEnv name ... to ssh? # can't pass environment to remote side, so prepend command with # variable declarations @@ -134,6 +158,6 @@ class Remote(object): except subprocess.CalledProcessError: raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: - raise cdist.Error(" ".join(*args) + ": " + error.args[1]) + raise cdist.Error(" ".join(command) + ": " + error.args[1]) except UnicodeDecodeError: raise DecodeError(command) diff --git a/cdist/install.py b/cdist/log.py similarity index 65% rename from cdist/install.py rename to cdist/log.py index 0f06f5e7..8c3aac79 100644 --- a/cdist/install.py +++ b/cdist/log.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -20,14 +20,19 @@ # # -import os -import cdist.config_install +import logging -class Install(cdist.config_install.ConfigInstall): - def __init__(self, *args, **kargs): - """Enhance config install with install support""" +class Log(logging.Logger): - # Setup environ to be used in emulator - os.environ['__install'] = "yes" + def __init__(self, name): - super().__init__(*args, **kargs) + self.name = name + super().__init__(name) + self.addFilter(self) + + def filter(self, record): + """Prefix messages with logger name""" + + record.msg = self.name + ": " + str(record.msg) + + return True diff --git a/cdist/message.py b/cdist/message.py new file mode 100644 index 00000000..b840a84d --- /dev/null +++ b/cdist/message.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# +# 2013 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 . +# +# + +import logging +import os +import shutil +import tempfile + +import cdist + +log = logging.getLogger(__name__) + + +class Message(object): + """Support messaging between types + + """ + def __init__(self, prefix, messages): + self.prefix = prefix + self.global_messages = messages + + self.messages_in = tempfile.mkstemp(suffix='.cdist_message_in')[1] + self.messages_out = tempfile.mkstemp(suffix='.cdist_message_out')[1] + + self._copy_messages() + + + @property + def env(self): + env = {} + env['__messages_in'] = self.messages_in + env['__messages_out'] = self.messages_out + + return env + + def _copy_messages(self): + """Copy global contents into our copy""" + shutil.copyfile(self.global_messages, self.messages_in) + + def _cleanup(self): + """remove temporary files""" + if os.path.exists(self.messages_in): + os.remove(self.messages_in) + if os.path.exists(self.messages_out): + os.remove(self.messages_out) + + def _merge_messages(self): + """merge newly written lines into global file""" + with open(self.messages_out) as fd: + content = fd.readlines() + + with open(self.global_messages, 'a') as fd: + for line in content: + fd.write("%s:%s" % (self.prefix, line)) + + def merge_messages(self): + self._merge_messages() + self._cleanup() diff --git a/cdist/resolver.py b/cdist/resolver.py deleted file mode 100644 index c1b2c292..00000000 --- a/cdist/resolver.py +++ /dev/null @@ -1,168 +0,0 @@ -# -*- coding: utf-8 -*- -# -# 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 . -# -# - -import logging -import os -import itertools -import fnmatch - -import cdist - -log = logging.getLogger(__name__) - - -class CircularReferenceError(cdist.Error): - def __init__(self, cdist_object, required_object): - self.cdist_object = cdist_object - self.required_object = required_object - - def __str__(self): - return 'Circular reference detected: %s -> %s' % (self.cdist_object.name, self.required_object.name) - - -class RequirementNotFoundError(cdist.Error): - def __init__(self, requirement): - self.requirement = requirement - - def __str__(self): - return 'Requirement could not be found: %s' % self.requirement - - -class DependencyResolver(object): - """Cdist's dependency resolver. - - Usage: - >> resolver = DependencyResolver(list_of_objects) - # Easy access to the objects we are working with - >> resolver.objects['__some_type/object_id'] - - # Easy access to a specific objects dependencies - >> resolver.dependencies['__some_type/object_id'] - [, ] - # Pretty print the dependency graph - >> from pprint import pprint - >> pprint(resolver.dependencies) - # Iterate over all existing objects in the correct order - >> for cdist_object in resolver: - >> do_something_with(cdist_object) - """ - def __init__(self, objects, logger=None): - self.objects = dict((o.name, o) for o in objects) - self._dependencies = None - self.log = logger or log - - @property - def dependencies(self): - """Build the dependency graph. - - Returns a dict where the keys are the object names and the values are - lists of all dependencies including the key object itself. - """ - if self._dependencies is None: - log.info("Resolving dependencies...") - self._dependencies = d = {} - self._preprocess_requirements() - for name,cdist_object in self.objects.items(): - resolved = [] - unresolved = [] - self._resolve_object_dependencies(cdist_object, resolved, unresolved) - d[name] = resolved - return self._dependencies - - def find_requirements_by_name(self, requirements): - """Takes a list of requirement patterns and returns a list of matching object instances. - - Patterns are expected to be Unix shell-style wildcards for use with fnmatch.filter. - - find_requirements_by_name(['__type/object_id', '__other_type/*']) -> - [, , ] - """ - object_names = self.objects.keys() - for pattern in requirements: - found = False - for requirement in fnmatch.filter(object_names, pattern): - found = True - yield self.objects[requirement] - if not found: - # FIXME: get rid of the singleton object_id, it should be invisible to the code -> hide it in Object - singleton = os.path.join(pattern, 'singleton') - if singleton in self.objects: - yield self.objects[singleton] - else: - raise RequirementNotFoundError(pattern) - - def _preprocess_requirements(self): - """Find all autorequire dependencies and merge them to be just requirements - for further processing. - """ - for cdist_object in self.objects.values(): - if cdist_object.autorequire: - # The objects (children) that this cdist_object (parent) defined - # in it's type manifest shall inherit all explicit requirements - # that the parent has so that user defined requirements are - # fullfilled and processed in the expected order. - for auto_requirement in self.find_requirements_by_name(cdist_object.autorequire): - for requirement in cdist_object.requirements: - if requirement not in auto_requirement.requirements: - auto_requirement.requirements.append(requirement) - # On the other hand the parent shall depend on all the children - # it created so that the user can setup dependencies on it as a - # whole without having to know anything about the parents - # internals. - cdist_object.requirements.extend(cdist_object.autorequire) - # As we changed the object on disc, we have to ensure it is not - # preprocessed again if someone would call us multiple times. - cdist_object.autorequire = [] - - def _resolve_object_dependencies(self, cdist_object, resolved, unresolved): - """Resolve all dependencies for the given cdist_object and store them - in the list which is passed as the 'resolved' arguments. - - e.g. - resolved = [] - unresolved = [] - resolve_object_dependencies(some_object, resolved, unresolved) - print("Dependencies for %s: %s" % (some_object, resolved)) - """ - self.log.debug('Resolving dependencies for: %s' % cdist_object.name) - try: - unresolved.append(cdist_object) - for required_object in self.find_requirements_by_name(cdist_object.requirements): - self.log.debug("Object %s requires %s", cdist_object, required_object) - if required_object not in resolved: - if required_object in unresolved: - raise CircularReferenceError(cdist_object, required_object) - self._resolve_object_dependencies(required_object, resolved, unresolved) - resolved.append(cdist_object) - unresolved.remove(cdist_object) - except RequirementNotFoundError as e: - raise cdist.CdistObjectError(cdist_object, "requires non-existing " + e.requirement) - - def __iter__(self): - """Iterate over all unique objects and yield them in the correct order. - """ - iterable = itertools.chain(*self.dependencies.values()) - # Keep record of objects that have already been seen - seen = set() - seen_add = seen.add - for cdist_object in itertools.filterfalse(seen.__contains__, iterable): - seen_add(cdist_object) - yield cdist_object diff --git a/cdist/shell.py b/cdist/shell.py new file mode 100644 index 00000000..8ca68115 --- /dev/null +++ b/cdist/shell.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# +# 2013 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 . +# +# + +import logging +import os +import subprocess + +# initialise cdist +import cdist.exec.local + + +import cdist.config + +log = logging.getLogger(__name__) + +class Shell(object): + + def __init__(self, shell=None): + + self.shell = shell + + self.target_host = "cdist-shell-no-target-host" + self.local = cdist.exec.local.Local( + target_host=self.target_host) + + def _init_shell(self): + """Select shell to execute, if not specified by user""" + + if not self.shell: + self.shell = os.environ.get('SHELL',"/bin/sh") + + def _init_files_dirs(self): + self.local.create_files_dirs() + + def _init_environment(self): + self.env = os.environ.copy() + additional_env = { + 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), + '__cdist_type_base_path': self.local.type_path, # for use in type emulator + '__cdist_manifest': "cdist shell", + '__global': self.local.base_path, + '__target_host': self.target_host, + '__manifest': self.local.manifest_path, + '__explorer': self.local.global_explorer_path, + } + + self.env.update(additional_env) + + def run(self): + self._init_shell() + self._init_files_dirs() + self._init_environment() + + log.info("Starting shell...") + self.local.run([self.shell], self.env) + log.info("Finished shell.") + + @classmethod + def commandline(cls, args): + shell = cls(args.shell) + shell.run() diff --git a/cdist/test/autorequire/__init__.py b/cdist/test/autorequire/__init__.py deleted file mode 100644 index 330680df..00000000 --- a/cdist/test/autorequire/__init__.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- -# -# 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 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 . -# -# - -import os -import shutil - -import cdist -from cdist import test -from cdist.exec import local -from cdist import core -from cdist.core import manifest -from cdist import resolver -from cdist import config -import cdist.context - -import os.path as op -my_dir = op.abspath(op.dirname(__file__)) -fixtures = op.join(my_dir, 'fixtures') -add_conf_dir = op.join(fixtures, 'conf') - -class AutorequireTestCase(test.CdistTestCase): - - def setUp(self): - self.orig_environ = os.environ - os.environ = os.environ.copy() - self.temp_dir = self.mkdtemp() - - self.out_dir = os.path.join(self.temp_dir, "out") - self.remote_out_dir = os.path.join(self.temp_dir, "remote") - - os.environ['__cdist_out_dir'] = self.out_dir - os.environ['__cdist_remote_out_dir'] = self.remote_out_dir - - self.context = cdist.context.Context( - target_host=self.target_host, - remote_copy=self.remote_copy, - remote_exec=self.remote_exec, - add_conf_dirs=[add_conf_dir], - exec_path=test.cdist_exec_path, - debug=False) - - self.config = config.Config(self.context) - - def tearDown(self): - os.environ = self.orig_environ - shutil.rmtree(self.temp_dir) - - def test_implicit_dependencies(self): - self.context.initial_manifest = os.path.join(self.context.local.manifest_path, 'implicit_dependencies') - self.config.stage_prepare() - - objects = core.CdistObject.list_objects(self.context.local.object_path, self.context.local.type_path) - dependency_resolver = resolver.DependencyResolver(objects) - expected_dependencies = [ - dependency_resolver.objects['__package_special/b'], - dependency_resolver.objects['__package/b'], - dependency_resolver.objects['__package_special/a'] - ] - resolved_dependencies = dependency_resolver.dependencies['__package_special/a'] - self.assertEqual(resolved_dependencies, expected_dependencies) - - def test_circular_dependency(self): - self.context.initial_manifest = os.path.join(self.context.local.manifest_path, 'circular_dependency') - self.config.stage_prepare() - # raises CircularDependecyError - self.config.stage_run() diff --git a/cdist/test/autorequire/fixtures/conf/manifest/circular_dependency b/cdist/test/autorequire/fixtures/conf/manifest/circular_dependency deleted file mode 100755 index 6ea308d1..00000000 --- a/cdist/test/autorequire/fixtures/conf/manifest/circular_dependency +++ /dev/null @@ -1,2 +0,0 @@ -# this has triggered CircularReferenceError -__nfsroot_client test diff --git a/cdist/test/autorequire/fixtures/conf/manifest/implicit_dependencies b/cdist/test/autorequire/fixtures/conf/manifest/implicit_dependencies deleted file mode 100755 index 7d68aed2..00000000 --- a/cdist/test/autorequire/fixtures/conf/manifest/implicit_dependencies +++ /dev/null @@ -1,3 +0,0 @@ -# this creates implicit dependencies through autorequire. -# this failed because autorequired dependencies where not aware of their anchestors dependencies -__top test diff --git a/cdist/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest b/cdist/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest deleted file mode 100755 index f6cb7833..00000000 --- a/cdist/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest +++ /dev/null @@ -1,3 +0,0 @@ -__user root -__root_ssh_authorized_key john -__root_ssh_authorized_key frank diff --git a/cdist/test/autorequire/fixtures/conf/type/__package/manifest b/cdist/test/autorequire/fixtures/conf/type/__package/manifest deleted file mode 100755 index 6f70e627..00000000 --- a/cdist/test/autorequire/fixtures/conf/type/__package/manifest +++ /dev/null @@ -1 +0,0 @@ -__package_special "$__object_id" diff --git a/cdist/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest b/cdist/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest deleted file mode 100755 index 6224629f..00000000 --- a/cdist/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest +++ /dev/null @@ -1,4 +0,0 @@ -user="$__object_id" -__directory /root/.ssh -require="__directory/root/.ssh" \ - __addifnosuchline "ssh-root-$user" diff --git a/cdist/test/autorequire/fixtures/conf/type/__top/manifest b/cdist/test/autorequire/fixtures/conf/type/__top/manifest deleted file mode 100755 index d6968c25..00000000 --- a/cdist/test/autorequire/fixtures/conf/type/__top/manifest +++ /dev/null @@ -1,2 +0,0 @@ -__package b -require="__package/b" __package a diff --git a/cdist/test/object/__init__.py b/cdist/test/cdist_object/__init__.py similarity index 77% rename from cdist/test/object/__init__.py rename to cdist/test/cdist_object/__init__.py index c4f46cd1..3c25a959 100644 --- a/cdist/test/object/__init__.py +++ b/cdist/test/cdist_object/__init__.py @@ -2,6 +2,7 @@ # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -48,7 +49,7 @@ class ObjectClassTestCase(test.CdistTestCase): self.expected_objects = [] for cdist_object_name in self.expected_object_names: - cdist_type, cdist_object_id = cdist_object_name.split("/", maxsplit=1) + cdist_type, cdist_object_id = cdist_object_name.split("/", 1) cdist_object = core.CdistObject(core.CdistType(type_base_path, cdist_type), object_base_path, cdist_object_id) self.expected_objects.append(cdist_object) @@ -58,12 +59,22 @@ class ObjectClassTestCase(test.CdistTestCase): def test_list_type_names(self): type_names = list(cdist.core.CdistObject.list_type_names(object_base_path)) - self.assertEqual(type_names, ['__first', '__second', '__third']) + self.assertEqual(sorted(type_names), ['__first', '__second', '__third']) def test_list_objects(self): - found_objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) + found_objects = sorted(list(core.CdistObject.list_objects(object_base_path, type_base_path))) self.assertEqual(found_objects, self.expected_objects) + def test_create_singleton(self): + """Check whether creating an object without id (singleton) works""" + singleton = self.expected_objects[0].object_from_name("__test_singleton") + # came here - everything fine + + def test_create_singleton_not_singleton_type(self): + """try to create an object of a type that is not a singleton + without an object id""" + with self.assertRaises(cdist.core.cdist_object.MissingObjectIdError): + self.expected_objects[0].object_from_name("__first") class ObjectIdTestCase(test.CdistTestCase): def test_object_id_contains_double_slash(self): @@ -84,6 +95,17 @@ class ObjectIdTestCase(test.CdistTestCase): core.CdistObject(cdist_type, object_base_path, illegal_object_id) # if we get here, the test passed + def test_object_id_contains_only_dot(self): + cdist_type = core.CdistType(type_base_path, '__third') + illegal_object_id = '.' + with self.assertRaises(core.IllegalObjectIdError): + core.CdistObject(cdist_type, object_base_path, illegal_object_id) + + def test_object_id_on_singleton_type(self): + cdist_type = core.CdistType(type_base_path, '__test_singleton') + illegal_object_id = 'object_id' + with self.assertRaises(core.IllegalObjectIdError): + core.CdistObject(cdist_type, object_base_path, illegal_object_id) class ObjectTestCase(test.CdistTestCase): @@ -92,7 +114,6 @@ class ObjectTestCase(test.CdistTestCase): self.cdist_object = core.CdistObject(self.cdist_type, object_base_path, 'moon') def tearDown(self): - self.cdist_object.changed = False self.cdist_object.prepared = False self.cdist_object.ran = False self.cdist_object.source = [] @@ -162,13 +183,6 @@ class ObjectTestCase(test.CdistTestCase): expected = [] self.assertEqual(list(self.cdist_object.requirements), expected) - def test_changed(self): - self.assertFalse(self.cdist_object.changed) - - def test_changed_after_changing(self): - self.cdist_object.changed = True - self.assertTrue(self.cdist_object.changed) - def test_state(self): self.assertEqual(self.cdist_object.state, '') @@ -212,54 +226,3 @@ class ObjectTestCase(test.CdistTestCase): self.assertTrue(isinstance(other_object, core.CdistObject)) self.assertEqual(other_object.cdist_type.name, '__first') self.assertEqual(other_object.object_id, 'man') - - - -class ObjectResolveRequirementsTestCase(test.CdistTestCase): - - def setUp(self): - 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_names = [o.name for o in self.objects] - - print(self.objects) - - self.cdist_type = core.CdistType(type_base_path, '__third') - self.cdist_object = core.CdistObject(self.cdist_type, object_base_path, 'moon') - - def tearDown(self): - for o in self.objects: - o.requirements = [] - - def test_find_requirements_by_name_string(self): - """Check that resolving requirements by name works (require all objects)""" - requirements = self.object_names - - self.cdist_object.requirements = requirements - - found_requirements = sorted(self.cdist_object.find_requirements_by_name(self.cdist_object.requirements)) - expected_requirements = sorted(self.objects) - - self.assertEqual(found_requirements, expected_requirements) - - def test_find_requirements_by_name_pattern(self): - """Test whether pattern matching on requirements works""" - - # Matches all objects in the end - requirements = ['__first/*', '__second/*-the', '__third/moon'] - - self.cdist_object.requirements = requirements - - expected_requirements = sorted(self.objects) - found_requirements = sorted(self.cdist_object.find_requirements_by_name(self.cdist_object.requirements)) - - self.assertEqual(expected_requirements, found_requirements) - - def test_requirement_not_found(self): - """Ensure an exception is thrown for missing depedencies""" - cdist_object = self.object_index['__first/man'] - cdist_object.requirements = ['__does/not/exist'] - - with self.assertRaises(core.cdist_object.RequirementNotFoundError): - # Use list, as generator does not (yet) raise the error - list(cdist_object.find_requirements_by_name(cdist_object.requirements)) diff --git a/cdist/test/config_install/fixtures/object/__first/.keep b/cdist/test/cdist_object/fixtures/object/__first/.keep similarity index 100% rename from cdist/test/config_install/fixtures/object/__first/.keep rename to cdist/test/cdist_object/fixtures/object/__first/.keep diff --git a/cdist/test/config_install/fixtures/object/__first/man/.cdist/.keep b/cdist/test/cdist_object/fixtures/object/__first/child/.cdist/.keep similarity index 100% rename from cdist/test/config_install/fixtures/object/__first/man/.cdist/.keep rename to cdist/test/cdist_object/fixtures/object/__first/child/.cdist/.keep diff --git a/cdist/test/config_install/fixtures/object/__second/.keep b/cdist/test/cdist_object/fixtures/object/__first/dog/.cdist/.keep similarity index 100% rename from cdist/test/config_install/fixtures/object/__second/.keep rename to cdist/test/cdist_object/fixtures/object/__first/dog/.cdist/.keep diff --git a/cdist/test/config_install/fixtures/object/__second/on-the/.cdist/.keep b/cdist/test/cdist_object/fixtures/object/__first/man/.cdist/.keep similarity index 100% rename from cdist/test/config_install/fixtures/object/__second/on-the/.cdist/.keep rename to cdist/test/cdist_object/fixtures/object/__first/man/.cdist/.keep diff --git a/cdist/test/config_install/fixtures/object/__third/.keep b/cdist/test/cdist_object/fixtures/object/__first/woman/.cdist/.keep similarity index 100% rename from cdist/test/config_install/fixtures/object/__third/.keep rename to cdist/test/cdist_object/fixtures/object/__first/woman/.cdist/.keep diff --git a/cdist/test/config_install/fixtures/object/__third/moon/.cdist/.keep b/cdist/test/cdist_object/fixtures/object/__second/.keep similarity index 100% rename from cdist/test/config_install/fixtures/object/__third/moon/.cdist/.keep rename to cdist/test/cdist_object/fixtures/object/__second/.keep diff --git a/cdist/test/config_install/fixtures/type/__first/.keep b/cdist/test/cdist_object/fixtures/object/__second/on-the/.cdist/.keep similarity index 100% rename from cdist/test/config_install/fixtures/type/__first/.keep rename to cdist/test/cdist_object/fixtures/object/__second/on-the/.cdist/.keep diff --git a/cdist/test/config_install/fixtures/type/__second/.keep b/cdist/test/cdist_object/fixtures/object/__second/under-the/.cdist/.keep similarity index 100% rename from cdist/test/config_install/fixtures/type/__second/.keep rename to cdist/test/cdist_object/fixtures/object/__second/under-the/.cdist/.keep diff --git a/cdist/test/config_install/fixtures/type/__third/.keep b/cdist/test/cdist_object/fixtures/object/__third/.keep similarity index 100% rename from cdist/test/config_install/fixtures/type/__third/.keep rename to cdist/test/cdist_object/fixtures/object/__third/.keep diff --git a/cdist/test/object/fixtures/object/__first/.keep b/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/.keep similarity index 100% rename from cdist/test/object/fixtures/object/__first/.keep rename to cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/.keep diff --git a/cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/name b/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/name similarity index 100% rename from cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/name rename to cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/name diff --git a/cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/planet b/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/planet similarity index 100% rename from cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/planet rename to cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/planet diff --git a/cdist/test/object/fixtures/object/__first/child/.cdist/.keep b/cdist/test/cdist_object/fixtures/type/__first/.keep similarity index 100% rename from cdist/test/object/fixtures/object/__first/child/.cdist/.keep rename to cdist/test/cdist_object/fixtures/type/__first/.keep diff --git a/cdist/test/object/fixtures/object/__first/dog/.cdist/.keep b/cdist/test/cdist_object/fixtures/type/__second/.keep similarity index 100% rename from cdist/test/object/fixtures/object/__first/dog/.cdist/.keep rename to cdist/test/cdist_object/fixtures/type/__second/.keep diff --git a/cdist/test/object/fixtures/object/__first/man/.cdist/.keep b/cdist/test/cdist_object/fixtures/type/__test_singleton/singleton similarity index 100% rename from cdist/test/object/fixtures/object/__first/man/.cdist/.keep rename to cdist/test/cdist_object/fixtures/type/__test_singleton/singleton diff --git a/cdist/test/object/fixtures/object/__first/woman/.cdist/.keep b/cdist/test/cdist_object/fixtures/type/__third/.keep similarity index 100% rename from cdist/test/object/fixtures/object/__first/woman/.cdist/.keep rename to cdist/test/cdist_object/fixtures/type/__third/.keep diff --git a/cdist/test/type/__init__.py b/cdist/test/cdist_type/__init__.py similarity index 92% rename from cdist/test/type/__init__.py rename to cdist/test/cdist_type/__init__.py index 5e774aa9..36a524b4 100644 --- a/cdist/test/type/__init__.py +++ b/cdist/test/cdist_type/__init__.py @@ -34,7 +34,7 @@ class TypeTestCase(test.CdistTestCase): def test_list_type_names(self): base_path = op.join(fixtures, 'list_types') type_names = core.CdistType.list_type_names(base_path) - self.assertEqual(type_names, ['__first', '__second', '__third']) + self.assertEqual(sorted(type_names), ['__first', '__second', '__third']) def test_list_types(self): base_path = op.join(fixtures, 'list_types') @@ -44,7 +44,7 @@ class TypeTestCase(test.CdistTestCase): core.CdistType(base_path, '__second'), core.CdistType(base_path, '__third'), ] - self.assertEqual(types, types_expected) + self.assertEqual(sorted(types), types_expected) def test_only_one_instance(self): base_path = fixtures @@ -106,16 +106,6 @@ class TypeTestCase(test.CdistTestCase): cdist_type = core.CdistType(base_path, '__not_singleton') self.assertFalse(cdist_type.is_singleton) - def test_install_is_install(self): - base_path = fixtures - cdist_type = core.CdistType(base_path, '__install') - self.assertTrue(cdist_type.is_install) - - def test_not_install_is_install(self): - base_path = fixtures - cdist_type = core.CdistType(base_path, '__not_install') - self.assertFalse(cdist_type.is_install) - def test_with_explorers(self): base_path = fixtures cdist_type = core.CdistType(base_path, '__with_explorers') @@ -156,3 +146,10 @@ class TypeTestCase(test.CdistTestCase): cdist_type = core.CdistType(base_path, '__without_boolean_parameters') self.assertEqual(cdist_type.boolean_parameters, []) + def test_with_parameter_defaults(self): + base_path = fixtures + cdist_type = core.CdistType(base_path, '__with_parameter_defaults') + self.assertTrue('optional1' in cdist_type.parameter_defaults) + self.assertFalse('optional2' in cdist_type.parameter_defaults) + self.assertEqual(cdist_type.parameter_defaults['optional1'], 'value1') + diff --git a/cdist/test/type/fixtures/__install/install b/cdist/test/cdist_type/fixtures/__install/install similarity index 100% rename from cdist/test/type/fixtures/__install/install rename to cdist/test/cdist_type/fixtures/__install/install diff --git a/cdist/test/object/fixtures/object/__second/.keep b/cdist/test/cdist_type/fixtures/__name_path/.keep similarity index 100% rename from cdist/test/object/fixtures/object/__second/.keep rename to cdist/test/cdist_type/fixtures/__name_path/.keep diff --git a/cdist/test/object/fixtures/object/__second/on-the/.cdist/.keep b/cdist/test/cdist_type/fixtures/__not_install/.keep similarity index 100% rename from cdist/test/object/fixtures/object/__second/on-the/.cdist/.keep rename to cdist/test/cdist_type/fixtures/__not_install/.keep diff --git a/cdist/test/object/fixtures/object/__second/under-the/.cdist/.keep b/cdist/test/cdist_type/fixtures/__not_singleton/.keep similarity index 100% rename from cdist/test/object/fixtures/object/__second/under-the/.cdist/.keep rename to cdist/test/cdist_type/fixtures/__not_singleton/.keep diff --git a/cdist/test/object/fixtures/object/__third/.keep b/cdist/test/cdist_type/fixtures/__singleton/singleton similarity index 100% rename from cdist/test/object/fixtures/object/__third/.keep rename to cdist/test/cdist_type/fixtures/__singleton/singleton diff --git a/cdist/test/type/fixtures/__with_boolean_parameters/parameter/boolean b/cdist/test/cdist_type/fixtures/__with_boolean_parameters/parameter/boolean similarity index 100% rename from cdist/test/type/fixtures/__with_boolean_parameters/parameter/boolean rename to cdist/test/cdist_type/fixtures/__with_boolean_parameters/parameter/boolean diff --git a/cdist/test/type/fixtures/__with_explorers/explorer/whatever b/cdist/test/cdist_type/fixtures/__with_explorers/explorer/whatever similarity index 100% rename from cdist/test/type/fixtures/__with_explorers/explorer/whatever rename to cdist/test/cdist_type/fixtures/__with_explorers/explorer/whatever diff --git a/cdist/test/type/fixtures/__with_optional_parameters/parameter/optional b/cdist/test/cdist_type/fixtures/__with_optional_parameters/parameter/optional similarity index 100% rename from cdist/test/type/fixtures/__with_optional_parameters/parameter/optional rename to cdist/test/cdist_type/fixtures/__with_optional_parameters/parameter/optional diff --git a/cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/default/optional1 b/cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/default/optional1 new file mode 100644 index 00000000..ef208405 --- /dev/null +++ b/cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/default/optional1 @@ -0,0 +1 @@ +value1 diff --git a/cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/optional b/cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/optional new file mode 100644 index 00000000..8174d2a9 --- /dev/null +++ b/cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/optional @@ -0,0 +1,2 @@ +optional1 +optional2 diff --git a/cdist/test/type/fixtures/__with_required_parameters/parameter/required b/cdist/test/cdist_type/fixtures/__with_required_parameters/parameter/required similarity index 100% rename from cdist/test/type/fixtures/__with_required_parameters/parameter/required rename to cdist/test/cdist_type/fixtures/__with_required_parameters/parameter/required diff --git a/cdist/test/object/fixtures/object/__third/moon/.cdist/.keep b/cdist/test/cdist_type/fixtures/__without_boolean_parameters/.keep similarity index 100% rename from cdist/test/object/fixtures/object/__third/moon/.cdist/.keep rename to cdist/test/cdist_type/fixtures/__without_boolean_parameters/.keep diff --git a/cdist/test/object/fixtures/type/__first/.keep b/cdist/test/cdist_type/fixtures/__without_explorers/.keep similarity index 100% rename from cdist/test/object/fixtures/type/__first/.keep rename to cdist/test/cdist_type/fixtures/__without_explorers/.keep diff --git a/cdist/test/object/fixtures/type/__second/.keep b/cdist/test/cdist_type/fixtures/__without_optional_parameters/.keep similarity index 100% rename from cdist/test/object/fixtures/type/__second/.keep rename to cdist/test/cdist_type/fixtures/__without_optional_parameters/.keep diff --git a/cdist/test/object/fixtures/type/__third/.keep b/cdist/test/cdist_type/fixtures/__without_required_parameters/.keep similarity index 100% rename from cdist/test/object/fixtures/type/__third/.keep rename to cdist/test/cdist_type/fixtures/__without_required_parameters/.keep diff --git a/cdist/test/resolver/fixtures/object/__first/.keep b/cdist/test/cdist_type/fixtures/list_types/__first/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__first/.keep rename to cdist/test/cdist_type/fixtures/list_types/__first/.keep diff --git a/cdist/test/resolver/fixtures/object/__first/child/.cdist/.keep b/cdist/test/cdist_type/fixtures/list_types/__second/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__first/child/.cdist/.keep rename to cdist/test/cdist_type/fixtures/list_types/__second/.keep diff --git a/cdist/test/resolver/fixtures/object/__first/dog/.cdist/.keep b/cdist/test/cdist_type/fixtures/list_types/__third/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__first/dog/.cdist/.keep rename to cdist/test/cdist_type/fixtures/list_types/__third/.keep diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 284ef9c0..796e8a51 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -39,21 +39,23 @@ conf_dir = op.join(fixtures, 'conf') class CodeTestCase(test.CdistTestCase): def setUp(self): - self.target_host = 'localhost' - - self.out_path = self.mkdtemp() + self.local_dir = self.mkdtemp() self.local = local.Local( target_host=self.target_host, - out_path = self.out_path, + base_path = self.local_dir, exec_path = cdist.test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() - self.remote_base_path = self.mkdtemp() + self.remote_dir = self.mkdtemp() remote_exec = self.remote_exec remote_copy = self.remote_copy - self.remote = remote.Remote(self.target_host, self.remote_base_path, remote_exec, remote_copy) + self.remote = remote.Remote( + target_host=self.target_host, + remote_exec=remote_exec, + remote_copy=remote_copy, + base_path=self.remote_dir) self.remote.create_files_dirs() self.code = code.Code(self.target_host, self.local, self.remote) @@ -63,8 +65,8 @@ class CodeTestCase(test.CdistTestCase): self.cdist_object.create() def tearDown(self): - shutil.rmtree(self.out_path) - shutil.rmtree(self.remote_base_path) + shutil.rmtree(self.local_dir) + shutil.rmtree(self.remote_dir) def test_run_gencode_local_environment(self): output_string = self.code.run_gencode_local(self.cdist_object) @@ -75,7 +77,7 @@ class CodeTestCase(test.CdistTestCase): key = junk.split(' ')[1] output_dict[key] = value self.assertEqual(output_dict['__target_host'], self.local.target_host) - self.assertEqual(output_dict['__global'], self.local.out_path) + self.assertEqual(output_dict['__global'], self.local.base_path) self.assertEqual(output_dict['__type'], self.cdist_type.absolute_path) self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) @@ -90,7 +92,7 @@ class CodeTestCase(test.CdistTestCase): key = junk.split(' ')[1] output_dict[key] = value self.assertEqual(output_dict['__target_host'], self.local.target_host) - self.assertEqual(output_dict['__global'], self.local.out_path) + self.assertEqual(output_dict['__global'], self.local.base_path) self.assertEqual(output_dict['__type'], self.cdist_type.absolute_path) self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) diff --git a/cdist/test/config/__init__.py b/cdist/test/config/__init__.py new file mode 100644 index 00000000..70501c89 --- /dev/null +++ b/cdist/test/config/__init__.py @@ -0,0 +1,166 @@ +# -*- coding: utf-8 -*- +# +# 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Daniel Heule (hda at sfs.biz) +# +# 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 . +# +# + +import os +import shutil + +from cdist import test +from cdist import core + +import cdist +import cdist.config +import cdist.core.cdist_type +import cdist.core.cdist_object + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') +object_base_path = op.join(fixtures, 'object') +type_base_path = op.join(fixtures, 'type') +add_conf_dir = op.join(fixtures, 'conf') + +class ConfigRunTestCase(test.CdistTestCase): + + def setUp(self): + + # Change env for context + self.orig_environ = os.environ + os.environ = os.environ.copy() + self.temp_dir = self.mkdtemp() + + self.local_dir = os.path.join(self.temp_dir, "local") + os.mkdir(self.local_dir) + self.local = cdist.exec.local.Local( + target_host=self.target_host, + base_path=self.local_dir) + + self.remote_dir = os.path.join(self.temp_dir, "remote") + os.mkdir(self.remote_dir) + self.remote = cdist.exec.remote.Remote( + target_host=self.target_host, + remote_copy=self.remote_copy, + remote_exec=self.remote_exec, + base_path=self.remote_dir) + + self.local.object_path = object_base_path + self.local.type_path = type_base_path + + self.config = cdist.config.Config(self.local, self.remote) + + 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_names = [o.name for o in self.objects] + + def tearDown(self): + for o in self.objects: + o.requirements = [] + o.state = "" + + os.environ = self.orig_environ + shutil.rmtree(self.temp_dir) + + def test_dependency_resolution(self): + first = self.object_index['__first/man'] + second = self.object_index['__second/on-the'] + third = self.object_index['__third/moon'] + + first.requirements = [second.name] + second.requirements = [third.name] + + # First run: + # solves first and maybe second (depending on the order in the set) + self.config.iterate_once() + self.assertTrue(third.state == third.STATE_DONE) + + self.config.iterate_once() + self.assertTrue(second.state == second.STATE_DONE) + + + try: + self.config.iterate_once() + except cdist.Error: + # Allow failing, because the third run may or may not be unecessary already, + # depending on the order of the objects + pass + self.assertTrue(first.state == first.STATE_DONE) + + def test_unresolvable_requirements(self): + """Ensure an exception is thrown for unresolvable depedencies""" + + # Create to objects depending on each other - no solution possible + first = self.object_index['__first/man'] + second = self.object_index['__second/on-the'] + + first.requirements = [second.name] + second.requirements = [first.name] + + with self.assertRaises(cdist.UnresolvableRequirementsError): + self.config.iterate_until_finished() + + def test_missing_requirements(self): + """Throw an error if requiring something non-existing""" + first = self.object_index['__first/man'] + first.requirements = ['__first/not/exist'] + with self.assertRaises(cdist.UnresolvableRequirementsError): + self.config.iterate_until_finished() + + def test_requirement_broken_type(self): + """Unknown type should be detected in the resolving process""" + first = self.object_index['__first/man'] + first.requirements = ['__nosuchtype/not/exist'] + with self.assertRaises(cdist.core.cdist_type.NoSuchTypeError): + self.config.iterate_until_finished() + + def test_requirement_singleton_where_no_singleton(self): + """Missing object id should be detected in the resolving process""" + first = self.object_index['__first/man'] + first.requirements = ['__first'] + with self.assertRaises(cdist.core.cdist_object.MissingObjectIdError): + self.config.iterate_until_finished() + + + def test_dryrun(self): + """Test if the dryrun option is working like expected""" + drylocal = cdist.exec.local.Local( + target_host=self.target_host, + base_path=self.local_dir, + #exec_path can not derivated from sys.argv in case of unittest ... + exec_path=os.path.abspath(os.path.join(my_dir,'../../../scripts/cdist')), + initial_manifest=os.path.join(fixtures, 'manifest/dryrun_manifest'), + add_conf_dirs=[ fixtures ] ) + + dryrun = cdist.config.Config(drylocal, self.remote, dry_run=True) + dryrun.run() + # if we are here, dryrun works like expected + + +# Currently the resolving code will simply detect that this object does +# not exist. It should probably check if the type is a singleton as well +# - but maybe only in the emulator - to be discussed. +# +# def test_requirement_no_singleton_where_singleton(self): +# """Missing object id should be detected in the resolving process""" +# first = self.object_index['__first/man'] +# first.requirements = ['__singleton_test/foo'] +# with self.assertRaises(cdist.core.?????): +# self.config.iterate_until_finished() diff --git a/cdist/test/config/fixtures/manifest/dryrun_manifest b/cdist/test/config/fixtures/manifest/dryrun_manifest new file mode 100644 index 00000000..53bb9aa5 --- /dev/null +++ b/cdist/test/config/fixtures/manifest/dryrun_manifest @@ -0,0 +1 @@ +__dryrun_test testit diff --git a/cdist/test/resolver/fixtures/object/__first/man/.cdist/.keep b/cdist/test/config/fixtures/object/__first/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__first/man/.cdist/.keep rename to cdist/test/config/fixtures/object/__first/.keep diff --git a/cdist/test/resolver/fixtures/object/__first/woman/.cdist/.keep b/cdist/test/config/fixtures/object/__first/man/.cdist/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__first/woman/.cdist/.keep rename to cdist/test/config/fixtures/object/__first/man/.cdist/.keep diff --git a/cdist/test/resolver/fixtures/object/__second/.keep b/cdist/test/config/fixtures/object/__second/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__second/.keep rename to cdist/test/config/fixtures/object/__second/.keep diff --git a/cdist/test/resolver/fixtures/object/__second/on-the/.cdist/.keep b/cdist/test/config/fixtures/object/__second/on-the/.cdist/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__second/on-the/.cdist/.keep rename to cdist/test/config/fixtures/object/__second/on-the/.cdist/.keep diff --git a/cdist/test/resolver/fixtures/object/__second/under-the/.cdist/.keep b/cdist/test/config/fixtures/object/__third/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__second/under-the/.cdist/.keep rename to cdist/test/config/fixtures/object/__third/.keep diff --git a/cdist/test/resolver/fixtures/object/__third/.keep b/cdist/test/config/fixtures/object/__third/moon/.cdist/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__third/.keep rename to cdist/test/config/fixtures/object/__third/moon/.cdist/.keep diff --git a/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name b/cdist/test/config/fixtures/object/__third/moon/.cdist/parameter/name similarity index 100% rename from cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name rename to cdist/test/config/fixtures/object/__third/moon/.cdist/parameter/name diff --git a/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet b/cdist/test/config/fixtures/object/__third/moon/.cdist/parameter/planet similarity index 100% rename from cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet rename to cdist/test/config/fixtures/object/__third/moon/.cdist/parameter/planet diff --git a/cdist/test/resolver/fixtures/object/__third/moon/.cdist/.keep b/cdist/test/config/fixtures/type/__dryrun_test/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__third/moon/.cdist/.keep rename to cdist/test/config/fixtures/type/__dryrun_test/.keep diff --git a/cdist/test/config/fixtures/type/__dryrun_test/gencode-local b/cdist/test/config/fixtures/type/__dryrun_test/gencode-local new file mode 100644 index 00000000..ccd584bd --- /dev/null +++ b/cdist/test/config/fixtures/type/__dryrun_test/gencode-local @@ -0,0 +1,3 @@ +# this type is only for testing the dryrun feature, it does nothing usefull +echo 'echo "This gencode-local script should never be executed >&2"' +echo 'exit 1' diff --git a/cdist/test/config/fixtures/type/__dryrun_test/gencode-remote b/cdist/test/config/fixtures/type/__dryrun_test/gencode-remote new file mode 100644 index 00000000..e57e4e27 --- /dev/null +++ b/cdist/test/config/fixtures/type/__dryrun_test/gencode-remote @@ -0,0 +1,3 @@ +# this type is only for testing the dryrun feature, it does nothing usefull +echo 'echo "this gencode-remote script should never be executed >&2"' +echo 'exit 1' diff --git a/cdist/test/resolver/fixtures/type/__first/.keep b/cdist/test/config/fixtures/type/__first/.keep similarity index 100% rename from cdist/test/resolver/fixtures/type/__first/.keep rename to cdist/test/config/fixtures/type/__first/.keep diff --git a/cdist/test/resolver/fixtures/type/__second/.keep b/cdist/test/config/fixtures/type/__second/.keep similarity index 100% rename from cdist/test/resolver/fixtures/type/__second/.keep rename to cdist/test/config/fixtures/type/__second/.keep diff --git a/cdist/test/resolver/fixtures/type/__third/.keep b/cdist/test/config/fixtures/type/__singleton_test/singleton similarity index 100% rename from cdist/test/resolver/fixtures/type/__third/.keep rename to cdist/test/config/fixtures/type/__singleton_test/singleton diff --git a/cdist/test/type/fixtures/__name_path/.keep b/cdist/test/config/fixtures/type/__third/.keep similarity index 100% rename from cdist/test/type/fixtures/__name_path/.keep rename to cdist/test/config/fixtures/type/__third/.keep diff --git a/cdist/test/config_install/__init__.py b/cdist/test/config_install/__init__.py deleted file mode 100644 index 2abf7614..00000000 --- a/cdist/test/config_install/__init__.py +++ /dev/null @@ -1,119 +0,0 @@ -# -*- coding: utf-8 -*- -# -# 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 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 . -# -# - -import os -import shutil - -from cdist import test -from cdist import core - -import cdist -import cdist.context -import cdist.config - -import os.path as op -my_dir = op.abspath(op.dirname(__file__)) -fixtures = op.join(my_dir, 'fixtures') -object_base_path = op.join(fixtures, 'object') -type_base_path = op.join(fixtures, 'type') -add_conf_dir = op.join(fixtures, 'conf') - -class ConfigInstallRunTestCase(test.CdistTestCase): - - def setUp(self): - - # Change env for context - self.orig_environ = os.environ - os.environ = os.environ.copy() - self.temp_dir = self.mkdtemp() - - self.out_dir = os.path.join(self.temp_dir, "out") - self.remote_out_dir = os.path.join(self.temp_dir, "remote") - - os.environ['__cdist_out_dir'] = self.out_dir - os.environ['__cdist_remote_out_dir'] = self.remote_out_dir - - self.context = cdist.context.Context( - target_host=self.target_host, - remote_copy=self.remote_copy, - remote_exec=self.remote_exec, - exec_path=test.cdist_exec_path, - debug=True) - - self.context.local.object_path = object_base_path - self.context.local.type_path = type_base_path - - self.config = cdist.config.Config(self.context) - - 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_names = [o.name for o in self.objects] - - def tearDown(self): - for o in self.objects: - o.requirements = [] - o.state = "" - - os.environ = self.orig_environ - shutil.rmtree(self.temp_dir) - - def test_dependency_resolution(self): - first = self.object_index['__first/man'] - second = self.object_index['__second/on-the'] - third = self.object_index['__third/moon'] - - first.requirements = [second.name] - second.requirements = [third.name] - - # First run: - # solves first and maybe second (depending on the order in the set) - self.config.stage_run_iterate() - self.assertTrue(third.state == third.STATE_DONE) - - self.config.stage_run_iterate() - self.assertTrue(second.state == second.STATE_DONE) - - - try: - self.config.stage_run_iterate() - except cdist.Error: - # Allow failing, because the third run may or may not be unecessary already, - # depending on the order of the objects - pass - self.assertTrue(first.state == first.STATE_DONE) - - def test_unresolvable_requirements(self): - """Ensure an exception is thrown for unresolvable depedencies""" - - # Create to objects depending on each other - no solution possible - first = self.object_index['__first/man'] - second = self.object_index['__second/on-the'] - - first.requirements = [second.name] - second.requirements = [first.name] - - # First round solves __third/moon - self.config.stage_run_iterate() - - # Second round detects it cannot solve the rest - with self.assertRaises(cdist.Error): - self.config.stage_run_iterate() diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index fc0b6695..870d6245 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -33,7 +34,6 @@ from cdist.exec import local from cdist import emulator from cdist import core from cdist import config -import cdist.context import os.path as op my_dir = op.abspath(op.dirname(__file__)) @@ -46,11 +46,11 @@ class EmulatorTestCase(test.CdistTestCase): self.temp_dir = self.mkdtemp() handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) - out_path = self.temp_dir + base_path = self.temp_dir self.local = local.Local( target_host=self.target_host, - out_path=out_path, + base_path=base_path, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -63,13 +63,13 @@ class EmulatorTestCase(test.CdistTestCase): def test_nonexistent_type_exec(self): argv = ['__does-not-exist'] - self.assertRaises(core.NoSuchTypeError, emulator.Emulator, argv, env=self.env) + self.assertRaises(core.cdist_type.NoSuchTypeError, emulator.Emulator, argv, env=self.env) def test_nonexistent_type_requirement(self): argv = ['__file', '/tmp/foobar'] self.env['require'] = '__does-not-exist/some-id' emu = emulator.Emulator(argv, env=self.env) - self.assertRaises(core.NoSuchTypeError, emu.run) + self.assertRaises(core.cdist_type.NoSuchTypeError, emu.run) def test_illegal_object_id_requirement(self): argv = ['__file', '/tmp/foobar'] @@ -81,7 +81,14 @@ class EmulatorTestCase(test.CdistTestCase): argv = ['__file', '/tmp/foobar'] self.env['require'] = '__file' emu = emulator.Emulator(argv, env=self.env) - self.assertRaises(core.IllegalObjectIdError, emu.run) + self.assertRaises(core.cdist_object.MissingObjectIdError, emu.run) + + def test_no_singleton_no_requirement(self): + argv = ['__file', '/tmp/foobar'] + self.env['require'] = '__test_singleton' + emu = emulator.Emulator(argv, env=self.env) + emu.run() + # If reached here, everything is fine def test_singleton_object_requirement(self): argv = ['__file', '/tmp/foobar'] @@ -96,16 +103,41 @@ class EmulatorTestCase(test.CdistTestCase): emu = emulator.Emulator(argv, env=self.env) # if we get here all is fine + def test_requirement_via_order_dependency(self): + self.env['CDIST_ORDER_DEPENDENCY'] = 'on' + argv = ['__planet', 'erde'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__planet', 'mars'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + # In real world, this is not shared over instances + del self.env['require'] + argv = ['__file', '/tmp/cdisttest'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + # now load the objects and verify the require parameter of the objects + cdist_type = core.CdistType(self.local.type_path, '__planet') + erde_object = core.CdistObject(cdist_type, self.local.object_path, 'erde') + mars_object = core.CdistObject(cdist_type, self.local.object_path, 'mars') + cdist_type = core.CdistType(self.local.type_path, '__file') + file_object = core.CdistObject(cdist_type, self.local.object_path, '/tmp/cdisttest') + # now test the recorded requirements + self.assertTrue(len(erde_object.requirements) == 0) + self.assertEqual(list(mars_object.requirements), ['__planet/erde']) + self.assertEqual(list(file_object.requirements), ['__planet/mars']) + # if we get here all is fine + class AutoRequireEmulatorTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() - out_path = os.path.join(self.temp_dir, "out") + base_path = os.path.join(self.temp_dir, "out") self.local = local.Local( target_host=self.target_host, - out_path=out_path, + base_path=base_path, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -118,23 +150,61 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): initial_manifest = os.path.join(self.local.manifest_path, "init") self.manifest.run_initial_manifest(initial_manifest) cdist_type = core.CdistType(self.local.type_path, '__saturn') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'singleton') + cdist_object = core.CdistObject(cdist_type, self.local.object_path) self.manifest.run_type_manifest(cdist_object) expected = ['__planet/Saturn', '__moon/Prometheus'] self.assertEqual(sorted(cdist_object.autorequire), sorted(expected)) +class OverrideTestCase(test.CdistTestCase): + + def setUp(self): + self.temp_dir = self.mkdtemp() + handle, self.script = self.mkstemp(dir=self.temp_dir) + os.close(handle) + base_path = self.temp_dir + + self.local = local.Local( + target_host=self.target_host, + base_path=base_path, + exec_path=test.cdist_exec_path, + add_conf_dirs=[conf_dir]) + self.local.create_files_dirs() + + self.manifest = core.Manifest(self.target_host, self.local) + self.env = self.manifest.env_initial_manifest(self.script) + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_override_negative(self): + argv = ['__file', '/tmp/foobar'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__file', '/tmp/foobar','--mode','404'] + emu = emulator.Emulator(argv, env=self.env) + self.assertRaises(cdist.Error, emu.run) + + def test_override_feature(self): + argv = ['__file', '/tmp/foobar'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__file', '/tmp/foobar','--mode','404'] + self.env['CDIST_OVERRIDE'] = 'on' + emu = emulator.Emulator(argv, env=self.env) + emu.run() + class ArgumentsTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() - out_path = self.temp_dir + base_path = self.temp_dir handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) self.local = local.Local( target_host=self.target_host, - out_path=out_path, + base_path=base_path, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -170,11 +240,13 @@ class ArgumentsTestCase(test.CdistTestCase): # empty file -> True self.assertTrue(cdist_object.parameters['boolean1'] == '') - def test_required(self): + def test_required_arguments(self): + """check whether assigning required parameter works""" type_name = '__arguments_required' object_id = 'some-id' value = 'some value' argv = [type_name, object_id, '--required1', value, '--required2', value] +# print(self.env) os.environ.update(self.env) emu = emulator.Emulator(argv) emu.run() @@ -211,6 +283,21 @@ class ArgumentsTestCase(test.CdistTestCase): self.assertFalse('optional2' in cdist_object.parameters) self.assertEqual(cdist_object.parameters['optional1'], value) + def test_argument_defaults(self): + type_name = '__argument_defaults' + object_id = 'some-id' + value = 'value1' + argv = [type_name, object_id] + os.environ.update(self.env) + emu = emulator.Emulator(argv) + emu.run() + + cdist_type = core.CdistType(self.local.type_path, type_name) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, object_id) + self.assertTrue('optional1' in cdist_object.parameters) + self.assertFalse('optional2' in cdist_object.parameters) + self.assertEqual(cdist_object.parameters['optional1'], value) + class StdinTestCase(test.CdistTestCase): @@ -219,11 +306,11 @@ class StdinTestCase(test.CdistTestCase): os.environ = os.environ.copy() self.temp_dir = self.mkdtemp() - out_path = os.path.join(self.temp_dir, "out") + base_path = os.path.join(self.temp_dir, "out") self.local = local.Local( target_host=self.target_host, - out_path=out_path, + base_path=base_path, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) diff --git a/cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/default/optional1 b/cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/default/optional1 new file mode 100644 index 00000000..ef208405 --- /dev/null +++ b/cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/default/optional1 @@ -0,0 +1 @@ +value1 diff --git a/cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/optional b/cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/optional new file mode 100644 index 00000000..8174d2a9 --- /dev/null +++ b/cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/optional @@ -0,0 +1,2 @@ +optional1 +optional2 diff --git a/cdist/test/type/fixtures/__not_install/.keep b/cdist/test/emulator/fixtures/conf/type/__test_singleton/singleton similarity index 100% rename from cdist/test/type/fixtures/__not_install/.keep rename to cdist/test/emulator/fixtures/conf/type/__test_singleton/singleton diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index a97b538a..92ef75a3 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -39,26 +39,25 @@ conf_dir = op.join(fixtures, "conf") class ExplorerClassTestCase(test.CdistTestCase): def setUp(self): - self.target_host = 'localhost' - - self.temp_dir = self.mkdtemp() - self.out_path = os.path.join(self.temp_dir, "out") - self.remote_base_path = os.path.join(self.temp_dir, "remote") + self.temp_dir = self.mkdtemp() + self.local_path = os.path.join(self.temp_dir, "local") + self.remote_base_path = os.path.join(self.temp_dir, "remote") os.makedirs(self.remote_base_path) self.local = local.Local( target_host=self.target_host, - out_path=self.out_path, + base_path=self.local_path, exec_path=test.cdist_exec_path, - add_conf_dirs=[conf_dir]) + add_conf_dirs=[conf_dir], + ) self.local.create_files_dirs() self.remote = remote.Remote( - self.target_host, - self.remote_base_path, - self.remote_exec, - self.remote_copy) + target_host=self.target_host, + remote_exec=self.remote_exec, + remote_copy=self.remote_copy, + base_path=self.remote_base_path) self.remote.create_files_dirs() self.explorer = explorer.Explorer( @@ -70,11 +69,13 @@ class ExplorerClassTestCase(test.CdistTestCase): shutil.rmtree(self.temp_dir) def test_list_global_explorer_names(self): + """Ensure that all explorers are listed""" names = self.explorer.list_global_explorer_names() self.assertIn("foobar", names) self.assertIn("global", names) def test_transfer_global_explorers(self): + """Ensure transferring explorers to remote works""" self.explorer.transfer_global_explorers() source = self.local.global_explorer_path destination = self.remote.global_explorer_path @@ -86,7 +87,7 @@ class ExplorerClassTestCase(test.CdistTestCase): output = self.explorer.run_global_explorer('global') self.assertEqual(output, 'global\n') - def test_run_global_explorers(self): + def test_global_explorer_output(self): """Ensure output is created for every global explorer""" out_path = self.mkdtemp() @@ -103,6 +104,7 @@ class ExplorerClassTestCase(test.CdistTestCase): self.assertEqual(self.explorer.list_type_explorer_names(cdist_type), expected) def test_transfer_type_explorers(self): + """Test if transferring type explorers works""" cdist_type = core.CdistType(self.local.type_path, '__test_type') self.explorer.transfer_type_explorers(cdist_type) source = os.path.join(self.local.type_path, cdist_type.explorer_path) diff --git a/cdist/test/fixtures/remote b/cdist/test/fixtures/remote deleted file mode 120000 index c5db6358..00000000 --- a/cdist/test/fixtures/remote +++ /dev/null @@ -1 +0,0 @@ -../../../other/examples/remote/local \ No newline at end of file diff --git a/cdist/test/fixtures/remote/README b/cdist/test/fixtures/remote/README new file mode 100644 index 00000000..cfd350f9 --- /dev/null +++ b/cdist/test/fixtures/remote/README @@ -0,0 +1,3 @@ +This effectively turns remote calling into local calling. + +Probably most useful for the unittesting. diff --git a/cdist/test/fixtures/remote/copy b/cdist/test/fixtures/remote/copy new file mode 100755 index 00000000..05f43eb1 --- /dev/null +++ b/cdist/test/fixtures/remote/copy @@ -0,0 +1,23 @@ +#!/bin/sh +# +# 2012-2013 Nico Schottelius (nico-cdist schottelius.org) +# 2013-2014 Steven Armstrong (steven-cdist 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 . +# + +code="$(echo "$@" | sed "s|\([[:space:]]\)$__target_host:|\1|g")" +cp -L $code diff --git a/cdist/test/fixtures/remote/exec b/cdist/test/fixtures/remote/exec new file mode 100755 index 00000000..838513a9 --- /dev/null +++ b/cdist/test/fixtures/remote/exec @@ -0,0 +1,23 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist 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 . +# +# + +target_host=$1; shift +echo "$@" | /bin/sh diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index 727017e7..c375a80f 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -46,11 +46,11 @@ class ManifestTestCase(test.CdistTestCase): self.orig_environ = os.environ os.environ = os.environ.copy() self.temp_dir = self.mkdtemp() - self.target_host = 'localhost' + out_path = self.temp_dir self.local = local.Local( target_host=self.target_host, - out_path=out_path, + base_path=out_path, exec_path = cdist.test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -78,7 +78,7 @@ class ManifestTestCase(test.CdistTestCase): output_dict[key] = value self.assertTrue(output_dict['PATH'].startswith(self.local.bin_path)) self.assertEqual(output_dict['__target_host'], self.local.target_host) - self.assertEqual(output_dict['__global'], self.local.out_path) + self.assertEqual(output_dict['__global'], self.local.base_path) self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) self.assertEqual(output_dict['__manifest'], self.local.manifest_path) @@ -99,7 +99,7 @@ class ManifestTestCase(test.CdistTestCase): output_dict[key] = value self.assertTrue(output_dict['PATH'].startswith(self.local.bin_path)) self.assertEqual(output_dict['__target_host'], self.local.target_host) - self.assertEqual(output_dict['__global'], self.local.out_path) + self.assertEqual(output_dict['__global'], self.local.base_path) self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) self.assertEqual(output_dict['__type'], cdist_type.absolute_path) self.assertEqual(output_dict['__object'], cdist_object.absolute_path) diff --git a/cdist/test/message/__init__.py b/cdist/test/message/__init__.py new file mode 100644 index 00000000..653847f1 --- /dev/null +++ b/cdist/test/message/__init__.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +# +# 2013 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 . +# +# + +import os +import tempfile + +from cdist import test +import cdist.message + +class MessageTestCase(test.CdistTestCase): + + def setUp(self): + self.prefix="cdist-test" + self.content = "A very short story" + self.tempfile = tempfile.mkstemp()[1] + self.message = cdist.message.Message(prefix=self.prefix, + messages=self.tempfile) + + def tearDown(self): + os.remove(self.tempfile) + self.message._cleanup() + + def test_env(self): + """ + Ensure environment is correct + """ + + env = self.message.env + + self.assertIn('__messages_in', env) + self.assertIn('__messages_out', env) + + + def test_copy_content(self): + """ + Ensure content copying is working + """ + + with open(self.tempfile, "w") as fd: + fd.write(self.content) + + self.message._copy_messages() + + with open(self.tempfile, "r") as fd: + testcontent = fd.read() + + self.assertEqual(self.content, testcontent) + + def test_message_merge_prefix(self): + """Ensure messages are merged and are prefixed""" + + expectedcontent = "%s:%s" % (self.prefix, self.content) + + out = self.message.env['__messages_out'] + + with open(out, "w") as fd: + fd.write(self.content) + + self.message._merge_messages() + + with open(self.tempfile, "r") as fd: + testcontent = fd.read() + + self.assertEqual(expectedcontent, testcontent) diff --git a/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name b/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name deleted file mode 100644 index 4129a761..00000000 --- a/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name +++ /dev/null @@ -1 +0,0 @@ -Prometheus diff --git a/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet b/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet deleted file mode 100644 index 8e6ee422..00000000 --- a/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet +++ /dev/null @@ -1 +0,0 @@ -Saturn diff --git a/cdist/test/type/fixtures/__not_singleton/.keep b/cdist/test/type/fixtures/__not_singleton/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/__without_boolean_parameters/.keep b/cdist/test/type/fixtures/__without_boolean_parameters/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/__without_explorers/.keep b/cdist/test/type/fixtures/__without_explorers/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/__without_optional_parameters/.keep b/cdist/test/type/fixtures/__without_optional_parameters/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/__without_required_parameters/.keep b/cdist/test/type/fixtures/__without_required_parameters/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/list_types/__first/.keep b/cdist/test/type/fixtures/list_types/__first/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/list_types/__second/.keep b/cdist/test/type/fixtures/list_types/__second/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/list_types/__third/.keep b/cdist/test/type/fixtures/list_types/__third/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/util/fsproperty.py b/cdist/util/fsproperty.py index 5814b2b4..49d4a32d 100644 --- a/cdist/util/fsproperty.py +++ b/cdist/util/fsproperty.py @@ -134,7 +134,11 @@ class DirectoryDict(collections.MutableMapping): def __setitem__(self, key, value): try: with open(os.path.join(self.path, key), "w") as fd: - if type(value) == type([]): + if (not hasattr(value, 'strip') and + (hasattr(value, '__getitem__') or + hasattr(value, '__iter__'))): + # if it looks like a sequence and quacks like a sequence, + # it is a sequence for v in value: fd.write(str(v) + '\n') else: diff --git a/docs/changelog b/docs/changelog index 12baa1a2..e8f98c01 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,9 +4,198 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -next: - * Type __jail: State absent should implies stopped (Jake Guffey) + +3.0.9: 2014-02-14 + * Core: Ignore order dependencies if override is set (Daniel Heule) + * Core: Improve Mac OS X support for unit tests (Steven Armstrong) + * Type __locale: Error out in case of unsupported OS + * Type __jail: Use default parameters for state (Daniel Heule) + * Type __pf_ruleset: Use default parameters for state (Daniel Heule) + * Type __postgres_database: Use default parameters for state (Daniel Heule) + * Type __postgres_role: Use default parameters for state (Daniel Heule) + * Type __rvm: Use default parameters for state (Daniel Heule) + * Type __rvm_gem: Use default parameters for state (Daniel Heule) + * Type __rvm_gemset: Use default parameters for state (Daniel Heule) + * Type __rvm_ruby: Use default parameters for state (Daniel Heule) + + +3.0.8: 2014-02-11 + * Core: Enhance object id verification (Daniel Heule) + * Core: Add unit tests for dependencies based on execution order (Daniel Heule) + * Core: Add unit tests for dry run (Daniel Heule) + +3.0.7: 2014-02-08 + * Core: Allow dependencies to be created based execution order (Daniel Heule) + * Core: Add tests for override (Daniel Heule) + +3.0.6: 2014-02-06 + * New Type: __apt_key (Steven Armstrong) + * New Type: __apt_key_uri (Steven Armstrong) + * New Type: __apt_norecommends (Steven Armstrong) + * New Type: __apt_source (Steven Armstrong) + * New Type: __ccollect_source + * Type __git: Use default parameters (Daniel Heule) + * Type __jail: Use default parameters (Daniel Heule) + * Type __package_yum: Use default parameters (Daniel Heule) + * Type __package_zypper: Use default parameters (Daniel Heule) + * Type __user_groups: Use default parameters (Daniel Heule) + +3.0.5: 2014-02-05 + * Core: Introduce override concept (Daniel Heule) + * Type __process: Make --state absent work (Steven Armstrong) + * Documentation: Update documentation for environment variables + +3.0.4: 2014-01-29 + * Core: Ignore install types in config mode + * Documentation: Update reference (files path in object space) + * Documentation: Update best practise: Replaces templates/ with files/ + * Type __apt_ppa: Install required software (Steven Armstrong) + * Type __debconf_set_selections: Support --file - to read from stdin + * Type __jail: Fix jaildir parameter handling (Jake Guffey) + +3.0.3: 2014-01-22 + * Core: Enhance error message when requirement is missing object id + * Core: Add environment variable to select shell for executing scripts (Daniel Heule) + * Explorer hostname: Return host name by using uname -n + * New Type: __hostname (Steven Armstrong) + * Type __cdist: Use default paremeters (Daniel Heule) + * Type __key_value: Use default paremeters (Daniel Heule) + * Type __line: Use printf instead of echo for printing user input + * Type __qemu_img: Use default paremeters (Daniel Heule) + * Type __zypper_repo: Use default paremeters (Daniel Heule) + * Type __zypper_service: Use default paremeters (Daniel Heule) + +3.0.2: 2014-01-19 + * Documentation: Document all messages sent by types (Daniel Heule) + * New Type: __block (Steven Armstrong) + * New Type: __mount (Steven Armstrong) + * Type __cron: Replace existing entry when changing it (Daniel Heule) + * Type __ssh_authorized_keys: Use new type __block (Steven Armstrong) + +3.0.1: 2014-01-14 + * Core: Copy only files, not directories (Steven Armstrong) + * Core: Allow hostnames to start with / + * Type __line: Remove unecessary backslash escape + * Type __directory: Add messaging support (Daniel Heule) + * Type __directory: Do not generate code if mode is 0xxx (Daniel Heule) + * Type __package: Fix typo in optional parameter ptype (Daniel Heule) + * Type __start_on_boot: Fix for SuSE's chkconfig (Daniel Heule) + +3.0.0: 2013-12-24 + * Core: Added messaging support + * Core: Removed unused "changed" attribute of objects + * Core: Support default values for multiple parameters (Steven Armstrong) + * Core: Ensure Object Parameter file contains \n (Steven Armstrong) + * New Type: __zypper_repo (Daniel Heule) + * New Type: __zypper_service (Daniel Heule) + * New Type: __package_emerge (Daniel Heule) + * New Type: __package_emerge_dependencies (Daniel Heule) + * Type __cron: Add support for raw lines (Daniel Heule) + * Type __cron: Suppress stderr output from crontab (Daniel Heule) + * Type __cron: Fix quoting issue (Daniel Heule) + * Type __file: Do not generate code if mode is 0xxx + * Type __iptables_rule: Use default parameter + * Type __key_value: Fix quoting issue (Steven Armstrong) + * Type __package: Use state --present by default (Steven Armstrong) + * Type __package_zypper: Support non packages as well (Daniel Heule) + * Type __package_zypper: Support package versions (Daniel Heule) + * Type __postfix_*: Depend on __postfix Type (Steven Armstrong) + * Type __postfix_postconf: Enable support for SuSE (Daniel Heule) + * Type __postfix: Enable support for SuSE (Daniel Heule) + * Type __start_on_boot: Use default parameter state + * Type __start_on_boot: Add support for gentoo (Daniel Heule) + * Type __user: Add support for state parameter (Daniel Heule) + * Type __user: Add support for system users (Daniel Heule) + * Type __user: Add messaging support (Steven Armstrong) + * Type __zypper_service: Support older SuSE releases (Daniel Heule) + +2.3.7: 2013-12-02 + * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) + * Type __file: Only remove file when state is absent (Steven Armstrong) + * Type __link: Only remove link when state is absent (Steven Armstrong) + * Type __directory: Only remove directory when state is absent (Steven Armstrong) + * Type __directory: Fix newly introduced quoting issue + * Type __package_zypper: Fix explorer and parameter issue (Daniel Heule) + * Core: Fix backtrace when cache cannot be deleted + +2.3.6: 2013-11-25 + * New Type: __locale + * Type __line: Ensure special characters are not interpreted + +2.3.5: 2013-10-10 + * Core: Unit test fix for remote_copy (Steven Armstrong) + * Documentation: Updated manpages of __package and __file (Alex Greif) + * Documentation: Add more examples to cdist-manifest (Dan Levin) + * Type __package_apt: Do not install recommends by default + +2.3.4: 2013-10-03 + * Core: Add missing bits to support dry run (Steven Armstrong) + * Core: Make unit test remote copy more compatible with scp (Steven Armstrong) + * New Type: __postfix (Steven Armstrong) + * New Type: __postfix_master (Steven Armstrong) + * New Type: __postfix_postconf (Steven Armstrong) + * New Type: __postfix_postmap (Steven Armstrong) + * New Type: __postfix_reload (Steven Armstrong) + * Type __line: Ensure regex does not contain / + * Type __ssh_authorized_keys: Bugfix: Preserve ownership (Steven Armstrong) + +2.3.3: 2013-09-09 + * Core: Add support for default values of optional parameters (Steven Armstrong) + * Type __start_on_boot: Bugfix for systemd (Steven Armstrong) + +2.3.2: 2013-09-05 + * Build: Ensure tests don't change attributes of non-test files + * Core: Fix typo in argument parser + * Core: Code cleanup: Remove old install code (Steven Armstrong) + * Core: Improve error message when using non-existing type in requirement + * New Type: __iptables_rule + * New Type: __iptables_apply + * Type __cdist: Also create home directory + * Type __cdist: Add support for --shell parameter + * Type __motd: Regenerate motd on Debian and Ubuntu + +2.3.1: 2013-08-28 + * Core: Support relative paths for configuration directories + * Core: Code cleanup (removed context class, added log class) + * Documentation: Add more best practises + * Documentation: Add troubleshooting chapter + * Type __key_value: Fix quoting problem (Steven Armstrong) + +2.3.0: 2013-08-12 + * Core: Added support for cdist shell + * Documentation: Improved some manpages + +2.2.0: 2013-07-12 + * Build: Cleanup the Makefile + * Type __package_opkg: Use shortcut version + * Core: Remove old pseudo object id "singleton" (Steven Armstrong) + +2.1.2: 2013-07-09 + * Build: Change clean-dist target to "distclean" + * Build: Moved a lot of build logic into Makefile for dependency resolution + * Core: Make global explorers available to initial manifest (Arkaitz Jimenez) + * Core: Change execution order to run object as one unit + * Documentation: Improved documentation (Tomáš Pospíšek) + * New Remote Example: Add support for sudo operations (Chase James) + * New Type: __update_alternatives + * New Type: __cdist + * Type __apt_ppa: Fix comparison operator (Tyler Akins) + * Type __start_on_boot: Archlinux changed to use systemd - adapt type + * Type __git: Missing quotes added (Chase James) + * Type __postgres_database: Make state parameter optional (Chase James) + * Type __postgres_role: Make state parameter optional, fix password bug (Chase James) + * Type __process: Make state parameter optional + * Type __cron: Simplyfied and syntax change + +2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies + * Core: Remove umask call - protect /var/lib/cdist only (Arkaitz Jimenez) + * Explorer os: Added Slackware support (Eivind Uggedal) + * Type __git: Support mode and fix owner/group settings (contradict) + * Type __jail: State absent should implies stopped (Jake Guffey) + * Type __directory: Make stat call compatible with FreeBSD (Jake Guffey) + * Type __cron: Allow crontab without entries (Arkaitz Jimenez) + * Type __user: Add support for creating user home (Arkaitz Jimenez) 2.1.0: 2012-12-09 * Core: Ensure global explorers are executable diff --git a/docs/dev/factsheet.odt b/docs/dev/factsheet.odt new file mode 100644 index 00000000..2bb2a84b Binary files /dev/null and b/docs/dev/factsheet.odt differ diff --git a/docs/dev/factsheet.pdf b/docs/dev/factsheet.pdf new file mode 100644 index 00000000..c59a1a6f Binary files /dev/null and b/docs/dev/factsheet.pdf differ diff --git a/docs/dev/logs/2011-11-16.workflow-example.dia b/docs/dev/logs/2011-11-16.workflow-example.dia new file mode 100644 index 00000000..8dab4a2c Binary files /dev/null and b/docs/dev/logs/2011-11-16.workflow-example.dia differ diff --git a/docs/dev/logs/2011-11-16.workflow-example.png b/docs/dev/logs/2011-11-16.workflow-example.png new file mode 100644 index 00000000..07a0f126 Binary files /dev/null and b/docs/dev/logs/2011-11-16.workflow-example.png differ diff --git a/docs/dev/logs/2011-11-17.workflow-example.dia b/docs/dev/logs/2011-11-17.workflow-example.dia new file mode 100644 index 00000000..7a9cd0f7 Binary files /dev/null and b/docs/dev/logs/2011-11-17.workflow-example.dia differ diff --git a/docs/dev/logs/2012-05-24.preos b/docs/dev/logs/2012-05-24.preos new file mode 100644 index 00000000..e4f988a7 --- /dev/null +++ b/docs/dev/logs/2012-05-24.preos @@ -0,0 +1,72 @@ +Todo for preos: + +get debian installer (?) + x86, amd64 +configure sshd + add authorized_keys +output files + tftp: cuni: curl -s "http://http.us.debian.org/debian/dists/$version/main/installer-$arch/current/images/netboot/netboot.tar.gz" | tar xz + iso + + +http://wiki.debian.org/DebianInstaller/ +-------------------------------------------------------------------------------- +debootstrap: + [19:33] brief:hack% sudo debootstrap squeeze ./debian-squeeze + [19:30] brief:hack# du -sh . + 213M . + +install kernel + [19:35] brief:hack# chroot debian-squeeze/ apt-get -y install linux-image-amd64 + [19:37] brief:debian-squeeze# ls boot/initrd* + boot/initrd.img-2.6.32-5-amd64 + [19:37] brief:debian-squeeze# ls boot/vmlinuz* + boot/vmlinuz-2.6.32-5-amd64 + +install sshd + [19:37] brief:hack# chroot debian-squeeze/ apt-get -y --force-yes install openssh-server + + - connect back? + - generate sshd keys? + +-------------------------------------------------------------------------------- +initramfs: + find . -print0 | bsdcpio $( (( QUIET )) && echo '--quiet' ) -R 0:0 -0oH newc | $COMPRESSION $COMPRESSION_OPTIONS > "$IMGPATH" + + /init for booting + find . -print0 | cpio --null -ov --format=newc | gzip -9 > /boot/my-initramfs.cpio.gz + cpio -H newc -o + find . | cpio -H newc -o > ../initramfs.cpio # <-- this is the actual initramfs + + +[19:39] brief:debian-squeeze# find . | bsdcpio -H newc -o > ../initramfs.cpio +[19:43] brief:debian-squeeze# xz ../initramfs.cpio + + +-------------------------------------------------------------------------------- +cdrom: + http://tldp.org/HOWTO/Bootdisk-HOWTO/cd-roms.html + +-------------------------------------------------------------------------------- + +[19:34] brief:hack# chroot debian-squeeze/ apt-cache search kernel | grep linux-image +linux-image-2.6.32-5-amd64-dbg - Debugging infos for Linux 2.6.32-5-amd64 +linux-image-2.6.32-5-amd64 - Linux 2.6.32 for 64-bit PCs +linux-image-2.6.32-5-openvz-amd64-dbg - Debugging infos for Linux 2.6.32-5-openvz-amd64 +linux-image-2.6.32-5-openvz-amd64 - Linux 2.6.32 for 64-bit PCs, OpenVZ support +linux-image-2.6.32-5-vserver-amd64-dbg - Debugging infos for Linux 2.6.32-5-vserver-amd64 +linux-image-2.6.32-5-vserver-amd64 - Linux 2.6.32 for 64-bit PCs, Linux-VServer support +linux-image-2.6.32-5-xen-amd64-dbg - Debugging infos for Linux 2.6.32-5-xen-amd64 +linux-image-2.6.32-5-xen-amd64 - Linux 2.6.32 for 64-bit PCs, Xen dom0 support +linux-image-2.6-amd64 - Linux 2.6 for 64-bit PCs (meta-package) +linux-image-2.6-openvz-amd64 - Linux 2.6 for 64-bit PCs (meta-package), OpenVZ support +linux-image-2.6-vserver-amd64 - Linux 2.6 for 64-bit PCs (meta-package), Linux-VServer support +linux-image-2.6-xen-amd64 - Linux 2.6 for 64-bit PCs (meta-package), Xen dom0 support +linux-image-amd64 - Linux for 64-bit PCs (meta-package) +linux-image-openvz-amd64 - Linux for 64-bit PCs (meta-package), OpenVZ support +linux-image-vserver-amd64 - Linux for 64-bit PCs (meta-package), Linux-VServer support +linux-image-xen-amd64 - Linux for 64-bit PCs (meta-package), Xen dom0 support +[19:34] brief:hack# + +-------------------------------------------------------------------------------- + diff --git a/docs/dev/logs/2012-09-03.dep-ideas.xoj b/docs/dev/logs/2012-09-03.dep-ideas.xoj new file mode 100644 index 00000000..b2ab927e Binary files /dev/null and b/docs/dev/logs/2012-09-03.dep-ideas.xoj differ diff --git a/docs/dev/logs/2012-11-02.cdist-vs-centralised-development.xoj b/docs/dev/logs/2012-11-02.cdist-vs-centralised-development.xoj new file mode 100644 index 00000000..56303893 Binary files /dev/null and b/docs/dev/logs/2012-11-02.cdist-vs-centralised-development.xoj differ diff --git a/docs/dev/logs/2012-11-15.cdist-sexy-interaction.svg b/docs/dev/logs/2012-11-15.cdist-sexy-interaction.svg new file mode 100644 index 00000000..788de83c --- /dev/null +++ b/docs/dev/logs/2012-11-15.cdist-sexy-interaction.svg @@ -0,0 +1,282 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + cdist + + + + configures hosts + + + + + sexy + + + + + + manages inventory + + + + + + installs hosts(missing) + + + + interact + + + + + + + + visualises inventory(missing) + + + + + + diff --git a/docs/dev/logs/2012-12-11.dependencies b/docs/dev/logs/2012-12-11.dependencies index e5506564..1c0adad8 100644 --- a/docs/dev/logs/2012-12-11.dependencies +++ b/docs/dev/logs/2012-12-11.dependencies @@ -8,28 +8,95 @@ __git bar __package git --state present -require="__git/foo" git bar: +require="__git/foo" __git bar: __git bar __git foo __package git --state present __package git --state present - __git foo - __package git --state present + __git foo <---| + __package git --state present ---| -> detects circular dependency +-------------------------------------------------------------------------------- + +require="__apt_repository/somewhere-where-you-can-find-package-git __git/foo" __git bar + + __git bar + __apt_repository somewhere-where-you-can-find-package-git + + __git foo + __package git --state present + __package_apt git depends nachher auf __apt_repository + __package git --state present + __git foo <---| + __package git --state present ---| + __apt_repository somewhere-where-you-can-find-package-git + +possible solutions: + - __package git does not depend on __git foo (clear dependency) + - because it DOES NOT depend on it! + - but we don't know whether this is always true :-/ + - multiple instances of __package git exist, with + - different required BY + - different requirements + - define non inheritent dependencies (?) + - because __git bar really depends only on __git foo + - proposal: introduce require_non_recursive and require_recursive (previously: require) + - recording the source of the dependency and use it to assist resolving (?) + __package git: + inherited require: __git foo von __git bar + __git foo: + inherited autorequire: __package git durch Nutzung + - break out circular references (?) + - if either of both parties is only locked by the other, allow execution of this one? + +-------------------------------------------------------------------------------- + +__package foo + __package_apt foo + +__package bar + __package_apt bar + +require="__package/foo" __package bar + + __package bar + __package foo + __package_apt foo + __package_apt bar + __package foo + -------------------------------------------------------------------------------- -__package abc - __package_apt abc +__type1 var1 + __type2 FIX -__sometype def - __package abc - __package_apt abc +__type1 var2 + __type2 FIX +-------------------------------------------------------------------------------- +facts: + - use is different from require="", as use makes USED depend on parent deps + - use = called/defined in the manifest of a type + - it is currently not recorded, where an object gained its requirements and autorequirements +-------------------------------------------------------------------------------- +requirements: + - a type should be a black box: + I can require an object and it is ensured, + everything it needs is executed before me. + +-------------------------------------------------------------------------------- +possible implementations +- requiring it should include everything it USES +-------------------------------------------------------------------------------- +solutions: + __type1 DEPENDS but does not use __type2 FIX + + -------------------------------------------------------------------------------- Change proposal: @@ -59,14 +126,14 @@ Order: For __package: -__sometype def - __package abc +__sometype bar + __package foo -__package abc - __package_apt abc +__package foo + __package_apt foo -1) __package_apt/abc (leaf node) +1) __package_apt/foo (leaf node) -2) __package/abc (new leaf node) +2) __package/foo (new leaf node) -3) __sometype/def (new leaf node) +3) __sometype/bar (new leaf node) diff --git a/docs/dev/logs/2013-01-03.dependencies-visualised.xoj b/docs/dev/logs/2013-01-03.dependencies-visualised.xoj new file mode 100644 index 00000000..715d2583 Binary files /dev/null and b/docs/dev/logs/2013-01-03.dependencies-visualised.xoj differ diff --git a/docs/dev/logs/2013-01-20.notifications b/docs/dev/logs/2013-01-20.notifications new file mode 100644 index 00000000..be326196 --- /dev/null +++ b/docs/dev/logs/2013-01-20.notifications @@ -0,0 +1,20 @@ +Allow cross-type communication + +Sending notifications is possible from + + - manifest + - gencode-local + - gencode-remote + +Sending a notification from an object means writing to the file "notifications" into +its object: + + echo mytest >> "$__object/notifications" # a type reports something + +Reading / Reacting on notifications works by accessing the file +referred to be "$__notifications". All notifications are prefixed with +the object name ($__object_name) and are appended into this file. + +To find out, whether a file was copied, run: + + grep __file/etc/passwd:copy "$__notifications" diff --git a/docs/dev/logs/2013-01-20.triggers b/docs/dev/logs/2013-01-20.triggers new file mode 100644 index 00000000..dc13c746 --- /dev/null +++ b/docs/dev/logs/2013-01-20.triggers @@ -0,0 +1,49 @@ +An alternative / complementary approach to notifications: triggers (or actions?) + +A type may support various actions by creating files in its subdirectory +"actions". Other types can trigger an action of a different type or object +by calling them (indirectly?): + + +if grep "__file/etc/nginx/conf.d/.*:copy" "$__notifications"; then + + # Call action from a type + cdist trigger __nginx/reload +fi + + +Not sure whether this approach (calling "actions" of other types) is sane, +as nginx should probably better know if it should be restarted "itself". + + +-------------------------------------------------------------------------------- + +Alternate approach: + +__nginx_vhost www.some-domain.ch --custom << eof +some custom code for __nginx_vhost inclusion +eof + +__nginx_vhost: + + manifest: + # __nginx_vhost requires __nginx: creates directories + + require"$__object_name" __nginx --require-only + + # Do WE or __file ... depend on nginx? + cdist require __nginx + + # Create file that contains the giving code + __file /etc/nginx/conf.d/www.some-domain.ch + + require="__nginx" __file /etc/nginx/conf.d/www.some-domain.ch + +__nginx: + manifest: + __package nginx --state present + + __file some-custom-files + + gencode-remote: + if first_install or file changed: diff --git a/docs/dev/logs/2013-02-05.debugging-wrong-singleton-type-parameter b/docs/dev/logs/2013-02-05.debugging-wrong-singleton-type-parameter new file mode 100644 index 00000000..5169b678 --- /dev/null +++ b/docs/dev/logs/2013-02-05.debugging-wrong-singleton-type-parameter @@ -0,0 +1,34 @@ +Traceback (most recent call last): + File "/home/users/nico/p/cdist/cdist/bin/../scripts/cdist", line 230, in + commandline() + File "/home/users/nico/p/cdist/cdist/bin/../scripts/cdist", line 104, in commandline + args.func(args) + File "/home/users/nico/p/cdist/cdist/bin/../scripts/cdist", line 107, in config + configinstall(args, mode=cdist.config.Config) + File "/home/users/nico/p/cdist/cdist/bin/../scripts/cdist", line 143, in configinstall + configinstall_onehost(host, args, mode, parallel=False) + File "/home/users/nico/p/cdist/cdist/bin/../scripts/cdist", line 180, in configinstall_onehost + c.deploy_and_cleanup() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/config_install.py", line 74, in deploy_and_cleanup + self.deploy_to() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/config_install.py", line 68, in deploy_to + self.stage_prepare() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/config_install.py", line 91, in stage_prepare + self.context.local.type_path): + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/core/cdist_object.py", line 80, in list_objects + yield cls(cdist.core.CdistType(type_base_path, type_name), object_base_path, object_id=object_id) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/core/cdist_object.py", line 65, in __init__ + self.validate_object_id() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/core/cdist_object.py", line 130, in validate_object_id + (self.cdist_type.name, self.parameters)) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/util/fsproperty.py", line 210, in __get__ + return self._get_attribute(instance, owner) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/util/fsproperty.py", line 202, in _get_attribute + path = self._get_path(instance) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/util/fsproperty.py", line 190, in _get_path + path = path(instance) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/core/cdist_object.py", line 192, in + parameters = fsproperty.DirectoryDictProperty(lambda obj: os.path.join(obj.base_path, obj.parameter_path)) +AttributeError: 'CdistObject' object has no attribute 'parameter_path' +[22:37] brief:~% + diff --git a/docs/dev/logs/2013-02-05.weird-notsingleton-type-error b/docs/dev/logs/2013-02-05.weird-notsingleton-type-error new file mode 100644 index 00000000..23693777 --- /dev/null +++ b/docs/dev/logs/2013-02-05.weird-notsingleton-type-error @@ -0,0 +1,15 @@ + +Hard to find the source bug/problem: + +DEBUG: solr.petspremium.de: (emulator) __file//etc/solr/solr.xml: Finished __file/etc/solr/solr.xml/.cdist {'mode': '0644', 'source': '/home/users/nico/.tmp/tmpn27s24/out/conf/type/__petspremium_solr/files/solr/solr.xml'} ++ for file in '$(find . -type f | sed '\''s,^./,,'\'')' ++ dfile=/etc/solr/web.xml ++ reqdir=/etc/solr ++ require=__directory/etc/solr ++ __file /etc/solr/web.xml --source /home/users/nico/.tmp/tmpn27s24/out/conf/type/__petspremium_solr/files/solr/web.xml --mode 0644 +DEBUG: solr.petspremium.de: (emulator): /home/users/nico/.tmp/tmpn27s24/out/bin/__file: Namespace(mode='0644', object_id=['/etc/solr/web.xml'], source='/home/users/nico/.tmp/tmpn27s24/out/conf/type/__petspremium_solr/files/solr/web.xml') +DEBUG: solr.petspremium.de: (emulator) __file//etc/solr/web.xml: Recording requirement: __directory/etc/solr +DEBUG: solr.petspremium.de: (emulator) __file//etc/solr/web.xml: Finished __file/etc/solr/web.xml/.cdist {'source': '/home/users/nico/.tmp/tmpn27s24/out/conf/type/__petspremium_solr/files/solr/web.xml', 'mode': '0644'} +ERROR: solr.petspremium.de: Type __directory requires object id (is not a singleton type) +INFO: Total processing time for 1 host(s): 9.756716251373291 +ERROR: Failed to deploy to the following hosts: solr.petspremium.de diff --git a/docs/dev/logs/2013-04-03.dependency-discussion b/docs/dev/logs/2013-04-03.dependency-discussion new file mode 100644 index 00000000..29b5b5b5 --- /dev/null +++ b/docs/dev/logs/2013-04-03.dependency-discussion @@ -0,0 +1,30 @@ +Steven, Nico + +Discussion raised due to proposal from Arkaitz Jimenez + +-------------------------------------------------------------------------------- + +Proposal changes back to cdist behaviour as of 2011 (see commit 61b7b68). + +Change would introduce: + +- no direct stage based running +- stages only in object (not globally) +- cannot build full dependency list before beginning + - Thus wildcard requirements (require="__file/*") don't work anymore + +Accepting this or similar approaches means: + +- Drop wildcard requirements (is undocumented anyway) +- Type execution is closed (again) + +Furthermore/other points: + +- Change cdist to continue run as long as possible + - Don't stop if an object fails + - Record failure, print at the end (and exit non zero) + +- Logging + - Catch output of manifest, gencode, code, do not display directly + - Print at the end + - Prefix with hostname as usual! diff --git a/docs/dev/logs/2013-04-08.execution-graph.xoj b/docs/dev/logs/2013-04-08.execution-graph.xoj new file mode 100644 index 00000000..25d48d3b Binary files /dev/null and b/docs/dev/logs/2013-04-08.execution-graph.xoj differ diff --git a/docs/dev/logs/2013-04-10.discussion b/docs/dev/logs/2013-04-10.discussion new file mode 100644 index 00000000..648ed470 --- /dev/null +++ b/docs/dev/logs/2013-04-10.discussion @@ -0,0 +1,77 @@ +Steven, Nico (ETH office) + +- Try out patch for dependency resolver changing from [nico] + - Add tests + - Cleanup code: + - remove all old resolver parts (including tests!) + - remve wildcard matching pattern code + +- Cache: [nobody] + - Should cache be usable by types? + - Should all run outputs be stored? + - Different caches for install and config + +- Replace fsproperties with cconfig [steven] + +- Maybe support "rerun from previous version (cache)"? [nobody] + - need to include initial manifest(s!) + - copy/link types + - save remote-{exec,copy} parameters (copy or save argument list) + + - cdist replay / oldconfig ? + +- Support diffing two configurations [nobody] + - cdist diff ? + +- Nested Types [both] + - Motivation: + - Put everything related into one directory + - Have a look at it when Arkaitz pushes out pull request + - Implementations: + + 1) Arkaitz + + Folder structure Call Object + __package/ __package abc __package/abc + __package/type/pkg __package.pkg abc __package.pkg/abc + __package/type/pkg/type/green __package.pkg.green abc __package.pkg.green/abc + + ... + + __package.pkg __package.pkg abc __package.pkg/abc + + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + => Need to forbid types with "." in the name! + + 2) Steven (earlier version) + + Folder structure Call Object + __package/.type __package abc __package/abc + __package/pkg/.type __package.pkg abc __package.pkg/abc + __package/pkg/green/.type __package.pkg.green abc __package.pkg.green/abc + + - Clashes: + - if __. and __ and subtype exist both (in both implementations) + +- Install [nobody] + - Merge into master? + - Needs some cleanups + +- PreOS [nobody] + - cdist preos / preos-generate + --output= + --arch=[i386|amd64|arm??] + --type=[usb, cdrom/iso, floppy, pxe] + --other-params (?) + + - Maybe implement using cdist config indirectly and a type __preos + + - Can be: + - Internally only (devs) + - Usable by end users + + - Requirements: + - git + - buildchain + - toolchain for target arch + - ... diff --git a/docs/dev/logs/2013-04-12.execution-order b/docs/dev/logs/2013-04-12.execution-order new file mode 100644 index 00000000..5100eeda --- /dev/null +++ b/docs/dev/logs/2013-04-12.execution-order @@ -0,0 +1,44 @@ +Old: + +- global explores (all) +- initial manifest +- for each object + execute type explorers + execute manifest + + continue until all objects (including newly created) + have their type explorers/manifests run +- build dependency tree +- for each object + execute gencode-* + execute code-* + +New: +- run all global explorers +- run initial manifest + creates zero or more cdist_objects +- for each cdist_object + if not cdist_object.has_unfullfilled_requirements: + execute type explorers + execute manifest + may create new objects, resulting in autorequirements + + # Gained requirements during manifest run + if object.has_auto_requirements(): + continue + + cdist_object.execute gencode-* + cdist_object.execute code-* + + +Requirements / Test cases for requirments / resolver: + + - omnipotence + - + + +-------------------------------------------------------------------------------- +ERROR: localhost: The following objects could not be resolved: __cdistmarker/singleton requires autorequires ; __directory/etc/sudoers.d requires autorequires ; __file/etc/sudoers.d/nico requires __directory/etc/sudoers.d autorequires ; __file/etc/motd requires autorequires ; __package_pacman/atop requires autorequires ; __package_pacman/screen requires autorequires ; __package_pacman/strace requires autorequires ; __package_pacman/vim requires autorequires ; __package_pacman/zsh requires autorequires ; __package_pacman/lftp requires autorequires ; __package_pacman/nmap requires autorequires ; __package_pacman/ntp requires autorequires ; __package_pacman/rsync requires autorequires ; __package_pacman/rtorrent requires autorequires ; __package_pacman/wget requires autorequires ; __package_pacman/nload requires autorequires ; __package_pacman/iftop requires autorequires ; __package_pacman/mosh requires autorequires ; __package_pacman/git requires autorequires ; __package_pacman/mercurial requires autorequires ; __package_pacman/netcat requires autorequires ; __package_pacman/python-virtualenv requires autorequires ; __package_pacman/wireshark-cli requires autorequires ; __package_pacman/sudo requires autorequires +INFO: Total processing time for 1 host(s): 32.30426597595215 +ERROR: Failed to deploy to the following hosts: localhost + diff --git a/docs/dev/logs/2013-05-04.ssh b/docs/dev/logs/2013-05-04.ssh new file mode 100644 index 00000000..176e5b62 --- /dev/null +++ b/docs/dev/logs/2013-05-04.ssh @@ -0,0 +1,340 @@ +- analysis of ssh connections for callback + SSH_CLIENT='::1 38502 22' + SSH_CONNECTION='::1 38502 ::1 22' + + -> callback possible to source host + + + +[ target host ] <--------------| + | | + | | + | | + | trigger | configuration + | | + v | +[ configuration host ] ----| + + +- dynamic port allocation for tunneling + + [1:37] bento:~% ssh -R 0:localhost:22 localhost + Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts. + Allocated port 53161 for remote forward to localhost:22 + + SSH_AUTH_SOCK=/tmp/ssh-zDCWbUVcUK/agent.30749 + SSH_CLIENT='::1 38587 22' + SSH_CONNECTION='::1 38587 ::1 22' + SSH_TTY=/dev/pts/21 + + +- ssh_config: + DynamicForward + LocalForward + RemoteForward + +- testing + +[1:52] bento:cdist% netstat -anp | grep 56844 +(Not all processes could be identified, non-owned process info + will not be shown, you would have to be root to see it all.) +tcp 0 0 127.0.0.1:56844 0.0.0.0:* LISTEN - +tcp6 0 0 ::1:56844 :::* LISTEN - +[1:53] bento:cdist% + + +[1:48] bento:~% ssh -R 0:localhost:22 localhost +Allocated port 56844 for remote forward to localhost:22 +... + +- chatting + +01:42 -!- Irssi: Join to #openssh was synced in 0 secs +01:42 < telmich> good evening +01:43 < telmich> I am trying to make use of remote port forwarding using dynamic port + allocation (port=0) -- I am wondering if there is an easy way to + access the port number on the remote side easily? +01:44 < telmich> background for this question is: I'd like to allow various clients to + login to a configuration server, which then configures the clients by + using the tunnel the client provides for the server to ssh back into +02:07 < BasketCase> telmich: afaik you need to use a tool like ss/netstat/lsof to see what port it has open + +- ssh debug + +[11:37] bento:~% ssh -R 0:localhost:22 localhost +Allocated port 33562 for remote forward to localhost:22 + + .. . .x+=:. s + dF @88> z` ^% :8 + '88bu. %8P . server aes128-ctr hmac-md5-etm@openssh.com zlib@openssh.com [preauth] +debug1: kex: server->client aes128-ctr hmac-md5-etm@openssh.com zlib@openssh.com [preauth] +debug1: expecting SSH2_MSG_KEX_ECDH_INIT [preauth] +debug1: SSH2_MSG_NEWKEYS sent [preauth] +debug1: expecting SSH2_MSG_NEWKEYS [preauth] +debug1: SSH2_MSG_NEWKEYS received [preauth] +debug1: KEX done [preauth] +debug1: userauth-request for user root service ssh-connection method none [preauth] +debug1: attempt 0 failures 0 [preauth] +debug1: PAM: initializing for "root" +debug1: PAM: setting PAM_RHOST to "localhost.localdomain" +debug1: PAM: setting PAM_TTY to "ssh" +debug1: userauth-request for user root service ssh-connection method publickey [preauth] +debug1: attempt 1 failures 0 [preauth] +debug1: test whether pkalg/pkblob are acceptable [preauth] +debug1: temporarily_use_uid: 0/0 (e=0/0) +debug1: trying public key file /root/.ssh/authorized_keys +debug1: fd 4 clearing O_NONBLOCK +debug1: matching key found: file /root/.ssh/authorized_keys, line 2 +Found matching RSA key: 2e:1b:3f:10:01:1d:21:6c:6c:1e:3d:a9:33:ba:3c:f7 +debug1: restore_uid: 0/0 +Postponed publickey for root from ::1 port 57848 ssh2 [preauth] +debug1: userauth-request for user root service ssh-connection method publickey [preauth] +debug1: attempt 2 failures 0 [preauth] +debug1: temporarily_use_uid: 0/0 (e=0/0) +debug1: trying public key file /root/.ssh/authorized_keys +debug1: fd 4 clearing O_NONBLOCK +debug1: matching key found: file /root/.ssh/authorized_keys, line 2 +Found matching RSA key: 2e:1b:3f:10:01:1d:21:6c:6c:1e:3d:a9:33:ba:3c:f7 +debug1: restore_uid: 0/0 +debug1: ssh_rsa_verify: signature correct +debug1: do_pam_account: called +Accepted publickey for root from ::1 port 57848 ssh2 +debug1: monitor_child_preauth: root has been authenticated by privileged process +debug1: Enabling compression at level 6. [preauth] +debug1: monitor_read_log: child log fd closed +debug1: PAM: establishing credentials +debug1: Entering interactive session for SSH2. +debug1: server_init_dispatch_20 +debug1: server_input_global_request: rtype tcpip-forward want_reply 1 +debug1: server_input_global_request: tcpip-forward listen localhost port 0 +debug1: Local forwarding listening on ::1 port 0. +debug1: Allocated listen port 33562 +debug1: channel 0: new [port listener] +debug1: Local forwarding listening on 127.0.0.1 port 33562. +debug1: channel 1: new [port listener] +debug1: server_input_channel_open: ctype session rchan 0 win 1048576 max 16384 +debug1: input_session_request +debug1: channel 2: new [server-session] +debug1: session_new: session 0 +debug1: session_open: channel 2 +debug1: session_open: session 0: link with channel 2 +debug1: server_input_channel_open: confirm session +debug1: server_input_global_request: rtype no-more-sessions@openssh.com want_reply 0 +debug1: server_input_channel_req: channel 2 request auth-agent-req@openssh.com reply 0 +debug1: session_by_channel: session 0 channel 2 +debug1: session_input_channel_req: session 0 req auth-agent-req@openssh.com +debug1: temporarily_use_uid: 0/0 (e=0/0) +debug1: restore_uid: 0/0 +debug1: channel 3: new [auth socket] +debug1: server_input_channel_req: channel 2 request pty-req reply 1 +debug1: session_by_channel: session 0 channel 2 +debug1: session_input_channel_req: session 0 req pty-req +debug1: Allocating pty. +debug1: session_pty_req: session 0 alloc /dev/pts/32 +debug1: server_input_channel_req: channel 2 request shell reply 1 +debug1: session_by_channel: session 0 channel 2 +debug1: session_input_channel_req: session 0 req shell +debug1: Setting controlling tty using TIOCSCTTY. + +-------------------------------------------------------------------------------- +debug1: server_input_global_request: rtype tcpip-forward want_reply 1 +debug1: server_input_global_request: tcpip-forward listen localhost port 0 +debug1: Local forwarding listening on ::1 port 0. +debug1: Allocated listen port 33562 +debug1: channel 0: new [port listener] +debug1: Local forwarding listening on 127.0.0.1 port 33562. + +[11:49] bento:openssh-6.2p1% grep "Allocated listen port" -r . +./channels.c: debug("Allocated listen port %d", +[11:49] bento:openssh-6.2p1% + + +-------------------------------------------------------------------------------- +[11:54] bento:~% ssh -R 0:localhost:22 -R 0:192.168.1.1:33 localhost +Allocated port 48392 for remote forward to localhost:22 +Allocated port 37515 for remote forward to 192.168.1.1:33 + + + + +debug1: server_input_global_request: rtype tcpip-forward want_reply 1 +debug1: server_input_global_request: tcpip-forward listen localhost port 0 +debug1: Local forwarding listening on ::1 port 0. +debug1: Allocated listen port 48392 +debug1: channel 0: new [port listener] +debug1: Local forwarding listening on 127.0.0.1 port 48392. +debug1: channel 1: new [port listener] +debug1: server_input_global_request: rtype tcpip-forward want_reply 1 +debug1: server_input_global_request: tcpip-forward listen localhost port 0 +debug1: Local forwarding listening on ::1 port 0. +debug1: Allocated listen port 37515 +debug1: channel 2: new [port listener] +debug1: Local forwarding listening on 127.0.0.1 port 37515. +debug1: channel 3: new [port listener] +debug1: server_input_channel_open: ctype session rchan 0 win 1048576 max 16384 +debug1: input_session_request +debug1: channel 4: new [server-session] +debug1: session_new: session 0 +debug1: session_open: channel 4 +debug1: session_open: session 0: link with channel 4 + +debug1: Local forwarding listening on ::1 port 5555. +debug1: channel 0: new [port listener] +debug1: Local forwarding listening on 127.0.0.1 port 5555. +debug1: channel 1: new [port listener] +debug1: server_input_global_request: rtype tcpip-forward want_reply 1 +debug1: server_input_global_request: tcpip-forward listen localhost port 4444 +debug1: Local forwarding listening on ::1 port 4444. +debug1: channel 2: new [port listener] +debug1: Local forwarding listening on 127.0.0.1 port 4444. +debug1: channel 3: new [port listener] +debug1: server_input_channel_open: ctype session rchan 0 win 1048576 max 16384 +debug1: input_session_request +debug1: channel 4: new [server-session] +debug1: session_new: session 0 +debug1: session_open: channel 4 + +-------------------------------------------------------------------------------- + +[12:06] bento:openssh-6.2p1% grep SSH_CONNECTION -r * +audit-bsm.c: case SSH_CONNECTION_CLOSE: +audit.c: {SSH_CONNECTION_CLOSE, "CONNECTION_CLOSE"}, +audit.c: {SSH_CONNECTION_ABANDON, "CONNECTION_ABANDON"}, +audit.h: SSH_CONNECTION_CLOSE, /* closed after attempting auth or session */ +audit.h: SSH_CONNECTION_ABANDON, /* closed without completing auth */ +audit-linux.c: case SSH_CONNECTION_CLOSE: +monitor.c: case SSH_CONNECTION_CLOSE: +regress/proxy-connect.sh: SSH_CONNECTION=`${SSH} -$p -F $OBJ/ssh_proxy 999.999.999.999 'echo $SSH_CONNECTION'` +regress/proxy-connect.sh: if [ "$SSH_CONNECTION" != "UNKNOWN 65535 UNKNOWN 65535" ]; then +regress/proxy-connect.sh: fail "bad SSH_CONNECTION" +session.c: child_set_env(&env, &envsize, "SSH_CONNECTION", buf); +sftp-server.c: if ((cp = getenv("SSH_CONNECTION")) != NULL) { +sftp-server.c: error("Malformed SSH_CONNECTION variable: \"%s\"", +sftp-server.c: getenv("SSH_CONNECTION")); +ssh.0: SSH_CONNECTION Identifies the client and server ends of the +ssh.1:.It Ev SSH_CONNECTION +sshd.c: PRIVSEP(audit_event(SSH_CONNECTION_CLOSE)); +sshd.c: audit_event(SSH_CONNECTION_ABANDON); +[12:06] bento:openssh-6.2p1% + +-------------------------------------------------------------------------------- +debug1: Remote connections from LOCALHOST:5555 forwarded to local address localhost:22 + +-------------------------------------------------------------------------------- +[12:42] bento:openssh-6.2p1% grep tcpip-forward * +channels.c: packet_put_cstring("tcpip-forward"); +channels.c: packet_put_cstring("cancel-tcpip-forward"); +Binary file channels.o matches +grep: contrib: Is a directory +Binary file libssh.a matches +grep: openbsd-compat: Is a directory +grep: regress: Is a directory +grep: scard: Is a directory +serverloop.c: if (strcmp(rtype, "tcpip-forward") == 0) { +serverloop.c: debug("server_input_global_request: tcpip-forward listen %s port %d", +serverloop.c: } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) { +serverloop.c: debug("%s: cancel-tcpip-forward addr %s port %d", __func__, +Binary file serverloop.o matches +Binary file ssh matches +Binary file sshd matches +Binary file ssh-keyscan matches +Binary file ssh-keysign matches +[12:42] bento:openssh-6.2p1% + +-------------------------------------------------------------------------------- +Channel information for (remote) forwarding: + + c = channel_new("port listener", type, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, + 0, "port listener", 1); + c->path = xstrdup(host); + c->host_port = port_to_connect; + c->listening_addr = addr == NULL ? NULL : xstrdup(addr); + if (listen_port == 0 && allocated_listen_port != NULL && + !(datafellows & SSH_BUG_DYNAMIC_RPORT)) + c->listening_port = *allocated_listen_port; + else + c->listening_port = listen_port; + +-------------------------------------------------------------------------------- + +Code handling remote forwarding in the client: +- ssh_init_forwarding + - channel_request_remote_forwarding + Sends hostname + port for ssh1 only - not send in ssh2 + +Code handling forwarding / listening in the server: + +- channel_new: creates channels, 2 per listener (ipv4/ipv6) + - channels_alloc contains number of channels +- server_input_global_request + Reads only listen port, not hostname/port to connect to + - channel_setup_remote_fwd_listener + - channel_setup_remote_fwd_listener + +Code handling environment variables: + +- child_set_env +1236 child_set_env(&env, &envsize, "SSH_CONNECTION", buf); + diff --git a/docs/dev/logs/2013-05-17.ssh-callback-socat b/docs/dev/logs/2013-05-17.ssh-callback-socat new file mode 100644 index 00000000..69428309 --- /dev/null +++ b/docs/dev/logs/2013-05-17.ssh-callback-socat @@ -0,0 +1,40 @@ + +start ssh +to controlhost, +bind other side to +localhost:22 + + +targethost ------> ssh ------> controlhost + | + | + socat: connect stdin/stdout to ? + start cdist with port information + added + + +Use + +socat + + +-------------------------------------------------------------------------------- + TCP:: + Connects to [TCP service] on [IP address] using TCP/IP version 4 or 6 depending on address specifi‐ + cation, name resolution, or option pf. + Option groups: FD,SOCKET,IP4,IP6,TCP,RETRY + Useful options: crnl, bind, pf, connect-timeout, tos, mtudiscover, mss, nodelay, nonblock, sourceport, retry, + readbytes + See also: TCP4, TCP6, TCP-LISTEN, UDP, SCTP-CONNECT, UNIX-CONNECT + +forever +-------------------------------------------------------------------------------- +[root@nico-dev-vm-snr01 yum.repos.d]# ps aux | grep socat +nico 25035 0.0 0.0 41640 1524 ? Ss 13:27 0:00 socat - TCP-LISTEN:1234 +root 25037 0.0 0.0 103240 836 pts/1 S+ 13:27 0:00 grep socat +[root@nico-dev-vm-snr01 yum.repos.d]# + + + +-------------------------------------------------------------------------------- + diff --git a/docs/dev/logs/2013-07-12.release b/docs/dev/logs/2013-07-12.release new file mode 100644 index 00000000..da4b296c --- /dev/null +++ b/docs/dev/logs/2013-07-12.release @@ -0,0 +1,38 @@ +- setup release date in docs/changelog to today manually + +- checkout master branch + [ + x check if date is correct in docs/changelog + x ensure all unittests work + - requires (wrong/outdated) versionfile! + x compile manpages + x compile speeches + ] + [ + x add manpages to website repo + x add speeches to website repo + x rsync cdist docs to website repo & add to website repo + x create blog entry & add to website repo + ] + x upload website + x fix latest link for manpages + x send mail to mailinglist -> also requires git tag & git release + x should also require web-release including blog! + + - create PKGBUILD for archlinux release + + x create git tag / read description + t if necessary create version branch + x change to version branch and merge tag! + x update git repos + x update website from repo + x create release on freecode + + x create versionfile + x make pypi release + x make archlinux release + +manual last steps: + +- announce on linkedin +- announce on twitter diff --git a/docs/dev/logs/2013-07-25.source-error-does-not-stop-cdist b/docs/dev/logs/2013-07-25.source-error-does-not-stop-cdist new file mode 100644 index 00000000..b0c43971 --- /dev/null +++ b/docs/dev/logs/2013-07-25.source-error-does-not-stop-cdist @@ -0,0 +1,56 @@ +Symptom: + running something in a manifest and that fails does not exist + the cdist run + +Analysis: + Find out what the shell does: + + [23:56] bento:testshell% cat a.sh + # source something that fails + . b.sh + [23:57] bento:testshell% cat b.sh + nosuchcommand + [23:57] bento:testshell% sh -e a.sh + a.sh: 2: .: b.sh: not found + [23:57] bento:testshell% echo $? + 2 + + -> exit 2 -> looks good + + + Find out what the python does: + + [23:57] bento:testshell% python3 + Python 3.3.2 (default, May 21 2013, 15:40:45) + [GCC 4.8.0 20130502 (prerelease)] on linux + Type "help", "copyright", "credits" or "license" for more information. + >>> import subprocess + >>> subprocess.check_call(["/bin/sh", "-e", "a.sh"]) + a.sh: 2: .: b.sh: not found + Traceback (most recent call last): + File "", line 1, in + File "/usr/lib/python3.3/subprocess.py", line 544, in check_call + raise CalledProcessError(retcode, cmd) + subprocess.CalledProcessError: Command '['/bin/sh', '-e', 'a.sh']' returned non-zero exit status 2 + >>> + + +Conclusion: + Manifests that execute (!) other shell scripts does + not necessarily give the -e flag to the other script + -> called script can have failures, but exit 0 + if something the last thing executed does exit 0! + +Solution: + Instead of doing stuff like + "$__manifest/special" + + use + sh -e "$__manifest/special" + + or source the script: + . "$__manifest/special" + + (runs the script in the same namespace/process as everything in the + calling script) + diff --git a/docs/dev/logs/2013-08-07.shell b/docs/dev/logs/2013-08-07.shell new file mode 100644 index 00000000..3fa9f139 --- /dev/null +++ b/docs/dev/logs/2013-08-07.shell @@ -0,0 +1,2 @@ +What about having a cdist shell to have a shell with all available types? +Let's give it a try! diff --git a/docs/dev/logs/2013-08-12.release b/docs/dev/logs/2013-08-12.release new file mode 100644 index 00000000..1db05681 --- /dev/null +++ b/docs/dev/logs/2013-08-12.release @@ -0,0 +1,28 @@ +- already on 2.3.0-1 during release + - user bug: there should be no changes / commits during a release process + +hard linking docs/man/man7/cdist-type__user.7 -> cdist-2.3.0-1-g8192c2c/docs/man/man7 +hard linking docs/man/man7/cdist-type__user.html -> cdist-2.3.0-1-g8192c2c/docs/man/man7 +hard linking docs/man/man7/cdist-type__user_groups.7 -> cdist-2.3.0-1-g8192c2c/docs/man/man7 +hard linking docs/man/man7/cdist-type__user_groups.html -> cdist-2.3.0-1-g8192c2c/docs/man/man7 +hard linking scripts/cdist -> cdist-2.3.0-1-g8192c2c/scripts +creating dist +Creating tar archive +removing 'cdist-2.3.0-1-g8192c2c' (and everything under it) +running upload +Submitting dist/cdist-2.3.0-1-g8192c2c.tar.gz to http://pypi.python.org/pypi +Server response (200): OK +touch .lock-pypi +./PKGBUILD.in 2.3.0 +==> Retrieving sources... + -> Downloading cdist-2.3.0.tar.gz... + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed + 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 + 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 +curl: (22) The requested URL returned error: 404 Not Found +==> ERROR: Failure while downloading cdist-2.3.0.tar.gz + Aborting... +make: *** [PKGBUILD] Error 1 +[12:38] bento:cdist% + diff --git a/docs/dev/logs/2013-08-18.cache-enhancement b/docs/dev/logs/2013-08-18.cache-enhancement new file mode 100644 index 00000000..95052dfe --- /dev/null +++ b/docs/dev/logs/2013-08-18.cache-enhancement @@ -0,0 +1,17 @@ +- always save cache = outdir + - even if run aborts (for debugging) + - add a state flag +- save cache in a date based directory +- also add support for a per-host pidfile +- allow user to specify cache dir - to give + full flexibility +- drop context - it is a very small unecessary wrapper + - maye introduce cdist.log instead! +- replace out_path with out_base + - directory under which all the subdirectories are + created + -> by default ~/.cdist/run + -> out_base_path +- drop support for deprecated environment variables + __cdist_out_dir + __cdist_remote_out_dir diff --git a/docs/dev/logs/2013-08-27-notifications.xoj b/docs/dev/logs/2013-08-27-notifications.xoj new file mode 100644 index 00000000..c34c4676 Binary files /dev/null and b/docs/dev/logs/2013-08-27-notifications.xoj differ diff --git a/docs/dev/logs/2013-08-28.release b/docs/dev/logs/2013-08-28.release new file mode 100644 index 00000000..23e23d88 --- /dev/null +++ b/docs/dev/logs/2013-08-28.release @@ -0,0 +1,5 @@ +- release process releases pypi from something + that is git describe based, not changelog based... + + - git describe should equal changelog, but may be + inconsistent due to branch merging! diff --git a/docs/dev/logs/2013-09-05.test-cp b/docs/dev/logs/2013-09-05.test-cp new file mode 100644 index 00000000..1f02ee5d --- /dev/null +++ b/docs/dev/logs/2013-09-05.test-cp @@ -0,0 +1,34 @@ +Test copy copys symlinks - making real files would be better + +Test how to use cp: + +[12:54] bento:~% cd test +[12:54] bento:test% ln -s /etc/passwd +[12:54] bento:test% cd .. +[12:54] bento:~% cp -r test test2 +[12:54] bento:~% ls -lh test2/ +total 4.0K +lrwxrwxrwx 1 nico nico 11 Sep 5 12:54 passwd -> /etc/passwd +[12:54] bento:~% rm -rf test2/ + +-------------------------------------------------------------------------------- +[12:54] bento:~% ls -lh test2/ +total 4.0K +lrwxrwxrwx 1 nico nico 11 Sep 5 12:54 passwd -> /etc/passwd +[12:54] bento:~% rm -rf test2/ +[12:54] bento:~% cp -r --dereference test test2 +[12:56] bento:~% ls -l test2/ +total 4 +-rw------- 1 nico nico 960 Sep 5 12:56 passwd +[12:56] bento:~% + +-------------------------------------------------------------------------------- +[13:04] bento:cdist% git describe +2.3.2 +[13:09] bento:cdist% vi MANIFEST.in +[13:09] bento:cdist% vi MANIFEST +[13:09] bento:cdist% vi setup.py +[13:09] bento:cdist% cat cdist/version.py +VERSION = "2.3.1-34-g7acf041" +[13:10] bento:cdist% + diff --git a/docs/dev/logs/2013-10-03.ossawards/infos b/docs/dev/logs/2013-10-03.ossawards/infos new file mode 100644 index 00000000..a18c686f --- /dev/null +++ b/docs/dev/logs/2013-10-03.ossawards/infos @@ -0,0 +1,13 @@ +Required for the ossawards until 2013-10-06: + - all source code + - licenses GPLv3 + - installation instructions, + - On Linux do the following: + - pip install + - + - necessary documents and + - a demo video onto our web hard. + - installation + - cdist via cdist + - presentation + - build from existing ones (?) diff --git a/docs/dev/logs/2013-10-29.__line b/docs/dev/logs/2013-10-29.__line new file mode 100644 index 00000000..bc15de2c --- /dev/null +++ b/docs/dev/logs/2013-10-29.__line @@ -0,0 +1,6 @@ +- fix handling of fixed strings + - ensure special characters are not interpreted +[12:18] bento:~% cat /etc/bash.bashrc +cat: /etc/bash.bashrc: Permission denied +[12:19] bento:~% + diff --git a/docs/dev/logs/2013-11-25.notifications b/docs/dev/logs/2013-11-25.notifications new file mode 100644 index 00000000..33c6f31b --- /dev/null +++ b/docs/dev/logs/2013-11-25.notifications @@ -0,0 +1,50 @@ +Follow up from 2013-01-20: + + - (re-)create message file per object? + - yes, but do not necessarily save in object space + - save $anywhere + + - object_run + - current notifications are imported into a file available at $__messages_in + - after object run, everything that has been written to $__messages_out is merged into the $__messages file + + - functions: + self.explorer.run_global_explorers(self.local.global_explorer_out_path) + self.manifest.run_initial_manifest(self.local.initial_manifest) + self.local.run_script(initial_manifest, env=self.env_initial_manifest(initial_manifest)) + self.explorer.run_type_explorers(cdist_object) + self.manifest.run_type_manifest(cdist_object) + self.local.run_script(type_manifest, env=self.env_type_manifest(cdist_object)) + self.code.run_gencode_local(cdist_object) + self.local.run_script(script, env=env, return_output=True) + self.code.run_gencode_remote(cdist_object) + self.local.run_script(script, env=env, return_output=True) + + + - message support in ... + - initialmanifest - yes + - explorer - no + - only locally - yes + + - how to use notification / messaging in cdist + - can be used in all local scripts: + - initial manifest + - type manifest + - type gencode-* + - order of object exeution is random or as you requested using require="" + + - example use: + +__file/gencode-local: + if [ "$local_cksum" != "$remote_cksum" ]; then + echo "$__remote_copy" "$source" "${__target_host}:${destination}" + echo "copy" >> "$__messages_out" + fi + +__nginx/manifest: + __file /etc/nginx/sites-enabled/myfile --source "$__type/files/nginx-config" + +__nginx/gencode-remote: + if grep -q "__file/etc/nginx/sites-enabled/myfile:copy" "$__messages_in"; then + echo /etc/init.d/nginx restart + fi diff --git a/docs/dev/logs/2013-12-12.discussion b/docs/dev/logs/2013-12-12.discussion new file mode 100644 index 00000000..58d25517 --- /dev/null +++ b/docs/dev/logs/2013-12-12.discussion @@ -0,0 +1,6 @@ +With Steven + +- Implement environments + - for configuring "anything" including switches + - can disable / use other global explorers +- 98% of our framework is generic and can be used for any applikation diff --git a/docs/dev/logs/2014-01-20.environments b/docs/dev/logs/2014-01-20.environments new file mode 100644 index 00000000..88fe42b9 --- /dev/null +++ b/docs/dev/logs/2014-01-20.environments @@ -0,0 +1,44 @@ +raw quote from irc + +16:00 < sar> telmich: btw, ich denke nicht dass man install schon zu gross bewerben + sollte +16:00 < telmich> sar: ack +16:00 < sar> telmich: imho sollten wir erst die cdist environments implementieren, + install waere dann eines davon +16:00 < sar> config ein anderes +16:01 < sar> foobar noch ein anderes +16:01 < sar> es macht einfach keinen sinn auf type ebene install vs nicht-install zu + unterscheiden +16:02 < telmich> sar: environments sind bei mir noch nicht ganz im gehirn (ganicht?) + angelangt - hast du (nochmal?) kurz eine idee, was du damit meinst? +16:02 < sar> telmich: wenn man cdist anschaut, dann macht es eigentlich folgendes: +16:03 < sar> - definiere objekte mit hilfe von types +16:03 < sar> - deps zwischen objekten +16:03 < sar> - queue von objekten abarbeiten und auf $etwas anwenden +16:03 < sar> das ist alles +16:04 < sar> telmich: das ist eigentlich ziemlich generisch +16:04 < sar> telmich: fuer mich wuerde es sich hier anbieten das auch so zu + abstrahieren +16:05 < sar> telmich: ein environment (nenn das mal so weil kein besserer name zzt) + koennte das wie $objekt auf $etwas bestimmen +16:05 < sar> telmich: und auch was fuer types es in diesem environment gibt +16:06 < telmich> sar: klingt gut +16:06 < sar> telmich: e.g. es gibt ein environment fuer config -> was wir jetzt haben +16:06 < sar> eins fuer install -> += was im install branch ist (nur die types), den + python code brauchts nacher nicht mehr +16:07 < sar> eins fuer cisco-switch -> hat types um mit cisco zu spielen +16:07 < sar> usw +16:07 < sar> ein environment hat auch eigene remote-{exec,copy} scripte +16:08 < sar> und vielleicht globale explorer, vielleicht auch nicht +16:08 < sar> ein enviroment ist ein cconfig style directory +16:09 < sar> wo man cdist drueber laufen laesst +16:09 < sar> so was in der art +16:13 < telmich> sar: hmmja...klingt gut +16:15 < telmich> vielleicht etwas für cdist 4 oder cdist 5 :-) +16:15 < telmich> aber ich denke auf jeden fall als grundgedanke behaltbar +16:16 < telmich> ok für dich, wenn ich den chat ins docs/dev/logs kopiere als + erinnerungs +16:16 < telmich> s/s$/?/? +16:16 < telmich> s/?$// +16:20 < sar> klar + diff --git a/docs/dev/logs/2014-02-13.discussion b/docs/dev/logs/2014-02-13.discussion new file mode 100644 index 00000000..70c0f4fc --- /dev/null +++ b/docs/dev/logs/2014-02-13.discussion @@ -0,0 +1,86 @@ +With Steven + +t marker .cdist breaks + - use random marker that starts with .cdist- + - has fixed number of following characters (like 6 or 10) + - write marker name to $__global/marker + - export $__global/marker path as $__marker + - document variable in cdist-reference + - also document the pattern how the marker is built + so that other people may be able to dig into the structure + from outside + +t save method + - in $__global/method + - values + - config + - install + - document path and description in cdist-reference + +t save whole runtime in cache + - missing items + - initial manifest may be specified on commandline + - always save the initial manifest to $__global/initial-manifest + - currently it is a lost tempfile + - remote exec / remote copy + - save to $__global/remote_exec + - save to $__global/remote_copy + - stdout and stderr of everything + - need to implement Steven's patch of stderr/stdout capturing + - exit code of cdist + - if it is complete, we can use it for replay / reconfigure + +- new idea: replay / reconfig / reinstall + - --from-cache? + +t stderr/stdout + - capture all messages + - prefix with target_host + - implementation exists in one of Steven's branches + - ping steven for updated pull request + +x on error dump all information about the failing object + - where created + - stderr + - stdout + - parameter (+values) + - everything known [tm] + +t multiple versions of cache + - see #298 + +t absolute path of types, explorer + - resolve instead of using the temporary link name + - #305 + +t report command + - from cache? + - #306 + +t add session to "run directories" + - instead of /var/lib/cdist (remote) + - instead of static dir in cache + - same id remote and local + - maybe timestamp + - in or excluding the pid of cdist? + +- cache + - also save when cdist fails + - save exit code + - be able to restore config + +- new command: cdist clean-cache + - --since + - --keep-versions --keep-lala $num + +- cdist 4.0.0pre2 + - cleanup in preos + +- logging for types + cdist log ...? + + - cdist logserver + - $__global/log.socket + - fifo? + echo into logpipe? + diff --git a/docs/gfx/cdist-and-sexy-white.png b/docs/gfx/cdist-and-sexy-white.png new file mode 100644 index 00000000..1366b9c2 Binary files /dev/null and b/docs/gfx/cdist-and-sexy-white.png differ diff --git a/docs/gfx/cdist-logo-1024-scaled.png b/docs/gfx/cdist-logo-1024-scaled.png new file mode 100644 index 00000000..4be8d4c9 Binary files /dev/null and b/docs/gfx/cdist-logo-1024-scaled.png differ diff --git a/docs/gfx/instalation-using-preos.odg b/docs/gfx/instalation-using-preos.odg new file mode 100644 index 00000000..6424bbc5 Binary files /dev/null and b/docs/gfx/instalation-using-preos.odg differ diff --git a/docs/gfx/label-cdist-ngcm.odt b/docs/gfx/label-cdist-ngcm.odt new file mode 100644 index 00000000..5e73b332 Binary files /dev/null and b/docs/gfx/label-cdist-ngcm.odt differ diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 225d647f..62614c55 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -116,8 +116,13 @@ confdir/type//parameter/required:: confdir/type//parameter/optional:: Parameters optionally accepted by type, \n seperated list. +confdir/type//parameter/default/*:: + Default values for optional parameters. + Assuming an optional parameter name of 'foo', it's default value would + be read from the file confdir/type//parameter/default/foo. + confdir/type//parameter/boolean:: - Boolean parameters accepted by type, \n seperated list. + Boolean parameters accepted by type, \n seperated list. confdir/type//explorer:: Location of the type specific explorers. @@ -126,7 +131,8 @@ confdir/type//explorer:: confdir/type//files:: This directory is reserved for user data and will not be used - by cdist at any time + by cdist at any time. It can be used for storing supplementary + files (like scripts to act as a template or configuration files). out/:: This directory contains output of cdist and is usually located @@ -170,21 +176,36 @@ OBJECTS For object to object communication and tests, the following paths are usable within a object directory: +files:: + This directory is reserved for user data and will not be used + by cdist at any time. It can be used freely by the type + (for instance to store template results). changed:: This empty file exists in an object directory, if the object has code to be excuted (either remote or local) +stdin:: + This file exists and contains data, if data was provided on stdin + when the type was called. -ENVIRONMENT VARIABLES ---------------------- +ENVIRONMENT VARIABLES (FOR READING) +----------------------------------- +The following environment variables are exported by cdist: + __explorer:: Directory that contains all global explorers. - Available for: explorer, type explorer + Available for: initial manifest, explorer, type explorer, shell __manifest:: Directory that contains the initial manifest. - Available for: initial manifest, type manifest + Available for: initial manifest, type manifest, shell __global:: Directory that contains generic output like explorer. + Available for: initial manifest, type manifest, type gencode, shell +__messages_in:: + File to read messages from + Available for: initial manifest, type manifest, type gencode +__messages_out:: + File to write messages Available for: initial manifest, type manifest, type gencode __object:: Directory that contains the current object. @@ -200,7 +221,7 @@ __object_name:: Available for: type manifest, type explorer, type gencode __target_host:: The host we are deploying to. - Available for: explorer, initial manifest, type explorer, type manifest, type gencode + Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell __type:: Path to the current type. Available for: type manifest, type gencode @@ -208,6 +229,18 @@ __type_explorer:: Directory that contains the type explorers. Available for: type explorer +ENVIRONMENT VARIABLES (FOR WRITING) +----------------------------------- +The following environment variables influence the behaviour of cdist: + +require:: + Setup dependencies between objects (see cdist-manifest(7)) + +CDIST_OVERRIDE:: + Allow overwriting type parameters (see cdist-manifest(7)) + +CDIST_ORDER_DEPENDENCY:: + Create dependencies based on the execution order (see cdist-manifest(7)) SEE ALSO -------- @@ -216,6 +249,6 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +Copyright \(C) 2011-2014 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). eof diff --git a/docs/man/man1/cdist.text b/docs/man/man1/cdist.text index 113454a7..e8c12991 100644 --- a/docs/man/man1/cdist.text +++ b/docs/man/man1/cdist.text @@ -5,40 +5,51 @@ Nico Schottelius NAME ---- -cdist - Configuration management +cdist - Usable Configuration Management SYNOPSIS -------- -cdist [-h] [-V] +cdist [-h] [-d] [-v] [-V] {banner,config,shell} ... -cdist banner +cdist banner [-h] [-d] [-v] cdist config [-h] [-d] [-V] [-c CONF_DIR] [-i MANIFEST] [-p] [-s] host [host ...] +cdist shell [-h] [-d] [-v] [-s SHELL] DESCRIPTION ----------- cdist is the frontend executable to the cdist configuration management. -cdist supports different as explained below. The options to the main -program are: +cdist supports different subcommands as explained below. + +GENERAL +------- +All commands except the following options: + +-d, --debug:: + Set log level to debug -h, --help:: Show the help screen +-v, --verbose: + Set log level to info, be more verbose + -V, --version:: Show version and exit BANNER -------- -Displays the cdist banner. +------ +Displays the cdist banner. Useful for printing +cdist posters - a must have for every office. CONFIG ------ -Configure a system +Configure one or more hosts -h, --help:: Show the help screen @@ -52,9 +63,6 @@ Configure a system --conf-dir argument have higher precedence over those set through the environment variable. --d, --debug:: - Enable debug output - -i MANIFEST, --initial-manifest MANIFEST:: Path to a cdist manifest or - to read from stdin @@ -70,20 +78,30 @@ Configure a system --remote-exec REMOTE_EXEC: Command to use for remote execution (should behave like ssh) +SHELL +----- +This command allows you to spawn a shell that enables access +to the types as commands. It can be thought as an +"interactive manifest" environment. See below for example +usage. Its primary use is for debugging type parameters. + +-s/--shell:: + Select shell to use, defaults to current shell + EXAMPLES -------- -------------------------------------------------------------------------------- # Configure ikq05.ethz.ch with debug enabled -cdist config -d ikq05.ethz.ch +% cdist config -d ikq05.ethz.ch # Configure hosts in parallel and use a different configuration directory -cdist config -c ~/p/cdist-nutzung \ +% cdist config -c ~/p/cdist-nutzung \ -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch # Use custom remote exec / copy commands -cdist config --remote-exec /path/to/my/remote/exec \ +% cdist config --remote-exec /path/to/my/remote/exec \ --remote-copy /path/to/my/remote/copy \ -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch @@ -91,20 +109,34 @@ cdist config --remote-exec /path/to/my/remote/exec \ cdist banner # Show help -cdist --help +% cdist --help # Show Version -cdist --version +% cdist --version + +# Enter a shell that has access to emulated types +% cdist shell +% __git +usage: __git --source SOURCE [--state STATE] [--branch BRANCH] + [--group GROUP] [--owner OWNER] [--mode MODE] object_id + + -------------------------------------------------------------------------------- ENVIRONMENT ----------- TMPDIR, TEMP, TMP:: - Setup the base directory for the temporary directory. - See http://docs.python.org/py3k/library/tempfile.html for - more information. This is rather useful, if the standard - directory used does not allow executables. + Setup the base directory for the temporary directory. + See http://docs.python.org/py3k/library/tempfile.html for + more information. This is rather useful, if the standard + directory used does not allow executables. + +CDIST_LOCAL_SHELL:: + Selects shell for local script execution, defaults to /bin/sh + +CDIST_REMOTE_SHELL:: + Selects shell for remote scirpt execution, defaults to /bin/sh EXIT STATUS @@ -125,5 +157,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-best-practice.text b/docs/man/man7/cdist-best-practice.text index 818c423a..a818be60 100644 --- a/docs/man/man7/cdist-best-practice.text +++ b/docs/man/man7/cdist-best-practice.text @@ -118,7 +118,7 @@ The following **.git/config** is taken from a a real world scenario: url = git://git.schottelius.org/cdist fetch = +refs/heads/*:refs/remotes/upstream/* -# Same as upstream, but works when being offline +# Same as upstream, but works when being offline [remote "local"] fetch = +refs/heads/*:refs/remotes/local/* url = /home/users/nico/p/cdist @@ -164,10 +164,10 @@ 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 +* create directory files/ in your type (convention) +* create the template as an executable file like files/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 @@ -182,19 +182,58 @@ server { 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" --------------------------------------------------------------------------------------- + "$__type/files/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" +-------------------------------------------------------------------------------- + + +TESTING A NEW TYPE +------------------ +If you want to test a new type on a node, you can tell cdist to only use an +object of this type: Use the '--initial-manifest' parameter +with - (stdin) as argument and feed object into stdin +of cdist: + +-------------------------------------------------------------------------------- +# Singleton type without parameter +echo __ungleich_munin_server | cdist --initial-manifest - munin.panter.ch + +# Singleton type with parameter +echo __ungleich_munin_node --allow 1.2.3.4 | \ + cdist --initial-manifest - rails-19.panter.ch + +# Normal type +echo __file /tmp/stdintest --mode 0644 | \ + cdist --initial-manifest - cdist-dev-01.ungleich.ch +-------------------------------------------------------------------------------- + + +OTHER CONTENT IN CDIST REPOSITORY +--------------------------------- +Usually the cdist repository contains all configuration +items. Sometimes you may have additional resources that +you would like to store in your central configuration +repositiory (like password files from KeepassX, +Libreoffice diagrams, etc.). + +It is recommended to use a subfolder named "non-cdist" +in the repository for such content: It allows you to +easily distinguish what is used by cdist and what not +and also to store all important files in one +repository. + SEE ALSO -------- @@ -204,5 +243,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-bootstrap.text b/docs/man/man7/cdist-bootstrap.text index 7e1bff0f..985d0f53 100644 --- a/docs/man/man7/cdist-bootstrap.text +++ b/docs/man/man7/cdist-bootstrap.text @@ -64,11 +64,11 @@ So **2.0** is the latest version branch in this example. All versions (2.0.x) within one version branch (2.0) are compatible to each other and won't break your configuration when updating. -It's up to you decide on which branch you want to base your own work: +It's up to you to decide which branch you want to base your own work on: master contains more recent changes, newer types, but may also break. -The versions branches are stable, but thus may miss the latest features. +The version branches are stable, but may lack the latest features. Your decision can be changed later on, but may result in merge conflicts, -which you'd have to solve. +which you will need to solve. Let's assume you want latest stuff and select the master branch as base for your own work. Now it's time to create your branch, which contains your diff --git a/docs/man/man7/cdist-hacker.text b/docs/man/man7/cdist-hacker.text index d0f9a399..2cbf5a8b 100644 --- a/docs/man/man7/cdist-hacker.text +++ b/docs/man/man7/cdist-hacker.text @@ -33,7 +33,6 @@ nearby, so grepping for FIXME gives all positions that need to be fixed. Indention is 4 spaces (welcome to the python world). - HOW TO SUBMIT STUFF FOR INCLUSION INTO UPSTREAM CDIST ----------------------------------------------------- If you did some cool changes to cdist, which you value as a benefit for @@ -51,7 +50,7 @@ work nor kill the authors brain: - On a merge request, always name the branch I should pull from - Always ensure **all** manpages build. Use **./build man** to test. - If you developed more than **one** feature, consider submitting them in - seperate branches. This way one feature can already be included, even if + separate 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, write a mail @@ -75,14 +74,91 @@ code and thus such a type introduces redundant functionality that is given by core cdist already. +EXAMPLE GIT WORKFLOW +--------------------- +The following workflow works fine for most developers: + +-------------------------------------------------------------------------------- +# get latest upstream master branch +git clone https://github.com/telmich/cdist.git + +# update if already existing +cd cdist; git fetch -v; git merge origin/master + +# create a new branch for your feature/bugfix +cd cdist # if you haven't done before +git checkout -b documentation_cleanup + +# *hack* +*hack* + +# clone the cdist repository on github if you haven't done so + +# configure your repo to know about your clone (only once) +git remote add github git@github.com:YOURUSERNAME/cdist.git + +# push the new branch to github +git push github documentation_cleanup + +# (or everything) +git push --mirror github + +# create a pull request at github (use a browser) +# *fixthingsbecausequalityassurancefoundissuesinourpatch* +*hack* + +# push code to github again +git push ... # like above + +# add comment that everything should be green now (use a browser) + +# go back to master branch +git checkout master + +# update master branch that includes your changes now +git fetch -v origin +git diff master..origin/master +git merge origin/master +-------------------------------------------------------------------------------- + +If at any point you want to go back to the original master branch, you can +use **git stash** to stash your changes away: + +-------------------------------------------------------------------------------- +# assume you are on documentation_cleanup +git stash + +# change to master and update to most recent upstream version +git checkout master +git fetch -v origin +git merge origin/master +-------------------------------------------------------------------------------- + +Similar when you want to develop another new feature, you go back +to the master branch and create another branch based on it: + +-------------------------------------------------------------------------------- +# change to master and update to most recent upstream version +git checkout master +git fetch -v origin +git merge origin/master + +git checkout -b another_feature +-------------------------------------------------------------------------------- + +(you can repeat the code above for as many features as you want to develop +in parallel) SEE ALSO -------- - cdist(7) +- git(1) +- git-checkout(1) +- git-stash(1) COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 19f6053e..057905ea 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -11,7 +11,7 @@ cdist-manifest - (Re-)Use types DESCRIPTION ----------- Manifests are used to define which objects to create. -Objects are instances of **types**, like in object orientated programming languages. +Objects are instances of **types**, like in object oriented programming languages. An object is represented by the combination of **type + slash + object name**: **__file/etc/cdist-configured** is an object of the type ***__file*** with the name ***etc/cdist-configured***. @@ -25,8 +25,8 @@ the reference with pointers to the manpages. Types in manifests are used like normal command line tools. Let's have a look at an example: -------------------------------------------------------------------------------- -# Create object of type __package with the parameter state = removed -__package apache2 --state removed +# Create object of type __package with the parameter state = absent +__package apache2 --state absent # Same with the __directory type __directory /tmp/cdist --state present @@ -57,9 +57,9 @@ 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. -Cdist searches for the initial manifest at **cdist/conf/manifest/init**. +Cdist expects the initial manifest at **cdist/conf/manifest/init**. -Within this initial manifest, you define, which objects should be +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: @@ -107,7 +107,7 @@ DEPENDENCIES ------------ If you want to describe that something requires something else, just setup the variable "require" to contain the requirements. Multiple -requirements can be added white space seperated. +requirements can be added white space separated. -------------------------------------------------------------------------------- # No dependency @@ -128,6 +128,38 @@ All objects that are created in a type manifest are automatically required from the type that is calling them. This is called "autorequirement" in cdist jargon. +CREATE DEPENDENCIES FROM EXECUTION ORDER +----------------------------------------- +You can tell cdist to execute all types in the order in which they are created +in the manifest by setting up the variable CDIST_ORDER_DEPENDENCY. +When cdist sees that this variable is setup, the current created object +automatically depends on the previously created object. + +It essentially helps you to build up blocks of code that build upon each other +(like first creating the directory xyz than the file below the directory). + +THIS IS A BETA FEATURE AND MAY BE REMOVED OR CHANGED AT ANY TIME. + + +OVERRIDES +--------- +In some special cases, you would like to create an already defined object +with different parameters. In normal situations this leads to an error in cdist. +If you whish, you can setup the environment variable CDIST_OVERRIDE +(any value or even empty is ok) to tell cdist, that this object override is +wanted and should be accepted. +ATTENTION: Only use this feature if you are 100% sure in which order +cdist encounter the affected objects, otherwhise this results +into an undefined situation. + +If CDIST_OVERRIDE and CDIST_ORDER_DEPENDENCY is set for an object, +CDIST_ORDER_DEPENDENCY will be ignored, because adding a dependency in case of +overrides would result in circular dependencies, which is an error. + +THIS IS A BETA FEATURE AND MAY BE REMOVED OR CHANGED AT ANY TIME. + + + EXAMPLES -------- @@ -135,12 +167,12 @@ The initial manifest may for instance contain the following code: -------------------------------------------------------------------------------- # Always create this file, so other sysadmins know cdist is used. -__file /etc/cdist-configured --type file +__file /etc/cdist-configured case "$__target_host" in my.server.name) - __file /root/bin/ --type directory - __file /etc/issue.net --type file --source "$__manifest/issue.net + __directory /root/bin/ + __file /etc/issue.net --source "$__manifest/issue.net ;; esac -------------------------------------------------------------------------------- @@ -148,9 +180,64 @@ esac The manifest of the type "nologin" may look like this: -------------------------------------------------------------------------------- -__file /etc/nologin --type file --source "$__type/files/default.nologin" +__file /etc/nologin --source "$__type/files/default.nologin" -------------------------------------------------------------------------------- +This example makes use of dependencies: + +-------------------------------------------------------------------------------- +# Ensure that lighttpd is installed +__package lighttpd --state present +# Ensure that munin makes use of lighttpd instead of the default webserver +# package as decided by the package manager +require="__package/lighttpd" __package munin --state present +-------------------------------------------------------------------------------- + +How to override objects: + +-------------------------------------------------------------------------------- +# for example in the inital manifest + +# reate user account foobar with some hash for password +__user foobar --password 'some_fancy_hash' --home /home/foobarexample + +# ... many statements and includes in the manifest later ... +# somewhere in a conditionaly sourced manifest +# (e.g. for example only sourced if a special application is on the target host) + +# this leads to an error ... +__user foobar --password 'some_other_hash' + +# this tells cdist, that you know that this is an override and should be accepted +CDIST_OVERRIDE=yes __user foobar --password 'some_other_hash' +# its only an override, means the parameter --home is not touched +# and stay at the original value of /home/foobarexample +-------------------------------------------------------------------------------- + +Dependencies defined by execution order work as following: + +-------------------------------------------------------------------------------- + +# Tells cdist to execute all types in the order in which they are created ... +export CDIST_ORDER_DEPENDENCY=on +__sample_type 1 +require="__some_type_somewhere/id" __sample_type 2 +__example_type 23 +# Now this types are executed in the creation order until the variable is unset +unset CDIST_ORDER_DEPENDENCY +# all now following types cdist makes the order .. +__not_in_order_type 42 + +# how it works : +# this lines above are translated to: +__sample_type 1 +require="__some_type_somewhere/id __sample_type/1" __sample_type 2 +require="__sample_type/2" __example_type 23 +__not_in_order_type 42 + +-------------------------------------------------------------------------------- + + SEE ALSO -------- @@ -160,5 +247,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2010-2012 Nico Schottelius. Free use of this software is +Copyright \(C) 2010-2014 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-messaging.text b/docs/man/man7/cdist-messaging.text new file mode 100644 index 00000000..0e53871e --- /dev/null +++ b/docs/man/man7/cdist-messaging.text @@ -0,0 +1,72 @@ +cdist-messaging(7) +================== +Nico Schottelius + +NAME +---- +cdist-messaging - How the initial manifest and types can communication + + +DESCRIPTION +----------- +cdist has a simple but powerful way of allowing communication between +the initial manifest and types as well as types and types. + +Whenever execution is passed from cdist to one of the +scripts described below, cdist generate 2 new temporary files +and exports the environment variables __messages_in and +__messages_out to point to them. + +Before handing over the control, the content of the global message +file is copied into the file referenced by $__messages_in. + +After cdist gained control back, the content of the file referenced +by $__messages_out is appended to the global message file. + +This way overwriting any of the two files by accident does not +interfere with other types. + +The order of execution is not defined unless you create dependencies +between the different objects (see cdist-manifest(7)) and thus you +can only react reliably on messages by objects that you depend on. + + +AVAILABILITY +------------ +Messaging is possible between all **local** scripts: + +- initial manifest +- type/manifest +- type/gencode-local +- type/gencode-remote + + +EXAMPLES +-------- +When you want to emit a message use: + +-------------------------------------------------------------------------------- +echo "something" >> "$__messages_out" +-------------------------------------------------------------------------------- + +When you want to react on a message use: + +-------------------------------------------------------------------------------- +if grep -q "^__your_type/object/id:something" "$__messages_in"; then + echo "I do something else" +fi +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist(1) +- cdist-manifest(7) +- cdist-reference(7) +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2013 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-quickstart.text b/docs/man/man7/cdist-quickstart.text index b718da64..8b754650 100644 --- a/docs/man/man7/cdist-quickstart.text +++ b/docs/man/man7/cdist-quickstart.text @@ -72,7 +72,9 @@ As soon as you are able to login without password to localhost, 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 +# Get cdist +# Mirrors can be found on +# http://www.nico.schottelius.org/software/cdist/install/#index2h4 git clone git://git.schottelius.org/cdist # Create manifest (maps configuration to host(s) diff --git a/docs/man/man7/cdist-stages.text b/docs/man/man7/cdist-stages.text index fa5e28d1..5f2d2e4c 100644 --- a/docs/man/man7/cdist-stages.text +++ b/docs/man/man7/cdist-stages.text @@ -33,7 +33,7 @@ be created, if it has different parameters. STAGE 3: OBJECT INFORMATION RETRIEVAL ------------------------------------- Every object is checked whether its type has explorers and if so, these are -executed on the target host. The results are transfered back +executed on the target host. The results are transferred back and can be used in the following stages to decide what changes need to be made on the target to implement the desired state. diff --git a/docs/man/man7/cdist-troubleshooting.text b/docs/man/man7/cdist-troubleshooting.text new file mode 100644 index 00000000..7c5e7612 --- /dev/null +++ b/docs/man/man7/cdist-troubleshooting.text @@ -0,0 +1,63 @@ +cdist-troubleshooting(7) +======================== +Nico Schottelius + + +NAME +---- +cdist-troubleshooting - common problems and their solutions + + +ERROR IN MANIFEST IS NOT CONSIDERED AN ERROR BY CDIST +----------------------------------------------------- +Situation: You are executing other scripts from a manifest. +This script fails, but cdist does not recognise the error. +An example script would be something like this: + +-------------------------------------------------------------------------------- +% cat ~/.cdist/manifest/init +"$__manifest/special" +% cat ~/.cdist/manifest/special +#!/bin/sh +echo "Here is an unclean exiting script" +somecommandthatdoesnotexist +echo "I continue here although previous command failed" +-------------------------------------------------------------------------------- + +We can clearly see that **somecommandthatdoesnotexist** +will fail in ~/.cdist/manifest/special. But as the custom +script is not called with the -e flag (exit on failure) of shell, +it does not lead to an error. And thus cdist sees the exit 0 +code of the last echo line instead of the failing command. + +All scripts executed by cdist carry the -e flag. +To prevent the above from happening, there are three solutions available, +two of which can be used in the calling script: +-------------------------------------------------------------------------------- +# Execute as before, but abort on failure +sh -e "$__manifest/special" + +# Source the script in our namespace, runs in a set -e environment: +. "$__manifest/special" +-------------------------------------------------------------------------------- + +The third solution is to include a shebang header in every script +you write to use the -e flag: + +-------------------------------------------------------------------------------- +% cat ~/.cdist/manifest/special +#!/bin/sh -e +... +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist(1) +- cdist-tutorial(7) + + +COPYING +------- +Copyright \(C) 2013 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-type.text b/docs/man/man7/cdist-type.text index 54b67be5..8415f991 100644 --- a/docs/man/man7/cdist-type.text +++ b/docs/man/man7/cdist-type.text @@ -67,25 +67,31 @@ A type consists of Types are stored below cdist/conf/type/. Their name should always be prefixed with two underscores (__) to prevent collisions with other executables in $PATH. -To begin a new type, just create the directory **cdist/conf/type/__NAME**. +To implement a new type, create the directory **cdist/conf/type/__NAME**. DEFINING PARAMETERS ------------------- Every type consists of required, optional and boolean parameters, which must -be created in a newline seperated file in ***parameter/required***, +each be declared in a newline separated file in ***parameter/required***, ***parameter/required_multiple***, ***parameter/optional***, ***parameter/optional_multiple*** and ***parameter/boolean***. Parameters which are allowed multiple times should be listed in -required_multiple or optional_multiple respectively. For all other parameters -the standard unix behaviour of the last given wins is applied. +required_multiple or optional_multiple respectively. All other parameters +follow the standard unix behaviour "the last given wins". If either is missing, the type will have no required, no optional, no boolean or no parameters at all. +Default values for optional parameters can be predefined in +***parameter/default/***. + Example: -------------------------------------------------------------------------------- echo servername >> cdist/conf/type/__nginx_vhost/parameter/required echo logdirectory >> cdist/conf/type/__nginx_vhost/parameter/optional +echo loglevel >> cdist/conf/type/__nginx_vhost/parameter/optional +mkdir cdist/conf/type/__nginx_vhost/parameter/default +echo warning > cdist/conf/type/__nginx_vhost/parameter/default/loglevel echo server_alias >> cdist/conf/type/__nginx_vhost/parameter/optional_multiple echo use_ssl >> cdist/conf/type/__nginx_vhost/parameter/boolean -------------------------------------------------------------------------------- @@ -108,6 +114,9 @@ if [ -f "$__object/parameter/logdirectory" ]; then logdirectory="$(cat "$__object/parameter/logdirectory")" fi +# optional parameter with predefined default +loglevel="$(cat "$__object/parameter/loglevel")" + # boolean parameter if [ -f "$__object/parameter/use_ssl" ]; then # file exists -> True @@ -125,7 +134,7 @@ fi INPUT FROM STDIN ------------------ +---------------- Every type can access what has been written on stdin when it has been called. The result is saved into the ***stdin*** file in the object directory. @@ -141,6 +150,7 @@ If you have not seen this syntax (<< eof) before, it may help you to read about "here documents". In the __file type, stdin is used as source for the file, if - is used for source: + -------------------------------------------------------------------------------- if [ -f "$__object/parameter/source" ]; then source="$(cat "$__object/parameter/source")" @@ -229,7 +239,7 @@ 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. -If the gencode scripts encounter an error, it should print diagnostic +If the gencode scripts encounters an error, it should print diagnostic messages to stderr and exit non-zero. If you need to debug the gencode script, you can write to stderr: diff --git a/docs/speeches/2012-12-11_lisa.odp b/docs/speeches/2012-12-11_lisa.odp new file mode 100644 index 00000000..45c78955 Binary files /dev/null and b/docs/speeches/2012-12-11_lisa.odp differ diff --git a/docs/speeches/2013-01-23_panter.notes b/docs/speeches/2013-01-23_panter.notes new file mode 100644 index 00000000..d223c7bc --- /dev/null +++ b/docs/speeches/2013-01-23_panter.notes @@ -0,0 +1,10 @@ +sexy & sexy: ein glückliches Paar + +inhalt vom vortrag + +ziele von sexy und cdist + + systemadministration hochgradig zu automatisieren + effizientes (tägliches) arbeiten + + diff --git a/docs/speeches/2013-01-23_panter.odp b/docs/speeches/2013-01-23_panter.odp new file mode 100644 index 00000000..7fa0e4c7 Binary files /dev/null and b/docs/speeches/2013-01-23_panter.odp differ diff --git a/docs/speeches/2013-03-25_ad_novum.odp b/docs/speeches/2013-03-25_ad_novum.odp new file mode 100644 index 00000000..305f0a5e Binary files /dev/null and b/docs/speeches/2013-03-25_ad_novum.odp differ diff --git a/docs/speeches/2013-10-05_ossawards.odp b/docs/speeches/2013-10-05_ossawards.odp new file mode 100644 index 00000000..d0e4511c Binary files /dev/null and b/docs/speeches/2013-10-05_ossawards.odp differ diff --git a/docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys.png b/docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys.png new file mode 100644 index 00000000..d5b9586a Binary files /dev/null and b/docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys.png differ diff --git a/docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys1comp.png b/docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys1comp.png new file mode 100644 index 00000000..f61d232c Binary files /dev/null and b/docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys1comp.png differ diff --git a/docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys4comp.png b/docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys4comp.png new file mode 100644 index 00000000..5b37e094 Binary files /dev/null and b/docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys4comp.png differ diff --git a/docs/speeches/2013-10-05_ossawards/ossawards-2013-4comp.png b/docs/speeches/2013-10-05_ossawards/ossawards-2013-4comp.png new file mode 100644 index 00000000..392eeeb8 Binary files /dev/null and b/docs/speeches/2013-10-05_ossawards/ossawards-2013-4comp.png differ diff --git a/docs/speeches/2013-10-05_ossawards/ossawards-2013-4sys.png b/docs/speeches/2013-10-05_ossawards/ossawards-2013-4sys.png new file mode 100644 index 00000000..5da1785a Binary files /dev/null and b/docs/speeches/2013-10-05_ossawards/ossawards-2013-4sys.png differ diff --git a/docs/speeches/2013-10-05_ossawards/ossawards-2013-sys-cdist.png b/docs/speeches/2013-10-05_ossawards/ossawards-2013-sys-cdist.png new file mode 100644 index 00000000..5fa66641 Binary files /dev/null and b/docs/speeches/2013-10-05_ossawards/ossawards-2013-sys-cdist.png differ diff --git a/docs/speeches/2013-10-05_ossawards/ossawards-2013-sys-chairman.png b/docs/speeches/2013-10-05_ossawards/ossawards-2013-sys-chairman.png new file mode 100644 index 00000000..01071950 Binary files /dev/null and b/docs/speeches/2013-10-05_ossawards/ossawards-2013-sys-chairman.png differ diff --git a/docs/speeches/2013-10-05_ossawards/ossawards-2013.xoj b/docs/speeches/2013-10-05_ossawards/ossawards-2013.xoj new file mode 100644 index 00000000..ce55c8b1 Binary files /dev/null and b/docs/speeches/2013-10-05_ossawards/ossawards-2013.xoj differ diff --git a/docs/speeches/2013-11-22_eth_linux_erfa.odp b/docs/speeches/2013-11-22_eth_linux_erfa.odp new file mode 100644 index 00000000..71d4719b Binary files /dev/null and b/docs/speeches/2013-11-22_eth_linux_erfa.odp differ diff --git a/docs/speeches/2013-11-22_eth_linux_erfa.pdf b/docs/speeches/2013-11-22_eth_linux_erfa.pdf new file mode 100644 index 00000000..3c2430af Binary files /dev/null and b/docs/speeches/2013-11-22_eth_linux_erfa.pdf differ diff --git a/docs/web/cdist/documentation.mdwn b/docs/web/cdist/documentation.mdwn index e5fd9bc9..db25b566 100644 --- a/docs/web/cdist/documentation.mdwn +++ b/docs/web/cdist/documentation.mdwn @@ -4,4 +4,6 @@ You can browse the latest [latest version of the manpages](/software/cdist/man/latest) or have a look at [all versions](/software/cdist/man). +You can also view [speeches about cdist](/software/cdist/speeches). + [[!tag cdist unix]] diff --git a/docs/web/cdist/install.mdwn b/docs/web/cdist/install.mdwn index ad97cd2b..c81354f0 100644 --- a/docs/web/cdist/install.mdwn +++ b/docs/web/cdist/install.mdwn @@ -10,7 +10,7 @@ This is the machine you use to configure the target hosts. * /bin/sh: A posix like shell (for instance bash, dash, zsh) * Python >= 3.2 * SSH client - * Asciidoc (for building the manpages) + * Asciidoc and xsltproc (for building the manpages) ### Target Hosts @@ -45,21 +45,25 @@ For Debian **wheezy** or newer: On **squeeze** you can add following line in **/etc/apt/sources.list** - deb http://ftp.debian.org/debian wheezy main + deb http://ftp.debian.org/debian wheezy main And add pinning entry in **/etc/apt/preferences.d/wheezy**: - Package: * - Pin: release n=wheezy - Pin-Priority: 1 + Package: * + Pin: release n=wheezy + Pin-Priority: 1 Please be aware that both **openssh-server** and **openssh-client** might be removed on **python3.2** installation. You surely want to reinstall them: - apt-get install -t wheezy openssh-server openssh-client + apt-get install -t wheezy openssh-server openssh-client For older Debian versions, installing python 3.2 from source is required. +If you want to build the cdist manpages: + + aptitude install --without-recommends asciidoc xsltproc + ### Fedora Fedora 15 and newer includes a recent python. @@ -139,7 +143,7 @@ To install cdist, execute the following commands: If you want to build and use the manpages, run: - ./build man + make man export MANPATH=$MANPATH:$(pwd -P)/doc/man #### Available versions in git diff --git a/docs/web/cdist/support.mdwn b/docs/web/cdist/support.mdwn index 7515070d..39388c5a 100644 --- a/docs/web/cdist/support.mdwn +++ b/docs/web/cdist/support.mdwn @@ -20,6 +20,6 @@ you can join the ### Commercial support You can request commercial support for cdist from -[my company](http://firma.schottelius.org/english/). +[my company](http://www.ungleich.ch/english/). [[!tag cdist unix]] diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index e486dff9..2e3e9b92 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -14,13 +14,72 @@ If you stay on a version branche (i.e. 1.0, 1.1., ...), nothing should break. The master branch on the other hand is the development branch and may not be working, break your setup or eat the tree in your garden. +### Safely upgrading to new versions + +To upgrade to **any** further cdist version, you can take the +following procedure to do a safe upgrade: + + # Create new branch to try out the update + git checkout -b upgrade_cdist + + # Get latest cdist version in git database + git fetch -v + + # see what will happen on merge - replace + # master with the branch you plan to merge + git diff upgrade_cdist..origin/master + + # Merge the new version + git merge origin/master + +Now you can ensure all custom types work with the new version. +Assume that you need to go back to an older version during +the migration/update, you can do so as follows: + + # commit changes + git commit -m ... + + # go back to original branch + git checkout master + +After that, you can go back and continue the upgrade: + + # git checkout upgrade_cdist + + ## Update The Python Package To upgrade to the lastet version do pip install --upgrade cdist -## Update Instructions +## General Update Instructions + +### Updating from 2.3 to 3.0 + +The **changed** attribute of objects has been removed. +Use [messaging](/software/cdist/man/3.0.0/man7/cdist-messaging.html) instead. + +### Updating from 2.2 to 2.3 + +No incompatiblities. + +### Updating from 2.1 to 2.2 + +Starting with 2.2, the syntax for requiring a singleton type changed: +Old format: + + require="__singleton_type/singleton" ... + +New format: + + require="__singleton_type" ... + +Internally the "singleton" object id was dropped to make life more easy. +You can probably fix your configuration by running the following code +snippet (currently untested, please report back if it works for you): + + find ~/.cdist/* -type f -exec sed -i 's,/singleton,,' {} \; ### Updating from 2.0 to 2.1 @@ -46,7 +105,6 @@ Have a look at the update guide for [[2.0 to 2.1|2.0-to-2.1]]. * Type **\_\_user**: Parameter --groups removed (use the new \_\_user_groups type) * Type **\_\_ssh_authorized_key** has been replaced by more flexible type **\_\_ssh_authorized_keys** - * require="" is deprecated: Use --after and --before as parameters instead ### Updating from 1.7 to 2.0 diff --git a/docs/web/cdist/why.mdwn b/docs/web/cdist/why.mdwn index 6dcfd441..f571555c 100644 --- a/docs/web/cdist/why.mdwn +++ b/docs/web/cdist/why.mdwn @@ -42,7 +42,8 @@ in almost all cases all dependencies are usually fulfilled. Cdist does not require an agent or a high level programming languages on the target host: it will run on any host that has a **ssh server running** and a posix compatible shell -(**/bin/sh**). +(**/bin/sh**). Compared to other configuration management systems, +it does not require to open up an additional port. ## Push based distribution diff --git a/other/examples/remote/local/copy b/other/examples/remote/local/copy index 644fee15..0cec3643 100755 --- a/other/examples/remote/local/copy +++ b/other/examples/remote/local/copy @@ -1,6 +1,7 @@ #!/bin/sh # # 2012 Nico Schottelius (nico-cdist schottelius.org) +# 2013 Steven Armstrong (steven-cdist armstrong.cc) # # This file is part of cdist. # @@ -19,9 +20,5 @@ # # -recursive=$1; shift -src=$1; shift -dst=$1; shift - -dst=$(echo $dst | sed "s/^${__target_host}://") -cp "$recursive" "$src" "$dst" +code="$(echo "$@" | sed "s|\([[:space:]]\)$__target_host:|\1|g")" +cp --dereference $code diff --git a/other/examples/remote/sudo/copy b/other/examples/remote/sudo/copy new file mode 100755 index 00000000..577f270e --- /dev/null +++ b/other/examples/remote/sudo/copy @@ -0,0 +1,51 @@ +#!/bin/sh +# +# 2012 Matt Coddington (mcoddington at gmail.com) +# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2013 Chase Allen James (nx-cdist at nu-ex.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. Uses the "--rsync-path" option +# to run the remote rsync instance with sudo. +# +# This command assumes your ssh configuration is already set up +# in ~/.ssh/config. +# +# Usage: +# cdist config --remote-copy /path/to/this/script target_host +# + +# For rsync to do the right thing, the source has to end with "/" if it is +# a directory. The below preprocessor loop takes care of that. + +# second last argument is the source +source_index=$(($#-1)) +index=0 +for arg in $@; do + if [ $index -eq 0 ]; then + # reset $@ + set -- + fi + index=$((index+=1)) + if [ $index -eq $source_index -a -d "$arg" ]; then + arg="${arg%/}/" + fi + set -- "$@" "$arg" +done + +rsync --copy-links --rsync-path="sudo rsync" -e 'ssh' "$@" diff --git a/other/examples/remote/sudo/exec b/other/examples/remote/sudo/exec new file mode 100755 index 00000000..90eae2da --- /dev/null +++ b/other/examples/remote/sudo/exec @@ -0,0 +1,30 @@ +#!/bin/sh +# +# 2013 Chase Allen James (nx-cdist at nu-ex.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 . +# +# Prefixes all remote commands with sudo. +# +# This command assumes your ssh configuration is already set up +# in ~/.ssh/config. +# +# Usage: +# cdist config --remote-exec "/path/to/this/script" target_host +# + +host="$1"; shift +ssh -q "$host" sudo sh -c \""$@"\" diff --git a/scripts/cdist b/scripts/cdist index fd18933a..39449666 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -26,7 +26,7 @@ def commandline(): import cdist.banner import cdist.config - import cdist.install + import cdist.shell # Construct parser others can reuse parser = {} @@ -52,42 +52,44 @@ def commandline(): parents=[parser['loglevel']]) parser['banner'].set_defaults(func=cdist.banner.banner) - # Config and install (common stuff) - parser['configinstall'] = argparse.ArgumentParser(add_help=False) - parser['configinstall'].add_argument('host', nargs='+', - help='one or more hosts to operate on') - parser['configinstall'].add_argument('-c', '--conf-dir', - help='Add configuration directory (can be repeated, last one wins)', - action='append') - parser['configinstall'].add_argument('-i', '--initial-manifest', - help='Path to a cdist manifest or \'-\' to read from stdin.', - dest='manifest', required=False) - parser['configinstall'].add_argument('-p', '--parallel', - help='Operate on multiple hosts in parallel', - action='store_true', dest='parallel') - parser['configinstall'].add_argument('-s', '--sequential', - help='Operate on multiple hosts sequentially (default)', - action='store_false', dest='parallel') - - parser['configinstall'].add_argument('--remote-copy', - help='Command to use for remote copy (should behave like scp)', - action='store', dest='remote_copy', - default="scp -o User=root -q") - parser['configinstall'].add_argument('--remote-exec', - help='Command to use for remote execution (should behave like ssh)', - action='store', dest='remote_exec', - default="ssh -o User=root -q") - # Config parser['config'] = parser['sub'].add_parser('config', - parents=[parser['loglevel'], parser['configinstall']]) - parser['config'].set_defaults(func=config) + parents=[parser['loglevel']]) + parser['config'].add_argument('host', nargs='+', + help='one or more hosts to operate on') + parser['config'].add_argument('-c', '--conf-dir', + help='Add configuration directory (can be repeated, last one wins)', + action='append') + parser['config'].add_argument('-i', '--initial-manifest', + help='Path to a cdist manifest or \'-\' to read from stdin.', + dest='manifest', required=False) + parser['config'].add_argument('-n', '--dry-run', + help='Do not execute code', action='store_true') + parser['config'].add_argument('-o', '--out-dir', + help='Directory to save cdist output in', dest="out_path") + parser['config'].add_argument('-p', '--parallel', + help='Operate on multiple hosts in parallel', + action='store_true', dest='parallel') + parser['config'].add_argument('-s', '--sequential', + help='Operate on multiple hosts sequentially (default)', + action='store_false', dest='parallel') + parser['config'].add_argument('--remote-copy', + help='Command to use for remote copy (should behave like scp)', + action='store', dest='remote_copy', + default=cdist.REMOTE_COPY) + parser['config'].add_argument('--remote-exec', + help='Command to use for remote execution (should behave like ssh)', + action='store', dest='remote_exec', + default=cdist.REMOTE_EXEC) + parser['config'].set_defaults(func=cdist.config.Config.commandline) + + # Shell + parser['shell'] = parser['sub'].add_parser('shell', + parents=[parser['loglevel']]) + parser['shell'].add_argument('-s', '--shell', + help='Select shell to use, defaults to current shell') + parser['shell'].set_defaults(func=cdist.shell.Shell.commandline) - # Install - # 20120525/sar: commented until it actually does something - #parser['install'] = parser['sub'].add_parser('install', - # parents=[parser['loglevel'], parser['configinstall']]) - #parser['install'].set_defaults(func=install) for p in parser: parser[p].epilog = "Get cdist at http://www.nico.schottelius.org/software/cdist/" @@ -101,106 +103,24 @@ def commandline(): logging.root.setLevel(logging.DEBUG) log.debug(args) - args.func(args) + log.info("version %s" % cdist.VERSION) -def config(args): - configinstall(args, mode=cdist.config.Config) + # Work around python 3.3 bug: + # http://bugs.python.org/issue16308 + # http://bugs.python.org/issue9253 -def install(args): - configinstall(args, mode=cdist.install.Install) - -def configinstall(args, mode): - """Configure or install remote system""" - import multiprocessing - import time - - initial_manifest_tempfile = None - if args.manifest == '-': - # read initial manifest from stdin - import tempfile - 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)) - - 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: - try: - configinstall_onehost(host, args, mode, parallel=False) - except cdist.Error as e: - failed_hosts.append(host) - - # 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 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)) - - 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""" + # FIXME: catching AttributeError also hides + # real problems.. try a different way + # FIXME: we always print main help, not + # the help of the actual parser being used! try: - import cdist.context + getattr(args, "func") + except AttributeError: + parser['main'].print_help() + sys.exit(0) - context = cdist.context.Context( - target_host=host, - remote_copy=args.remote_copy, - remote_exec=args.remote_exec, - initial_manifest=args.manifest, - add_conf_dirs=args.conf_dir, - exec_path=sys.argv[0], - debug=args.debug) - - c = mode(context) - c.deploy_and_cleanup() - context.cleanup() - - except cdist.Error as e: - context.log.error(e) - # We are running in our own process here, need to sys.exit! - if parallel: - sys.exit(1) - else: - raise - - 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""" - import cdist.emulator - emulator = cdist.emulator.Emulator(sys.argv) - return emulator.run() + args.func(args) if __name__ == "__main__": # Sys is needed for sys.exit() @@ -208,8 +128,8 @@ if __name__ == "__main__": cdistpythonversion = '3.2' if sys.version < cdistpythonversion: - print('Cdist requires Python >= ' + cdistpythonversion + - ' on the source host.', file=sys.stderr) + print('Python >= ' + cdistpythonversion + + ' is required on the source host.', file=sys.stderr) sys.exit(1) @@ -220,22 +140,24 @@ if __name__ == "__main__": import os import re import cdist + import cdist.log - log = logging.getLogger("cdist") + logging.setLoggerClass(cdist.log.Log) logging.basicConfig(format='%(levelname)s: %(message)s') + log = logging.getLogger("cdist") if re.match("__", os.path.basename(sys.argv[0])): - emulator() + import cdist.emulator + emulator = cdist.emulator.Emulator(sys.argv) + emulator.run() else: commandline() except KeyboardInterrupt: - pass + exit_code = 2 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/setup.py b/setup.py index 25fc4820..c484a269 100644 --- a/setup.py +++ b/setup.py @@ -1,10 +1,21 @@ from distutils.core import setup import cdist import os +import re def data_finder(data_dir): entries = [] for name in os.listdir(data_dir): + + # Skip .gitignore files + if name == ".gitignore": + continue + + # Skip vim swp files + swpfile = re.search(r'^\..*\.swp$', name) + if swpfile: + continue + entry = os.path.join(data_dir, name) if os.path.isdir(entry): entries.extend(data_finder(entry))