From bb7ee39cb3f90331ffb4b7f214798b3af68210f5 Mon Sep 17 00:00:00 2001 From: Cem Gokmen Date: Thu, 6 Apr 2017 00:41:26 -0400 Subject: [PATCH] Final changes before launch, added some bash scripts to make things easier, updated readme --- README.md | 53 ++++++++++++++++++++++++++--- main.py | 68 ++++++++++++++----------------------- scripts/build-image.sh | 4 +++ scripts/create-container.sh | 4 +++ scripts/startup-config.sh | 13 +++++++ verne.service | 12 +++++++ 6 files changed, 106 insertions(+), 48 deletions(-) create mode 100644 scripts/build-image.sh create mode 100644 scripts/create-container.sh create mode 100644 scripts/startup-config.sh create mode 100644 verne.service diff --git a/README.md b/README.md index 257d91b..c5c985f 100644 --- a/README.md +++ b/README.md @@ -9,30 +9,73 @@ These instructions will get you a copy of the project up and running on your loc The software is designed to be run on a Docker container where a number of software libraries will be installed. As a result, the docker-ce package is required. Run the following command to install Docker: -`curl -sSL https://get.docker.com | sh` +```bash +curl -sSL https://get.docker.com | sh +``` ### Building the Image The Docker image is not available at the moment on the Docker hub, as a result, you need to compile it using the following command: -`docker build -t gtviples/verne .` +```bash +docker build -t gtviples/verne . +``` ### Installing and Running -To run the project, a container must be created with this image and the correct parameters, including the unless-stopped restart policy and the correct volume links to any devices. For example: +To run the project, a container must be created with this image and the correct parameters. For example: -``` +```bash docker create \ --name=verne --device /dev/ttyAMA0 \ --device /dev/i2c-1 \ -v /home/pi/vernedata:/data \ - --restart=on-failure \ gtviples/verne ``` Then, the container can be started and stopped using the `docker start verne` and `docker stop verne` commands. +Note that we are not running this container with a restart policy because of the fact that we want the code to run just once. +As a result, we need another way of making sure that the container is started on startup. + +We start by making sure that the responsibility of starting docker is on systemd and not on upstart: + +```bash +echo manual | sudo tee /etc/init/docker.override +sudo systemctl enable docker +``` + +We will use a systemd service setup to ensure that our container is run on boot. Create a file `/etc/systemd/system/verne.service` with the following contents: +``` +[Unit] +Description=Verne +Requires=docker.service +After=docker.service + +[Service] +Restart=no +ExecStart=/usr/bin/docker start -a verne +ExecStop=/usr/bin/docker stop -t 5 verne + +[Install] +WantedBy=default.target +``` +For convenience, this file is provided in the repository so that you can just copy and paste it. + +To run the service, do the following: +``` +systemctl daemon-reload +systemctl start verne.service +``` + +And to set it to start on startup, do the following: +```bash +systemctl enable verne.service +``` + +The script can be built using `sudo ./scripts/build-image.sh`, the container can be created using `sudo ./scripts/create-container.sh` and the startup settings can be configured using `sudo ./scripts/startup-config.sh` + ## Built With * [Docker](https://www.docker.com/) - The container-based deployment system diff --git a/main.py b/main.py index 3a2ffad..6585072 100644 --- a/main.py +++ b/main.py @@ -12,16 +12,6 @@ fileDir = os.path.dirname(os.path.realpath(__file__)) CONFIG_PATH = "/data/config.yml" -class GracefulKiller: - kill_now = False - - def __init__(self): - signal.signal(signal.SIGINT, self.exit_gracefully) - signal.signal(signal.SIGTERM, self.exit_gracefully) - - def exit_gracefully(self, signum, frame): - self.kill_now = True - def getSmallestCSVFileNumberGreaterThan(currentFile, modules): # If files exist, we want to find an int at which file-i does not exist, and increment it # once more to make it clear that this is from a new recording. @@ -41,7 +31,7 @@ def getCSVFilesFromModules(modules, missionTime, i): csvs = {} for m in modules.keys(): f = open('/data/%s-%d.csv' % (m, i), 'wb') - writer = csv.writer(f, delimiter=' ', quotechar='|', quoting=csv.QUOTE_MINIMAL) + writer = csv.writer(f, delimiter=', ', quotechar='|', quoting=csv.QUOTE_MINIMAL) printableMissionTime = missionTime - datetime.fromtimestamp(0) writer.writerow([int(printableMissionTime.total_seconds() * 1000)]) @@ -55,8 +45,6 @@ def closeCSVFiles(csvs): c[0].close() if __name__ == '__main__': - killer = GracefulKiller() - # Initialize the logger logging.basicConfig(level=logging.INFO) logger = logging.getLogger("verne") @@ -131,46 +119,40 @@ def death(error): timeToRenewFile = missionTime + timedelta(hours=cutFileAfterHours) currentFile = getSmallestCSVFileNumberGreaterThan(0, modules) + currentFile += 1 # So that we get a gap from the last time this script was run + + logger.info("Creating initial CSV files. File number: %d" % currentFile) csvs = getCSVFilesFromModules(modules, missionTime, currentFile) logger.info("Liftoff: starting recording.") - forcedStop = False - while True: - currentTime = datetime.now() - missionElapsedTime = int((currentTime - missionTime).total_seconds() * 1000) - - if currentTime > timeToKill: - # It's time to end the recording! Goodbye! - forcedStop = False - break + try: + while True: + currentTime = datetime.now() + missionElapsedTime = int((currentTime - missionTime).total_seconds() * 1000) - if currentTime > timeToRenewFile: - closeCSVFiles(csvs) + if currentTime > timeToKill: + # It's time to end the recording! Goodbye! + break - currentFile = getSmallestCSVFileNumberGreaterThan(currentFile, modules) - csvs = getCSVFilesFromModules(modules, missionTime, currentFile) + if currentTime > timeToRenewFile: + closeCSVFiles(csvs) - timeToRenewFile = currentTime + timedelta(hours=cutFileAfterHours) - logger.info("File cutoff time reached. New file number: %d" % currentFile) + currentFile = getSmallestCSVFileNumberGreaterThan(currentFile, modules) + csvs = getCSVFilesFromModules(modules, missionTime, currentFile) - for m in modules.keys(): - data = modules[m].poll(missionElapsedTime) + timeToRenewFile = currentTime + timedelta(hours=cutFileAfterHours) + logger.info("File cutoff time reached. New file number: %d" % currentFile) - if data is not None and len(data) > 0: - writer = csvs[m][1] + for m in modules.keys(): + data = modules[m].poll(missionElapsedTime) - for datum in data: - writer.writerow([missionElapsedTime] + list(datum)) - - if killer.kill_now: - forcedStop = True - break + if data is not None and len(data) > 0: + writer = csvs[m][1] - closeCSVFiles(csvs) - if forcedStop: - logger.info("The script has been force-stopped. Maybe restart it?") - sys.exit(1) - else: + for datum in data: + writer.writerow([missionElapsedTime] + list(datum)) + finally: + closeCSVFiles(csvs) logger.info("The eagle has landed: stopping recording. Goodbye!") sys.exit(0) \ No newline at end of file diff --git a/scripts/build-image.sh b/scripts/build-image.sh new file mode 100644 index 0000000..e2b29c2 --- /dev/null +++ b/scripts/build-image.sh @@ -0,0 +1,4 @@ +#!/bin/sh +set -ex #Fail if any line fails, print everything + +docker build -t gtviples/verne . \ No newline at end of file diff --git a/scripts/create-container.sh b/scripts/create-container.sh new file mode 100644 index 0000000..519c3c4 --- /dev/null +++ b/scripts/create-container.sh @@ -0,0 +1,4 @@ +#!/bin/sh +set -ex #Fail if any line fails, print everything + +docker create --name=verne --device /dev/ttyAMA0 --device /dev/i2c-1 -v /home/pi/vernedata:/data gtviples/verne \ No newline at end of file diff --git a/scripts/startup-config.sh b/scripts/startup-config.sh new file mode 100644 index 0000000..4f8d66c --- /dev/null +++ b/scripts/startup-config.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -ex #Fail if any line fails, print everything + +SCRIPTDIR="$(dirname "$0")" + +# Copy the service +\cp -rf "$SCRIPTDIR/../verne.service" /etc/systemd/system/ + +# Reload systemd +systemctl daemon-reload + +# Add it to startup +systemctl enable verne.service \ No newline at end of file diff --git a/verne.service b/verne.service new file mode 100644 index 0000000..c7a1d1b --- /dev/null +++ b/verne.service @@ -0,0 +1,12 @@ +[Unit] +Description=Verne +Requires=docker.service +After=docker.service + +[Service] +Restart=no +ExecStart=/usr/bin/docker start -a verne +ExecStop=/usr/bin/docker stop -t 5 verne + +[Install] +WantedBy=default.target \ No newline at end of file