Compare commits

...

7 commits

Author SHA1 Message Date
evilham 3ee742f0ab Kamila's changes +iocage_cone + tinydns* ~ __daemontools_service
Consider at some point whether or not they are worth upstreaming.
(also __pf_rdr belongs to this batch)
2020-04-26 17:54:36 +02:00
evilham 47e1267097 Merge branch 'master' into local 2020-04-26 16:42:30 +02:00
evilham cd6c02d16c Add copyright notice and make consistent with other types 2020-04-25 01:29:17 +02:00
evilham 9e5c8a2524 Merge branch 'to-upstream' into local 2020-04-24 20:28:11 +02:00
evilham 6cb0afdb9f Changes changes 2020-04-24 13:29:43 +02:00
evilham 9fdc9082f4 [__letsencrypt_acmetiny] fix spellcheck warnings (bugs!) 2020-03-23 12:35:54 +01:00
evilham 1bd19d6dee [__letsencrypt_acmetiny] Simpler alternative to certbot.
This is inspired heavily by `debops.pki` in the https://debops.org project.
However there are several simplifications to their way of doing it.
2020-03-23 12:26:59 +01:00
39 changed files with 632 additions and 3 deletions

View file

@ -40,6 +40,12 @@ run-file
log-run
Command to run for log consumption. Default: `multilog t ./main`
owner
User to chown to.
group
User to chgrp to.
servicedir
Directory to install into. Default: `/service`

View file

@ -9,6 +9,8 @@ servicedir=$(cat "$__object/parameter/servicedir")
run=$(cat "$__object/parameter/run")
runfile=$(cat "$__object/parameter/run-file")
logrun=$(cat "$__object/parameter/log-run")
owner=$(cat "$__object/parameter/owner")
group=$(cat "$__object/parameter/group")
svc=$(cat "$__type/explorer/svc")
@ -25,14 +27,22 @@ badusage() {
[ -z "$run$runfile" ] && badusage
[ -n "$run" ] && [ -n "$runfile" ] && badusage
__directory "$servicedir/$name/log/main" --parents
flags=""
if [ -n "$owner" ]; then
flags="$flags --owner $owner"
fi
if [ -n "$group" ]; then
flags="$flags --group $group"
fi
__directory "$servicedir/$name/log/main" --parents $flags
echo "$RUN_PREFIX$run" | require="__directory/$servicedir/$name/log/main" __config_file "$servicedir/$name/run" \
--onchange "svc -t '$servicedir/$name' 2>/dev/null" \
--mode 755 \
--mode 755 $flags \
--source "${runfile:--}"
echo "$RUN_PREFIX$logrun" | require="__directory/$servicedir/$name/log/main" __config_file "$servicedir/$name/log/run" \
--onchange "svc -t '$servicedir/$name/log' 2>/dev/null" \
--mode 755 \
--mode 755 $flags \
--source "-"

View file

@ -1,4 +1,6 @@
group
log-run
owner
run
run-file
servicedir

View file

@ -0,0 +1,152 @@
#!/bin/sh
state="$(cat $__object/parameter/state)"
template="$(cat $__object/parameter/template)"
ip4_addr="$(cat $__object/parameter/bridge)|$(cat $__object/parameter/ip)"
interfaces="none:none"
defaultrouter="none"
vnet="off"
jail_zfs_dataset="$(cat $__object/parameter/jail_zfs_dataset)"
devfs_ruleset="$(cat $__object/parameter/devfs_ruleset)"
allow_socket_af="$(cat $__object/parameter/allow_socket_af)"
mount_procfs="$(cat $__object/parameter/mount_procfs)"
mount_linprocfs="$(cat $__object/parameter/mount_linprocfs)"
if [ "X$state" = "Xabsent" ]; then
cat <<EOF
iocage stop $__object_id || true
iocage destroy -f $__object_id || true
rm -f /iocage/jails/$__object_id
EOF
else
cat <<EOF
get_property_zfs () {
zfs get -H -o value \$1 "\$2"
}
get_property_iocage () {
get_property_zfs "org.freebsd.iocage:\$1" "/iocage/jails/\$2"
}
create_new=0
if [ ! -d /iocage/jails/"$__object_id" ]; then
echo "Jail $__object_id does not exist, going to create."
create_new=1
else
base=\$(get_property_zfs origin "/iocage/jails/$__object_id")
current_template=\$(get_property_zfs org.freebsd.iocage:tag "\$base")
if [ "X\$current_template" != "X$template" ]; then
echo "Jail $__object_id has base \$current_template, which is not $template. " >&2
create_new=1
fi
fi
if [ \$create_new -eq 0 ]; then
if [ "off" == "\$(get_property_iocage jail_zfs "$__object_id")" ]; then
current_jail_zfs_dataset=""
else
current_jail_zfs_dataset="\$(get_property_iocage jail_zfs_dataset "$__object_id")"
fi
fi
configure=0
if [ \$create_new -eq 1 ]; then
configure=1
elif [ "X$vnet" != "X\$(get_property_iocage vnet "$__object_id")" ]; then
configure=1
elif [ "X$ip4_addr" != "X\$(get_property_iocage ip4_addr "$__object_id")" ]; then
configure=1
elif [ "X$interfaces" != "X\$(get_property_iocage interfaces "$__object_id")" ]; then
configure=1
elif [ "X$defaultrouter" != "X\$(get_property_iocage defaultrouter "$__object_id")" ]; then
configure=1
elif [ "X$mount_procfs" != "X\$(get_property_iocage mount_procfs "$__object_id")" ]; then
configure=1
elif [ "X$devfs_ruleset" != "X\$(get_property_iocage devfs_ruleset "$__object_id")" ]; then
configure=1
elif [ "X$allow_socket_af" != "X\$(get_property_iocage allow_socket_af "$__object_id")" ]; then
configure=1
elif [ "X$jail_zfs_dataset" != "X\$current_jail_zfs_dataset" ]; then
configure=1
fi
if [ \$create_new -eq 1 ]; then
echo "Creating jail $__object_id" >&2
iocage stop $__object_id || true
iocage destroy -f $__object_id || true
# Without VNETs, we should not need this.
# TODO(riso): Use nicer path
# /root/cdist/ioc deconfigure $__object_id
rm -f /iocage/jails/$__object_id
iocage clone $template tag=$__object_id
iocage set boot=on $__object_id
UUID=\$(iocage list | grep " $__object_id " | awk "{ print \\\$2; }")
rm -f /iocage/jails/$__object_id
ln -s /iocage/jails/\$UUID /iocage/jails/$__object_id
else
UUID=\$(iocage list | grep " $__object_id " | awk "{ print \\\$2; }")
echo "Jail $__object_id already exists, UUID=\$UUID" >&2
fi
ROOT="/iocage/jails/\$UUID/root"
FSTAB="/iocage/jails/\$UUID/fstab"
rm -f \$FSTAB.new
touch \$FSTAB.new
cat $__object/parameter/mount 2>/dev/null | \\
while read mount; do
src=\$(echo \$mount | awk -F: "{ print \\\$1; }")
dst_rel=\$(echo \$mount | awk -F: "{ print \\\$2; }")
dst="/iocage/jails/\$UUID/root/\$dst_rel"
mkdir -p "\$dst"
echo "\$src \$dst nullfs rw 0 0" >>\$FSTAB.new
done
if [ $mount_linprocfs -eq 1 ]; then
echo "linproc /iocage/jails/\$UUID/root/compat/linux/proc linprocfs rw 0 0" >>\$FSTAB.new
fi
fstab_changed=0
if diff -q \$FSTAB \$FSTAB.new >/dev/null; then
# pass
else
configure=1
fstab_changed=1
fi
if [ \$configure -eq 1 ]; then
echo "Configuring jail $__object_id." >&2
iocage stop $__object_id || true
iocage set vnet="$vnet" $__object_id
iocage set interfaces="$interfaces" $__object_id
iocage set hostname="$__object_id" $__object_id
iocage set ip4_addr="$ip4_addr" $__object_id
iocage set defaultrouter="$defaultrouter" $__object_id
iocage set mount_procfs="$mount_procfs" $__object_id
iocage set devfs_ruleset="$devfs_ruleset" $__object_id
iocage set allow_socket_af="$allow_socket_af" $__object_id
if [ -n "$jail_zfs_dataset" ]; then
iocage set jail_zfs=on $__object_id
iocage set jail_zfs_dataset="$jail_zfs_dataset" $__object_id
else
iocage set jail_zfs=off $__object_id
fi
if [ \$fstab_changed -eq 1 ]; then
umount -afF \$FSTAB || true
mv \$FSTAB.new \$FSTAB
fi
iocage start $__object_id || true
# Iocage creates new mac address, but arp can have an old mac cached.
# TODO(riso): Is this true without VNETs?
arp -d -a
else
echo "Jail $__object_id is already configured." >&2
fi
rm -f \$FSTAB.new
EOF
fi

View file

@ -0,0 +1 @@
__package iocage

View file

@ -0,0 +1 @@
bridge0

View file

@ -0,0 +1 @@
4

View file

@ -0,0 +1 @@
0

View file

@ -0,0 +1 @@
24

View file

@ -0,0 +1 @@
present

View file

@ -0,0 +1,7 @@
state
bridge
jail_zfs_dataset
mount_procfs
mount_linprocfs
devfs_ruleset
allow_socket_af

View file

@ -0,0 +1 @@
mount

View file

@ -0,0 +1,2 @@
ip
template

View file

@ -0,0 +1,112 @@
#!/bin/sh -e
ACME_TINY_CERT_REQUEST_DIR="/var/acme-tiny/cert-requests"
ACME_TINY_ACCOUNT_KEY="/var/acme-tiny/account.key"
ACME_CHALLENGE_DIR="/srv/www/sites/acme/public/.well-known/acme-challenge"
REALM="${__object_id}"
EXTRA_DOMAINS=""
if [ -f "${__object}/parameter/extra-domain" ]; then
EXTRA_DOMAINS="$(cat "${__object}/parameter/extra-domain")"
fi
#TODO: support linux too
REALMS_DIR="/usr/local/etc/pki/realms"
REALM_DIR="${REALMS_DIR}/${REALM}"
REALM_CERT="${REALM_DIR}/default.crt"
REALM_KEY="${REALM_DIR}/default.key"
REALM_CERT_REQUEST="${ACME_TINY_CERT_REQUEST_DIR}/${REALM}.csr"
REALM_CERT_REQUEST_CNF="${ACME_TINY_CERT_REQUEST_DIR}/${REALM}.cnf"
CSR_ALT_NAMES=""
REALM_CERT_REQUEST_CNF_LINE=""
if [ -n "${EXTRA_DOMAINS}" ]; then
CSR_ALT_NAMES="DNS:${REALM}"
for domain in ${EXTRA_DOMAINS}; do
CSR_ALT_NAMES="${CSR_ALT_NAMES},DNS:${domain}"
done
# CSR requests are executed always against .new, only after succeeding .new replaces the .cnf
REALM_CERT_REQUEST_CNF_LINE="-reqexts SAN -config '${REALM_CERT_REQUEST_CNF}.new'"
fi
cat << EOF
if [ ! -d '${REALM_DIR}' ]; then
mkdir -p '${REALM_DIR}'
fi
if [ ! -f '${REALM_KEY}' ]; then
openssl genrsa 4096 > '${REALM_KEY}'
fi
if [ ! -d '${ACME_TINY_CERT_REQUEST_DIR}' ]; then
mkdir '${ACME_TINY_CERT_REQUEST_DIR}'
fi
FORCE_CSR_REGEN=""
if [ -n '${CSR_ALT_NAMES}' ]; then
# Generate new config
cat /etc/ssl/openssl.cnf > '${REALM_CERT_REQUEST_CNF}.new'
printf '[SAN]\nsubjectAltName=${CSR_ALT_NAMES}' >> '${REALM_CERT_REQUEST_CNF}.new'
# Compare to previous config if necessary
if [ -f '${REALM_CERT_REQUEST_CNF}' ]; then
CNF_DIFF=\$(diff -q '${REALM_CERT_REQUEST_CNF}' '${REALM_CERT_REQUEST_CNF}.new' || true)
if [ -n "\${CNF_DIFF}" ]; then
# Options have changed
FORCE_CSR_REGEN="YES"
else
# Since they match, we won't be using this, clean it
rm '${REALM_CERT_REQUEST_CNF}.new'
fi
else
# We never used SAN here, CSR regen needed.
FORCE_CSR_REGEN="YES"
fi
else
# We used SAN at some point, not any more
if [ -f '${REALM_CERT_REQUEST_CNF}' ]; then
rm '${REALM_CERT_REQUEST_CNF}'
FORCE_CSR_REGEN="YES"
fi
fi
# Create or re-create when params have changed
if [ ! -f '${REALM_CERT_REQUEST}' -o -n "\${FORCE_CSR_REGEN}" ]; then
openssl req -new -sha256 -key '${REALM_KEY}' -subj '/CN=${REALM}' -out '${REALM_CERT_REQUEST}' ${REALM_CERT_REQUEST_CNF_LINE}
fi
# Check if cert exists, and if so whether or not it's older than a month
if [ -f '${REALM_CERT}' ]; then
MODIFIED_IN_30d="\$(find '${REALM_CERT}' -mtime -30d)"
if [ -z "\${MODIFIED_IN_30d}" ]; then
# Cert is over a month old, it's fine to regenerate
FORCE_CRT_REGEN="YES"
fi
else
# This cert doesn't exist
FORCE_CRT_REGEN="YES"
fi
# Only request certificate when needed
# TODO: support linux too
if [ -n "\${FORCE_CSR_REGEN}" -o -n "\${FORCE_CRT_REGEN}" ]; then
doas -u acme-tiny -- acme_tiny \
--account '${ACME_TINY_ACCOUNT_KEY}' \
--csr '${REALM_CERT_REQUEST}' \
--acme-dir '${ACME_CHALLENGE_DIR}' > '${REALM_CERT}.new'
if [ -s '${REALM_CERT}.new' ]; then
mv '${REALM_CERT}.new' '${REALM_CERT}'
else
echo "Failed to generate cert for realm '${REALM}'."
exit 1
fi
fi
cat "${REALM_CERT}" "${REALMS_DIR}/chain.pem" > ${REALM_DIR}/fullchain.pem
if [ -n '${REALM_CERT_REQUEST_CNF_LINE}' -a -f '${REALM_CERT_REQUEST_CNF}.new' ]; then
# CSR and cert generation succeded with a new config, put new config in-place.
# This is the last thing we do, so we try again next time if sth fails.
mv '${REALM_CERT_REQUEST_CNF}.new' '${REALM_CERT_REQUEST_CNF}'
fi
EOF

View file

@ -0,0 +1 @@
#__letsencrypt_acmetiny_base

View file

@ -0,0 +1 @@
extra-domain

View file

@ -0,0 +1,12 @@
#!/bin/sh -e
ACME_HOME="/var/acme-tiny"
ACME_ACCOUNT_KEY="${ACME_HOME}/account.key"
cat << EOF
if [ ! -f '${ACME_ACCOUNT_KEY}' ]; then
openssl genrsa 4096 > '${ACME_ACCOUNT_KEY}'
chown acme-tiny:acme-tiny '${ACME_ACCOUNT_KEY}'
chmod 640 '${ACME_ACCOUNT_KEY}'
fi
EOF

View file

@ -0,0 +1,227 @@
# Arguments
ACME_DOMAIN="$(cat "${__object}/parameter/acme_domain" || true)"
if [ -z "${ACME_DOMAIN}" ]; then
ACME_DOMAIN="${__target_host}"
fi
# Install needed stuffz
## TODO: consider not depending on nginx? It is... practical though.
## TODO: Maybe just move this out to a sepecial type?
__package "nginx"
NGINX_ETC="/usr/local/etc/nginx"
# Setup the acme-challenge snippet
require="__package/nginx" __directory "${NGINX_ETC}/snippets" --state present
require="__directory${NGINX_ETC}/snippets" __file "${NGINX_ETC}/snippets/acme-challenge.conf" \
--mode 644 \
--source - << EOF
# This file is managed remotely, all changes will be lost
# This was heavily inspired by debops.org.
# Automatic Certificate Management Environment (ACME) support.
# https://tools.ietf.org/html/draft-ietf-acme-acme-01
# https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment
# Return the ACME challenge present in the server public root.
# If not found, switch to global web server root.
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
try_files \$uri @well-known-acme-challenge;
}
# Return the ACME challenge present in the global server public root.
# If not present, redirect request to a specified domain.
location @well-known-acme-challenge {
root /srv/www/sites/acme/public;
default_type "text/plain";
try_files \$uri @redirect-acme-challenge;
}
# Redirect the ACME challenge to a different host. If a redirect loop is
# detected, return 404.
location @redirect-acme-challenge {
if (\$arg_redirect) {
return 404;
}
return 307 \$scheme://${ACME_DOMAIN}\$request_uri?redirect=yes;
}
# Return 404 if ACME challenge well known path is accessed directly.
location = /.well-known/acme-challenge/ {
return 404;
}
EOF
require="__package/nginx" __directory "${NGINX_ETC}/sites-enabled" --state present
require="__directory${NGINX_ETC}/sites-enabled" __file "${NGINX_ETC}/nginx.conf" \
--mode 644 \
--source - << EOF
# This file is managed remotely, all changes will be lost
worker_processes 1;
# This default error log path is compiled-in to make sure configuration parsing
# errors are logged somewhere, especially during unattended boot when stderr
# isn't normally logged anywhere. This path will be touched on every nginx
# start regardless of error log location configured here. See
# https://trac.nginx.org/nginx/ticket/147 for more info.
#
#error_log /var/log/nginx/error.log;
#
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
server_tokens off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
types_hash_max_size 2048;
gzip on;
gzip_disable "msie6";
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types
application/atom+xml
application/javascript
application/json
application/ld+json
application/manifest+json
application/rss+xml
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/bmp
image/svg+xml
image/x-icon
text/cache-manifest
text/css
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
#add_header X-Clacks-Overhead "GNU Terry Pratchett";
# Virtual Hosts Configs
include ${NGINX_ETC}/sites-enabled/*.conf;
}
EOF
require="__directory${NGINX_ETC}/sites-enabled" __file "${NGINX_ETC}/sites-enabled/welcome.conf" \
--mode 644 \
--source - << EOF
# This file is managed remotely, all changes will be lost
# nginx server configuration for:
# - https://welcome/
server {
listen [::]:80;
server_name welcome;
root /srv/www/sites/welcome/public;
include snippets/acme-challenge.conf;
location / {
return 301 https://\$host\$request_uri;
}
}
EOF
## TODO: this is kinda bad, don't restart every time.
## Otherwise this isn't idempotent.
require="__package/nginx" __service nginx --action onerestart
require="__package/nginx" __start_on_boot nginx
__package "acme-tiny"
# Create acme-tiny user and secure home dir
ACME_TINY_HOME="/var/acme-tiny"
require="__package/acme-tiny" __user acme-tiny --system --home ${ACME_TINY_HOME} --comment "acme-tiny client"
require="__user/acme-tiny" __directory "${ACME_TINY_HOME}" --state present --mode 0750 --owner acme-tiny --group acme-tiny
# Create ACME challenge dirs to be served by nginx
ACME_PUBLIC_DIR="/srv/www/sites/acme/public"
ACME_WELLKNOWN_DIR="${ACME_PUBLIC_DIR}/.well-known"
ACME_CHALLENGE_DIR="${ACME_WELLKNOWN_DIR}/acme-challenge"
__directory "${ACME_PUBLIC_DIR}" \
--parents \
--state present \
--owner acme-tiny --group www \
--mode 2750 # TODO: check whether this does require gid?
require="__directory${ACME_PUBLIC_DIR}" __directory "${ACME_WELLKNOWN_DIR}" \
--state present \
--owner acme-tiny --group www \
--mode 0750
require="__directory${ACME_WELLKNOWN_DIR}" __directory "${ACME_CHALLENGE_DIR}" \
--state present \
--owner acme-tiny --group www \
--mode 0750
__package doas
DOAS_CONF="/usr/local/etc/doas.conf"
require="__package/doas" __file "${DOAS_CONF}" --mode 0640
require="__file${DOAS_CONF}" __line "${DOAS_CONF}" \
--regex 'root as acme-tiny' \
--line 'permit nopass root as acme-tiny'
# Setup CA
REALMS_DIR="/usr/local/etc/pki/realms"
__directory "${REALMS_DIR}" \
--parents \
--state present \
--mode 0755
require="__directory${REALMS_DIR}" __file ${REALMS_DIR}/intermediate.pem \
--mode 0644 \
--source - << EOF
$(curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt)
EOF
require="__directory${REALMS_DIR}" __file ${REALMS_DIR}/root.pem \
--mode 0644 \
--source - << EOF
$(curl -s https://letsencrypt.org/certs/trustid-x3-root.pem.txt)
EOF
require="__directory${REALMS_DIR}" __file ${REALMS_DIR}/chain.pem \
--mode 0644 \
--source - << EOF
$(curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt)
$(curl -s https://letsencrypt.org/certs/trustid-x3-root.pem.txt)
EOF

View file

@ -0,0 +1 @@
acme_domain

View file

@ -0,0 +1,40 @@
#!/bin/sh -e
#
# 2016 Kamila Součková (coding at kamila.is)
#
# 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/>.
#
# TODO it would be cool to print a warning if a generated anchor is unused in pf.conf
ANCHORS_DIR=/etc/pf.d
proto="$(cat "${__object}/parameter/proto")"
from="$(cat "${__object}/parameter/from")"
to="$(cat "${__object}/parameter/to")"
state="$(cat "${__object}/parameter/state")"
# This breaks utterly with IPv6
from="$(echo ${from} | sed 's/:/ port /')"
to="$(echo ${to} | sed 's/:/ port /')"
anchor_name="$(echo ${__object_id} | cut -d/ -f1)"
rule="rdr pass log proto ${proto} from any to ${from} -> ${to}"
__directory "${ANCHORS_DIR}" --parents
require="__directory/${ANCHORS_DIR}" \
__line __pf_rdr/${__object_id} --state ${state} --line "${rule}" --file ${ANCHORS_DIR}/${anchor_name}

View file

@ -0,0 +1 @@
tcp

View file

@ -0,0 +1 @@
present

View file

@ -0,0 +1,2 @@
proto
state

View file

@ -0,0 +1,2 @@
from
to

View file

@ -0,0 +1,7 @@
servicename=$__object_id
user="$(cat "$__object/parameter/user")"
server_ip="$(cat "$__object/parameter/server-ip")"
cat<<EOF
test -d /etc/tinydns/$servicename || tinydns-conf $user $user /etc/tinydns/$servicename $server_ip
EOF

View file

@ -0,0 +1,8 @@
service_name=$__object_id
user="$(cat "$__object/parameter/user")"
__package djbdns
__directory /etc/tinydns --mode 755
__user $user --system --shell /bin/false
require="__daemontools" __link /service/tinydns-$service_name --type symbolic --source /etc/tinydns/$service_name

View file

@ -0,0 +1,2 @@
user
server-ip

View file

@ -0,0 +1,9 @@
servicename=$(echo $__object_id | cut -d/ -f1)
name=$(echo $__object_id | cut -d/ -f2-)
ip="$(cat "$__object/parameter/ip")"
cat<<EOF
cd /etc/tinydns/$servicename/root
grep '=$name:$ip' data 2>/dev/null || ./add-host $name $ip
make
EOF

View file

View file

@ -0,0 +1 @@
ip

View file

@ -0,0 +1,13 @@
set -x
servicename=$(echo $__object_id | cut -d/ -f1)
name=$(echo $__object_id | cut -d/ -f2-)
ip="$(cat "$__object/parameter/ip")"
cat<<EOF
cd /etc/tinydns/$servicename/root
grep .$host:$ip data 2>/dev/null || ./add-ns $name $ip
make
EOF
set +x

View file

@ -0,0 +1 @@
ip