# Copyright (c) 2014-2018 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
import sys
import inspect
from .core import AM, APIRegistry
[docs]class HostPOAs(object):
def __init__ (self, vtsam):
self.am = vtsam
[docs] def getARPTable (self, context, sname, client_ids):
if not isinstance(client_ids, list): client_ids = [client_ids]
return self.am._apiv3.poa(context, self.am.urlv3, sname, "api:uh.host:get-arp-table",
options={"client-ids": client_ids})
[docs] def getRouteTable (self, context, sname, client_ids):
if not isinstance(client_ids, list): client_ids = [client_ids]
return self.am._apiv3.poa(context, self.am.urlv3, sname, "api:uh.host:get-route-table",
options={"client-ids": client_ids})
[docs] def svcStatus (self, context, sname, client_ids):
if not isinstance(client_ids, list): client_ids = [client_ids]
return self.am._apiv3.poa(context, self.am.urlv3, sname, "api:uh.host:supervisor-status",
options={"client-ids": client_ids})
[docs] def execcmd (self, context, sname, client_ids, cmd):
if not isinstance(client_ids, list): client_ids = [client_ids]
return self.am._apiv3.poa(context, self.am.urlv3, sname, "api:uh.host:exec",
options={"client-ids": client_ids, "cmd" : cmd})
[docs]class v4RouterPOAs(object):
def __init__ (self, vtsam):
self.am = vtsam
[docs] def addOSPFNetworks (self, context, sname, client_ids, nets):
"""Add OSPF Networks to areas on the given routers
Args:
context: geni-lib context
sname (str): Slice name
client_ids (list): A list of client-id strings
nets (list): A list of (network, area) tuples
"""
if not isinstance(client_ids, list): client_ids = [client_ids]
return self.am._apiv3.poa(context, self.am.urlv3, sname, "vts:uh.quagga:add-ospf-nets",
options={"client-ids": client_ids, "networks" : nets})
[docs] def getRouteTable (self, context, sname, client_ids):
if not isinstance(client_ids, list): client_ids = [client_ids]
return self.am._apiv3.poa(context, self.am.urlv3, sname, "vts:uh.quagga:get-route-table",
options={"client-ids": client_ids})
[docs] def getOSPFNeighbors (self, context, sname, client_ids):
if not isinstance(client_ids, list): client_ids = [client_ids]
return self.am._apiv3.poa(context, self.am.urlv3, sname, "vts:uh.quagga:get-ospf-neighbors",
options={"client-ids": client_ids})
[docs]class Policy(object):
def __init__ (self, vtsam):
self.am = vtsam
# Policy consent hooks for GDPR-style compliance
[docs] def getText (self, context, pid = None):
"""Get the text contents of the policy requested. If no policy is specified and only one policy
exists at the aggregate, that policy text will be returned.
Args:
context: geni-lib context
pid: policy ID (typically from `getversion` output)
Returns:
str: Text contents of policy
"""
opts = {}
if pid:
opts["policy-id"] = pid
return self.am._apiv3.paa(context, self.am.urlv3, "vts:policy:get-text", options = opts)
[docs] def giveConsent (self, context, pid):
"""Give consent to the policy indicated for the user URN in the credential used.
Args:
context: geni-lib context
pid: policy ID
"""
return self.am._apiv3.paa(context, self.am.urlv3, "vts:policy:consent", options = {"policy-id" : pid})
[docs] def revokeConsent (self, context, pid):
"""Revoke consent from this date forward to the policy indicated for the user URN in the credential used.
Args:
context: geni-lib context
pid: policy ID
"""
return self.am._apiv3.paa(context, self.am.urlv3, "vts:policy:revoke", options = {"policy-id" : pid})
[docs]class VTS(AM):
"""Wrapper for all VTS-supported AMAPI functions"""
def __init__ (self, name, host, url = None):
self._host = host
if url is None:
url = "https://%s:3626/foam/gapi/2" % (self._host)
self.urlv3 = "%s3" % (url[:-1])
self._apiv3 = APIRegistry.get("amapiv3")
super(VTS, self).__init__(name, url, "amapiv2", "vts")
self.Host = HostPOAs(self)
self.IPv4Router = v4RouterPOAs(self)
self.Policy = Policy(self)
[docs] def allocate (self, context, sname, rspec):
rspec_data = rspec.toXMLString(ucode=True)
manifest = self._apiv3.allocate(context, self.urlv3, sname, rspec_data)
return self.amtype.parseManifest(manifest)
[docs] def provision (self, context, sname):
udata = []
for user in context._users:
data = {"urn" : user.urn, "keys" : [open(x, "rb").read() for x in user._keys]}
udata.append(data)
res = self._apiv3.provision(context, self.urlv3, sname, options = {"geni_users" : udata})
if res["code"]["geni_code"] == 0:
return self.amtype.parseManifest(res["value"])
[docs] def changeController (self, context, sname, url, datapaths, ofver=None):
options={"controller-url" : url, "datapaths" : datapaths}
if ofver:
options["openflow-version"] = ofver
return self._apiv3.poa(context, self.urlv3, sname, "vts:of:change-controller", options)
[docs] def dumpFlows (self, context, sname, datapaths, show_hidden=False):
"""Get the current flows and flow stats from the requested datapaths.
Args:
context: geni-lib context
sname (str): Slice name
datapaths (list): A list of datapath client_id strings
show_hidden (bool): Show hidden flows (if any)
Returns:
dict: Key/Value dictionary of format `{ client_id : [(flow_field, ...), ...] }`
"""
return self._apiv3.poa(context, self.urlv3, sname, "vts:of:dump-flows",
options={"datapaths" : datapaths, "show-hidden" : show_hidden})
[docs] def getL2Table (self, context, sname, client_ids):
if not isinstance(client_ids, list): client_ids = [client_ids]
return self._apiv3.poa(context, self.urlv3, sname, "api:l2-switch:get-l2-table",
options={"client-ids" : client_ids})
[docs] def clearL2Table (self, context, sname, client_ids):
if not isinstance(client_ids, list): client_ids = [client_ids]
return self._apiv3.poa(context, self.urlv3, sname, "api:uh.vswitch:clear-l2-table",
options={"client-ids" : client_ids})
[docs] def clearFlows (self, context, sname, datapaths):
"""Clear all installed flows from the requested datapaths.
Args:
context: geni-lib context
sname (str): Slice name
datapaths (list): A list of datapath client_id strings
"""
return self._apiv3.poa(context, self.urlv3, sname, "vts:of:clear-flows", options={"datapaths" : datapaths})
[docs] def portDown (self, context, sname, client_id):
return self._apiv3.poa(context, self.urlv3, sname, "vts:port-down",
options={"port-client-id" : client_id})
[docs] def portUp (self, context, sname, client_id):
return self._apiv3.poa(context, self.urlv3, sname, "vts:port-up",
options={"port-client-id" : client_id})
[docs] def addFlows (self, context, sname, flows):
return self._apiv3.poa(context, self.urlv3, sname, "vts:of:add-flows", options={"rules" : flows})
[docs] def getSTPInfo (self, context, sname, datapaths):
if not isinstance(datapaths, list): datapaths = [datapaths]
return self._apiv3.poa(context, self.urlv3, sname, "vts:l2:stp-info",
options={"datapaths" : datapaths})
[docs] def getRSTPInfo (self, context, sname, datapaths):
if not isinstance(datapaths, list): datapaths = [datapaths]
return self._apiv3.poa(context, self.urlv3, sname, "vts:l2:rstp-info",
options={"datapaths" : datapaths})
[docs] def getPortInfo (self, context, sname, datapaths):
if not isinstance(datapaths, list): datapaths = [datapaths]
return self._apiv3.poa(context, self.urlv3, sname, "vts:raw:get-port-info",
options={"datapaths" : datapaths})
[docs] def setPortBehaviour (self, context, sname, port_list):
port_json_list = []
for (port,obj) in port_list:
port_json_list.append((port, obj.__json__()))
return self._apiv3.poa(context, self.urlv3, sname, "vts:raw:set-port-behaviour",
options={"ports" : port_json_list})
[docs] def getLeaseInfo (self, context, sname, client_ids):
if not isinstance(client_ids, list): client_ids = [client_ids]
return self._apiv3.poa(context, self.urlv3, sname, "api:uh.dhcp:get-leases",
options = {"client-ids" : client_ids})
[docs] def setPortVLAN (self, context, sname, port_tuples):
if not isinstance(port_tuples, list): port_tuples = [port_tuples]
return self._apiv3.poa(context, self.urlv3, sname, "vts:raw:set-vlan",
options = {"ports" : port_tuples})
[docs] def setPortTrunk (self, context, sname, port_list):
if not isinstance(port_list, list): port_list = [port_list]
return self._apiv3.poa(context, self.urlv3, sname, "vts:raw:set-trunk",
options = {"ports" : port_list})
[docs] def addSSHKeys (self, context, sname, client_ids, keys):
if not isinstance(client_ids, list): client_ids = [client_ids]
if not isinstance(keys, list): keys = [keys]
return self._apiv3.poa(context, self.urlv3, sname, "vts:container:add-keys",
options = {"client-ids" : client_ids, "ssh-keys" : keys})
[docs] def setDHCPSubnet (self, context, sname, subnet_tuples):
if not isinstance(subnet_tuples, list): subnet_tuples = [subnet_tuples]
clid_map = {}
for clid,subnet in subnet_tuples:
clid_map[clid] = subnet
return self._apiv3.poa(context, self.urlv3, sname, "api:uh.dhcp:set-subnet",
options = {"client-id-map" : clid_map})
[docs] def addDNSResourceRecord (self, context, sname, client_id, record_name, record_type, record_value, record_ttl=7200):
return self._apiv3.poa(context, self.urlv3, sname, "vts:uh.dnsroot:add-resource-record",
options = {"client-id" : client_id,
"record-name" : record_name,
"record-type" : record_type,
"record-value" : record_value,
"record-ttl" : record_ttl})
[docs] def deleteDNSResourceRecord (self, context, sname, client_id, record_name, record_type):
return self._apiv3.poa(context, self.urlv3, sname, "vts:uh.dnsroot:delete-resource-record",
options = {"client-id" : client_id,
"record-name" : record_name,
"record-type" : record_type})
[docs] def getAllDNSResourceRecords(self, context, sname, client_ids):
if not isinstance(client_ids, list): client_ids = [client_ids]
return self._apiv3.poa(context, self.urlv3, sname, "vts:uh.dnsroot:get-all-records",
options={"client-ids": client_ids})
[docs] def getLastDNSDHCPops(self, context, sname, client_ids, number_of_operations, dns_OR_dhcp):
if not isinstance(client_ids, list): client_ids = [client_ids]
return self._apiv3.poa(context, self.urlv3, sname, "vts:uh.dnsdhcp:get-last-DNSDHCP-ops",
options={"client-ids": client_ids,
"number-of-operations": number_of_operations,
"dns-OR-dhcp": dns_OR_dhcp})
[docs] def setDeleteLock (self, context, sname):
"""Prevent the given sliver from being deleted by another user with the credential.
.. note::
Locks are cumulative, and removed by calling `deletesliver`. When the last locking
user calls `deletesliver`, the sliver will be deleted. It is not possible to remove
your lock without risking deletion.
Args:
context: geni-lib context
sname (str): Slice name
"""
return self._apiv3.poa(context, self.urlv3, sname, "geni:set-delete-lock", {})
[docs] def dropboxLink (self, context):
"""Link your user_urn to a Dropbox account at this aggregate.
Args:
context: geni-lib context
Returns:
str: Dropbox authorization URL to paste into web browser
"""
return self._apiv3.paa(context, self.urlv3, "vts:dropbox:link-account")
[docs] def dropboxFinalize (self, context, authcode):
"""Finalize the Dropbox account link for this aggregate.
Args:
context: geni-lib context
authcode (str): Authorization code given by Dropbox
"""
return self._apiv3.paa(context, self.urlv3, "vts:dropbox:complete-link", {"auth-code" : authcode})
[docs] def dropboxUpload (self, context, sname, cvols):
"""Trigger upload to associated Dropbox account from requested container volumes.
Args:
context: geni-lib context
sname (str): Slice name
cvols (list): List of `(container client-id, volume-id)` tuples
"""
data = {}
for (cid,volid) in cvols:
data.setdefault(cid, []).append(volid)
return self._apiv3.poa(context, self.urlv3, sname, "vts:dropbox:upload", options = {"vols" : [data]})
[docs] def hgPull (self, context, sname, cvols):
"""Update an HgMount volume with the latest data from the source repository.
Args:
context: geni-lib context
sname (str): Slice name
cvols (list): List of `(container client-id, volume-id)` tuples
"""
data = {}
for (cid,volid) in cvols:
data.setdefault(cid, []).append((volid, True))
return self._apiv3.poa(context, self.urlv3, sname, "vts:hg:pull", options = {"vols" : [data]})
Clemson = VTS("vts-clemson", "clemson.vts.bsswks.net")
GPO = VTS("vts-gpo", "gpo.vts.bsswks.net")
Illinois = VTS("vts-illinois", "uiuc.vts.bsswks.net")
NPS = VTS("vts-nps", "nps.vts.bsswks.net")
UKYPKS2 = VTS("vts-ukypks2", "ukypks2.vts.bsswks.net")
StarLight = VTS("vts-starlight", "starlight.vts.bsswks.net")
[docs]def aggregates ():
module = sys.modules[__name__]
for _,obj in inspect.getmembers(module):
if isinstance(obj, AM):
yield obj
[docs]def name_to_aggregate ():
result = dict()
module = sys.modules[__name__]
for _,obj in inspect.getmembers(module):
if isinstance(obj, AM):
result[obj.name] = obj
return result
[docs]def aggregateFromHost (host):
module = sys.modules[__name__]
for _,obj in inspect.getmembers(module):
if isinstance(obj, AM):
if obj._host == host:
return obj