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 2 years ago
parent 6a53b307ba
commit ba0f05436c
  1. 8
      config/default.yaml
  2. 2
      config/dev-debug.yaml
  3. 2
      config/dev.yaml
  4. 6
      config/production.yaml
  5. 53
      index.js
  6. 6
      nodemon.json
  7. 5
      package.json
  8. 16
      run
  9. 0
      systemd/README.md
  10. 7
      systemd/install
  11. 4
      systemd/log
  12. 3
      systemd/persist
  13. 11
      systemd/start
  14. 8
      systemd/status
  15. 10
      systemd/stop
  16. 17
      systemd/update-public-ip@.service

@ -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:
interval: 10 # seconds to keep trying lookup of changed value
timeout: 2 # minutes before giving up - failed set

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

@ -1,5 +1,5 @@
network: 'testing kebler network'
domain: 'test.kebler.net'
dev: true
announce: true
verbose: v
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

@ -7,15 +7,18 @@ import { promisify } from 'util'
const lookup = promisify(clookup)
import { CronJob } from 'cron'
console.log(JSON.stringify(opts, null, 3))
const rname = process.argv[2] || opts.domain
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()
}
const interval = (opts.lookup || {}).interval * 1000 || 10000
const timeout = (opts.lookup || {}).timeout * 1000 * 60 || 120000
const verbose = (opts.verbose ||'').length
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
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)
notify = notifier.send.bind(notifier)
}
if (opts.cron) {
if (opts.cron && !opts.debug) {
console.log('setting up check cron job every', opts.cron,'minutes')
const cronstr = `0 */${opts.cron} * * * *`
const job = new CronJob(cronstr, checkIP)
@ -34,7 +36,7 @@ const route53 = new Route53(opts.aws ? opts.aws : {profile:'default'})
job.start()
} else {
console.log('running check a single time')
checkIP
checkIP()
}
})().catch(err => {
@ -52,24 +54,41 @@ async function checkIP () {
curr = ip.join('.')
}
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) {
let msg=`For 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)
let msg=`${timestamp()} Network:${opts.network}, a new public ip has been detected for ${rname} from ${saved} to ${curr}`
console.log(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 ()=>{
if (curr === (await lookup(rname)).address) {
msg=`Update Succeeded, lookup of ${rname} is now ${curr}`
clearInterval(check)
} else msg=`Update Pending, will check again in ${(opts.lookup || {}).interval || 10 } seconds`
console.log(msg)
notify(msg)
clearTimeout(fail)
console.log(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)
// const fail = setTimeout(,timeout)
,interval*1000)
} 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",
"scripts": {
"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",
"license": "MIT",
@ -22,7 +23,7 @@
"homepage": "https://github.com/uCOMmandIt/uci-utils#readme",
"dependencies": {
"@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/route53": "^0.1.2",
"config": "^3.3.2",

16
run

@ -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…
Cancel
Save