initial bits for boxctl
This commit is contained in:
commit
8ba54c36eb
15
LICENSE
Normal file
15
LICENSE
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Aaron Bieber <aaron@bolddaemon.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
27
Makefile
Normal file
27
Makefile
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# $OpenBSD$
|
||||||
|
|
||||||
|
PREFIX ?= /usr/local
|
||||||
|
SCRIPT = boxctl.sh
|
||||||
|
MAN = man/boxctl.8
|
||||||
|
MANDIR ?= ${PREFIX}/man/man
|
||||||
|
BINDIR ?= ${PREFIX}/bin
|
||||||
|
|
||||||
|
README.md: man/boxctl.8
|
||||||
|
mandoc -T lint man/boxctl.8
|
||||||
|
mandoc -T markdown man/boxctl.8 >$@
|
||||||
|
|
||||||
|
sign:
|
||||||
|
@sha256 boxctl.sh > SHA256
|
||||||
|
@signify -S -s ~/signify/boxctl.sec -m SHA256 -x SHA256.sig
|
||||||
|
@cat SHA256 >> SHA256.sig
|
||||||
|
|
||||||
|
verify:
|
||||||
|
@signify -C -p /etc/signify/boxctl.pub -x SHA256.sig boxctl.sh
|
||||||
|
|
||||||
|
realinstall:
|
||||||
|
${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
|
||||||
|
${.CURDIR}/${SCRIPT} ${DESTDIR}${BINDIR}/boxctl
|
||||||
|
|
||||||
|
.PHONY: verify sign
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
117
README.md
Normal file
117
README.md
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
BOXCTL(8) - System Manager's Manual
|
||||||
|
|
||||||
|
# NAME
|
||||||
|
|
||||||
|
**boxctl** - tool to manage remote
|
||||||
|
OpenBSD
|
||||||
|
machines
|
||||||
|
|
||||||
|
# SYNOPSIS
|
||||||
|
|
||||||
|
**boxctl**
|
||||||
|
\[**-mnv**]
|
||||||
|
\[**-h** *host*]
|
||||||
|
\[**-u** *user*]
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
|
||||||
|
**boxctl**
|
||||||
|
is a
|
||||||
|
ksh(1)
|
||||||
|
script designed to help manage
|
||||||
|
OpenBSD
|
||||||
|
machines.
|
||||||
|
It uses only tools contained in
|
||||||
|
OpenBSD
|
||||||
|
base.
|
||||||
|
|
||||||
|
The options are as follows:
|
||||||
|
|
||||||
|
**-h** *host*
|
||||||
|
|
||||||
|
> Remote host to be managed.
|
||||||
|
|
||||||
|
**-u** *user*
|
||||||
|
|
||||||
|
> User to connect to
|
||||||
|
> *host*
|
||||||
|
> with.
|
||||||
|
> Defaults to
|
||||||
|
> *root*.
|
||||||
|
|
||||||
|
**-m**
|
||||||
|
|
||||||
|
> Run maintenance tasks.
|
||||||
|
> This includes deleting unused dependencies using
|
||||||
|
> pkg\_delete(1).
|
||||||
|
> And installing / updating firmware using
|
||||||
|
> fw\_update(1).
|
||||||
|
|
||||||
|
**-n**
|
||||||
|
|
||||||
|
> Dry run.
|
||||||
|
> This will only print the commands that will be run.
|
||||||
|
|
||||||
|
**-v**
|
||||||
|
|
||||||
|
> Increase verbosity.
|
||||||
|
> More v's can be specified to increase information output.
|
||||||
|
> The number of v's are passed to tools used by
|
||||||
|
> **boxctl**.
|
||||||
|
|
||||||
|
# FILES
|
||||||
|
|
||||||
|
*$CWD/files*
|
||||||
|
|
||||||
|
> Is a ":" delimited index of source file, owner, group, mode and destination.
|
||||||
|
> Each source will be copied to the specified destination, then chown/chmod will
|
||||||
|
> be run with the values specified.
|
||||||
|
> If this file does not exist, no files are copied.
|
||||||
|
|
||||||
|
*$CWD/services*
|
||||||
|
|
||||||
|
> An optional file that contains a list of services to enable on the remote
|
||||||
|
> host.
|
||||||
|
> If a service is already enabled, it will be restarted each run of
|
||||||
|
> **boxctl**.
|
||||||
|
|
||||||
|
*$CWD/packages*
|
||||||
|
|
||||||
|
> When this file exists,
|
||||||
|
> **boxctl**
|
||||||
|
> will install the packages contained therewithin on the remote host.
|
||||||
|
> A list is cached on the remote host under /etc/packages.
|
||||||
|
> This list (if it exists) will be compared using
|
||||||
|
> diff(1)
|
||||||
|
> and only missing packages will be installed.
|
||||||
|
> Package names should be listed by their fuzzy names.
|
||||||
|
> See
|
||||||
|
> pkg\_info(1)
|
||||||
|
> for more information on fuzzy names.
|
||||||
|
|
||||||
|
# SEE ALSO
|
||||||
|
|
||||||
|
chmod(1),
|
||||||
|
diff(1),
|
||||||
|
fw\_update(1),
|
||||||
|
pkg\_add(1),
|
||||||
|
pkg\_delete(1),
|
||||||
|
pkg\_info(1),
|
||||||
|
scp(1),
|
||||||
|
ssh(1),
|
||||||
|
chown(8),
|
||||||
|
rcctl(8)
|
||||||
|
|
||||||
|
# HISTORY
|
||||||
|
|
||||||
|
The first version of
|
||||||
|
**boxctl**
|
||||||
|
was released in September of 2019.
|
||||||
|
|
||||||
|
# AUTHORS
|
||||||
|
|
||||||
|
**boxctl**
|
||||||
|
was written by
|
||||||
|
Aaron Bieber <[aaron@bolddaemon.com](mailto:aaron@bolddaemon.com)>.
|
||||||
|
|
||||||
|
OpenBSD 6.6 - September 23, 2019
|
198
boxctl.sh
Executable file
198
boxctl.sh
Executable file
@ -0,0 +1,198 @@
|
|||||||
|
#!/bin/ksh
|
||||||
|
|
||||||
|
# /*
|
||||||
|
# * Copyright (c) 2019 Aaron Bieber <aaron@bolddaemon.com>
|
||||||
|
# *
|
||||||
|
# * Permission to use, copy, modify, and distribute this software for any
|
||||||
|
# * purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# * copyright notice and this permission notice appear in all copies.
|
||||||
|
# *
|
||||||
|
# * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
# */
|
||||||
|
|
||||||
|
set -au
|
||||||
|
|
||||||
|
SERVER=""
|
||||||
|
RUN_USER="root"
|
||||||
|
VERBOSITY=0
|
||||||
|
DRY=0
|
||||||
|
MAINTENANCE=0
|
||||||
|
SSH_CTL_PATH="/tmp/boxctl-%r@%h:%p"
|
||||||
|
SSH_OPTS="-o ControlMaster=auto -o ControlPersist=60s -o ControlPath=${SSH_CTL_PATH}"
|
||||||
|
SERVICE_START_RESTART=$(cat <<EOF
|
||||||
|
/usr/sbin/rcctl enable %s; \
|
||||||
|
/usr/sbin/rcctl check %s && \
|
||||||
|
/usr/sbin/rcctl restart %s || \
|
||||||
|
/usr/sbin/rcctl start %s
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
PKG_DIFF_INSTALL=$(cat <<EOF
|
||||||
|
if [ -f /etc/packages ]; then
|
||||||
|
# Already ran a full install, so only install new packages
|
||||||
|
diff -u /etc/packages /etc/packages.tmp | grep -e ^+[a-z0-9] | \
|
||||||
|
sed 's/^+//' > /tmp/new_packages
|
||||||
|
/usr/sbin/pkg_add %s -z -l /tmp/new_packages
|
||||||
|
else
|
||||||
|
/usr/sbin/pkg_add %s -z -l /etc/packages.tmp
|
||||||
|
fi
|
||||||
|
mv /etc/packages.tmp /etc/packages
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
while getopts "h:u:nv" arg; do
|
||||||
|
case $arg in
|
||||||
|
h)
|
||||||
|
SERVER=$OPTARG
|
||||||
|
;;
|
||||||
|
v)
|
||||||
|
VERBOSITY=$((VERBOSITY+1))
|
||||||
|
;;
|
||||||
|
n)
|
||||||
|
DRY=1
|
||||||
|
;;
|
||||||
|
u)
|
||||||
|
RUN_USER=$OPTARG
|
||||||
|
;;
|
||||||
|
m)
|
||||||
|
MAINTENANCE=1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
msg() {
|
||||||
|
local _level _msg
|
||||||
|
_level=$1
|
||||||
|
_msg=$2
|
||||||
|
if [ $VERBOSITY -ge $_level ] && [ $DRY == 0 ]; then
|
||||||
|
echo "==> $_msg"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
expand_v() {
|
||||||
|
V=""
|
||||||
|
if [ $VERBOSITY -gt 0 ]; then
|
||||||
|
for v in $(jot $VERBOSITY); do
|
||||||
|
V="${V}v"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [ "${V}" == "" ]; then
|
||||||
|
echo "${V}"
|
||||||
|
else
|
||||||
|
echo "-${V}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_verbose() {
|
||||||
|
local _opt=""
|
||||||
|
if [ $VERBOSITY -ge 4 ]; then
|
||||||
|
_opt="$V"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $DRY == 1 ]; then
|
||||||
|
echo ssh ${SSH_OPTS} $_opt "$1" "${2}"
|
||||||
|
else
|
||||||
|
ssh ${SSH_OPTS} $_opt "$1" "${2}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_quiet() {
|
||||||
|
if [ $DRY == 1 ]; then
|
||||||
|
echo "ssh ${SSH_OPTS} '$1' '${2}' >/dev/null"
|
||||||
|
else
|
||||||
|
ssh ${SSH_OPTS} "$1" "${2}" >/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
scp_verbose() {
|
||||||
|
local _opt=""
|
||||||
|
if [ $VERBOSITY -ge 4 ]; then
|
||||||
|
_opt="$V"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $DRY == 1 ]; then
|
||||||
|
echo scp ${SSH_OPTS} $_opt "$1" "${2}"
|
||||||
|
else
|
||||||
|
scp ${SSH_OPTS} $_opt "$1" "${2}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
scp_quiet() {
|
||||||
|
if [ $DRY == 1 ]; then
|
||||||
|
echo "scp ${SSH_OPTS} '$1' '${2}' >/dev/null"
|
||||||
|
else
|
||||||
|
scp ${SSH_OPTS} "$1" "${2}" >/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_scp() {
|
||||||
|
local _src _dest
|
||||||
|
_src=$1
|
||||||
|
_dest=$2
|
||||||
|
|
||||||
|
if [ $VERBOSITY -gt 2 ]; then
|
||||||
|
scp_verbose "$_src" "$_dest"
|
||||||
|
else
|
||||||
|
scp_quiet "$_src" "$_dest"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_ssh() {
|
||||||
|
local _server _cmd
|
||||||
|
_server=$1
|
||||||
|
_cmd=$2
|
||||||
|
|
||||||
|
if [ $VERBOSITY -gt 2 ]; then
|
||||||
|
ssh_verbose "$_server" "$_cmd"
|
||||||
|
else
|
||||||
|
ssh_quiet "$_server" "$_cmd"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
V=$(expand_v)
|
||||||
|
|
||||||
|
if [ -f ./files ]; then
|
||||||
|
msg 0 "Installing files"
|
||||||
|
for file in $(cat files); do
|
||||||
|
local _src _dest _mode _owner _group
|
||||||
|
read _src _owner _group _mode _dest <<EOF
|
||||||
|
$(echo $file | sed 's/:/ /g')
|
||||||
|
EOF
|
||||||
|
msg 1 "\t${_src} -> ${_dest}"
|
||||||
|
msg 2 "\t\tchown ${_owner}:${_group} $_dest"
|
||||||
|
msg 2 "\t\tchmod ${_mode} $_dest"
|
||||||
|
|
||||||
|
_scp $_src "${RUN_USER}@${SERVER}:$_dest"
|
||||||
|
_ssh ${RUN_USER}@${SERVER} "/sbin/chown ${_owner}:${_group} $_dest; \
|
||||||
|
/bin/chmod ${_mode} $_dest"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f ./services ]; then
|
||||||
|
msg 0 "Enabling services"
|
||||||
|
for service in $(cat services); do
|
||||||
|
msg 1 "\tenabling/restarting ${service}"
|
||||||
|
cmd="$(printf "$SERVICE_START_RESTART" \
|
||||||
|
$service $service $service $service)"
|
||||||
|
_ssh ${RUN_USER}@${SERVER} "${cmd}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f ./packages ]; then
|
||||||
|
msg 0 "Installing $(wc -l packages | awk '{print $1 " " $2}') on ${SERVER}"
|
||||||
|
cmd=$(printf "${PKG_DIFF_INSTALL}" $V $V)
|
||||||
|
_scp packages "${RUN_USER}@${SERVER}:/etc/packages.tmp"
|
||||||
|
_ssh ${RUN_USER}@${SERVER} "${cmd}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $MAINTENANCE == 1 ]; then
|
||||||
|
msg 0 "Cleaning up unused packages"
|
||||||
|
_ssh ${RUN_USER}@${SERVER} "/usr/sbin/pkg_delete -a"
|
||||||
|
fi
|
110
man/boxctl.8
Normal file
110
man/boxctl.8
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
.\" $OpenBSD$
|
||||||
|
.\"
|
||||||
|
.\" Copyright (c) 2019 Aaron Bieber <aaron@bolddaemon.com>
|
||||||
|
.\"
|
||||||
|
.\" Permission to use, copy, modify, and distribute this software for any
|
||||||
|
.\" purpose with or without fee is hereby granted, provided that the above
|
||||||
|
.\" copyright notice and this permission notice appear in all copies.
|
||||||
|
.\"
|
||||||
|
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
.\"
|
||||||
|
.Dd $Mdocdate: September 23 2019 $
|
||||||
|
.Dt BOXCTL 8
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm boxctl
|
||||||
|
.Nd tool to manage remote
|
||||||
|
.Ox
|
||||||
|
machines
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm boxctl
|
||||||
|
.Op Fl mnv
|
||||||
|
.Op Fl h Ar host
|
||||||
|
.Op Fl u Ar user
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
is a
|
||||||
|
.Xr ksh 1
|
||||||
|
script designed to help manage
|
||||||
|
.Ox
|
||||||
|
machines.
|
||||||
|
It uses only tools contained in
|
||||||
|
.Ox
|
||||||
|
base.
|
||||||
|
.Pp
|
||||||
|
The options are as follows:
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl h Ar host
|
||||||
|
Remote host to be managed.
|
||||||
|
.It Fl u Ar user
|
||||||
|
User to connect to
|
||||||
|
.Pa host
|
||||||
|
with.
|
||||||
|
Defaults to
|
||||||
|
.Pa root .
|
||||||
|
.It Fl m
|
||||||
|
Run maintenance tasks.
|
||||||
|
This includes deleting unused dependencies using
|
||||||
|
.Xr pkg_delete 1 .
|
||||||
|
And installing / updating firmware using
|
||||||
|
.Xr fw_update 1 .
|
||||||
|
.It Fl n
|
||||||
|
Dry run.
|
||||||
|
This will only print the commands that will be run.
|
||||||
|
.It Fl v
|
||||||
|
Increase verbosity.
|
||||||
|
More v's can be specified to increase information output.
|
||||||
|
The number of v's are passed to tools used by
|
||||||
|
.Nm .
|
||||||
|
.El
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width $CWD/packages
|
||||||
|
.It Pa $CWD/files
|
||||||
|
Is a ":" delimited index of source file, owner, group, mode and destination.
|
||||||
|
Each source will be copied to the specified destination, then chown/chmod will
|
||||||
|
be run with the values specified.
|
||||||
|
If this file does not exist, no files are copied.
|
||||||
|
.It Pa $CWD/services
|
||||||
|
An optional file that contains a list of services to enable on the remote
|
||||||
|
host.
|
||||||
|
If a service is already enabled, it will be restarted each run of
|
||||||
|
.Nm .
|
||||||
|
.It Pa $CWD/packages
|
||||||
|
When this file exists,
|
||||||
|
.Nm
|
||||||
|
will install the packages contained therewithin on the remote host.
|
||||||
|
A list is cached on the remote host under /etc/packages.
|
||||||
|
This list (if it exists) will be compared using
|
||||||
|
.Xr diff 1
|
||||||
|
and only missing packages will be installed.
|
||||||
|
Package names should be listed by their fuzzy names.
|
||||||
|
See
|
||||||
|
.Xr pkg_info 1
|
||||||
|
for more information on fuzzy names.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr chmod 1 ,
|
||||||
|
.Xr diff 1 ,
|
||||||
|
.Xr fw_update 1 ,
|
||||||
|
.Xr pkg_add 1 ,
|
||||||
|
.Xr pkg_delete 1 ,
|
||||||
|
.Xr pkg_info 1 ,
|
||||||
|
.Xr scp 1 ,
|
||||||
|
.Xr ssh 1 ,
|
||||||
|
.Xr chown 8 ,
|
||||||
|
.Xr rcctl 8
|
||||||
|
.Sh HISTORY
|
||||||
|
The first version of
|
||||||
|
.Nm
|
||||||
|
was released in September of 2019.
|
||||||
|
.Sh AUTHORS
|
||||||
|
.An -nosplit
|
||||||
|
.Nm
|
||||||
|
was written by
|
||||||
|
.An Aaron Bieber Aq Mt aaron@bolddaemon.com .
|
Loading…
Reference in New Issue
Block a user