added in systemd unit and scripts

added in APP_INSTANCE for custom start includine debug
first basic working version that has been deployed
master
David Kebler 2020-10-13 08:19:38 -07:00
parent 6a53b307ba
commit ba0f05436c
16 changed files with 130 additions and 28 deletions

View File

@ -1,11 +1,3 @@
notify:
services:
pushsafer:
module: "@uci-utils/notify-pushsafer-plugin"
email:
module: "@uci-utils/notify-email-plugin"
subject: 'A Public IP Address has changed'
cron: 10 # interval in minutes to check to see if public ip has changed, comment to run just once or set to falsey
lookup: lookup:
interval: 10 # seconds to keep trying lookup of changed value interval: 10 # seconds to keep trying lookup of changed value
timeout: 2 # minutes before giving up - failed set timeout: 2 # minutes before giving up - failed set

2
config/dev-debug.yaml Normal file
View File

@ -0,0 +1,2 @@
debug: true
verbose: vv

View File

@ -1,5 +1,5 @@
network: 'testing kebler network' network: 'testing kebler network'
domain: 'test.kebler.net' domain: 'test.kebler.net'
dev: true dev: true
announce: true verbose: v
cron: 1 cron: 1

6
config/production.yaml Normal file
View File

@ -0,0 +1,6 @@
announce: false
pro: true
cron: 30 # interval in minutes to check to see if public ip has changed, comment to run just once or set to falsey
lookup:
interval: 10 # seconds to keep trying lookup of changed value
timeout: 2 # minutes before giving up - failed set

View File

@ -7,15 +7,18 @@ import { promisify } from 'util'
const lookup = promisify(clookup) const lookup = promisify(clookup)
import { CronJob } from 'cron' import { CronJob } from 'cron'
console.log(JSON.stringify(opts, null, 3))
const rname = process.argv[2] || opts.domain const rname = process.argv[2] || opts.domain
if (!rname) { if (!rname) {
console.log('exiting, must supply subdomain record name to check') console.log('exiting, must supply (sub)domain record name to check')
console.log(JSON.stringify(opts, null, 3))
process.exit() process.exit()
} }
const interval = (opts.lookup || {}).interval * 1000 || 10000 const verbose = (opts.verbose ||'').length
const timeout = (opts.lookup || {}).timeout * 1000 * 60 || 120000 const interval = (opts.lookup || {}).interval || 10 // seconds
const timeout = (opts.lookup || {}).timeout || 5 // minutes
if (verbose) console.log(JSON.stringify(opts, null, 3))
let notify=()=>{} // noop let notify=()=>{} // noop
const route53 = new Route53(opts.aws ? opts.aws : {profile:'default'}) const route53 = new Route53(opts.aws ? opts.aws : {profile:'default'})
@ -25,8 +28,7 @@ const route53 = new Route53(opts.aws ? opts.aws : {profile:'default'})
const notifier = await Notifier.create(opts.notify) const notifier = await Notifier.create(opts.notify)
notify = notifier.send.bind(notifier) notify = notifier.send.bind(notifier)
} }
if (opts.cron && !opts.debug) {
if (opts.cron) {
console.log('setting up check cron job every', opts.cron,'minutes') console.log('setting up check cron job every', opts.cron,'minutes')
const cronstr = `0 */${opts.cron} * * * *` const cronstr = `0 */${opts.cron} * * * *`
const job = new CronJob(cronstr, checkIP) const job = new CronJob(cronstr, checkIP)
@ -34,7 +36,7 @@ const route53 = new Route53(opts.aws ? opts.aws : {profile:'default'})
job.start() job.start()
} else { } else {
console.log('running check a single time') console.log('running check a single time')
checkIP checkIP()
} }
})().catch(err => { })().catch(err => {
@ -52,24 +54,41 @@ async function checkIP () {
curr = ip.join('.') curr = ip.join('.')
} }
const saved = await route53.getZoneRecordValue(rname) const saved = await route53.getZoneRecordValue(rname)
if (opts.announce) notify('checking for change in public ip') if (opts.debug) notify('checking for change in public ip',timestamp())
if (curr !== saved) { if (curr !== saved) {
let msg=`For Network:${opts.network}, a new public ip has been detected for ${rname} from ${saved} to ${curr}` let msg=`${timestamp()} Network:${opts.network}, a new public ip has been detected for ${rname} from ${saved} to ${curr}`
console.log(msg)
notify(msg)
msg=JSON.stringify(await route53.updateZoneRecordValue(rname,curr),null,3)
console.log(msg) console.log(msg)
notify(msg) notify(msg)
const res=JSON.stringify(await route53.updateZoneRecordValue(rname,curr),null,3)
console.log(res)
notify(res)
const fail = setTimeout(()=>{
clearInterval(check)
msg=`${timestamp()}, ${opts.network}: FATAL the pending change of ip address was not realized in ${timeout*(opts.debug ? 10 : 60)} seconds. Human attention required`
console.log(msg)
notify(msg)
},timeout*1000*(opts.debug ? 10 : 60))
const check = setInterval(async ()=>{ const check = setInterval(async ()=>{
if (curr === (await lookup(rname)).address) { if (curr === (await lookup(rname)).address) {
msg=`Update Succeeded, lookup of ${rname} is now ${curr}` msg=`Update Succeeded, lookup of ${rname} is now ${curr}`
clearInterval(check) clearInterval(check)
} else msg=`Update Pending, will check again in ${(opts.lookup || {}).interval || 10 } seconds` clearTimeout(fail)
console.log(msg) console.log(msg)
notify(msg) notify(msg)
} else {
msg=`Update Pending, will check again in ${interval} seconds`
if (verbose || opts.debug ) {
notify(msg)
console.log(msg)
}
}
} }
,(opts.lookup || {}).interval * 1000 || 10000) ,interval*1000)
// const fail = setTimeout(,timeout)
} else console.log('Public IP has not changed, nothing to do', saved) } else console.log('Public IP has not changed, nothing to do', saved)
} }
function timestamp() {
return new Date().toLocaleString().replace('T', ' ').substring(0, 19)
}

6
nodemon.json Normal file
View File

@ -0,0 +1,6 @@
{
"ignoreRoot": [".git"],
"watch": ["config/","node_modules/@uci/","node_modules/@uci-utils/","src/","index.js"],
"ignore": [".git"],
"ext" : "yaml, js"
}

View File

@ -5,7 +5,8 @@
"main": "src/route53.js", "main": "src/route53.js",
"scripts": { "scripts": {
"start": "node -r esm index.js", "start": "node -r esm index.js",
"dev": "NODE_ENV=dev nodemon -r esm index.js" "dev": "NODE_ENV=dev nodemon -r esm index.js",
"dev:debug": "NODE_APP_INSTANCE=debug npm run dev"
}, },
"author": "David Kebler", "author": "David Kebler",
"license": "MIT", "license": "MIT",
@ -22,7 +23,7 @@
"homepage": "https://github.com/uCOMmandIt/uci-utils#readme", "homepage": "https://github.com/uCOMmandIt/uci-utils#readme",
"dependencies": { "dependencies": {
"@uci-utils/notify": "^0.1.5", "@uci-utils/notify": "^0.1.5",
"@uci-utils/notify-email-plugin": "^0.1.5", "@uci-utils/notify-email-plugin": "^0.1.6",
"@uci-utils/notify-pushsafer-plugin": "^0.1.2", "@uci-utils/notify-pushsafer-plugin": "^0.1.2",
"@uci-utils/route53": "^0.1.2", "@uci-utils/route53": "^0.1.2",
"config": "^3.3.2", "config": "^3.3.2",

16
run Executable file
View File

@ -0,0 +1,16 @@
#!/bin/bash
CONF=$1
if [ -z "$CONF" ];
then
echo missing configuration argument, aborting
exit 1
fi
DIR="$(dirname "$(readlink -f "$0")")"
# echo $DIR
cd $DIR || exit
NODE=$(which node)
export NODE_ENV=production
export NODE_APP_INSTANCE=$CONF
export NODE_ENV=$2
# echo $NODE
$NODE -r esm $DIR/index.js

7
systemd/install Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
# install template system space
DIR="$(dirname "$(readlink -f "$0")")"
sudo \cp -f $DIR/update-public-ip@.service /etc/systemd/system
echo "update-public-ip@.service copied to systemd"
. start
. persist

4
systemd/log Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
CONF=$1
sudo journalctl --unit=update-public-ip@$CONF.service -n 50 --no-pager
exit 1

3
systemd/persist Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
CONF=$1
sudo systemctl enable update-public-ip@$CONF

11
systemd/start Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash
CONF=$1
if [ -z "$CONF" ];
then
echo missing configuration argument, aborting
exit 1
fi
sudo systemctl daemon-reload
sudo systemctl stop update-public-ip@$CONF
sudo systemctl start update-public-ip@$CONF
sudo systemctl status update-public-ip@$CONF

8
systemd/status Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
CONF=$1
if [ -z "$CONF" ];
then
echo missing configuration argument, aborting
exit 1
fi
sudo systemctl status update-public-ip@$CONF

10
systemd/stop Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash
CONF=$1
if [ -z "$CONF" ];
then
echo missing configuration argument, aborting
exit 1
fi
sudo systemctl stop update-public-ip@$CONF
sudo systemctl status update-public-ip@$CONF
sudo journalctl --unit=update-public-ip@$CONF.service -n 100 --no-pager

View File

@ -0,0 +1,17 @@
[Unit]
Description=Update DNS record at Route53 with LAN public IP
After=network-online.target
[Service]
# if using aws profile files must be in .aws under user home given below.
User=sysadmin
Group=sysadmin
# NODE_ENV and NODE_INSTANCE will determine configuration file. see config directory in repo
Environment=NODE_ENV=production
Environment=NODE_APP_INSTANCE=%i
WorkingDirectory=/opt/update-public-ip
ExecStart=/usr/bin/node -r esm /opt/update-public-ip/index.js
Restart=always
RestartSec=3
[Install]
WantedBy=default.target