= Plug-in Interfaces = Access controllers respond to a series of standard calls from the experiment controller to create local allocations. These are described in conceptual detail [FeddPluginArchitecture elsewhere on this site] and in a [http://groups.geni.net/geni/attachment/wiki/TIEDProtoGENIPlugin/TIED_CF_plugin_design_spec_v1.0.pdf document about the design of the ProtoGENI plug-in]. This section discussed the calls and their encoding for developers interested in reading and extending existing plug-in code, developers will likely want to [FeddSkelPlugin configure and play with the skeleton plug-in] when you have completed this page (or before reading it, depending on how one's neurons are arranged). The interfaces are all described in xsd and SOAP, and these are easy enough to convert into python data structures [SoapToPython once you know how]. Below we describe the semantics of each call, and the tools available to plug-in writers to assist in implementation. These tools are available when plug-ins derive from [source:fedd/federation/access.py federation.access], as [source:fedd/federation/skeleton_access.py federation.skeleton_access] is. Each python method in the plug-in that corresponds to a plug-in interface is called with the same parameters: * the request: a python dict representing the parameters to the call as encoded in SOAP * the calling fid: a [source:fedd/federation/fedid.py fedid object] holding the caller's identity Each method should return the python dict encoding the response or raise a [source:fedd/federation/service_error.py service_error] containing information about the error. The service_error class contains error codes (in either the [source:wsdl/fedd_types.xsd XSD] or [source:fedd/federation/service_error.py python] definitions. Many requests and responses include attribute/value pairs set by the experiment controller to plug-ins that understand them. They are not commonly used but do represent a lightweight extension mechanism. If a plug-in adds one to a sub-experiment description or topology element, the experiment controller generally passes it through transparently. == Initialization == This is not an interface from the experiment controller, but we discuss it to mention the tools available for implementors. These include routines to save state and interpret the standard parts of the [FeddDatabases#AccessComponentAccessDB access database], including specializing for testbed dependent data. The method {{{read_access(file, local_info_parser)}}} takes the file to read and a function that takes the string following the access attribute and returns the local testbed attributes, stored into the self.access dict, keyed by the [FeddAbout#GlobalIdentifiers:Three-levelNames three-name] being authorized. The {{{___init___()}}} routine of [source:fedd/federation/skeleton_access.py federation.skeleton_access] includes an example of this. The base class also creates {{{self.auth}}}, which is an [source:fedd/federation/authorizer.py authorizer object]. This object keeps track of the authorization attributes associated with the three-level names and fedids that the plug-in knows. When reading the authorization database, the base class assigns the attributes given by the attribute field of the database to the relevant names. Generally this will an '''access''' attribute tp three-level names allowed to make allocations. Other attributes can be added by the plug-in, and the authorizer used to control acces to them. The [source:fedd/federation/skeleton_access.py skeleton plug-in] includes code to do ths. In addition, the initializer of the [source:fedd/federation/access.py federation.access] base class parses standard parameters from {{{[access]}}} section from the configuration file. The fields and corresponding class instance attributes are: '''cert_file''':: The certificate file that contains the [FeddAbout#GlobalIdentifiers:Fedids fedid] that identifies this access controller. It is stored in {{{self.cert_file}}}. '''cert_pw''':: Password for the certificate file, if any. Stored in {{{self.cert_pw}}}. '''trusted_certs''':: Certificates used to validate the signatures of other fedd principals. Generally unused. Stored in {{{self.trusted_certs}}}. Those first three attributes are initialized by the {{{[access]}}} section, if given, or {{{[globals]}}}, if not. '''access_state''':: The file storing persistent state. Stored in {{{self.state_file}}}. '''certdir''':: Directory to store local certificates for allocations in. Stored in {{{self.certdir}}}. '''project_priority''':: Affects the standard access lookup routines by preferring matches on project if true. Stored in {{{self.project_priority}}}, though most implementations will not need to access it. '''create_debug''':: Intended to keep the plug-in from making any persistent changes to the facility. Plug-in writers are expected to honor it. It is stored in {{{self.create_debug}}}. '''leave_tmpfiles''':: Intended to tell the plug-in not to delete temporary files. Plug-in writers are expected to honor it. Stored in {{{self.cleanup}}}, negated; that is if '''leave_tempfiles''' is false in the configuration {{{self.cleanup}}} is true. {{{self.cleanup}}} defaults to true. '''type''':: Distinguishes between sub-types of the plug-in. Stored in {{{self.access_type}}}; semantics are up to the plug-in writer. '''log_level''':: The level of log entries to pass to the logger. Any of the values in [http://docs.python.org/library/logging.html the standard python logging choices] are acceptable. It is only stored as internal state of {{{self.log}}}, a logger allocated by the initializer. Finally, the default initializer allocates a Lock to be acquired when accessing persistent state and reads that state from {{{self.state_file}}}. The plug-in initializer is largely plug-in depenent, but must also set the methods to be called for each interface call in the {{{self.soap_services}}} and {{{self.xmlrpcservices}}} dicts. == !RequestAccess == The !RequestAccess command asks the testbed to map the [FeddAbout#GlobalIdentifiers:Three-levelNames three-level name] on the call into local permissions and to do any bookkeeping associated with later attachment of resources to that allocation. Specifically, a [http://fedd.isi.deterlab.net/trac/wiki/FeddAbout#GlobalIdentifiers:Fedids fedid] must be created. Requests from this allocation back to the central experiment controller will be made under that principal/fedid. Such requests gather configuration information or parameters passed between sub-experiments during creation. The per-allocation fedid allows fine-grained control of access to thie information at the experiment controller, as well as the ability to name (and therefore request operation on) the various allocations made on this plug-in. The plug-in should add an authorization attribute to the creator of the allocation that indicates that the creator can manipulate the allocation via any of the other commands. Existing plug-ins do this by adding an attribute with the same value as the allocation's fedid to the [source:fedd/federation/authorizer.py authorization object]. A !RequestAccess message has the following format: {{{ request = { # list of strings of the form user:name project:name (these will be replaced by ABAC credentials in fedd 3.1) 'credential': [ 'user:u', 'project:p' ] # Requested services 'service': [ # Each of these has an identifier, service name, server (optional), and a list of attributes as service parameters { 'id': '0001', 'name': 'project_export', 'visibility': 'export', 'fedAttr: [ { 'attribute': 'att_name', 'value': 'val1'} ] } ], } }}} The credentials are opaquely and correctly handled by the [source:fedd/federation/access.py access controller base class]. Service requests encode the various [FeddAbout#ExperimentServices services] that the facility will be asked for in this allocation. There are also some scheduling fields that are for future expansion. The DETER experiment controller never includes them. The response message has the form: {{{ response = { 'allocID': { 'fedid': fedidobj }, 'service': [ # The meta service 'export_project' in the request has become 2 actual service descriptions with the same ID as the request { 'id': '0001', 'name': 'SMB', 'visibility': 'export', 'fedAttr: [ { 'attribute': 'att_name', 'value': 'val1'} ] } ] }, { 'id': '0001', 'name': 'userconf', 'visibility': 'export', 'fedAttr: [ { 'attribute': 'att_name', 'value': 'val1'} ] }, ] } }}} The response includes the fedid of the allocation and the actual services exported. Note that in the example the single '''export_project''' request has become 2 specific service exports. See the [sources:fedd/federation/emulab_access.py emulab plug-in] for an example of how services are decoded and managed. == !StartSegment == This is the operation where the plug-in has the most to do. The resources described in the segment description are attached to the allocation and configured to provide the various services, including interconnection with other testbeds. The request has the format: {{{ request = { 'allocID' { 'fedid': fedid_obj }, 'segmentdescription': { 'topdldescription': { # a topdl description as a dict (see below) }, }, 'service': [ # The meta service 'export_project' in the request has become 2 actual service descriptions with the same ID as the request { 'id': '0001', 'name': 'SMB', 'visibility': 'export', 'fedAttr: [ { 'attribute': 'att_name', 'value': 'val1'} ] } ] }, { 'id': '0001', 'name': 'userconf', 'visibility': 'export', 'fedAttr: [ { 'attribute': 'att_name', 'value': 'val1'} ] }, ], 'connection': [ { 'type': 'transit', 'portal': 'hostname', 'peer': 'remote_hostname', 'parameter': [ { # The parameter 'name': 'ssh_port', # Where to get it (local part of a url) 'key': 'djfahlshl/val', # where to get it (host running the synchronized store) 'store': 'https://users.isi.deterlab.net:23235', # Whether we need to send or receive the value 'type': 'output', }, ] } ], } }}} To get the topdl representation out of the (potentially large and complex) dict that describes it, the simplest mechanism is to use the {{{topdl.topology_from_startsegment}}} function: {{{ top = topdl.topology_from_startsegment(request) }}} That is done in all the existing plug-in code. The various plug-ins walk, alter, and write topologies in several ways, and that code is a good guide to them. The [source:fedd/federation/topdl.py topdl source] is also available. The connection information explains how the connectivity is established between the sub-experiments. Now there are two ways to establish connections - ssh tunnels and direct transit connections. The ssh connection implies a portal in this experiment (it will be in the topology description) that will connect to the peer. Generally the port on which to communicate will be a parameter as it is here. Parameters are set using the !SetValue interface, which is [FeddPluginCalls#UsingSetValueandGetValue described below]. There are a few conventional parameters: '''peer''':: The DNS name or IP address of the other side of the connection '''ssh_port''':: The port to contact ssh on the peer '''vlan_id''':: For federants that are connected to transit federants, e.g., dragon, this is the VLAN ID to use in the connection For most federants the {{{import_store_info}}} member of {{{federation/access.py}}} will import the necessary parameters correctly. For those outputting values, the {{{export_store_info}}} member of {{{federation/emulab_access.py}}} is a good starting point. A plug-in should export its connection parameters as soon as it can determine them, and import connection parameters as late as it can in the experiment creation process. The service parameters are the same format, and for services exported from this sub-experiment often the same content, as those returned from a !RequestAccess request. The connectivity and service information is particularly useful if the service and connectivity set-up is being done using [FeddAbout#TheFederationKit the DETER federation kit]. While other systems for providing this connectivity are fine, the federation kit provides a robust implementation that runs across several Unix based platforms. The [source:fedd/federation/emulab_access.py Emulab plug-in] is a good place to look at the details of configuring the federation kit. In addition to configuring and establishing connectivity, the plug-in must convert the topology description into an embeddable topology. The [source:fedd/federation/topdl.py topdl source] includes several conversions into different formats, including emulab ns2 and [http://www.protogeni.net/trac/protogeni/wiki/RSpec ProtoGENI RSpecs (v1.0)]. While there is considerable support available, !StartSegment is the operation that is the most tricky for the plug-in developer. The response has the format: {{{ response = { # Same as in the request 'allocID': { 'fedid': fedid_object }, 'allocationLog': 'a log of the allocation from the plug-in's perspective. This may be edited or complete.', 'segmentdescription' : { 'topdldescription': # Topdl description }, # Description of the allocation 'embedding': [ { 'topname': 'name_from_topdl', 'physname': 'testbed_name', 'testbed': 'testbed_id_from_topdl' }, #... ], # Generic attribute value pairs, rarely used. 'fedAttr' : [ { 'attribute': 'a1', 'value': 'v1'}, {'attribute': 'a2', 'value: 'v2' } ], } }}} The allocation log is a plug-in's eye view of the allocation. It is output by the experiment controller and can be viewed by the user using [FeddCommands#fedd_spewlog.py fedd_spewlog.py]. The segment description that is returned may be annotated with more detail about the segment as constructed. For example specifics of the hardware on which an element was instantiated could be filled in. The embedding provides a way for the experiment controller to map elements from the global experiment description into a name in the plug-in's name space. Currently this is available to the user from the [FeddCommands#fedd_ftopo.py fedd_ftopo.py] command and is used in ad hoc ways. In a future release this information will be useful in executing remote operations from the experiment controller. == !TerminateSegment == This operation basically undoes the resource assignemnt and configuration accomplished by !StartSegment. The sub-experiment resources are released and the connectivity and services terminated. Local facility rules on cleaning the resources and restoring them to use by others apply. The request message looks like: {{{ request = { 'allocID': { 'fedid': fedid_obj }, 'force': True, } }}} AllocID identifies the sub-experiment to terminate. If {{{force}}} is True, remove resources even if they are in the middle of being allocate or if the plug-in would otherwise not do so. The response messgae looks like: {{{ response = { 'allocID': { 'fedid': fedid_obj }, 'deallocationLog': 'A long string', } }}} The {{{allocID}}} tells which segment has been destroyed. A plug-in can also send the deallocation log to the experiment controller and on to the user. [FeddCommands#fedd_terminate.py fedd_terminate.py] provides an option to display or save these logs, if plug-ins send them. == !ReleaseAccess == This reverses a successful !RequestAccess. Remove the unique fedid for this allocation, and unbind the local resource information from it. After this call returns there will no longer be an allocation. The request and response message are the same: {{{ request_or_response = { 'allocID': { 'fedid': fedid_obj } } }}} {{{allocID}}} identifies either the allocation to release or that has been released. == Using !SetValue and !GetValue == The experiment controller acts as an exchange point where access controllers can exchange information they need to interconnect. Specifically the parameters in the connection structures of a !StartSegment request are exchanged through the experiment controller. A !SetValue request has the form: {{{ request = { 'name': key_from_connection_parameter, 'value': value_to_set, } }}} Values are strings and the name is a unique key (generated by the experiment controller) that identifies the variable. Access is contolled for each variable. The response is {{{ request = { 'name': key_from_connection_parameter, 'value': value_set, 'proof': An_ABAC_proof_of_access } }}} !GetValue requests are similarly formatted: {{{ request = { 'name': key_from_connection_parameter, # If wait is true, the call will block until some access controller has set the value 'wait': boolean, } }}} and the response is {{{ response = { 'name': key_from_connection_parameter, # This is optional. If wait was not set in the request and the value is unset, this field will not be in the response 'value': value, 'proof': An_ABAC_proof_of_access } }}} Requesting !GetValue with the {{{wait}}} parameter set blocks the caller until the value is set. Commonly, access controllers will set their output parameters using multiple SetValue calls and then wait for values from others using blocking !GetValue calls. == Next == Developers may want to proceed to [FeddSkelPlugin configure and play with the skeleton plug-in].