diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0b8cef1..0000000 --- a/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -install: - - echo "hello" - -script: - - echo "Not done." diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cc1aee..42333ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +Version 1.3 (Status: RELEASED) +* Upgrade scripts now check for "github_branch" to download correct latest version file. +* Upgrade scripts now return different exit codes depending on issue (dev versions will no longer crash the daemon due to unsupported version) +* Complete visual overhaul of nafsdmctl (looks a lot nicer) +* New development mode, allowing latest commit to always be installed on master and slave (not set version numbers). +* Slave: development functions are now enabled using the config.conf instead of adding files. +* Developer mode introduced in version 1.2.5-stable has been renamed to "skipVersionCheck" +* nafsdmctl: now has remove by domain and remove by ID functions +* nafsdmctl: now has status/start/stop/restart functions for the webinterface +* Slaves now report last connection time to master (nafsdmctl can show a table of which slaves has connected recently) +* nafscli logviewer no longer throws a traceback message on exit (using CTRL+C) +* Rewrote most log messages for both master and slave +* Ability to enable or disable nafsdm upgrades on start (if turned off, you will have to use nafscli upgrade) on slave daemon +* nafscli status now has -a argument which shows the full systemd status of the nafsdm daemon +* (minor): Update all copyright notices to 2018 + Version 1.2.5 (Status: RELEASED) * Added nafscli for the slave, a command-line interface * Added developer mode for both Slave and Master (disables version checking) diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 28b2c31..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,11 +0,0 @@ -pipeline { - agent any - - stages { - stage("Testrun") { - steps { - echo 'Will testrun. Code not done....' - } - } - } -} diff --git a/README.md b/README.md index a0753ab..96b64c9 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,54 @@ # nafsdm -**Current status: STABLE, version 1.2.5-stable** +**Current status: STABLE, version 1.3-stable** Manages DNS nodes and makes sure domains are saved in the slaves configs. Runs on Python and SSH. *nafsdm stands for "not advanced, fast, simple dns manager"* # Prerequisites & Compatibility -Before installing nafsdm, make sure you have at least one master and one slave. The master needs to have SSH open (at least a firewall that only allows your slave IP's) and all slaves need to have bind already configured (**nafsdm DOES NOT install bind for you**) +Before installing nafsdm, make sure you have at least one bind master and one slave already configured. The master needs to have SSH open (at least a firewall that only allows your slave IP's) and all slaves need to have bind already configured (**nafsdm DOES NOT install bind for you**) -nafsdm is tested to work with the following operating systems: +nafsdm is tested to work on the following operating systems: * Debian 8, 9 (7 should work fine) * Ubuntu 16.04.2 (old versions like 14.04 should also work fine, but may lack systemd) * CentOS 7 -# Installation -To install, you will need at least one slave and one master. All slaves will connect to the master (make sure firewall allows SSH connections from all slaves) +nafsdm currently works with: -nafsdm has installation scripts for both master and slaves. +* bind9 (or 'named' on CentOS) -## Master installation -Connect to your master server, and download the installation script. +# Installation +Installing nafsdm can be done using the guide below. -`wget https://raw.githubusercontent.com/MrKaKisen/nafsdm/master/setupMaster.sh` +Before installing, make sure you do not have any existing installation of nafsdm (the installer will not upgrade current installations) -The file also needs to be executable. +## Master installation +Connect to your master server and initiate the installation script. -`chmod +x setupMaster.sh` +`bash <(curl -s https://raw.githubusercontent.com/MrKaKisen/nafsdm/master/setupMaster.sh)` -Now run the installer. The installer will guide you through the steps. +Follow the steps in the installation. -`./setupMaster.sh` +If the above command fails, you can also manually download the script and execute it (using for example wget). -Once it's finished, run the master daemon once, as it will generate keys (as the installer says). +Once it's finished, run the master once, as it will generate keys (the installer also reminds you of this). `nafsdm-master` -Now, copy the SSH key contents somewhere to your computer as it will be needed on the slaves later on (as the output says). +Now, copy the SSH key contents somewhere to your computer as it will be needed on the slaves later on. `cat /home/master-nafsdm/.ssh/nafsdm_rsa` (this will print the key) -The master installation is now finished and should be ready to use. You can use `nafsdmctl` to add/remove domains. +The master installation is now finished and should be ready to use. You can use `nafsdmctl` to add/remove domains or check the status of connected daemons. ## Slave installation You will have to perform these steps on every slave you would like to install this on. -Connect to your slave and download the installation script. +Connect to your slave and initiate the installation script. -`wget https://raw.githubusercontent.com/MrKaKisen/nafsdm/master/setupSlave.sh` +`bash <(curl -s https://raw.githubusercontent.com/MrKaKisen/nafsdm/master/setupSlave.sh)` -The file also need to be executable. - -`chmod +x setupSlave.sh` - -Now run the slave installer. The installer will guide you through the steps. - -`./setupSlave.sh` +Follow the steps in the installation. Once it's finished, you can open up the config with your editor of choice (example below uses nano) to set it up correctly. @@ -75,13 +69,15 @@ Here is an explanation of what every option is. `nodeName` = name of this node -Once that's done, you can paste over the SSH key you saved earlier to the slave. Paste it in to the file mentioned below. +The development section isn't something you should edit unless you're absolutely sure of what you're doing. + +Once you've updated the config, you can paste over the SSH key you saved earlier to the slave. Paste it in to the file mentioned below. `nano /home/slave-nafsdm/.ssh/master_key` The key also needs to have correct permissions. -`chmod 600 /home/slave-nafsdm/.ssh/master_key` (nafsdm will NOT work if the correct permissions are not used) +`chmod 600 /home/slave-nafsdm/.ssh/master_key` (nafsdm will **NOT** work if the correct permissions are not used) You're done! You should now be able to start the slave (if everything is correctly configured). diff --git a/TODO.md b/TODO.md index c4edf5d..9179078 100644 --- a/TODO.md +++ b/TODO.md @@ -2,7 +2,7 @@ (remove completely from list when finished/solved) ## High Priority -* Rework nafsdmctl (make it look nicer) +* nafsdmctl webinterface enable and disable ## Lower Priority * rework the master diff --git a/master-nafsdm/nafsdmctl/__main__.py b/master-nafsdm/nafsdmctl/__main__.py index 2b482bc..1cfac47 100644 --- a/master-nafsdm/nafsdmctl/__main__.py +++ b/master-nafsdm/nafsdmctl/__main__.py @@ -8,28 +8,137 @@ import sys import os import os.path +from tabulate import tabulate from db import * +from connAlive import slaveConnections, flushSlaveConnections +import subprocess +import time # catching ctrl+c import signal # global vars -longLine = ("---------------------------------------------------------") +debug = False +class bcolors: # (thanks to https://stackoverflow.com/a/287944/8321546) + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + # thanks to https://stackoverflow.com/questions/287871/print-in-terminal-with-colors/287944#comment7475474_287944 + BOLD = "\033[1m" + # thanks to https://stackoverflow.com/a/21786287/8321546 + GREENBG = "\x1b[6;30;42m" # green bg with black text + REDBG = "\x1b[2;30;41m" # red bg with black text + + def disable(self): + self.HEADER = '' + self.OKBLUE = '' + self.OKGREEN = '' + self.WARNING = '' + self.FAIL = '' + self.ENDC = '' # functions def signal_handler(signal, frame): print("CTRL+C - quitting.") exit(0) +# visual print functions +def errorPrint(message): + print("nafsdmctl: " + bcolors.FAIL + message + bcolors.ENDC) + +def successPrint(message): + print("nafsdmctl: " + bcolors.OKGREEN + message + bcolors.ENDC) + +def printSyntax(): + # syntax and info + print("Usage: nafsdmctl [COMMAND] [ARG] ...") + print("\n" + bcolors.BOLD + bcolors.FAIL + "nafsdm control " + bcolors.ENDC + "for master daemon" + "\n") + print("Commands:") + print(bcolors.BOLD + " slavestatus [flush]" + bcolors.ENDC + " Shows connection status of all slaves.") + print(bcolors.BOLD + " add [domain.tld] [masterIP] [comment] [nodes.nodes] [dnssec.no/yes]" + bcolors.ENDC + " Add a new domain") + print(bcolors.BOLD + " removedomain [domain]" + bcolors.ENDC + " Remove a record by domain") + print(bcolors.BOLD + " removeid [id]" + bcolors.ENDC + " Remove a record by ID") + print(bcolors.BOLD + " edit [domain]" + bcolors.ENDC + " Edit a domain") + print(bcolors.BOLD + " list" + bcolors.ENDC + " List all domains") + print("\n" + "nafsdm webinterface commands:") + print(bcolors.BOLD + " webinterface status" + bcolors.ENDC + " Shows status of webinterface") + print(bcolors.BOLD + " webinterface start" + bcolors.ENDC + " Start the nafsdm-webinterface") + print(bcolors.BOLD + " webinterface stop" + bcolors.ENDC + " Start the nafsdm-webinterface") + print(bcolors.BOLD + " webinterface restart" + bcolors.ENDC + " Start the nafsdm-webinterface") + +# webinterface control commands +def webinterfaceStatus(): + try: + output = subprocess.check_output(["/bin/systemctl", "status", "nafsdm-webinterface.service"]) + except Exception, e: + outputSaved = str(e.output) + if debug: + print("DEBUG - output from systemctl status nafsdm-webinterface") + print(outputSaved) + for line in outputSaved.split("\n"): + if "Active:" in line: + if "active (running)" in line: + return True + else: + return False + errorPrint("an error occured during status check (perhaps webinterface is not enabled on this system?)") + exit(1) + + for line in output.split("\n"): + if "Active:" in line: + if "active (running)" in line: + return True + # systemd should give us 'Active: active (running)' if it's running, otherwise it's not + return False + +def startWebinterface(): + # simple start command to systemd + try: + output = subprocess.check_output(["/bin/systemctl", "start", "nafsdm-webinterface.service"]) + except Exception: + errorPrint("an error occured during webinterface start") + exit(1) + + return True +def stopWebinterface(): + # simple stop command to systemd + try: + output = subprocess.check_output(["/bin/systemctl", "stop", "nafsdm-webinterface.service"]) + except Exception: + errorPrint("an error occured during webinterface stop") + exit(1) + + return True + +def restartWebinterface(): + # we'll send a simple restart command to systemd + try: + output = subprocess.check_output(["/bin/systemctl", "restart", "nafsdm-webinterface.service"]) + except Exception: + errorPrint("an error occured during webinterface restart") + exit(1) + + return True + +# slave connection status +def printSlaveConnections(): + # get slave connection status + slaveConn = slaveConnections(bcolors) + + # print a fancy table using tabulate + headers = [bcolors.BOLD + "hostname", "latest connection", "latest connection date", "interval" + bcolors.ENDC] + + print(bcolors.BOLD + "Current date: " + bcolors.ENDC + time.strftime("%Y-%M-%d %H:%M:%S") + "\n") + print tabulate(slaveConn, headers, tablefmt="fancy_grid") + # global check if user hasn't typed any vars if len(sys.argv) < 2: - # length is two as len doesn't use 0 as first one - print("syntax error: please use correct argument." + "\n" + - "\n" + "nafsdmctl 'add domain.tld 0.0.0.0 OwnComment nodes.nodes.nodes dnssec.[yes/no]'" + - "\n" + "nafsdmctl 'remove domain.tld'" + - "\n" + "nafsdmctl 'edit domain.tld'"+ - "\n" + "nafsdmctl 'list'") - exit(1) + # not enough args + printSyntax() + exit(0) # check which command user has run if (sys.argv[1] == "add"): @@ -42,50 +151,65 @@ def signal_handler(signal, frame): if "." in sys.argv[6]: if "yes" in sys.argv[6] or "no" in sys.argv[6]: addDomain(sys.argv) - print("Domain added.") + successPrint("domain added") else: - print("syntax error: use dnssec.yes or dnssec.no only.") + errorPrint("use dnssec.yes or dnssec.no only.") + exit(1) else: - print("syntax error: invalid dnssec option?") + errorPrint("invalid dnssec option") + exit(1) else: - print("syntax error: invalid master IP?") + errorPrint("invalid master IP") exit(1) else: - print("syntax error: invalid domain name?") + errorPrint("invalid domain name") exit(1) else: - print("syntax error: 'nafsdmctl add domain.tld 0.0.0.0 OwnComment nodes.nodes.nodes dnssec.[yes/no]' is correct syntax") + errorPrint("not enough arguments") + printSyntax() exit(1) -elif (sys.argv[1] == "remove"): +elif (sys.argv[1] == "removedomain"): if (len(sys.argv) == 3): if "." in sys.argv[2]: if removeDomain(sys.argv[2]) == True: - print("nafsdmctl: remove succesful") + successPrint("remove succesful") else: - print("nafsdmctl: remove failed. Invalid domain name?") + errorPrint("remove failed - invalid domain name?") else: - print("syntax error: invalid domain name?") + errorPrint("invalid domain name") else: - print("syntax error: 'nafsdmctl remove domain.tld' is correct syntax") + errorPrint("not enough arguments") + printSyntax() + exit(1) +elif (sys.argv[1] == "removeid"): + if (len(sys.argv) == 3): + if removeDomainId(sys.argv[2]) == True: + successPrint("remove succesful") + else: + errorPrint("remove failed - invalid id?") + else: + errorPrint("not enough arguments") + printSyntax() + exit(1) elif (sys.argv[1] == "list"): # get domains domainsRaw = listDomains() - # print format to user - print(longLine) - print("id - domain - masterIP - comment - slaves - dnssec") - print(longLine) + # create table we append domains in + printTable = [] for row in domainsRaw: if row != None: if row[5] == "y": - print(str(row[0]) + " - " + row[1] + " - "+ row[2] + " - " + row[3] + " - " + row[4] + " - yes") + printTable.append([str(row[0]), row[1], row[2], row[3], row[4], bcolors.OKGREEN + "yes" + bcolors.ENDC]) elif row[5] == "n": - print(str(row[0]) + " - " + row[1] + " - "+ row[2] + " - " + row[3] + " - " + row[4] + " - no") + printTable.append([str(row[0]), row[1], row[2], row[3], row[4], bcolors.FAIL + "no" + bcolors.ENDC]) else: - print(str(row[0]) + " - " + row[1] + " - "+ row[2] + " - " + row[3] + " - " + row[4] + " - " + row[5]) + printTable.append([str(row[0]), row[1], row[2], row[3], row[4], row[5]]) - print(longLine) + # print a fancy table using tabulate + headers = [bcolors.BOLD + "id", "domain", "master IP", "comment", "slaves", "DNSSEC status" + bcolors.ENDC] + print tabulate(printTable, headers, tablefmt="fancy_grid") elif (sys.argv[1] == "edit"): @@ -107,7 +231,7 @@ def signal_handler(signal, frame): if slaves == "": slaves = None else: - print("syntax error: invalid slaves. Continuing anyways (set to same as before)") + errorPrint("invalid slaves. Continuing anyways (value set to same as before)") slaves = None # DNSSEC @@ -118,24 +242,61 @@ def signal_handler(signal, frame): dnssec = "n" else: dnssec = None - print("syntax error: only yes or no supported. Value set to same as before.") + errorPrint("only yes or no supported. Value set to same as before.") # set the domain domain = sys.argv[2] if editDomain(domain, master_ip, comment, slaves, dnssec) == True: - print("nafsdmctl: edit succesful") + successPrint("edit succesful") + else: + errorPrint("edit failed") + else: + errorPrint("invalid domain name?") + else: + errorPrint("not enough arguments") + printSyntax() + exit(1) +elif (sys.argv[1] == "webinterface"): + if len(sys.argv) < 3: + errorPrint("not enough arguments") + printSyntax() + exit(1) + else: + if sys.argv[2] == "status": + if webinterfaceStatus(): + print("status: " + bcolors.GREENBG + "running" + bcolors.ENDC) + else: + print("status: " + bcolors.REDBG + "not running" + bcolors.ENDC) + elif sys.argv[2] == "start": + if webinterfaceStatus(): + errorPrint("webinterface is already running") else: - print("nafsdmctl: edit failed") + if startWebinterface(): + successPrint("webinterface started") + elif sys.argv[2] == "stop": + if stopWebinterface(): + successPrint("webinterface stopped") + elif sys.argv[2] == "restart": + if restartWebinterface(): + successPrint("webinterface restarted") else: - print("syntax error: invalid domain name?") + errorPrint("invalid webinterface argument") + printSyntax() + exit(1) +elif (sys.argv[1] == "slavestatus"): + if len(sys.argv) < 3: + printSlaveConnections() else: - print("syntax error: 'nafsdmctl edit domain.tld' is correct syntax") + if sys.argv[2] == "flush": + if flushSlaveConnections(): + successPrint("flush successful") + else: + errorPrint("flush failed") + else: + errorPrint("invalid argument") + printSyntax() + exit(1) else: - # just prints some of the syntaxes and exists as an error - print("syntax error: please use correct argument." + "\n" + - "\n" + "nafsdmctl 'nafsdmctl add domain.tld 0.0.0.0 OwnComment nodes.nodes.nodes dnssec.[yes/no]'" + - "\n" + "nafsdmctl 'remove domain.tld'" + - "\n" + "nafsdmctl 'edit domain.tld'"+ - "\n" + "nafsdmctl 'list'") + printSyntax() exit(1) diff --git a/master-nafsdm/nafsdmctl/connAlive.py b/master-nafsdm/nafsdmctl/connAlive.py new file mode 100644 index 0000000..d2c983e --- /dev/null +++ b/master-nafsdm/nafsdmctl/connAlive.py @@ -0,0 +1,62 @@ +# nafsdmctl +# connAlive +# connection alive status +# (c) Vilhelm Prytz 2018 +# https://github.com/mrkakisen/nafsdm + +import os +from os import listdir +from os.path import isfile, join +import subprocess +import time + +# determine time ago +def timeAgo(filename): + statbuf = os.stat(filename) + modifiedTime = format(statbuf.st_mtime) + epochAgo = int(float(time.time())) - int(float(modifiedTime)) + + fullString = time.strftime('%M min(s) and %S sec(s) ago', time.localtime(epochAgo)) + + if epochAgo > 3600: + fullString = str(epochAgo/3600) + " hour(s) ago" + + if epochAgo > 86400: + fullString = str(epochAgo/86400) + " day(s) ago" + + return fullString, epochAgo + +def slaveConnections(bcolors): + slaveConnections = [] + fileList = [f for f in listdir("/home/master-nafsdm/slaveAlive") if isfile(join("/home/master-nafsdm/slaveAlive", f))] + + for file in fileList: + if ".slaveConn" in file: + f = open("/home/master-nafsdm/slaveAlive/" + file, "r") + slaveDate = f.read() + f.close() + + f = open("/home/master-nafsdm/slaveAlive/" + file.split(".")[0] + ".slaveInterval") + interval = f.read() + f.close() + + timeAgoString, epochAgo = timeAgo("/home/master-nafsdm/slaveAlive/" + file) + + if int(epochAgo) > int(interval)+5: + slaveConnections.append(["[" + bcolors.FAIL + "!" + bcolors.ENDC + "] " + file.split(".")[0], bcolors.FAIL + timeAgoString + bcolors.ENDC, slaveDate, interval]) + else: + slaveConnections.append([file.split(".")[0], bcolors.OKGREEN + timeAgoString + bcolors.ENDC, slaveDate, interval]) + + return slaveConnections + +# deletes all slave connections +def flushSlaveConnections(): + fileList = [f for f in listdir("/home/master-nafsdm/slaveAlive") if isfile(join("/home/master-nafsdm/slaveAlive", f))] + + for file in fileList: + try: + os.remove("/home/master-nafsdm/slaveAlive/" + file) + except Exception: + print("failed to delete " + file) + + return True diff --git a/master-nafsdm/nafsdmctl/db.py b/master-nafsdm/nafsdmctl/db.py index ecb7e9b..e6f1fae 100644 --- a/master-nafsdm/nafsdmctl/db.py +++ b/master-nafsdm/nafsdmctl/db.py @@ -61,6 +61,28 @@ def removeDomain(domain): return status +def removeDomainId(domainId): + connection, cursor = dbConnection() + + sql_command = '''DELETE FROM domain WHERE id="''' + str(domainId) + '''";''' + + # execute + cursor.execute(sql_command) + + # check if domain is there + cursor.execute('''SELECT * FROM domain WHERE id= "''' + str(domainId) + '''";''') + + if len(cursor.fetchall()) == 0: + status = True + else: + status = False + + # close connection + connection.commit() + connection.close() + + return status + def listDomains(): connection, cursor = dbConnection() diff --git a/master-nafsdm/pythondaemon/__main__.py b/master-nafsdm/pythondaemon/__main__.py index e4e29c1..512dec3 100644 --- a/master-nafsdm/pythondaemon/__main__.py +++ b/master-nafsdm/pythondaemon/__main__.py @@ -11,11 +11,15 @@ from version import version from versionCheck import checkUpdate -log("Master nafsdm starting up! Welcome! Running version " + version) +log("*******************************************************") +log("master-nafsdm - running version " + version) +log("*******************************************************") + +log("Performing pre-start checks..") # pre checks if not os.path.isfile("/home/master-nafsdm/.ssh/nafsdm_rsa"): - log("SSH directory not found. Running first time setup!") + log("SSH directory not found. Performing first time setup!") setupSSH() # check for upgrade script @@ -51,7 +55,13 @@ log("Could not find the domains.sql file. Configuring database..") setupDatabase() +# check for the slave alive folder +if not os.path.exists("/home/master-nafsdm/slaveAlive"): + log("Creating slaveAlive directory..") + os.makedirs("/home/master-nafsdm/slaveAlive") + + # check for new update checkUpdate() -log("Master DNS daemon ready.") +log("nafsdm-master is now ready.") diff --git a/master-nafsdm/pythondaemon/version.py b/master-nafsdm/pythondaemon/version.py index 062087d..34193a4 100644 --- a/master-nafsdm/pythondaemon/version.py +++ b/master-nafsdm/pythondaemon/version.py @@ -1 +1 @@ -version = "1.2.5-stable" +version = "1.3-stable" diff --git a/master-nafsdm/pythondaemon/versionCheck.py b/master-nafsdm/pythondaemon/versionCheck.py index ba1615a..1793198 100644 --- a/master-nafsdm/pythondaemon/versionCheck.py +++ b/master-nafsdm/pythondaemon/versionCheck.py @@ -11,7 +11,10 @@ import os.path github_branch = "master" +devIcMode = False devStatus = False +doICUpdate = False +normalUpdate = False # dev function for specifing branch if os.path.isfile("/home/master-nafsdm/pythondaemon/dev_github_branch.txt"): @@ -32,63 +35,101 @@ else: devStatus = False +# dev ic mode +if os.path.isfile("/home/master-nafsdm/pythondaemon/dev_ic_mode.txt"): + f = open("/home/master-nafsdm/pythondaemon/dev_ic_mode.txt") + devIcModeRaw = f.read() + f.close() + if "True" in devIcModeRaw: + devIcMode = True + else: + devIcMode = False + def checkUpdate(): + normalUpdate = False + doICUpdate = False if devStatus == True: log("Developer mode enabled, skipping version checking.") else: - log("Checking if a new version is available..") - r = requests.get("https://raw.githubusercontent.com/MrKaKisen/nafsdm/" + github_branch + "/version.txt") - - # check if we got a good code, requests has builtin codes which are OK - if (r.status_code == requests.codes.ok): - if (r.text.split("\n")[0] == version): - log("You're running the latest version, " + version + "!") + if devIcMode: + log("Development commit update mode.") + response = requests.get("https://api.github.com/repos/mrkakisen/nafsdm/branches/development") + if (response.status_code == requests.codes.ok): + data = response.json() + latestCommit = data["commit"]["sha"][0:7] + if version.split("-")[0] == latestCommit: + log("You're using the latest development commit!") + else: + doICUpdate = True + log("A new update is available (dev commit - my version: " + version + " - latest version: " + latestCommit + "-dev)") else: - log("NOTICE: There is a new version available! New version: " + r.text.split("\n")[0]) - if (os.path.exists("/home/master-nafsdm/tempUpgrade")): - log("WARN: folder already exists?") + log("FATAL: Couldn't connect to GitHub! Quitting...") + exit(1) + else: + log("Checking if a new version is available..") + r = requests.get("https://raw.githubusercontent.com/MrKaKisen/nafsdm/" + github_branch + "/version.txt") + + # check if we got a good code, requests has builtin codes which are OK + if (r.status_code == requests.codes.ok): + if (r.text.split("\n")[0] == version): + log("You're running the latest version, " + version + "!") + normalUpdate = False else: - os.makedirs("/home/master-nafsdm/pythondaemon/tempUpgrade") - # shortcut to make the shit importable - f = open("/home/master-nafsdm/pythondaemon/tempUpgrade/__init__.py", "w") - f.write(" ") - f.close() + log("NOTICE: There is a new version available! New version: " + r.text.split("\n")[0]) + normalUpdate = True + + if normalUpdate == True or doICUpdate == True: + if (os.path.exists("/home/master-nafsdm/tempUpgrade")): + log("WARN: folder already exists?") + else: + os.makedirs("/home/master-nafsdm/pythondaemon/tempUpgrade") + # shortcut to make the shit importable + f = open("/home/master-nafsdm/pythondaemon/tempUpgrade/__init__.py", "w") + f.write(" ") + f.close() + + url = ("https://raw.githubusercontent.com/MrKaKisen/nafsdm/" + github_branch + "/scripts/upgradeMaster.sh") + r = requests.get(url) + if (r.status_code == requests.codes.ok): + f = open("/home/master-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh", "w") + f.write(r.content) + f.close() + import subprocess + outputNull = subprocess.check_output(["chmod", "+x", "/home/master-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh"]) - url = ("https://raw.githubusercontent.com/MrKaKisen/nafsdm/" + github_branch + "/scripts/upgradeMaster.sh") + url = ("https://raw.githubusercontent.com/MrKaKisen/nafsdm/" + github_branch + "/scripts/upgradeMaster.py") r = requests.get(url) if (r.status_code == requests.codes.ok): - f = open("/home/master-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh", "w") + f = open("/home/master-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.py", "w") f.write(r.content) f.close() import subprocess - outputNull = subprocess.check_output(["chmod", "+x", "/home/master-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh"]) + outputNull = subprocess.check_output(["chmod", "+x", "/home/master-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.py"]) - url = ("https://raw.githubusercontent.com/MrKaKisen/nafsdm/" + github_branch + "/scripts/upgradeMaster.py") - r = requests.get(url) - if (r.status_code == requests.codes.ok): - f = open("/home/master-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.py", "w") - f.write(r.content) - f.close() - import subprocess - outputNull = subprocess.check_output(["chmod", "+x", "/home/master-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.py"]) - - from tempUpgrade.temp_upgrade import initUpgrade - upgradeStatus = initUpgrade() - if upgradeStatus == "exception": - log("FATAL: An error occured during upgrade. Either you use a unsupported version or the script failed mid-through (that would break your installation). Please retry or run the script manually.") - exit(1) - else: - f = open("/home/master-nafsdm/upgradeLog.log", "w") - f.write(upgradeStatus) - f.close() - log("INFO: Upgrade completed. Please update your configuration as the upgradeLog.log says.") - exit(0) + from tempUpgrade.temp_upgrade import initUpgrade + if doICUpdate: + upgradeStatus = initUpgrade(github_branch, True) else: - log("FATAL: Couldn't connect to GitHub! Quitting...") + upgradeStatus = initUpgrade(github_branch, False) + if upgradeStatus == "exception": + log("FATAL: An error occured during upgrade. The script probably failed mid-through (that would break your installation). Please retry or run the script manually.") + exit(1) + elif upgradeStatus == "unsupported": + log("WARNING: You're running an unsupported version - nafsdm will not be able to upgrade.") + log("WARNING: Consider using developer mode to skip version checking.") + elif upgradeStatus == "unknownException": + log("Unknown exception occured during upgrade.") exit(1) + else: + f = open("/home/master-nafsdm/upgradeLog.log", "w") + f.write(upgradeStatus) + f.close() + log("Upgrade completed. Make sure no additional adjustments are required for this particular upgrade.") + log("Upgrade log is available at /home/master-nafsdm/upgradeLog.log") + exit(0) else: - log("FATAL: Couldn't connect to GitHub! Quitting..") + log("FATAL: Failed to establish connection to GitHub.") exit(1) - else: - log("FATAL: Couldn't receive latest version (on GitHub). Quitting.") - exit(1) + else: + log("FATAL: Failed to establish connection to GitHub.") + exit(1) diff --git a/scripts/requirements_master.txt b/scripts/requirements_master.txt index 9270fa9..26ed495 100644 --- a/scripts/requirements_master.txt +++ b/scripts/requirements_master.txt @@ -1,3 +1,4 @@ requests flask gunicorn +tabulate diff --git a/scripts/upgradeMaster.py b/scripts/upgradeMaster.py index 6f857be..4c7854f 100644 --- a/scripts/upgradeMaster.py +++ b/scripts/upgradeMaster.py @@ -1,6 +1,6 @@ # nafsdm # upgrade script for nafsdm master -# (c) Vilhelm Prytz 2017 +# (c) Vilhelm Prytz 2018 # https://github.com/mrkakisen/nafsdm # why have a seperate script for this? incase the thing needs more args than it knows @@ -8,11 +8,28 @@ # imports import subprocess -def initUpgrade(): +# import version +import sys +sys.path.insert(0, "/home/master-nafsdm/pythondaemon") +from version import version + +def initUpgrade(github_branch="master", dev_ic_mode=False): try: - output = subprocess.check_output(["/bin/bash", "/home/master-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh"]) - except Exception: - # no point of logging anyways - return "exception" + output = subprocess.check_output(["/bin/bash", "/home/master-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh", github_branch, str(dev_ic_mode)]) + except subprocess.CalledProcessError as grepexc: + # we want grepexc to determine the exit code (if it's an issue or just unsupported version) + exit_code = grepexc.returncode + + # these versions cannot tell the difference between unsupported and exception and has therefore their own section in this script + if version == "1.2.5-stable" or version == "1.2.4-stable" or version == "1.2.3-stable" or version == "1.2.2-stable" or version == "1.2.1-stable" or version == "1.2-stable" or version == "1.1-stable" or version == "1.0.1-stable": + return "exception" + else: + # return different depending on exit code (for versions after 1.2.5-stable) + if int(exit_code) == 128: + return "unsupported" + if int(exit_code) == 1: + return "exception" + else: + return "unknownException" return output diff --git a/scripts/upgradeMaster.sh b/scripts/upgradeMaster.sh index c7d8c99..a9c8c98 100644 --- a/scripts/upgradeMaster.sh +++ b/scripts/upgradeMaster.sh @@ -1,8 +1,13 @@ # nafsdm # upgrade script for nafsdm master -# (c) Vilhelm Prytz 2017 +# (c) Vilhelm Prytz 2018 # https://github.com/mrkakisen/nafsdm +# Exit codes: +# normal - 0 +# error - 1 +# unsupported version - 128 + # check if user is root or not if [[ $EUID -ne 0 ]]; then echo "* This script must be run with root privileges (sudo)." 1>&2 @@ -18,15 +23,16 @@ python -mplatform | grep -qi debian && echo "debian" > /home/master-nafsdm/syste OPERATINGSYS="`cat /home/master-nafsdm/system-type.txt`" if [ "$OPERATINGSYS" == "centos" ]; then - yum install curl wget -y + yum install curl wget git -y elif [[ "$OPERATINGSYS" == "debian" ]] || [[ "$OPERATINGSYS" == "ubuntu" ]] ; then - apt-get install curl wget -y + apt-get install curl wget git -y else echo "* Invalid OS. Quit." exit 1 fi -BRANCH="master" +BRANCH="$1" +DEV_IC_MODE="$2" DL_URL="https://github.com/MrKaKisen/nafsdm/archive/" MY_VERSION_RAW="`cat /home/master-nafsdm/pythondaemon/version.py`" LATEST_VERSION=$(curl https://raw.githubusercontent.com/MrKaKisen/nafsdm/$BRANCH/version.txt) @@ -54,17 +60,28 @@ elif [ "$MY_VERSION_RAW" == 'version = "1.2.3-stable"' ]; then elif [ "$MY_VERSION_RAW" == 'version = "1.2.4-stable"' ]; then echo "* Detected version 1.2.4-stable - supported by this upgrade script." MY_VERSION="1.2.4-stable" +elif [ "$MY_VERSION_RAW" == 'version = "1.2.5-stable"' ]; then + echo "* Detected version 1.2.5-stable - supported by this upgrade script." + MY_VERSION="1.2.5-stable" else - echo "* Your version is not supported (dev versions and 1.0 is not supported)." - exit 1 + if [ "$DEV_IC_MODE" == "False" ]; then + echo "* Your version is not supported (dev versions and 1.0 is not supported)." + exit 128 + else + MY_VERSION="dev_release" + fi fi echo "* Downloading newest version." cd /tmp -wget $DL_URL$LATEST_VERSION.tar.gz -O nafsdm.tar.gz -tar -zxvf nafsdm.tar.gz -mv nafsdm-* nafsdm -rm -rf nafsdm.tar.gz +if [ "$DEV_IC_MODE" == "True" ]; then + git clone -b development https://github.com/MrKaKisen/nafsdm.git +else + wget $DL_URL$LATEST_VERSION.tar.gz -O nafsdm.tar.gz + tar -zxvf nafsdm.tar.gz + mv nafsdm-* nafsdm + rm -rf nafsdm.tar.gz +fi # req dl wget -O requirements.txt $REQ_URL @@ -87,9 +104,16 @@ if [ "$MY_VERSION" == "1.0.1-stable" ]; then pip install -r requirements.txt rm -rf requirements.txt + # from version 1.3 onwards + if [ ! -d "/home/master-nafsdm/slaveAlive" ]; then + mkdir /home/master-nafsdm/slaveAlive + fi + chown -R master-nafsdm:master-nafsdm /home/master-nafsdm/slaveAlive + echo "* Upgrade completed. Note: before you start all slaves, update the /home/master-nafsdm/data/domains.txt to use the new DNSSEC support!" echo "* After the list of slaves in the config, add a space and this: 'dnssec.yes' (without colons). Replace yes with no if the domain does not use dnssec." echo "* NAFSDM WILL NOT START IF THIS SCRIPT EXISTS. DELETE IT BEFORE START." + elif [ "$MY_VERSION" == "1.1-stable" ]; then echo "* Replacing python files.." rm -rf /home/master-nafsdm/pythondaemon @@ -107,9 +131,16 @@ elif [ "$MY_VERSION" == "1.1-stable" ]; then pip install -r requirements.txt rm -rf requirements.txt + # from version 1.3 onwards + if [ ! -d "/home/master-nafsdm/slaveAlive" ]; then + mkdir /home/master-nafsdm/slaveAlive + fi + chown -R master-nafsdm:master-nafsdm /home/master-nafsdm/slaveAlive + echo "* Upgrade completed. Note: before you start all slaves, update the /home/master-nafsdm/data/domains.txt to use the new DNSSEC support!" echo "* After the list of slaves in the config, add a space and this: 'dnssec.yes' (without colons). Replace yes with no if the domain does not use dnssec." echo "* NAFSDM WILL NOT START IF THIS SCRIPT EXISTS. DELETE IT BEFORE START." + elif [ "$MY_VERSION" == "1.2-stable" ]; then echo "* Replacing python files.." rm -rf /home/master-nafsdm/pythondaemon @@ -127,7 +158,14 @@ elif [ "$MY_VERSION" == "1.2-stable" ]; then pip install -r requirements.txt rm -rf requirements.txt + # from version 1.3 onwards + if [ ! -d "/home/master-nafsdm/slaveAlive" ]; then + mkdir /home/master-nafsdm/slaveAlive + fi + chown -R master-nafsdm:master-nafsdm /home/master-nafsdm/slaveAlive + echo "* Update completed. Nothing to do or change!" + elif [ "$MY_VERSION" == "1.2.1-stable" ]; then echo "* Replacing python files.." rm -rf /home/master-nafsdm/pythondaemon @@ -145,7 +183,14 @@ elif [ "$MY_VERSION" == "1.2.1-stable" ]; then pip install -r requirements.txt rm -rf requirements.txt + # from version 1.3 onwards + if [ ! -d "/home/master-nafsdm/slaveAlive" ]; then + mkdir /home/master-nafsdm/slaveAlive + fi + chown -R master-nafsdm:master-nafsdm /home/master-nafsdm/slaveAlive + echo "* Update completed. Nothing to do or change!" + elif [ "$MY_VERSION" == "1.2.2-stable" ]; then echo "* Replacing python files.." rm -rf /home/master-nafsdm/pythondaemon @@ -163,7 +208,14 @@ elif [ "$MY_VERSION" == "1.2.2-stable" ]; then pip install -r requirements.txt rm -rf requirements.txt + # from version 1.3 onwards + if [ ! -d "/home/master-nafsdm/slaveAlive" ]; then + mkdir /home/master-nafsdm/slaveAlive + fi + chown -R master-nafsdm:master-nafsdm /home/master-nafsdm/slaveAlive + echo "* Update completed. Nothing to do or change!" + elif [ "$MY_VERSION" == "1.2.3-stable" ]; then echo "* Replacing python files.." rm -rf /home/master-nafsdm/pythondaemon @@ -181,7 +233,14 @@ elif [ "$MY_VERSION" == "1.2.3-stable" ]; then pip install -r requirements.txt rm -rf requirements.txt + # from version 1.3 onwards + if [ ! -d "/home/master-nafsdm/slaveAlive" ]; then + mkdir /home/master-nafsdm/slaveAlive + fi + chown -R master-nafsdm:master-nafsdm /home/master-nafsdm/slaveAlive + echo "* Update completed. Nothing to do or change!" + elif [ "$MY_VERSION" == "1.2.4-stable" ]; then echo "* Replacing python files.." rm -rf /home/master-nafsdm/pythondaemon @@ -200,10 +259,84 @@ elif [ "$MY_VERSION" == "1.2.4-stable" ]; then pip install -r requirements.txt rm -rf requirements.txt + # from version 1.3 onwards + if [ ! -d "/home/master-nafsdm/slaveAlive" ]; then + mkdir /home/master-nafsdm/slaveAlive + fi + chown -R master-nafsdm:master-nafsdm /home/master-nafsdm/slaveAlive + echo "* Update completed. Nothing to do or change!" + +elif [ "$MY_VERSION" == "1.2.5-stable" ]; then + echo "* Replacing python files.." + rm -rf /home/master-nafsdm/pythondaemon + rm -rf /home/master-nafsdm/nafsdmctl + cp nafsdm/master-nafsdm/pythondaemon /home/master-nafsdm/pythondaemon -R + cp nafsdm/master-nafsdm/nafsdmctl /home/master-nafsdm/nafsdmctl -R + + # newer than version 1.2.4, all versions that already have the webinterface + rm -rf /home/master-nafsdm/webinterface + cp nafsdm/master-nafsdm/webinterface /home/master-nafsdm/webinterface -R + cp nafsdm/systemconfigs/nafsdm-webinterface.service /home/master-nafsdm/webinterface/nafsdm-webinterface.service + chmod +x /home/master-nafsdm/webinterface/enableInterface.sh + chmod +x /home/master-nafsdm/webinterface/start.sh + + # newer than version 1.2.4 + pip install -r requirements.txt + rm -rf requirements.txt + + # from version 1.3 onwards + if [ ! -d "/home/master-nafsdm/slaveAlive" ]; then + mkdir /home/master-nafsdm/slaveAlive + fi + chown -R master-nafsdm:master-nafsdm /home/master-nafsdm/slaveAlive + + echo "* Update completed. Nothing to do or change!" + +# for dev versions +elif [ "$MY_VERSION" == "dev_release" ]; then + echo "* Replacing python files.." + rm -rf /home/master-nafsdm/pythondaemon + rm -rf /home/master-nafsdm/nafsdmctl + cp nafsdm/master-nafsdm/pythondaemon /home/master-nafsdm/pythondaemon -R + cp nafsdm/master-nafsdm/nafsdmctl /home/master-nafsdm/nafsdmctl -R + + # newer than version 1.2.4, all versions that already have the webinterface + rm -rf /home/master-nafsdm/webinterface + cp nafsdm/master-nafsdm/webinterface /home/master-nafsdm/webinterface -R + cp nafsdm/systemconfigs/nafsdm-webinterface.service /home/master-nafsdm/webinterface/nafsdm-webinterface.service + chmod +x /home/master-nafsdm/webinterface/enableInterface.sh + chmod +x /home/master-nafsdm/webinterface/start.sh + + # newer than version 1.2.4 + pip install -r requirements.txt + rm -rf requirements.txt + + # from version 1.3 onwards + if [ ! -d "/home/master-nafsdm/slaveAlive" ]; then + mkdir /home/master-nafsdm/slaveAlive + fi + chown -R master-nafsdm:master-nafsdm /home/master-nafsdm/slaveAlive + + # dev set version + if [ "$DEV_IC_MODE" == "True" ]; then + echo "* Setting dev version.." + + cd /tmp/nafsdm + COMMIT_HASH=$(git log -n 1 development | sed -n '1p' | cut -c8-14) + echo "version = \"$COMMIT_HASH-dev\"" > /home/master-nafsdm/pythondaemon/version.py + echo "True" > /home/master-nafsdm/pythondaemon/dev_ic_mode.txt + echo "development" > /home/master-nafsdm/pythondaemon/dev_github_branch.txt + + echo "* Done." + fi + + echo "* Update completed. Nothing to do or change!" + else echo "* Oops - something that shouldn't happen, happend anyways." exit 1 fi rm -rf /tmp/nafsdm +exit 0 diff --git a/scripts/upgradeSlave.py b/scripts/upgradeSlave.py index a2a8f42..e365c00 100644 --- a/scripts/upgradeSlave.py +++ b/scripts/upgradeSlave.py @@ -1,6 +1,6 @@ # nafsdm # upgrade script for nafsdm slave -# (c) Vilhelm Prytz 2017 +# (c) Vilhelm Prytz 2018 # https://github.com/mrkakisen/nafsdm # why have a seperate script for this? incase the thing needs more args than it knows @@ -8,11 +8,28 @@ # imports import subprocess -def initUpgrade(config): +# import version +import sys +sys.path.insert(0, "/home/slave-nafsdm/pythondaemon") +from version import version + +def initUpgrade(config, github_branch="master", dev_ic_mode=False): try: - output = subprocess.check_output(["/bin/bash", "/home/slave-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh", config.type]) - except Exception: - # no point of logging anyways - return "exception" + output = subprocess.check_output(["/bin/bash", "/home/slave-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh", str(config.type), str(github_branch), str(dev_ic_mode)]) + except subprocess.CalledProcessError as grepexc: + # we want grepexc to determine the exit code (if it's an issue or just unsupported version) + exit_code = grepexc.returncode + + # these versions cannot tell the difference between unsupported and exception and has therefore their own section in this script + if version == "1.2.5-stable" or version == "1.2.4-stable" or version == "1.2.3-stable" or version == "1.2.2-stable" or version == "1.2.1-stable" or version == "1.2-stable" or version == "1.1-stable" or version == "1.0.1-stable": + return "exception" + else: + # return different depending on exit code (for versions after 1.2.5-stable) + if int(exit_code) == 128: + return "unsupported" + if int(exit_code) == 1: + return "exception" + else: + return "unknownException" return output diff --git a/scripts/upgradeSlave.sh b/scripts/upgradeSlave.sh index 4e68b6d..602045c 100644 --- a/scripts/upgradeSlave.sh +++ b/scripts/upgradeSlave.sh @@ -1,8 +1,13 @@ # nafsdm # upgrade script for nafsdm slave -# (c) Vilhelm Prytz 2017 +# (c) Vilhelm Prytz 2018 # https://github.com/mrkakisen/nafsdm +# Exit codes: +# normal - 0 +# error - 1 +# unsupported version - 128 + # check if user is root or not if [[ $EUID -ne 0 ]]; then echo "* This script must be run with root privileges (sudo)." 1>&2 @@ -11,19 +16,20 @@ fi echo "* Welcome to nafsdm slave upgrade script!" -echo -n "* Enter operating system (debian/ubuntu/centos): " +# set OPERATINGSYS first OPERATINGSYS="$1" if [ "$OPERATINGSYS" == "centos" ]; then - yum install curl wget -y + yum install curl wget git -y elif [[ "$OPERATINGSYS" == "debian" ]] || [[ "$OPERATINGSYS" == "ubuntu" ]] ; then - apt-get install curl wget -y + apt-get install curl wget git -y else echo "* Invalid OS. Quit." exit 1 fi -BRANCH="master" +BRANCH="$2" +DEV_IC_MODE="$3" DL_URL="https://github.com/MrKaKisen/nafsdm/archive/" MY_VERSION_RAW="`cat /home/slave-nafsdm/pythondaemon/version.py`" LATEST_VERSION=$(curl https://raw.githubusercontent.com/MrKaKisen/nafsdm/$BRANCH/version.txt) @@ -50,17 +56,28 @@ elif [ "$MY_VERSION_RAW" == 'version = "1.2.3-stable"' ]; then elif [ "$MY_VERSION_RAW" == 'version = "1.2.4-stable"' ]; then echo "* Detected version 1.2.4-stable - supported by this upgrade script." MY_VERSION="1.2.4-stable" +elif [ "$MY_VERSION_RAW" == 'version = "1.2.5-stable"' ]; then + echo "* Detected version 1.2.5-stable - supported by this upgrade script." + MY_VERSION="1.2.5-stable" else - echo "* Your version is not supported (dev versions and 1.0 is not supported)." - exit 1 + if [ "$DEV_IC_MODE" == "False" ]; then + echo "* Your version is not supported (dev versions and 1.0 is not supported)." + exit 128 + else + MY_VERSION="dev_release" + fi fi echo "* Downloading newest version." cd /tmp -wget $DL_URL$LATEST_VERSION.tar.gz -O nafsdm.tar.gz -tar -zxvf nafsdm.tar.gz -mv nafsdm-* nafsdm -rm -rf nafsdm.tar.gz +if [ "$DEV_IC_MODE" == "True" ]; then + git clone -b development https://github.com/MrKaKisen/nafsdm.git +else + wget $DL_URL$LATEST_VERSION.tar.gz -O nafsdm.tar.gz + tar -zxvf nafsdm.tar.gz + mv nafsdm-* nafsdm + rm -rf nafsdm.tar.gz +fi # perform upgrade if [ "$MY_VERSION" == "1.0.1-stable" ]; then @@ -91,8 +108,13 @@ if [ "$MY_VERSION" == "1.0.1-stable" ]; then cp nafsdm/systemconfigs/nafscli /usr/bin/nafscli chmod +x /usr/bin/nafscli + # add new development section to config file (versions after 1.2.5) & added new options section + echo -e "\n[options]\nupgradeOnStart = False" >> /home/slave-nafsdm/config.conf + echo -e "\n[development]\ngithub_branch = master\nskipVersionCheck = False\nincrementalCommitVersions = False" >> /home/slave-nafsdm/config.conf + echo "* Upgrade completed." echo "* Script has automatically modified your config to match with the new standards." + elif [ "$MY_VERSION" == "1.1-stable" ]; then echo "* Replacing python files.." rm -rf /home/slave-nafsdm/pythondaemon @@ -113,8 +135,13 @@ elif [ "$MY_VERSION" == "1.1-stable" ]; then cp nafsdm/systemconfigs/nafscli /usr/bin/nafscli chmod +x /usr/bin/nafscli + # add new development section to config file (versions after 1.2.5) & added new options section + echo -e "\n[options]\nupgradeOnStart = False" >> /home/slave-nafsdm/config.conf + echo -e "\n[development]\ngithub_branch = master\nskipVersionCheck = False\nincrementalCommitVersions = False" >> /home/slave-nafsdm/config.conf + echo "* Upgrade completed. You can now start nafsdm-slave again (make sure master is also upgraded!)-" rm -rf /home/slave-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh + elif [ "$MY_VERSION" == "1.2-stable" ]; then echo "* Replacing python files.." rm -rf /home/slave-nafsdm/pythondaemon @@ -135,8 +162,13 @@ elif [ "$MY_VERSION" == "1.2-stable" ]; then cp nafsdm/systemconfigs/nafscli /usr/bin/nafscli chmod +x /usr/bin/nafscli + # add new development section to config file (versions after 1.2.5) & added new options section + echo -e "\n[options]\nupgradeOnStart = False" >> /home/slave-nafsdm/config.conf + echo -e "\n[development]\ngithub_branch = master\nskipVersionCheck = False\nincrementalCommitVersions = False" >> /home/slave-nafsdm/config.conf + echo "* Upgrade completed. You can now start nafsdm-slave again (make sure master is also upgraded!)-" rm -rf /home/slave-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh + elif [ "$MY_VERSION" == "1.2.1-stable" ]; then echo "* Replacing python files.." rm -rf /home/slave-nafsdm/pythondaemon @@ -152,6 +184,10 @@ elif [ "$MY_VERSION" == "1.2.1-stable" ]; then cp nafsdm/systemconfigs/nafscli /usr/bin/nafscli chmod +x /usr/bin/nafscli + # add new development section to config file (versions after 1.2.5) & added new options section + echo -e "\n[options]\nupgradeOnStart = False" >> /home/slave-nafsdm/config.conf + echo -e "\n[development]\ngithub_branch = master\nskipVersionCheck = False\nincrementalCommitVersions = False" >> /home/slave-nafsdm/config.conf + echo "* Upgrade completed. You can now start nafsdm-slave again (make sure master is also upgraded!)-" rm -rf /home/slave-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh @@ -165,6 +201,10 @@ elif [ "$MY_VERSION" == "1.2.2-stable" ]; then cp nafsdm/systemconfigs/nafscli /usr/bin/nafscli chmod +x /usr/bin/nafscli + # add new development section to config file (versions after 1.2.5) & added new options section + echo -e "\n[options]\nupgradeOnStart = False" >> /home/slave-nafsdm/config.conf + echo -e "\n[development]\ngithub_branch = master\nskipVersionCheck = False\nincrementalCommitVersions = False" >> /home/slave-nafsdm/config.conf + echo "* Upgrade completed. You can now start nafsdm-slave again (make sure master is also upgraded!)-" rm -rf /home/slave-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh @@ -178,6 +218,10 @@ elif [ "$MY_VERSION" == "1.2.3-stable" ]; then cp nafsdm/systemconfigs/nafscli /usr/bin/nafscli chmod +x /usr/bin/nafscli + # add new development section to config file (versions after 1.2.5) & added new options section + echo -e "\n[options]\nupgradeOnStart = False" >> /home/slave-nafsdm/config.conf + echo -e "\n[development]\ngithub_branch = master\nskipVersionCheck = False\nincrementalCommitVersions = False" >> /home/slave-nafsdm/config.conf + echo "* Upgrade completed. You can now start nafsdm-slave again (make sure master is also upgraded!)-" rm -rf /home/slave-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh @@ -191,6 +235,10 @@ elif [ "$MY_VERSION" == "1.2.4-stable" ]; then cp nafsdm/systemconfigs/nafscli /usr/bin/nafscli chmod +x /usr/bin/nafscli + # add new development section to config file (versions after 1.2.5) & added new options section + echo -e "\n[options]\nupgradeOnStart = False" >> /home/slave-nafsdm/config.conf + echo -e "\n[development]\ngithub_branch = master\nskipVersionCheck = False\nincrementalCommitVersions = False" >> /home/slave-nafsdm/config.conf + echo "* Upgrade completed. You can now start nafsdm-slave again (make sure master is also upgraded!)-" rm -rf /home/slave-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh @@ -203,7 +251,36 @@ elif [ "$MY_VERSION" == "1.2.5-stable" ]; then rm -rf /home/slave-nafsdm/nafscli cp nafsdm/slave-nafsdm/nafscli /home/slave-nafsdm/nafscli -R + # add new development section to config file (versions after 1.2.5) & added new options section + echo -e "\n[options]\nupgradeOnStart = False" >> /home/slave-nafsdm/config.conf + echo -e "\n[development]\ngithub_branch = master\nskipVersionCheck = False\nincrementalCommitVersions = False" >> /home/slave-nafsdm/config.conf + + echo "* Upgrade completed. You can now start nafsdm-slave again (make sure master is also upgraded!)-" + rm -rf /home/slave-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh + +# for dev versions +elif [ "$MY_VERSION" == "dev_release" ]; then + echo "* Replacing python files.." + rm -rf /home/slave-nafsdm/pythondaemon + cp nafsdm/slave-nafsdm/pythondaemon /home/slave-nafsdm/pythondaemon -R + + # nafscli reinstall (delete and copy) (from version 1.2.5 onwards) + rm -rf /home/slave-nafsdm/nafscli + cp nafsdm/slave-nafsdm/nafscli /home/slave-nafsdm/nafscli -R + + # dev set version + if [ "$DEV_IC_MODE" == "True" ]; then + echo "* Setting dev version.." + + cd /tmp/nafsdm + COMMIT_HASH=$(git log -n 1 development | sed -n '1p' | cut -c8-14) + echo "version = \"$COMMIT_HASH-dev\"" > /home/slave-nafsdm/pythondaemon/version.py + + echo "* Done." + fi + echo "* Upgrade completed. You can now start nafsdm-slave again (make sure master is also upgraded!)-" + echo "* Make sure to copy the [development] section into config.conf and make sure branch is set to development and that incrementalCommitVersions is set to True." rm -rf /home/slave-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.sh else @@ -212,3 +289,4 @@ else fi rm -rf /tmp/nafsdm +exit 0 diff --git a/setupMaster.sh b/setupMaster.sh index 908ce48..796fb5c 100644 --- a/setupMaster.sh +++ b/setupMaster.sh @@ -1,6 +1,6 @@ # nafsdm # help script for setting up nafsdm on the master -# Copyright Vilhelm Prytz 2017 +# Copyright Vilhelm Prytz 2018 # https://github.com/mrkakisen/nafsdm # check if user is root or not @@ -9,7 +9,8 @@ if [[ $EUID -ne 0 ]]; then exit 1 fi -# DL_VERSION will be changed at the time of update +CLONE_URL="https://github.com/MrKaKisen/nafsdm.git" +CLONE_BRANCH="development" DL_URL="https://github.com/MrKaKisen/nafsdm/archive/" REQ_URL="https://raw.githubusercontent.com/MrKaKisen/nafsdm/master/scripts/requirements_master.txt" GITHUB_DIR="master-nafsdm" @@ -50,7 +51,7 @@ elif [[ "$OPERATINGSYS" == "debian" ]] || [[ "$OPERATINGSYS" == "ubuntu" ]] ; th pip install -r requirements.txt rm -rf requirements.txt else - echo "Invalid operating system. Only 'debian', 'ubuntu' and 'centos' supported." + echo "* Invalid operating system. Only 'debian', 'ubuntu' and 'centos' supported." exit 1 fi @@ -58,39 +59,67 @@ fi echo "* Fetching information about latest version.." LATEST_VERSION=$(curl https://raw.githubusercontent.com/MrKaKisen/nafsdm/master/version.txt) -# select version -echo "* Please select your version. Type in the version number or type 'latest' for latest version." -echo -n "* Version: " -read VERSION_USER - -if [ "$VERSION_USER" == "latest" ]; then - echo -n "* Confirm? (y/n): " - read CONFIRM - if [ "$CONFIRM" == "y" ]; then - DL_VERSION="$LATEST_VERSION" +# commit updates +echo "* Developers only: Would you like to enable incremental commit updates and use development branch only?" +echo "* Warning: This is a developer function, do not use in a production environment." +echo -n "* Enable? (y/n): " +read DEV_IC_CONFIRM + +if [ "$DEV_IC_CONFIRM" == "y" ]; then + if [ "$OPERATINGSYS" == "centos" ]; then + yum install git -y + elif [[ "$OPERATINGSYS" == "debian" ]] || [[ "$OPERATINGSYS" == "ubuntu" ]] ; then + apt-get install git -y else - echo "* Aborting.." + echo "* Invalid operating system." exit 1 fi -else - echo -n "* Confirm? If version doesn't exist, script will fail. (y/n): " - read CONFIRM - if [ "$CONFIRM" == "y" ]; then - DL_VERSION="$VERSION_USER" + + cd /tmp + git clone -b $CLONE_BRANCH $CLONE_URL +elif [ "$DEV_IC_CONFIRM" == "n" ]; then + echo "* Skipping.." + # select version + echo "* Please select your version. Type in the version number or type 'latest' for latest version." + echo -n "* Version: " + read VERSION_USER + + if [ "$VERSION_USER" == "latest" ]; then + echo -n "* Confirm? (y/n): " + read CONFIRM + if [ "$CONFIRM" == "y" ]; then + DL_VERSION="$LATEST_VERSION" + else + echo "* Aborting.." + exit 1 + fi else - echo "* Aborting.." - exit 1 + echo -n "* Confirm? If version doesn't exist, script will fail. (y/n): " + read CONFIRM + if [ "$CONFIRM" == "y" ]; then + DL_VERSION="$VERSION_USER" + else + echo "* Aborting.." + exit 1 + fi fi +else + echo "* Aborting.." + exit 1 fi echo "* Required packages installed!" echo "* Downloading nafsdm & installing.." # download in temp dir +if [ "$DEV_IC_CONFIRM" == "n" ]; then + cd /tmp + wget $DL_URL$DL_VERSION.tar.gz -O nafsdm.tar.gz + tar -zxvf nafsdm.tar.gz + mv nafsdm-* nafsdm +fi + cd /tmp -wget $DL_URL$DL_VERSION.tar.gz -O nafsdm.tar.gz -tar -zxvf nafsdm.tar.gz -mv nafsdm-* nafsdm useradd $USER # debian and ubuntu doesn't create its home dir automatically, unlike centos @@ -98,7 +127,9 @@ if [[ "$OPERATINGSYS" == "debian" ]] || [[ "$OPERATINGSYS" == "ubuntu" ]] ; then mkdir $HOME_DIR fi mkdir $HOME_DIR/.ssh +mkdir $HOME_DIR/slaveAlive chown -R master-nafsdm:master-nafsdm $HOME_DIR/.ssh +chown -R master-nafsdm:master-nafsdm $HOME_DIR/slaveAlive cp /tmp/nafsdm/$GITHUB_DIR /home -R cp /tmp/nafsdm/LICENSE $HOME_DIR/LICENSE @@ -113,6 +144,15 @@ chmod +x /home/master-nafsdm/webinterface/start.sh chmod +x /usr/bin/nafsdmctl chmod +x /usr/bin/nafsdm-master +# dev set version +if [ "$DEV_IC_CONFIRM" == "y" ]; then + cd /tmp/nafsdm + COMMIT_HASH=$(git log -n 1 development | sed -n '1p' | cut -c8-14) + echo "version = \"$COMMIT_HASH-dev\"" > /home/master-nafsdm/pythondaemon/version.py + echo "True" > /home/master-nafsdm/pythondaemon/dev_ic_mode.txt + echo "development" > /home/master-nafsdm/pythondaemon/dev_github_branch.txt +fi + echo "* Installed. Cleanup.." rm /tmp/nafsdm -rf diff --git a/setupSlave.sh b/setupSlave.sh index aecb8a4..13dbb5d 100644 --- a/setupSlave.sh +++ b/setupSlave.sh @@ -1,6 +1,6 @@ # nafsdm # help script for setting up nafsdm on all slaves -# Copyright Vilhelm Prytz 2017 +# Copyright Vilhelm Prytz 2018 # https://github.com/mrkakisen/nafsdm # check if user is root or not @@ -9,7 +9,8 @@ if [[ $EUID -ne 0 ]]; then exit 1 fi -# DL_VERSION will be changed at the time of update +CLONE_URL="https://github.com/MrKaKisen/nafsdm.git" +CLONE_BRANCH="development" DL_URL="https://github.com/MrKaKisen/nafsdm/archive/" GITHUB_DIR="slave-nafsdm" HOME_DIR="/home/slave-nafsdm" @@ -49,39 +50,67 @@ fi echo "* Fetching information about latest version.." LATEST_VERSION=$(curl https://raw.githubusercontent.com/MrKaKisen/nafsdm/master/version.txt) -# select version -echo "* Please select your version. Type in the version number or type 'latest' for latest version." -echo -n "* Version: " -read VERSION_USER - -if [ "$VERSION_USER" == "latest" ]; then - echo -n "* Confirm? (y/n): " - read CONFIRM - if [ "$CONFIRM" == "y" ]; then - DL_VERSION="$LATEST_VERSION" +# commit updates +echo "* Developers only: Would you like to enable incremental commit updates and use development branch only?" +echo "* Warning: This is a developer function, do not use in a production environment." +echo -n "* Enable? (y/n): " +read DEV_IC_CONFIRM + +if [ "$DEV_IC_CONFIRM" == "y" ]; then + if [ "$OPERATINGSYS" == "centos" ]; then + yum install git -y + elif [[ "$OPERATINGSYS" == "debian" ]] || [[ "$OPERATINGSYS" == "ubuntu" ]] ; then + apt-get install git -y else - echo "* Aborting.." + echo "* Invalid operating system." exit 1 fi -else - echo -n "* Confirm? If version doesn't exist, script will fail. (y/n): " - read CONFIRM - if [ "$CONFIRM" == "y" ]; then - DL_VERSION="$VERSION_USER" + + cd /tmp + git clone -b $CLONE_BRANCH $CLONE_URL +elif [ "$DEV_IC_CONFIRM" == "n" ]; then + echo "* Skipping.." + # select version + echo "* Please select your version. Type in the version number or type 'latest' for latest version." + echo -n "* Version: " + read VERSION_USER + + if [ "$VERSION_USER" == "latest" ]; then + echo -n "* Confirm? (y/n): " + read CONFIRM + if [ "$CONFIRM" == "y" ]; then + DL_VERSION="$LATEST_VERSION" + else + echo "* Aborting.." + exit 1 + fi else - echo "* Aborting.." - exit 1 + echo -n "* Confirm? If version doesn't exist, script will fail. (y/n): " + read CONFIRM + if [ "$CONFIRM" == "y" ]; then + DL_VERSION="$VERSION_USER" + else + echo "* Aborting.." + exit 1 + fi fi +else + echo "* Aborting.." + exit 1 fi echo "* Required packages installed!" echo "* Downloading nafsdm & installing.." # download in temp dir +if [ "$DEV_IC_CONFIRM" == "n" ]; then + cd /tmp + wget $DL_URL$DL_VERSION.tar.gz -O nafsdm.tar.gz + tar -zxvf nafsdm.tar.gz + mv nafsdm-* nafsdm +fi + cd /tmp -wget $DL_URL$DL_VERSION.tar.gz -O nafsdm.tar.gz -tar -zxvf nafsdm.tar.gz -mv nafsdm-* nafsdm useradd $USER # debian and ubuntu doesn't create its home dir automatically, unlike centos @@ -103,6 +132,17 @@ cp /tmp/nafsdm/systemconfigs/nafscli /usr/bin/nafscli chmod +x /home/slave-nafsdm/start.py chmod +x /usr/bin/nafscli +# dev set version +if [ "$DEV_IC_CONFIRM" == "y" ]; then + cd /tmp/nafsdm + COMMIT_HASH=$(git log -n 1 development | sed -n '1p' | cut -c8-14) + echo "version = \"$COMMIT_HASH-dev\"" > /home/slave-nafsdm/pythondaemon/version.py + + # enable IC mode and change branch to master + sed -i '10s/.*/github_branch = development/' /home/slave-nafsdm/config.conf + sed -i '12s/.*/incrementalCommitVersions = True/' /home/slave-nafsdm/config.conf +fi + echo "* Installed. Cleanup.." rm /tmp/nafsdm -rf diff --git a/slave-nafsdm/config.conf b/slave-nafsdm/config.conf index 410692a..17f5148 100644 --- a/slave-nafsdm/config.conf +++ b/slave-nafsdm/config.conf @@ -5,3 +5,11 @@ update_interval = 60 type = debian/centos/ubuntu bindPath = /etc/bind/mydns.zones nodeName = dns1 + +[options] +upgradeOnStart = False + +[development] +github_branch = master +skipVersionCheck = False +incrementalCommitVersions = False diff --git a/slave-nafsdm/nafscli/__main__.py b/slave-nafsdm/nafscli/__main__.py index 0d73d53..8e4024f 100644 --- a/slave-nafsdm/nafscli/__main__.py +++ b/slave-nafsdm/nafscli/__main__.py @@ -10,6 +10,9 @@ import subprocess import requests +# get config +from getConfig import getConfig + # global vars github_branch = "master" debug = False @@ -35,14 +38,13 @@ def disable(self): self.FAIL = '' self.ENDC = '' -# dev function for specifing branch -if os.path.isfile("/home/slave-nafsdm/pythondaemon/dev_github_branch.txt"): - f = open("/home/slave-nafsdm/pythondaemon/dev_github_branch.txt") - branchRaw = f.read() - f.close() - - if "development" in branchRaw: - github_branch = "development" +# get config +config = getConfig() +github_branch = config.dev_github_branch +if config.dev_incrementalCommitVersions == "True" or config.dev_incrementalCommitVersions == "true": + devICMode = True +else: + devICMode = False # functions def errorPrint(message): @@ -56,7 +58,7 @@ def printSyntax(): print("Usage: nafscli [COMMAND]") print("\n" + bcolors.BOLD + bcolors.FAIL + "nafsdm command-line interface " + bcolors.ENDC + "for slave daemon" + "\n") print("Commands:") - print(bcolors.BOLD + " status" + bcolors.ENDC + " Show current status of the daemon") + print(bcolors.BOLD + " status [-a]" + bcolors.ENDC + " Show current status of the daemon (-a shows all information)") print(bcolors.BOLD + " version" + bcolors.ENDC + " Current version of nafsdm") print(bcolors.BOLD + " start" + bcolors.ENDC + " Start the daemon") print(bcolors.BOLD + " stop" + bcolors.ENDC + " Stop the daemon") @@ -75,18 +77,18 @@ def checkStatus(): for line in outputSaved.split("\n"): if "Active:" in line: if "active (running)" in line: - return True + return True, outputSaved else: - return False + return False, outputSaved errorPrint("an error occured during status check") exit(1) for line in output.split("\n"): if "Active:" in line: if "active (running)" in line: - return True + return True, output # systemd should give us 'Active: active (running)' if it's running, otherwise it's not - return False + return False, output def fetchVersion(): try: @@ -110,15 +112,25 @@ def fetchVersion(): return version def checkVersion(currentVersion): - r = requests.get("https://raw.githubusercontent.com/MrKaKisen/nafsdm/" + github_branch + "/version.txt") + if devICMode: + response = requests.get("https://api.github.com/repos/mrkakisen/nafsdm/branches/development") + if (response.status_code == requests.codes.ok): + data = response.json() + latestCommit = data["commit"]["sha"][0:7] + if currentVersion.split("-")[0] == latestCommit: + return True, None + else: + return False, latestCommit + "-dev" + else: + r = requests.get("https://raw.githubusercontent.com/MrKaKisen/nafsdm/" + github_branch + "/version.txt") - # check for ok response codes - if (r.status_code == requests.codes.ok): - # code borrowed from daemon/versionCheck.py - if (r.text.split("\n")[0] == currentVersion): - return True, None - else: - return False, r.text.split("\n")[0] + # check for ok response codes + if (r.status_code == requests.codes.ok): + # code borrowed from daemon/versionCheck.py + if (r.text.split("\n")[0] == currentVersion): + return True, None + else: + return False, r.text.split("\n")[0] def restartDaemon(): # we'll send a simple restart command to systemd @@ -152,7 +164,7 @@ def stopDaemon(): # the CLI can communicate with the daemon by setting a new CLI state def setCLIState(newState): - if checkStatus(): + if checkStatus()[0]: try: f = open("/home/slave-nafsdm/pythondaemon/cli_state", "w") except Exception: @@ -178,11 +190,24 @@ def setCLIState(newState): # routes if sys.argv[1] == "status": - status = checkStatus() - if status: - print("status: " + bcolors.GREENBG + "running" + bcolors.ENDC) + if len(sys.argv) < 3: + status, output = checkStatus() + if status: + print("status: " + bcolors.GREENBG + "running" + bcolors.ENDC) + else: + print("status: " + bcolors.REDBG + "not running" + bcolors.ENDC) else: - print("status: " + bcolors.REDBG + "not running" + bcolors.ENDC) + if sys.argv[2] == "-a": + status, output = checkStatus() + print(output) + if status: + print("status: " + bcolors.GREENBG + "running" + bcolors.ENDC) + else: + print("status: " + bcolors.REDBG + "not running" + bcolors.ENDC) + else: + errorPrint("invalid argument") + printSyntax() + exit(1) elif sys.argv[1] == "version": version = fetchVersion() @@ -190,6 +215,8 @@ def setCLIState(newState): if versionStatus == True: if github_branch == "development": print("seems like you're using the development branch") + if devICMode: + print("seems like you're using the incremental commit versions") successPrint("you're running the latest version, " + version) else: print("nafscli: " + bcolors.OKGREEN + "a new version is available, " + bcolors.BOLD + newVersion + " (your version is " + version + ")" + bcolors.ENDC) @@ -202,14 +229,20 @@ def setCLIState(newState): successPrint("upgrade command sent to daemon") elif sys.argv[1] == "log": print("nafscli: " + bcolors.WARNING + "press CTRL+C to exit logviewer" + bcolors.ENDC) + + # supress all traceback info + sys.tracebacklimit = 0 try: output = subprocess.call(["tail", "-f", "/home/slave-nafsdm/log.log"]) except Exception: errorPrint("could not read log") exit(1) + # back to default value + sys.tracebacklimit = 1000 + elif sys.argv[1] == "start": - if checkStatus(): + if checkStatus()[0]: errorPrint("daemon is already running") else: if startDaemon(): diff --git a/slave-nafsdm/nafscli/getConfig.py b/slave-nafsdm/nafscli/getConfig.py new file mode 100644 index 0000000..be136f7 --- /dev/null +++ b/slave-nafsdm/nafscli/getConfig.py @@ -0,0 +1,43 @@ +# nafscli +# (c) Vilhelm Prytz 2018 +# getConfig +# parses the config and returns in var +# https://github.com/mrkakisen/nafsdm + +import logging +import ConfigParser +import sys + +# import configDir +sys.path.insert(0, "/home/slave-nafsdm/pythondaemon") +from configDir import __configDir__ as configDir + +class Config(object): + import ConfigParser + + def __init__(self, configFile): + parser = ConfigParser.ConfigParser() + parser.read(configFile) + + try: + self.host = parser.get("nafsdm", "host") + self.user = parser.get("nafsdm", "user") + self.update_interval = parser.get("nafsdm", "update_interval") + self.type = parser.get("nafsdm", "type") + self.bindPath = parser.get("nafsdm", "bindPath") + self.nodeName = parser.get("nafsdm", "nodeName") + + # dev section + self.dev_github_branch = parser.get("development", "github_branch") + self.dev_skipVersionCheck = parser.get("development", "skipVersionCheck") + self.dev_incrementalCommitVersions = parser.get("development", "incrementalCommitVersions") + + except Exception: + print("unexpected error occured during config reading") + exit(1) + + +def getConfig(): + config = Config(configDir) + + return config diff --git a/slave-nafsdm/pythondaemon/__main__.py b/slave-nafsdm/pythondaemon/__main__.py index d96f2f3..8c98c58 100644 --- a/slave-nafsdm/pythondaemon/__main__.py +++ b/slave-nafsdm/pythondaemon/__main__.py @@ -1,5 +1,5 @@ # nafsdm -# (c) Vilhelm Prytz 2017 +# (c) Vilhelm Prytz 2018 # __main__ # get's stuff goooing # https://github.com/mrkakisen/nafsdm @@ -35,16 +35,21 @@ def main(): logger.addHandler(fh) # welcome - logging.info("Welcome to Slave nafsdm version " + version) + logging.info("*******************************************************") + logging.info("nafsdm-slave daemon - running version " + version) + logging.info("*******************************************************") + + logging.info("Running pre-start checks..") # check if the upgrade script is present (we shouldn't be running if so) if os.path.isfile("/home/slave-nafsdm/tempUpgrade/temp_upgrade.sh"): - logging.warning("Upgrade script found. Please delete the upgrade script before runing nafsdm-slave!") + logging.warning("Upgrade script was found during pre-start checks. Please delete the upgrade script before runing nafsdm-slave!") logging.warning("Note: the script is left there because the config has changed and needs updating.") exit(1) if os.path.isfile("/home/slave-nafsdm/config-legacy.conf"): - logging.warning("Legacy config was found. This probably means that nafsdm has been upgraded but the config hasn't been changed yet.") + logging.warning("Legacy config was found. This probably means that nafsdm has been upgraded but the config hasn't been updated yet.") + logging.warning("Remove the legacy config when finished.") exit(1) # check if the temp folder exists diff --git a/slave-nafsdm/pythondaemon/connAlive.py b/slave-nafsdm/pythondaemon/connAlive.py new file mode 100644 index 0000000..cac90d6 --- /dev/null +++ b/slave-nafsdm/pythondaemon/connAlive.py @@ -0,0 +1,31 @@ +# nafsdm +# (c) Vilhelm Prytz 2018 +# __main__ +# connects to the master to say we're running +# https://github.com/mrkakisen/nafsdm + +import logging +import subprocess +import time + +def connectAlive(config): + currentTime = time.strftime("%Y-%M-%d %H:%M:%S") + + try: + output = subprocess.check_output(["ssh", "-i", "/home/slave-nafsdm/.ssh/master_key", config.user + "@" + config.host, "/usr/bin/env", "echo", '"' + currentTime + '"', ">", "/home/master-nafsdm/slaveAlive/" + config.nodeName + ".slaveConn"]) + except Exception: + logging.exception("An error occured during SSH connection.") + logging.error("Could not update alive status - please check if the master is currently reachable.") + + return False + + # also set our connection interval + try: + output = subprocess.check_output(["ssh", "-i", "/home/slave-nafsdm/.ssh/master_key", config.user + "@" + config.host, "/usr/bin/env", "echo", '"' + config.update_interval + '"', ">", "/home/master-nafsdm/slaveAlive/" + config.nodeName + ".slaveInterval"]) + except Exception: + logging.exception("An error occured during SSH connection.") + logging.error("Could not update alive status - please check if the master is currently reachable.") + + return False + + return True diff --git a/slave-nafsdm/pythondaemon/daemon.py b/slave-nafsdm/pythondaemon/daemon.py index 2c8d750..3f5458c 100644 --- a/slave-nafsdm/pythondaemon/daemon.py +++ b/slave-nafsdm/pythondaemon/daemon.py @@ -1,5 +1,5 @@ # nafsdm -# (c) Vilhelm Prytz 2017 +# (c) Vilhelm Prytz 2018 # __main__ # daemon functions # https://github.com/mrkakisen/nafsdm @@ -12,6 +12,7 @@ from db import parseDbData from shutil import copyfile from version import version +from connAlive import connectAlive def changeDetected(): changeDetected = None @@ -71,7 +72,7 @@ def checkMasterVersion(config): return True else: logging.critical("We're NOT running the same version as the master! (my version: " + str(version) + " - Master version: " + masterVersion + ")") - logging.critical("nafsdm will not be able to start.") + logging.critical("nafsdm-slave daemon will not be able to start.") exit(1) @@ -95,7 +96,7 @@ def getData(config): outputNull = subprocess.check_output(["scp", "-i", "/home/slave-nafsdm/.ssh/master_key", config.user + "@" + config.host + ":/home/master-nafsdm/data/domains.sql", "/home/slave-nafsdm/temp/domains_temp.sql"]) except Exception: logging.exception("An error occured during SCP connection.") - logging.error("Please check if the master is up and working.") + logging.error("Please check if the master is up and reachable.") def writeData(config): if os.path.isfile("/home/slave-nafsdm/temp/domains_temp.sql") == True: @@ -164,16 +165,16 @@ def writeData(config): logging.debug("New config has been written.") else: logging.error("An error occured while reading data that was recently downloaded. This usually means the file never was downloaded and therefore doesn't exist.") - logging.error("Couldn't read from domains file! Connection error?") def reloadBind(): # if it fails, it will be printed in log reloadSucceeded = True + logging.info("Reloading bind..") try: logging.info("Reload output (should be empty if ok): " + subprocess.check_output(["rndc", "reconfig"])) except Exception: logging.exception("An error occured during bind reload.") - logging.error("Due to the recent error, we will continue to try to reload bind.") + logging.error("Due to previous error, nafsdm will retry bind reload.") reloadSucceeded = False if reloadSucceeded == True: @@ -181,21 +182,26 @@ def reloadBind(): try: copyfile("/home/slave-nafsdm/temp/domains_temp.sql", "/home/slave-nafsdm/temp/domains_before.sql") except Exception: - logging.exception("Error occured during file replacement domains_temp to domains_before.") + logging.exception("Error occured during file replacement (domains_temp to domains_before).") logging.error("Do we have permissions to that folder?") def runDaemon(config): - logging.info("Daemon started!") + logging.info("Starting daemon..") # run everything once as we get immediate output if everything is OK versionCheck = checkMasterVersion(config) if versionCheck == False: logging.warning("Skipping master version check step..") + # connect alive + if connectAlive(config) == False: + logging.warning("Could not write alive status.") getData(config) writeData(config) reloadBind() + logging.info("Daemon started!") + endlessLoop = False while endlessLoop == False: time.sleep(int(config.update_interval)) @@ -214,3 +220,7 @@ def runDaemon(config): logging.info("Change detected! Writing configuration & reloading bind") writeData(config) reloadBind() + + # connect alive + if connectAlive(config) == False: + logging.warning("Could not write alive status.") diff --git a/slave-nafsdm/pythondaemon/db.py b/slave-nafsdm/pythondaemon/db.py index d8f9b4a..71503bb 100644 --- a/slave-nafsdm/pythondaemon/db.py +++ b/slave-nafsdm/pythondaemon/db.py @@ -1,5 +1,5 @@ # nafsdm -# (c) Vilhelm Prytz 2017 +# (c) Vilhelm Prytz 2018 # db # database SQL communication # https://github.com/mrkakisen/nafsdm diff --git a/slave-nafsdm/pythondaemon/getConfig.py b/slave-nafsdm/pythondaemon/getConfig.py index 73ae743..75f1d1c 100644 --- a/slave-nafsdm/pythondaemon/getConfig.py +++ b/slave-nafsdm/pythondaemon/getConfig.py @@ -1,5 +1,5 @@ # nafsdm -# (c) Vilhelm Prytz 2017 +# (c) Vilhelm Prytz 2018 # getConfig # parses the config and returns in var # https://github.com/mrkakisen/nafsdm @@ -23,9 +23,17 @@ def __init__(self, configFile): self.bindPath = parser.get("nafsdm", "bindPath") self.nodeName = parser.get("nafsdm", "nodeName") + # options section + self.options_upgradeOnStart = parser.get("options", "upgradeOnStart") + + # dev section + self.dev_github_branch = parser.get("development", "github_branch") + self.dev_skipVersionCheck = parser.get("development", "skipVersionCheck") + self.dev_incrementalCommitVersions = parser.get("development", "incrementalCommitVersions") + except Exception: - logging.exception("Could not read config. Please check your config if it's setup properly.") - logging.critical("Exiting application due to recent error.") + logging.exception("Could not read config. Please check if your config is setup properly.") + logging.critical("Exiting due to previous error.") quit(1) diff --git a/slave-nafsdm/pythondaemon/version.py b/slave-nafsdm/pythondaemon/version.py index 062087d..34193a4 100644 --- a/slave-nafsdm/pythondaemon/version.py +++ b/slave-nafsdm/pythondaemon/version.py @@ -1 +1 @@ -version = "1.2.5-stable" +version = "1.3-stable" diff --git a/slave-nafsdm/pythondaemon/versionCheck.py b/slave-nafsdm/pythondaemon/versionCheck.py index c63eb3d..d1fc0a4 100644 --- a/slave-nafsdm/pythondaemon/versionCheck.py +++ b/slave-nafsdm/pythondaemon/versionCheck.py @@ -1,5 +1,5 @@ # nafsdm -# (c) Vilhelm Prytz 2017 +# (c) Vilhelm Prytz 2018 # versionCheck # checks if a new version is available # https://github.com/mrkakisen/nafsdm @@ -10,43 +10,69 @@ import requests import os.path -devStatus = False github_branch = "master" +devIcMode = False +devSkipVersionCheck = False +doICUpdate = False +normalUpdate = False +upgradeOnStart = False # dev function for specifing branch -if os.path.isfile("/home/slave-nafsdm/pythondaemon/dev_github_branch.txt"): - f = open("/home/slave-nafsdm/pythondaemon/dev_github_branch.txt") - branchRaw = f.read() - f.close() +def setDevFunctions(config): + github_branch = config.dev_github_branch + devSkipVersionCheck = False + devIcMode = False + upgradeOnStart = False - if "development" in branchRaw: - github_branch = "development" + # dev section + if config.dev_skipVersionCheck == "True" or config.dev_skipVersionCheck == "true": + devSkipVersionCheck = True + if config.dev_incrementalCommitVersions == "True" or config.dev_incrementalCommitVersions == "true": + devIcMode = True -# dev mode, disables auto updater -if os.path.isfile("/home/slave-nafsdm/pythondaemon/dev_devmode.txt"): - f = open("/home/slave-nafsdm/pythondaemon/dev_devmode.txt") - devStatusRaw = f.read() - f.close() - if "True" in devStatusRaw: - devStatus = True - else: - devStatus = False + # options section + if config.options_upgradeOnStart == "True" or config.options_upgradeOnStart == "true": + upgradeOnStart = True + + return github_branch, devSkipVersionCheck, devIcMode, upgradeOnStart def checkUpdate(config, mode): - if devStatus == True: - logging.warning("Developer mode enabled, skipping version checking.") + github_branch, devSkipVersionCheck, devIcMode, upgradeOnStart = setDevFunctions(config) + doICUpdate = False + normalUpdate = False + if devSkipVersionCheck == True: + logging.warning("Version check skipping mode enabled, skipping version checking.") else: - logging.info("Checking if a new version is available..") - r = requests.get("https://raw.githubusercontent.com/MrKaKisen/nafsdm/" + github_branch + "/version.txt") - - # check if we got a good code, requests has builtin codes which are OK - if (r.status_code == requests.codes.ok): - if (r.text.split("\n")[0] == version): - logging.info("You're running the latest version, " + version + "!") + if devIcMode: + logging.info("Development commit update mode.") + response = requests.get("https://api.github.com/repos/mrkakisen/nafsdm/branches/development") + if (response.status_code == requests.codes.ok): + data = response.json() + latestCommit = data["commit"]["sha"][0:7] + if version.split("-")[0] == latestCommit: + logging.info("You're using the latest development commit!") + else: + doICUpdate = True + logging.info("A new update is available (dev commit - my version: " + version + " - latest version: " + latestCommit + "-dev)") else: - logging.info("There is a new version available! New version: " + r.text.split("\n")[0]) + logging.critical("Failed to establish connection to GitHub.") + exit(1) + else: + logging.info("Checking for new versions..") + r = requests.get("https://raw.githubusercontent.com/MrKaKisen/nafsdm/" + github_branch + "/version.txt") + + # check if we got a good code, requests has builtin codes which are OK + if (r.status_code == requests.codes.ok): + if (r.text.split("\n")[0] == version): + logging.info("You're running the latest version, " + version + "!") + else: + logging.info("There is a new version available! New version: " + r.text.split("\n")[0]) + normalUpdate = True + + if normalUpdate == True or doICUpdate == True: + if upgradeOnStart or mode == "cli": if (os.path.exists("/home/slave-nafsdm/tempUpgrade")): - logging.warning("Temp upgrade folder already exists?") + logging.warning("Temp upgrade folder already exists!") else: os.makedirs("/home/slave-nafsdm/pythondaemon/tempUpgrade") # shortcut to make the shit importable @@ -74,17 +100,28 @@ def checkUpdate(config, mode): outputNull = subprocess.check_output(["chmod", "+x", "/home/slave-nafsdm/pythondaemon/tempUpgrade/temp_upgrade.py"]) from tempUpgrade.temp_upgrade import initUpgrade - upgradeStatus = initUpgrade(config) + if doICUpdate: + upgradeStatus = initUpgrade(config, github_branch, True) + else: + upgradeStatus = initUpgrade(config, github_branch, False) if upgradeStatus == "exception": - logging.critical("An error occured during upgrade. Either you use a unsupported version or the script failed mid-through (that would break your installation). Please retry or run the script manually.") + logging.critical("An error occured during upgrade. The script probably failed mid-through (that would break your installation). Please retry or run the script manually.") + exit(1) + elif upgradeStatus == "unsupported": + logging.warning("You're running an unsupported version - nafsdm will not be able to upgrade.") + logging.warning("Consider enabling skip version checking.") + logging.info("nafsdm will continue boot") + elif upgradeStatus == "unknownException": + logging.critical("Unknown exception occured during upgrade.") exit(1) else: f = open("/home/slave-nafsdm/upgradeLog.log", "w") f.write(upgradeStatus) f.close() - logging.info("Upgrade completed. Please update your configuration as the upgradeLog.log says.") + logging.info("Upgrade completed. Make sure no additional adjustments are required for this particular upgrade.") + logging.info("Upgrade log is available at /home/slave-nafsdm/upgradeLog.log") if mode == "cli": - logging.info("Upgrade command sent from CLI. Restarting nafsdm-slave..") + logging.info("Upgrade command was sent from CLI. Restarting nafsdm-slave..") try: output = subprocess.check_output(["/bin/systemctl", "restart", "nafsdm-slave.service"]) except Exception: @@ -94,11 +131,11 @@ def checkUpdate(config, mode): else: exit(0) else: - logging.critical("Couldn't connect to GitHub! Quitting...") + logging.critical("Failed to establish connection to GitHub.") exit(1) else: - logging.critical("Couldn't connect to GitHub! Quitting..") + logging.critical("Failed to establish connection to GitHub.") exit(1) - else: - logging.critical("Couldn't receive latest version (on GitHub). Quitting.") - exit(1) + else: + logging.info("Upgrade on start is disabled - nafsdm will not perform upgrade.") + logging.info("It is recommended to upgrade as soon as possible using 'nafscli upgrade'") diff --git a/version.txt b/version.txt index 9bc4894..3211be4 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.2.5-stable +1.3-stable