Real World rc.d Script for Open Source Go Projects

#CI #CD #FreeBSD #Git #Go #Init

I host 33 web services on my personal servers. Ten of which are Go web services which I have created. They’re “open source.” In quotes as some services and their sources are obscured (I don’t care to document their uses). Managing more than a couple web services effectively needs some level of automation. Specifically around building and deploying the web services. Of which I handle with Git hooks and rc.d on FreeBSD.

On this blog you can find posts on minimal rc.d scripts and minimal CI/CD scripts but here I will show a full example I use across a number of open source Go projects that I think work well for general usage (and is used for this very blog).

I’ll begin with the post-update Git hook.

#!/usr/bin/env sh

SERV='service_name'
TUSER='ssh_user'
THOST='ssh_target'
TPORT='ssh_port'

ssh -p $TPORT $TUSER@$THOST "service $SERV update ; echo deploy complete"

Pretty simple. You can see the hook does not build the software. It simply informs the target machine it should update. (Then assumes the update was performed successfully…).

The heavy lifting is on the rc.d script.

#!/bin/sh

# PROVIDE: servicename
# REQUIRE: LOGIN DAEMON NETWORKING

. /etc/rc.subr

name=servicename
rcvar=servicename_enable
extra_commands="update"

start_cmd="servicename_start"
stop_cmd="servicename_stop"
restart_cmd="servicename_restart"
update_cmd="servicename_update"

SERVICENAME="servicename"
SERVICENAME_BIN="/go/bin/$SERVICENAME"
SERVICENAME_GIT_SERVER="not.github.com"
SERVICENAME_GIT_USER="the_username"
SERVICENAME_GIT="$SERVICENAME_GIT_SERVER/$SERVICENAME_GIT_USER/$SERVICENAME"
SERVICENAME_GO="/usr/local/bin/go"
SERVICENAME_RUN="$SERVICENAME_BIN -port 80"

servicename_start() 
{
        if [ ! -f $SERVICENAME_BIN ] ; then
                servicename_download
        fi
        daemon -r \
        -p /var/log/servicename_child_pid \
        -P /var/log/servicename_supervisor_pid \
        -o /var/log/servicename \
        $SERVICENAME_RUN
}

servicename_stop()
{
        if [ -f /var/log/servicename_supervisor_pid ] ; then
                cat /var/log/servicename_supervisor_pid | xargs kill -9 
                rm /var/log/servicename_supervisor_pid
        fi
        if [ -f /var/log/servicename_child_pid ] ; then
                cat /var/log/servicename_child_pid | xargs kill -9 
                rm /var/log/servicename_child_pid
        fi
}

servicename_restart()
{
        servicename_stop
        servicename_start
}

servicename_update()
{
        servicename_download
        servicename_restart
}

servicename_download() 
{
        env PATH="$PATH:/usr/local/bin" GOPROXY=direct $SERVICENAME_GO get -u $SERVICENAME_GIT@latest
}

load_rc_config $name
run_rc_command "$1"

This requires both Go and Git to be installed on the target machine.

When service servicename update is issued the target machine will fetch the new Go source from Git, build the service, then restart the service.

EOF