Commit 84a24fbf authored by David Johnson's avatar David Johnson

Many interrelated changes: exceptions, caching, managers.

  * Move exceptions into common file.  Ok, this isn't interrelated, but
    it became so, sorry.

  * Move ensure_slice, ensure_sliver into core ElasticSliceManager
    "abstract" interface, from SimpleElasticSliceManager; refactor them
    to split out create_slice and create_sliver as separate methods; and
    expose all these things via ApplicableMethod.

  * Add a new interpretation of the cache-relevant force=(True|False)
    parameter: now if that value is an integer, take that as a max_age
    when querying the cache.  So now the caller can prevent the cache
    from returning non-expired values if the value is older than a
    caller-specified max age.

  * Improve _cache_add to use synchronous ctime/xtime if relevant.

  * Add ctime to CacheNotifier (.added).

  * Add get_sliver_credential().

  * Expose the manager should_add_nodes/add_nodes/delete_nodes methods
    via ApplicableMethod.

  * Change the manager.*add_nodes* methods to accept an additional
    count=N parameter.  If 0, should_add_nodes will make an estimate of
    how many nodes to add them, and add them.  If nonzero, it will see
    if it should add that number of nodes, and do so if allowed.  This
    allows, for instance, a CLI invocation to force multiple nodes to be
    added if possible, even if by default the manager would only add one
    at a time.

  * Add a force= param to ProtoGeniServer.get_wrapped_manifest().
parent 740ae2c9
......@@ -14,6 +14,16 @@ elasticslice.util.util module
----------
elasticslice.util.exceptions module
-----------------------------------
.. automodule:: elasticslice.util.exceptions
:members:
:undoc-members:
:show-inheritance:
----------
elasticslice.util.applicable module
-----------------------------------
......
......@@ -8,6 +8,7 @@ from elasticslice.rpc.protogeni import ProtoGeniClientDefs, ProtoGeniServer, \
ProtoGeniResponse, ProtoGeniManifestWrapper, \
ProtoGeniClientServerEndpoint, ProtoGeniClientServer, SENDMAIL
from elasticslice.util.applicable import ApplicableClass,ApplicableMethod
import elasticslice.util.exceptions as exc
import geni.rspec.pgad as RSpecAd
import geni.rspec.pg as RSpec
import geni.rspec.igext as IG
......@@ -23,42 +24,6 @@ DAY = HOUR * 24
MONTH = DAY * 31
YEAR = DAY * 365
class NonexistentSliceError(Exception):
def __init__(self,msg=None):
s = "cannot resolve nor create slice"
if msg:
s += ": " + msg
super(NonexistentSliceError,self).__init__(s)
pass
class NonexistentSliverError(Exception):
def __init__(self,msg=None):
s = "cannot resolve nor create sliver"
if msg:
s += ": " + msg
super(NonexistentSliverError,self).__init__(s)
pass
class NonexistentHelperError(Exception):
def __init__(self,msg=None):
s = "No helper object"
if msg is not None:
s += ": " + msg
pass
super(NonexistentHelperError,self).__init__(s)
pass
pass
class NotImplementedError(Exception):
def __init__(self,msg=None):
s = "Method not implemented"
if msg is not None:
s += ": " + msg
pass
super(NotImplementedError,self).__init__(s)
pass
pass
class ElasticSliceHelper(object):
"""
......@@ -87,13 +52,13 @@ class ElasticSliceHelper(object):
generate new nodes (that don't overlap with existing ones, for
instance).
"""
raise NotImplementedError("create_rspec")
raise exc.NotImplementedError("create_rspec")
def get_add_args(self,count=1):
"""
Returns a dict of nodes that conforms to the CMv2 AddNodes() API call.
"""
raise NotImplementedError("get_add_args")
raise exc.NotImplementedError("get_add_args")
def get_delete_commands(self,nodelist):
"""
......@@ -153,14 +118,14 @@ class PluginElasticSliceHelper(ElasticSliceHelper):
if self.helper:
return self.helper.create_rspec()
else:
raise NotImplementedError("create_rspec")
raise exc.NotImplementedError("create_rspec")
pass
def get_add_args(self,count=1):
if self.helper:
return self.helper.get_add_args(count=count)
else:
raise NotImplementedError("get_add_args")
raise exc.NotImplementedError("get_add_args")
pass
def get_delete_commands(self,nodelist):
......@@ -709,6 +674,19 @@ class ElasticSliceManager(ElasticSliceHelper):
self.config = config
pass
@ApplicableMethod(alias='managed_create_slice')
def create_slice(self):
"""
Create the slice from within the manager, using information
from the ElasticSliceHelper associated with this ElasticSliceManager.
"""
ret = self.server.create_slice()
if ret:
return ret
LOG.error("Could not create slice!")
raise exc.NonexistentSliceError()
@ApplicableMethod(alias='managed_ensure_slice')
def ensure_slice(self):
"""
......@@ -718,27 +696,18 @@ class ElasticSliceManager(ElasticSliceHelper):
if ret:
return ret
LOG.info("Slice does not exist, creating...")
ret = self.server.create_slice()
if ret:
return ret
return self.create_slice()
LOG.error("Could not create slice!")
raise NonexistentSliceError()
@ApplicableMethod(alias='managed_ensure_sliver')
def ensure_sliver(self,cm=None):
@ApplicableMethod(alias='managed_create_sliver')
def create_sliver(self,cm=None):
"""
Check to see if the sliver exists; if not, create it using information
Create the sliver from within the manager, using information
from the ElasticSliceHelper associated with this ElasticSliceManager.
:param cm: the CM (component manager) at which to create the sliver.
"""
if not cm: cm = self.default_cm
ret = self.server.resolve_sliver(cm=cm)
if ret:
return ret
LOG.info("Sliver does not exist, creating...")
# Grab an rspec from the helper (us, via plugin helper)
# Save off old argv because geni-lib scripts process it :(
oldargv = sys.argv
......@@ -753,12 +722,30 @@ class ElasticSliceManager(ElasticSliceHelper):
return ret
LOG.error("Could not create sliver!")
raise NonexistentSliverError()
raise exc.NonexistentSliverError()
@ApplicableMethod(alias='managed_ensure_sliver')
def ensure_sliver(self,cm=None):
"""
Check to see if the sliver exists; if not, create it using information
from the ElasticSliceHelper associated with this ElasticSliceManager.
:param cm: the CM (component manager) at which to create the sliver.
"""
if not cm: cm = self.default_cm
ret = self.server.resolve_sliver(cm=cm)
if ret:
return ret
LOG.info("Sliver does not exist, creating...")
return self.create_sliver(cm=cm)
def _add_nodes(self,nodes={},cm=None):
return self.server.add_nodes(nodes=nodes,cm=cm)
def should_add_nodes(self,cm=None):
@ApplicableMethod(alias='managed_should_add_nodes')
def should_add_nodes(self,count=0,cm=None):
"""
By default, add_nodes calls this method to find out if it should
add any nodes. If this function returns an integer, add_nodes
......@@ -767,15 +754,26 @@ class ElasticSliceManager(ElasticSliceHelper):
If the function returns a dict, it passes that directly to
_add_nodes. If the function returns None, False, nothing is
added. This gives subclasses enough flexibility, hopefully.
If you pass a nonzero, positive integer via `count`, this method
must check if it should add exactly `count` nodes, or not, and
return accordingly.
:param count: If nonzero, positive integer, this method checks if the manager should add exactly `count` nodes, or not, and return accordingly.
:param cm: the CM (component manager) at which to add nodes.
"""
return False
def add_nodes(self,cm=None):
@ApplicableMethod(
alias='managed_add_nodes')
def add_nodes(self,count=0,cm=None):
"""
This function manages the addition of nodes. This manager will
call it to add nodes to this slice, as necessary.
:param count: If nonzero, positive integer, this method checks (via :func:`should_add_nodes`) if the manager should add exactly `count` nodes, or not, and return accordingly.
:param cm: the CM (component manager) at which to add nodes.
"""
result = self.should_add_nodes(cm=cm)
result = self.should_add_nodes(count=count,cm=cm)
if not result:
return
......@@ -800,12 +798,15 @@ class ElasticSliceManager(ElasticSliceHelper):
def _delete_nodes(self,nodelist,cm=None):
return self.server.delete_nodes(nodes=nodelist,cm=cm)
@ApplicableMethod(alias='managed_should_delete_nodes')
def should_delete_nodes(self,cm=None):
"""
Should we delete a node? If so, this function must return a
list of nodes to delete. This list is exactly the arguments
that CM::DeleteNodes expects. If there is nothing to do, it can
return None or False.
:param cm: the CM (component manager) at which to add nodes.
"""
return False
......@@ -879,7 +880,7 @@ class ElasticSliceManager(ElasticSliceHelper):
interval between core operations has been reached. Otherwise, the core
operations are only performed at the intervals specified for each.
"""
raise NotImplementedError("manage_once")
raise exc.NotImplementedError("manage_once")
def manage(self):
"""
......@@ -1070,7 +1071,6 @@ class SimpleElasticSliceManager(ElasticSliceManager,
# Set up our aggregate (CM) databases.
for cm in self.cmlist:
self.aggdata[cm] = dict(cmdict)
self.aggdata[cm] = \
dict(node_map={},allxml='',availxml='',all=None,avail=None,
status={},node_status={},adding={},deleting={})
......@@ -1517,7 +1517,7 @@ class SimpleElasticSliceManager(ElasticSliceManager,
return manifest
def should_add_nodes(self,cm=None):
def should_add_nodes(self,count=0,cm=None):
if not cm: cm = self.default_cm
LOG.debug("should_add_nodes: cm=%s" % (str(cm)))
......@@ -1576,8 +1576,8 @@ class SimpleElasticSliceManager(ElasticSliceManager,
return False
pass
def add_nodes(self,cm=None):
retval = super(SimpleElasticSliceManager,self).add_nodes(cm=cm)
def add_nodes(self,count=0,cm=None):
retval = super(SimpleElasticSliceManager,self).add_nodes(count=count,cm=cm)
if not retval:
return None
else:
......
This diff is collapsed.
class NonexistentSliceError(Exception):
def __init__(self,msg=None):
s = "cannot resolve slice"
if msg:
s += ": " + msg
super(NonexistentSliceError,self).__init__(s)
pass
class NonexistentSliverError(Exception):
def __init__(self,msg=None):
s = "cannot resolve sliver"
if msg:
s += ": " + msg
super(NonexistentSliverError,self).__init__(s)
pass
class NonexistentHelperError(Exception):
def __init__(self,msg=None):
s = "No helper object"
if msg is not None:
s += ": " + msg
pass
super(NonexistentHelperError,self).__init__(s)
pass
pass
class NotImplementedError(Exception):
def __init__(self,msg=None):
s = "Method not implemented"
if msg is not None:
s += ": " + msg
pass
super(NotImplementedError,self).__init__(s)
pass
pass
class InvalidArgumentError(Exception):
pass
class RPCError(Exception):
"""
Raised as an exception on XMLRPC method errors. Encapsulates error
information.
"""
def __init__(self,rpcname,rval,response,msg=None):
s = "Server returned error code %s while executing %s (%s)" \
% (str(rval),rpcname,str(response))
if msg:
s += ": " + msg
pass
super(RPCError,self).__init__(s)
self.rval = rval
self.response = response
pass
pass
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment