Commit 6501cf07 authored by David Johnson's avatar David Johnson

Pythonize the whole library so that PYTHONPATH and module paths are sane.

There are a couple bugfixes in here -- there was a bad call to
super().__init__ that passed self as the first arg.  I also removed the
config file manager_class and helper_class defaults.

Also updates the slurm module and adds important notes about subclassing
both an existing helper and manager inside of a single class... method
resolution order is important!  See the slurm module, or the new docs
for SimpleElasticSliceManager for that.
parent d538b17a
*.pyc *.pyc
This diff is collapsed.
import logging import logging
from manager import SimpleElasticSliceManager, SimpleElasticSliceHelper from elasticslice.managers.core import SimpleElasticSliceHelper, \
from util import ShellCommand SimpleElasticSliceManager
from elasticslice.util.util import ShellCommand
...@@ -11,7 +12,15 @@ YEAR = DAY * 365 ...@@ -11,7 +12,15 @@ YEAR = DAY * 365
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class SlurmDynamicManager(SimpleElasticSliceManager, SimpleElasticSliceHelper): #
# NB: it is very important that, as documented, SimpleElasticSliceHelper
# is the first class here, so that its methods override those of
# SimpleElasticSliceManager. Why? Because SimpleElasticSliceManager is
# also a helper -- it is a PluginElasticSliceHelper, which means it
# accepts a plugin helper, and doesn't have any functionality of its own
# (other than to call the the plugin helper object's methods).
class SlurmDynamicManager(SimpleElasticSliceHelper,SimpleElasticSliceManager):
DEF_ORDER = [ 'ensure_slice','ensure_sliver','update_sliver_status', DEF_ORDER = [ 'ensure_slice','ensure_sliver','update_sliver_status',
'renew','update_available','update_all','get_system_state', 'renew','update_available','update_all','get_system_state',
...@@ -22,10 +31,10 @@ class SlurmDynamicManager(SimpleElasticSliceManager, SimpleElasticSliceHelper): ...@@ -22,10 +31,10 @@ class SlurmDynamicManager(SimpleElasticSliceManager, SimpleElasticSliceHelper):
add_nodes=5 * MINUTE,delete_nodes=5 * MINUTE) add_nodes=5 * MINUTE,delete_nodes=5 * MINUTE)
def __init__(self,server,config=None): def __init__(self,server,config=None):
SimpleElasticSliceManager.__init__(self,server,config=config, SimpleElasticSliceManager.__init__(self,server,config=config,
manage_order=SlurmDynamicManager.DEF_ORDER, manage_order=SlurmDynamicManager.DEF_ORDER,
manage_intervals=SlurmDynamicManager.DEF_INTERVALS) manage_intervals=SlurmDynamicManager.DEF_INTERVALS)
self.slurm = SlurmScheduler() self.slurm = SlurmScheduler()
# Manager functions redefined: # Manager functions redefined:
...@@ -4,7 +4,7 @@ import os ...@@ -4,7 +4,7 @@ import os
import traceback import traceback
import time import time
import threading import threading
from protogeniclientlib import ProtoGeniClientDefs, ProtoGeniServer, \ from elasticslice.rpc.protogeni import ProtoGeniClientDefs, ProtoGeniServer, \
ProtoGeniResponse, ProtoGeniManifestWrapper, \ ProtoGeniResponse, ProtoGeniManifestWrapper, \
ProtoGeniClientServerEndpoint, ProtoGeniClientServer, SENDMAIL ProtoGeniClientServerEndpoint, ProtoGeniClientServer, SENDMAIL
import geni.rspec.pgad as RSpecAd import geni.rspec.pgad as RSpecAd
...@@ -157,7 +157,7 @@ class SimpleElasticSliceHelper(ElasticSliceHelper): ...@@ -157,7 +157,7 @@ class SimpleElasticSliceHelper(ElasticSliceHelper):
num_pcs=1,image_urn=None,num_lans=0,multiplex_lans=False, num_pcs=1,image_urn=None,num_lans=0,multiplex_lans=False,
tarballs=[],startup_command=None,nodetype=None, tarballs=[],startup_command=None,nodetype=None,
node_prefix="node",lan_prefix="lan"): node_prefix="node",lan_prefix="lan"):
super(SimpleElasticSliceHelper,self).__init__(self,server) super(SimpleElasticSliceHelper,self).__init__(server)
self.config = config self.config = config
self.rspec = RSpec.Request() self.rspec = RSpec.Request()
...@@ -789,13 +789,36 @@ class SimpleElasticSliceManager(ElasticSliceManager, ...@@ -789,13 +789,36 @@ class SimpleElasticSliceManager(ElasticSliceManager,
ElasticSliceManager locks using a per-instance threading.RLock. ElasticSliceManager locks using a per-instance threading.RLock.
Thus, once one thread has the lock, they're good. Thus, once one thread has the lock, they're good.
If you subclass SimpleElasticSliceManager, and want to replace its
helper functions, it is very important that you first subclass
whatever helper class you're extending, then
SimpleElasticSliceManager. For instance,
class FooManager(SimpleElasticSliceHelper,SimpleElasticSliceManager):
Why? Because that makes the method resolution order inside of FooManager
be FooManager, SimpleElasticSliceHelper, SimpleElasticSliceManager ... .
If you instead tried to do the reverse:
class FooManager(SimpleElasticSliceManager,SimpleElasticSliceHelper):
the method resolution order would be FooManager, SimpleElasticSliceManager,
SimpleElasticSliceHelper. Because SimpleElasticSliceManager provides an
implementation of each method in the ElasticSliceHelper interface, those
methods will be called, and those from SimpleElasticSliceHelper will never
be called (which defeats the point, that you hoped to re-use the helper
methods from SimpleElasticSliceHelper). So consider method resolution
order! Helpers are not mixins, because an ElasticSliceManager is also
an ElasticSliceHelper! This is an OO multiple inheritance style, not a
mixin style.
""" """
def __init__(self,server,config=None, def __init__(self,server,config=None,
minthreshold=DEF_MIN_THRESHOLD,maxthreshold=DEF_MAX_THRESHOLD, minthreshold=DEF_MIN_THRESHOLD,maxthreshold=DEF_MAX_THRESHOLD,
percent_available_minimum=0.50, percent_available_minimum=0.50,
manage_order=DEF_ORDER,manage_intervals=DEF_INTERVALS, manage_order=DEF_ORDER,manage_intervals=DEF_INTERVALS,
retry_interval=MINUTE/2, retry_interval=MINUTE/2,
nodetype=None,cmlist=None,enable_delete=False,email=True): nodetype=None,cmlist=None,enable_delete=False,email=True):
ElasticSliceManager.__init__(self,server=server) ElasticSliceManager.__init__(self,server=server)
PluginElasticSliceHelper.__init__(self,server=server) PluginElasticSliceHelper.__init__(self,server=server)
...@@ -818,6 +841,8 @@ class SimpleElasticSliceManager(ElasticSliceManager, ...@@ -818,6 +841,8 @@ class SimpleElasticSliceManager(ElasticSliceManager,
self.server = server self.server = server
self.config = config self.config = config
LOG.debug("server = %s, config = %s" % (server,config))
self.minthreshold = (config and 'minthreshold' in config.all self.minthreshold = (config and 'minthreshold' in config.all
and config.all['minthreshold']) or minthreshold and config.all['minthreshold']) or minthreshold
self.maxthreshold = (config and 'maxthreshold' in config.all self.maxthreshold = (config and 'maxthreshold' in config.all
...@@ -127,9 +127,11 @@ def parse_options(): ...@@ -127,9 +127,11 @@ def parse_options():
parser.add_option("--image_urn", dest="image_urn", parser.add_option("--image_urn", dest="image_urn",
help="Set the default image URN, e.g.") help="Set the default image URN, e.g.")
parser.add_option("--manager_class",dest="manager_class", parser.add_option("--manager_class",dest="manager_class",
help="The class to instantiate and use as the Manager [default: %default]") help="The class to instantiate and use as the Manager [default: elasticslice.managers.core.SimpleElasticSliceManager]")
# default="manager.SimpleElasticSliceManager")
parser.add_option("--helper_class",dest="helper_class", parser.add_option("--helper_class",dest="helper_class",
help="The class to instantiate and use as the Helper [default: %default]") help="The class to instantiate and use as the Helper [default: elasticslice.managers.core.SimpleElasticSliceHelper, if you also use the default manager_class]")
# default="manager.SimpleElasticSliceHelper")
parser.add_option("--clientserver_endpoint_class", parser.add_option("--clientserver_endpoint_class",
dest="clientserver_endpoint_class [default %default]", dest="clientserver_endpoint_class [default %default]",
help="The class to instantiate and use as the Client Server endpoint [default: %default]") help="The class to instantiate and use as the Client Server endpoint [default: %default]")
name = elasticslice
version = 0.1
summary = A library and tools to manage ProtoGeni experiments that dynamically change size
description-file =
author = David M Johnson, Dmitry Duplyakin
author-email =,
home-page =
classifier =
Intended Audience :: Information Technology
Intended Audience :: System Administrators
Operating System :: POSIX :: Linux
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
packages =
#data_files =
# etc/main.conf =
# etc/elasticslice.conf
setup-hooks =
warnerrors = true
#!/usr/bin/env python
import setuptools
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment