Commit c6955b9c authored by David Johnson's avatar David Johnson

Whoops, add the replacement client from 6501cf07 .

parent 6501cf07
#!/usr/bin/python -i
##
## This is an example script that creates a dynamically expandable
## slice. All slices are "dynamically" expandable, of course, but
## usually that process involves generating a new request rspec and
## calling Update() to update your entire sliver. Instead, we create a
## slice, populate it with additional sliver info from an rspec, and
## then AddNodes() and DeleteNodes() as necessary. However, only a
## subset of node metadata can be set -- things like tarballs, OS, any
## LANs to join. You cannot add a new link or lan via this mechanism.
##
## If the slice doesn't exist, we create one, and create an initial
## rspec to populate the slice with all slivers it needs, and contact
## the necessary AM(s) to obtain the resources. During runtime, this
## script can add or remove nodes, according to its resource demands.
## It periodically renews the slice and its slivers.
##
## This script runs (at least) three threads. The main thread kicks off
## a management loop (ElasticSliceManager.manage); a
## ProtoGeniClientServer listens for incoming connections from ProtoGENI
## CM management scripts; and finally, the main thread "hangs around"
## (if you pass the -i option to python when invoking elasticslice!) so
## that you can manually manage your slice. For instance, if you pass
## the options that auto-start the threads (-A -M), you can stop them by
## typing stop() at the python prompt. Then you can issue manual
## management operations, like
##
## > server.renew_slice()
##
## or
##
## > server.delete_nodes(['node-10','node-11'])
##
## You can resume automatic management by typing start().
##
## You'll need to have geni-lib download and in your PYTHONPATH;
## otherwise, the import of protogeniclientlib will fail, since it tries
## to pull in geni-lib modules.
##
## You'll also need to have your Emulab encrypted SSL certificate;
## you'll want to place the passphrase for it in something like
## ~/.ssl/password (or specify an alternate location as a command-line
## argument to this script), otherwise you'll have to type the
## passphrase every time the key gets used! You'll also need the public
## bits of the CA certs for each CM you plan to use, so that the client
## server this script runs for you can verify incoming connections from
## CMs you are using.
##
## With the following command, all configuration options will be read
## from the specified config file:
##
## python elasticslice.py --config ../etc/main.conf
##
## Configuration options from the file will be overriden
## if specific command-line arguments are provided. To see
## the list of available arguments and their defaults, do:
##
## python elasticslice.py -h
##
## Here's a couple commands with command-line arguments:
##
## python -i elasticslice.py -d -D johnsond -U david -P foo -S djds \
## --default-cm clutah -C ~/.ssl/clutah-cacert.pem -A -M
##
## (this runs the elasticslice script in debug mode (and spews tons of
## output; you'll want to log it); creates a client server that
## authenticates incoming requests with HTTPS username/password
## authentication, with username 'david' and password 'foo'; operates
## on a slice with the HRN djds; uses the clutah (cloudlab utah) CM
## to create its sliver; and uses ~/.ssl/clutah-cacert.pem as the
## cacert for verification purposes. Finally, the -A option says to
## autostart the client server so that it is listening for incoming
## connections; and the -M option says to autostart the manager's
## infinite mangement loop (the thing that tries to add nodes if
## there are enough free resources).
##
## Here's a second command line that requires you to have a copy of the
## dynamic version of my openstack profile; not only is this script a
## geni-lib rspec generate (i.e., a Cloudlab geni-lib script) -- but it
## is also a ElasticsliceManagerHelper that provides the generateRspec
## and generateAddNodesArgs functions that a ElasticSliceManager relies
## on to bring semantics to a dynamic experiment.
##
## python -i elasticslice.py -d -D johnsond -U david -P foo -p 13333 -S djdos \
## --default-cm clutah -C ~/.ssl/clutah-cacert.pem \
## -H ~/g/openstack-build-ubuntu/osp-dynamic.py -A -M 2>&1 | tee log.1
##
## (this is much the same, but it uses -p to run the client server on
## a different port than the default (15243); uses a different slice
## HRN; and uses -H to specify a script that provides a
## ElasticSliceHelper (the openstack elasticslice helper.) Oh, and
## it also logs to a file.
##
import os
import getopt
import sys
import threading
import traceback
import logging
import importlib
import elasticslice.rpc.protogeni as pgrpc
import elasticslice.managers.core as coremanagers
from elasticslice.util.util import parse_options, configure_logging, Config
SECOND = 1
MINUTE = SECOND * 60
HOUR = MINUTE * 60
DAY = HOUR * 24
MONTH = DAY * 31
YEAR = DAY * 365
#logging.basicConfig()
LOG = logging.getLogger(__name__)
config = None
server = None
clientserver = None
manager = None
helper = None
(manager_classpath,manager_mod,manager_class) = (None,None,None)
(helper_classpath,helper_mod,helper_class) = (None,None,None)
(clientserver_classpath,clientserver_mod,clientserver_class) = (None,None,None)
client_endpoint_class = None
##
## Simple wrapper functions that are useful on the CLI for the administrator
## who might do things manually, interactively.
##
def createServer():
global server
if not server:
server = pgrpc.ProtoGeniServer(config=config)
server.loadCache()
pass
return server
def createHelper():
global helper,helper_mod,helper_class
if not helper and helper_classpath:
if helper_classpath.find('.') > -1:
class_idx = helper_classpath.rfind('.')
classname = helper_classpath[class_idx+1:]
modpath = helper_classpath[:class_idx]
LOG.info("importing %s from %s as helper" % (classname,modpath))
helper_mod = importlib.import_module(modpath)
helper_class = getattr(helper_mod,classname)
helper = helper_class(server,config=config)
LOG.info("instantiated %s from %s as helper"
% (helper_class,helper_mod))
else:
LOG.error("helper_class must be a fully-qualified class name"
" (i.e., path.to.module.ClassName)")
return helper
pass
##elif not helper:
## helper = coremanagers.SimpleElasticSliceManagerHelper()
elif helper:
LOG.warn("Helper already exists!")
else:
LOG.info("helper_class not specified; cannot create helper!")
pass
return helper
def createManager():
global manager,manager_mod,manager_class
if not manager and manager_classpath:
if manager_classpath.find('.') > -1:
class_idx = manager_classpath.rfind('.')
classname = manager_classpath[class_idx+1:]
modpath = manager_classpath[:class_idx]
LOG.info("importing %s from %s as manager" % (classname,modpath))
manager_mod = importlib.import_module(modpath)
manager_class = getattr(manager_mod,classname)
manager = manager_class(server,config=config)
LOG.info("instantiated %s from %s as manager"
% (manager_class,manager_mod))
else:
LOG.error("manager_class must be a fully-qualified class name"
" (i.e., path.to.module.ClassName)")
return manager
pass
##elif not manager:
## manager = coremanagers.SimpleElasticSliceManagerManager()
elif manager:
LOG.warn("Manager already exists!")
else:
LOG.error("manager_class not specified; cannot create manager!")
pass
if manager:
set_helper = None
try:
set_helper = getattr(manager,'set_helper')
except:
pass
if set_helper:
try:
set_helper(helper)
except:
LOG.exception("manager.set_helper failed!")
pass
pass
pass
return manager
def startManager():
global manager
if not manager:
createManager()
pass
manager.start()
pass
def stopManager():
global manager
if manager:
manager.stop()
pass
def createClientServer():
global clientserver,clientserver_mod,clientserver_class,clientserver_endpoint
if not clientserver and clientserver_classpath:
if clientserver_classpath.find('.') > -1:
class_idx = clientserver_classpath.rfind('.')
classname = clientserver_classpath[class_idx+1:]
modpath = clientserver_classpath[:class_idx]
LOG.info("importing %s from %s as clientserver" % (classname,modpath))
clientserver_mod = importlib.import_module(modpath)
clientserver_class = getattr(clientserver,classname)
clientserver_endpoint = clientserver_class(server,config=config)
LOG.info("instantiated %s from %s as clientserver"
% (clientserver_class,clientserver_mod))
else:
LOG.error("clientserver_class must be a fully-qualified class name"
" (i.e., path.to.module.ClassName)")
return clientserver
pass
elif not clientserver \
and manager and isinstance(manager,coremanagers.ElasticSliceClientEndpoint):
LOG.info("using manager as clientserver endpoint!")
clientserver_endpoint = manager
##elif not clientserver:
## clientserver = coremanagers.SimpleElasticSliceManagerClientServer()
elif clientserver:
LOG.warn("ClientServer already exists!")
return clientserver
else:
LOG.info("clientserver_class not specified, and manager is not an"
" endpoint; cannot create clientserver!")
return None
clientserver_endpoint = manager
cskwargs = dict(modules={ 'dynslice':clientserver_endpoint })
clientserver = pgrpc.ProtoGeniClientServer(**cskwargs)
#
# Also try to tell our server who we are.
#
try:
srv = createServer()
srv.set_client_endpoint(clientserver,config.all['node_delete_wait_time'])
except:
LOG.exception("could not set client endpoint!")
pass
return clientserver
def startClientServer():
global clientserver
if not clientserver:
createClientServer()
pass
clientserver.handle_requests_threaded()
pass
def stopClientServer():
global clientserver
if not clientserver:
print "Client Server not running!"
else:
clientserver.stop_handling()
pass
def stop():
stopClientServer()
stopManager()
pass
def start():
startClientServer()
startManager()
pass
def lookupSlice(name=None):
if not server: createServer()
return server.resolve_slice(name=name)
def createSlice(name=None):
if not server: createServer()
return server.create_slice(name=name)
def renewSlice(name=None,additional_seconds=pgrpc.DAY,cmlist=None):
if not server: createServer()
return server.renew_slice(name=name,additional_seconds=additional_seconds,
cmlist=cmlist)
def deleteSlice(name=None,cmlist=None):
if not server: createServer()
return server.delete_slice(name=name,cmlist=cmlist)
def createSliver(rspec,cm=None,name=None):
if not server: createServer()
return server.create_sliver(rspec,cm=cm,name=name)
def deleteSliver(cm=None,name=None):
if not server: createServer()
return server.delete_sliver(name=name,cm=cm)
def renewSliver(cm=None,name=None):
if not server: createServer()
return server.renew_sliver(name=name,cm=cm)
def sliverStatus(name=None,cm=None):
if not server: createServer()
return server.sliver_status(name=name,cm=cm)
def renew(name=None,cmlist=None):
if not server: createServer()
retval1 = renewSlice()
retval2 = renewSliver()
return (retval1,retval2)
def addNodes(nodes,name=None,cm=None):
if not server: createServer()
return server.add_nodes(nodes=nodes,name=name,cm=cm)
def getResources(cm=None,available=True):
if not server: createServer()
return server.get_resources(cm=cm,available=available)
def deleteNodes(nodes,name=None,cm=None):
if not server: createServer()
return server.delete_nodes(nodes=nodes,name=name,cm=cm)
def verify_config(config):
if config.minthreshold > config.maxthreshold:
LOG.error("Min threshold (%s) is greater than max threshold (%s)"
% (str(config.minthreshold),str(config.maxthreshold)))
pass
if __name__ == "__main__":
(options, args) = parse_options()
configure_logging(options.debug)
config = Config(options)
verify_config(config)
manager_classpath = config.all['manager_class']
helper_classpath = config.all['helper_class']
clientserver_endpoint_classpath = config.all['clientserver_endpoint_class']
manager_class = config.all['manager_class'] \
or 'manager.SimpleElasticSliceManager'
helper_class = config.all['helper_class'] \
or 'manager.SimpleElasticSliceHelper'
# The default manager is an Endpoint, so for now don't force an
# Endpoint on the user.
clientserver_class = config.all['clientserver_endpoint_class'] or None
LOG.debug("Completed verification of the provided configuration options")
# TODO:
# # Always create the server handle object; both the manager and any
# # manager helper need it.
# LOG.debug("server args: %s" % (str(skwargs),))
createServer()
createHelper()
# Always create the manager. Do that after the helper,
createManager()
if config.automanage:
startManager()
pass
if config.autostart:
startClientServer()
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