added command-line record editer, a few SFI demo scripts
authorScott Baker <bakers@cs.arizona.edu>
Fri, 23 Jan 2009 19:57:49 +0000 (19:57 +0000)
committerScott Baker <bakers@cs.arizona.edu>
Fri, 23 Jan 2009 19:57:49 +0000 (19:57 +0000)
cmdline/editRecord.py [new file with mode: 0644]
cmdline/genicli.py
cmdline/sfi.py
cmdline/testSfi.sh [new file with mode: 0644]
cmdline/testSfiSliceRegister.sh [new file with mode: 0644]
cmdline/testUser.sh

diff --git a/cmdline/editRecord.py b/cmdline/editRecord.py
new file mode 100644 (file)
index 0000000..74d5d58
--- /dev/null
@@ -0,0 +1,172 @@
+#! /usr/bin/env python
+from __future__ import with_statement
+
+# sfi -- slice-based facility interface
+
+import sys
+import os, os.path
+import getopt
+from util.cert import Keypair, Certificate
+from util.credential import Credential
+from util.geniclient import GeniClient
+from util.record import GeniRecord
+from util.gid import GID
+
+infile = None
+outfile = None
+gidfile = None
+email = None
+ip = None
+dns = None
+hrn = None
+type = None
+dump = False
+researcher = []
+
+long_opts = ["infile=", "outfile=", "email=", "ip=", "dns=", "gidfile=", "hrn=", "type=", "addresearcher=", "delresearcher=", "dump"]
+
+def showhelp():
+   print "syntax: editRecord.py <options>"
+   print "    --help                ... show help"
+   print "    --infile <name>       ... read record from file"
+   print "    --outfile <name>      ... write record to file"
+   print "    --dump                ... dump record to stdout"
+   print "    --gidfile <fn>        ... load gid from file"
+   print "    --hrn <name>          ... set hrn"
+   print "    --type <type>         ... set type (user|slice|sa|ma|...)"
+   print "    --email <addr>        ... user: set email address"
+   print "    --ip <addr>           ... node: set ip address"
+   print "    --dns <hostname>      ... node: set hostname"
+   print "    --addresearcher <hrn> ... slice: add researcher"
+   print "    --delresearcher <hrn> ... slice: delete researcher"
+
+def process_options():
+   global infile, outfile
+   global email, ip, dns, gidfile, hrn, type
+   global researcher
+   global dump
+
+   (options, args) = getopt.getopt(sys.argv[1:], '', long_opts)
+   for opt in options:
+       name = opt[0]
+       val = opt[1]
+
+       if name == "--help":
+           showhelp()
+           sys.exit(0)
+       elif name == "--infile":
+           infile = val
+       elif name == "--outfile":
+           outfile = val
+       elif name == "--email":
+           email = val
+       elif name == "--ip":
+           ip = val
+       elif name == "--dns":
+           dns = val
+       elif name == "--gidfile":
+           gidfile = val
+       elif name == "--hrn":
+           hrn = val
+       elif name == "--type":
+           type = val
+       elif name == "--dump":
+           dump = True
+       elif name == "--addresearcher":
+           researcher.append(val)
+       elif name == "--delresearcher":
+           researcher.append("-" + val)
+
+def errorcheck(record):
+   geni_info = record.get_geni_info()
+
+   if not record.type:
+       print "Warning: no type specified"
+   if not record.type in ["user", "sa", "ma", "slice", "node"]:
+       print "Warning: unknown record type"
+   if not record.name:
+       print "Warning: unknown record name"
+   if not record.gid:
+       print "Warning: unknown record gid"
+
+   if record.type == "user":
+       if not geni_info.get("email",None):
+           print "Warning: unknown email in user record"
+
+   if record.type == "node":
+       if not geni_info.get("ip",None):
+           print "Warning: unknown ip in node record"
+       if not geni_info.get("dns",None):
+           print "Warning: unknown dns in node record"
+
+# updates is a list of items to add or remove. If an item starts with "-", then
+# it will be removed. Otherwise it will be added
+def update_list(dict, listname, updates):
+   list = dict.get(listname, [])
+   for hrn in updates:
+       if hrn.startswith("-"):
+           real_hrn = hrn[1:]
+           if real_hrn in list:
+               list.delete(real_hrn)
+       else:
+           if not hrn in list:
+               list.append(hrn)
+
+   dict[listname] = list
+
+def main():
+   process_options()
+
+   # if the user didn't tell us to do much of anything, then maybe he needs
+   # some help
+   if (not infile) and (not outfile) and (not dump):
+       showhelp()
+       return
+
+   if infile:
+       str = file(infile, "r").read()
+       record = GeniRecord(string = str)
+   else:
+       record = GeniRecord()
+
+   geni_info = record.get_geni_info()
+   geni_info_orig = geni_info.copy()
+
+   if email:
+       geni_info["email"] = email
+
+   if ip:
+       geni_info["ip"] = ip
+
+   if dns:
+       geni_info["dns"] = dns
+
+   if hrn:
+       record.name = hrn
+
+   if type:
+       record.type = type
+
+   if gidfile:
+       gid_str = file(gidfile, "r").read()
+       gid = GID(string=gid_str)
+       record.set_gid(gid)
+
+   if researcher:
+       update_list(geni_info, "researcher", researcher)
+
+   if (geni_info != geni_info_orig):
+       record.set_geni_info(geni_info)
+
+   errorcheck(record)
+
+   if dump:
+       record.dump(False)
+
+   if outfile:
+       str = record.save_to_string()
+       file(outfile, "w").write(str)
+       print "wrote record to", outfile
+
+if __name__=="__main__":
+   main()
index 2006460..40c9ff9 100644 (file)
@@ -32,6 +32,8 @@ gid_pkey_fn = None
 gid_fn = None
 filter = None
 
+dump_fn = None
+
 dump_parents = False
 
 leaf_name = None
@@ -58,7 +60,8 @@ def showhelp():
    print "    --short          ... list records in short format (name only)"
    print "commands:"
    print "    resolve <hrn>"
-   print "    dumpCredential"
+   print "    dumpCredential <filename>"
+   print "    dumpGid <filename>"
    print "    getCredential <type> <hrn>"
    print "    list <hrn>"
    print "    start <hrn>"
@@ -82,6 +85,7 @@ def process_options():
    global server_url
    global filter
    global short
+   global dump_fn
 
    (options, args) = getopt.getopt(sys.argv[1:], '', long_opts)
    for opt in options:
@@ -179,6 +183,12 @@ def process_options():
            sys.exit(-1)
        hrn = args[1]
 
+   elif opname == "dumpGid":
+       if len(args) < 2:
+           print "syntax: dumpGid <filename>"
+           sys.exit(-1)
+       dump_fn = args[1]
+
    leaf_name = get_leaf(username)
 
    if cert_file == None:
@@ -208,6 +218,10 @@ def get_authority(x):
 def dumpCredential():
    pass
 
+def dumpGid():
+   gid = GID(filename = dump_fn)
+   gid.dump()
+
 # creates a self-signed certificate and private key
 def createKey():
    k = Keypair(create=True)
@@ -253,7 +267,7 @@ def main():
 
    # if the operation is not a local operation, then create a geniclient to
    # talk to the server
-   if (opname != "dumpCredential") and (opname != "help") and (opname != "createKey"):
+   if (opname != "dumpCredential") and (opname != "help") and (opname != "createKey") and (opname != "dumpGid"):
        if not os.path.exists(key_file):
            print "key file", key_file, "does not exist"
            sys.exit(-1)
@@ -269,7 +283,7 @@ def main():
 
    # if a cred_file was specified, then load the credential
    if (cred_file=="None") or (opname == "help") or (opname == "createKey") or \
-      (opname == "redeemTicket"):
+      (opname == "redeemTicket") or (opname == "dumpCredential") or (opname == "dumpGid"):
       cred = None
    else:
       cred = Credential(filename = cred_file)
@@ -277,6 +291,9 @@ def main():
    if opname == "dumpCredential":
       dumpCredential()
 
+   elif opname == "dumpGid":
+      dumpGid()
+
    elif opname == "help":
       showhelp()
 
index 6d442ed..f9e53a2 100755 (executable)
@@ -5,10 +5,13 @@ from __future__ import with_statement
 
 import sys
 import os, os.path
+import tempfile
 from optparse import OptionParser
 from util.cert import Keypair, Certificate
 from util.credential import Credential
 from util.geniclient import GeniClient
+from util.gid import create_uuid
+from util.record import GeniRecord
 
 sfi_dir = os.path.expanduser("~/.sfi/")
 slicemgr = None
@@ -139,7 +142,11 @@ def get_user_cred():
 def get_auth_cred():
    global authority
 
-   file = os.path.join(sfi_dir, "authority.cred")
+   if not authority:
+      print "no authority specified. Use -a or set SF_AUTH"
+      sys.exit(-1)
+
+   file = os.path.join(sfi_dir, get_leaf("authority") +".cred")
    if (os.path.isfile(file)):
       auth_cred = Credential(filename=file)
       return auth_cred
@@ -182,7 +189,7 @@ def get_rspec_file(rspec):
    if (os.path.isfile(file)):
       return file
    else:
-      print "No such rspec file"
+      print "No such rspec file", rspec
       sys.exit(1)
 
 def get_record_file(record):
@@ -193,9 +200,24 @@ def get_record_file(record):
    if (os.path.isfile(file)):
       return file
    else:
-      print "No such registry record file"
+      print "No such registry record file", record
       sys.exit(1)
 
+def load_publickey_string(fn):
+   f = file(fn,"r")
+   key_string = f.read()
+
+   # if the filename is a private key file, then extract the public key
+   if "PRIVATE KEY" in key_string:
+       outfn = tempfile.mktemp()
+       cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
+       os.system(cmd)
+       f = file(outfn, "r")
+       key_string = f.read()
+       os.remove(outfn)
+
+   return key_string
+
 
 #
 # Generate sub-command parser
@@ -204,6 +226,7 @@ def create_cmd_parser(command, additional_cmdargs = None):
    cmdargs = {"list": "name",
               "show": "name",
               "remove": "name",
+              "creategid": "hrn publickey_fn",
               "add": "name record",
               "update": "name record",
               "nodes": "[name]",
@@ -238,7 +261,7 @@ def create_cmd_parser(command, additional_cmdargs = None):
            help="type filter (user|slice|sa|ma|node|aggregate)",
            choices=("user","slice","sa","ma","node","aggregate", "all"),
            default="all")
-   if command in ("show", "list", "nodes", "resources"):
+   if command in ("show", "list", "nodes", "resources", "creategid"):
       parser.add_option("-o", "--output", dest="file",
            help="output XML to file", metavar="FILE", default=None)
    return parser
@@ -340,23 +363,40 @@ def remove(opts, args):
    auth_cred = get_auth_cred()
    return registry.remove(auth_cred, opts.type, args[0])
 
+def creategid(opts, args):
+   global registry
+   auth_cred = get_auth_cred()
+   hrn = args[0]
+   pkey_string = load_publickey_string(args[1])
+   gid = registry.create_gid(auth_cred, hrn, create_uuid(), pkey_string)
+   if (opts.file is not None):
+      gid.save_to_file(opts.file, save_parents=True)
+   else:
+      print "I created your gid, but you did not ask me to save it"
+
 # add named registry record
 def add(opts, args):
    global registry
    auth_cred = get_auth_cred()
-   rec_file = get_record_file(args[1])
-   with open(rec_file) as f:
-      record = f.read()
+   rec_file = get_record_file(args[0])
+   record = load_record_from_file(rec_file)
    return registry.register(auth_cred, record)
 
 # update named registry entry
 def update(opts, args):
    global registry
    user_cred = get_user_cred()
-   rec_file = get_record_file(args[1])
-   with open(rec_file) as f:
-      record = f.read()
-   return registry.update(user_cred, record)
+   rec_file = get_record_file(args[0])
+   record = load_record_from_file(rec_file)
+
+   if record.get_type() == "user":
+       cred = user_cred
+   elif record.get_type() in ["sa", "ma", "slice", "node"]:
+       cred = get_auth_cred()
+   else:
+       raise "unknown record type" + record.get_type()
+
+   return registry.update(cred, record)
 
 #
 # Slice-related commands
@@ -387,7 +427,7 @@ def slices(opts, args):
 # show rspec for named slice
 def resources(opts, args):
    global slicemgr
-   slice_cred = get_slice_cred(args[0]) 
+   slice_cred = get_slice_cred(args[0])
    result = slicemgr.get_slice_resources(slice_cred, args[0])
    display_rspec(opts.format, result)
    if (opts.file is not None):
@@ -397,7 +437,7 @@ def resources(opts, args):
 # created named slice with given rspec
 def create(opts, args):
    global slicemgr
-   slice_cred = get_slice_cred(args[0]) 
+   slice_cred = get_slice_cred(args[0])
    rspec_file = get_rspec_file(args[1])
    with open(rspec_file) as f:
       rspec = f.read()
@@ -406,25 +446,25 @@ def create(opts, args):
 # delete named slice
 def delete(opts, args):
    global slicemgr
-   slice_cred = get_slice_cred(args[0]) 
+   slice_cred = get_slice_cred(args[0])
    return slicemgr.delete_slice(slice_cred)
 
 # start named slice
 def start(opts, args):
    global slicemgr
-   slice_cred = get_slice_cred(args[0]) 
+   slice_cred = get_slice_cred(args[0])
    return slicemgr.start_slice(slice_cred)
 
 # stop named slice
 def stop(opts, args):
    global slicemgr
-   slice_cred = get_slice_cred(args[0]) 
+   slice_cred = get_slice_cred(args[0])
    return slicemgr.stop_slice(slice_cred)
 
 # reset named slice
 def reset(opts, args):
    global slicemgr
-   slice_cred = get_slice_cred(args[0]) 
+   slice_cred = get_slice_cred(args[0])
    return slicemgr.reset_slice(slice_cred)
 
 #
@@ -472,5 +512,10 @@ def save_record_to_file(filename, record):
    file(filename, "w").write(str)
    return
 
+def load_record_from_file(filename):
+   str = file(filename, "r").read()
+   record = GeniRecord(string=str)
+   return record
+
 if __name__=="__main__":
    main()
diff --git a/cmdline/testSfi.sh b/cmdline/testSfi.sh
new file mode 100644 (file)
index 0000000..f47c8da
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+source configSfi.sh
+
+rm -f saved_record.*
+
+python ./sfi.py show -o saved_record.$SFI_USER $SFI_USER
+python ./sfi.py list -o saved_record.$SFI_AUTH $SFI_AUTH
+
+#rm -f saved_record.*
diff --git a/cmdline/testSfiSliceRegister.sh b/cmdline/testSfiSliceRegister.sh
new file mode 100644 (file)
index 0000000..2d6fe4b
--- /dev/null
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+source configSfi.sh
+
+CWD=`pwd`
+
+# private key to use when creating GID for new slice
+export TEST_KEY=$CWD/testkey.pkey
+
+export TEST_SLICE_GID=$CWD/testslice.gid
+export TEST_SLICE_RECORD=$CWD/testslice.record
+export TEST_SLICE_HRN=$SFI_AUTH.testslice
+
+echo XXXXX -------------------------------------------------------------------
+echo XXXXX Creating a GID for test slice $TEST_SLICE_HRN
+echo XXXXX -------------------------------------------------------------------
+
+python ./sfi.py creategid -o $TEST_SLICE_GID $TEST_SLICE_HRN $TEST_KEY
+
+echo XXXXX -------------------------------------------------------------------
+echo XXXXX Removing the test slice. this will cause an error if the slice does
+echo XXXXX not exist -- this error can be ignored
+echo XXXXX -------------------------------------------------------------------
+
+python ./sfi.py remove --type slice $TEST_SLICE_HRN
+
+echo XXXXX -------------------------------------------------------------------
+echo XXXXX Creating a record for the test slice
+echo XXXXX -------------------------------------------------------------------
+
+python ./editRecord.py --hrn $TEST_SLICE_HRN --gidfile $TEST_SLICE_GID --type slice --addresearcher $SFI_USER --outfile $TEST_SLICE_RECORD
+
+echo XXXXX -------------------------------------------------------------------
+echo XXXXX Adding the test slice, $TEST_SLICE_HRN
+echo XXXXX -------------------------------------------------------------------
+
+python ./sfi.py add $TEST_SLICE_RECORD
+
+echo XXXXX -------------------------------------------------------------------
+echo XXXXX The slice should have one researcher, $SFI_USER
+echo XXXXX -------------------------------------------------------------------
+
+python ./sfi.py show $TEST_SLICE_HRN
+
+echo XXXXX -------------------------------------------------------------------
+echo XXXXX Adding $TEST_USER_2 to the slice researchers
+echo XXXXX -------------------------------------------------------------------
+
+python ./editRecord.py --infile $TEST_SLICE_RECORD --outfile $TEST_SLICE_RECORD --addresearcher $TEST_USER_2 --outfile $TEST_SLICE_RECORD
+
+echo XXXXX -------------------------------------------------------------------
+echo XXXXX Updating the slice
+echo XXXXX -------------------------------------------------------------------
+
+python ./sfi.py update $TEST_SLICE_RECORD
+
+echo XXXXX -------------------------------------------------------------------
+echo XXXXX The slice record should now have two users: $SFI_USER, $TEST_USER_2
+echo XXXXX -------------------------------------------------------------------
+
+python ./sfi.py show $TEST_SLICE_HRN
+
index f1aa80a..8462446 100755 (executable)
@@ -51,3 +51,6 @@ echo XXXXX -------------------------------------------------------------------
 echo XXXXX Update Self
 python ./genicli.py --server $PLC_URL --username $USERNAME update user $USER_HRN
 
+echo XXXXX -------------------------------------------------------------------
+echo XXXXX List Records in parent authority
+python ./genicli.py --server $PLC_URL --username $USERNAME --short list $PARENT_HRN
\ No newline at end of file