added in systemd unit and scripts
added in APP_INSTANCE for custom start includine debug first basic working version that has been deployedmaster
parent
6a53b307ba
commit
ba0f05436c
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
debug: true
|
||||||
|
verbose: vv
|
|
@ -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
|
||||||
|
|
|
@ -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
|
53
index.js
53
index.js
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"ignoreRoot": [".git"],
|
||||||
|
"watch": ["config/","node_modules/@uci/","node_modules/@uci-utils/","src/","index.js"],
|
||||||
|
"ignore": [".git"],
|
||||||
|
"ext" : "yaml, js"
|
||||||
|
}
|
|
@ -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",
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/bash
|
||||||
|
CONF=$1
|
||||||
|
sudo journalctl --unit=update-public-ip@$CONF.service -n 50 --no-pager
|
||||||
|
exit 1
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
CONF=$1
|
||||||
|
sudo systemctl enable update-public-ip@$CONF
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue