Source code for geni.util

# Copyright (c) 2014-2016  Barnstormer Softworks, Ltd.

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import absolute_import, print_function

import multiprocessing as MP
import time
import traceback as tb
import tempfile
import json
import os.path

from .aggregate.apis import ListResourcesError, DeleteSliverError

def _getdefault (obj, attr, default):
  if hasattr(obj, attr):
    return obj[attr]
  else:
    return default

[docs]def checkavailrawpc (context, am): """Returns a list of node objects representing available raw PCs at the given aggregate.""" avail = [] ad = am.listresources(context) for node in ad.nodes: if node.exclusive and node.available: if "raw-pc" in node.sliver_types: avail.append(node) return avail
def _corelogininfo (manifest): from .rspec.vtsmanifest import Manifest as VTSM from .rspec.pgmanifest import Manifest as PGM linfo = [] if isinstance(manifest, PGM): for node in manifest.nodes: linfo.extend([(node.client_id, x.username, x.hostname, x.port) for x in node.logins]) elif isinstance(manifest, VTSM): for container in manifest.containers: linfo.extend([(container.client_id, x.username, x.hostname, x.port) for x in container.logins]) return linfo
[docs]def printlogininfo (context = None, am = None, slice = None, manifest = None): """Prints out host login info in the format: :: [client_id][username] hostname:port If a manifest object is provided the information will be mined from this data, otherwise you must supply a context, slice, and am and a manifest will be requested from the given aggregate.""" if not manifest: manifest = am.listresources(context, slice) info = _corelogininfo(manifest) for line in info: print("[%s][%s] %s: %d" % (line[0], line[1], line[2], line[3]))
# You can't put very much information in a queue before you hang your OS # trying to write to the pipe, so we only write the paths and then load # them again on the backside def _mp_get_manifest (context, site, slc, q): try: # Don't use geni.tempfile here - we don't want them deleted when the child process ends # TODO: tempfiles should get deleted when the parent process picks them back up mf = site.listresources(context, slc) tf = tempfile.NamedTemporaryFile(delete=False) tf.write(mf.text) path = tf.name tf.close() q.put((site.name, slc, path)) except ListResourcesError: q.put((site.name, slc, None)) except Exception: tb.print_exc() q.put((site.name, slc, None))
[docs]def getManifests (context, ams, slices): """Returns a two-level dictionary of the form: :: {slice_name : { site_object : manifest_object, ... }, ...} Containing the manifests for all provided slices at all the provided sites. Requests are made in parallel and the function blocks until the slowest site returns (or times out).""" sitemap = {} for am in ams: sitemap[am.name] = am q = MP.Queue() for site in ams: for slc in slices: p = MP.Process(target=_mp_get_manifest, args=(context, site, slc, q)) p.start() while MP.active_children(): time.sleep(0.5) d = {} while not q.empty(): (site,slc,mpath) = q.get() if mpath: am = sitemap[site] data = open(mpath).read() mf = am.amtype.parseManifest(data) d.setdefault(slc, {})[sitemap[site]] = mf return d
def _mp_get_advertisement (context, site, q): try: ad = site.listresources(context) q.put((site.name, ad)) except Exception: q.put((site.name, None))
[docs]def getAdvertisements (context, ams): """Returns a dictionary of the form: :: { site_object : advertisement_object, ...} Containing the advertisements for all the requested aggregates. Requests are made in parallel and the function blocks until the slowest site returns (or times out). .. warning:: Particularly large advertisements may break the shared memory queue used by this function.""" q = MP.Queue() for site in ams: p = MP.Process(target=_mp_get_advertisement, args=(context, site, q)) p.start() while MP.active_children(): time.sleep(0.5) d = {} while not q.empty(): (site,ad) = q.get() d[site] = ad return d
[docs]def deleteSliverExists(am, context, slice): """Attempts to delete all slivers for the given slice at the given AM, suppressing all returned errors.""" try: am.deletesliver(context, slice) except DeleteSliverError: pass
[docs]def builddot (manifests): """Constructs a dotfile of the topology described in the passed in manifest list and returns it as a string.""" # pylint: disable=too-many-branches from .rspec import vtsmanifest as VTSM from .rspec.pgmanifest import Manifest as PGM dot_data = [] dda = dot_data.append # Save a lot of typing dda("digraph {") for manifest in manifests: if isinstance(manifest, PGM): intf_map = {} for node in manifest.nodes: dda("\"%s\" [label = \"%s\"]" % (node.sliver_id, node.name)) for interface in node.interfaces: intf_map[interface.sliver_id] = (node, interface) for link in manifest.links: label = link.client_id name = link.client_id if link.vlan: label = "VLAN\n%s" % (link.vlan) name = link.vlan dda("\"%s\" [label=\"%s\",shape=doublecircle,fontsize=11.0]" % (name, label)) for ref in link.interface_refs: dda("\"%s\" -> \"%s\" [taillabel=\"%s\"]" % ( intf_map[ref][0].sliver_id, name, intf_map[ref][1].component_id.split(":")[-1])) dda("\"%s\" -> \"%s\"" % (name, intf_map[ref][0].sliver_id)) elif isinstance(manifest, VTSM.Manifest): # TODO: We need to actually go through datapaths and such, but we can approximate for now for port in manifest.ports: if isinstance(port, VTSM.GREPort): pass elif isinstance(port, VTSM.PGLocalPort): dda("\"%s\" -> \"%s\" [taillabel=\"%s\"]" % (port.dpname, port.shared_vlan, port.name)) dda("\"%s\" -> \"%s\"" % (port.shared_vlan, port.dpname)) elif isinstance(port, VTSM.InternalPort): dda("\"%s\" -> \"%s\" [taillabel=\"%s\"]" % (port.dpname, port.remote_dpname, port.name)) elif isinstance(port, VTSM.InternalContainerPort): dda("\"%s\" -> \"%s\" [taillabel=\"%s\"]" % (port.dpname, port.remote_dpname, port.name)) elif isinstance(port, VTSM.GenericPort): pass else: continue ### TODO: Unsupported Port Type for dp in manifest.datapaths: dda("\"%s\" [shape=rectangle]" % (dp.client_id)) dda("}") return "\n".join(dot_data)
[docs]def loadContext (path = None, key_passphrase = None): import geni._coreutil as GCU from geni.aggregate import FrameworkRegistry from geni.aggregate.context import Context from geni.aggregate.user import User if path is None: path = GCU.getDefaultContextPath() else: path = os.path.expanduser(path) obj = json.load(open(path, "r")) version = _getdefault(obj, "version", 1) if key_passphrase is True: import getpass key_passphrase = getpass.getpass("Private key passphrase: ") if version == 1: cf = FrameworkRegistry.get(obj["framework"])() cf.cert = obj["cert-path"] if key_passphrase: cf.setKey(obj["key-path"], key_passphrase) else: cf.key = obj["key-path"] user = User() user.name = obj["user-name"] user.urn = obj["user-urn"] user.addKey(obj["user-pubkeypath"]) context = Context() context.addUser(user) context.cf = cf context.project = obj["project"] elif version == 2: context = Context() fobj = obj["framework-info"] cf = FrameworkRegistry.get(fobj["type"])() cf.cert = fobj["cert-path"] if key_passphrase: cf.setKey(fobj["key-path"], key_passphrase) else: cf.key = fobj["key-path"] context.cf = cf context.project = fobj["project"] ulist = obj["users"] for uobj in ulist: user = User() user.name = uobj["username"] user.urn = _getdefault(uobj, "urn", None) klist = uobj["keys"] for keypath in klist: user.addKey(keypath) context.addUser(user) return context
[docs]def hasDataContext (): import geni._coreutil as GCU path = GCU.getDefaultContextPath() return os.path.exists(path)