--- /dev/null
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+
+<base target="_top">
+
+<style type="text/css">
+
+
+/* default css */
+
+table {
+ font-size: 1em;
+ line-height: inherit;
+}
+
+
+tr {
+
+ text-align: left;
+
+}
+
+
+div, address, ol, ul, li, option, select {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+p {
+ margin: 0px;
+}
+
+body {
+ margin: 6px;
+ padding: 0px;
+ font-family: Verdana, sans-serif;
+ font-size: 10pt;
+ background-color: #ffffff;
+}
+
+
+img {
+ -moz-force-broken-image-icon: 1;
+}
+
+@media screen {
+ html.pageview {
+ background-color: #f3f3f3 !important;
+ }
+
+
+
+ body {
+ min-height: 1100px;
+ }
+ * html body {
+ height: 1100px;
+ }
+ .pageview body {
+ border-top: 1px solid #ccc;
+ border-left: 1px solid #ccc;
+ border-right: 2px solid #bbb;
+ border-bottom: 2px solid #bbb;
+ width: 648px !important;
+ margin: 15px auto 25px;
+ padding: 40px 50px;
+ }
+ /* IE6 */
+ * html {
+ overflow-y: scroll;
+ }
+ * html.pageview body {
+ overflow-x: auto;
+ }
+ /* Prevent repaint errors when scrolling in Safari. This "Star-7" css hack
+ targets Safari 3.1, but not WebKit nightlies and presumably Safari 4.
+ That's OK because this bug is fixed in WebKit nightlies/Safari 4 :-). */
+ html*#wys_frame::before {
+ content: '\A0';
+ position: fixed;
+ overflow: hidden;
+ width: 0;
+ height: 0;
+ top: 0;
+ left: 0;
+ }
+
+
+
+
+
+
+
+ .br_fix br:not(:-moz-last-node):not(:-moz-first-node) {
+
+ position:relative;
+
+ left: -1ex
+
+ }
+
+ .br_fix br+br {
+ position: static !important
+ }
+}
+
+h6 { font-size: 8pt }
+h5 { font-size: 8pt }
+h4 { font-size: 10pt }
+h3 { font-size: 12pt }
+h2 { font-size: 14pt }
+h1 { font-size: 18pt }
+
+blockquote {padding: 10px; border: 1px #DDD dashed }
+
+a img {border: 0}
+
+.pb {
+ border-width: 0;
+ page-break-after: always;
+ /* We don't want this to be resizeable, so enforce a width and height
+ using !important */
+ height: 1px !important;
+ width: 100% !important;
+}
+
+.editor .pb {
+ border-top: 1px dashed #C0C0C0;
+ border-bottom: 1px dashed #C0C0C0;
+}
+
+div.google_header, div.google_footer {
+ position: relative;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+
+/* Table of contents */
+.editor div.writely-toc {
+ background-color: #f3f3f3;
+ border: 1px solid #ccc;
+}
+.writely-toc > ol {
+ padding-left: 3em;
+ font-weight: bold;
+}
+ol.writely-toc-subheading {
+ padding-left: 1em;
+ font-weight: normal;
+}
+/* IE6 only */
+* html writely-toc ol {
+ list-style-position: inside;
+}
+.writely-toc-none {
+ list-style-type: none;
+}
+.writely-toc-decimal {
+ list-style-type: decimal;
+}
+.writely-toc-upper-alpha {
+ list-style-type: upper-alpha;
+}
+.writely-toc-lower-alpha {
+ list-style-type: lower-alpha;
+}
+.writely-toc-upper-roman {
+ list-style-type: upper-roman;
+}
+.writely-toc-lower-roman {
+ list-style-type: lower-roman;
+}
+.writely-toc-disc {
+ list-style-type: disc;
+}
+
+/* end default css */
+
+
+ /* default print css */
+
+ @media print {
+ body {
+ padding: 0;
+ margin: 0;
+ }
+
+ div.google_header, div.google_footer {
+ display: block;
+ min-height: 0;
+ border: none;
+ }
+
+ div.google_header {
+ flow: static(header);
+ }
+
+ /* used to insert page numbers */
+ div.google_header::before, div.google_footer::before {
+ position: absolute;
+ top: 0;
+ }
+
+ div.google_footer {
+ flow: static(footer);
+ }
+
+ /* always consider this element at the start of the doc */
+ div#google_footer {
+ flow: static(footer, start);
+ }
+
+ span.google_pagenumber {
+ content: counter(page);
+ }
+
+ span.google_pagecount {
+ content: counter(pages);
+ }
+
+
+ callout.google_footnote {
+
+ display: prince-footnote;
+ footnote-style-position: inside;
+ /* These styles keep the footnote from taking on the style of the text
+ surrounding the footnote marker. They can be overridden in the
+ document CSS. */
+ color: #000;
+ font-family: Verdana;
+ font-size: 10.0pt;
+ font-weight: normal;
+ }
+
+ /* Table of contents */
+ #WritelyTableOfContents a::after {
+ content: leader('.') target-counter(attr(href), page);
+ }
+
+ #WritelyTableOfContents a {
+ text-decoration: none;
+ color: black;
+ }
+ }
+
+ @page {
+ @top {
+ content: flow(header);
+ }
+ @bottom {
+ content: flow(footer);
+ }
+ @footnotes {
+ border-top: solid black thin;
+ padding-top: 8pt;
+ }
+ }
+ /* end default print css */
+
+
+/* custom css */
+
+
+/* end custom css */
+
+
+
+ /* ui edited css */
+
+ body {
+ font-family: Verdana;
+
+ font-size: 10.0pt;
+ line-height: normal;
+ background-color: #ffffff;
+ }
+ /* end ui edited css */
+
+
+
+/* editor CSS */
+.editor a:visited {color: #551A8B}
+.editor table.zeroBorder {border: 1px dotted gray}
+.editor table.zeroBorder td {border: 1px dotted gray}
+.editor table.zeroBorder th {border: 1px dotted gray}
+
+
+.editor div.google_header, .editor div.google_footer {
+ border: 2px #DDDDDD dashed;
+ position: static;
+ width: 100%;
+ min-height: 2em;
+}
+
+.editor .misspell {background-color: yellow}
+
+.editor .writely-comment {
+ font-size: 9pt;
+ line-height: 1.4;
+ padding: 1px;
+ border: 1px dashed #C0C0C0
+}
+
+
+/* end editor CSS */
+</style>
+
+
+</head>
+
+<body onload="DoPageLoad();"
+
+ revision="dhkdd78p_13kvrgbnfb:231">
+
+
+
+
+<DIV>\r
+ <DIV>\r
+ <B>Geniwrapper Design Document</B>\r
+ </DIV>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>1.0 High Level Overview</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The purpose of Geniwrapper is to provide a Geni-like interface around the\r
+ existing planetlab infrastructure. The existing infrastructure consists of two\r
+ parts: planetlab central (PLC) and planetlab nodes. These two parts map\r
+ logically into the Geni Registry and Geni Components. However, it is not an\r
+ exact mapping. Due to the nature of planetlab, some component functionality\r
+ overlaps with PLC. For example, PLC takes an active role in managing state on\r
+ planetlab nodes, and therefore some Geni component state exists on PLC,\r
+ leading to some component APIs to exist on PLC.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Geniwrapper is comprised of the following logical modules: <I>utility\r
+ classes</I>, <I>registry wrapper</I>, <I>component wrapper</I>, and <I>command\r
+ line client</I>. Client-server communication uses a variant of XML-RPC called\r
+ the <I>Geni protocol</I>. Section 1 of this document presents a very brief\r
+ overview of each module. In-depth discussion occurs later.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Much of this design adheres to the SFA, and as such this document avoids\r
+ duplication of the information already presented in the SFA. For example, the\r
+ description of privileges, which operations are allowed by a specific\r
+ privileges, and how privileges are assigned to principals is described fully\r
+ in the SFA and is therefore not duplicated here.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ NOTE: <b>API documentation</b> is extracted from code comments automatically\r
+ and is maintained in separate files, one documentation file corresponding to\r
+ each python source file. An effort has been made to keep API documentation\r
+ separate from this document, so that the API documentation may be\r
+ self-maintaining as the code is updated.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Geniwrapper is checked into a subversion repository at\r
+ <A href=http://svn.planetlab.org/geniwrapper>http://svn.planetlab.org/geniwrapper</A>.\r
+ [TODO: verify link]\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <DIV>\r
+ <B>1.1 Utility classes</B>\r
+ </DIV>\r
+ <DIV>\r
+ \r
+ </DIV>\r
+ <DIV>\r
+ Utility classes include python classes that implement certificates, GIDs,\r
+ credentials, and tickets. There are also utility classes for implementing\r
+ the server and client stubs and the security protocol. The utility modules\r
+ are designed to be generally re-usable. For example, the credential\r
+ management class may be used as part of the Geni Registry, Geni Components,\r
+ and the end-user tools that interact with Geni.\r
+ </DIV>\r
+ <DIV>\r
+ \r
+ </DIV>\r
+ <DIV>\r
+ The utility classes are located in the\r
+ <I>util</I> subdirectory.\r
+ </DIV>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>1.2 The registry (PLC) wrapper</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The registry wrapper is intended to be colocated with PLC. All communication\r
+ between the registry wrapper and PLC uses the PLCAPI interface and as such,\r
+ the registry wrapper can be run on a separate machine for ease of development.\r
+ In addition to the Geni registry operations (register, update, ...), the\r
+ registry also implements component operations, such as GetTicket, that must be\r
+ located on PLC due to SFA engineering decisions.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The registry wrapper is located in the <I>registry</I> subdirectory\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ TODO: Slice interface shall be implemented in registry wrapper.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>1.3 The component wrapper</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The component wrapper is located on planetlab nodes. It implements the\r
+ component interface, management interface, and portions of the slice\r
+ interface. Due to SFA engineering decisions, some component operations (i.e.\r
+ GetTicket) are implemented in the registry wrapper instead of the component\r
+ wrapper.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The component wrapper is located in the <I>component</I> subdirectory.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>1.4 Command line client</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The command line client exports a client interface to Geni that may be used\r
+ for testing and demonstration purposes. It allows easy invocation of Geni api\r
+ functions and dumps the results in a human-readable format.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The command line client is located in the <I>cmdline</I>\r
+ subdirectory\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>1.5 Geni Protocol</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The Geni protocol is based on XML-RPC. It is implemented primarily in the\r
+ geniserver.py and geniclient.py files located with the utility classes.\r
+ Modifications to the XML-RPC protocol include the following:\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<OL>\r
+ <LI>\r
+ The transport mechanism uses HTTPS instead of HTTP.\r
+ <LI>\r
+ HTTPS certificate verification is disabled so that custom Geni\r
+ verification based on GID can be done instead.\r
+ <LI>\r
+ When an exception occurs on the server, verbose exception information is\r
+ sent to the client, to assist debugging efforts\r
+ </LI>\r
+</OL>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Authentication:\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Authentication of the client by the server is done by using Credentials/GIDs.\r
+ Generally, each operation contains a credential as the first argument. This\r
+ credential includes the GID of the caller, which in turn contains the public\r
+ key of the caller. The server ensures that this public key matches the public\r
+ key that is being used to decrypt the HTTPS connection, thus ensuring the\r
+ caller must posess the private key that corresponds to the GID.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Authentication of the server by the client is left as an exercise for the\r
+ client. It may be done easily by specifying the server's public key when the\r
+ client create the HTTPS connection. This presumes the client knows the public\r
+ key (or GID) of the server he is trying to connect to.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>2.0 Utility Classes</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>2.1 Certificates and Keys (cert.py)</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Geniwrapper uses two crypto libraries: pyOpenSSL and M2Crypto to implement the\r
+ necessary crypto functionality. Ideally just one of these libraries would be\r
+ used, but unfortunately each of these libraries is independently lacking. The\r
+ pyOpenSSL library is missing many necessary functions, and the M2Crypto\r
+ library has crashed inside of some of the functions. The design decision is to\r
+ use pyOpenSSL whenever possible as it seems more stable, and only use M2Crypto\r
+ for those functions that are not possible in pyOpenSSL.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>2.1.1 Keys</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Public-private key pairs are implemented by the <B>Keypair </B>class. A\r
+ Keypair object may represent both a public and private key pair, or it may\r
+ represent only a public key (this usage is consistent with OpenSSL).\r
+</DIV>\r
+<P>\r
+ \r
+</P>\r
+<DIV>\r
+ <B>2.1.2 Certificates</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The certificate class implements a general purpose X509 certificate, making\r
+ use of the appropriate pyOpenSSL or M2Crypto abstractions. It also adds\r
+ several addition features, such as the ability to maintain a chain of parent\r
+ certificates, and storage of application-specific data.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Certificates include the ability to maintain a chain of parents. Each\r
+ certificate includes a pointer to it's parent certificate. When loaded from a\r
+ file or a string, the parent chain will be automatically loaded. When saving a\r
+ certificate to a file or a string, the caller can choose whether to save the\r
+ parent certificates as well.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Example creation of a certificate:\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ # create a key for an issuer<BR>\r
+ issuerKey = Keypair(create=True)<BR>\r
+ issuerSubject = "testissuer"\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ # create a key for the certificate\r
+</DIV>\r
+<DIV>\r
+ userKey = KeyPair(create=True)\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ # create the certificate, set the issuer, and\r
+ sign it\r
+</DIV>\r
+<DIV>\r
+ cert = Certificate(subject="test")<BR>\r
+ cert.set_issuer(issuerKey, issuerSubject)\r
+</DIV>\r
+<DIV>\r
+ cert.set_pubkey(userKey)<BR>\r
+ cert.sign()\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>2.1.3 Certificate Verification</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <P>\r
+ Verification examines a chain of certificates to ensure that each parent\r
+ signs the child, and that some certificate in the chain is signed by a\r
+ trusted certificate. Verification is a basic recursion:\r
+ </P>\r
+ <PRE> if this_certificate was signed by trusted_certs:<BR> return<BR> else<BR> return verify_chain(parent, trusted_certs)</PRE>\r
+</DIV>\r
+<DIV>\r
+ At each recursion, the parent is tested to ensure that it did sign the child.\r
+ If a parent did not sign a child, then an exception is thrown. If the bottom\r
+ of the recursion is reached and the certificate does not match a trusted root,\r
+ then an exception is thrown.\r
+</DIV>\r
+<DIV>\r
+ <BR>\r
+ <B>2.2 GIDS (gid.py)</B>\r
+</DIV>\r
+<DIV>\r
+ <B></B> \r
+</DIV>\r
+<DIV>\r
+ GIDs are a derivative class of certificates and as such the GID class\r
+ inherits all the methods of the certificate class. A GID includes a tuple\r
+ of the following fields: \r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ (uuid, hrn, public_key)\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ UUID is a unique identifier and is created by the python uuid module (or the\r
+ utility function create_uuid() in gid.py).\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ HRN is a human readable name. It is a dotted form similar to a backward domain\r
+ name. For example, planetlab.us.arizona.bakers.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ PUBLIC_KEY is the public key of the principal identified by the UUID/HRN. It\r
+ is a Keypair object as defined in the cert.py module.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ It is expected that there is a one-to-one pairing between UUIDs and HRN, but\r
+ it is uncertain how this would be inforced or if it needs to be enforced.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>2.2.1 Encoding and Decoding</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The 5 fields of the GID tuple are stored in the subject-alt-name field of\r
+ the X509 certificate. Two routines are included to package and unpackage these\r
+ fields: Encode() and Decode(). Encode should be called prior to signing the\r
+ GID. Decode is automatically called on demand by the various get_*()\r
+ functions.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>2.2.2 Verification of GIDs</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+Verification first performs the checks of the certificate class (verifying that\r
+each parent signs the child, etc). In addition, GIDs also confirm that the\r
+parent's HRN is a prefix of the child's HRN. Verifying these prefixes prevents a\r
+rogue authority from signing a GID for a principal that is not a member of that\r
+authority. For example, planetlab.us.arizona cannot sign a GID for\r
+planetlab.us.princeton.foo.\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>2.3 Credentials (credential.py)</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Credentials are a derivative class of certificates and as such the credential\r
+ class inherits all the methods of the certificate class. A credential includes\r
+ a tuple of the following fields:\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ (GIDCaller, GIDObject, LifeTime, Privileges, Delegate)\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ GIDCaller identifies the holder of the credential. When a credential is\r
+ presented to a component, the security layer ensures that the client matches\r
+ the public key that is contained in GIDCaller.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ GIDObject identifies the object of the credential. This object depends upon\r
+ the type of the credential. For example, the credential for a user likely has\r
+ GIDObject == GIDCaller. Credentials for slices would include the GID of the\r
+ slice in the GIDObject field. Credentials for authorities include the GID of\r
+ the authority in the GIDObject field.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ LifeTime is the lifetime of the credential. Currently not implemented; expect\r
+ to implement it as an expiration date, and refuse credentials beyond that\r
+ date.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Privileges is a Rights object that describes the rights that are granted to\r
+ the holder of the credential.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Delegate is a True/False bit that indicates whether or not a credential can be\r
+ delegated to a different caller.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>2.3.1 Encoding and Decoding</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The 5 fields of the credential tuple are stored in the subject-alt-name field\r
+ of the X509 certificate. Two routines are included to package and unpackage\r
+ these fields: Encode() and Decode(). Encode should be called prior to signing\r
+ the credential. Decode is automatically called on demand by the various\r
+ get_*() functions.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>2.3.2 Verification of Credentials</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ In addition to the checks for ordinary certificates, verification of\r
+ credentials also ensures that the delegate bit was set by each parent in the\r
+ chain. If a delegate bit was not set, then an exception is thrown. Each\r
+ credential must also contain a subset of the rights of the parent credential\r
+ (i.e. a user credential cannot delegate authority rights).<BR>\r
+ <BR>\r
+ <B>2.4 Rights (rights.py)<BR>\r
+ <BR>\r
+ </B>Rights are implemented by two classes:<BR>\r
+ <BR>\r
+ Right - represents a single right<BR>\r
+ RightList - represents a list of rights A right may allow several different\r
+ operations.<BR>\r
+ <BR>\r
+ For example, the "info" right allows "listslices", "listcomponentresources",\r
+ etc.<BR>\r
+ <BR>\r
+ <B>2.5 Records (record.py)</B><BR>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The GeniRecord class implements a Geni Record. The GeniRecord class implements\r
+ an abstract interface for the record, so that a client may use records without\r
+ having to understant the underlying implementation details, such as whether\r
+ the record is realized in the registry database, a local cache, or has been\r
+ transmitted over the wire by an interface. A GeniRecord is a tuple (Name, GID,\r
+ Type, Info).\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Name specifies the HRN of the object GID is the GID of the object\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Type is user | sa | ma | slice | component Info is comprised of the\r
+ following sub-fields\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Pointer is a pointer to the record in the PL database\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ pl_info is planetlab-specific info (when talking to client)\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ geni_info = geni-specific info (when talking to client)\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The pointer is interpreted depending on the type of the record. For example,\r
+ if the type=="user", then pointer is assumed to be a person_id that indexes\r
+ into the persons table.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ A given HRN may have more than one record, provided that the records are of\r
+ different types. For example, planetlab.us.arizona may have both an SA and a\r
+ MA record, but cannot have two SA records.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>2.6 Tickets (geniticket.py)</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Similar to GIDs and Credentials, tickets also leverage the certificate object.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ A Ticket is tuple:<BR>\r
+ (gidCaller, gidObject, attributes, rspec, delegate)<BR>\r
+ <BR>\r
+ gidCaller = GID of the caller performing the operation<BR>\r
+ gidObject = GID of the slice<BR>\r
+ attributes = slice attributes (keys, vref, instantiation,\r
+ etc)<BR>\r
+ rspec = resources\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Tickets are created by invoking GetTicket() on the Registry. The slice\r
+ attributes and rspec are taken from the planetlab slice database and represent\r
+ the current state of the slice. As of yet, tickets do not include any concept\r
+ of time -- a ticket represents the state of the slice at the current time\r
+ only.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Tickets are redeemed by invoking RedeemTicket() on the Registry. The\r
+ attributes and spec are combined back into a planetlab slice record and handed\r
+ off to the node manager.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Tickets are signed by an authority and include parentage information that\r
+ traces the chain of authorities back to a trusted root.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>2.6.1 rspecs</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The rspec is currently a dictionary of {name: value} pairs. These pairs are\r
+ taken verbatim from the planetlab slice database.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The general rule that is used is that things in the slice record that do not\r
+ specifically imply a tangible resource (initscripts, keys, etc) are treated as\r
+ attributes and things that do specify a tangible resource (disk, network, etc)\r
+ are treated as the rspec.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ TODO: The definition of an rspec is evolving. It remains to reconcile the\r
+ eclipse schema with Geniwrapper. Gacks is also using another rspec format,\r
+ which may be need to be reconciled with the eclipse schema and/or geniwrapper.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <DIV>\r
+ <B>2.6.2 Encoding and Decoding</B>\r
+ </DIV>\r
+ <DIV>\r
+ \r
+ </DIV>\r
+ <DIV>\r
+ The 5 fields of the credential tuple are stored in the subject-alt-name\r
+ field of the X509 certificate. Two routines are included to package and\r
+ unpackage these fields: Encode() and Decode(). Encode should be called prior\r
+ to signing the ticket. Decode is automatically called on demand by the\r
+ various get_*() functions.\r
+ </DIV>\r
+ <DIV>\r
+ \r
+ </DIV>\r
+ <DIV>\r
+ <B>2.6.3 Verification of Tickets</B>\r
+ </DIV>\r
+ <DIV>\r
+ \r
+ </DIV>\r
+ <DIV>\r
+ Verification uses the standard parentage verification provided by the\r
+ certificate class. Specifically, each certificate is signed by a parent, and\r
+ some certificate must resolve to the trusted root set that is specified on\r
+ the component.\r
+ </DIV>\r
+ <DIV>\r
+ \r
+ </DIV>\r
+ <DIV>\r
+ Unlike credentials and GIDs, the parent of a ticket may be a degenerate\r
+ ticket that does not include the full 5-tuple (caller, object, attributes,\r
+ rspec, delegate). In such a case, the parent is just a placeholder in the\r
+ chain of authority used to convey the parentage information.\r
+ </DIV>\r
+ <DIV>\r
+ \r
+ </DIV>\r
+ <DIV>\r
+ Delegation of tickets is not something that is discussed in the SFA, but it\r
+ is supported in the ticket class and may be a useful feature. For example,\r
+ Alice may hold a ticket for a particular component, and delegate that ticket\r
+ to Bob. Bob could then instantiate a slice for Alice. This may be one way to\r
+ implement a slice manager.<BR>\r
+ <BR>\r
+ <B>2.7 Hierarchy of Authorities (hierarchy.py)</B><BR>\r
+ <BR>\r
+ This module implements a hierarchy of authorities and performs a similar\r
+ function as the "tree" module of the original geniwrapper prototype. An HRN\r
+ is assumed to be a string of authorities separated by dots. For example,\r
+ "planetlab.us.arizona.bakers". Each component of the HRN is a different\r
+ authority, with the last component being a leaf in the tree. Each authority\r
+ is stored in a subdirectory on the registry.<BR>\r
+ <BR>\r
+ Inside this subdirectory are several files:<BR>\r
+ *.GID - GID file<BR>\r
+ *.PKEY - private key file<BR>\r
+ *.DBINFO - database info<BR>\r
+ <BR>\r
+ The hierarchy class can be used to create GIDs, Credentials, and Tickets for\r
+ a given authority.\r
+ </DIV>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The default behavior is that all authorities contained in the hierarchy will\r
+ be located together in a single physical registry. However, this is not\r
+ strictly necessary. The *.DBINFO files contain the database information for an\r
+ authority and can easily be configured to point to other machines. How an\r
+ authority would cause the DBINFO files to be installed in the correct places\r
+ is left as a separate exercise, possibly via an out-of-band management\r
+ interface or a web page.\r
+</DIV>\r
+<DIV>\r
+ <BR>\r
+ <B>2.8 Configuration Information (config.py)</B><BR>\r
+ <BR>\r
+ This module holds configuration parameters for geniwrapper. There are two main\r
+ pieces of information that are used: the database connection and the PLCAPI\r
+ connection.<BR>\r
+ <BR>\r
+ Geniwrapper uses a MYSQL database to store records. This database may be\r
+ co-located with the PLC database, or it may be a separate database. The\r
+ following parameters define the connection to the database. Note that\r
+ Geniwrapper does not access any of the PLC databases directly via a mysql\r
+ connection; All PLC databases are accessed via PLCAPI.<BR>\r
+</DIV>\r
+<P>\r
+ Geniwrapper uses a PLCAPI connection to perform operations on the registry,\r
+ such as creating and deleting slices. This connection requires an account on\r
+ the PLC server with full administrator access. The Url parameter controls\r
+ whether the connection uses PLCAPI directly (i.e. Geniwrapper is located on\r
+ the same machine as PLC), or uses a XMLRPC connection to the PLC machine. If\r
+ you wish to use the API directly, then remove the Url field from the\r
+ dictionary.\r
+</P>\r
+<DIV>\r
+ <BR>\r
+ <B>2.8.1 Database Configuration</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Below is an example database configuration from config.py:\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ def get_default_dbinfo():<BR>\r
+ dbinfo={}<BR>\r
+ dbinfo['dbname'] = 'planetlab4'<BR>\r
+ dbinfo['address'] = 'localhost'<BR>\r
+ dbinfo['port'] = 5432<BR>\r
+ dbinfo['user'] = 'pgsqluser'<BR>\r
+ dbinfo['password'] = '4c77b272-c892-4bdf-a833-dddeeee1a2ed'\r
+</DIV>\r
+<DIV>\r
+ return dbinfo\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ This identifies several important pieces of the database configuration. The\r
+ name specifies the database name as used by pgsql. The address is the hostname\r
+ (or ip-address) of the machine that is hosting the database. It is most likely\r
+ the local machine. Port specifies the socket port where the pgsql is\r
+ listening. The user and password authenticate Geniwrapper to the pgsql\r
+ database. In this example, an existing PLC database was used. This is not\r
+ strictly necessary as only Geni-specific information is stored in this\r
+ database. A separate database could be used, on a separate machine than PLC if\r
+ desired.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>2.8.2 PLCAPI Configuration</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Blow is an example PLCAPI configuration from config.py:\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ def get_pl_auth():<BR>\r
+ pl_auth = {'Username':\r
+ <A href="mailto:'root@198.0.0.132'">'root@198.0.0.132'</A>,<BR>\r
+ 'AuthMethod': 'password',<BR>\r
+ 'AuthString': 'root',<BR>\r
+ "Url":\r
+ "<A href=https://localhost/PLCAPI/>https://localhost:443/PLCAPI/</A>"<BR>\r
+ }\r
+</DIV>\r
+<DIV>\r
+ return pl_auth\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The PLCAPI configuration tells Geniwrapper how to connect to PLC. There are\r
+ two options: a local connection or a remote connection. If the Url field is\r
+ defined, then a remote connection is assumed, and Geniwrapper will attempt to\r
+ connect via XMLRPC to a remote PLCAPI server. If the Url field is not defined,\r
+ then Geniwrapper will assume that PYTHONPATH includes the relevant PLCAPI\r
+ classes to use PLCAPI directly.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Username specifies the name of the PLCAPI user. It is suggested that a user\r
+ with full administrative authority be allowed. Otherwise, Geniwrapper will be\r
+ unable to lookup public keys and other information that PLC does not make\r
+ available publicly. Administrative permission is also required to create PLC\r
+ sites, users, etc. Authmethod and AuthString specify the password require to\r
+ use this account.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>3.0 The Registry Wrapper</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ This wrapper implements the Geni Registry. According to the SFA, the basic\r
+ functionality of a registry is to map HRNs into records. However, because of\r
+ the interactions between Geniwrapper and PLC, the registry does more than act\r
+ as a simple database. The registry performs API calls on PLC that create\r
+ slices, sites, users, etc., and as such may indirectly cause slices to be\r
+ instantiated on components, because components are also linked to PLC.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The mapping of Geni objects to planetlab objects is relatively\r
+ straightforward:\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ slice = slice\r
+</DIV>\r
+<DIV>\r
+ user = person\r
+</DIV>\r
+<DIV>\r
+ component = node\r
+</DIV>\r
+<DIV>\r
+ sa = site\r
+</DIV>\r
+<DIV>\r
+ ma = site\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The one part that is slightly counterintuitive is SA and MA, which both map to\r
+ the planetlab site object. In a unified registry (a registry that serves as\r
+ both slice and component registry), these will map to the same site record in\r
+ the PLC database. However, there are two distinct Geni records, one for\r
+ the SA and one for the MA. \r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Registry operations generally authenticate the caller by credential.\r
+ There are a few exceptions, and the registry API documents should note\r
+ those exceptions. \r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>3.1 Registry Tools</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The registry include several additional tools that are used to manage it.\r
+ These include:\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ import.py - imports existing PLC records into the registry\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ nuke.py - deletes all Geni records\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>3.1 Bootstrapping a Registry</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ There are several items that need to be done before starting the registry.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ 1) Update util/config.py to match the parameters of your PLC installation.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ 2) Import the existing planetlab database, creating the appropriate geni\r
+ records. This is done by running the "import.py" tool.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ 3) Create a "trusted_roots" directory and place the certificate of the root\r
+ authority in that directory. Given the defaults in import.py, this certificate\r
+ would be named "planetlab.gid". For example, mkdir trusted_roots; cp\r
+ authorities/planetlab.gid trusted_roots/\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>4.0 The Component Wrapper</B>\r
+</DIV>\r
+<DIV>\r
+ <BR>\r
+ The Geni Component Wrapper implements the Geni Component Manager. It includes\r
+ functions for redeeming tickets, starting/stopping/resetting/deleting slices,\r
+ and management such as rebooting the component.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The design of the component differs from the registry wrapper in the respect\r
+ that the component wrapper must be located physically on the planetlab node\r
+ that it is responsible for. The component wrapper interacts directly with\r
+ portions of the node manager code on the node.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>4.1 Component Authentication of Credentials</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The component authenticates credentials the same way that the registry does.\r
+ Specifically, there is a directory of trusted_root certificates (or GIDs) on\r
+ the component. Any credential presented to the component must include in it's\r
+ parentage some certificate in the set of trusted roots. Otherwise, and\r
+ exception is thrown.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>4.2 The Ticket interface</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The ticket interface is split between the Registry (PLC) and the Component.\r
+ This is due to the SFA engineering decisions, specifically that the\r
+ authoritative copy of planetlab state is stored on PLC and only cached on the\r
+ components. Thus, GetTicket() is implemented on the Registry, and\r
+ RedeemTicket() is implemented on the component. InstantiateSlice is not\r
+ implemented, as that operation is a combination of GetTicket/RedeemTicket and\r
+ would therefore span the Registry and Component.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>4.3 Sliver Credentials</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ A recent Geni Architecture call mentioned the need for sliver credentials. A\r
+ sliver credential would be identical to a slice credential, but would 1) only\r
+ be redeemable on a particular component, and 2) would resolve to a\r
+ trusted_root unique to that component (likely the component's GID\r
+ certificate). Sliver credentials would be returned by the RedeemTicket call\r
+ and would give the caller the permission required to start and stop the\r
+ sliver, etc.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Sliver credentials are not yet implemented, but their implementation would be\r
+ straightforward.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>4.4 Bootstrapping the Component Wrapper</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The first step is to install some required libraries on the component. These\r
+ include the m2crypto and pyopenssl libraries. Installing the actual RPMs for\r
+ these libaries on a running component proved difficult due to additional\r
+ support packages that require installation (python-devel, etc). For\r
+ development purposes, it was sufficient to copy the installed/compiled version\r
+ of the libraries from the development machine to the component.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The second step is to copy the files required by the component wrapper to\r
+ the node manager. They are copied to the /usr/share/Nodemanager directory. A\r
+ list of the files is contained in the copynode.sh script in the component\r
+ subdirectory.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The third step is to copy the trusted root certificates to the component. They\r
+ are stored in /usr/share/Nodemanager/trusted_roots. This should include the\r
+ certificate for the registry.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The fourth step is to start the component manager. This is done by\r
+ connecting to the component via SSH and running\r
+ /usr/share/Nodemanager/component.py.\r
+</DIV>\r
+<DIV>\r
+ <BR>\r
+ In a production environment, all of these steps would be integrated into the\r
+ DVD boot image for the planetlab node.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>5.0 Command-Line Interface</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ A command-line interface is provided that allows a user to interact with the\r
+ Geni Registry and Component. This command line interface is located in the\r
+ cmdline directory and can be invoked by running genicli.py. Specifying\r
+ "genicli.py help" will display a list of available commands.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>5.1 Examples</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Several examples of using the CLI are presented in the form of shell scripts\r
+ in the cmdline directory. These scripts demonstrate creating slices,\r
+ authorities, users, nodes, and getting tickets and redeeming tickets. Rather\r
+ than duplicating all of those examples here, a few short examples are\r
+ presented below.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>5.1.1 Getting a Credential</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ python ./genicli.py --username root --credfile None --outfile test.cred\r
+ getCredential user planetlab.us.pl.account_test\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The credential for planetlab.us.pl.account_test is retrieved and stored in the\r
+ local file test.cred. The private ket test.pkey is used when opening the\r
+ XMLRPC connection and authenticates the client. test.pkey must match the\r
+ public key that is in the GID for the user record for\r
+ planetlab.us.pl.account_test.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Sample output: (in human-readable summary)\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ CREDENTIAL planetlab.us.pl.account_test<BR>\r
+ privs: refresh,resolve,info<BR>\r
+ gidCaller:<BR>\r
+ hrn:\r
+ planetlab.us.pl.account_test<BR>\r
+ uuid:\r
+ 276262316202422735940395896620385479122<BR>\r
+ gidObject:<BR>\r
+ hrn:\r
+ planetlab.us.pl.account_test<BR>\r
+ uuid:\r
+ 276262316202422735940395896620385479122<BR>\r
+ delegate: False\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>5.1.2 Resolving a record</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ python ./genicli.py --username test resolve planetlab.us.pl.account_test\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The record for planetlab.us.pl.account_test is retrieved and printed to\r
+ stdout. The credential used comes from the local file test.cred.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Sample output: (in human-readable summary)\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ RECORD planetlab.us.pl.account_test<BR>\r
+ hrn: planetlab.us.pl.account_test<BR>\r
+ type: user<BR>\r
+ gid:<BR>\r
+ hrn:\r
+ planetlab.us.pl.account_test<BR>\r
+ uuid:\r
+ 276262316202422735940395896620385479122<BR>\r
+ pointer: 6<BR>\r
+ geni_info:<BR>\r
+ email :\r
+ <A href=mailto:test@test.com>test@test.com</A><BR>\r
+ pl_info:<BR>\r
+ bio : None<BR>\r
+ first_name : test<BR>\r
+ last_name : account<BR>\r
+ last_updated : 1222497672<BR>\r
+ uuid : None<BR>\r
+ roles : ['user']<BR>\r
+ title : None<BR>\r
+ url : None<BR>\r
+ key_ids : [1]<BR>\r
+ enabled : True<BR>\r
+ slice_ids : [24]<BR>\r
+ phone : None<BR>\r
+ peer_person_id : None<BR>\r
+ role_ids : [30]<BR>\r
+ person_id : 6<BR>\r
+ date_created : 1219083140<BR>\r
+ site_ids : [1]<BR>\r
+ peer_id : None<BR>\r
+ email :\r
+ <A href=mailto:test@test.com>test@test.com</A>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>5.1.3 Updating a record</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ python ./genicli.py --username test update user planetlab.us.pl.account_test\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ The record for planetlab.us.pl.account_test is updated. The credential used\r
+ comes from the local file test.cred. No changes are specified, so the only\r
+ thing that should be updated is the expiration time.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ <B>5.1.4 Resolving an authority</B>\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ An authority is an example of an HRN that might resolve to two different\r
+ records, an SA and a MA record.\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ python ./genicli.py --username test resolve planetlab.us.pl\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ Sample Output: (in human readable summary)\r
+</DIV>\r
+<DIV>\r
+ \r
+</DIV>\r
+<DIV>\r
+ RECORD planetlab.us.pl<BR>\r
+ hrn: planetlab.us.pl<BR>\r
+ type: sa<BR>\r
+ gid:<BR>\r
+ hrn: planetlab.us.pl<BR>\r
+ uuid:\r
+ 294786197975089072547582920862317666209<BR>\r
+ pointer: 1<BR>\r
+ geni_info:<BR>\r
+ pi :\r
+ ['planetlab.us.pl.Administrator_Default']<BR>\r
+ pl_info:<BR>\r
+ last_updated : 1224136003<BR>\r
+ node_ids : [1]<BR>\r
+ site_id : 1<BR>\r
+ pcu_ids : []<BR>\r
+ max_slices : 100<BR>\r
+ ext_consortium_id : None<BR>\r
+ peer_site_id : None<BR>\r
+ abbreviated_name : plctest<BR>\r
+ uuid :\r
+ 230749975723590978208303655640765327534<BR>\r
+ person_ids : [2, 4, 6]<BR>\r
+ slice_ids : [24, 1, 2]<BR>\r
+ latitude : None<BR>\r
+ peer_id : None<BR>\r
+ max_slivers : 1000<BR>\r
+ is_public : False<BR>\r
+ address_ids : []<BR>\r
+ name : plctest Central<BR>\r
+ url :\r
+ <A href=http://198.0.0.132/>http://198.0.0.132/</A><BR>\r
+ enabled : True<BR>\r
+ longitude : None<BR>\r
+ login_base : pl<BR>\r
+ date_created : 1209428329<BR>\r
+ RESULT:<BR>\r
+ RECORD planetlab.us.pl<BR>\r
+ hrn: planetlab.us.pl<BR>\r
+ type: ma<BR>\r
+ gid:<BR>\r
+ hrn: planetlab.us.pl<BR>\r
+ uuid:\r
+ 294786197975089072547582920862317666209<BR>\r
+ pointer: 1<BR>\r
+ geni_info:<BR>\r
+ operator : []<BR>\r
+ owner :\r
+ ['planetlab.us.pl.Administrator_Default']<BR>\r
+ pl_info:<BR>\r
+ last_updated : 1224136003<BR>\r
+ node_ids : [1]<BR>\r
+ site_id : 1<BR>\r
+ pcu_ids : []<BR>\r
+ max_slices : 100<BR>\r
+ ext_consortium_id : None<BR>\r
+ peer_site_id : None<BR>\r
+ abbreviated_name : plctest<BR>\r
+ uuid :\r
+ 230749975723590978208303655640765327534<BR>\r
+ person_ids : [2, 4, 6]<BR>\r
+ slice_ids : [24, 1, 2]<BR>\r
+ latitude : None<BR>\r
+ peer_id : None<BR>\r
+ max_slivers : 1000<BR>\r
+ is_public : False<BR>\r
+ address_ids : []<BR>\r
+ name : plctest Central<BR>\r
+ url :\r
+ <A href=http://198.0.0.132/>http://198.0.0.132/</A><BR>\r
+ enabled : True<BR>\r
+ longitude : None<BR>\r
+ login_base : pl<BR>\r
+ date_created : 1209428329\r
+</DIV>\r
+<BR>
\ No newline at end of file