Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Settings and Python Logging #5

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 59 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

Copyright (C) 2014-2015 Jaguar Land Rover
Copyright (C) 2015,2016 Jaguar Land Rover

This document is licensed under Creative Commons
Attribution-ShareAlike 4.0 International.
Expand Down Expand Up @@ -117,23 +117,68 @@ LocMedMgr | Local Media Manager



# RUNNING THE CODE ON UBUNTU 14.10 AND 15.10
# INSTALLATION AND CONFIGURATION

## Install python and add ons.
## Installation on Debian and Ubuntu

Make sure you have Python 2.7 (or later 2.X) installed.

Install the necessary python libraries

sudo apt-get install python-gtk2
sudo apt-get install python-gtk2 python-storm

## Installation on Fedora

Make sure you have Python 2.7 (or later 2.X) installed.

Install the necessary python libraries

sudo dnf install python-gtk2 python-storm

## Configuration (All Distributions)

All configuration is accomplished by changing the configuration variables in ```common/settings.py```.

Common settings are:

* SWM_SIMULATION:
If set to ```True``` SWM runs in simulation mode. In this mode FUSE and
squashfuse are used to mount the SquashFS archive containing the update.
If set to ```False``` SWM must be run as root.

* SWM_SIMULATION_WAIT:
Time in seconds to wait for simulated operations.

* DB_URL:
SWM maintains update information in a SQLite database. This variable sets
path and name of the database file.

* LOGGER:
The standard logger is ```swm.default```, which outputs logging information
to the console and to the file specified by ```LOGFILE```. Other loggers are
```swm.console``` which outputs to the console only and ```swm.file``` which
outputs to a log file only.

* LOGFILE:
Path and name to the log file.


# RUNNING

## Launch SWM components
In a terminal window, run a fully automated demo using:

sudo sh start_swm.sh -r

```sudo``` is needed since the sample_update.upd file is a squashfs image that needs to be mounted.
```sudo``` is needed only if running in *real mode* with ```SWM_SIMULATION = False``` in ```common/settings.py```.

**WARNING:** When running in *real mode* SWM attempts to install the software package nano on the system. The
```start_swm.sh``` script figures out what distribution it is running on and chooses an RPM (Fedora) or DEB (Debian and Ubuntu)
software update to execute.

When running in *simulation mode*, you need to have Filesystem in User Space (FUSE) and squashfuse installed on your system.
FUSE is standard for virtually all Linux distributions, including Debian, Fedora and Ubuntu. squashfuse is not a standard
package and the distributions do not have it in their repositories. However, it can easily be compiled from source which can
be found at https://github.com/vasi/squashfuse.

```-r``` Specifies that the database storing already processed software operations (hosted in an update) should
be reset. If that is not done, subsequent runs will all return "Already processed"
Expand All @@ -145,8 +190,14 @@ and control the actions.
Each launched component will get their own terminal window.

## Watch execution
The system will execute the manifest from ```sample_update/update_manifest.json```, stored in the
```sample_update.upd``` squashfs image of the ```sample_update``` directory.
When running in *simulation mode* the system will execute the manifest from ```sample_update/update_manifest.json```,
stored in the ```sample_update.upd``` squashfs image of the ```sample_update``` directory.

When running in *real mode* the system will determine what distribution it is running on and then:
* if running on Fedora, execute the manifest from ```rpm_update/update_manifest.json```, stored in the ```rpm_update.upd```
squashfs image of the ```rpm_update``` directory;
* if running on Debian or Ubuntu, execute the manifest from ```deb_update/update_manifest.json```, stored in the ```deb_update.upd```
squashfs image of the ```deb_update``` directory.

During the execution the HMI window will show an overall progress bar and a progress bar for each
software operation carried out.
Expand Down
145 changes: 145 additions & 0 deletions common/daemon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
"""
Copyright (C) 2014, Jaguar Land Rover

This program is licensed under the terms and conditions of the
Mozilla Public License, version 2.0. The full text of the
Mozilla Public License is at https://www.mozilla.org/MPL/2.0/

Adapted from http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/

Maintainer: Rudolf Streif ([email protected])
"""

"""
Base class to create Linux daemons.
"""

import os, sys, atexit, time
from signal import *


class Daemon(object):
"""
A generic daemon class.
Usage: subclass the Daemon class and override the run() method
"""
def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
self.stdin = stdin
self.stdout = stdout
self.stderr = stderr
self.pidfile = pidfile

def daemonize(self):
"""
do the UNIX double-fork magic, see Stevens' "Advanced
Programming in the UNIX Environment" for details (ISBN 0201563177)
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
"""
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError, e:
sys.stderr.write("Daemon: Fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)

# decouple from parent environment
os.chdir("/")
os.setsid()
os.umask(0)

# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
sys.exit(0)
except OSError, e:
sys.stderr.write("Daemon: Fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)

# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = file(self.stdin, 'r')
so = file(self.stdout, 'a+')
se = file(self.stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())

# write pidfile
atexit.register(self.delpid)
pid = str(os.getpid())
file(self.pidfile,'w+').write("%s\n" % pid)

def delpid(self):
os.remove(self.pidfile)

def start(self):
"""
Start the daemon
"""
# Check for a pidfile to see if the daemon already runs
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None

if pid:
message = "Daemon: Pidfile %s already exist. Daemon already running?\n"
sys.stderr.write(message % self.pidfile)
sys.exit(1)

# Start the daemon
self.daemonize()
self.run()

def stop(self):
"""
Stop the daemon
"""
# Get the pid from the pidfile
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None

if not pid:
message = "Daemon: Pidfile %s does not exist. Daemon not running?\n"
sys.stderr.write(message % self.pidfile)
return # not an error in a restart

# Try killing the daemon process
try:
while 1:
os.kill(pid, SIGTERM)
time.sleep(0.1)
except OSError, err:
err = str(err)
if err.find("No such process") > 0:
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
message = "Daemon: Error shutting down: %s\n"
sys.stderr.write(message % err)
sys.exit(1)

def restart(self):
"""
Restart the daemon
"""
self.stop()
self.start()

def run(self):
"""
You should override this method when you subclass Daemon. It will be called after the process has been
daemonized by start() or restart().
"""

Loading