forked from ungleich-public/cdist
Compare commits
31 commits
Author | SHA1 | Date | |
---|---|---|---|
|
ed6d26245b | ||
|
94a7975e32 | ||
|
5b9c652221 | ||
|
deaff9c8e7 | ||
|
340df8305c | ||
|
f39a2ba975 | ||
|
42b8a005be | ||
|
1e2440161c | ||
|
55baa0278d | ||
|
b17bf193a9 | ||
|
9e89088e61 | ||
|
cde6a91ef2 | ||
|
bf6ce46c95 | ||
|
b47b9b1ba0 | ||
|
1da9dcce4a | ||
|
6802cd990e | ||
|
17c39ebef5 | ||
|
225f75ca8f | ||
|
77d704113c | ||
|
595cfec572 | ||
|
b7af305636 | ||
|
1588476a91 | ||
|
420aaaee16 | ||
|
a2243cf59e | ||
|
3dcd270158 | ||
|
4a5a475e3e | ||
|
1a5cc67cc8 | ||
|
a094679173 | ||
|
912c675903 | ||
|
9d030bddc1 | ||
|
9a2e5758f5 |
98 changed files with 2136 additions and 1838 deletions
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# 2011-2022 Nico Schottelius (nico-cdist at schottelius.org)
|
# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
|
||||||
# 2016-2019 Darko Poljak (darko.poljak at gmail.com)
|
# 2016-2019 Darko Poljak (darko.poljak at gmail.com)
|
||||||
#
|
#
|
||||||
# This file is part of cdist.
|
# This file is part of cdist.
|
||||||
|
|
|
@ -63,6 +63,9 @@ REMOTE_COPY = "scp -o User=root -q"
|
||||||
REMOTE_EXEC = "ssh -o User=root"
|
REMOTE_EXEC = "ssh -o User=root"
|
||||||
REMOTE_CMDS_CLEANUP_PATTERN = "ssh -o User=root -O exit -S {}"
|
REMOTE_CMDS_CLEANUP_PATTERN = "ssh -o User=root -O exit -S {}"
|
||||||
|
|
||||||
|
ORDER_DEP_STATE_NAME = 'order_dep_state'
|
||||||
|
TYPEORDER_DEP_NAME = 'typeorder_dep'
|
||||||
|
|
||||||
|
|
||||||
MIN_SUPPORTED_PYTHON_VERSION = (3, 5)
|
MIN_SUPPORTED_PYTHON_VERSION = (3, 5)
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import logging
|
||||||
import collections
|
import collections
|
||||||
import functools
|
import functools
|
||||||
import cdist.configuration
|
import cdist.configuration
|
||||||
|
import cdist.trigger
|
||||||
import cdist.log
|
import cdist.log
|
||||||
import cdist.preos
|
import cdist.preos
|
||||||
import cdist.info
|
import cdist.info
|
||||||
|
@ -12,7 +13,7 @@ import cdist.scan.commandline
|
||||||
|
|
||||||
|
|
||||||
# set of beta sub-commands
|
# set of beta sub-commands
|
||||||
BETA_COMMANDS = set(('install', 'inventory', 'scan', ))
|
BETA_COMMANDS = set(('install', 'inventory', 'scan', 'trigger', ))
|
||||||
# set of beta arguments for sub-commands
|
# set of beta arguments for sub-commands
|
||||||
BETA_ARGS = {
|
BETA_ARGS = {
|
||||||
'config': set(('tag', 'all_tagged_hosts', 'use_archiving', )),
|
'config': set(('tag', 'all_tagged_hosts', 'use_archiving', )),
|
||||||
|
@ -472,6 +473,9 @@ def get_parsers():
|
||||||
parser['info'].set_defaults(func=cdist.info.Info.commandline)
|
parser['info'].set_defaults(func=cdist.info.Info.commandline)
|
||||||
|
|
||||||
# Scan = config + further
|
# Scan = config + further
|
||||||
|
parser['scan'] = parser['sub'].add_parser('scan', add_help=False,
|
||||||
|
parents=[parser['config']])
|
||||||
|
|
||||||
parser['scan'] = parser['sub'].add_parser(
|
parser['scan'] = parser['sub'].add_parser(
|
||||||
'scan', parents=[parser['loglevel'],
|
'scan', parents=[parser['loglevel'],
|
||||||
parser['beta'],
|
parser['beta'],
|
||||||
|
@ -509,6 +513,28 @@ def get_parsers():
|
||||||
help='How long (seconds) to wait between ICMPv6 echo requests')
|
help='How long (seconds) to wait between ICMPv6 echo requests')
|
||||||
parser['scan'].set_defaults(func=cdist.scan.commandline.commandline)
|
parser['scan'].set_defaults(func=cdist.scan.commandline.commandline)
|
||||||
|
|
||||||
|
# Trigger
|
||||||
|
parser['trigger'] = parser['sub'].add_parser(
|
||||||
|
'trigger', parents=[parser['loglevel'],
|
||||||
|
parser['beta'],
|
||||||
|
parser['common'],
|
||||||
|
parser['config_main']])
|
||||||
|
parser['trigger'].add_argument(
|
||||||
|
'-D', '--directory', action='store', required=False,
|
||||||
|
help=('Where to create local files'))
|
||||||
|
parser['trigger'].add_argument(
|
||||||
|
'-H', '--http-port', action='store', default=3000, required=False,
|
||||||
|
help=('Create trigger listener via http on specified port'))
|
||||||
|
parser['trigger'].add_argument(
|
||||||
|
'--ipv6', default=False,
|
||||||
|
help=('Listen to both IPv4 and IPv6 (instead of only IPv4)'),
|
||||||
|
action='store_true')
|
||||||
|
parser['trigger'].add_argument(
|
||||||
|
'-O', '--source', action='store', required=False,
|
||||||
|
help=('Which file to copy for creation'))
|
||||||
|
|
||||||
|
parser['trigger'].set_defaults(func=cdist.trigger.Trigger.commandline)
|
||||||
|
|
||||||
for p in parser:
|
for p in parser:
|
||||||
parser[p].epilog = EPILOG
|
parser[p].epilog = EPILOG
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,6 @@
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
case "$("$__explorer/os")" in
|
case "$("$__explorer/os")" in
|
||||||
checkpoint)
|
|
||||||
awk '{printf("%s\n", $(NF-1))}' /etc/cp-release
|
|
||||||
;;
|
|
||||||
openwrt)
|
openwrt)
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
(. /etc/openwrt_release && echo "$DISTRIB_CODENAME")
|
(. /etc/openwrt_release && echo "$DISTRIB_CODENAME")
|
||||||
|
|
|
@ -21,9 +21,6 @@
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
case "$("$__explorer/os")" in
|
case "$("$__explorer/os")" in
|
||||||
checkpoint)
|
|
||||||
cat /etc/cp-release
|
|
||||||
;;
|
|
||||||
openwrt)
|
openwrt)
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
(. /etc/openwrt_release && echo "$DISTRIB_DESCRIPTION")
|
(. /etc/openwrt_release && echo "$DISTRIB_DESCRIPTION")
|
||||||
|
|
|
@ -21,9 +21,6 @@
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
case "$("$__explorer/os")" in
|
case "$("$__explorer/os")" in
|
||||||
checkpoint)
|
|
||||||
echo "CheckPoint"
|
|
||||||
;;
|
|
||||||
openwrt)
|
openwrt)
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
(. /etc/openwrt_release && echo "$DISTRIB_ID")
|
(. /etc/openwrt_release && echo "$DISTRIB_ID")
|
||||||
|
|
|
@ -21,9 +21,6 @@
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
case "$("$__explorer/os")" in
|
case "$("$__explorer/os")" in
|
||||||
checkpoint)
|
|
||||||
sed /etc/cp-release -e 's/.* R\([1-9][0-9]*\)\.[0-9]*$/\1/'
|
|
||||||
;;
|
|
||||||
openwrt)
|
openwrt)
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
(. /etc/openwrt_release && echo "$DISTRIB_RELEASE")
|
(. /etc/openwrt_release && echo "$DISTRIB_RELEASE")
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -116,13 +116,6 @@ if [ -f /etc/slackware-version ]; then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Appliances
|
|
||||||
|
|
||||||
if grep -q '^Check Point Gaia' /etc/cp-release 2>/dev/null; then
|
|
||||||
echo checkpoint
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
uname_s="$(uname -s)"
|
uname_s="$(uname -s)"
|
||||||
|
|
||||||
# Assume there is no tr on the client -> do lower case ourselves
|
# Assume there is no tr on the client -> do lower case ourselves
|
||||||
|
|
|
@ -34,9 +34,5 @@ elif test -f /var/run/os-release
|
||||||
then
|
then
|
||||||
# FreeBSD (created by os-release service)
|
# FreeBSD (created by os-release service)
|
||||||
cat /var/run/os-release
|
cat /var/run/os-release
|
||||||
elif test -f /etc/cp-release
|
|
||||||
then
|
|
||||||
# Checkpoint firewall or management (actually linux based)
|
|
||||||
cat /etc/cp-release
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,6 @@ in
|
||||||
# empty, but well...
|
# empty, but well...
|
||||||
cat /etc/arch-release
|
cat /etc/arch-release
|
||||||
;;
|
;;
|
||||||
checkpoint)
|
|
||||||
awk '{version=$NF; printf("%s\n", substr(version, 2))}' /etc/cp-release
|
|
||||||
;;
|
|
||||||
debian)
|
debian)
|
||||||
debian_version=$(cat /etc/debian_version)
|
debian_version=$(cat /etc/debian_version)
|
||||||
case $debian_version
|
case $debian_version
|
||||||
|
@ -82,7 +79,6 @@ in
|
||||||
# ceres versions don't have a number, so we decode by codename:
|
# ceres versions don't have a number, so we decode by codename:
|
||||||
case ${devuan_version}
|
case ${devuan_version}
|
||||||
in
|
in
|
||||||
(daedalus/ceres) echo 4.99 ;;
|
|
||||||
(chimaera/ceres) echo 3.99 ;;
|
(chimaera/ceres) echo 3.99 ;;
|
||||||
(beowulf/ceres) echo 2.99 ;;
|
(beowulf/ceres) echo 2.99 ;;
|
||||||
(ascii/ceres) echo 1.99 ;;
|
(ascii/ceres) echo 1.99 ;;
|
||||||
|
|
|
@ -24,4 +24,4 @@ else
|
||||||
name="$__object_id"
|
name="$__object_id"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
apt-mark showhold | grep -q "^${name}$" && echo hold || echo unhold
|
apt-mark showhold | grep -Fq "$name" && echo hold || echo unhold
|
||||||
|
|
|
@ -57,11 +57,6 @@ __file "/etc/apt/preferences.d/$name" \
|
||||||
--owner root --group root --mode 0644 \
|
--owner root --group root --mode 0644 \
|
||||||
--state "$state" \
|
--state "$state" \
|
||||||
--source - << EOF
|
--source - << EOF
|
||||||
# Created by cdist ${__type##*/}
|
|
||||||
# Do not change. Changes will be overwritten.
|
|
||||||
#
|
|
||||||
|
|
||||||
# $name
|
|
||||||
Package: $package
|
Package: $package
|
||||||
Pin: $pin
|
Pin: $pin
|
||||||
Pin-Priority: $priority
|
Pin-Priority: $priority
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
500
|
|
|
@ -1,3 +1,2 @@
|
||||||
state
|
state
|
||||||
package
|
package
|
||||||
priority
|
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
distribution
|
distribution
|
||||||
|
priority
|
||||||
|
|
55
cdist/conf/type/__apt_ppa/files/remove-apt-repository
Executable file
55
cdist/conf/type/__apt_ppa/files/remove-apt-repository
Executable file
|
@ -0,0 +1,55 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Remove the given apt repository.
|
||||||
|
#
|
||||||
|
# Exit with:
|
||||||
|
# 0: if it worked
|
||||||
|
# 1: if not
|
||||||
|
# 2: on other error
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from aptsources import distro, sourceslist
|
||||||
|
from softwareproperties import ppa
|
||||||
|
from softwareproperties.SoftwareProperties import SoftwareProperties
|
||||||
|
|
||||||
|
|
||||||
|
def remove_if_empty(file_name):
|
||||||
|
with open(file_name, 'r') as f:
|
||||||
|
if f.read().strip():
|
||||||
|
return
|
||||||
|
os.unlink(file_name)
|
||||||
|
|
||||||
|
def remove_repository(repository):
|
||||||
|
#print 'repository:', repository
|
||||||
|
codename = distro.get_distro().codename
|
||||||
|
#print 'codename:', codename
|
||||||
|
(line, file) = ppa.expand_ppa_line(repository.strip(), codename)
|
||||||
|
#print 'line:', line
|
||||||
|
#print 'file:', file
|
||||||
|
deb_source_entry = sourceslist.SourceEntry(line, file)
|
||||||
|
src_source_entry = sourceslist.SourceEntry('deb-src{}'.format(line[3:]), file)
|
||||||
|
|
||||||
|
try:
|
||||||
|
sp = SoftwareProperties()
|
||||||
|
sp.remove_source(deb_source_entry)
|
||||||
|
try:
|
||||||
|
# If there's a deb-src entry, remove that too
|
||||||
|
sp.remove_source(src_source_entry)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
remove_if_empty(file)
|
||||||
|
return True
|
||||||
|
except ValueError:
|
||||||
|
print >> sys.stderr, "Error: '%s' doesn't exists in a sourcelist file" % line
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if (len(sys.argv) != 2):
|
||||||
|
print >> sys.stderr, 'Error: need a repository as argument'
|
||||||
|
sys.exit(2)
|
||||||
|
repository = sys.argv[1]
|
||||||
|
if remove_repository(repository):
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
sys.exit(1)
|
|
@ -29,9 +29,9 @@ fi
|
||||||
|
|
||||||
case "$state_should" in
|
case "$state_should" in
|
||||||
present)
|
present)
|
||||||
echo "add-apt-repository -y '$name'"
|
echo "add-apt-repository '$name'"
|
||||||
;;
|
;;
|
||||||
absent)
|
absent)
|
||||||
echo "add-apt-repository -r -y '$name'"
|
echo "remove-apt-repository '$name'"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -20,4 +20,9 @@
|
||||||
|
|
||||||
__package software-properties-common
|
__package software-properties-common
|
||||||
|
|
||||||
|
require="__package/software-properties-common" \
|
||||||
|
__file /usr/local/bin/remove-apt-repository \
|
||||||
|
--source "$__type/files/remove-apt-repository" \
|
||||||
|
--mode 0755
|
||||||
|
|
||||||
require="$__object_name" __apt_update_index
|
require="$__object_name" __apt_update_index
|
||||||
|
|
|
@ -2,14 +2,13 @@
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
entry="$uri $distribution $component"
|
entry="$uri $distribution $component"
|
||||||
|
|
||||||
cat << DONE
|
cat << DONE
|
||||||
# Created by cdist ${__type##*/}
|
# Created by cdist ${__type##*/}
|
||||||
# Do not change. Changes will be overwritten.
|
# Do not change. Changes will be overwritten.
|
||||||
#
|
#
|
||||||
|
|
||||||
# $name
|
# $name
|
||||||
deb ${options} $entry
|
deb ${forcedarch} $entry
|
||||||
DONE
|
DONE
|
||||||
if [ -f "$__object/parameter/include-src" ]; then
|
if [ -f "$__object/parameter/include-src" ]; then
|
||||||
echo "deb-src $entry"
|
echo "deb-src $entry"
|
||||||
|
|
|
@ -22,21 +22,7 @@
|
||||||
name="$__object_id"
|
name="$__object_id"
|
||||||
destination="/etc/apt/sources.list.d/${name}.list"
|
destination="/etc/apt/sources.list.d/${name}.list"
|
||||||
|
|
||||||
# There are special arguments to apt(8) to prevent aborts if apt woudn't been
|
|
||||||
# updated after the 19th April 2021 till the bullseye release. The additional
|
|
||||||
# arguments acknoledge the happend suite change (the apt(8) update does the
|
|
||||||
# same by itself).
|
|
||||||
#
|
|
||||||
# Using '-o $config' instead of the --allow-releaseinfo-change-* parameter
|
|
||||||
# allows backward compatablility to pre-buster Debian versions.
|
|
||||||
#
|
|
||||||
# See more: ticket #861
|
|
||||||
# https://code.ungleich.ch/ungleich-public/cdist/-/issues/861
|
|
||||||
apt_opts="-o Acquire::AllowReleaseInfoChange::Suite=true -o Acquire::AllowReleaseInfoChange::Version=true"
|
|
||||||
|
|
||||||
# run 'apt-get update' only if something changed with our sources.list file
|
|
||||||
# it will be run a second time on error as a redundancy messure to success
|
|
||||||
if grep -q "^__file${destination}" "$__messages_in"; then
|
if grep -q "^__file${destination}" "$__messages_in"; then
|
||||||
printf 'apt-get %s update || apt-get %s update\n' "$apt_opts" "$apt_opts"
|
printf 'apt-get update || apt-get update\n'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,6 @@ OPTIONAL PARAMETERS
|
||||||
arch
|
arch
|
||||||
set this if you need to force and specific arch (ubuntu specific)
|
set this if you need to force and specific arch (ubuntu specific)
|
||||||
|
|
||||||
signed-by
|
|
||||||
provide a GPG key fingerprint or keyring path for signature checks
|
|
||||||
|
|
||||||
state
|
state
|
||||||
'present' or 'absent', defaults to 'present'
|
'present' or 'absent', defaults to 'present'
|
||||||
|
|
||||||
|
@ -59,11 +56,6 @@ EXAMPLES
|
||||||
--uri http://archive.canonical.com/ \
|
--uri http://archive.canonical.com/ \
|
||||||
--component partner --state present
|
--component partner --state present
|
||||||
|
|
||||||
__apt_source goaccess \
|
|
||||||
--uri http://deb.goaccess.io/ \
|
|
||||||
--component main \
|
|
||||||
--signed-by C03B48887D5E56B046715D3297BD1A0133449C3D
|
|
||||||
|
|
||||||
|
|
||||||
AUTHORS
|
AUTHORS
|
||||||
-------
|
-------
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
name="$__object_id"
|
name="$__object_id"
|
||||||
state="$(cat "$__object/parameter/state")"
|
state="$(cat "$__object/parameter/state")"
|
||||||
uri="$(cat "$__object/parameter/uri")"
|
uri="$(cat "$__object/parameter/uri")"
|
||||||
options=""
|
|
||||||
|
|
||||||
if [ -f "$__object/parameter/distribution" ]; then
|
if [ -f "$__object/parameter/distribution" ]; then
|
||||||
distribution="$(cat "$__object/parameter/distribution")"
|
distribution="$(cat "$__object/parameter/distribution")"
|
||||||
|
@ -32,15 +31,9 @@ fi
|
||||||
component="$(cat "$__object/parameter/component")"
|
component="$(cat "$__object/parameter/component")"
|
||||||
|
|
||||||
if [ -f "$__object/parameter/arch" ]; then
|
if [ -f "$__object/parameter/arch" ]; then
|
||||||
options="arch=$(cat "$__object/parameter/arch")"
|
forcedarch="[arch=$(cat "$__object/parameter/arch")]"
|
||||||
fi
|
else
|
||||||
|
forcedarch=""
|
||||||
if [ -f "$__object/parameter/signed-by" ]; then
|
|
||||||
options="$options signed-by=$(cat "$__object/parameter/signed-by")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$options" ]; then
|
|
||||||
options="[$options]"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# export variables for use in template
|
# export variables for use in template
|
||||||
|
@ -48,7 +41,7 @@ export name
|
||||||
export uri
|
export uri
|
||||||
export distribution
|
export distribution
|
||||||
export component
|
export component
|
||||||
export options
|
export forcedarch
|
||||||
|
|
||||||
# generate file from template
|
# generate file from template
|
||||||
mkdir "$__object/files"
|
mkdir "$__object/files"
|
||||||
|
|
|
@ -2,4 +2,3 @@ state
|
||||||
distribution
|
distribution
|
||||||
component
|
component
|
||||||
arch
|
arch
|
||||||
signed-by
|
|
||||||
|
|
|
@ -18,23 +18,9 @@
|
||||||
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
# There are special arguments to apt(8) to prevent aborts if apt woudn't been
|
|
||||||
# updated after the 19th April 2021 till the bullseye release. The additional
|
|
||||||
# arguments acknoledge the happend suite change (the apt(8) update does the
|
|
||||||
# same by itself).
|
|
||||||
#
|
|
||||||
# Using '-o $config' instead of the --allow-releaseinfo-change-* parameter
|
|
||||||
# allows backward compatablility to pre-buster Debian versions.
|
|
||||||
#
|
|
||||||
# See more: ticket #861
|
|
||||||
# https://code.ungleich.ch/ungleich-public/cdist/-/issues/861
|
|
||||||
apt_opts="-o Acquire::AllowReleaseInfoChange::Suite=true -o Acquire::AllowReleaseInfoChange::Version=true"
|
|
||||||
|
|
||||||
# run 'apt-get update' if anything in /etc/apt is newer then /var/lib/apt/lists
|
# run 'apt-get update' if anything in /etc/apt is newer then /var/lib/apt/lists
|
||||||
# it will be run a second time on error as a redundancy messure to success
|
|
||||||
cat << DONE
|
cat << DONE
|
||||||
if find /etc/apt -mindepth 1 -cnewer /var/lib/apt/lists | grep . > /dev/null; then
|
if find /etc/apt -mindepth 1 -cnewer /var/lib/apt/lists | grep . > /dev/null; then
|
||||||
apt-get $apt_opts update || apt-get $apt_opts update
|
apt-get update || apt-get update
|
||||||
fi
|
fi
|
||||||
DONE
|
DONE
|
||||||
|
|
12
cdist/conf/type/__cdist_preos_trigger/gencode-remote
Normal file
12
cdist/conf/type/__cdist_preos_trigger/gencode-remote
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
os=$(cat "$__global/explorer/os")
|
||||||
|
|
||||||
|
case "$os" in
|
||||||
|
devuan)
|
||||||
|
echo "update-rc.d cdist-preos-trigger defaults > /dev/null"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
45
cdist/conf/type/__cdist_preos_trigger/man.rst
Normal file
45
cdist/conf/type/__cdist_preos_trigger/man.rst
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
cdist-type__cdist_preos_trigger(7)
|
||||||
|
==================================
|
||||||
|
|
||||||
|
NAME
|
||||||
|
----
|
||||||
|
cdist-type__cdist_preos_trigger - configure cdist preos trigger
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
-----------
|
||||||
|
Create cdist PreOS trigger by creating systemd unit file that will be started
|
||||||
|
at boot and will execute trigger command - connect to specified host and port.
|
||||||
|
|
||||||
|
|
||||||
|
REQUIRED PARAMETERS
|
||||||
|
-------------------
|
||||||
|
trigger-command
|
||||||
|
Command that will be executed as a PreOS cdist trigger.
|
||||||
|
|
||||||
|
|
||||||
|
OPTIONAL PARAMETERS
|
||||||
|
-------------------
|
||||||
|
None
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
|
--------
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
# Configure default curl trigger for host cdist.ungleich.ch at port 80.
|
||||||
|
__cdist_preos_trigger http --trigger-command '/usr/bin/curl cdist.ungleich.ch:80'
|
||||||
|
|
||||||
|
|
||||||
|
AUTHORS
|
||||||
|
-------
|
||||||
|
Darko Poljak <darko.poljak--@--ungleich.ch>
|
||||||
|
|
||||||
|
|
||||||
|
COPYING
|
||||||
|
-------
|
||||||
|
Copyright \(C) 2016 Darko Poljak. 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.
|
67
cdist/conf/type/__cdist_preos_trigger/manifest
Normal file
67
cdist/conf/type/__cdist_preos_trigger/manifest
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
os="$(cat "$__global/explorer/os")"
|
||||||
|
trigger_command=$(cat "$__object/parameter/trigger-command")
|
||||||
|
|
||||||
|
case "$os" in
|
||||||
|
devuan)
|
||||||
|
__file /etc/init.d/cdist-preos-trigger --owner root \
|
||||||
|
--group root \
|
||||||
|
--mode 755 \
|
||||||
|
--source - << EOF
|
||||||
|
#!/bin/sh
|
||||||
|
# /etc/init.d/cdist-preos-trigger
|
||||||
|
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: cdist-preos-trigger
|
||||||
|
# Required-Start: \$all
|
||||||
|
# Required-Stop:
|
||||||
|
# Default-Start: 2 3 4 5 S
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Short-Description: Execute cdist preos trigger command
|
||||||
|
# Description: Execute cdist preos trigger commnad.
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
|
case "\$1" in
|
||||||
|
start)
|
||||||
|
echo "Starting cdist-preos-trigger command"
|
||||||
|
${trigger_command} &
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
# no-op
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: /etc/init.d/cdist-preos-trigger {start|stop}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
__file /etc/systemd/system/cdist-preos-trigger.service --owner root \
|
||||||
|
--group root \
|
||||||
|
--mode 644 \
|
||||||
|
--source - << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=preos trigger
|
||||||
|
Wants=network-online.target
|
||||||
|
After=network.target network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
Restart=no
|
||||||
|
# Broken systemd
|
||||||
|
ExecStartPre=/bin/sleep 5
|
||||||
|
ExecStart=${trigger_command}
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
require="__file/etc/systemd/system/cdist-preos-trigger.service" \
|
||||||
|
__start_on_boot cdist-preos-trigger
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
1
cdist/conf/type/__cdist_preos_trigger/parameter/required
Normal file
1
cdist/conf/type/__cdist_preos_trigger/parameter/required
Normal file
|
@ -0,0 +1 @@
|
||||||
|
trigger-command
|
|
@ -1 +0,0 @@
|
||||||
'file' has been deprecated in favour of 'line' in order to provide idempotency.
|
|
|
@ -37,12 +37,6 @@ state
|
||||||
source
|
source
|
||||||
forwarded to :strong:`__file` type
|
forwarded to :strong:`__file` type
|
||||||
|
|
||||||
file
|
|
||||||
forwarded to :strong:`__file` type
|
|
||||||
This can be used if multiple users need to have a dotfile updated,
|
|
||||||
which will result in duplicate object id errors. When using the
|
|
||||||
file parameter the object id can be some unique value.
|
|
||||||
|
|
||||||
MESSAGES
|
MESSAGES
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
@ -67,15 +61,6 @@ EXAMPLES
|
||||||
# Install default xmonad config for user 'eve'. Parent directory is created automatically.
|
# Install default xmonad config for user 'eve'. Parent directory is created automatically.
|
||||||
__dot_file .xmonad/xmonad.hs --user eve --state exists --source "$__files/xmonad.hs"
|
__dot_file .xmonad/xmonad.hs --user eve --state exists --source "$__files/xmonad.hs"
|
||||||
|
|
||||||
# install .vimrc for root and some users
|
|
||||||
for user in root userx usery userz; do
|
|
||||||
__dot_file "${user}_dot_vimrc" \
|
|
||||||
--user $user \
|
|
||||||
--file .vimrc \
|
|
||||||
--state exists \
|
|
||||||
--source "$__files/$user/.vimrc"
|
|
||||||
done
|
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|
|
@ -20,19 +20,13 @@ user="$(cat "${__object}/parameter/user")"
|
||||||
home="$(cat "${__object}/explorer/home")"
|
home="$(cat "${__object}/explorer/home")"
|
||||||
primary_group="$(cat "${__object}/explorer/primary_group")"
|
primary_group="$(cat "${__object}/explorer/primary_group")"
|
||||||
dirmode="$(cat "${__object}/parameter/dirmode")"
|
dirmode="$(cat "${__object}/parameter/dirmode")"
|
||||||
if [ -f "${__object}/parameter/file" ]; then
|
|
||||||
file="$(cat "${__object}/parameter/file")"
|
|
||||||
else
|
|
||||||
file="${__object_id}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# Create parent directory. Type __directory has flag 'parents', but it
|
# Create parent directory. Type __directory has flag 'parents', but it
|
||||||
# will leave us with root-owned directory in user home, which is not
|
# will leave us with root-owned directory in user home, which is not
|
||||||
# acceptable. So we create parent directories one-by-one. XXX: maybe
|
# acceptable. So we create parent directories one-by-one. XXX: maybe
|
||||||
# it should be fixed in '__directory'?
|
# it should be fixed in '__directory'?
|
||||||
set --
|
set --
|
||||||
subpath=${file}
|
subpath=${__object_id}
|
||||||
while subpath="$(dirname "${subpath}")" ; do
|
while subpath="$(dirname "${subpath}")" ; do
|
||||||
[ "${subpath}" = . ] && break
|
[ "${subpath}" = . ] && break
|
||||||
set -- "${subpath}" "$@"
|
set -- "${subpath}" "$@"
|
||||||
|
@ -70,4 +64,4 @@ if [ "${source}" = "-" ] ; then
|
||||||
fi
|
fi
|
||||||
unset source
|
unset source
|
||||||
|
|
||||||
__file "${home}/${file}" --owner "$user" --group "$primary_group" "$@"
|
__file "${home}/${__object_id}" --owner "$user" --group "$primary_group" "$@"
|
||||||
|
|
124
cdist/conf/type/__file/__init__.py
Normal file
124
cdist/conf/type/__file/__init__.py
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
from cdist.core.pytypes import *
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
class FileType(PythonType):
|
||||||
|
def get_attribute(self, stat_file, attribute, value_should):
|
||||||
|
if os.path.exists(stat_file):
|
||||||
|
if re.match('[0-9]', value_should):
|
||||||
|
index = 1
|
||||||
|
else:
|
||||||
|
index = 2
|
||||||
|
with open(stat_file, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
if re.match(attribute + ":", line):
|
||||||
|
fields = line.split()
|
||||||
|
return fields[index]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def set_attribute(self, attribute, value_should, destination):
|
||||||
|
cmd = {
|
||||||
|
'group': 'chgrp',
|
||||||
|
'owner': 'chown',
|
||||||
|
'mode': 'chmod',
|
||||||
|
}
|
||||||
|
self.send_message("{} '{}'".format(cmd[attribute], value_should))
|
||||||
|
return "{} '{}' '{}'".format(cmd[attribute], value_should, destination)
|
||||||
|
|
||||||
|
def type_manifest(self):
|
||||||
|
yield from ()
|
||||||
|
|
||||||
|
def type_gencode(self):
|
||||||
|
typeis = self.get_explorer('type')
|
||||||
|
state_should = self.get_parameter('state')
|
||||||
|
|
||||||
|
if state_should == 'exists' and typeis == 'file':
|
||||||
|
return
|
||||||
|
|
||||||
|
source = self.get_parameter('source')
|
||||||
|
if source == '-':
|
||||||
|
source = self.stdin_path
|
||||||
|
destination = '/' + self.object_id
|
||||||
|
if state_should == 'pre-exists':
|
||||||
|
if source is not None:
|
||||||
|
self.die('--source cannot be used with --state pre-exists')
|
||||||
|
if typeis == 'file':
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
self.die('File {} does not exist'.format(destination))
|
||||||
|
|
||||||
|
create_file = False
|
||||||
|
upload_file = False
|
||||||
|
set_attributes = False
|
||||||
|
fire_onchange = False
|
||||||
|
code = []
|
||||||
|
if state_should == 'present' or state_should == 'exists':
|
||||||
|
if source is None:
|
||||||
|
remote_stat = self.get_explorer('stat')
|
||||||
|
if not remote_stat:
|
||||||
|
create_file = True
|
||||||
|
else:
|
||||||
|
if os.path.exists(source):
|
||||||
|
if typeis == 'file':
|
||||||
|
local_cksum = self.run_local(['cksum', source, ])
|
||||||
|
local_cksum = local_cksum.split()[0]
|
||||||
|
remote_cksum = self.get_explorer('cksum')
|
||||||
|
remote_cksum = remote_cksum.split()[0]
|
||||||
|
upload_file = local_cksum != remote_cksum
|
||||||
|
else:
|
||||||
|
upload_file = True
|
||||||
|
else:
|
||||||
|
self.die('Source {} does not exist'.format(source))
|
||||||
|
if create_file or upload_file:
|
||||||
|
set_attributes = True
|
||||||
|
fire_onchange = True
|
||||||
|
tempfile_template = '{}.cdist.XXXXXXXXXX'.format(destination)
|
||||||
|
destination_upload = self.run_remote(
|
||||||
|
["mktemp", tempfile_template, ])
|
||||||
|
if upload_file:
|
||||||
|
self.transfer(source, destination_upload)
|
||||||
|
code.append('rm -rf {}'.format(destination))
|
||||||
|
code.append('mv {} {}'.format(destination_upload, destination))
|
||||||
|
|
||||||
|
if state_should in ('present', 'exists', 'pre-exists', ):
|
||||||
|
for attribute in ('group', 'owner', 'mode', ):
|
||||||
|
if attribute in self.parameters:
|
||||||
|
value_should = self.get_parameter(attribute)
|
||||||
|
if attribute == 'mode':
|
||||||
|
value_should = re.sub('^0', '', value_should)
|
||||||
|
stat_file = self.get_explorer_file('stat')
|
||||||
|
value_is = self.get_attribute(stat_file, attribute,
|
||||||
|
value_should)
|
||||||
|
if set_attributes or value_should != value_is:
|
||||||
|
fire_onchange = True
|
||||||
|
code.append(self.set_attribute(attribute,
|
||||||
|
value_should,
|
||||||
|
destination))
|
||||||
|
elif state_should == 'absent':
|
||||||
|
if typeis == 'file':
|
||||||
|
code.append('rm -f {}'.format(destination))
|
||||||
|
self.send_message('remove')
|
||||||
|
fire_onchange = True
|
||||||
|
else:
|
||||||
|
self.die('Unknown state {}'.format(state_should))
|
||||||
|
|
||||||
|
if fire_onchange:
|
||||||
|
onchange = self.get_parameter('onchange')
|
||||||
|
if onchange:
|
||||||
|
code.append(onchange)
|
||||||
|
|
||||||
|
return "\n".join(code)
|
||||||
|
|
||||||
|
def get_args_parser(self):
|
||||||
|
parser = argparse.ArgumentParser(add_help=False,
|
||||||
|
argument_default=argparse.SUPPRESS)
|
||||||
|
parser.add_argument('--state', dest='state', action='store',
|
||||||
|
required=False, default='present')
|
||||||
|
for param in ('group', 'mode', 'owner', 'source', 'onchange'):
|
||||||
|
parser.add_argument('--' + param, dest=param, action='store',
|
||||||
|
required=False, default=None)
|
||||||
|
|
||||||
|
parser.add_argument("object_id", nargs=1)
|
||||||
|
return parser
|
34
cdist/conf/type/__file_old/explorer/cksum
Executable file
34
cdist/conf/type/__file_old/explorer/cksum
Executable file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# 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
|
116
cdist/conf/type/__file_old/explorer/stat
Executable file
116
cdist/conf/type/__file_old/explorer/stat
Executable file
|
@ -0,0 +1,116 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
|
||||||
|
# 2019 Nico Schottelius (nico-cdist at schottelius.org)
|
||||||
|
# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
|
||||||
|
#
|
||||||
|
# This file is part of cdist.
|
||||||
|
#
|
||||||
|
# cdist is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# cdist is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
destination="/$__object_id"
|
||||||
|
|
||||||
|
fallback() {
|
||||||
|
# Fallback: Patch the output together, manually.
|
||||||
|
|
||||||
|
ls_line=$(ls -ldn "$destination")
|
||||||
|
|
||||||
|
uid=$(echo "$ls_line" | awk '{ print $3 }')
|
||||||
|
gid=$(echo "$ls_line" | awk '{ print $4 }')
|
||||||
|
|
||||||
|
owner=$(awk -F: -v uid="$uid" '$3 == uid { print $1; f=1 } END { if (!f) print "UNKNOWN" }' /etc/passwd)
|
||||||
|
group=$(awk -F: -v uid="$uid" '$3 == uid { print $1; f=1 } END { if (!f) print "UNKNOWN" }' /etc/group)
|
||||||
|
|
||||||
|
mode_text=$(echo "$ls_line" | awk '{ print $1 }')
|
||||||
|
mode=$(echo "$mode_text" | awk '{ k=0; for (i=0; i<=8; i++) k += ((substr($1, i+2, 1) ~ /[rwx]/) * 2^(8-i)); printf("%0o", k) }')
|
||||||
|
|
||||||
|
size=$(echo "$ls_line" | awk '{ print $5 }')
|
||||||
|
links=$(echo "$ls_line" | awk '{ print $2 }')
|
||||||
|
|
||||||
|
printf 'type: %s\nowner: %d %s\ngroup: %d %s\nmode: %s %s\nsize: %d\nlinks: %d\n' \
|
||||||
|
"$("$__type_explorer/type")" \
|
||||||
|
"$uid" "$owner" \
|
||||||
|
"$gid" "$group" \
|
||||||
|
"$mode" "$mode_text" \
|
||||||
|
"$size" \
|
||||||
|
"$links"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# nothing to work with, nothing we could do
|
||||||
|
[ -e "$destination" ] || exit 0
|
||||||
|
|
||||||
|
|
||||||
|
if ! command -v stat >/dev/null
|
||||||
|
then
|
||||||
|
fallback
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
case $("$__explorer/os")
|
||||||
|
in
|
||||||
|
freebsd|netbsd|openbsd|macosx)
|
||||||
|
stat -f "type: %HT
|
||||||
|
owner: %Du %Su
|
||||||
|
group: %Dg %Sg
|
||||||
|
mode: %Lp %Sp
|
||||||
|
size: %Dz
|
||||||
|
links: %Dl
|
||||||
|
" "$destination" | awk '/^type/ { print tolower($0); next } { print }'
|
||||||
|
;;
|
||||||
|
solaris)
|
||||||
|
ls1="$( ls -ld "$destination" )"
|
||||||
|
ls2="$( ls -ldn "$destination" )"
|
||||||
|
|
||||||
|
if [ -f "$__object/parameter/mode" ]
|
||||||
|
then mode_should="$( cat "$__object/parameter/mode" )"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# yes, it is ugly hack, but if you know better way...
|
||||||
|
if [ -z "$( find "$destination" -perm "$mode_should" )" ]
|
||||||
|
then octets=888
|
||||||
|
else octets="$( echo "$mode_should" | sed 's/^0//' )"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$( echo "$ls1" | cut -c1-1 )" in
|
||||||
|
-) echo 'type: regular file' ;;
|
||||||
|
d) echo 'type: directory' ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "owner: $( echo "$ls2" \
|
||||||
|
| awk '{print $3}' ) $( echo "$ls1" \
|
||||||
|
| awk '{print $3}' )"
|
||||||
|
|
||||||
|
echo "group: $( echo "$ls2" \
|
||||||
|
| awk '{print $4}' ) $( echo "$ls1" \
|
||||||
|
| awk '{print $4}' )"
|
||||||
|
|
||||||
|
echo "mode: $octets $( echo "$ls1" | awk '{print $1}' )"
|
||||||
|
echo "size: $( echo "$ls1" | awk '{print $5}' )"
|
||||||
|
echo "links: $( echo "$ls1" | awk '{print $2}' )"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# NOTE: Do not use --printf here as it is not supported by BusyBox stat.
|
||||||
|
# NOTE: BusyBox's stat might not support the "-c" option, in which case
|
||||||
|
# we fall through to the shell fallback.
|
||||||
|
stat -c "type: %F
|
||||||
|
owner: %u %U
|
||||||
|
group: %g %G
|
||||||
|
mode: %a %A
|
||||||
|
size: %s
|
||||||
|
links: %h" "$destination" 2>/dev/null || fallback
|
||||||
|
;;
|
||||||
|
esac
|
33
cdist/conf/type/__file_old/explorer/type
Executable file
33
cdist/conf/type/__file_old/explorer/type
Executable file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
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
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/sh -e
|
#!/bin/sh -e
|
||||||
#
|
#
|
||||||
# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
|
# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
|
||||||
# 2013-2022 Steven Armstrong (steven-cdist armstrong.cc)
|
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
|
||||||
#
|
#
|
||||||
# This file is part of cdist.
|
# This file is part of cdist.
|
||||||
#
|
#
|
||||||
|
@ -72,7 +72,6 @@ if [ "$state_should" = "present" ] || [ "$state_should" = "exists" ]; then
|
||||||
if [ "$type" != "file" ]; then
|
if [ "$type" != "file" ]; then
|
||||||
# destination is not a regular file, upload source to replace it
|
# destination is not a regular file, upload source to replace it
|
||||||
upload_file=1
|
upload_file=1
|
||||||
echo upload >> "$__messages_out"
|
|
||||||
else
|
else
|
||||||
local_cksum="$(cksum < "$source")"
|
local_cksum="$(cksum < "$source")"
|
||||||
remote_cksum="$(cat "$__object/explorer/cksum")"
|
remote_cksum="$(cat "$__object/explorer/cksum")"
|
||||||
|
@ -89,39 +88,27 @@ if [ "$state_should" = "present" ] || [ "$state_should" = "exists" ]; then
|
||||||
mkdir "$__object/files"
|
mkdir "$__object/files"
|
||||||
touch "$__object/files/set-attributes"
|
touch "$__object/files/set-attributes"
|
||||||
|
|
||||||
if [ "$create_file" ]; then
|
|
||||||
# When creating an empty file we create it locally and then
|
|
||||||
# upload it so that permissions can be set before moving the file
|
|
||||||
# into place.
|
|
||||||
source="$__object/files/empty"
|
|
||||||
touch "$source"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# upload file to temp location
|
# upload file to temp location
|
||||||
upload_destination="${destination}.cdist.${__cdist_object_marker}.$$"
|
tempfile_template="${destination}.cdist.XXXXXXXXXX"
|
||||||
# Yes, we are aware that this is a race condition.
|
|
||||||
# However:
|
|
||||||
# a) cdist usually writes to directories that are not user writable
|
|
||||||
# (probably > 99.9%)
|
|
||||||
# b) if they are user owned, the user / attacker always wins
|
|
||||||
# (probably < 0.1%)
|
|
||||||
# c) the only case which we could improve are tmp directories and we
|
|
||||||
# don't think managing tmp directories with cdist is a typical case
|
|
||||||
# ("the rest %)"
|
|
||||||
|
|
||||||
# Tell gencode-remote to where we uploaded the file so it can move
|
|
||||||
# it to its final destination.
|
|
||||||
echo "$upload_destination" > "$__object/files/upload-destination"
|
|
||||||
|
|
||||||
# IPv6 fix
|
|
||||||
if echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$'
|
|
||||||
then
|
|
||||||
my_target_host="[${__target_host}]"
|
|
||||||
else
|
|
||||||
my_target_host="${__target_host}"
|
|
||||||
fi
|
|
||||||
cat << DONE
|
cat << DONE
|
||||||
$__remote_copy "$source" "${my_target_host}:${upload_destination}"
|
destination_upload="\$($__remote_exec $__target_host "mktemp $tempfile_template")"
|
||||||
|
DONE
|
||||||
|
if [ "$upload_file" ]; then
|
||||||
|
echo upload >> "$__messages_out"
|
||||||
|
# IPv6 fix
|
||||||
|
if echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$'
|
||||||
|
then
|
||||||
|
my_target_host="[${__target_host}]"
|
||||||
|
else
|
||||||
|
my_target_host="${__target_host}"
|
||||||
|
fi
|
||||||
|
cat << DONE
|
||||||
|
$__remote_copy "$source" "${my_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
|
DONE
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/sh -e
|
#!/bin/sh -e
|
||||||
#
|
#
|
||||||
# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
|
# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
|
||||||
# 2013-2022 Steven Armstrong (steven-cdist armstrong.cc)
|
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
|
||||||
#
|
#
|
||||||
# This file is part of cdist.
|
# This file is part of cdist.
|
||||||
#
|
#
|
||||||
|
@ -62,13 +62,6 @@ set_mode() {
|
||||||
|
|
||||||
case "$state_should" in
|
case "$state_should" in
|
||||||
present|exists)
|
present|exists)
|
||||||
if [ -f "$__object/files/upload-destination" ]; then
|
|
||||||
final_destination="$destination"
|
|
||||||
# We change the 'global' $destination variable here so we can
|
|
||||||
# change attributes of the new/uploaded file before moving it
|
|
||||||
# to it's final destination.
|
|
||||||
destination="$(cat "$__object/files/upload-destination")"
|
|
||||||
fi
|
|
||||||
# Note: Mode - needs to happen last as a chown/chgrp can alter mode by
|
# Note: Mode - needs to happen last as a chown/chgrp can alter mode by
|
||||||
# clearing S_ISUID and S_ISGID bits (see chown(2))
|
# clearing S_ISUID and S_ISGID bits (see chown(2))
|
||||||
for attribute in group owner mode; do
|
for attribute in group owner mode; do
|
||||||
|
@ -88,11 +81,6 @@ case "$state_should" in
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ -f "$__object/files/upload-destination" ]; then
|
|
||||||
# move uploaded file into place
|
|
||||||
printf 'rm -rf "%s"\n' "$final_destination"
|
|
||||||
printf 'mv "%s" "%s"\n' "$destination" "$final_destination"
|
|
||||||
fi
|
|
||||||
if [ -f "$__object/files/set-attributes" ]; then
|
if [ -f "$__object/files/set-attributes" ]; then
|
||||||
# set-attributes is created if file is created or uploaded in gencode-local
|
# set-attributes is created if file is created or uploaded in gencode-local
|
||||||
fire_onchange=1
|
fire_onchange=1
|
1
cdist/conf/type/__file_py
Symbolic link
1
cdist/conf/type/__file_py
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
__file
|
|
@ -15,7 +15,7 @@ case $os in
|
||||||
# Differntation not needed anymore
|
# Differntation not needed anymore
|
||||||
apt_source_distribution=stable
|
apt_source_distribution=stable
|
||||||
;;
|
;;
|
||||||
10*|11*)
|
10*)
|
||||||
# Differntation not needed anymore
|
# Differntation not needed anymore
|
||||||
apt_source_distribution=stable
|
apt_source_distribution=stable
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
frontend http
|
|
||||||
bind BIND@:80
|
|
||||||
mode http
|
|
||||||
option httplog
|
|
||||||
default_backend http
|
|
||||||
|
|
||||||
backend http
|
|
||||||
mode http
|
|
|
@ -1,10 +0,0 @@
|
||||||
frontend https
|
|
||||||
bind BIND@:443
|
|
||||||
mode tcp
|
|
||||||
option tcplog
|
|
||||||
tcp-request inspect-delay 5s
|
|
||||||
tcp-request content accept if { req_ssl_hello_type 1 }
|
|
||||||
default_backend https
|
|
||||||
|
|
||||||
backend https
|
|
||||||
mode tcp
|
|
|
@ -1,12 +0,0 @@
|
||||||
frontend imaps
|
|
||||||
bind BIND@:143
|
|
||||||
bind BIND@:993
|
|
||||||
|
|
||||||
mode tcp
|
|
||||||
option tcplog
|
|
||||||
tcp-request inspect-delay 5s
|
|
||||||
tcp-request content accept if { req_ssl_hello_type 1 }
|
|
||||||
default_backend imaps
|
|
||||||
|
|
||||||
backend imaps
|
|
||||||
mode tcp
|
|
|
@ -1,12 +0,0 @@
|
||||||
frontend smtps
|
|
||||||
bind BIND@:25
|
|
||||||
bind BIND@:465
|
|
||||||
|
|
||||||
mode tcp
|
|
||||||
option tcplog
|
|
||||||
tcp-request inspect-delay 5s
|
|
||||||
tcp-request content accept if { req_ssl_hello_type 1 }
|
|
||||||
default_backend smtps
|
|
||||||
|
|
||||||
backend smtps
|
|
||||||
mode tcp
|
|
|
@ -1,121 +0,0 @@
|
||||||
cdist-type__haproxy_dualstack(7)
|
|
||||||
================================
|
|
||||||
|
|
||||||
|
|
||||||
NAME
|
|
||||||
----
|
|
||||||
cdist-type__haproxy_dualstack - Proxy services from a dual-stack server
|
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
-----------
|
|
||||||
This (singleton) type installs and configures haproxy to act as a dual-stack
|
|
||||||
proxy for single-stack services.
|
|
||||||
|
|
||||||
This can be useful to add IPv4 support to IPv6-only services while only using
|
|
||||||
one IPv4 for many such services.
|
|
||||||
|
|
||||||
By default this type uses the plain TCP proxy mode, which means that there is no
|
|
||||||
need for TLS termination on this host when SNI is supported.
|
|
||||||
This also means that proxied services will not receive the client's IP address,
|
|
||||||
but will see the proxy's IP address instead (that of `$__target_host`).
|
|
||||||
|
|
||||||
This can be solved by using the PROXY protocol, but do take into account that,
|
|
||||||
e.g. nginx cannot serve both regular HTTP(S) and PROXY protocols on the same
|
|
||||||
port, so you will need to use other ports for that.
|
|
||||||
|
|
||||||
As a recommendation in this type: use TCP ports 8080 and 591 respectively to
|
|
||||||
serve HTTP and HTTPS using the PROXY protocol.
|
|
||||||
|
|
||||||
See the EXAMPLES for more details.
|
|
||||||
|
|
||||||
|
|
||||||
OPTIONAL PARAMETERS
|
|
||||||
-------------------
|
|
||||||
v4proxy
|
|
||||||
Proxy incoming IPv4 connections to the equivalent IPv6 endpoint.
|
|
||||||
In its simplest use, it must be a NAME with an `AAAA` DNS entry, which is
|
|
||||||
the IP address actually providing the proxied services.
|
|
||||||
The full format of this argument is:
|
|
||||||
`[proxy:]NAME[[:PROTOCOL_1=PORT_1]...[:PROTOCOL_N=PORT_N]]`
|
|
||||||
Where starting with `proxy:` determines that the PROXY protocol must be
|
|
||||||
used and each `:PROTOCOL=PORT` (e.g. `:http=8080` or `:https=591`) is a PORT
|
|
||||||
override for the given PROTOCOL (see `--protocol`), if not present the
|
|
||||||
PROTOCOL's default port will be used.
|
|
||||||
|
|
||||||
|
|
||||||
v6proxy
|
|
||||||
Proxy incoming IPv6 connections to the equivalent IPv4 endpoint.
|
|
||||||
In its simplest use, it must be a NAME with an `A` DNS entry, which is
|
|
||||||
the IP address actually providing the proxied services.
|
|
||||||
See `--v4proxy` for more options and details.
|
|
||||||
|
|
||||||
protocol
|
|
||||||
Can be passed multiple times or as a space-separated list of protocols.
|
|
||||||
Currently supported protocols are: `http`, `https`, `imaps`, `smtps`.
|
|
||||||
This defaults to: `http https imaps smtps`.
|
|
||||||
|
|
||||||
|
|
||||||
EXAMPLES
|
|
||||||
--------
|
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
# Proxy the IPv6-only services so IPv4-only clients can access them
|
|
||||||
# This uses HAProxy's TCP mode for http, https, imaps and smtps
|
|
||||||
__haproxy_dualstack \
|
|
||||||
--v4proxy ipv6.chat \
|
|
||||||
--v4proxy matrix.ungleich.ch
|
|
||||||
|
|
||||||
# Proxy the IPv6-only HTTP(S) services so IPv4-only clients can access them
|
|
||||||
# Note this means that the backend IPv6-only server will only see
|
|
||||||
# the IPv6 address of the haproxy host managed by cdist, which can be
|
|
||||||
# troublesome if this information is relevant for analytics/security/...
|
|
||||||
# See the PROXY example below
|
|
||||||
__haproxy_dualstack \
|
|
||||||
--protocol http --protocol https \
|
|
||||||
--v4proxy ipv6.chat \
|
|
||||||
--v4proxy matrix.ungleich.ch
|
|
||||||
|
|
||||||
# Use the PROXY protocol to proxy the IPv6-only HTTP(S) services enabling
|
|
||||||
# IPv4-only clients to access them while maintaining the client's IP address
|
|
||||||
__haproxy_dualstack \
|
|
||||||
--protocol http --protocol https \
|
|
||||||
--v4proxy proxy:ipv6.chat:http=8080:https=591 \
|
|
||||||
--v4proxy proxy:matrix.ungleich.ch:http=8080:https=591
|
|
||||||
# Note however that the PROXY protocol is not compatible with regular
|
|
||||||
# HTTP(S) protocols, so your nginx will have to listen on different ports
|
|
||||||
# with the PROXY settings.
|
|
||||||
# Note that you will need to restrict access to the 8080 port to prevent
|
|
||||||
# Client IP spoofing.
|
|
||||||
# This can be something like:
|
|
||||||
# server {
|
|
||||||
# # listen for regular HTTP connections
|
|
||||||
# listen [::]:80 default_server;
|
|
||||||
# listen 80 default_server;
|
|
||||||
# # listen for PROXY HTTP connections
|
|
||||||
# listen [::]:8080 proxy_protocol;
|
|
||||||
# # Accept the Client's IP from the PROXY protocol
|
|
||||||
# real_ip_header proxy_protocol;
|
|
||||||
# }
|
|
||||||
|
|
||||||
|
|
||||||
SEE ALSO
|
|
||||||
--------
|
|
||||||
- https://www.haproxy.com/blog/enhanced-ssl-load-balancing-with-server-name-indication-sni-tls-extension/
|
|
||||||
- https://www.haproxy.com/blog/haproxy/proxy-protocol/
|
|
||||||
- https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/
|
|
||||||
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
-------
|
|
||||||
ungleich <foss--@--ungleich.ch>
|
|
||||||
Evilham <cvs--@--evilham.com>
|
|
||||||
|
|
||||||
|
|
||||||
COPYING
|
|
||||||
-------
|
|
||||||
Copyright \(C) 2021 ungleich glarus ag. 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.
|
|
|
@ -1,155 +0,0 @@
|
||||||
#!/bin/sh -eu
|
|
||||||
|
|
||||||
__package haproxy
|
|
||||||
require="__package/haproxy" __start_on_boot haproxy
|
|
||||||
|
|
||||||
tmpdir="$__object/files"
|
|
||||||
mkdir "$tmpdir"
|
|
||||||
configtmp="$__object/files/haproxy.cfg"
|
|
||||||
|
|
||||||
os=$(cat "$__global/explorer/os")
|
|
||||||
case $os in
|
|
||||||
freebsd)
|
|
||||||
CONFIG_FILE="/usr/local/etc/haproxy.conf"
|
|
||||||
cat <<EOF > "$configtmp"
|
|
||||||
global
|
|
||||||
maxconn 4000
|
|
||||||
user nobody
|
|
||||||
group nogroup
|
|
||||||
daemon
|
|
||||||
|
|
||||||
EOF
|
|
||||||
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
CONFIG_FILE="/etc/haproxy/haproxy.cfg"
|
|
||||||
cat <<EOF > "$configtmp"
|
|
||||||
global
|
|
||||||
log [::1] local2
|
|
||||||
chroot /var/lib/haproxy
|
|
||||||
pidfile /var/run/haproxy.pid
|
|
||||||
maxconn 4000
|
|
||||||
user haproxy
|
|
||||||
group haproxy
|
|
||||||
daemon
|
|
||||||
|
|
||||||
# turn on stats unix socket
|
|
||||||
stats socket /var/lib/haproxy/stats
|
|
||||||
|
|
||||||
EOF
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
cat <<EOF >> "$configtmp"
|
|
||||||
defaults
|
|
||||||
retries 3
|
|
||||||
log global
|
|
||||||
timeout http-request 10s
|
|
||||||
timeout queue 1m
|
|
||||||
timeout connect 10s
|
|
||||||
timeout client 1m
|
|
||||||
timeout server 1m
|
|
||||||
timeout http-keep-alive 10s
|
|
||||||
timeout check 10s
|
|
||||||
EOF
|
|
||||||
|
|
||||||
dig_cmd="$(command -v dig || true)"
|
|
||||||
get_ip() {
|
|
||||||
# Usage: get_ip (ipv4|ipv6) NAME
|
|
||||||
# uses "dig" if available, else fallback to "host"
|
|
||||||
case $1 in
|
|
||||||
ipv4)
|
|
||||||
if [ -n "${dig_cmd}" ]; then
|
|
||||||
${dig_cmd} +short A "$2"
|
|
||||||
else
|
|
||||||
host -t A "$2" | cut -d ' ' -f 4 | grep -v 'found:'
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
ipv6)
|
|
||||||
if [ -n "${dig_cmd}" ]; then
|
|
||||||
${dig_cmd} +short AAAA "$2"
|
|
||||||
else
|
|
||||||
host -t AAAA "$2" | cut -d ' ' -f 5 | grep -v 'NXDOMAIN'
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
PROTOCOLS="$(cat "$__object/parameter/protocol")"
|
|
||||||
|
|
||||||
for proxy in v4proxy v6proxy; do
|
|
||||||
param=$__object/parameter/$proxy
|
|
||||||
# no backend? skip generating code
|
|
||||||
if [ ! -f "$param" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# turn backend name into bind parameter: v4backend -> ipv4@
|
|
||||||
bind=$(echo $proxy | sed -e 's/^/ip/' -e 's/proxy//')
|
|
||||||
|
|
||||||
case $bind in
|
|
||||||
ipv4)
|
|
||||||
backendproto=ipv6
|
|
||||||
;;
|
|
||||||
ipv6)
|
|
||||||
backendproto=ipv4
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
for proto in ${PROTOCOLS}; do
|
|
||||||
# Add protocol "header"
|
|
||||||
printf "\n# %s %s \n" "${bind}" "${proto}" >> "$configtmp"
|
|
||||||
|
|
||||||
sed -e "s/BIND/$bind/" \
|
|
||||||
-e "s/\(frontend[[:space:]].*\)/\1$bind/" \
|
|
||||||
-e "s/\(backend[[:space:]].*\)/\\1$bind/" \
|
|
||||||
"$__type/files/$proto" >> "$configtmp"
|
|
||||||
|
|
||||||
while read -r hostdefinition; do
|
|
||||||
if echo "$hostdefinition" | grep -qE '^proxy:'; then
|
|
||||||
# Proxy protocol was requested
|
|
||||||
host="$(echo "$hostdefinition" | sed -E 's/^proxy:([^:]+).*$/\1/')"
|
|
||||||
send_proxy=" send-proxy"
|
|
||||||
else
|
|
||||||
# Just use tcp proxy mode
|
|
||||||
host="$hostdefinition"
|
|
||||||
send_proxy=""
|
|
||||||
fi
|
|
||||||
if echo "$hostdefinition" | grep -qE ":${proto}="; then
|
|
||||||
# Use custom port definition if requested
|
|
||||||
port="$(echo "$hostdefinition" | sed -E "s/^(.*:)?${proto}=([0-9]+).*$/:\2/")"
|
|
||||||
else
|
|
||||||
# Else use the default
|
|
||||||
port=""
|
|
||||||
fi
|
|
||||||
servername=$host
|
|
||||||
|
|
||||||
res=$(get_ip "$bind" "$servername")
|
|
||||||
|
|
||||||
if [ -z "$res" ]; then
|
|
||||||
echo "$servername does not resolve - aborting config" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Treat protocols without TLS+SNI specially
|
|
||||||
if [ "$proto" = http ]; then
|
|
||||||
echo " use-server $servername if { hdr(host) -i $host }" >> "$configtmp"
|
|
||||||
else
|
|
||||||
echo " use-server $servername if { req_ssl_sni -i $host }" >> "$configtmp"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create the "server" itself.
|
|
||||||
# Note that port and send_proxy will be empty unless
|
|
||||||
# they were requested by the type user
|
|
||||||
echo " server $servername ${backendproto}@${host}${port}${send_proxy}" >> "$configtmp"
|
|
||||||
|
|
||||||
done < "$param"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
# Create config file
|
|
||||||
require="__package/haproxy" __file ${CONFIG_FILE} --source "$configtmp" --mode 0644
|
|
||||||
|
|
||||||
require="__file${CONFIG_FILE}" __check_messages "haproxy_reload" \
|
|
||||||
--pattern "^__file${CONFIG_FILE}" \
|
|
||||||
--execute "service haproxy reload || service haproxy restart"
|
|
|
@ -1 +0,0 @@
|
||||||
http https imaps smtps
|
|
|
@ -1,3 +0,0 @@
|
||||||
protocol
|
|
||||||
v4proxy
|
|
||||||
v6proxy
|
|
|
@ -41,7 +41,7 @@ if [ -z "${certbot_fullpath}" ]; then
|
||||||
require="__apt_source/stretch-backports" __package_apt certbot \
|
require="__apt_source/stretch-backports" __package_apt certbot \
|
||||||
--target-release stretch-backports
|
--target-release stretch-backports
|
||||||
;;
|
;;
|
||||||
10*|11*)
|
10*)
|
||||||
__package_apt certbot
|
__package_apt certbot
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ if [ -z "${certbot_fullpath}" ]; then
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
freebsd)
|
freebsd)
|
||||||
__package py39-certbot
|
__package py37-certbot
|
||||||
certbot_fullpath="/usr/local/bin/certbot"
|
certbot_fullpath="/usr/local/bin/certbot"
|
||||||
;;
|
;;
|
||||||
ubuntu)
|
ubuntu)
|
||||||
|
|
|
@ -81,24 +81,12 @@ aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes -o Dpkg::Options::=
|
||||||
|
|
||||||
case "$state_should" in
|
case "$state_should" in
|
||||||
present)
|
present)
|
||||||
# There are special arguments to apt(8) to prevent aborts if apt woudn't been
|
|
||||||
# updated after the 19th April 2021 till the bullseye release. The additional
|
|
||||||
# arguments acknoledge the happend suite change (the apt(8) update does the
|
|
||||||
# same by itself).
|
|
||||||
#
|
|
||||||
# Using '-o $config' instead of the --allow-releaseinfo-change-* parameter
|
|
||||||
# allows backward compatablility to pre-buster Debian versions.
|
|
||||||
#
|
|
||||||
# See more: ticket #861
|
|
||||||
# https://code.ungleich.ch/ungleich-public/cdist/-/issues/861
|
|
||||||
apt_opts="-o Acquire::AllowReleaseInfoChange::Suite=true -o Acquire::AllowReleaseInfoChange::Version=true"
|
|
||||||
|
|
||||||
# following is bit ugly, but important hack.
|
# following is bit ugly, but important hack.
|
||||||
# due to how cdist config run works, there isn't
|
# due to how cdist config run works, there isn't
|
||||||
# currently better way to do it :(
|
# currently better way to do it :(
|
||||||
cat << EOF
|
cat << EOF
|
||||||
if [ ! -f /var/cache/apt/pkgcache.bin ] || [ "\$( stat --format %Y /var/cache/apt/pkgcache.bin )" -lt "\$( date +%s -d '-1 day' )" ]
|
if [ ! -f /var/cache/apt/pkgcache.bin ] || [ "\$( stat --format %Y /var/cache/apt/pkgcache.bin )" -lt "\$( date +%s -d '-1 day' )" ]
|
||||||
then echo apt-get $apt_opts update > /dev/null 2>&1 || true
|
then echo apt-get update > /dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
EOF
|
EOF
|
||||||
if [ -n "$version" ]; then
|
if [ -n "$version" ]; then
|
||||||
|
|
|
@ -41,19 +41,7 @@ fi
|
||||||
case "$type" in
|
case "$type" in
|
||||||
yum) ;;
|
yum) ;;
|
||||||
apt)
|
apt)
|
||||||
# There are special arguments to apt(8) to prevent aborts if apt woudn't been
|
echo "apt-get --quiet update"
|
||||||
# updated after the 19th April 2021 till the bullseye release. The additional
|
|
||||||
# arguments acknoledge the happend suite change (the apt(8) update does the
|
|
||||||
# same by itself).
|
|
||||||
#
|
|
||||||
# Using '-o $config' instead of the --allow-releaseinfo-change-* parameter
|
|
||||||
# allows backward compatablility to pre-buster Debian versions.
|
|
||||||
#
|
|
||||||
# See more: ticket #861
|
|
||||||
# https://code.ungleich.ch/ungleich-public/cdist/-/issues/861
|
|
||||||
apt_opts="-o Acquire::AllowReleaseInfoChange::Suite=true -o Acquire::AllowReleaseInfoChange::Version=true"
|
|
||||||
|
|
||||||
echo "apt-get --quiet $apt_opts update"
|
|
||||||
echo "apt-cache updated (age was: $currage)" >> "$__messages_out"
|
echo "apt-cache updated (age was: $currage)" >> "$__messages_out"
|
||||||
;;
|
;;
|
||||||
pacman)
|
pacman)
|
||||||
|
|
|
@ -28,10 +28,6 @@ apt_clean="$__object/parameter/apt-clean"
|
||||||
|
|
||||||
apt_dist_upgrade="$__object/parameter/apt-dist-upgrade"
|
apt_dist_upgrade="$__object/parameter/apt-dist-upgrade"
|
||||||
|
|
||||||
if [ -f "$__object/parameter/apt-with-new-pkgs" ]; then
|
|
||||||
apt_with_new_pkgs="--with-new-pkgs"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "$type" ]; then
|
if [ -f "$type" ]; then
|
||||||
type="$(cat "$type")"
|
type="$(cat "$type")"
|
||||||
else
|
else
|
||||||
|
@ -58,7 +54,7 @@ case "$type" in
|
||||||
apt)
|
apt)
|
||||||
if [ -f "$apt_dist_upgrade" ]
|
if [ -f "$apt_dist_upgrade" ]
|
||||||
then echo "$aptget dist-upgrade"
|
then echo "$aptget dist-upgrade"
|
||||||
else echo "$aptget $apt_with_new_pkgs upgrade"
|
else echo "$aptget upgrade"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f "$apt_clean" ]
|
if [ -f "$apt_clean" ]
|
||||||
|
|
|
@ -33,14 +33,6 @@ BOOLEAN PARAMETERS
|
||||||
apt-dist-upgrade
|
apt-dist-upgrade
|
||||||
Do dist-upgrade instead of upgrade.
|
Do dist-upgrade instead of upgrade.
|
||||||
|
|
||||||
apt-with-new-pkg
|
|
||||||
Allow installing new packages when used in conjunction with
|
|
||||||
upgrade. This is useful if the update of an installed package
|
|
||||||
requires new dependencies to be installed. Instead of holding the
|
|
||||||
package back upgrade will upgrade the package and install the new
|
|
||||||
dependencies. Note that upgrade with this option will never remove
|
|
||||||
packages, only allow adding new ones.
|
|
||||||
|
|
||||||
apt-clean
|
apt-clean
|
||||||
Clean out the local repository of retrieved package files.
|
Clean out the local repository of retrieved package files.
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
apt-clean
|
apt-clean
|
||||||
apt-dist-upgrade
|
apt-dist-upgrade
|
||||||
apt-with-new-pkgs
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
#!/bin/sh -e
|
|
||||||
|
|
||||||
if [ -f "$__object/parameter/file" ]
|
|
||||||
then
|
|
||||||
file="$( cat "$__object/parameter/file" )"
|
|
||||||
else
|
|
||||||
file="/$__object_id"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -e "$file" ]
|
|
||||||
then
|
|
||||||
echo "$file does not exist" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat "$file"
|
|
|
@ -1,58 +0,0 @@
|
||||||
#!/bin/sh -e
|
|
||||||
|
|
||||||
if [ -f "$__object/parameter/file" ]
|
|
||||||
then
|
|
||||||
file="$( cat "$__object/parameter/file" )"
|
|
||||||
else
|
|
||||||
file="/$__object_id"
|
|
||||||
fi
|
|
||||||
|
|
||||||
script="$( cat "$__object/parameter/script" )"
|
|
||||||
|
|
||||||
if [ "$script" = '-' ]
|
|
||||||
then
|
|
||||||
script="$( cat "$__object/stdin" )"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# since stdin is not available in explorer, we pull file from target with explorer
|
|
||||||
|
|
||||||
file_from_target="$__object/explorer/file"
|
|
||||||
|
|
||||||
sed_cmd='sed'
|
|
||||||
|
|
||||||
if [ -f "$__object/parameter/regexp-extended" ]
|
|
||||||
then
|
|
||||||
sed_cmd="$sed_cmd -E"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# do sed dry run, diff result and if no change, then there's nothing to do
|
|
||||||
# also redirect diff's output to stderr for debugging purposes
|
|
||||||
|
|
||||||
if echo "$script" | "$sed_cmd" -f - "$file_from_target" | diff -u "$file_from_target" - >&2
|
|
||||||
then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# we can't use -i, because it's not posix, so we fly with tempfile and cp
|
|
||||||
# and we use cp because we want to preserve destination file's attributes
|
|
||||||
|
|
||||||
# shellcheck disable=SC2016
|
|
||||||
echo 'tmp="$__object/tempfile"'
|
|
||||||
|
|
||||||
echo "$sed_cmd -f - '$file' > \"\$tmp\" << EOF"
|
|
||||||
|
|
||||||
echo "$script"
|
|
||||||
|
|
||||||
echo 'EOF'
|
|
||||||
|
|
||||||
echo "cp \"\$tmp\" '$file'"
|
|
||||||
|
|
||||||
# shellcheck disable=SC2016
|
|
||||||
echo 'rm -f "$tmp"'
|
|
||||||
|
|
||||||
echo 'change' >> "$__messages_out"
|
|
||||||
|
|
||||||
if [ -f "$__object/parameter/onchange" ]
|
|
||||||
then
|
|
||||||
cat "$__object/parameter/onchange"
|
|
||||||
fi
|
|
|
@ -1,57 +0,0 @@
|
||||||
cdist-type__sed(7)
|
|
||||||
==================
|
|
||||||
|
|
||||||
NAME
|
|
||||||
----
|
|
||||||
cdist-type__sed - Transform text files with ``sed``
|
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
-----------
|
|
||||||
Transform text files with ``sed``.
|
|
||||||
|
|
||||||
|
|
||||||
REQUIRED MULTIPLE PARAMETERS
|
|
||||||
----------------------------
|
|
||||||
script
|
|
||||||
``sed`` script.
|
|
||||||
If ``-`` then the script is read from ``stdin``.
|
|
||||||
|
|
||||||
|
|
||||||
OPTIONAL PARAMETERS
|
|
||||||
-------------------
|
|
||||||
file
|
|
||||||
Path to the file. Defaults to ``$__object_id``.
|
|
||||||
|
|
||||||
onchange
|
|
||||||
Execute this command if ``sed`` changes file.
|
|
||||||
|
|
||||||
|
|
||||||
BOOLEAN PARAMETERS
|
|
||||||
------------------
|
|
||||||
regexp-extended
|
|
||||||
Use extended regular expressions in the script.
|
|
||||||
Might not be supported with every ``sed`` version.
|
|
||||||
|
|
||||||
|
|
||||||
EXAMPLES
|
|
||||||
--------
|
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
__sed /tmp/foobar --script 's/foo/bar/'
|
|
||||||
|
|
||||||
echo 's/foo/bar/' | __sed foobar --file /tmp/foobar --script -
|
|
||||||
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
-------
|
|
||||||
Ander Punnar <ander-at-kvlt-dot-ee>
|
|
||||||
|
|
||||||
|
|
||||||
COPYING
|
|
||||||
-------
|
|
||||||
Copyright \(C) 2021 Ander Punnar. 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.
|
|
|
@ -1 +0,0 @@
|
||||||
regexp-extended
|
|
|
@ -1,2 +0,0 @@
|
||||||
file
|
|
||||||
onchange
|
|
|
@ -1 +0,0 @@
|
||||||
script
|
|
|
@ -40,7 +40,6 @@ if [ -f "$file" ]; then
|
||||||
grep -v -F -x '$line' '$file' >\$tmpfile
|
grep -v -F -x '$line' '$file' >\$tmpfile
|
||||||
fi
|
fi
|
||||||
cat "\$tmpfile" >"$file"
|
cat "\$tmpfile" >"$file"
|
||||||
rm -f "\$tmpfile"
|
|
||||||
DONE
|
DONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ import cdist.hostsource
|
||||||
import cdist.exec.local
|
import cdist.exec.local
|
||||||
import cdist.exec.remote
|
import cdist.exec.remote
|
||||||
import cdist.util.ipaddr as ipaddr
|
import cdist.util.ipaddr as ipaddr
|
||||||
|
import cdist.util.python_type_util as pytype_util
|
||||||
import cdist.configuration
|
import cdist.configuration
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,13 +92,15 @@ class Config:
|
||||||
shutil.rmtree(path)
|
shutil.rmtree(path)
|
||||||
|
|
||||||
def __init__(self, local, remote, dry_run=False, jobs=None,
|
def __init__(self, local, remote, dry_run=False, jobs=None,
|
||||||
cleanup_cmds=None, remove_remote_files_dirs=False):
|
cleanup_cmds=None, remove_remote_files_dirs=False,
|
||||||
|
timestamp=False):
|
||||||
|
|
||||||
self.local = local
|
self.local = local
|
||||||
self.remote = remote
|
self.remote = remote
|
||||||
self._open_logger()
|
self._open_logger()
|
||||||
self.dry_run = dry_run
|
self.dry_run = dry_run
|
||||||
self.jobs = jobs
|
self.jobs = jobs
|
||||||
|
self.timestamp = timestamp
|
||||||
if cleanup_cmds:
|
if cleanup_cmds:
|
||||||
self.cleanup_cmds = cleanup_cmds
|
self.cleanup_cmds = cleanup_cmds
|
||||||
else:
|
else:
|
||||||
|
@ -437,7 +440,8 @@ class Config:
|
||||||
cleanup_cmds.append(cleanup_cmd)
|
cleanup_cmds.append(cleanup_cmd)
|
||||||
c = cls(local, remote, dry_run=args.dry_run, jobs=args.jobs,
|
c = cls(local, remote, dry_run=args.dry_run, jobs=args.jobs,
|
||||||
cleanup_cmds=cleanup_cmds,
|
cleanup_cmds=cleanup_cmds,
|
||||||
remove_remote_files_dirs=remove_remote_files_dirs)
|
remove_remote_files_dirs=remove_remote_files_dirs,
|
||||||
|
timestamp=args.timestamp)
|
||||||
c.run()
|
c.run()
|
||||||
cls._remove_paths()
|
cls._remove_paths()
|
||||||
|
|
||||||
|
@ -475,6 +479,7 @@ class Config:
|
||||||
'dry' if self.dry_run else 'configuration')
|
'dry' if self.dry_run else 'configuration')
|
||||||
|
|
||||||
self._init_files_dirs()
|
self._init_files_dirs()
|
||||||
|
self.local.collect_python_types()
|
||||||
|
|
||||||
self.explorer.run_global_explorers(self.local.global_explorer_out_path)
|
self.explorer.run_global_explorers(self.local.global_explorer_out_path)
|
||||||
try:
|
try:
|
||||||
|
@ -790,6 +795,21 @@ class Config:
|
||||||
args = [param, cdist_type.name]
|
args = [param, cdist_type.name]
|
||||||
self.log.warning(format, *args)
|
self.log.warning(format, *args)
|
||||||
|
|
||||||
|
def _timeit(self, func, msg_prefix):
|
||||||
|
def wrapper_func(*args, **kwargs):
|
||||||
|
loglevel = self.log.getEffectiveLevel()
|
||||||
|
if loglevel >= logging.VERBOSE and self.timestamp:
|
||||||
|
start_time = time.time()
|
||||||
|
rv = func(*args, **kwargs)
|
||||||
|
end_time = time.time()
|
||||||
|
duration = end_time - start_time
|
||||||
|
self.log.verbose("%s duration: %.6f seconds",
|
||||||
|
msg_prefix, duration)
|
||||||
|
else:
|
||||||
|
rv = func(*args, **kwargs)
|
||||||
|
return rv
|
||||||
|
return wrapper_func
|
||||||
|
|
||||||
def object_prepare(self, cdist_object, transfer_type_explorers=True):
|
def object_prepare(self, cdist_object, transfer_type_explorers=True):
|
||||||
"""Prepare object: Run type explorer + manifest"""
|
"""Prepare object: Run type explorer + manifest"""
|
||||||
self._handle_deprecation(cdist_object)
|
self._handle_deprecation(cdist_object)
|
||||||
|
@ -798,7 +818,19 @@ class Config:
|
||||||
cdist_object.name)
|
cdist_object.name)
|
||||||
self.explorer.run_type_explorers(cdist_object, transfer_type_explorers)
|
self.explorer.run_type_explorers(cdist_object, transfer_type_explorers)
|
||||||
try:
|
try:
|
||||||
self.manifest.run_type_manifest(cdist_object)
|
self.log.verbose("Preparing object {}".format(cdist_object.name))
|
||||||
|
self.log.verbose(
|
||||||
|
"Running manifest and explorers for " + cdist_object.name)
|
||||||
|
self.explorer.run_type_explorers(cdist_object,
|
||||||
|
transfer_type_explorers)
|
||||||
|
if pytype_util.is_python_type(cdist_object.cdist_type):
|
||||||
|
self._timeit(self.manifest.run_py_type_manifest,
|
||||||
|
"Python type manifest for {}".format(
|
||||||
|
cdist_object.name))(cdist_object)
|
||||||
|
else:
|
||||||
|
self._timeit(self.manifest.run_type_manifest,
|
||||||
|
"Type manifest for {}".format(
|
||||||
|
cdist_object.name))(cdist_object)
|
||||||
self.log.trace("[ORDER_DEP] Removing order dep files for %s",
|
self.log.trace("[ORDER_DEP] Removing order dep files for %s",
|
||||||
cdist_object)
|
cdist_object)
|
||||||
cdist_object.cleanup()
|
cdist_object.cleanup()
|
||||||
|
@ -816,9 +848,21 @@ class Config:
|
||||||
|
|
||||||
# Generate
|
# Generate
|
||||||
self.log.debug("Generating code for %s", cdist_object.name)
|
self.log.debug("Generating code for %s", cdist_object.name)
|
||||||
cdist_object.code_local = self.code.run_gencode_local(cdist_object)
|
if pytype_util.is_python_type(cdist_object.cdist_type):
|
||||||
cdist_object.code_remote = self.code.run_gencode_remote(
|
cdist_object.code_local = ''
|
||||||
cdist_object)
|
cdist_object.code_remote = self._timeit(
|
||||||
|
self.code.run_py,
|
||||||
|
"Python type generate code for {}".format(
|
||||||
|
cdist_object.name))(cdist_object)
|
||||||
|
else:
|
||||||
|
cdist_object.code_local = self._timeit(
|
||||||
|
self.code.run_gencode_local,
|
||||||
|
"Type generate code local for {}".format(
|
||||||
|
cdist_object.name))(cdist_object)
|
||||||
|
cdist_object.code_remote = self._timeit(
|
||||||
|
self.code.run_gencode_remote,
|
||||||
|
"Type generate code remote for {}".format(
|
||||||
|
cdist_object.name))(cdist_object)
|
||||||
if cdist_object.code_local or cdist_object.code_remote:
|
if cdist_object.code_local or cdist_object.code_remote:
|
||||||
cdist_object.changed = True
|
cdist_object.changed = True
|
||||||
|
|
||||||
|
@ -829,12 +873,16 @@ class Config:
|
||||||
if cdist_object.code_local:
|
if cdist_object.code_local:
|
||||||
self.log.trace("Executing local code for %s",
|
self.log.trace("Executing local code for %s",
|
||||||
cdist_object.name)
|
cdist_object.name)
|
||||||
self.code.run_code_local(cdist_object)
|
self._timeit(self.code.run_code_local,
|
||||||
|
"Type run code local for {}".format(
|
||||||
|
cdist_object.name))(cdist_object)
|
||||||
if cdist_object.code_remote:
|
if cdist_object.code_remote:
|
||||||
self.log.trace("Executing remote code for %s",
|
self.log.trace("Executing remote code for %s",
|
||||||
cdist_object.name)
|
cdist_object.name)
|
||||||
self.code.transfer_code_remote(cdist_object)
|
self.code.transfer_code_remote(cdist_object)
|
||||||
self.code.run_code_remote(cdist_object)
|
self._timeit(self.code.run_code_remote,
|
||||||
|
"Type run code remote for {}".format(
|
||||||
|
cdist_object.name))(cdist_object)
|
||||||
|
|
||||||
# Mark this object as done
|
# Mark this object as done
|
||||||
self.log.trace("Finishing run of %s", cdist_object.name)
|
self.log.trace("Finishing run of %s", cdist_object.name)
|
||||||
|
|
|
@ -29,3 +29,4 @@ from cdist.core.manifest import Manifest
|
||||||
from cdist.core.code import Code
|
from cdist.core.code import Code
|
||||||
from cdist.core.util import listdir
|
from cdist.core.util import listdir
|
||||||
from cdist.core.util import log_level_env_var_val, log_level_name_env_var_val
|
from cdist.core.util import log_level_env_var_val, log_level_name_env_var_val
|
||||||
|
import cdist.core.pytypes
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import inspect
|
||||||
|
from cdist.core.pytypes import get_pytype_class
|
||||||
from . import util
|
from . import util
|
||||||
|
|
||||||
|
|
||||||
|
@ -120,6 +122,27 @@ class Code:
|
||||||
self.env['__cdist_log_server_socket'] = os.environ[
|
self.env['__cdist_log_server_socket'] = os.environ[
|
||||||
'__cdist_log_server_socket_export']
|
'__cdist_log_server_socket_export']
|
||||||
|
|
||||||
|
def run_py(self, cdist_object):
|
||||||
|
cdist_type = cdist_object.cdist_type
|
||||||
|
type_class = get_pytype_class(cdist_type)
|
||||||
|
if type_class is not None:
|
||||||
|
env = os.environ.copy()
|
||||||
|
env.update(self.env)
|
||||||
|
message_prefix = cdist_object.name
|
||||||
|
type_obj = type_class(env=env, cdist_object=cdist_object,
|
||||||
|
local=self.local, remote=self.remote,
|
||||||
|
message_prefix=message_prefix)
|
||||||
|
if hasattr(type_obj, 'run') and inspect.ismethod(type_obj.run):
|
||||||
|
if self.local.save_output_streams:
|
||||||
|
which = 'gencode-py'
|
||||||
|
stderr_path = os.path.join(cdist_object.stderr_path, which)
|
||||||
|
stdout_path = os.path.join(cdist_object.stdout_path, which)
|
||||||
|
with open(stderr_path, 'a+') as stderr, \
|
||||||
|
open(stdout_path, 'a+') as stdout:
|
||||||
|
return type_obj.run(stdout=stdout, stderr=stderr)
|
||||||
|
else:
|
||||||
|
return type_obj.run()
|
||||||
|
|
||||||
def _run_gencode(self, cdist_object, which):
|
def _run_gencode(self, cdist_object, which):
|
||||||
cdist_type = cdist_object.cdist_type
|
cdist_type = cdist_object.cdist_type
|
||||||
gencode_attr = getattr(cdist_type, 'gencode_{}_path'.format(which))
|
gencode_attr = getattr(cdist_type, 'gencode_{}_path'.format(which))
|
||||||
|
|
|
@ -22,9 +22,12 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import inspect
|
||||||
import cdist
|
import cdist
|
||||||
|
import cdist.emulator
|
||||||
from . import util
|
from . import util
|
||||||
|
from cdist.core.pytypes import Command, get_pytype_class
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
common:
|
common:
|
||||||
|
@ -96,9 +99,6 @@ class Manifest:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ORDER_DEP_STATE_NAME = 'order_dep_state'
|
|
||||||
TYPEORDER_DEP_NAME = 'typeorder_dep'
|
|
||||||
|
|
||||||
def __init__(self, target_host, local, dry_run=False):
|
def __init__(self, target_host, local, dry_run=False):
|
||||||
self.target_host = target_host
|
self.target_host = target_host
|
||||||
self.local = local
|
self.local = local
|
||||||
|
@ -225,5 +225,58 @@ class Manifest:
|
||||||
os.remove(os.path.join(self.local.base_path, fname))
|
os.remove(os.path.join(self.local.base_path, fname))
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
_rm_file(Manifest.ORDER_DEP_STATE_NAME)
|
_rm_file(cdist.ORDER_DEP_STATE_NAME)
|
||||||
_rm_file(Manifest.TYPEORDER_DEP_NAME)
|
_rm_file(cdist.TYPEORDER_DEP_NAME)
|
||||||
|
|
||||||
|
def env_py_type_manifest(self, cdist_object):
|
||||||
|
env = os.environ.copy()
|
||||||
|
env.update(self.env)
|
||||||
|
env.update({
|
||||||
|
'__cdist_object_marker': self.local.object_marker_name,
|
||||||
|
'__cdist_manifest': cdist_object.cdist_type,
|
||||||
|
'__manifest': self.local.manifest_path,
|
||||||
|
'__object': cdist_object.absolute_path,
|
||||||
|
'__object_id': cdist_object.object_id,
|
||||||
|
'__object_name': cdist_object.name,
|
||||||
|
'__type': cdist_object.cdist_type.absolute_path,
|
||||||
|
})
|
||||||
|
|
||||||
|
return env
|
||||||
|
|
||||||
|
def run_py_type_manifest(self, cdist_object):
|
||||||
|
cdist_type = cdist_object.cdist_type
|
||||||
|
type_class = get_pytype_class(cdist_type)
|
||||||
|
if type_class is not None:
|
||||||
|
self.log.verbose("Running python type manifest for object %s",
|
||||||
|
cdist_object.name)
|
||||||
|
message_prefix = cdist_object.name
|
||||||
|
env = self.env_py_type_manifest(cdist_object)
|
||||||
|
type_obj = type_class(env=env, cdist_object=cdist_object,
|
||||||
|
local=self.local, remote=None,
|
||||||
|
message_prefix=message_prefix)
|
||||||
|
if self.local.save_output_streams:
|
||||||
|
which = 'manifest'
|
||||||
|
stderr_path = os.path.join(cdist_object.stderr_path, which)
|
||||||
|
stdout_path = os.path.join(cdist_object.stdout_path, which)
|
||||||
|
with open(stderr_path, 'a+') as stderr, \
|
||||||
|
open(stdout_path, 'a+') as stdout:
|
||||||
|
self._process_py_type_manifest_entries(
|
||||||
|
type_obj, env, stdout=stdout, stderr=stderr)
|
||||||
|
else:
|
||||||
|
self._process_py_type_manifest_entries(type_obj, env)
|
||||||
|
|
||||||
|
def _process_py_type_manifest_entries(self, type_obj, env, stdout=None,
|
||||||
|
stderr=None):
|
||||||
|
if hasattr(type_obj, 'manifest') and \
|
||||||
|
inspect.ismethod(type_obj.manifest):
|
||||||
|
for cmd in type_obj.manifest(stdout=stdout, stderr=stderr):
|
||||||
|
if not isinstance(cmd, Command):
|
||||||
|
raise TypeError("Manifest command must be of type Command")
|
||||||
|
kwargs = {
|
||||||
|
'argv': cmd.cmd_line(),
|
||||||
|
'env': env,
|
||||||
|
}
|
||||||
|
if cmd.stdin:
|
||||||
|
kwargs['stdin'] = cmd.stdin
|
||||||
|
emulator = cdist.emulator.Emulator(**kwargs)
|
||||||
|
emulator.run()
|
||||||
|
|
190
cdist/core/pytypes.py
Normal file
190
cdist/core/pytypes.py
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import io
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
from cdist import message, Error
|
||||||
|
import importlib.util
|
||||||
|
import inspect
|
||||||
|
import cdist
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["PythonType", "Command", "command"]
|
||||||
|
|
||||||
|
|
||||||
|
class PythonType:
|
||||||
|
def __init__(self, env, cdist_object, local, remote, message_prefix=None):
|
||||||
|
self.env = env
|
||||||
|
self.cdist_object = cdist_object
|
||||||
|
self.local = local
|
||||||
|
self.remote = remote
|
||||||
|
if self.cdist_object:
|
||||||
|
self.object_id = cdist_object.object_id
|
||||||
|
self.object_name = cdist_object.name
|
||||||
|
self.cdist_type = cdist_object.cdist_type
|
||||||
|
self.object_path = cdist_object.absolute_path
|
||||||
|
self.explorer_path = os.path.join(self.object_path, 'explorer')
|
||||||
|
self.type_path = cdist_object.cdist_type.absolute_path
|
||||||
|
self.parameters = cdist_object.parameters
|
||||||
|
self.stdin_path = os.path.join(self.object_path, 'stdin')
|
||||||
|
if self.local:
|
||||||
|
self.log = logging.getLogger(
|
||||||
|
self.local.target_host[0] + ':' + self.object_name)
|
||||||
|
|
||||||
|
self.message_prefix = message_prefix
|
||||||
|
self.message = None
|
||||||
|
|
||||||
|
def get_parameter(self, name):
|
||||||
|
return self.parameters.get(name)
|
||||||
|
|
||||||
|
def get_explorer_file(self, name):
|
||||||
|
path = os.path.join(self.explorer_path, name)
|
||||||
|
return path
|
||||||
|
|
||||||
|
def get_explorer(self, name):
|
||||||
|
path = self.get_explorer_file(name)
|
||||||
|
with open(path, 'r') as f:
|
||||||
|
value = f.read()
|
||||||
|
if value:
|
||||||
|
value = value.strip()
|
||||||
|
return value
|
||||||
|
|
||||||
|
def run_local(self, command, env=None):
|
||||||
|
rv = self.local.run(command, env=env, return_output=True)
|
||||||
|
if rv:
|
||||||
|
rv = rv.rstrip('\n')
|
||||||
|
return rv
|
||||||
|
|
||||||
|
def run_remote(self, command, env=None):
|
||||||
|
rv = self.remote.run(command, env=env, return_output=True)
|
||||||
|
if rv:
|
||||||
|
rv = rv.rstrip('\n')
|
||||||
|
return rv
|
||||||
|
|
||||||
|
def transfer(self, source, destination):
|
||||||
|
self.remote.transfer(source, destination)
|
||||||
|
|
||||||
|
def die(self, msg):
|
||||||
|
raise Error("{}: {}".format(self.cdist_object, msg))
|
||||||
|
|
||||||
|
def manifest(self, stdout=None, stderr=None):
|
||||||
|
try:
|
||||||
|
if self.message_prefix:
|
||||||
|
self.message = message.Message(self.message_prefix,
|
||||||
|
self.local.messages_path)
|
||||||
|
self.env.update(self.message.env)
|
||||||
|
if stdout is not None:
|
||||||
|
stdout_save = sys.stdout
|
||||||
|
sys.stdout = stdout
|
||||||
|
if stderr is not None:
|
||||||
|
stderr_save = sys.stderr
|
||||||
|
sys.stderr = stderr
|
||||||
|
yield from self.type_manifest()
|
||||||
|
finally:
|
||||||
|
if self.message:
|
||||||
|
self.message.merge_messages()
|
||||||
|
if stdout is not None:
|
||||||
|
sys.stdout = stdout_save
|
||||||
|
if stderr is not None:
|
||||||
|
sys.stderr = stderr_save
|
||||||
|
|
||||||
|
def run(self, stdout=None, stderr=None):
|
||||||
|
try:
|
||||||
|
if self.message_prefix:
|
||||||
|
self.message = message.Message(self.message_prefix,
|
||||||
|
self.local.messages_path)
|
||||||
|
if stdout is not None:
|
||||||
|
stdout_save = sys.stdout
|
||||||
|
sys.stdout = stdout
|
||||||
|
if stderr is not None:
|
||||||
|
stderr_save = sys.stderr
|
||||||
|
sys.stderr = stderr
|
||||||
|
return self.type_gencode()
|
||||||
|
finally:
|
||||||
|
if self.message:
|
||||||
|
self.message.merge_messages()
|
||||||
|
if stdout is not None:
|
||||||
|
sys.stdout = stdout_save
|
||||||
|
if stderr is not None:
|
||||||
|
sys.stderr = stderr_save
|
||||||
|
|
||||||
|
def send_message(self, msg):
|
||||||
|
if self.message:
|
||||||
|
with open(self.message.messages_out, 'a') as f:
|
||||||
|
print(msg, file=f)
|
||||||
|
|
||||||
|
def receive_message(self, pattern):
|
||||||
|
if self.message:
|
||||||
|
with open(self.message.messages_in, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
match = re.search(pattern, line)
|
||||||
|
if match:
|
||||||
|
return match
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_args_parser(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def type_manifest(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def type_gencode(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Command:
|
||||||
|
def __init__(self, name, *args, **kwargs):
|
||||||
|
self.name = name
|
||||||
|
self.args = args
|
||||||
|
self.kwargs = kwargs
|
||||||
|
self.stdin = None
|
||||||
|
|
||||||
|
def feed_stdin(self, value):
|
||||||
|
# If file-like object then read its value.
|
||||||
|
if value is not None and isinstance(value, io.IOBase):
|
||||||
|
value = value.read()
|
||||||
|
|
||||||
|
# Convert to bytes file-like object.
|
||||||
|
if value is None:
|
||||||
|
self.stdin = None
|
||||||
|
elif isinstance(value, str):
|
||||||
|
self.stdin = io.BytesIO(value.encode('utf-8'))
|
||||||
|
elif isinstance(value, bytes) or isinstance(value, bytearray):
|
||||||
|
self.stdin = io.BytesIO(value)
|
||||||
|
else:
|
||||||
|
raise TypeError("value must be str, bytes, bytearray, file-like "
|
||||||
|
"object or None")
|
||||||
|
return self
|
||||||
|
|
||||||
|
def cmd_line(self):
|
||||||
|
argv = [self.name, ]
|
||||||
|
for param in self.args:
|
||||||
|
argv.append(param)
|
||||||
|
for key, value in self.kwargs.items():
|
||||||
|
argv.append("--{}".format(key))
|
||||||
|
argv.append(value)
|
||||||
|
return argv
|
||||||
|
|
||||||
|
|
||||||
|
def command(name, *args, **kwargs):
|
||||||
|
return Command(name, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def get_pytype_class(cdist_type):
|
||||||
|
module_name = cdist_type.name
|
||||||
|
file_path = os.path.join(cdist_type.absolute_path, '__init__.py')
|
||||||
|
type_class = None
|
||||||
|
if os.path.isfile(file_path):
|
||||||
|
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
||||||
|
m = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(m)
|
||||||
|
classes = inspect.getmembers(m, inspect.isclass)
|
||||||
|
for _, cl in classes:
|
||||||
|
if cl != PythonType and issubclass(cl, PythonType):
|
||||||
|
if type_class:
|
||||||
|
raise cdist.Error(
|
||||||
|
"Only one python type class is supported, but at least"
|
||||||
|
" two found: {}".format((type_class, cl, )))
|
||||||
|
else:
|
||||||
|
type_class = cl
|
||||||
|
return type_class
|
|
@ -30,7 +30,9 @@ import re
|
||||||
import cdist
|
import cdist
|
||||||
from cdist import core
|
from cdist import core
|
||||||
from cdist import flock
|
from cdist import flock
|
||||||
from cdist.core.manifest import Manifest
|
import cdist.util.python_type_util as pytype_util
|
||||||
|
from cdist.core.pytypes import get_pytype_class
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
|
||||||
class MissingRequiredEnvironmentVariableError(cdist.Error):
|
class MissingRequiredEnvironmentVariableError(cdist.Error):
|
||||||
|
@ -85,9 +87,9 @@ class Emulator:
|
||||||
self.typeorder_path = os.path.join(self.global_path, "typeorder")
|
self.typeorder_path = os.path.join(self.global_path, "typeorder")
|
||||||
|
|
||||||
self.typeorder_dep_path = os.path.join(self.global_path,
|
self.typeorder_dep_path = os.path.join(self.global_path,
|
||||||
Manifest.TYPEORDER_DEP_NAME)
|
cdist.TYPEORDER_DEP_NAME)
|
||||||
self.order_dep_state_path = os.path.join(self.global_path,
|
self.order_dep_state_path = os.path.join(self.global_path,
|
||||||
Manifest.ORDER_DEP_STATE_NAME)
|
cdist.ORDER_DEP_STATE_NAME)
|
||||||
|
|
||||||
self.type_name = os.path.basename(argv[0])
|
self.type_name = os.path.basename(argv[0])
|
||||||
self.cdist_type = core.CdistType(self.type_base_path, self.type_name)
|
self.cdist_type = core.CdistType(self.type_base_path, self.type_name)
|
||||||
|
@ -97,7 +99,28 @@ class Emulator:
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Emulate type commands (i.e. __file and co)"""
|
"""Emulate type commands (i.e. __file and co)"""
|
||||||
|
|
||||||
self.commandline()
|
args_parser = None
|
||||||
|
if pytype_util.is_python_type(self.cdist_type):
|
||||||
|
type_class = get_pytype_class(self.cdist_type)
|
||||||
|
if type_class is not None:
|
||||||
|
# We only need to call parse_args so we need plain instance.
|
||||||
|
type_obj = type_class(env=None, cdist_object=None, local=None,
|
||||||
|
remote=None)
|
||||||
|
if (hasattr(type_obj, 'get_args_parser') and
|
||||||
|
inspect.ismethod(type_obj.get_args_parser)):
|
||||||
|
args_parser = type_obj.get_args_parser()
|
||||||
|
self.log.trace("Using python type argument parser")
|
||||||
|
print("Using python type argument parser")
|
||||||
|
if args_parser is None:
|
||||||
|
# Fallback to classic way.
|
||||||
|
args_parser = self.get_args_parser()
|
||||||
|
self.log.trace("Fallback to classic argument parser")
|
||||||
|
print("Fallback to classic argument parser")
|
||||||
|
else:
|
||||||
|
args_parser = self.get_args_parser()
|
||||||
|
self.log.trace("Using emulator classic argument parser")
|
||||||
|
print("Using emulator classic argument parser")
|
||||||
|
self.commandline(args_parser)
|
||||||
self.init_object()
|
self.init_object()
|
||||||
|
|
||||||
# locking for parallel execution
|
# locking for parallel execution
|
||||||
|
@ -133,9 +156,7 @@ class Emulator:
|
||||||
colored_log = self.env.get('__cdist_colored_log', 'false')
|
colored_log = self.env.get('__cdist_colored_log', 'false')
|
||||||
cdist.log.CdistFormatter.USE_COLORS = colored_log == 'true'
|
cdist.log.CdistFormatter.USE_COLORS = colored_log == 'true'
|
||||||
|
|
||||||
def commandline(self):
|
def get_args_parser(self):
|
||||||
"""Parse command line"""
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(add_help=False,
|
parser = argparse.ArgumentParser(add_help=False,
|
||||||
argument_default=argparse.SUPPRESS)
|
argument_default=argparse.SUPPRESS)
|
||||||
|
|
||||||
|
@ -167,8 +188,10 @@ class Emulator:
|
||||||
# If not singleton support one positional parameter
|
# If not singleton support one positional parameter
|
||||||
if not self.cdist_type.is_singleton:
|
if not self.cdist_type.is_singleton:
|
||||||
parser.add_argument("object_id", nargs=1)
|
parser.add_argument("object_id", nargs=1)
|
||||||
|
return parser
|
||||||
|
|
||||||
# And finally parse/verify parameter
|
def commandline(self, parser):
|
||||||
|
"""Parse command line"""
|
||||||
self.args = parser.parse_args(self.argv[1:])
|
self.args = parser.parse_args(self.argv[1:])
|
||||||
self.log.trace('Args: %s', self.args)
|
self.log.trace('Args: %s', self.args)
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,9 @@ import cdist
|
||||||
import cdist.message
|
import cdist.message
|
||||||
from cdist import core
|
from cdist import core
|
||||||
import cdist.exec.util as util
|
import cdist.exec.util as util
|
||||||
|
import cdist.util.python_type_util as pytype_util
|
||||||
|
from cdist.core import pytypes
|
||||||
|
import functools
|
||||||
|
|
||||||
CONF_SUBDIRS_LINKED = ["explorer", "files", "manifest", "type", ]
|
CONF_SUBDIRS_LINKED = ["explorer", "files", "manifest", "type", ]
|
||||||
|
|
||||||
|
@ -369,3 +372,16 @@ class Local:
|
||||||
raise cdist.Error(
|
raise cdist.Error(
|
||||||
"Linking emulator from {} to {} failed: {}".format(
|
"Linking emulator from {} to {} failed: {}".format(
|
||||||
src, dst, e.__str__()))
|
src, dst, e.__str__()))
|
||||||
|
|
||||||
|
def collect_python_types(self):
|
||||||
|
for cdist_type in core.CdistType.list_types(self.type_path):
|
||||||
|
if pytype_util.is_python_type(cdist_type):
|
||||||
|
self.log.trace("Detected python type %s, collecting it".format(
|
||||||
|
cdist_type.name))
|
||||||
|
f = functools.partial(pytypes.command, cdist_type.name)
|
||||||
|
if cdist_type.name.startswith('__'):
|
||||||
|
attr_name = cdist_type.name.replace('__', '', 1)
|
||||||
|
else:
|
||||||
|
attr_name = cdist_type.name
|
||||||
|
setattr(pytypes, attr_name, f)
|
||||||
|
pytypes.__all__.append(attr_name)
|
||||||
|
|
|
@ -84,7 +84,7 @@ def _process_hosts_simple(action, host, manifest, verbose,
|
||||||
"""
|
"""
|
||||||
if isinstance(host, str):
|
if isinstance(host, str):
|
||||||
hosts = [host, ]
|
hosts = [host, ]
|
||||||
elif isinstance(host, collections.abc.Iterable):
|
elif isinstance(host, collections.Iterable):
|
||||||
hosts = host
|
hosts = host
|
||||||
else:
|
else:
|
||||||
raise cdist.Error('Invalid host argument: {}'.format(host))
|
raise cdist.Error('Invalid host argument: {}'.format(host))
|
||||||
|
|
|
@ -126,6 +126,12 @@ class Debian:
|
||||||
help="suite used for debootstrap, "
|
help="suite used for debootstrap, "
|
||||||
"by default '{}'".format(defargs.suite),
|
"by default '{}'".format(defargs.suite),
|
||||||
dest='suite', default=defargs.suite)
|
dest='suite', default=defargs.suite)
|
||||||
|
parser.add_argument(
|
||||||
|
'-t', '--trigger-command',
|
||||||
|
help=("trigger command that will be added to cdist config; "
|
||||||
|
"'__cdist_preos_trigger http ...' type is appended to "
|
||||||
|
"initial manifest"),
|
||||||
|
dest='trigger_command')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-y', '--remote-copy',
|
'-y', '--remote-copy',
|
||||||
help=("remote copy that cdist config will use, by default "
|
help=("remote copy that cdist config will use, by default "
|
||||||
|
|
|
@ -127,6 +127,13 @@ then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "${trigger_command}" ]
|
||||||
|
then
|
||||||
|
trigger_line="__cdist_preos_trigger http --trigger-command '${trigger_command}'\n"
|
||||||
|
else
|
||||||
|
trigger_line=""
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "${keyfile_cnt}" -a "${keyfile_cnt}" -gt 0 ]
|
if [ "${keyfile_cnt}" -a "${keyfile_cnt}" -gt 0 ]
|
||||||
then
|
then
|
||||||
i="$((keyfile_cnt - 1))"
|
i="$((keyfile_cnt - 1))"
|
||||||
|
@ -174,7 +181,7 @@ then
|
||||||
fi
|
fi
|
||||||
grub_lines="${grub_manifest_line}${grub_kern_params_line}"
|
grub_lines="${grub_manifest_line}${grub_kern_params_line}"
|
||||||
|
|
||||||
printf "${ssh_auth_keys_line}${grub_lines}" \
|
printf "${trigger_line}${ssh_auth_keys_line}${grub_lines}" \
|
||||||
| cat "${manifest}" - |\
|
| cat "${manifest}" - |\
|
||||||
cdist config \
|
cdist config \
|
||||||
${cdist_params} -i - \
|
${cdist_params} -i - \
|
||||||
|
|
229
cdist/trigger.py
Normal file
229
cdist/trigger.py
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# 2016 Nico Schottelius (nico-cdist at schottelius.org)
|
||||||
|
#
|
||||||
|
# This file is part of cdist.
|
||||||
|
#
|
||||||
|
# cdist is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# cdist is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
import ipaddress
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
import socket
|
||||||
|
import http.server
|
||||||
|
import os
|
||||||
|
import socketserver
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
import cdist.config
|
||||||
|
import cdist.log
|
||||||
|
import cdist.util.ipaddr as ipaddr
|
||||||
|
|
||||||
|
|
||||||
|
class Trigger():
|
||||||
|
"""cdist trigger handling"""
|
||||||
|
|
||||||
|
# Arguments that are only trigger specific
|
||||||
|
triggers_args = ["http_port", "ipv6", "directory", "source", ]
|
||||||
|
|
||||||
|
def __init__(self, http_port=None, dry_run=False, ipv6=False,
|
||||||
|
directory=None, source=None, cdistargs=None):
|
||||||
|
self.dry_run = dry_run
|
||||||
|
self.http_port = int(http_port)
|
||||||
|
self.ipv6 = ipv6
|
||||||
|
self.args = cdistargs
|
||||||
|
|
||||||
|
self.directory = directory
|
||||||
|
self.source = source
|
||||||
|
|
||||||
|
log.debug("IPv6: %s", self.ipv6)
|
||||||
|
|
||||||
|
def run_httpd(self):
|
||||||
|
server_address = ('', self.http_port)
|
||||||
|
|
||||||
|
if self.ipv6:
|
||||||
|
httpdcls = HTTPServerV6
|
||||||
|
else:
|
||||||
|
httpdcls = HTTPServerV4
|
||||||
|
httpd = httpdcls(self.args, self.directory, self.source,
|
||||||
|
server_address, TriggerHttp)
|
||||||
|
|
||||||
|
log.debug("Starting server at port %d", self.http_port)
|
||||||
|
if self.dry_run:
|
||||||
|
log.debug("Running in dry run mode")
|
||||||
|
httpd.serve_forever()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
if self.http_port:
|
||||||
|
self.run_httpd()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def commandline(cls, args):
|
||||||
|
global log
|
||||||
|
|
||||||
|
# remove root logger default cdist handler and configure trigger's own
|
||||||
|
logging.getLogger().handlers = []
|
||||||
|
logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s')
|
||||||
|
|
||||||
|
log = logging.getLogger("trigger")
|
||||||
|
ownargs = {}
|
||||||
|
for targ in cls.triggers_args:
|
||||||
|
arg = getattr(args, targ)
|
||||||
|
ownargs[targ] = arg
|
||||||
|
|
||||||
|
del arg
|
||||||
|
|
||||||
|
t = cls(dry_run=args.dry_run, cdistargs=args, **ownargs)
|
||||||
|
t.run()
|
||||||
|
|
||||||
|
|
||||||
|
class TriggerHttp(http.server.BaseHTTPRequestHandler):
|
||||||
|
actions = {
|
||||||
|
"cdist": ["config", "install", ],
|
||||||
|
"file": ["present", "absent", ],
|
||||||
|
}
|
||||||
|
|
||||||
|
def do_HEAD(self):
|
||||||
|
self.dispatch_request()
|
||||||
|
|
||||||
|
def do_POST(self):
|
||||||
|
self.dispatch_request()
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
self.dispatch_request()
|
||||||
|
|
||||||
|
def _actions_regex(self):
|
||||||
|
regex = ["^/(?P<subsystem>", ]
|
||||||
|
regex.extend("|".join(self.actions.keys()))
|
||||||
|
regex.append(")/(?P<action>")
|
||||||
|
regex.extend("|".join("|".join(self.actions[x]) for x in self.actions))
|
||||||
|
regex.append(")/")
|
||||||
|
|
||||||
|
return "".join(regex)
|
||||||
|
|
||||||
|
def dispatch_request(self):
|
||||||
|
host = self.client_address[0]
|
||||||
|
code = 200
|
||||||
|
message = None
|
||||||
|
|
||||||
|
self.cdistargs = self.server.cdistargs
|
||||||
|
|
||||||
|
actions_regex = self._actions_regex()
|
||||||
|
m = re.match(actions_regex, self.path)
|
||||||
|
|
||||||
|
if m:
|
||||||
|
subsystem = m.group('subsystem')
|
||||||
|
action = m.group('action')
|
||||||
|
handler = getattr(self, "handler_" + subsystem)
|
||||||
|
|
||||||
|
if action not in self.actions[subsystem]:
|
||||||
|
code = 404
|
||||||
|
else:
|
||||||
|
code = 404
|
||||||
|
|
||||||
|
if code == 200:
|
||||||
|
log.debug("Calling {} -> {}".format(subsystem, action))
|
||||||
|
try:
|
||||||
|
handler(action, host)
|
||||||
|
except cdist.Error as e:
|
||||||
|
# cdist is not broken, cdist run is broken
|
||||||
|
code = 599 # use arbitrary unassigned error code
|
||||||
|
message = str(e)
|
||||||
|
except Exception as e:
|
||||||
|
# cdist/trigger server is broken
|
||||||
|
log.exception(e)
|
||||||
|
code = 500
|
||||||
|
|
||||||
|
self.send_response(code=code, message=message)
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
def handler_file(self, action, host):
|
||||||
|
if not self.server.directory or not self.server.source:
|
||||||
|
log.info("Cannot serve file request: directory or source "
|
||||||
|
"not setup")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
ipaddress.ip_address(host)
|
||||||
|
except ValueError:
|
||||||
|
log.error("Host is not a valid IP address - aborting")
|
||||||
|
return
|
||||||
|
|
||||||
|
dst = os.path.join(self.server.directory, host)
|
||||||
|
|
||||||
|
if action == "present":
|
||||||
|
shutil.copyfile(self.server.source, dst)
|
||||||
|
if action == "absent":
|
||||||
|
if os.path.exists(dst):
|
||||||
|
os.remove(dst)
|
||||||
|
|
||||||
|
def handler_cdist(self, action, host):
|
||||||
|
log.debug("Running cdist action %s for %s", action, host)
|
||||||
|
|
||||||
|
if self.server.dry_run:
|
||||||
|
log.info("Dry run, skipping cdist execution")
|
||||||
|
return
|
||||||
|
|
||||||
|
cname = action.title()
|
||||||
|
module = getattr(cdist, action)
|
||||||
|
theclass = getattr(module, cname)
|
||||||
|
|
||||||
|
if hasattr(self.cdistargs, 'out_path'):
|
||||||
|
out_path = self.cdistargs.out_path
|
||||||
|
else:
|
||||||
|
out_path = None
|
||||||
|
host_base_path, hostdir = theclass.create_host_base_dirs(
|
||||||
|
host, theclass.create_base_root_path(out_path))
|
||||||
|
theclass.construct_remote_exec_copy_patterns(self.cdistargs)
|
||||||
|
host_tags = None
|
||||||
|
host_name = ipaddr.resolve_target_host_name(host)
|
||||||
|
log.debug('Resolved target host name: %s', host_name)
|
||||||
|
if host_name:
|
||||||
|
target_host = host_name
|
||||||
|
else:
|
||||||
|
target_host = host
|
||||||
|
log.debug('Using target_host: %s', target_host)
|
||||||
|
log.debug("Executing cdist onehost with params: %s, %s, %s, %s, %s, ",
|
||||||
|
target_host, host_tags, host_base_path, hostdir,
|
||||||
|
self.cdistargs)
|
||||||
|
cfg = cdist.configuration.Configuration(self.cdistargs)
|
||||||
|
configuration = cfg.get_config(section='GLOBAL')
|
||||||
|
theclass.onehost(target_host, host_tags, host_base_path, hostdir,
|
||||||
|
self.cdistargs, parallel=False,
|
||||||
|
configuration=configuration)
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPServerV6(socketserver.ForkingMixIn, http.server.HTTPServer):
|
||||||
|
"""
|
||||||
|
Server that listens to both IPv4 and IPv6 requests.
|
||||||
|
"""
|
||||||
|
address_family = socket.AF_INET6
|
||||||
|
|
||||||
|
def __init__(self, cdistargs, directory, source, *args, **kwargs):
|
||||||
|
self.cdistargs = cdistargs
|
||||||
|
self.dry_run = cdistargs.dry_run
|
||||||
|
self.directory = directory
|
||||||
|
self.source = source
|
||||||
|
|
||||||
|
http.server.HTTPServer.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPServerV4(HTTPServerV6):
|
||||||
|
"""
|
||||||
|
Server that listens to IPv4 requests.
|
||||||
|
"""
|
||||||
|
address_family = socket.AF_INET
|
|
@ -33,7 +33,7 @@ class AbsolutePathRequiredError(cdist.Error):
|
||||||
return 'Absolute path required, got: {}'.format(self.path)
|
return 'Absolute path required, got: {}'.format(self.path)
|
||||||
|
|
||||||
|
|
||||||
class FileList(collections.abc.MutableSequence):
|
class FileList(collections.MutableSequence):
|
||||||
"""A list that stores it's state in a file.
|
"""A list that stores it's state in a file.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -102,7 +102,7 @@ class FileList(collections.abc.MutableSequence):
|
||||||
self.__write(lines)
|
self.__write(lines)
|
||||||
|
|
||||||
|
|
||||||
class DirectoryDict(collections.abc.MutableMapping):
|
class DirectoryDict(collections.MutableMapping):
|
||||||
"""A dict that stores it's items as files in a directory.
|
"""A dict that stores it's items as files in a directory.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
27
cdist/util/python_type_util.py
Normal file
27
cdist/util/python_type_util.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# 2019 Darko Poljak (darko.poljak at gmail.com)
|
||||||
|
#
|
||||||
|
# This file is part of cdist.
|
||||||
|
#
|
||||||
|
# cdist is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# cdist is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def is_python_type(cdist_type):
|
||||||
|
init_path = os.path.join(cdist_type.absolute_path, '__init__.py')
|
||||||
|
return os.path.exists(init_path)
|
|
@ -6,7 +6,7 @@ _cdist()
|
||||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||||
prevprev="${COMP_WORDS[COMP_CWORD-2]}"
|
prevprev="${COMP_WORDS[COMP_CWORD-2]}"
|
||||||
opts="-h --help -q --quiet -v --verbose -V --version"
|
opts="-h --help -q --quiet -v --verbose -V --version"
|
||||||
cmds="banner config install inventory preos shell"
|
cmds="banner config install inventory preos shell trigger"
|
||||||
|
|
||||||
case "${prevprev}" in
|
case "${prevprev}" in
|
||||||
shell)
|
shell)
|
||||||
|
@ -80,6 +80,14 @@ _cdist()
|
||||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
trigger)
|
||||||
|
opts="-h --help -d --debug -v --verbose -b --beta \
|
||||||
|
-C --cache-path-pattern -c --conf-dir -i --initial-manifest \
|
||||||
|
-j --jobs -n --dry-run -o --out-dir --remote-copy \
|
||||||
|
--remote-exec -6 --ipv6 -H --http-port -D --directory -S --source"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
inventory)
|
inventory)
|
||||||
cmds="list add-host del-host add-tag del-tag"
|
cmds="list add-host del-host add-tag del-tag"
|
||||||
opts="-h --help -q --quiet -v --verbose"
|
opts="-h --help -q --quiet -v --verbose"
|
||||||
|
|
|
@ -11,7 +11,7 @@ _cdist()
|
||||||
|
|
||||||
case $state in
|
case $state in
|
||||||
opts_cmds)
|
opts_cmds)
|
||||||
_arguments '1:Options and commands:(banner config install inventory preos shell -h --help -q --quiet -v --verbose -V --version)'
|
_arguments '1:Options and commands:(banner config install inventory preos shell trigger -h --help -q --quiet -v --verbose -V --version)'
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
case $words[2] in
|
case $words[2] in
|
||||||
|
|
|
@ -1,32 +1,9 @@
|
||||||
Changelog
|
Changelog
|
||||||
---------
|
---------
|
||||||
|
|
||||||
7.0.1:
|
next:
|
||||||
* Core: Remove double definition of scan parser (Nico Schottelius)
|
* Core: Add trigger functionality (Nico Schottelius, Darko Poljak)
|
||||||
* Type __apt_mark: Narrow down grep for hold packages (marcoduif)
|
* Core: Implement core support for python types (Darko Poljak)
|
||||||
* Type __apt_source: Set required options variable (Mark Verboom)
|
|
||||||
* Type __letsencrypt_cert: Update python version (Michelle)
|
|
||||||
* Explorer os_version: Add support for Daedalus (Michelle)
|
|
||||||
* Explorer machine_type: Correct incorrect VMM matching (Mark Verboom)
|
|
||||||
|
|
||||||
7.0.0: 2022-07-31
|
|
||||||
* Explorer machine_type: Rewrite (Dennis Camera)
|
|
||||||
* New type: __sed (Ander Punnar)
|
|
||||||
* New type: __haproxy_dualstack (Evilham and ungleich)
|
|
||||||
* Type __apt_update_index: Fix complaint about suite change (Matthias Stecher)
|
|
||||||
* Type __package_update_index: Fix complaint about suite change (Matthias Stecher)
|
|
||||||
* Type __package_upgrade_all: Add new --apt-with-new-pkgs argument (Evilham)
|
|
||||||
* Type __apt_source: Fix complaint about suite change (Matthias Stecher)
|
|
||||||
* Type __package_apt: Fix complaint about suite change (Matthias Stecher)
|
|
||||||
* Type __debconf_set_selections: Fix bug where --file was unsupported (Evilham)
|
|
||||||
* Types __letsencrypt_cert, __grafana_dashboard: Improve bullseye support (Evilham)
|
|
||||||
* Type __ssh_authorized_key: Also remove tmpfile if removing line (Mark Verboom)
|
|
||||||
* Type __apt_pin: Add default priority, add comment in generated files (Daniel Fancsali)
|
|
||||||
* Type __file: make file uploading and attribute changes more atomic (Steven Armstrong)
|
|
||||||
* Type __dot_file: Add support for using --file parameter (Stephan Leemburg)
|
|
||||||
* Type __apt_ppa: Replace custom "remove-apt-repository" with add-apt-repository -r (Romain Dartigues)
|
|
||||||
* Type __apt_source: Add signed-by parameter (Daniel Fancsali)
|
|
||||||
* Explorer: add support for checkpoint (Stephan Leemburg)
|
|
||||||
|
|
||||||
6.9.8: 2021-08-24
|
6.9.8: 2021-08-24
|
||||||
* Type __rsync: Rewrite (Ander Punnar)
|
* Type __rsync: Rewrite (Ander Punnar)
|
||||||
|
|
376
docs/dev/python-types/benchmark
Normal file
376
docs/dev/python-types/benchmark
Normal file
|
@ -0,0 +1,376 @@
|
||||||
|
# sh type, no file at remote
|
||||||
|
echo 'x=0; while [ $x -lt 50 ]; do head -c 102400 /dev/random | __file /root/foo${x}.bin --source - --mode 0640 --owner root --group root; x=$((x + 1)); done' | ./bin/cdist config -v -P -i - 185.203.112.26
|
||||||
|
|
||||||
|
INFO: [20181121125154.045799] 185.203.112.26: Starting configuration run
|
||||||
|
INFO: [20181121125237.029892] 185.203.112.26: Processing __file/root/foo0.bin
|
||||||
|
INFO: [20181121125239.881529] 185.203.112.26: Processing __file/root/foo1.bin
|
||||||
|
INFO: [20181121125243.265672] 185.203.112.26: Processing __file/root/foo2.bin
|
||||||
|
INFO: [20181121125246.929903] 185.203.112.26: Processing __file/root/foo3.bin
|
||||||
|
INFO: [20181121125251.811258] 185.203.112.26: Processing __file/root/foo4.bin
|
||||||
|
INFO: [20181121125257.784416] 185.203.112.26: Processing __file/root/foo5.bin
|
||||||
|
INFO: [20181121125302.686275] 185.203.112.26: Processing __file/root/foo6.bin
|
||||||
|
INFO: [20181121125306.394030] 185.203.112.26: Processing __file/root/foo7.bin
|
||||||
|
INFO: [20181121125308.610023] 185.203.112.26: Processing __file/root/foo8.bin
|
||||||
|
INFO: [20181121125310.868538] 185.203.112.26: Processing __file/root/foo9.bin
|
||||||
|
INFO: [20181121125313.017972] 185.203.112.26: Processing __file/root/foo10.bin
|
||||||
|
INFO: [20181121125315.201342] 185.203.112.26: Processing __file/root/foo11.bin
|
||||||
|
INFO: [20181121125317.333055] 185.203.112.26: Processing __file/root/foo12.bin
|
||||||
|
INFO: [20181121125319.463929] 185.203.112.26: Processing __file/root/foo13.bin
|
||||||
|
INFO: [20181121125321.595410] 185.203.112.26: Processing __file/root/foo14.bin
|
||||||
|
INFO: [20181121125323.689697] 185.203.112.26: Processing __file/root/foo15.bin
|
||||||
|
INFO: [20181121125325.768283] 185.203.112.26: Processing __file/root/foo16.bin
|
||||||
|
INFO: [20181121125327.814793] 185.203.112.26: Processing __file/root/foo17.bin
|
||||||
|
INFO: [20181121125329.873073] 185.203.112.26: Processing __file/root/foo18.bin
|
||||||
|
INFO: [20181121125331.953886] 185.203.112.26: Processing __file/root/foo19.bin
|
||||||
|
INFO: [20181121125334.118290] 185.203.112.26: Processing __file/root/foo20.bin
|
||||||
|
INFO: [20181121125336.390849] 185.203.112.26: Processing __file/root/foo21.bin
|
||||||
|
INFO: [20181121125338.576698] 185.203.112.26: Processing __file/root/foo22.bin
|
||||||
|
INFO: [20181121125340.819044] 185.203.112.26: Processing __file/root/foo23.bin
|
||||||
|
INFO: [20181121125343.680419] 185.203.112.26: Processing __file/root/foo24.bin
|
||||||
|
INFO: [20181121125346.044907] 185.203.112.26: Processing __file/root/foo25.bin
|
||||||
|
INFO: [20181121125348.179574] 185.203.112.26: Processing __file/root/foo26.bin
|
||||||
|
INFO: [20181121125350.314970] 185.203.112.26: Processing __file/root/foo27.bin
|
||||||
|
INFO: [20181121125352.447394] 185.203.112.26: Processing __file/root/foo28.bin
|
||||||
|
INFO: [20181121125354.586637] 185.203.112.26: Processing __file/root/foo29.bin
|
||||||
|
INFO: [20181121125356.722699] 185.203.112.26: Processing __file/root/foo30.bin
|
||||||
|
INFO: [20181121125358.883538] 185.203.112.26: Processing __file/root/foo31.bin
|
||||||
|
INFO: [20181121125401.020967] 185.203.112.26: Processing __file/root/foo32.bin
|
||||||
|
INFO: [20181121125403.160146] 185.203.112.26: Processing __file/root/foo33.bin
|
||||||
|
INFO: [20181121125405.289048] 185.203.112.26: Processing __file/root/foo34.bin
|
||||||
|
INFO: [20181121125407.423994] 185.203.112.26: Processing __file/root/foo35.bin
|
||||||
|
INFO: [20181121125409.530135] 185.203.112.26: Processing __file/root/foo36.bin
|
||||||
|
INFO: [20181121125411.659683] 185.203.112.26: Processing __file/root/foo37.bin
|
||||||
|
INFO: [20181121125413.786177] 185.203.112.26: Processing __file/root/foo38.bin
|
||||||
|
INFO: [20181121125415.919152] 185.203.112.26: Processing __file/root/foo39.bin
|
||||||
|
INFO: [20181121125418.051496] 185.203.112.26: Processing __file/root/foo40.bin
|
||||||
|
INFO: [20181121125420.204577] 185.203.112.26: Processing __file/root/foo41.bin
|
||||||
|
INFO: [20181121125422.339697] 185.203.112.26: Processing __file/root/foo42.bin
|
||||||
|
INFO: [20181121125424.450966] 185.203.112.26: Processing __file/root/foo43.bin
|
||||||
|
INFO: [20181121125426.487831] 185.203.112.26: Processing __file/root/foo44.bin
|
||||||
|
INFO: [20181121125428.585516] 185.203.112.26: Processing __file/root/foo45.bin
|
||||||
|
INFO: [20181121125430.749002] 185.203.112.26: Processing __file/root/foo46.bin
|
||||||
|
INFO: [20181121125432.865290] 185.203.112.26: Processing __file/root/foo47.bin
|
||||||
|
INFO: [20181121125435.004009] 185.203.112.26: Processing __file/root/foo48.bin
|
||||||
|
INFO: [20181121125437.228566] 185.203.112.26: Processing __file/root/foo49.bin
|
||||||
|
INFO: [20181121125439.429440] 185.203.112.26: Finished successful run in 165.38 seconds
|
||||||
|
|
||||||
|
# sh type, files exist at remote but content changes
|
||||||
|
echo 'x=0; while [ $x -lt 50 ]; do head -c 102400 /dev/random | __file /root/foo${x}.bin --source - --mode 0640 --owner root --group root; x=$((x + 1)); done' | ./bin/cdist config -v -P -i - 185.203.112.26
|
||||||
|
|
||||||
|
INFO: [20181121125529.952800] 185.203.112.26: Starting configuration run
|
||||||
|
INFO: [20181121125541.175180] 185.203.112.26: Processing __file/root/foo0.bin
|
||||||
|
INFO: [20181121125543.219561] 185.203.112.26: Processing __file/root/foo1.bin
|
||||||
|
INFO: [20181121125545.116073] 185.203.112.26: Processing __file/root/foo2.bin
|
||||||
|
INFO: [20181121125547.011359] 185.203.112.26: Processing __file/root/foo3.bin
|
||||||
|
INFO: [20181121125548.916288] 185.203.112.26: Processing __file/root/foo4.bin
|
||||||
|
INFO: [20181121125550.821351] 185.203.112.26: Processing __file/root/foo5.bin
|
||||||
|
INFO: [20181121125552.723887] 185.203.112.26: Processing __file/root/foo6.bin
|
||||||
|
INFO: [20181121125554.635662] 185.203.112.26: Processing __file/root/foo7.bin
|
||||||
|
INFO: [20181121125556.568639] 185.203.112.26: Processing __file/root/foo8.bin
|
||||||
|
INFO: [20181121125558.508852] 185.203.112.26: Processing __file/root/foo9.bin
|
||||||
|
INFO: [20181121125600.464475] 185.203.112.26: Processing __file/root/foo10.bin
|
||||||
|
INFO: [20181121125602.429261] 185.203.112.26: Processing __file/root/foo11.bin
|
||||||
|
INFO: [20181121125604.428942] 185.203.112.26: Processing __file/root/foo12.bin
|
||||||
|
INFO: [20181121125606.442193] 185.203.112.26: Processing __file/root/foo13.bin
|
||||||
|
INFO: [20181121125608.474473] 185.203.112.26: Processing __file/root/foo14.bin
|
||||||
|
INFO: [20181121125610.535252] 185.203.112.26: Processing __file/root/foo15.bin
|
||||||
|
INFO: [20181121125612.609560] 185.203.112.26: Processing __file/root/foo16.bin
|
||||||
|
INFO: [20181121125614.708507] 185.203.112.26: Processing __file/root/foo17.bin
|
||||||
|
INFO: [20181121125616.824721] 185.203.112.26: Processing __file/root/foo18.bin
|
||||||
|
INFO: [20181121125618.924521] 185.203.112.26: Processing __file/root/foo19.bin
|
||||||
|
INFO: [20181121125621.007543] 185.203.112.26: Processing __file/root/foo20.bin
|
||||||
|
INFO: [20181121125623.133204] 185.203.112.26: Processing __file/root/foo21.bin
|
||||||
|
INFO: [20181121125625.333471] 185.203.112.26: Processing __file/root/foo22.bin
|
||||||
|
INFO: [20181121125627.396334] 185.203.112.26: Processing __file/root/foo23.bin
|
||||||
|
INFO: [20181121125629.526492] 185.203.112.26: Processing __file/root/foo24.bin
|
||||||
|
INFO: [20181121125631.628454] 185.203.112.26: Processing __file/root/foo25.bin
|
||||||
|
INFO: [20181121125633.743142] 185.203.112.26: Processing __file/root/foo26.bin
|
||||||
|
INFO: [20181121125635.952547] 185.203.112.26: Processing __file/root/foo27.bin
|
||||||
|
INFO: [20181121125637.986746] 185.203.112.26: Processing __file/root/foo28.bin
|
||||||
|
INFO: [20181121125640.020415] 185.203.112.26: Processing __file/root/foo29.bin
|
||||||
|
INFO: [20181121125642.081373] 185.203.112.26: Processing __file/root/foo30.bin
|
||||||
|
INFO: [20181121125644.174744] 185.203.112.26: Processing __file/root/foo31.bin
|
||||||
|
INFO: [20181121125646.286532] 185.203.112.26: Processing __file/root/foo32.bin
|
||||||
|
INFO: [20181121125648.396447] 185.203.112.26: Processing __file/root/foo33.bin
|
||||||
|
INFO: [20181121125650.460107] 185.203.112.26: Processing __file/root/foo34.bin
|
||||||
|
INFO: [20181121125652.557125] 185.203.112.26: Processing __file/root/foo35.bin
|
||||||
|
INFO: [20181121125654.667456] 185.203.112.26: Processing __file/root/foo36.bin
|
||||||
|
INFO: [20181121125656.746960] 185.203.112.26: Processing __file/root/foo37.bin
|
||||||
|
INFO: [20181121125658.854229] 185.203.112.26: Processing __file/root/foo38.bin
|
||||||
|
INFO: [20181121125700.968145] 185.203.112.26: Processing __file/root/foo39.bin
|
||||||
|
INFO: [20181121125703.109376] 185.203.112.26: Processing __file/root/foo40.bin
|
||||||
|
INFO: [20181121125705.318163] 185.203.112.26: Processing __file/root/foo41.bin
|
||||||
|
INFO: [20181121125707.440575] 185.203.112.26: Processing __file/root/foo42.bin
|
||||||
|
INFO: [20181121125709.551261] 185.203.112.26: Processing __file/root/foo43.bin
|
||||||
|
INFO: [20181121125711.657753] 185.203.112.26: Processing __file/root/foo44.bin
|
||||||
|
INFO: [20181121125713.774819] 185.203.112.26: Processing __file/root/foo45.bin
|
||||||
|
INFO: [20181121125715.887428] 185.203.112.26: Processing __file/root/foo46.bin
|
||||||
|
INFO: [20181121125717.995104] 185.203.112.26: Processing __file/root/foo47.bin
|
||||||
|
INFO: [20181121125720.110196] 185.203.112.26: Processing __file/root/foo48.bin
|
||||||
|
INFO: [20181121125722.232932] 185.203.112.26: Processing __file/root/foo49.bin
|
||||||
|
INFO: [20181121125724.451523] 185.203.112.26: Finished successful run in 114.50 seconds
|
||||||
|
|
||||||
|
# py type, no file at remote
|
||||||
|
echo 'x=0; while [ $x -lt 50 ]; do head -c 102400 /dev/random | __file_py /root/foo${x}.bin --source - --mode 0640 --owner root --group root; x=$((x + 1)); done' | ./bin/cdist config -v -P -i - 185.203.112.26
|
||||||
|
|
||||||
|
INFO: [20181121125812.034197] 185.203.112.26: Starting configuration run
|
||||||
|
INFO: [20181121125823.927353] 185.203.112.26: Processing __file_py/root/foo0.bin
|
||||||
|
INFO: [20181121125825.715361] 185.203.112.26: Processing __file_py/root/foo1.bin
|
||||||
|
INFO: [20181121125827.511296] 185.203.112.26: Processing __file_py/root/foo2.bin
|
||||||
|
INFO: [20181121125829.293455] 185.203.112.26: Processing __file_py/root/foo3.bin
|
||||||
|
INFO: [20181121125831.086696] 185.203.112.26: Processing __file_py/root/foo4.bin
|
||||||
|
INFO: [20181121125832.867582] 185.203.112.26: Processing __file_py/root/foo5.bin
|
||||||
|
INFO: [20181121125834.652511] 185.203.112.26: Processing __file_py/root/foo6.bin
|
||||||
|
INFO: [20181121125836.450393] 185.203.112.26: Processing __file_py/root/foo7.bin
|
||||||
|
INFO: [20181121125838.255152] 185.203.112.26: Processing __file_py/root/foo8.bin
|
||||||
|
INFO: [20181121125840.065808] 185.203.112.26: Processing __file_py/root/foo9.bin
|
||||||
|
INFO: [20181121125841.889049] 185.203.112.26: Processing __file_py/root/foo10.bin
|
||||||
|
INFO: [20181121125843.719280] 185.203.112.26: Processing __file_py/root/foo11.bin
|
||||||
|
INFO: [20181121125845.560165] 185.203.112.26: Processing __file_py/root/foo12.bin
|
||||||
|
INFO: [20181121125847.416138] 185.203.112.26: Processing __file_py/root/foo13.bin
|
||||||
|
INFO: [20181121125849.289851] 185.203.112.26: Processing __file_py/root/foo14.bin
|
||||||
|
INFO: [20181121125851.180203] 185.203.112.26: Processing __file_py/root/foo15.bin
|
||||||
|
INFO: [20181121125853.074978] 185.203.112.26: Processing __file_py/root/foo16.bin
|
||||||
|
INFO: [20181121125855.086107] 185.203.112.26: Processing __file_py/root/foo17.bin
|
||||||
|
INFO: [20181121125857.041100] 185.203.112.26: Processing __file_py/root/foo18.bin
|
||||||
|
INFO: [20181121125859.025581] 185.203.112.26: Processing __file_py/root/foo19.bin
|
||||||
|
INFO: [20181121125901.072067] 185.203.112.26: Processing __file_py/root/foo20.bin
|
||||||
|
INFO: [20181121125903.026711] 185.203.112.26: Processing __file_py/root/foo21.bin
|
||||||
|
INFO: [20181121125904.994824] 185.203.112.26: Processing __file_py/root/foo22.bin
|
||||||
|
INFO: [20181121125906.956296] 185.203.112.26: Processing __file_py/root/foo23.bin
|
||||||
|
INFO: [20181121125908.929231] 185.203.112.26: Processing __file_py/root/foo24.bin
|
||||||
|
INFO: [20181121125910.882672] 185.203.112.26: Processing __file_py/root/foo25.bin
|
||||||
|
INFO: [20181121125912.839834] 185.203.112.26: Processing __file_py/root/foo26.bin
|
||||||
|
INFO: [20181121125914.789904] 185.203.112.26: Processing __file_py/root/foo27.bin
|
||||||
|
INFO: [20181121125916.743930] 185.203.112.26: Processing __file_py/root/foo28.bin
|
||||||
|
INFO: [20181121125918.698258] 185.203.112.26: Processing __file_py/root/foo29.bin
|
||||||
|
INFO: [20181121125920.657118] 185.203.112.26: Processing __file_py/root/foo30.bin
|
||||||
|
INFO: [20181121125922.618898] 185.203.112.26: Processing __file_py/root/foo31.bin
|
||||||
|
INFO: [20181121125924.567847] 185.203.112.26: Processing __file_py/root/foo32.bin
|
||||||
|
INFO: [20181121125926.524617] 185.203.112.26: Processing __file_py/root/foo33.bin
|
||||||
|
INFO: [20181121125928.396400] 185.203.112.26: Processing __file_py/root/foo34.bin
|
||||||
|
INFO: [20181121125930.209237] 185.203.112.26: Processing __file_py/root/foo35.bin
|
||||||
|
INFO: [20181121125931.998377] 185.203.112.26: Processing __file_py/root/foo36.bin
|
||||||
|
INFO: [20181121125933.786883] 185.203.112.26: Processing __file_py/root/foo37.bin
|
||||||
|
INFO: [20181121125935.579348] 185.203.112.26: Processing __file_py/root/foo38.bin
|
||||||
|
INFO: [20181121125937.366197] 185.203.112.26: Processing __file_py/root/foo39.bin
|
||||||
|
INFO: [20181121125939.155643] 185.203.112.26: Processing __file_py/root/foo40.bin
|
||||||
|
INFO: [20181121125941.052837] 185.203.112.26: Processing __file_py/root/foo41.bin
|
||||||
|
INFO: [20181121125942.953670] 185.203.112.26: Processing __file_py/root/foo42.bin
|
||||||
|
INFO: [20181121125944.781567] 185.203.112.26: Processing __file_py/root/foo43.bin
|
||||||
|
INFO: [20181121125946.622485] 185.203.112.26: Processing __file_py/root/foo44.bin
|
||||||
|
INFO: [20181121125948.470701] 185.203.112.26: Processing __file_py/root/foo45.bin
|
||||||
|
INFO: [20181121125950.356949] 185.203.112.26: Processing __file_py/root/foo46.bin
|
||||||
|
INFO: [20181121125952.232014] 185.203.112.26: Processing __file_py/root/foo47.bin
|
||||||
|
INFO: [20181121125954.128887] 185.203.112.26: Processing __file_py/root/foo48.bin
|
||||||
|
INFO: [20181121125956.037541] 185.203.112.26: Processing __file_py/root/foo49.bin
|
||||||
|
INFO: [20181121125957.514738] 185.203.112.26: Finished successful run in 105.48 seconds
|
||||||
|
|
||||||
|
# py type, files exist at remote but content changes
|
||||||
|
echo 'x=0; while [ $x -lt 50 ]; do head -c 102400 /dev/random | __file_py /root/foo${x}.bin --source - --mode 0640 --owner root --group root; x=$((x + 1)); done' | ./bin/cdist config -v -P -i - 185.203.112.26
|
||||||
|
|
||||||
|
INFO: [20181121130056.484643] 185.203.112.26: Starting configuration run
|
||||||
|
INFO: [20181121130108.545059] 185.203.112.26: Processing __file_py/root/foo0.bin
|
||||||
|
INFO: [20181121130110.339217] 185.203.112.26: Processing __file_py/root/foo1.bin
|
||||||
|
INFO: [20181121130112.136448] 185.203.112.26: Processing __file_py/root/foo2.bin
|
||||||
|
INFO: [20181121130113.923820] 185.203.112.26: Processing __file_py/root/foo3.bin
|
||||||
|
INFO: [20181121130115.715667] 185.203.112.26: Processing __file_py/root/foo4.bin
|
||||||
|
INFO: [20181121130117.508696] 185.203.112.26: Processing __file_py/root/foo5.bin
|
||||||
|
INFO: [20181121130119.300839] 185.203.112.26: Processing __file_py/root/foo6.bin
|
||||||
|
INFO: [20181121130124.296312] 185.203.112.26: Processing __file_py/root/foo7.bin
|
||||||
|
INFO: [20181121130131.109195] 185.203.112.26: Processing __file_py/root/foo8.bin
|
||||||
|
INFO: [20181121130133.303817] 185.203.112.26: Processing __file_py/root/foo9.bin
|
||||||
|
INFO: [20181121130136.396440] 185.203.112.26: Processing __file_py/root/foo10.bin
|
||||||
|
INFO: [20181121130138.443128] 185.203.112.26: Processing __file_py/root/foo11.bin
|
||||||
|
INFO: [20181121130140.462868] 185.203.112.26: Processing __file_py/root/foo12.bin
|
||||||
|
INFO: [20181121130142.476196] 185.203.112.26: Processing __file_py/root/foo13.bin
|
||||||
|
INFO: [20181121130145.937900] 185.203.112.26: Processing __file_py/root/foo14.bin
|
||||||
|
INFO: [20181121130148.013672] 185.203.112.26: Processing __file_py/root/foo15.bin
|
||||||
|
INFO: [20181121130150.042588] 185.203.112.26: Processing __file_py/root/foo16.bin
|
||||||
|
INFO: [20181121130152.050793] 185.203.112.26: Processing __file_py/root/foo17.bin
|
||||||
|
INFO: [20181121130154.083089] 185.203.112.26: Processing __file_py/root/foo18.bin
|
||||||
|
INFO: [20181121130156.100091] 185.203.112.26: Processing __file_py/root/foo19.bin
|
||||||
|
INFO: [20181121130158.103005] 185.203.112.26: Processing __file_py/root/foo20.bin
|
||||||
|
INFO: [20181121130200.188390] 185.203.112.26: Processing __file_py/root/foo21.bin
|
||||||
|
INFO: [20181121130202.197574] 185.203.112.26: Processing __file_py/root/foo22.bin
|
||||||
|
INFO: [20181121130205.269102] 185.203.112.26: Processing __file_py/root/foo23.bin
|
||||||
|
INFO: [20181121130208.457011] 185.203.112.26: Processing __file_py/root/foo24.bin
|
||||||
|
INFO: [20181121130211.574321] 185.203.112.26: Processing __file_py/root/foo25.bin
|
||||||
|
INFO: [20181121130213.719894] 185.203.112.26: Processing __file_py/root/foo26.bin
|
||||||
|
INFO: [20181121130215.762977] 185.203.112.26: Processing __file_py/root/foo27.bin
|
||||||
|
INFO: [20181121130217.778624] 185.203.112.26: Processing __file_py/root/foo28.bin
|
||||||
|
INFO: [20181121130219.840477] 185.203.112.26: Processing __file_py/root/foo29.bin
|
||||||
|
INFO: [20181121130221.852389] 185.203.112.26: Processing __file_py/root/foo30.bin
|
||||||
|
INFO: [20181121130223.850898] 185.203.112.26: Processing __file_py/root/foo31.bin
|
||||||
|
INFO: [20181121130225.858812] 185.203.112.26: Processing __file_py/root/foo32.bin
|
||||||
|
INFO: [20181121130227.855295] 185.203.112.26: Processing __file_py/root/foo33.bin
|
||||||
|
INFO: [20181121130229.952673] 185.203.112.26: Processing __file_py/root/foo34.bin
|
||||||
|
INFO: [20181121130231.956904] 185.203.112.26: Processing __file_py/root/foo35.bin
|
||||||
|
INFO: [20181121130233.961954] 185.203.112.26: Processing __file_py/root/foo36.bin
|
||||||
|
INFO: [20181121130236.012158] 185.203.112.26: Processing __file_py/root/foo37.bin
|
||||||
|
INFO: [20181121130238.024422] 185.203.112.26: Processing __file_py/root/foo38.bin
|
||||||
|
INFO: [20181121130241.238800] 185.203.112.26: Processing __file_py/root/foo39.bin
|
||||||
|
INFO: [20181121130243.463237] 185.203.112.26: Processing __file_py/root/foo40.bin
|
||||||
|
INFO: [20181121130245.610314] 185.203.112.26: Processing __file_py/root/foo41.bin
|
||||||
|
INFO: [20181121130247.661385] 185.203.112.26: Processing __file_py/root/foo42.bin
|
||||||
|
INFO: [20181121130250.399845] 185.203.112.26: Processing __file_py/root/foo43.bin
|
||||||
|
INFO: [20181121130252.832133] 185.203.112.26: Processing __file_py/root/foo44.bin
|
||||||
|
INFO: [20181121130254.955658] 185.203.112.26: Processing __file_py/root/foo45.bin
|
||||||
|
INFO: [20181121130257.039587] 185.203.112.26: Processing __file_py/root/foo46.bin
|
||||||
|
INFO: [20181121130259.178847] 185.203.112.26: Processing __file_py/root/foo47.bin
|
||||||
|
INFO: [20181121130301.357922] 185.203.112.26: Processing __file_py/root/foo48.bin
|
||||||
|
INFO: [20181121130303.356299] 185.203.112.26: Processing __file_py/root/foo49.bin
|
||||||
|
INFO: [20181121130305.144393] 185.203.112.26: Finished successful run in 128.66 seconds
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# init test file content
|
||||||
|
head -c 102400 /dev/random > /tmp/test.file
|
||||||
|
|
||||||
|
# sh type, no file at remote
|
||||||
|
echo 'x=0; while [ $x -lt 50 ]; do __file /root/foo${x}.bin --source /tmp/test.file --mode 0640 --owner root --group root; x=$((x + 1)); done' | ./bin/cdist config -v -P -i - 185.203.112.26
|
||||||
|
|
||||||
|
INFO: [20181121130612.519698] 185.203.112.26: Starting configuration run
|
||||||
|
INFO: [20181121130624.219344] 185.203.112.26: Processing __file/root/foo0.bin
|
||||||
|
INFO: [20181121130626.980052] 185.203.112.26: Processing __file/root/foo1.bin
|
||||||
|
INFO: [20181121130631.200669] 185.203.112.26: Processing __file/root/foo2.bin
|
||||||
|
INFO: [20181121130642.790229] 185.203.112.26: Processing __file/root/foo3.bin
|
||||||
|
INFO: [20181121130646.565599] 185.203.112.26: Processing __file/root/foo4.bin
|
||||||
|
INFO: [20181121130648.724875] 185.203.112.26: Processing __file/root/foo5.bin
|
||||||
|
INFO: [20181121130651.464686] 185.203.112.26: Processing __file/root/foo6.bin
|
||||||
|
INFO: [20181121130653.639581] 185.203.112.26: Processing __file/root/foo7.bin
|
||||||
|
INFO: [20181121130655.773987] 185.203.112.26: Processing __file/root/foo8.bin
|
||||||
|
INFO: [20181121130657.933136] 185.203.112.26: Processing __file/root/foo9.bin
|
||||||
|
INFO: [20181121130700.065158] 185.203.112.26: Processing __file/root/foo10.bin
|
||||||
|
INFO: [20181121130702.216456] 185.203.112.26: Processing __file/root/foo11.bin
|
||||||
|
INFO: [20181121130704.429030] 185.203.112.26: Processing __file/root/foo12.bin
|
||||||
|
INFO: [20181121130706.562114] 185.203.112.26: Processing __file/root/foo13.bin
|
||||||
|
INFO: [20181121130708.696584] 185.203.112.26: Processing __file/root/foo14.bin
|
||||||
|
INFO: [20181121130710.830002] 185.203.112.26: Processing __file/root/foo15.bin
|
||||||
|
INFO: [20181121130712.966631] 185.203.112.26: Processing __file/root/foo16.bin
|
||||||
|
INFO: [20181121130715.151833] 185.203.112.26: Processing __file/root/foo17.bin
|
||||||
|
INFO: [20181121130717.355196] 185.203.112.26: Processing __file/root/foo18.bin
|
||||||
|
INFO: [20181121130719.486316] 185.203.112.26: Processing __file/root/foo19.bin
|
||||||
|
INFO: [20181121130721.619933] 185.203.112.26: Processing __file/root/foo20.bin
|
||||||
|
INFO: [20181121130723.786670] 185.203.112.26: Processing __file/root/foo21.bin
|
||||||
|
INFO: [20181121130725.924736] 185.203.112.26: Processing __file/root/foo22.bin
|
||||||
|
INFO: [20181121130728.060224] 185.203.112.26: Processing __file/root/foo23.bin
|
||||||
|
INFO: [20181121130730.178729] 185.203.112.26: Processing __file/root/foo24.bin
|
||||||
|
INFO: [20181121130732.309264] 185.203.112.26: Processing __file/root/foo25.bin
|
||||||
|
INFO: [20181121130734.479895] 185.203.112.26: Processing __file/root/foo26.bin
|
||||||
|
INFO: [20181121130736.653085] 185.203.112.26: Processing __file/root/foo27.bin
|
||||||
|
INFO: [20181121130738.814291] 185.203.112.26: Processing __file/root/foo28.bin
|
||||||
|
INFO: [20181121130741.029646] 185.203.112.26: Processing __file/root/foo29.bin
|
||||||
|
INFO: [20181121130743.128717] 185.203.112.26: Processing __file/root/foo30.bin
|
||||||
|
INFO: [20181121130745.233272] 185.203.112.26: Processing __file/root/foo31.bin
|
||||||
|
INFO: [20181121130747.364681] 185.203.112.26: Processing __file/root/foo32.bin
|
||||||
|
INFO: [20181121130749.491793] 185.203.112.26: Processing __file/root/foo33.bin
|
||||||
|
INFO: [20181121130751.620492] 185.203.112.26: Processing __file/root/foo34.bin
|
||||||
|
INFO: [20181121130753.743519] 185.203.112.26: Processing __file/root/foo35.bin
|
||||||
|
INFO: [20181121130755.862169] 185.203.112.26: Processing __file/root/foo36.bin
|
||||||
|
INFO: [20181121130758.000172] 185.203.112.26: Processing __file/root/foo37.bin
|
||||||
|
INFO: [20181121130800.090405] 185.203.112.26: Processing __file/root/foo38.bin
|
||||||
|
INFO: [20181121130802.211849] 185.203.112.26: Processing __file/root/foo39.bin
|
||||||
|
INFO: [20181121130804.356363] 185.203.112.26: Processing __file/root/foo40.bin
|
||||||
|
INFO: [20181121130806.548412] 185.203.112.26: Processing __file/root/foo41.bin
|
||||||
|
INFO: [20181121130808.671279] 185.203.112.26: Processing __file/root/foo42.bin
|
||||||
|
INFO: [20181121130810.752813] 185.203.112.26: Processing __file/root/foo43.bin
|
||||||
|
INFO: [20181121130812.844502] 185.203.112.26: Processing __file/root/foo44.bin
|
||||||
|
INFO: [20181121130814.950501] 185.203.112.26: Processing __file/root/foo45.bin
|
||||||
|
INFO: [20181121130817.040587] 185.203.112.26: Processing __file/root/foo46.bin
|
||||||
|
INFO: [20181121130819.175850] 185.203.112.26: Processing __file/root/foo47.bin
|
||||||
|
INFO: [20181121130821.332900] 185.203.112.26: Processing __file/root/foo48.bin
|
||||||
|
INFO: [20181121130823.543119] 185.203.112.26: Processing __file/root/foo49.bin
|
||||||
|
INFO: [20181121130825.833163] 185.203.112.26: Finished successful run in 133.31 seconds
|
||||||
|
|
||||||
|
# sh type, files exist at remote
|
||||||
|
echo 'x=0; while [ $x -lt 50 ]; do __file /root/foo${x}.bin --source /tmp/test.file --mode 0640 --owner root --group root; x=$((x + 1)); done' | ./bin/cdist config -v -P -i - 185.203.112.26
|
||||||
|
|
||||||
|
INFO: [20181121130854.980007] 185.203.112.26: Starting configuration run
|
||||||
|
INFO: [20181121130957.927705] 185.203.112.26: Finished successful run in 62.95 seconds
|
||||||
|
|
||||||
|
# py type, no file at remote
|
||||||
|
echo 'x=0; while [ $x -lt 50 ]; do __file_py /root/foo${x}.bin --source /tmp/test.file --mode 0640 --owner root --group root; x=$((x + 1)); done' | ./bin/cdist config -v -P -i - 185.203.112.26
|
||||||
|
|
||||||
|
INFO: [20181121131110.179480] 185.203.112.26: Starting configuration run
|
||||||
|
INFO: [20181121131122.086849] 185.203.112.26: Processing __file_py/root/foo0.bin
|
||||||
|
INFO: [20181121131123.876029] 185.203.112.26: Processing __file_py/root/foo1.bin
|
||||||
|
INFO: [20181121131125.668664] 185.203.112.26: Processing __file_py/root/foo2.bin
|
||||||
|
INFO: [20181121131127.460721] 185.203.112.26: Processing __file_py/root/foo3.bin
|
||||||
|
INFO: [20181121131129.591229] 185.203.112.26: Processing __file_py/root/foo4.bin
|
||||||
|
INFO: [20181121131131.390379] 185.203.112.26: Processing __file_py/root/foo5.bin
|
||||||
|
INFO: [20181121131133.195275] 185.203.112.26: Processing __file_py/root/foo6.bin
|
||||||
|
INFO: [20181121131135.006282] 185.203.112.26: Processing __file_py/root/foo7.bin
|
||||||
|
INFO: [20181121131136.834448] 185.203.112.26: Processing __file_py/root/foo8.bin
|
||||||
|
INFO: [20181121131138.659301] 185.203.112.26: Processing __file_py/root/foo9.bin
|
||||||
|
INFO: [20181121131140.496856] 185.203.112.26: Processing __file_py/root/foo10.bin
|
||||||
|
INFO: [20181121131142.367813] 185.203.112.26: Processing __file_py/root/foo11.bin
|
||||||
|
INFO: [20181121131144.239817] 185.203.112.26: Processing __file_py/root/foo12.bin
|
||||||
|
INFO: [20181121131146.133314] 185.203.112.26: Processing __file_py/root/foo13.bin
|
||||||
|
INFO: [20181121131148.049380] 185.203.112.26: Processing __file_py/root/foo14.bin
|
||||||
|
INFO: [20181121131149.974696] 185.203.112.26: Processing __file_py/root/foo15.bin
|
||||||
|
INFO: [20181121131151.929083] 185.203.112.26: Processing __file_py/root/foo16.bin
|
||||||
|
INFO: [20181121131153.923590] 185.203.112.26: Processing __file_py/root/foo17.bin
|
||||||
|
INFO: [20181121131155.874910] 185.203.112.26: Processing __file_py/root/foo18.bin
|
||||||
|
INFO: [20181121131157.857904] 185.203.112.26: Processing __file_py/root/foo19.bin
|
||||||
|
INFO: [20181121131159.902006] 185.203.112.26: Processing __file_py/root/foo20.bin
|
||||||
|
INFO: [20181121131201.859840] 185.203.112.26: Processing __file_py/root/foo21.bin
|
||||||
|
INFO: [20181121131203.810875] 185.203.112.26: Processing __file_py/root/foo22.bin
|
||||||
|
INFO: [20181121131205.763291] 185.203.112.26: Processing __file_py/root/foo23.bin
|
||||||
|
INFO: [20181121131207.710932] 185.203.112.26: Processing __file_py/root/foo24.bin
|
||||||
|
INFO: [20181121131209.658154] 185.203.112.26: Processing __file_py/root/foo25.bin
|
||||||
|
INFO: [20181121131211.615374] 185.203.112.26: Processing __file_py/root/foo26.bin
|
||||||
|
INFO: [20181121131213.569721] 185.203.112.26: Processing __file_py/root/foo27.bin
|
||||||
|
INFO: [20181121131215.522624] 185.203.112.26: Processing __file_py/root/foo28.bin
|
||||||
|
INFO: [20181121131217.471128] 185.203.112.26: Processing __file_py/root/foo29.bin
|
||||||
|
INFO: [20181121131219.421712] 185.203.112.26: Processing __file_py/root/foo30.bin
|
||||||
|
INFO: [20181121131221.375699] 185.203.112.26: Processing __file_py/root/foo31.bin
|
||||||
|
INFO: [20181121131223.327672] 185.203.112.26: Processing __file_py/root/foo32.bin
|
||||||
|
INFO: [20181121131225.281373] 185.203.112.26: Processing __file_py/root/foo33.bin
|
||||||
|
INFO: [20181121131227.256711] 185.203.112.26: Processing __file_py/root/foo34.bin
|
||||||
|
INFO: [20181121131229.209255] 185.203.112.26: Processing __file_py/root/foo35.bin
|
||||||
|
INFO: [20181121131231.170170] 185.203.112.26: Processing __file_py/root/foo36.bin
|
||||||
|
INFO: [20181121131233.123407] 185.203.112.26: Processing __file_py/root/foo37.bin
|
||||||
|
INFO: [20181121131235.077713] 185.203.112.26: Processing __file_py/root/foo38.bin
|
||||||
|
INFO: [20181121131237.017138] 185.203.112.26: Processing __file_py/root/foo39.bin
|
||||||
|
INFO: [20181121131238.988189] 185.203.112.26: Processing __file_py/root/foo40.bin
|
||||||
|
INFO: [20181121131241.026849] 185.203.112.26: Processing __file_py/root/foo41.bin
|
||||||
|
INFO: [20181121131242.978335] 185.203.112.26: Processing __file_py/root/foo42.bin
|
||||||
|
INFO: [20181121131244.934562] 185.203.112.26: Processing __file_py/root/foo43.bin
|
||||||
|
INFO: [20181121131246.885320] 185.203.112.26: Processing __file_py/root/foo44.bin
|
||||||
|
INFO: [20181121131248.835008] 185.203.112.26: Processing __file_py/root/foo45.bin
|
||||||
|
INFO: [20181121131250.789727] 185.203.112.26: Processing __file_py/root/foo46.bin
|
||||||
|
INFO: [20181121131252.738686] 185.203.112.26: Processing __file_py/root/foo47.bin
|
||||||
|
INFO: [20181121131254.691465] 185.203.112.26: Processing __file_py/root/foo48.bin
|
||||||
|
INFO: [20181121131256.640896] 185.203.112.26: Processing __file_py/root/foo49.bin
|
||||||
|
INFO: [20181121131258.194372] 185.203.112.26: Finished successful run in 108.01 seconds
|
||||||
|
|
||||||
|
# py type, files exist at remote
|
||||||
|
echo 'x=0; while [ $x -lt 50 ]; do __file_py /root/foo${x}.bin --source /tmp/test.file --mode 0640 --owner root --group root; x=$((x + 1)); done' | ./bin/cdist config -v -P -i - 185.203.112.26
|
||||||
|
|
||||||
|
INFO: [20181121131327.054523] 185.203.112.26: Starting configuration run
|
||||||
|
INFO: [20181121131428.031761] 185.203.112.26: Finished successful run in 60.98 seconds
|
||||||
|
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
# sh type, no file at remote
|
||||||
|
INFO: [20181121125439.429440] 185.203.112.26: Finished successful run in 165.38 seconds
|
||||||
|
# py type, no file at remote
|
||||||
|
INFO: [20181121125957.514738] 185.203.112.26: Finished successful run in 105.48 seconds
|
||||||
|
|
||||||
|
# sh type, files exist at remote but content changes
|
||||||
|
INFO: [20181121125724.451523] 185.203.112.26: Finished successful run in 114.50 seconds
|
||||||
|
# py type, files exist at remote but content changes
|
||||||
|
INFO: [20181121130305.144393] 185.203.112.26: Finished successful run in 128.66 seconds
|
||||||
|
|
||||||
|
|
||||||
|
# sh type, no file at remote
|
||||||
|
INFO: [20181121130825.833163] 185.203.112.26: Finished successful run in 133.31 seconds
|
||||||
|
# py type, no file at remote
|
||||||
|
INFO: [20181121131258.194372] 185.203.112.26: Finished successful run in 108.01 seconds
|
||||||
|
|
||||||
|
# sh type, files exist at remote
|
||||||
|
INFO: [20181121130957.927705] 185.203.112.26: Finished successful run in 62.95 seconds
|
||||||
|
# py type, files exist at remote
|
||||||
|
INFO: [20181121131428.031761] 185.203.112.26: Finished successful run in 60.98 seconds
|
43
docs/dev/python-types/benchmark.sh
Executable file
43
docs/dev/python-types/benchmark.sh
Executable file
|
@ -0,0 +1,43 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Addapt to your env.
|
||||||
|
CDIST_PATH="$CDIST_PATH:./docs/dev/python-types/conf"
|
||||||
|
export CDIST_PATH
|
||||||
|
TARGET_HOST=185.203.112.26
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]
|
||||||
|
then
|
||||||
|
N=1
|
||||||
|
else
|
||||||
|
N=$1
|
||||||
|
fi
|
||||||
|
|
||||||
|
manifest() {
|
||||||
|
bytes=$(echo "$1 * 1024" | bc)
|
||||||
|
echo "head -c ${bytes} /dev/random | __file$2 /root/foo$3.bin --source - --mode 0640 --owner root --group root"
|
||||||
|
}
|
||||||
|
|
||||||
|
verbosity="-vv" #"-vvv"
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt "$N" ]
|
||||||
|
do
|
||||||
|
if [ "$N" -ne 1 ]
|
||||||
|
then
|
||||||
|
printf "iteration %d\\n" "$i"
|
||||||
|
fi
|
||||||
|
printf "shinit clean state...\\n"
|
||||||
|
ssh root@${TARGET_HOST} 'rm foo$i.bin;'
|
||||||
|
manifest 50 "" $i | ./bin/cdist config "${verbosity}" -P -i - ${TARGET_HOST}
|
||||||
|
|
||||||
|
printf "pyinit clean state...\\n"
|
||||||
|
ssh root@${TARGET_HOST} 'rm foo$i.bin;'
|
||||||
|
manifest 50 '_py' $i | ./bin/cdist config "${verbosity}" -P -i - ${TARGET_HOST}
|
||||||
|
|
||||||
|
printf "shinit present state...\\n"
|
||||||
|
manifest 50 "" $i | ./bin/cdist config "${verbosity}" -P -i - ${TARGET_HOST}
|
||||||
|
|
||||||
|
printf "pyinit present state...\\n"
|
||||||
|
manifest 50 '_py' $i | ./bin/cdist config "${verbosity}" -P -i - ${TARGET_HOST}
|
||||||
|
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
7
docs/dev/python-types/conf/manifest/pyinit
Normal file
7
docs/dev/python-types/conf/manifest/pyinit
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#for x in 1; do
|
||||||
|
# echo xxx${x} | __file_py /root/foobar${x} --source - --mode 0640 --owner root --group root;
|
||||||
|
#done
|
||||||
|
#__dummy_config_py test1
|
||||||
|
|
||||||
|
echo xxx | __file_py /root/foobar --source - --mode 0640 --owner root --group root
|
||||||
|
__dummy_config_py test1
|
7
docs/dev/python-types/conf/manifest/shinit
Normal file
7
docs/dev/python-types/conf/manifest/shinit
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#for x in 1; do
|
||||||
|
# echo xxx${x} | __file /root/foobar${x} --source - --mode 0640 --owner root --group root;
|
||||||
|
#done
|
||||||
|
#__dummy_config_sh test1
|
||||||
|
|
||||||
|
echo xxx | __file /root/foobar --source - --mode 0640 --owner root --group root
|
||||||
|
__dummy_config_sh test1
|
|
@ -0,0 +1,22 @@
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from cdist.core.pytypes import *
|
||||||
|
|
||||||
|
|
||||||
|
class DummyConfig(PythonType):
|
||||||
|
def type_manifest(self):
|
||||||
|
print('dummy manifest stdout')
|
||||||
|
print('dummy manifest stderr\n', file=sys.stderr)
|
||||||
|
yield file_py('/root/dummy1.conf',
|
||||||
|
mode='0640',
|
||||||
|
owner='root',
|
||||||
|
group='root',
|
||||||
|
source='-').feed_stdin('dummy=1\n')
|
||||||
|
|
||||||
|
self_path = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
conf_path = os.path.join(self_path, 'files', 'dummy.conf')
|
||||||
|
yield file_py('/root/dummy2.conf',
|
||||||
|
mode='0640',
|
||||||
|
owner='root',
|
||||||
|
group='root',
|
||||||
|
source=conf_path)
|
|
@ -0,0 +1 @@
|
||||||
|
dummy=2
|
|
@ -0,0 +1 @@
|
||||||
|
dummy=2
|
|
@ -0,0 +1,6 @@
|
||||||
|
printf 'dummy manifest stdout\n'
|
||||||
|
printf 'dummy manifest stderr\n' >&2
|
||||||
|
|
||||||
|
printf "dummy=1\\n" | __file /root/dummy1.conf --mode 0640 --owner root --group root --source -
|
||||||
|
|
||||||
|
__file /root/dummy2.conf --mode 0600 --owner root --group root --source "$__type/files/dummy.conf"
|
27
docs/dev/python-types/test.sh
Executable file
27
docs/dev/python-types/test.sh
Executable file
|
@ -0,0 +1,27 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Addapt to your env.
|
||||||
|
CDIST_PATH="$CDIST_PATH:./docs/dev/python-types/conf"
|
||||||
|
export CDIST_PATH
|
||||||
|
TARGET_HOST=185.203.112.26
|
||||||
|
env | grep CDIST_PATH
|
||||||
|
|
||||||
|
for streams in ' ' '-S'
|
||||||
|
do
|
||||||
|
for x in sh py
|
||||||
|
do
|
||||||
|
printf "[%s] Removing old foobar* files\\n" "$x"
|
||||||
|
printf -- "----------------\\n"
|
||||||
|
ssh root@${TARGET_HOST} 'rm foobar*; rm dummy*'
|
||||||
|
printf "[%s] Listing foobar* files\\n" "$x"
|
||||||
|
printf -- "----------------\\n"
|
||||||
|
ssh root@${TARGET_HOST} 'ls foobar* dummy*'
|
||||||
|
printf "[%s] Running cdist config, streams: %s\\n" "$x" "$streams"
|
||||||
|
printf -- "----------------\\n"
|
||||||
|
./bin/cdist config -P ${streams} -v -i ./docs/dev/python-types/conf/manifest/${x}init -- ${TARGET_HOST}
|
||||||
|
printf "[%s] Listing foobar* files\\n" "$x"
|
||||||
|
printf -- "----------------\\n"
|
||||||
|
ssh root@${TARGET_HOST} 'ls foobar* dummy*'
|
||||||
|
./bin/cdist config -P ${streams} -v -i ./docs/dev/python-types/conf/manifest/${x}init -- ${TARGET_HOST}
|
||||||
|
done
|
||||||
|
done
|
36
docs/dev/python-types/timeit.sh
Executable file
36
docs/dev/python-types/timeit.sh
Executable file
|
@ -0,0 +1,36 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Addapt to your env.
|
||||||
|
CDIST_PATH="$CDIST_PATH:./docs/dev/python-types/conf"
|
||||||
|
export CDIST_PATH
|
||||||
|
TARGET_HOST=185.203.112.26
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]
|
||||||
|
then
|
||||||
|
N=1
|
||||||
|
else
|
||||||
|
N=$1
|
||||||
|
fi
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt "$N" ]
|
||||||
|
do
|
||||||
|
if [ "$N" -ne 1 ]
|
||||||
|
then
|
||||||
|
printf "iteration %d\\n" "$i"
|
||||||
|
fi
|
||||||
|
printf "shinit clean state...\\n"
|
||||||
|
ssh root@${TARGET_HOST} 'rm foobar*; rm dummy*;'
|
||||||
|
|
||||||
|
time ./bin/cdist config -vv -P -i ./docs/dev/python-types/conf/manifest/shinit ${TARGET_HOST}
|
||||||
|
printf "pyinit clean state...\\n"
|
||||||
|
ssh root@$${TARGET_HOST} 'rm foobar*; rm dummy*;'
|
||||||
|
time ./bin/cdist config -vv -P -i ./docs/dev/python-types/conf/manifest/pyinit ${TARGET_HOST}
|
||||||
|
|
||||||
|
printf "shinit present state...\\n"
|
||||||
|
time ./bin/cdist config -vv -P -i ./docs/dev/python-types/conf/manifest/shinit ${TARGET_HOST}
|
||||||
|
|
||||||
|
printf "pyinit present state...\\n"
|
||||||
|
time ./bin/cdist config -vv -P -i ./docs/dev/python-types/conf/manifest/pyinit ${TARGET_HOST}
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
|
@ -1,90 +0,0 @@
|
||||||
* Install requirements (Alpine)
|
|
||||||
- apk add py3-pycodestyle shellcheck py3-sphinx py3-sphinx_rtd_theme \
|
|
||||||
py3-build twine
|
|
||||||
* Ensure your gpg setup works with the email used in the git commit!
|
|
||||||
- For me this is nico@nico-notebook.schottelius.org
|
|
||||||
- Signature / id is on nb2
|
|
||||||
* Create ~/.pypirc
|
|
||||||
[distutils]
|
|
||||||
index-servers =
|
|
||||||
pypi
|
|
||||||
cdist
|
|
||||||
|
|
||||||
[pypi]
|
|
||||||
username = __token__
|
|
||||||
password = ...
|
|
||||||
|
|
||||||
[cdist]
|
|
||||||
repository = https://upload.pypi.org/legacy/
|
|
||||||
username = __token__
|
|
||||||
password = ...
|
|
||||||
|
|
||||||
* Add date in docs/changelog
|
|
||||||
* Run ./bin/cdist-build-helper
|
|
||||||
* TODO Move to "build"
|
|
||||||
- python3 -m build
|
|
||||||
* DONE git tag: when?
|
|
||||||
CLOSED: [2022-07-31 Sun 23:58]
|
|
||||||
** Asked during release process: ok
|
|
||||||
* DONE Pypi error with distutils: do not use distutils anymore
|
|
||||||
CLOSED: [2022-07-31 Sun 23:58]
|
|
||||||
python3 setup.py sdist upload
|
|
||||||
...
|
|
||||||
Creating tar archive
|
|
||||||
removing 'cdist-7.0.0' (and everything under it)
|
|
||||||
running upload
|
|
||||||
Submitting dist/cdist-7.0.0.tar.gz to https://upload.pypi.org/legacy/
|
|
||||||
Upload failed (400): Invalid value for blake2_256_digest. Error: Use a valid, hex-encoded, BLAKE2 message digest.
|
|
||||||
error: Upload failed (400): Invalid value for blake2_256_digest. Error: Use a valid, hex-encoded, BLAKE2 message digest.
|
|
||||||
(venv2) [22:50] nb2:cdist%
|
|
||||||
|
|
||||||
* DONE Pypi error with twine: fixed in twine 4.0.1
|
|
||||||
CLOSED: [2022-07-31 Sun 23:58]
|
|
||||||
|
|
||||||
Seeing:
|
|
||||||
|
|
||||||
(venv2) [22:47] nb2:cdist% twine upload dist/cdist-7.0.0*
|
|
||||||
Uploading distributions to https://upload.pypi.org/legacy/
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "/usr/bin/twine", line 8, in <module>
|
|
||||||
sys.exit(main())
|
|
||||||
File "/usr/lib/python3.10/site-packages/twine/__main__.py", line 28, in main
|
|
||||||
result = cli.dispatch(sys.argv[1:])
|
|
||||||
File "/usr/lib/python3.10/site-packages/twine/cli.py", line 68, in dispatch
|
|
||||||
return main(args.args)
|
|
||||||
File "/usr/lib/python3.10/site-packages/twine/commands/upload.py", line 197, in main
|
|
||||||
return upload(upload_settings, parsed_args.dists)
|
|
||||||
File "/usr/lib/python3.10/site-packages/twine/commands/upload.py", line 141, in upload
|
|
||||||
resp = repository.upload(package)
|
|
||||||
File "/usr/lib/python3.10/site-packages/twine/repository.py", line 189, in upload
|
|
||||||
resp = self._upload(package)
|
|
||||||
File "/usr/lib/python3.10/site-packages/twine/repository.py", line 144, in _upload
|
|
||||||
data = package.metadata_dictionary()
|
|
||||||
File "/usr/lib/python3.10/site-packages/twine/package.py", line 181, in metadata_dictionary
|
|
||||||
"dynamic": meta.dynamic,
|
|
||||||
AttributeError: 'Wheel' object has no attribute 'dynamic'
|
|
||||||
|
|
||||||
|
|
||||||
Fix:
|
|
||||||
|
|
||||||
|
|
||||||
(venv2) [23:43] nb2:cdist% pipx run twine upload dist/*
|
|
||||||
⚠️ twine is already on your PATH and installed at /home/nico/venv2/bin/twine. Downloading and running anyway.
|
|
||||||
Uploading distributions to https://upload.pypi.org/legacy/
|
|
||||||
Uploading cdist-7.0.0-py3-none-any.whl
|
|
||||||
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 868.6/868.6 kB • 00:04 • 221.3 kB/s
|
|
||||||
Uploading cdist-7.0.0.tar.gz
|
|
||||||
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.5/1.5 MB • 00:08 • 169.3 kB/s
|
|
||||||
|
|
||||||
View at:
|
|
||||||
https://pypi.org/project/cdist/7.0.0/
|
|
||||||
* TODO cdist web
|
|
||||||
- on staticweb-2022
|
|
||||||
- Should be moved to sftp/k8s
|
|
||||||
|
|
||||||
|
|
||||||
Manual steps:
|
|
||||||
|
|
||||||
~/bin/permissions.public html/
|
|
||||||
rsync -a html/ staticweb.ungleich.ch:/home/services/www/nico/www.cdi.st/www/manual/7.0.0/
|
|
||||||
ssh staticweb.ungleich.ch "cd /home/services/www/nico/www.cdi.st/www/manual; ln -sf 7.0.0 latest"
|
|
|
@ -25,15 +25,16 @@ For example, to create an ubuntu PreOS:
|
||||||
.. code-block:: sh
|
.. code-block:: sh
|
||||||
|
|
||||||
$ cdist preos ubuntu /preos/preos-ubuntu -B -C \
|
$ cdist preos ubuntu /preos/preos-ubuntu -B -C \
|
||||||
-k ~/.ssh/id_rsa.pub -p /preos/pxe-ubuntu
|
-k ~/.ssh/id_rsa.pub -p /preos/pxe-ubuntu \
|
||||||
|
-t "/usr/bin/curl 192.168.111.5:3000/cdist/install/"
|
||||||
|
|
||||||
For more info about the available options see the cdist manual page.
|
For more info about the available options see the cdist manual page.
|
||||||
|
|
||||||
This will bootstrap (``-B``) ubuntu PreOS in the ``/preos/preos-ubuntu``
|
This will bootstrap (``-B``) ubuntu PreOS in ``/preos/preos-ubuntu`` directory, it
|
||||||
directory, it will be configured (``-C``) using default the built-in initial
|
will be configured (``-C``) using default built-in initial manifest and with
|
||||||
manifest and with specified ssh authorized key (``-k``).
|
specified ssh authorized key (``-k``) and with specified trigger command (``-t``).
|
||||||
After bootstrapping and configuration, the PXE boot directory will be
|
After bootstrapping and configuration PXE
|
||||||
created (``-p``) in ``/preos/pxe-ubuntu``.
|
boot directory will be created (``-p``) in ``/preos/pxe-ubuntu``.
|
||||||
|
|
||||||
After PreOS is created, new machines can be booted using the created PXE
|
After PreOS is created, new machines can be booted using the created PXE
|
||||||
(after proper dhcp and tftp settings).
|
(after proper dhcp and tftp settings).
|
||||||
|
@ -41,8 +42,17 @@ After PreOS is created, new machines can be booted using the created PXE
|
||||||
Since PreOS is configured with ssh authorized key it can be accessed through
|
Since PreOS is configured with ssh authorized key it can be accessed through
|
||||||
ssh, i.e. it can be further installed and configured with cdist.
|
ssh, i.e. it can be further installed and configured with cdist.
|
||||||
|
|
||||||
Implementing a new PreOS sub-command
|
When installing and configuring new machines using cdist's PreOS concept
|
||||||
------------------------------------
|
cdist can use triggering for host installation/configuration, which is described
|
||||||
|
in the previous chapter.
|
||||||
|
|
||||||
|
When new machine is booted with PreOS then trigger command is executed.
|
||||||
|
Machine will connect to cdist trigger server. If the request is, for example,
|
||||||
|
for installation then cdist trigger server will start install command for the
|
||||||
|
client host using parameters specified at trigger server startup.
|
||||||
|
|
||||||
|
Implementing new PreOS sub-command
|
||||||
|
----------------------------------
|
||||||
preos command is implemented as a plugin system. This plugin system scans for
|
preos command is implemented as a plugin system. This plugin system scans for
|
||||||
preos subcommands in the ``cdist/preos/`` distribution directory and also in
|
preos subcommands in the ``cdist/preos/`` distribution directory and also in
|
||||||
``~/.cdist/preos/`` directory if it exists.
|
``~/.cdist/preos/`` directory if it exists.
|
||||||
|
@ -127,3 +137,32 @@ When you try to run this new preos you will get:
|
||||||
|
|
||||||
In the ``commandline`` function/method you have all the freedom to actually create
|
In the ``commandline`` function/method you have all the freedom to actually create
|
||||||
a PreOS.
|
a PreOS.
|
||||||
|
|
||||||
|
Simple tipical use case for using PreOS and trigger
|
||||||
|
---------------------------------------------------
|
||||||
|
Tipical use case for using PreOS and trigger command include the following steps.
|
||||||
|
|
||||||
|
#. Create PreOS PXE with ssh key and trigger command for installation.
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
$ cdist preos ubuntu /preos/ubuntu -b -C \
|
||||||
|
-k ~/.ssh/id_rsa.pub -p /preos/pxe \
|
||||||
|
-t "/usr/bin/curl 192.168.111.5:3000/cdist/install/"
|
||||||
|
|
||||||
|
#. Configure dhcp server and tftp server.
|
||||||
|
|
||||||
|
#. On cdist host (192.168.111.5 from above) start trigger command (it will use
|
||||||
|
default init manifest for installation).
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
$ cdist trigger -b -v
|
||||||
|
|
||||||
|
#. After all is set up start new machines (PXE boot).
|
||||||
|
|
||||||
|
#. New machine boots and executes trigger command, i.e. triggers installation.
|
||||||
|
|
||||||
|
#. Cdist trigger server starts installing host that has triggered it.
|
||||||
|
|
||||||
|
#. After cdist install is finished new host is installed.
|
||||||
|
|
35
docs/src/cdist-trigger.rst
Normal file
35
docs/src/cdist-trigger.rst
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
Trigger
|
||||||
|
=======
|
||||||
|
|
||||||
|
Description
|
||||||
|
-----------
|
||||||
|
cdist supports triggering for host installation/configuration using trigger command.
|
||||||
|
This command starts trigger server at management node, for example:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
$ cdist trigger -b -v
|
||||||
|
|
||||||
|
This will start cdist trigger server in verbose mode. cdist trigger server accepts
|
||||||
|
simple requests for configuration and for installation:
|
||||||
|
|
||||||
|
* :strong:`/cdist/install/` for installation
|
||||||
|
* :strong:`/cdist/config/` for configuration.
|
||||||
|
|
||||||
|
Other configuration parameters are the same as in like cdist config (See `cdist <man1/cdist.html>`_).
|
||||||
|
|
||||||
|
Machines can then trigger cdist trigger server with appropriate requests.
|
||||||
|
If the request is, for example, for installation (:strong:`/cdist/install/`)
|
||||||
|
then cdist trigger server will start install command for the client host using
|
||||||
|
parameters specified at trigger server startup. For the above example that means
|
||||||
|
that client will be installed using default initial manifest.
|
||||||
|
|
||||||
|
When triggered cdist will try to reverse DNS lookup for host name and if
|
||||||
|
host name is dervied then it is used for running cdist config. If no
|
||||||
|
host name is resolved then IP address is used.
|
||||||
|
|
||||||
|
This command returns the following response codes to client requests:
|
||||||
|
|
||||||
|
* 200 for success
|
||||||
|
* 599 for cdist run errors
|
||||||
|
* 500 for cdist/server errors.
|
|
@ -522,3 +522,92 @@ How to include a type into upstream cdist
|
||||||
If you think your type may be useful for others, ensure it works with the
|
If you think your type may be useful for others, ensure it works with the
|
||||||
current master branch of cdist and have a look at `cdist hacking <cdist-hacker.html>`_ on
|
current master branch of cdist and have a look at `cdist hacking <cdist-hacker.html>`_ on
|
||||||
how to submit it.
|
how to submit it.
|
||||||
|
|
||||||
|
|
||||||
|
Python types
|
||||||
|
------------
|
||||||
|
From version/branch **beta** cdist support python types, types that are written
|
||||||
|
in python language with cdist's core support. cdist detects such type if type is
|
||||||
|
detectable as a python package, i.e. if **__init__.py** file is present in type's
|
||||||
|
root directory. Upon that detection cdist will try to run such type as core python
|
||||||
|
type.
|
||||||
|
|
||||||
|
Note that this differs from plain cdist type where scripts are written in pure
|
||||||
|
python and have a proper shebang.
|
||||||
|
|
||||||
|
Core python types replace manifest and gencode scripts. Parameters, singleton,
|
||||||
|
nonparallel are still defined as for common types. Explorer code is also written
|
||||||
|
in shell, since this is the code that is directly executed at target host.
|
||||||
|
|
||||||
|
When writing python type you can extend **cdist.core.pytypes.PythonType** class.
|
||||||
|
You need to implement the following methods:
|
||||||
|
|
||||||
|
* **get_args_parser**: implementation should return **argparse.ArgumentParser** and if
|
||||||
|
it is undefined or returned None then cdist falls back to classic type parameter
|
||||||
|
definition and argument parsing
|
||||||
|
* **type_manifest**: implementation should yield **cdist.core.pytypes.<type-name>**
|
||||||
|
attribute function call result, or **yield from ()** if type does not use other types
|
||||||
|
* **type_gencode**: implementation should return a string consisting of lines
|
||||||
|
of shell code that will be executed at target host.
|
||||||
|
|
||||||
|
**cdist.core.pytypes.<type-name>** attributes correspond to detected python types.
|
||||||
|
**Note** that double underscore ('__') at the beginning of type name is removed.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from cdist.core.pytypes import *
|
||||||
|
|
||||||
|
|
||||||
|
class DummyConfig(PythonType):
|
||||||
|
def type_manifest(self):
|
||||||
|
print('dummy manifest stdout')
|
||||||
|
print('dummy manifest stderr\n', file=sys.stderr)
|
||||||
|
yield file_py('/root/dummy1.conf',
|
||||||
|
mode='0640',
|
||||||
|
owner='root',
|
||||||
|
group='root',
|
||||||
|
source='-').feed_stdin('dummy=1\n')
|
||||||
|
|
||||||
|
self_path = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
conf_path = os.path.join(self_path, 'files', 'dummy.conf')
|
||||||
|
yield file_py('/root/dummy2.conf',
|
||||||
|
mode='0640',
|
||||||
|
owner='root',
|
||||||
|
group='root',
|
||||||
|
source=conf_path)
|
||||||
|
|
||||||
|
**cdist.core.PythonType** class provides the following methods:
|
||||||
|
|
||||||
|
* **get_parameter**: get type parameter
|
||||||
|
* **get_explorer_file**: get path to file for specified explorer
|
||||||
|
* **get_explorer**: get value for specified explorer
|
||||||
|
* **run_local**: run specified command locally
|
||||||
|
* **run_remote**: run specified command remotely
|
||||||
|
* **transfer**: transfer specified source to the remote
|
||||||
|
* **die**: raise error
|
||||||
|
* **send_message**: send message
|
||||||
|
* **receive_message**: get message.
|
||||||
|
|
||||||
|
When running python type, cdist will save output streams to **gencode-py**,
|
||||||
|
stdout and stderr output files.
|
||||||
|
|
||||||
|
As a reference implementation you can take a look at **__file_py** type,
|
||||||
|
which is re-implementation of **__file** type.
|
||||||
|
|
||||||
|
Furthermore, under **docs/dev/python-types** there are sample cdist conf directory,
|
||||||
|
init manifests and scripts for running and measuring duration of samples.
|
||||||
|
There, under **conf/type/__dummy_config** you can find another example of
|
||||||
|
python type, which (unlike **__file_py** type) also uses new manifest implementation
|
||||||
|
that yields **cdist.core.pytypes.<type-name>** attribute function call results.
|
||||||
|
|
||||||
|
**NOTE** that python types implementation is under the beta, not directly controled by
|
||||||
|
the **-b/--beta** option. It is controled by the explicit usage of python types in
|
||||||
|
your config.
|
||||||
|
|
||||||
|
Also, this documenation is only an introduction, and not a complete guide to python
|
||||||
|
types. Currently, it is just a short introduction so one can start to write and use
|
||||||
|
python types.
|
||||||
|
|
|
@ -33,6 +33,7 @@ It natively supports IPv6 since the first release.
|
||||||
cdist-messaging
|
cdist-messaging
|
||||||
cdist-parallelization
|
cdist-parallelization
|
||||||
cdist-inventory
|
cdist-inventory
|
||||||
|
cdist-trigger
|
||||||
cdist-preos
|
cdist-preos
|
||||||
cdist-scan
|
cdist-scan
|
||||||
cdist-integration
|
cdist-integration
|
||||||
|
|
|
@ -11,7 +11,7 @@ SYNOPSIS
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
cdist [-h] [-V] {banner,config,install,inventory,preos,shell,info} ...
|
cdist [-h] [-V] {banner,config,install,inventory,preos,shell,info,trigger} ...
|
||||||
|
|
||||||
cdist banner [-h] [-l LOGLEVEL] [-q] [-v]
|
cdist banner [-h] [-l LOGLEVEL] [-q] [-v]
|
||||||
|
|
||||||
|
@ -66,21 +66,24 @@ SYNOPSIS
|
||||||
[-C] [-c CDIST_PARAMS] [-D DRIVE] [-e REMOTE_EXEC]
|
[-C] [-c CDIST_PARAMS] [-D DRIVE] [-e REMOTE_EXEC]
|
||||||
[-i MANIFEST] [-k KEYFILE ] [-m MIRROR]
|
[-i MANIFEST] [-k KEYFILE ] [-m MIRROR]
|
||||||
[-P ROOT_PASSWORD] [-p PXE_BOOT_DIR] [-r]
|
[-P ROOT_PASSWORD] [-p PXE_BOOT_DIR] [-r]
|
||||||
[-S SCRIPT] [-s SUITE] [-y REMOTE_COPY]
|
[-S SCRIPT] [-s SUITE] [-t TRIGGER_COMMAND]
|
||||||
|
[-y REMOTE_COPY]
|
||||||
target_dir
|
target_dir
|
||||||
|
|
||||||
cdist preos [preos-options] devuan [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-a ARCH] [-B]
|
cdist preos [preos-options] devuan [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-a ARCH] [-B]
|
||||||
[-C] [-c CDIST_PARAMS] [-D DRIVE] [-e REMOTE_EXEC]
|
[-C] [-c CDIST_PARAMS] [-D DRIVE] [-e REMOTE_EXEC]
|
||||||
[-i MANIFEST] [-k KEYFILE ] [-m MIRROR]
|
[-i MANIFEST] [-k KEYFILE ] [-m MIRROR]
|
||||||
[-P ROOT_PASSWORD] [-p PXE_BOOT_DIR] [-r]
|
[-P ROOT_PASSWORD] [-p PXE_BOOT_DIR] [-r]
|
||||||
[-S SCRIPT] [-s SUITE] [-y REMOTE_COPY]
|
[-S SCRIPT] [-s SUITE] [-t TRIGGER_COMMAND]
|
||||||
|
[-y REMOTE_COPY]
|
||||||
target_dir
|
target_dir
|
||||||
|
|
||||||
cdist preos [preos-options] ubuntu [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-a ARCH] [-B]
|
cdist preos [preos-options] ubuntu [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-a ARCH] [-B]
|
||||||
[-C] [-c CDIST_PARAMS] [-D DRIVE] [-e REMOTE_EXEC]
|
[-C] [-c CDIST_PARAMS] [-D DRIVE] [-e REMOTE_EXEC]
|
||||||
[-i MANIFEST] [-k KEYFILE ] [-m MIRROR]
|
[-i MANIFEST] [-k KEYFILE ] [-m MIRROR]
|
||||||
[-P ROOT_PASSWORD] [-p PXE_BOOT_DIR] [-r]
|
[-P ROOT_PASSWORD] [-p PXE_BOOT_DIR] [-r]
|
||||||
[-S SCRIPT] [-s SUITE] [-y REMOTE_COPY]
|
[-S SCRIPT] [-s SUITE] [-t TRIGGER_COMMAND]
|
||||||
|
[-y REMOTE_COPY]
|
||||||
target_dir
|
target_dir
|
||||||
|
|
||||||
cdist shell [-h] [-l LOGLEVEL] [-q] [-v] [--colors WHEN] [-s SHELL]
|
cdist shell [-h] [-l LOGLEVEL] [-q] [-v] [--colors WHEN] [-s SHELL]
|
||||||
|
@ -88,6 +91,12 @@ SYNOPSIS
|
||||||
cdist info [-h] [-a] [-c CONF_DIR] [-e] [-F] [-f] [-g CONFIG_FILE] [-t]
|
cdist info [-h] [-a] [-c CONF_DIR] [-e] [-F] [-f] [-g CONFIG_FILE] [-t]
|
||||||
[pattern]
|
[pattern]
|
||||||
|
|
||||||
|
cdist trigger [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] [-4]
|
||||||
|
[-6] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST]
|
||||||
|
[-j [JOBS]] [-n] [-o OUT_PATH] [-P]
|
||||||
|
[-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_PATH]
|
||||||
|
[--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC]
|
||||||
|
[-S] [-D DIRECTORY] [-H HTTP_PORT] [--ipv6] [-O SOURCE]
|
||||||
cdist scan -I INTERFACE [--m MODE] [--name-mapper PATH_TO_SCRIPT] [--list]
|
cdist scan -I INTERFACE [--m MODE] [--name-mapper PATH_TO_SCRIPT] [--list]
|
||||||
[-d CONFIG_DELAY] [-t TRIGGER_DELAY]
|
[-d CONFIG_DELAY] [-t TRIGGER_DELAY]
|
||||||
|
|
||||||
|
@ -535,6 +544,10 @@ PREOS DEBIAN/DEVUAN
|
||||||
**-s SUITE, --suite SUITE**
|
**-s SUITE, --suite SUITE**
|
||||||
suite used for debootstrap, by default 'stable'
|
suite used for debootstrap, by default 'stable'
|
||||||
|
|
||||||
|
**-t TRIGGER_COMMAND, --trigger-command TRIGGER_COMMAND**
|
||||||
|
trigger command that will be added to cdist config;
|
||||||
|
'``__cdist_preos_trigger http ...``' type is appended to initial manifest
|
||||||
|
|
||||||
**-y REMOTE_COPY, --remote-copy REMOTE_COPY**
|
**-y REMOTE_COPY, --remote-copy REMOTE_COPY**
|
||||||
remote copy that cdist config will use, by default
|
remote copy that cdist config will use, by default
|
||||||
internal script is used
|
internal script is used
|
||||||
|
@ -595,6 +608,10 @@ PREOS UBUNTU
|
||||||
**-s SUITE, --suite SUITE**
|
**-s SUITE, --suite SUITE**
|
||||||
suite used for debootstrap, by default 'xenial'
|
suite used for debootstrap, by default 'xenial'
|
||||||
|
|
||||||
|
**-t TRIGGER_COMMAND, --trigger-command TRIGGER_COMMAND**
|
||||||
|
trigger command that will be added to cdist config;
|
||||||
|
'``__cdist_preos_trigger http ...``' type is appended to initial manifest
|
||||||
|
|
||||||
**-y REMOTE_COPY, --remote-copy REMOTE_COPY**
|
**-y REMOTE_COPY, --remote-copy REMOTE_COPY**
|
||||||
remote copy that cdist config will use, by default
|
remote copy that cdist config will use, by default
|
||||||
internal script is used
|
internal script is used
|
||||||
|
@ -644,6 +661,95 @@ Display information for cdist (global explorers, types).
|
||||||
**-t, --types**
|
**-t, --types**
|
||||||
Display info for types.
|
Display info for types.
|
||||||
|
|
||||||
|
TRIGGER
|
||||||
|
-------
|
||||||
|
Start trigger (simple http server) that waits for connections. When host
|
||||||
|
connects then it triggers config or install command and then cdist
|
||||||
|
config/install is executed which configures/installs host.
|
||||||
|
When triggered cdist will try to reverse DNS lookup for host name and if
|
||||||
|
host name is dervied then it is used for running cdist config. If no
|
||||||
|
host name is resolved then IP address is used.
|
||||||
|
Request path recognizes following requests:
|
||||||
|
|
||||||
|
* :strong:`/cdist/config/.*` for config
|
||||||
|
* :strong:`/cdist/install/.*` for install.
|
||||||
|
|
||||||
|
This command returns the following response codes to client requests:
|
||||||
|
|
||||||
|
* 200 for success
|
||||||
|
* 599 for cdist run errors
|
||||||
|
* 500 for cdist/server errors.
|
||||||
|
|
||||||
|
**-4, -force-ipv4**
|
||||||
|
Force to use IPv4 addresses only. No influence for
|
||||||
|
custom remote commands.
|
||||||
|
|
||||||
|
**-6, --force-ipv6**
|
||||||
|
Force to use IPv6 addresses only. No influence for
|
||||||
|
custom remote commands.
|
||||||
|
|
||||||
|
**-C CACHE_PATH_PATTERN, --cache-path-pattern CACHE_PATH_PATTERN**
|
||||||
|
Specify custom cache path pattern. If it is not set
|
||||||
|
then default hostdir is used.
|
||||||
|
|
||||||
|
**-c CONF_DIR, --conf-dir CONF_DIR**
|
||||||
|
Add configuration directory (can be repeated, last one
|
||||||
|
wins).
|
||||||
|
|
||||||
|
**-D DIRECTORY, --directory DIRECTORY**
|
||||||
|
Where to create local files
|
||||||
|
|
||||||
|
**-g CONFIG_FILE, --config-file CONFIG_FILE**
|
||||||
|
Use specified custom configuration file.
|
||||||
|
|
||||||
|
**-H HTTP_PORT, --http-port HTTP_PORT**
|
||||||
|
Create trigger listener via http on specified port
|
||||||
|
|
||||||
|
**-i MANIFEST, --initial-manifest MANIFEST**
|
||||||
|
Path to a cdist manifest or '-' to read from stdin.
|
||||||
|
|
||||||
|
**--ipv6**
|
||||||
|
Listen to both IPv4 and IPv6 (instead of only IPv4)
|
||||||
|
|
||||||
|
**-j [JOBS], --jobs [JOBS]**
|
||||||
|
Operate in parallel in specified maximum number of
|
||||||
|
jobs. Global explorers, object prepare and object run
|
||||||
|
are supported. Without argument CPU count is used by
|
||||||
|
default. Currently in beta.
|
||||||
|
|
||||||
|
**-n, --dry-run**
|
||||||
|
Do not execute code.
|
||||||
|
|
||||||
|
**-O SOURCE, --source SOURCE**
|
||||||
|
Which file to copy for creation
|
||||||
|
|
||||||
|
**-o OUT_PATH, --out-dir OUT_PATH**
|
||||||
|
Directory to save cdist output in.
|
||||||
|
|
||||||
|
**-P, --timestamp**
|
||||||
|
Timestamp log messages with the current local date and
|
||||||
|
time in the format: YYYYMMDDHHMMSS.us.
|
||||||
|
|
||||||
|
**-R [{tar,tgz,tbz2,txz}], --use-archiving [{tar,tgz,tbz2,txz}]**
|
||||||
|
Operate by using archiving with compression where
|
||||||
|
appropriate. Supported values are: tar - tar archive,
|
||||||
|
tgz - gzip tar archive (the default), tbz2 - bzip2 tar
|
||||||
|
archive and txz - lzma tar archive. Currently in beta.
|
||||||
|
|
||||||
|
**-r REMOTE_OUT_PATH, --remote-out-dir REMOTE_OUT_PATH**
|
||||||
|
Directory to save cdist output in on the target host.
|
||||||
|
|
||||||
|
**--remote-copy REMOTE_COPY**
|
||||||
|
Command to use for remote copy (should behave like
|
||||||
|
scp).
|
||||||
|
|
||||||
|
**--remote-exec REMOTE_EXEC**
|
||||||
|
Command to use for remote execution (should behave
|
||||||
|
like ssh).
|
||||||
|
|
||||||
|
**-S, --disable-saving-output-streams**
|
||||||
|
Disable saving output streams.
|
||||||
|
|
||||||
SCAN
|
SCAN
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -867,20 +973,28 @@ EXAMPLES
|
||||||
# Configure all hosts from inventory db
|
# Configure all hosts from inventory db
|
||||||
$ cdist config -b -A
|
$ cdist config -b -A
|
||||||
|
|
||||||
# Create default debian PreOS in debug mode
|
# Create default debian PreOS in debug mode with config
|
||||||
|
# trigger command
|
||||||
$ cdist preos debian /preos/preos-debian -vvvv -C \
|
$ cdist preos debian /preos/preos-debian -vvvv -C \
|
||||||
-k ~/.ssh/id_rsa.pub -p /preos/pxe-debian
|
-k ~/.ssh/id_rsa.pub -p /preos/pxe-debian \
|
||||||
|
-t "/usr/bin/curl 192.168.111.5:3000/config/"
|
||||||
|
|
||||||
# Create ubuntu PreOS
|
# Create ubuntu PreOS with install trigger command
|
||||||
$ cdist preos ubuntu /preos/preos-ubuntu -C \
|
$ cdist preos ubuntu /preos/preos-ubuntu -C \
|
||||||
-k ~/.ssh/id_rsa.pub -p /preos/pxe-ubuntu
|
-k ~/.ssh/id_rsa.pub -p /preos/pxe-ubuntu \
|
||||||
|
-t "/usr/bin/curl 192.168.111.5:3000/install/"
|
||||||
|
|
||||||
# Create ubuntu PreOS on drive /dev/sdb
|
# Create ubuntu PreOS on drive /dev/sdb with install trigger command
|
||||||
# and set root password to 'password'.
|
# and set root password to 'password'.
|
||||||
$ cdist preos ubuntu /mnt -B -C \
|
$ cdist preos ubuntu /mnt -B -C \
|
||||||
-k ~/.ssh/id_rsa.pub -D /dev/sdb \
|
-k ~/.ssh/id_rsa.pub -D /dev/sdb \
|
||||||
|
-t "/usr/bin/curl 192.168.111.5:3000/install/" \
|
||||||
-P password
|
-P password
|
||||||
|
|
||||||
|
# Start trigger in verbose mode that will configure host using specified
|
||||||
|
# init manifest
|
||||||
|
% cdist trigger -v -i ~/.cdist/manifest/init-for-triggered
|
||||||
|
|
||||||
|
|
||||||
ENVIRONMENT
|
ENVIRONMENT
|
||||||
-----------
|
-----------
|
||||||
|
|
Loading…
Reference in a new issue