* [gentoo-commits] proj/grss:master commit in: grs/, tests/
@ 2015-07-09 23:05 Anthony G. Basile
0 siblings, 0 replies; 3+ messages in thread
From: Anthony G. Basile @ 2015-07-09 23:05 UTC (permalink / raw
To: gentoo-commits
commit: a83efe19256bf9d63a5039e7448155531cf56ee3
Author: Anthony G. Basile <blueness <AT> gentoo <DOT> org>
AuthorDate: Thu Jul 9 23:08:08 2015 +0000
Commit: Anthony G. Basile <blueness <AT> gentoo <DOT> org>
CommitDate: Thu Jul 9 23:08:08 2015 +0000
URL: https://gitweb.gentoo.org/proj/grss.git/commit/?id=a83efe19
grs/Rotator.py: document and improve.
grs/Log.py | 6 ++----
grs/PivotChroot.py | 3 +--
grs/Rotator.py | 38 ++++++++++++++++++++++++++++++++------
grs/Seed.py | 4 +---
tests/test-log.py | 31 +++++++++++++++++++++----------
5 files changed, 57 insertions(+), 25 deletions(-)
diff --git a/grs/Log.py b/grs/Log.py
index 201eeb9..5a87a92 100644
--- a/grs/Log.py
+++ b/grs/Log.py
@@ -26,8 +26,6 @@ class Log(Rotator):
f.write('%s\n' % msg)
- def rotate_logs(self):
- self.rotate(self.logfile)
- if os.path.isfile(self.logfile):
- shutil.move(self.logfile, '%s.0' % self.logfile)
+ def rotate_logs(self, upper_limit = 20):
+ self.full_rotate(self.logfile, upper_limit=upper_limit)
open('%s' % self.logfile, 'a').close()
diff --git a/grs/PivotChroot.py b/grs/PivotChroot.py
index ff0fb69..cbfb29f 100644
--- a/grs/PivotChroot.py
+++ b/grs/PivotChroot.py
@@ -35,8 +35,7 @@ class PivotChroot(Rotator):
# Move portage_configroot out of the way to system.0,
# then pivot out the inner chroot to system.
- self.rotate(self.portage_configroot)
- shutil.move(self.portage_configroot, '%s.0' % self.portage_configroot)
+ self.full_rotate(self.portage_configroot)
inner_chroot = os.path.join('%s.0' % self.portage_configroot, subchroot)
shutil.move(inner_chroot, os.path.join(self.tmpdir, 'system'))
diff --git a/grs/Rotator.py b/grs/Rotator.py
index d82c9fd..0dccdf8 100644
--- a/grs/Rotator.py
+++ b/grs/Rotator.py
@@ -2,16 +2,29 @@
import glob
import re
+import os
import shutil
class Rotator():
- """ doc here
- more doc
- """
+ """ Super class for rotating files or directories. """
- def rotate(self, obj):
- """ doc here
- more doc
+ def rotate(self, obj, upper_limit = 20):
+ """ Does the work of rotating objects fitting the pattern obj.(d+).
+
+ obj -> The absolute path to the objects to be rotated. The
+ obj's are assumed to have a pattern obj.(d+) and does NOT
+ include a bare obj not followed by a decimal. (For that,
+ use full_rotate() below). Note that gaps in numbers are
+ are preserved. Eg.
+
+ Old Name New Name
+ log (untouched)
+ log.0 log.1
+ log.1 log.2
+ log.3 log.4 (Note the gap is preserved.)
+ log.4 log.5
+
+ obj's paste an upper limit are deleted.
"""
objs = glob.glob('%s.*' % obj)
indexed_obj = {}
@@ -23,6 +36,19 @@ class Rotator():
count.reverse()
for c in count:
current_obj = indexed_obj[c]
+ if c >= upper_limit:
+ try:
+ shutil.rmtree(current_obj)
+ except NotADirectoryError:
+ os.unlink(current_obj)
+ continue
m = re.search('^(.+)\.\d+$', current_obj)
next_obj = '%s.%d' % (m.group(1), c+1)
shutil.move(current_obj, next_obj)
+
+
+ def full_rotate(self, obj, upper_limit = 20):
+ """ Rotate both obj and obj.(d+). """
+ self.rotate(obj, upper_limit = upper_limit)
+ if os.path.exists(obj):
+ shutil.move(obj, '%s.0' % obj)
diff --git a/grs/Seed.py b/grs/Seed.py
index aad5d20..1ce5f48 100644
--- a/grs/Seed.py
+++ b/grs/Seed.py
@@ -35,9 +35,7 @@ class Seed(Rotator):
"""
# Rotate the old portage_configroot and package out of the way
for directory in [self.portage_configroot, self.package]:
- self.rotate(directory)
- if os.path.isdir(directory):
- shutil.move(directory, '%s.0' % directory)
+ self.full_rotate(directory)
os.makedirs(directory, mode=0o755, exist_ok=False)
# Download a stage tarball if we don't have one
diff --git a/tests/test-log.py b/tests/test-log.py
index f132ca0..b419fbb 100755
--- a/tests/test-log.py
+++ b/tests/test-log.py
@@ -10,16 +10,10 @@ from grs import Log
logdir = '/tmp/test-log'
-def doit(stamped = False):
- if os.path.isdir(logdir):
- shutil.rmtree(logdir)
- os.makedirs(logdir)
- logfile = os.path.join(logdir, 'test.log')
-
- lo = Log(logfile)
+def doit(lo, stamped = False):
+ # Create a log with knowing contents and rotate 3 times.
for i in range(10):
lo.log('first %d' % i, stamped)
-
lo.rotate_logs()
lo.rotate_logs()
lo.rotate_logs()
@@ -28,6 +22,7 @@ def doit(stamped = False):
def hashtest(expect_pass = True):
+ # Hash up our log and three rotations. Do we get what we expected?
m = hashlib.md5()
for i in [ '', '.0', '.1', '.2']:
log = os.path.join(logdir, 'test.log%s' % i)
@@ -39,7 +34,23 @@ def hashtest(expect_pass = True):
assert(m.hexdigest() != '485b8bf3a9e08bd5ccfdff7e1a8fe4e1')
if __name__ == "__main__":
- doit(stamped=False)
+ if os.path.isdir(logdir):
+ shutil.rmtree(logdir)
+ os.makedirs(logdir)
+ logfile = os.path.join(logdir, 'test.log')
+ lo = Log(logfile)
+
+ doit(lo, stamped=False)
hashtest(expect_pass=True)
- doit(stamped=True)
+ doit(lo, stamped=True)
hashtest(expect_pass=False)
+
+ # Make sure we're dropping past the upper limit.
+ lo.rotate_logs(upper_limit=2)
+ assert(os.path.isfile(logfile))
+ assert(os.path.isfile(logfile+'.0'))
+ assert(os.path.isfile(logfile+'.1'))
+ assert(os.path.isfile(logfile+'.2'))
+ assert(not os.path.isfile(logfile+'.3'))
+ assert(not os.path.isfile(logfile+'.4'))
+ assert(not os.path.isfile(logfile+'.5'))
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [gentoo-commits] proj/grss:master commit in: grs/, tests/
@ 2015-07-10 1:23 Anthony G. Basile
0 siblings, 0 replies; 3+ messages in thread
From: Anthony G. Basile @ 2015-07-10 1:23 UTC (permalink / raw
To: gentoo-commits
commit: 07baec53eaadb095a61f9c6c6f21109a20f4cad6
Author: Anthony G. Basile <blueness <AT> gentoo <DOT> org>
AuthorDate: Fri Jul 10 01:25:50 2015 +0000
Commit: Anthony G. Basile <blueness <AT> gentoo <DOT> org>
CommitDate: Fri Jul 10 01:25:50 2015 +0000
URL: https://gitweb.gentoo.org/proj/grss.git/commit/?id=07baec53
grs/Constants.py: add documentation.
grs/Constants.py | 82 ++++++++++++++++++++++++++++++++++++++++++++----------
tests/systems.conf | 1 -
2 files changed, 68 insertions(+), 15 deletions(-)
diff --git a/grs/Constants.py b/grs/Constants.py
index 501d79d..b9ea1d9 100644
--- a/grs/Constants.py
+++ b/grs/Constants.py
@@ -5,30 +5,62 @@ import sys
import configparser
from copy import deepcopy
-CONFIG = '/etc/grs/systems.conf'
class Constants():
- """ doc here
- more doc
+ """ Read a global configuration file and set/override constants for
+ each GRS spec. These constants are exported in the form:
+
+ CONST.nameservers[x] contains the namserver for the xth GRS spec
+ CONST.repo_uris[x] contains the repo_uri for the xth GRS spec
+ etc.
+
+ Notice the 's' added to the list name to distinguish the list from
+ the constant it holds. Here the x is an integer corresponding to a
+ section in a global config file, which by default is located at
+ '/etc/grs/systes.conf'. This file is in configparser format and
+ each section introduces a new GRS namespace. The default values
+ for all possible constants in any given GRS namespace are defined
+ by the space[] dictionary below, but these can be overridden using
+ the item:value pairs from the section of any given GRS namespace.
+ E.g. Suppose /etc/grs/systems.conf contains
+
+ [my-cool-desktop]
+ kernelroot : /tmp/kernel_src_tree
+
+ [my-cool-server]
+ nameserver : 192.168.100.1
+
+ Then CONST.kernelroots[0] is '/tmp/kernel_src_tree' rather than the
+ default value '/var/tmp/grs/my-cool-desktop/kernel'. The remainder
+ of the constants default as delineated in the space[] dictionary with
+ %s replaced by 'my-cool-desktop'. Similarly CONST.my-cool-servers[1]
+ is 192.168.100.1 rather than 8.8.8.8.
+
+ Finally, the that class overrides __setattr__, __gettattr__ and
+ __delattr__ so that you cannot add/change/delete constants in
+ a GRS namespace.
"""
- def __init__(self, configfile = CONFIG):
+ def __init__(self, configfile = '/etc/grs/systems.conf'):
+ # If there's no config file, we're dead in the water.
if not os.path.isfile(configfile):
- sys.stderr.write('Configuration file %s not found\n' % configfile)
- sys.exit(1)
+ raise Exception('Configuration file %s not found\n' % configfile)
+
self.config = configparser.ConfigParser(delimiters = ':', comment_prefixes = '#')
self.config.read(configfile)
- self.names = list(self.config.sections())
-
+ # These values will probably fail in the future, but that's okay
+ # because they really should never be used. They live outside of
+ # any GRS namespace and are just 'defaults'.
server = 'http://distfiles.gentoo.org/'
- stagedir = 'gentoo/releases/amd64/autobuilds/current-stage3-amd64-uclibc-hardened/'
+ stagedir = 'releases/amd64/autobuilds/current-stage3-amd64-uclibc-hardened/'
stagefile = 'stage3-amd64-uclibc-hardened-20150510.tar.bz2'
default_stage_uri = server + stagedir + stagefile
+ # This is the space of all possible constants for any given GRS namespace
space = {
'nameserver' : '8.8.8.8',
- 'repo_uri' : 'git://tweedledum.dyc.edu/grs',
+ 'repo_uri' : 'git://anongit.gentoo.org/proj/grs.git',
'stage_uri' : default_stage_uri,
'libdir' : '/var/lib/grs/%s',
'logfile' : '/var/log/grs/%s.log',
@@ -40,49 +72,70 @@ class Constants():
'pidfile' : '/run/grs-%s.pid'
}
+ # We add an 's' to each list for a particular constant,
+ # and initialize the list to be empty.
for key in space:
self.__dict__[key+'s'] = []
+ # Each section is a 'namespace' corresponding to each GRS spec.
+ # We export these in the CONST.names[] list.
+ self.names = list(self.config.sections())
+
+ # We go over all the sections in the config file. The
+ # order here had better be the same as self.names[], else
+ # CONST.names[x] doesn't corresponde to the other CONST.foo[x]
+ # for every x.
for section in self.config.sections():
overrides = dict(self.config[section].items())
+ # Either we have an override value from the config
+ # file, else we contruct a default name.
for key in space:
if key in overrides:
value = overrides[key]
else:
+ # Either the default name has a slot %s to
+ # file or else it doesn't.
try:
value = space[key] % section
except TypeError:
value = space[key]
+ # We're counting on the order in which we append here to
+ # correspond to the GRS namespace for the key:value pair.
self.__dict__[key+'s'].append(value)
+ # Allow CONST.foo = bar only once!
def __setattr__(self, key, value):
if not key in self.__dict__:
self.__dict__[key] = value
else:
pass
-
+ # Don't retrieve the original else you can overwrite it,
+ # rather deep copy it.
def __getattr__(self, key, value = None):
if key in self.__dict__:
return deepcopy(self.__dict__[key])
-
+ # You can't del(CONST.foo).
def __delattr__(self, key):
if key in self.__dict__:
pass
+# Instantiate once and export all our constant in CONST.
CONST = Constants()
+# Constants outside any GRS namespace.
CONST.PACKAGE_NAME = "Gentoo Reference System"
CONST.PACKAGE_VERSION = 0.0
CONST.PACKAGE_DESCRIPTION = "Update a GRS by cloning a predefined system."
CONST.BUG_REPORTS = 'http://bugs.gentoo.org'
-# The are defaults in case objects are instantiated without namespaces
-# but they should not be used under normal working condidtions.
+# The are defaults in case objects of other classes which depend on values
+# of libdir, logfile, etc. are instantiated outside of any namespaces.
+# They should not be needed under normal working condidtions.
CONST.LIBDIR = '/var/lib/grs'
CONST.LOGFILE = '/var/log/grs.log'
CONST.TMPDIR = '/var/tmp/grs'
@@ -92,6 +145,7 @@ CONST.KERNELROOT = '/var/tmp/grs/kernel'
CONST.PORTAGE_CONFIGROOT = '/var/tmp/grs/system'
CONST.PIDFILE = '/run/grs.pid'
+# These are used by grsup and are hard coded values.
CONST.PORTAGE_CONFIGDIR = '/etc/portage'
CONST.PORTAGE_DIRTYFILE = '/etc/portage/.grs_dirty'
CONST.WORLD_CONFIG = '/etc/grs/world.conf'
diff --git a/tests/systems.conf b/tests/systems.conf
deleted file mode 120000
index b92ef4f..0000000
--- a/tests/systems.conf
+++ /dev/null
@@ -1 +0,0 @@
-../systems.conf
\ No newline at end of file
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [gentoo-commits] proj/grss:master commit in: grs/, tests/
@ 2015-07-10 19:07 Anthony G. Basile
0 siblings, 0 replies; 3+ messages in thread
From: Anthony G. Basile @ 2015-07-10 19:07 UTC (permalink / raw
To: gentoo-commits
commit: 3905cabb9652305dcd220b96bb53d8d1617d30ca
Author: Anthony G. Basile <blueness <AT> gentoo <DOT> org>
AuthorDate: Fri Jul 10 19:09:48 2015 +0000
Commit: Anthony G. Basile <blueness <AT> gentoo <DOT> org>
CommitDate: Fri Jul 10 19:09:48 2015 +0000
URL: https://gitweb.gentoo.org/proj/grss.git/commit/?id=3905cabb
grs/Daemon.py: remove unused stop() and restart().
grs/Daemon.py | 73 ++++++++++------------------------------------------
tests/test-daemon.py | 12 ++-------
2 files changed, 16 insertions(+), 69 deletions(-)
diff --git a/grs/Daemon.py b/grs/Daemon.py
index 0d2d988..38b7d9a 100644
--- a/grs/Daemon.py
+++ b/grs/Daemon.py
@@ -11,12 +11,12 @@ class Daemon:
See: http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
To use, inherit by a subclass which overrides run() and does all the
- daemon work. You start the daemon with
+ work. You start the daemon with
- d = MyDaemon(pidfile, foo='1', bar='2') # Any number for kwargs after pidfile
+ d = MyDaemon(pidfile, foo='1', bar='2') # Any **kwargs after pidfile
d.start() # to start the daemon
- d.restart() # to restart the daemon
- d.stop() # to stop the daemon
+
+ All signal handling should be defined in a subfunction within run().
Note: This isn't completely general daemon code as it doesn't close stdout/stderr.
Rather these are redirected to /var/log/grs/grs-daemon-<pid>.err to capture any
@@ -24,13 +24,13 @@ class Daemon:
"""
def __init__(self, pidfile, **kwargs):
- """ Since this will be used as a super class, we'll accept any **kwargs
- and insert them to our internal __dict__.
- """
+ # Since this will be used as a super class, we'll accept any **kwargs
+ # and insert them to our internal __dict__.
self.pidfile = pidfile
for k in kwargs:
self.__dict__[k] = kwargs[k]
+
def daemonize(self):
try:
pid = os.fork()
@@ -76,11 +76,14 @@ class Daemon:
os.remove(self.pidfile)
+ def run(self):
+ pass
+
+
def start(self):
- # If there's a pidfile when we try to startup, then either
- # its stale or we're already running. If the pidfile is stale,
- # remove it and startup as usual. If we're already running,
- # then don't start a second instance.
+ # If there's a pidfile when we try to startup, then:
+ # 1) If the pidfile is stale, remove it and startup as usual.
+ # 2) If we're already running, then don't start a second instance.
try:
with open(self.pidfile, 'r') as pf:
pid = int(pf.read().strip())
@@ -97,51 +100,3 @@ class Daemon:
self.daemonize()
self.run()
-
-
- def stop(self):
- # Try to open our pidfile and read our pid. If you have a pid but
- # there is no process at that pid, then we're not running and all
- # we have to do is cleanup our stale pidfile.a If we can't get a
- # pid from our pidfile, then we've lost the original process. Either
- # it crashed or something else killed the pidfile. We don't know.
- # Finally if have a valid pid, send it a bunch of SIGTERMS followed
- # by SIGKILLS just in case.
- try:
- with open(self.pidfile,'r') as pf:
- pid = int(pf.read().strip())
- except IOError:
- pid = None
-
- if pid and not os.path.exists('/proc/%d' % pid):
- sys.stderr.write('process not running\n')
- sys.stderr.write('unlinking stale pid file %s\n' % self.pidfile)
- os.unlink(self.pidfile)
- return
-
- if not pid:
- sys.stderr.write('process not running\n')
- return # not an error in a restart
-
- try:
- for i in range(10):
- os.kill(pid, signal.SIGTERM)
- time.sleep(0.2)
- while True:
- os.kill(pid, signal.SIGKILL)
- time.sleep(0.2)
- except ProcessLookupError as err:
- try:
- os.remove(self.pidfile)
- except IOError as err:
- sys.stderr.write('%s\n' % err)
- except OSError as err:
- sys.stderr.write('%s\n' %err)
- return
-
- def restart(self):
- self.stop()
- self.start()
-
- def run(self):
- pass
diff --git a/tests/test-daemon.py b/tests/test-daemon.py
index 27300e2..f121dae 100755
--- a/tests/test-daemon.py
+++ b/tests/test-daemon.py
@@ -46,26 +46,18 @@ if __name__ == "__main__":
Execute(cmd)
if len(sys.argv) != 2:
- print('%s [start1 start2 startb stop1 stop2 restart1 restart2 pids killall]' % sys.argv[0])
+ print('%s [start1 start2 start12 pids killall]' % sys.argv[0])
sys.exit(1)
if 'start1' == sys.argv[1]:
daemon1.start()
elif 'start2' == sys.argv[1]:
daemon2.start()
- elif 'startb' == sys.argv[1]:
+ elif 'start12' == sys.argv[1]:
if not os.fork():
daemon1.start()
elif not os.fork():
daemon2.start()
- elif 'stop1' == sys.argv[1]:
- daemon1.stop()
- elif 'stop2' == sys.argv[1]:
- daemon2.stop()
- elif 'restart1' == sys.argv[1]:
- daemon1.restart()
- elif 'restart2' == sys.argv[1]:
- daemon2.restart()
elif 'pids' == sys.argv[1]:
try:
print('daemon1:\n%s' % open(mypid1, 'r').read())
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2015-07-10 19:07 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-10 1:23 [gentoo-commits] proj/grss:master commit in: grs/, tests/ Anthony G. Basile
-- strict thread matches above, loose matches on Subject: below --
2015-07-10 19:07 Anthony G. Basile
2015-07-09 23:05 Anthony G. Basile
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox