Use persistent Docker images for development (#113)
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This PR adds support for building Docker images during development which can be re-used multiple times. This allows us to easily run `docker-compose up` and `docker-compose down` many times without having to reinstall packages from scratch every time. Reviewed-on: #113
This commit is contained in:
parent
392ec153d0
commit
5332259731
18
.drone.yml
18
.drone.yml
|
@ -5,34 +5,34 @@ name: default
|
|||
steps:
|
||||
# use the step name to mock out the gethostname() call in our tests
|
||||
- name: phosphoric-acid
|
||||
image: python:3.9-bullseye
|
||||
image: python:3.9-slim-bullseye
|
||||
# unfortunately we have to do everything in one step because there's no
|
||||
# way to share system packages between steps
|
||||
commands:
|
||||
# install dependencies
|
||||
- apt update && apt install -y libkrb5-dev libpq-dev python3-dev libaugeas0
|
||||
- apt update
|
||||
- apt install --no-install-recommends -y gcc libkrb5-dev libaugeas0
|
||||
- python3 -m venv venv
|
||||
- . venv/bin/activate
|
||||
- pip install -r dev-requirements.txt
|
||||
- pip install -r requirements.txt
|
||||
- venv/bin/pip install -r dev-requirements.txt -r requirements.txt
|
||||
|
||||
# lint
|
||||
- flake8
|
||||
|
||||
# unit + integration tests
|
||||
- .drone/phosphoric-acid-setup.sh
|
||||
- bash -c ". .drone/phosphoric-acid-setup.sh && IMAGE__setup && CONTAINER__setup"
|
||||
- pytest -v
|
||||
|
||||
services:
|
||||
- name: auth1
|
||||
image: debian:bullseye
|
||||
image: debian:bullseye-slim
|
||||
commands:
|
||||
- .drone/auth1-setup.sh
|
||||
- bash -c ". .drone/auth1-setup.sh && IMAGE__setup && CONTAINER__setup"
|
||||
- sleep infinity
|
||||
- name: coffee
|
||||
image: debian:bullseye
|
||||
image: debian:bullseye-slim
|
||||
commands:
|
||||
- .drone/coffee-setup.sh
|
||||
- bash -c ". .drone/coffee-setup.sh && IMAGE__setup && CONTAINER__setup"
|
||||
- sleep infinity
|
||||
|
||||
trigger:
|
||||
|
|
|
@ -4,102 +4,128 @@ set -ex
|
|||
|
||||
. .drone/common.sh
|
||||
|
||||
# set FQDN in /etc/hosts
|
||||
add_fqdn_to_hosts $(get_ip_addr $(hostname)) auth1
|
||||
|
||||
if [ -n "$CI" ]; then
|
||||
# I'm not sure why, but we also need to remove the hosts entry for the
|
||||
# container's real hostname, otherwise slapd only looks for the principal
|
||||
# ldap/<container hostname> (this is with the sasl-host option)
|
||||
sed -E "/\\b$(hostname)\\b/d" /etc/hosts > /tmp/hosts
|
||||
cat /tmp/hosts > /etc/hosts
|
||||
rm /tmp/hosts
|
||||
fi
|
||||
|
||||
apt install -y psmisc
|
||||
|
||||
# If we don't do this then OpenLDAP uses a lot of RAM
|
||||
ulimit -n 1024
|
||||
|
||||
# LDAP
|
||||
apt install -y --no-install-recommends slapd ldap-utils libnss-ldapd sudo-ldap
|
||||
# `service slapd stop` doesn't seem to work
|
||||
killall slapd || true
|
||||
service nslcd stop || true
|
||||
rm -rf /etc/ldap/slapd.d
|
||||
rm /var/lib/ldap/*
|
||||
cp .drone/slapd.conf /etc/ldap/slapd.conf
|
||||
cp .drone/ldap.conf /etc/ldap/ldap.conf
|
||||
cp /usr/share/doc/sudo-ldap/schema.OpenLDAP /etc/ldap/schema/sudo.schema
|
||||
cp .drone/rfc2307bis.schema /etc/ldap/schema/
|
||||
cp .drone/csc.schema /etc/ldap/schema/
|
||||
chown -R openldap:openldap /etc/ldap/schema/ /var/lib/ldap/ /etc/ldap/
|
||||
sleep 0.5 && service slapd start
|
||||
grep -Eq '^map group member uniqueMember$' /etc/nslcd.conf || \
|
||||
echo 'map group member uniqueMember' >> /etc/nslcd.conf
|
||||
sed -E -i 's/^uri .*$/uri ldap:\/\/auth1.csclub.internal/' /etc/nslcd.conf
|
||||
sed -E -i 's/^base .*$/base dc=csclub,dc=internal/' /etc/nslcd.conf
|
||||
cp .drone/nsswitch.conf /etc/nsswitch.conf
|
||||
service nslcd start
|
||||
ldapadd -c -f .drone/data.ldif -Y EXTERNAL -H ldapi:///
|
||||
if [ -z "$CI" ]; then
|
||||
ldapadd -c -f .drone/uwldap_data.ldif -Y EXTERNAL -H ldapi:/// || true
|
||||
# setup ldapvi for convenience
|
||||
apt install -y vim ldapvi
|
||||
echo 'export EDITOR=vim' >> /root/.bashrc
|
||||
echo 'alias ldapvi="ldapvi -Y EXTERNAL -h ldapi:///"' >> /root/.bashrc
|
||||
fi
|
||||
CONTAINER__fix_hosts() {
|
||||
add_fqdn_to_hosts $(get_ip_addr $(hostname)) auth1
|
||||
if [ -n "$CI" ]; then
|
||||
# I'm not sure why, but we also need to remove the hosts entry for the
|
||||
# container's real hostname, otherwise slapd only looks for the principal
|
||||
# ldap/<container hostname> (this is with the sasl-host option)
|
||||
sed -E "/\\b$(hostname)\\b/d" /etc/hosts > /tmp/hosts
|
||||
cat /tmp/hosts > /etc/hosts
|
||||
rm /tmp/hosts
|
||||
fi
|
||||
}
|
||||
|
||||
# KERBEROS
|
||||
apt install -y krb5-admin-server krb5-user libpam-krb5 libsasl2-modules-gssapi-mit sasl2-bin
|
||||
service krb5-admin-server stop || true
|
||||
service krb5-kdc stop || true
|
||||
service saslauthd stop || true
|
||||
cp .drone/krb5.conf /etc/krb5.conf
|
||||
cp .drone/kdc.conf /etc/krb5kdc.conf
|
||||
echo '*/admin *' > /etc/krb5kdc/kadm5.acl
|
||||
rm -f /var/lib/krb5kdc/*
|
||||
echo -e 'krb5\nkrb5' | krb5_newrealm
|
||||
service krb5-kdc start
|
||||
service krb5-admin-server start
|
||||
rm -f /etc/krb5.keytab
|
||||
cat <<EOF | kadmin.local
|
||||
IMAGE__setup_ldap() {
|
||||
# In the "slim" Docker images, /usr/share/doc/* is excluded by default
|
||||
echo 'path-include /usr/share/doc/sudo-ldap/schema.OpenLDAP' > /etc/dpkg/dpkg.cfg.d/zz-ceo
|
||||
apt install -y --no-install-recommends slapd ldap-utils libnss-ldapd sudo-ldap
|
||||
# `service slapd stop` doesn't seem to work
|
||||
killall slapd || true
|
||||
service nslcd stop || true
|
||||
rm -rf /etc/ldap/slapd.d
|
||||
rm /var/lib/ldap/*
|
||||
cp .drone/slapd.conf /etc/ldap/slapd.conf
|
||||
cp .drone/ldap.conf /etc/ldap/ldap.conf
|
||||
cp /usr/share/doc/sudo-ldap/schema.OpenLDAP /etc/ldap/schema/sudo.schema
|
||||
cp .drone/rfc2307bis.schema /etc/ldap/schema/
|
||||
cp .drone/csc.schema /etc/ldap/schema/
|
||||
chown -R openldap:openldap /etc/ldap/schema/ /var/lib/ldap/ /etc/ldap/
|
||||
sleep 0.5 && service slapd start
|
||||
ldapadd -c -f .drone/data.ldif -Y EXTERNAL -H ldapi:///
|
||||
if [ -z "$CI" ]; then
|
||||
ldapadd -c -f .drone/uwldap_data.ldif -Y EXTERNAL -H ldapi:/// || true
|
||||
# setup ldapvi for convenience
|
||||
apt install -y --no-install-recommends vim ldapvi
|
||||
grep -q 'export EDITOR' /root/.bashrc || \
|
||||
echo 'export EDITOR=vim' >> /root/.bashrc
|
||||
grep -q 'alias ldapvi' /root/.bashrc || \
|
||||
echo 'alias ldapvi="ldapvi -Y EXTERNAL -h ldapi:///"' >> /root/.bashrc
|
||||
fi
|
||||
}
|
||||
|
||||
IMAGE__setup_krb5() {
|
||||
apt install -y krb5-admin-server krb5-user libpam-krb5 libsasl2-modules-gssapi-mit sasl2-bin
|
||||
service krb5-admin-server stop || true
|
||||
service krb5-kdc stop || true
|
||||
service saslauthd stop || true
|
||||
cp .drone/krb5.conf /etc/krb5.conf
|
||||
cp .drone/kdc.conf /etc/krb5kdc.conf
|
||||
echo '*/admin *' > /etc/krb5kdc/kadm5.acl
|
||||
rm -f /var/lib/krb5kdc/*
|
||||
echo -e 'krb5\nkrb5' | krb5_newrealm
|
||||
service krb5-kdc start
|
||||
service krb5-admin-server start
|
||||
rm -f /etc/krb5.keytab
|
||||
cat <<EOF | kadmin.local
|
||||
addpol -minlength 4 default
|
||||
addprinc -pw krb5 sysadmin/admin
|
||||
addprinc -pw krb5 ctdalek
|
||||
addprinc -pw krb5 exec1
|
||||
addprinc -pw krb5 regular1
|
||||
addprinc -pw krb5 office1
|
||||
addprinc -randkey ceod/admin
|
||||
addprinc -randkey host/auth1.csclub.internal
|
||||
addprinc -randkey ldap/auth1.csclub.internal
|
||||
ktadd host/auth1.csclub.internal
|
||||
ktadd ldap/auth1.csclub.internal
|
||||
EOF
|
||||
groupadd keytab || true
|
||||
chgrp keytab /etc/krb5.keytab
|
||||
chmod 640 /etc/krb5.keytab
|
||||
usermod -a -G keytab openldap
|
||||
usermod -a -G sasl openldap
|
||||
cat <<EOF > /usr/lib/sasl2/slapd.conf
|
||||
# Add all of the people defined in data.ldif
|
||||
for princ in ctdalek exec1 regular1 office1; do
|
||||
echo "addprinc -pw krb5 $princ" | kadmin.local
|
||||
done
|
||||
groupadd keytab || true
|
||||
chgrp keytab /etc/krb5.keytab
|
||||
chmod 640 /etc/krb5.keytab
|
||||
usermod -a -G keytab openldap
|
||||
usermod -a -G sasl openldap
|
||||
cat <<EOF > /usr/lib/sasl2/slapd.conf
|
||||
mech_list: plain login gssapi external
|
||||
pwcheck_method: saslauthd
|
||||
EOF
|
||||
sed -E -i 's/^START=.*$/START=yes/' /etc/default/saslauthd
|
||||
sed -E -i 's/^MECHANISMS=.*$/MECHANISMS="kerberos5"/' /etc/default/saslauthd
|
||||
service saslauthd start
|
||||
while true; do
|
||||
killall slapd
|
||||
sleep 1
|
||||
if service slapd start; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
sed -E -i 's/^START=.*$/START=yes/' /etc/default/saslauthd
|
||||
sed -E -i 's/^MECHANISMS=.*$/MECHANISMS="kerberos5"/' /etc/default/saslauthd
|
||||
}
|
||||
|
||||
# sync with phosphoric-acid
|
||||
nc -l 0.0.0.0 9000 &
|
||||
if [ -z "$CI" ]; then
|
||||
# sync with coffee
|
||||
nc -l 0.0.0.0 9001 &
|
||||
# sync with mail
|
||||
nc -l 0.0.0.0 9002 &
|
||||
fi
|
||||
IMAGE__setup() {
|
||||
# slapd needs /etc/hosts to be setup properly
|
||||
CONTAINER__fix_resolv_conf
|
||||
CONTAINER__fix_hosts
|
||||
|
||||
apt update
|
||||
# for the 'killall' command
|
||||
apt install -y psmisc
|
||||
|
||||
IMAGE__setup_ldap
|
||||
IMAGE__setup_krb5
|
||||
IMAGE__common_setup
|
||||
|
||||
service slapd stop || true
|
||||
killall slapd || true
|
||||
service krb5-admin-server stop || true
|
||||
service krb5-kdc stop || true
|
||||
service saslauthd stop || true
|
||||
}
|
||||
|
||||
CONTAINER__setup() {
|
||||
CONTAINER__fix_resolv_conf
|
||||
CONTAINER__fix_hosts
|
||||
|
||||
local started_slapd=false
|
||||
for i in {1..5}; do
|
||||
if service slapd start; then
|
||||
started_slapd=true
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [ $started_slapd != "true" ]; then
|
||||
echo "Failed to start slapd" >&2
|
||||
return 1
|
||||
fi
|
||||
service krb5-admin-server start
|
||||
service krb5-kdc start
|
||||
service saslauthd start
|
||||
service nslcd start
|
||||
# Let other containers know that we're ready
|
||||
nc -l -k 0.0.0.0 9000 &
|
||||
}
|
||||
|
|
|
@ -4,25 +4,28 @@ set -ex
|
|||
|
||||
. .drone/common.sh
|
||||
|
||||
# set FQDN in /etc/hosts
|
||||
add_fqdn_to_hosts $(get_ip_addr $(hostname)) coffee
|
||||
add_fqdn_to_hosts $(get_ip_addr auth1) auth1
|
||||
CONTAINER__fix_hosts() {
|
||||
add_fqdn_to_hosts $(get_ip_addr $(hostname)) coffee
|
||||
add_fqdn_to_hosts $(get_ip_addr auth1) auth1
|
||||
}
|
||||
|
||||
apt install --no-install-recommends -y default-mysql-server postgresql
|
||||
IMAGE__setup() {
|
||||
IMAGE__ceod_setup
|
||||
apt install --no-install-recommends -y default-mysql-server postgresql
|
||||
|
||||
# MYSQL
|
||||
service mariadb stop
|
||||
sed -E -i 's/^(bind-address[[:space:]]+= 127\.0\.0\.1)$/#\1/' /etc/mysql/mariadb.conf.d/50-server.cnf
|
||||
service mariadb start
|
||||
cat <<EOF | mysql
|
||||
# MYSQL
|
||||
service mariadb stop
|
||||
sed -E -i 's/^(bind-address[[:space:]]+= 127\.0\.0\.1)$/#\1/' /etc/mysql/mariadb.conf.d/50-server.cnf
|
||||
service mariadb start
|
||||
cat <<EOF | mysql
|
||||
CREATE USER IF NOT EXISTS 'mysql' IDENTIFIED BY 'mysql';
|
||||
GRANT ALL PRIVILEGES ON *.* TO 'mysql' WITH GRANT OPTION;
|
||||
EOF
|
||||
|
||||
# POSTGRESQL
|
||||
service postgresql stop
|
||||
POSTGRES_DIR=/etc/postgresql/*/main
|
||||
cat <<EOF > $POSTGRES_DIR/pg_hba.conf
|
||||
# POSTGRESQL
|
||||
service postgresql stop
|
||||
local POSTGRES_DIR=/etc/postgresql/*/main
|
||||
cat <<EOF > $POSTGRES_DIR/pg_hba.conf
|
||||
# TYPE DATABASE USER ADDRESS METHOD
|
||||
local all postgres peer
|
||||
host all postgres localhost md5
|
||||
|
@ -36,19 +39,29 @@ local sameuser all peer
|
|||
host sameuser all 0.0.0.0/0 md5
|
||||
host sameuser all ::/0 md5
|
||||
EOF
|
||||
grep -Eq "^listen_addresses = '*'$" $POSTGRES_DIR/postgresql.conf || \
|
||||
echo "listen_addresses = '*'" >> $POSTGRES_DIR/postgresql.conf
|
||||
service postgresql start
|
||||
su -c "
|
||||
cat <<EOF | psql
|
||||
grep -Eq "^listen_addresses = '*'$" $POSTGRES_DIR/postgresql.conf || \
|
||||
echo "listen_addresses = '*'" >> $POSTGRES_DIR/postgresql.conf
|
||||
service postgresql start
|
||||
su -c "
|
||||
cat <<EOF | psql
|
||||
ALTER USER postgres WITH PASSWORD 'postgres';
|
||||
REVOKE ALL ON SCHEMA public FROM public;
|
||||
GRANT ALL ON SCHEMA public TO postgres;
|
||||
EOF" postgres
|
||||
|
||||
if [ -z "$CI" ]; then
|
||||
auth_setup coffee
|
||||
fi
|
||||
service mariadb stop || true
|
||||
service postgresql stop || true
|
||||
}
|
||||
|
||||
# sync with phosphoric-acid
|
||||
nc -l 0.0.0.0 9000 &
|
||||
CONTAINER__setup() {
|
||||
CONTAINER__fix_resolv_conf
|
||||
CONTAINER__fix_hosts
|
||||
CONTAINER__ceod_setup
|
||||
if [ -z "$CI" ]; then
|
||||
CONTAINER__auth_setup coffee
|
||||
fi
|
||||
service mariadb start
|
||||
service postgresql start
|
||||
# sync with phosphoric-acid
|
||||
nc -l -k 0.0.0.0 9000 &
|
||||
}
|
||||
|
|
177
.drone/common.sh
177
.drone/common.sh
|
@ -1,77 +1,10 @@
|
|||
# TODO: fix Drone
|
||||
chmod 1777 /tmp
|
||||
|
||||
# don't resolve container names to *real* CSC machines
|
||||
sed -E 's/([[:alnum:]-]+\.)*uwaterloo\.ca//g' /etc/resolv.conf > /tmp/resolv.conf
|
||||
# remove empty 'search' lines, if we created them
|
||||
sed -E -i '/^search[[:space:]]*$/d' /tmp/resolv.conf
|
||||
# also remove the 'rotate' option, since this can cause the Docker DNS server
|
||||
# to be circumvented
|
||||
sed -E -i '/^options.*\brotate/d' /tmp/resolv.conf
|
||||
cp /tmp/resolv.conf /etc/resolv.conf
|
||||
rm /tmp/resolv.conf
|
||||
|
||||
# normally systemd creates /run/ceod for us
|
||||
mkdir -p /run/ceod
|
||||
|
||||
# mock out systemctl
|
||||
ln -sf /bin/true /usr/local/bin/systemctl
|
||||
# mock out acme.sh
|
||||
mkdir -p /root/.acme.sh
|
||||
ln -sf /bin/true /root/.acme.sh/acme.sh
|
||||
# mock out kubectl
|
||||
cp .drone/mock_kubectl /usr/local/bin/kubectl
|
||||
chmod +x /usr/local/bin/kubectl
|
||||
# add k8s authority certificate
|
||||
mkdir -p /etc/csc
|
||||
cp .drone/k8s-authority.crt /etc/csc/k8s-authority.crt
|
||||
# openssl is actually already present in the python Docker image,
|
||||
# so we don't need to mock it out
|
||||
|
||||
# netcat is used for synchronization between the containers
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt update
|
||||
apt install -y netcat-openbsd
|
||||
if [ "$(hostname)" != auth1 ]; then
|
||||
# ceod uses Augeas, which is not installed by default in the Python
|
||||
# Docker container
|
||||
apt install -y libaugeas0
|
||||
fi
|
||||
|
||||
get_ip_addr() {
|
||||
getent hosts $1 | cut -d' ' -f1
|
||||
}
|
||||
|
||||
add_fqdn_to_hosts() {
|
||||
ip_addr=$1
|
||||
hostname=$2
|
||||
sed -E "/${ip_addr}.*\\b${hostname}\\b/d" /etc/hosts > /tmp/hosts
|
||||
cp /tmp/hosts /etc/hosts
|
||||
rm /tmp/hosts
|
||||
echo "$ip_addr $hostname.csclub.internal $hostname" >> /etc/hosts
|
||||
}
|
||||
|
||||
sync_with() {
|
||||
host=$1
|
||||
port=9000
|
||||
if [ $# -eq 2 ]; then
|
||||
port=$2
|
||||
fi
|
||||
synced=false
|
||||
# give it 20 minutes (can be slow if you're using e.g. NFS or Ceph)
|
||||
for i in {1..240}; do
|
||||
if nc -vz $host $port ; then
|
||||
synced=true
|
||||
break
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
test $synced = true
|
||||
}
|
||||
|
||||
auth_setup() {
|
||||
hostname=$1
|
||||
# The IMAGE__ functions should be called when building the image.
|
||||
# The CONTAINER__ functions should be called when running an instance of the
|
||||
# image in a container.
|
||||
|
||||
IMAGE__auth_setup() {
|
||||
# LDAP
|
||||
apt install -y --no-install-recommends libnss-ldapd
|
||||
service nslcd stop || true
|
||||
|
@ -86,28 +19,98 @@ auth_setup() {
|
|||
# KERBEROS
|
||||
apt install -y krb5-user libpam-krb5 libsasl2-modules-gssapi-mit
|
||||
cp .drone/krb5.conf /etc/krb5.conf
|
||||
}
|
||||
|
||||
if [ $hostname = phosphoric-acid ]; then
|
||||
sync_port=9000
|
||||
elif [ $hostname = coffee ]; then
|
||||
sync_port=9001
|
||||
else
|
||||
sync_port=9002
|
||||
fi
|
||||
sync_with auth1 $sync_port
|
||||
IMAGE__common_setup() {
|
||||
apt update
|
||||
# netcat is used for synchronization between the containers
|
||||
apt install -y netcat-openbsd
|
||||
IMAGE__auth_setup
|
||||
}
|
||||
|
||||
IMAGE__ceod_setup() {
|
||||
IMAGE__common_setup
|
||||
# ceod uses Augeas, which is not installed by default in the Python
|
||||
# Docker container
|
||||
apt install -y libaugeas0
|
||||
}
|
||||
|
||||
CONTAINER__fix_resolv_conf() {
|
||||
# don't resolve container names to *real* CSC machines
|
||||
sed -E 's/([[:alnum:]-]+\.)*uwaterloo\.ca//g' /etc/resolv.conf > /tmp/resolv.conf
|
||||
# remove empty 'search' lines, if we created them
|
||||
sed -E -i '/^search[[:space:]]*$/d' /tmp/resolv.conf
|
||||
# also remove the 'rotate' option, since this can cause the Docker DNS server
|
||||
# to be circumvented
|
||||
sed -E -i '/^options.*\brotate/d' /tmp/resolv.conf
|
||||
# we can't replace /etc/resolv.conf using 'mv' because it's mounted into the container
|
||||
cp /tmp/resolv.conf /etc/resolv.conf
|
||||
rm /tmp/resolv.conf
|
||||
}
|
||||
|
||||
CONTAINER__auth_setup() {
|
||||
local hostname=$1
|
||||
sync_with auth1
|
||||
service nslcd start
|
||||
rm -f /etc/krb5.keytab
|
||||
cat <<EOF | kadmin -p sysadmin/admin -w krb5
|
||||
addprinc -randkey host/$hostname.csclub.internal
|
||||
ktadd host/$hostname.csclub.internal
|
||||
addprinc -randkey ceod/$hostname.csclub.internal
|
||||
ktadd host/$hostname.csclub.internal
|
||||
ktadd ceod/$hostname.csclub.internal
|
||||
EOF
|
||||
if [ $hostname = phosphoric-acid ]; then
|
||||
cat <<EOF | kadmin -p sysadmin/admin -w krb5
|
||||
addprinc -randkey ceod/admin
|
||||
ktadd ceod/admin
|
||||
EOF
|
||||
fi
|
||||
service nslcd start
|
||||
}
|
||||
|
||||
CONTAINER__ceod_setup() {
|
||||
# normally systemd creates /run/ceod for us
|
||||
mkdir -p /run/ceod
|
||||
|
||||
# mock out systemctl
|
||||
ln -sf /bin/true /usr/local/bin/systemctl
|
||||
# mock out acme.sh
|
||||
mkdir -p /root/.acme.sh
|
||||
ln -sf /bin/true /root/.acme.sh/acme.sh
|
||||
# mock out kubectl
|
||||
cp .drone/mock_kubectl /usr/local/bin/kubectl
|
||||
chmod +x /usr/local/bin/kubectl
|
||||
# add k8s authority certificate
|
||||
mkdir -p /etc/csc
|
||||
cp .drone/k8s-authority.crt /etc/csc/k8s-authority.crt
|
||||
# openssl is actually already present in the python Docker image,
|
||||
# so we don't need to mock it out
|
||||
}
|
||||
|
||||
# Common utility functions
|
||||
|
||||
get_ip_addr() {
|
||||
# There appears to be a bug in newer versions of Podman where using both
|
||||
# --name and --hostname causes a container to have two identical DNS
|
||||
# entries, which causes `getent hosts` to print two lines.
|
||||
# So we use `head -n 1` to select just the first line.
|
||||
getent hosts $1 | head -n 1 | cut -d' ' -f1
|
||||
}
|
||||
|
||||
add_fqdn_to_hosts() {
|
||||
local ip_addr=$1
|
||||
local hostname=$2
|
||||
sed -E "/${ip_addr}.*\\b${hostname}\\b/d" /etc/hosts > /tmp/hosts
|
||||
# we can't replace /etc/hosts using 'mv' because it's mounted into the container
|
||||
cp /tmp/hosts /etc/hosts
|
||||
rm /tmp/hosts
|
||||
echo "$ip_addr $hostname.csclub.internal $hostname" >> /etc/hosts
|
||||
}
|
||||
|
||||
sync_with() {
|
||||
local host=$1
|
||||
local port=9000
|
||||
local synced=false
|
||||
# give it 20 minutes (can be slow if you're using e.g. NFS or Ceph)
|
||||
for i in {1..240}; do
|
||||
if nc -vz $host $port ; then
|
||||
synced=true
|
||||
break
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
test $synced = true
|
||||
}
|
||||
|
|
|
@ -4,20 +4,27 @@ set -ex
|
|||
|
||||
. .drone/common.sh
|
||||
|
||||
# set FQDN in /etc/hosts
|
||||
add_fqdn_to_hosts $(get_ip_addr $(hostname)) mail
|
||||
add_fqdn_to_hosts $(get_ip_addr auth1) auth1
|
||||
CONTAINER__fix_hosts() {
|
||||
add_fqdn_to_hosts $(get_ip_addr $(hostname)) mail
|
||||
add_fqdn_to_hosts $(get_ip_addr auth1) auth1
|
||||
}
|
||||
|
||||
. venv/bin/activate
|
||||
python -m tests.MockMailmanServer &
|
||||
python -m tests.MockSMTPServer &
|
||||
python -m tests.MockCloudStackServer &
|
||||
python -m tests.MockHarborServer &
|
||||
IMAGE__setup() {
|
||||
IMAGE__ceod_setup
|
||||
}
|
||||
|
||||
auth_setup mail
|
||||
|
||||
# for the VHostManager
|
||||
mkdir -p /run/ceod/member-vhosts
|
||||
|
||||
# sync with phosphoric-acid
|
||||
nc -l 0.0.0.0 9000 &
|
||||
CONTAINER__setup() {
|
||||
CONTAINER__fix_resolv_conf
|
||||
CONTAINER__fix_hosts
|
||||
CONTAINER__ceod_setup
|
||||
CONTAINER__auth_setup mail
|
||||
# for the VHostManager
|
||||
mkdir -p /run/ceod/member-vhosts
|
||||
# mock services
|
||||
venv/bin/python -m tests.MockMailmanServer &
|
||||
venv/bin/python -m tests.MockSMTPServer &
|
||||
venv/bin/python -m tests.MockCloudStackServer &
|
||||
venv/bin/python -m tests.MockHarborServer &
|
||||
# sync with phosphoric-acid
|
||||
nc -l -k 0.0.0.0 9000 &
|
||||
}
|
||||
|
|
|
@ -4,29 +4,44 @@ set -ex
|
|||
|
||||
. .drone/common.sh
|
||||
|
||||
# set FQDN in /etc/hosts
|
||||
add_fqdn_to_hosts "$(get_ip_addr $(hostname))" phosphoric-acid
|
||||
add_fqdn_to_hosts "$(get_ip_addr auth1)" auth1
|
||||
add_fqdn_to_hosts "$(get_ip_addr coffee)" coffee
|
||||
# mail container doesn't run in CI
|
||||
if [ -z "$CI" ]; then
|
||||
add_fqdn_to_hosts $(get_ip_addr mail) mail
|
||||
fi
|
||||
CONTAINER__fix_hosts() {
|
||||
add_fqdn_to_hosts "$(get_ip_addr $(hostname))" phosphoric-acid
|
||||
add_fqdn_to_hosts "$(get_ip_addr auth1)" auth1
|
||||
add_fqdn_to_hosts "$(get_ip_addr coffee)" coffee
|
||||
# mail container doesn't run in CI
|
||||
if [ -z "$CI" ]; then
|
||||
add_fqdn_to_hosts $(get_ip_addr mail) mail
|
||||
fi
|
||||
}
|
||||
|
||||
auth_setup phosphoric-acid
|
||||
CONTAINER__setup_userdirs() {
|
||||
# initialize the skel directory
|
||||
shopt -s dotglob
|
||||
mkdir -p /users/skel
|
||||
cp /etc/skel/* /users/skel/
|
||||
|
||||
# initialize the skel directory
|
||||
shopt -s dotglob
|
||||
mkdir -p /users/skel
|
||||
cp /etc/skel/* /users/skel/
|
||||
# create directories for users
|
||||
for user in ctdalek regular1 exec1; do
|
||||
mkdir -p /users/$user
|
||||
chown $user:$user /users/$user
|
||||
done
|
||||
}
|
||||
|
||||
# create directories for users
|
||||
for user in ctdalek regular1 exec1; do
|
||||
mkdir -p /users/$user
|
||||
chown $user:$user /users/$user
|
||||
done
|
||||
IMAGE__setup() {
|
||||
IMAGE__ceod_setup
|
||||
# git is required by the ClubWebHostingService
|
||||
apt install --no-install-recommends -y git
|
||||
}
|
||||
|
||||
sync_with coffee
|
||||
if [ -z "$CI" ]; then
|
||||
sync_with mail
|
||||
fi
|
||||
CONTAINER__setup() {
|
||||
CONTAINER__fix_resolv_conf
|
||||
CONTAINER__fix_hosts
|
||||
CONTAINER__ceod_setup
|
||||
CONTAINER__auth_setup phosphoric-acid
|
||||
CONTAINER__setup_userdirs
|
||||
echo "ktadd ceod/admin" | kadmin -p sysadmin/admin -w krb5
|
||||
sync_with coffee
|
||||
if [ -z "$CI" ]; then
|
||||
sync_with mail
|
||||
fi
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
docker run --rm -v "$PWD:$PWD:z" -w "$PWD" python:3.9-bullseye sh -c './lint-docker.sh'
|
||||
docker run --rm -v "$PWD:$PWD:z" -w "$PWD" python:3.9-bullseye scripts/lint-docker.sh
|
||||
|
||||
exit $?
|
||||
|
|
24
README.md
24
README.md
|
@ -10,17 +10,29 @@ overview of its architecture.
|
|||
The API documentation is available as a plain HTML file in [docs/redoc-static.html](docs/redoc-static.html).
|
||||
|
||||
## Development
|
||||
### Docker
|
||||
### Podman
|
||||
If you are not modifying code related to email or Mailman, then you may use
|
||||
Docker containers instead, which are much easier to work with than the VM.
|
||||
Podman containers instead, which are much easier to work with than the VM.
|
||||
|
||||
First, make sure you create the virtualenv:
|
||||
If you are using Podman, make sure to set the `DOCKER_HOST` environment variable
|
||||
if you have not done so already:
|
||||
```bash
|
||||
# Add the following to e.g. your ~/.bashrc
|
||||
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock
|
||||
```
|
||||
The Podman socket also needs to be running:
|
||||
```bash
|
||||
# Enabled by default on Debian, but not on Fedora
|
||||
systemctl --user enable --now podman.socket
|
||||
```
|
||||
|
||||
First, create the container images:
|
||||
```sh
|
||||
docker run --rm -v "$PWD:$PWD:z" -w "$PWD" python:3.9-bullseye sh -c 'apt update && apt install -y libaugeas0 && python -m venv venv && . venv/bin/activate && pip install -r requirements.txt -r dev-requirements.txt'
|
||||
scripts/build-all-images.sh
|
||||
```
|
||||
Then bring up the containers:
|
||||
```sh
|
||||
docker-compose up -d # or without -d to run in the foreground
|
||||
docker-compose up -d
|
||||
```
|
||||
This will create some containers with the bare minimum necessary for ceod to
|
||||
run, and start ceod on each of phosphoric-acid, mail, and coffee container.
|
||||
|
@ -188,7 +200,7 @@ flask run -h 0.0.0.0 -p 9987
|
|||
```
|
||||
|
||||
Sometimes changes you make in the source code don't show up while Flask
|
||||
is running. Stop the flask app (Ctrl-C), run `clear_cache.sh`, then
|
||||
is running. Stop the flask app (Ctrl-C), run `scripts/clear_cache.sh`, then
|
||||
restart the app.
|
||||
|
||||
## Interacting with the application
|
||||
|
|
|
@ -1,41 +1,51 @@
|
|||
version: "3.6"
|
||||
|
||||
x-common: &common
|
||||
image: python:3.9-bullseye
|
||||
image: ceo-generic:bullseye
|
||||
volumes:
|
||||
- .:$PWD:z
|
||||
- ceo-venv:/app/venv:ro
|
||||
- ./.drone:/app/.drone:ro
|
||||
- ./docker-entrypoint.sh:/app/docker-entrypoint.sh:ro
|
||||
- ./ceo:/app/ceo:ro
|
||||
- ./ceo_common:/app/ceo_common:ro
|
||||
- ./ceod:/app/ceod:ro
|
||||
- ./tests:/app/tests:ro
|
||||
security_opt:
|
||||
- label:disable
|
||||
working_dir: /app
|
||||
entrypoint:
|
||||
- ./docker-entrypoint.sh
|
||||
|
||||
x-ceod-common: &ceod-common
|
||||
<<: *common
|
||||
environment:
|
||||
FLASK_APP: ceod.api
|
||||
FLASK_DEBUG: "true"
|
||||
working_dir: $PWD
|
||||
entrypoint:
|
||||
- ./docker-entrypoint.sh
|
||||
|
||||
services:
|
||||
auth1:
|
||||
<<: *common
|
||||
image: debian:bullseye
|
||||
image: ceo-auth1:bullseye
|
||||
hostname: auth1
|
||||
command: auth1
|
||||
|
||||
coffee:
|
||||
<<: *common
|
||||
<<: *ceod-common
|
||||
image: ceo-coffee:bullseye
|
||||
command: coffee
|
||||
hostname: coffee
|
||||
depends_on:
|
||||
- auth1
|
||||
|
||||
mail:
|
||||
<<: *common
|
||||
<<: *ceod-common
|
||||
command: mail
|
||||
hostname: mail
|
||||
depends_on:
|
||||
- auth1
|
||||
|
||||
phosphoric-acid:
|
||||
<<: *common
|
||||
<<: *ceod-common
|
||||
command: phosphoric-acid
|
||||
hostname: phosphoric-acid
|
||||
depends_on:
|
||||
|
@ -43,4 +53,8 @@ services:
|
|||
- coffee
|
||||
- mail
|
||||
|
||||
volumes:
|
||||
ceo-venv:
|
||||
external: true
|
||||
|
||||
# vim: expandtab sw=2 ts=2
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
#!/bin/sh -e
|
||||
#!/bin/bash
|
||||
|
||||
if ! [ -d venv ]; then
|
||||
echo "You need to create the virtualenv first!" >&2
|
||||
set -ex
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "Usage: $0 <host>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
host="$1"
|
||||
[ -x ".drone/$host-setup.sh" ] && ".drone/$host-setup.sh"
|
||||
if ! [ -d venv ]; then
|
||||
echo "You need to mount the virtualenv" >&2
|
||||
exit 1
|
||||
fi
|
||||
. .drone/$host-setup.sh
|
||||
CONTAINER__setup
|
||||
|
||||
if [ "$host" = auth1 ]; then
|
||||
exec sleep infinity
|
||||
else
|
||||
. venv/bin/activate
|
||||
exec .drone/supervise.sh flask run -h 0.0.0.0 -p 9987
|
||||
exec .drone/supervise.sh venv/bin/flask run -h 0.0.0.0 -p 9987
|
||||
fi
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eux
|
||||
|
||||
SUITE=bullseye
|
||||
PYTHON_VER=3.9
|
||||
DOCKER=docker
|
||||
if command -v podman >/dev/null; then
|
||||
DOCKER=podman
|
||||
export BUILDAH_FORMAT=docker
|
||||
fi
|
||||
|
||||
build_image() {
|
||||
local HOST=$1
|
||||
local BASE_IMAGE=$2
|
||||
local IMAGE=ceo-$HOST:$SUITE
|
||||
if $DOCKER image exists $IMAGE; then
|
||||
return
|
||||
fi
|
||||
run=". .drone/$HOST-setup.sh && IMAGE__setup"
|
||||
if [ $HOST = generic ]; then
|
||||
run=". .drone/phosphoric-acid-setup.sh && IMAGE__setup"
|
||||
fi
|
||||
$DOCKER build -t $IMAGE -f - . <<EOF
|
||||
FROM $BASE_IMAGE
|
||||
WORKDIR /app
|
||||
COPY .drone .drone
|
||||
RUN [ "/bin/bash", "-c", "$run" ]
|
||||
ENTRYPOINT [ "./docker-entrypoint.sh" ]
|
||||
EOF
|
||||
}
|
||||
|
||||
# Install the Python dependencies into a volume and re-use it for all the containers
|
||||
if ! $DOCKER volume exists ceo-venv; then
|
||||
$DOCKER volume create ceo-venv
|
||||
$DOCKER run \
|
||||
--rm \
|
||||
-w /app/venv \
|
||||
-v ceo-venv:/app/venv:z \
|
||||
-v ./requirements.txt:/tmp/requirements.txt:ro \
|
||||
-v ./dev-requirements.txt:/tmp/dev-requirements.txt:ro \
|
||||
python:$PYTHON_VER-slim-$SUITE \
|
||||
sh -c "apt update && apt install --no-install-recommends -y gcc libkrb5-dev libaugeas0 && python -m venv . && bin/pip install -r /tmp/requirements.txt -r /tmp/dev-requirements.txt"
|
||||
fi
|
||||
|
||||
build_image auth1 debian:$SUITE-slim
|
||||
build_image coffee python:$PYTHON_VER-slim-$SUITE
|
||||
# Used by the phosphoric-acid and mail containers
|
||||
build_image generic python:$PYTHON_VER-slim-$SUITE
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -eux
|
||||
|
||||
DOCKER=docker
|
||||
if command -v podman >/dev/null; then
|
||||
DOCKER=podman
|
||||
fi
|
||||
|
||||
$DOCKER images --format="{{index .Names 0}}" | \
|
||||
grep -E "^(localhost/)?ceo-" | \
|
||||
while read name; do $DOCKER rmi $name; done
|
||||
|
||||
if $DOCKER volume exists ceo-venv; then
|
||||
$DOCKER volume rm ceo-venv
|
||||
fi
|
Loading…
Reference in New Issue