-
-# xxx NOTE this will soon be reviewed to take advantage of sfaclientlib
+#
+# sfi.py - basic SFA command-line client
+# the actual binary in sfa/clientbin essentially runs main()
+# this module is used in sfascan
+#
import sys
sys.path.append('.')
from lxml import etree
from StringIO import StringIO
from optparse import OptionParser
+from pprint import PrettyPrinter
from sfa.trust.certificate import Keypair, Certificate
from sfa.trust.gid import GID
from sfa.util.version import version_core
from sfa.util.cache import Cache
-from sfa.storage.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
+from sfa.storage.persistentobjs import RegRecord, RegAuthority, RegUser, RegSlice, RegNode
+from sfa.storage.persistentobjs import make_record
from sfa.rspecs.rspec import RSpec
from sfa.rspecs.rspec_converter import RSpecConverter
f.close()
return
-def save_records_to_file(filename, recordList, format="xml"):
+def save_records_to_file(filename, record_dicts, format="xml"):
if format == "xml":
index = 0
- for record in recordList:
+ for record_dict in record_dicts:
if index > 0:
- save_record_to_file(filename + "." + str(index), record)
+ save_record_to_file(filename + "." + str(index), record_dict)
else:
- save_record_to_file(filename, record)
+ save_record_to_file(filename, record_dict)
index = index + 1
elif format == "xmllist":
f = open(filename, "w")
f.write("<recordlist>\n")
- for record in recordList:
- record = SfaRecord(dict=record)
- f.write('<record hrn="' + record.get_name() + '" type="' + record.get_type() + '" />\n')
+ for record_dict in record_dicts:
+ record_obj=make_record (dict=record_dict)
+ f.write('<record hrn="' + record_obj.hrn + '" type="' + record_obj.type + '" />\n')
f.write("</recordlist>\n")
f.close()
elif format == "hrnlist":
f = open(filename, "w")
- for record in recordList:
- record = SfaRecord(dict=record)
- f.write(record.get_name() + "\n")
+ for record_dict in record_dicts:
+ record_obj=make_record (dict=record_dict)
+ f.write(record_obj.hrn + "\n")
f.close()
else:
# this should never happen
print "unknown output format", format
-def save_record_to_file(filename, record):
- if record['type'] in ['user']:
- record = UserRecord(dict=record)
- elif record['type'] in ['slice']:
- record = SliceRecord(dict=record)
- elif record['type'] in ['node']:
- record = NodeRecord(dict=record)
- elif record['type'] in ['authority', 'ma', 'sa']:
- record = AuthorityRecord(dict=record)
- else:
- record = SfaRecord(dict=record)
+def save_record_to_file(filename, record_dict):
+ rec_record = make_record (dict=record_dict)
str = record.save_to_string()
f=codecs.open(filename, encoding='utf-8',mode="w")
f.write(str)
# load methods
def load_record_from_file(filename):
f=codecs.open(filename, encoding="utf-8", mode="r")
- str = f.read()
+ xml_string = f.read()
f.close()
- record = SfaRecord(string=str)
- return record
+ return make_record (xml=xml_string)
import uuid
class Sfi:
- required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
+ # dirty hack to make this class usable from the outside
+ required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user', 'user_private_key']
@staticmethod
def default_sfi_dir ():
# user specifies remote aggregate/sm/component
if command in ("resources", "slices", "create", "delete", "start", "stop",
"restart", "shutdown", "get_ticket", "renew", "status"):
- parser.add_option("-c", "--component", dest="component", default=None,
- help="component hrn")
parser.add_option("-d", "--delegate", dest="delegate", default=None,
action="store_true",
help="Include a credential delegated to the user's root"+\
help="type filter ([all]|user|slice|authority|node|aggregate)",
choices=("all", "user", "slice", "authority", "node", "aggregate"),
default="all")
- # display formats
if command in ("resources"):
+ # rspec version
parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
help="schema type and version of resulting RSpec")
+ # disable/enable cached rspecs
+ parser.add_option("-c", "--current", dest="current", default=False,
+ action="store_true",
+ help="Request the current rspec bypassing the cache. Cached rspecs are returned by default")
+ # display formats
parser.add_option("-f", "--format", dest="format", type="choice",
help="display format ([xml]|dns|ip)", default="xml",
choices=("xml", "dns", "ip"))
parser.add_option("-D", "--debug",
action="store_true", dest="debug", default=False,
help="Debug (xml-rpc) protocol messages")
- parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
- help="RPC protocol (xmlrpc or soap)")
# would it make sense to use ~/.ssh/id_rsa as a default here ?
parser.add_option("-k", "--private-key",
action="store", dest="user_private_key", default=None,
self.sliceapi_proxy=SfaServerProxy(cm_url, self.private_key, self.my_gid)
else:
# otherwise use what was provided as --sliceapi, or SFI_SM in the config
+ if not self.sm_url.startswith('http://') or self.sm_url.startswith('https://'):
+ self.sm_url = 'http://' + self.sm_url
self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
self.sliceapi_proxy = SfaServerProxy(self.sm_url, self.private_key, self.my_gid,
timeout=self.options.timeout, verbose=self.options.debug)
return result
### ois = options if supported
+ # to be used in something like serverproxy.Method (arg1, arg2, *self.ois(api_options))
def ois (self, server, option_dict):
- if self.server_supports_options_arg (server) : return [option_dict]
- else: return []
+ if self.server_supports_options_arg (server):
+ return [option_dict]
+ elif self.server_supports_call_id_arg (server):
+ return [ unique_call_id () ]
+ else:
+ return []
+
+ ### cis = call_id if supported - like ois
+ def cis (self, server):
+ if self.server_supports_call_id_arg (server):
+ return [ unique_call_id ]
+ else:
+ return []
######################################## miscell utilities
def get_rspec_file(self, rspec):
server = self.sliceapi()
result = server.GetVersion()
version = ReturnValue.get_value(result)
- for (k,v) in version.iteritems():
- print "%-20s: %s"%(k,v)
+ pprinter = PrettyPrinter(indent=4)
+ pprinter.pprint(version)
if options.file:
save_variable_to_file(version, options.file, options.fileformat)
self.print_help()
sys.exit(1)
hrn = args[0]
- records = self.registry().Resolve(hrn, self.my_credential_string)
- records = filter_records(options.type, records)
- if not records:
+ record_dicts = self.registry().Resolve(hrn, self.my_credential_string)
+ record_dicts = filter_records(options.type, record_dicts)
+ if not record_dicts:
self.logger.error("No record of type %s"% options.type)
+ records = [ make_record (dict=record_dict) for record_dict in record_dicts ]
for record in records:
- if record['type'] in ['user']:
- record = UserRecord(dict=record)
- elif record['type'] in ['slice']:
- record = SliceRecord(dict=record)
- elif record['type'] in ['node']:
- record = NodeRecord(dict=record)
- elif record['type'].startswith('authority'):
- record = AuthorityRecord(dict=record)
- else:
- record = SfaRecord(dict=record)
- if (options.format == "text"):
- record.dump()
- else:
- print record.save_to_string()
+ if (options.format == "text"): record.dump()
+ else: print record.save_as_xml()
if options.file:
- save_records_to_file(options.file, records, options.fileformat)
+ save_records_to_file(options.file, record_dicts, options.fileformat)
return
def add(self, options, args):
sys.exit(1)
record_filepath = args[0]
rec_file = self.get_record_file(record_filepath)
- record = load_record_from_file(rec_file).as_dict()
+ record = load_record_from_file(rec_file).todict()
return self.registry().Register(record, auth_cred)
def update(self, options, args):
sys.exit(1)
rec_file = self.get_record_file(args[0])
record = load_record_from_file(rec_file)
- if record['type'] == "user":
- if record.get_name() == self.user:
+ if record.type == "user":
+ if record.hrn == self.user:
cred = self.my_credential_string
else:
cred = self.my_authority_credential_string()
- elif record['type'] in ["slice"]:
+ elif record.type in ["slice"]:
try:
- cred = self.slice_credential_string(record.get_name())
+ cred = self.slice_credential_string(record.hrn)
except ServerException, e:
# XXX smbaker -- once we have better error return codes, update this
# to do something better than a string compare
cred = self.my_authority_credential_string()
else:
raise
- elif record.get_type() in ["authority"]:
+ elif record.type in ["authority"]:
cred = self.my_authority_credential_string()
- elif record.get_type() == 'node':
+ elif record.type == 'node':
cred = self.my_authority_credential_string()
else:
- raise "unknown record type" + record.get_type()
- record = record.as_dict()
- return self.registry().Update(record, cred)
+ raise "unknown record type" + record.type
+ record_dict = record.todict()
+ return self.registry().Update(record_dict, cred)
def remove(self, options, args):
"remove registry record by name (Remove)"
def slices(self, options, args):
"list instantiated slices (ListSlices) - returns urn's"
server = self.sliceapi()
- call_args = []
+ # creds
creds = [self.my_credential_string]
if options.delegate:
delegated_cred = self.delegate_cred(self.my_credential_string, get_authority(self.authority))
creds.append(delegated_cred)
- call_args.append(creds)
- if self.server_supports_options_arg(server):
- api_options = {}
- api_options ['call_id'] = unique_call_id()
- args.append(api_options)
- elif self.server_supports_call_id_arg(server):
- args.append(unique_call_id())
- result = server.ListSlices(*call_args)
+ # options and call_id when supported
+ api_options = {}
+ api_options['call_id']=unique_call_id()
+ result = server.ListSlices(creds, *self.ois(server,api_options))
value = ReturnValue.get_value(result)
display_list(value)
return
# show rspec for named slice
def resources(self, options, args):
"""
- with no arg, discover available resources,
-or currently provisioned resources (ListResources)
+ with no arg, discover available resources, (ListResources)
+or with an slice hrn, shows currently provisioned resources
"""
server = self.sliceapi()
- call_args = []
- creds = []
# set creds
+ creds = []
if args:
creds.append(self.slice_credential_string(args[0]))
else:
creds.append(self.my_credential_string)
if options.delegate:
creds.append(self.delegate_cred(cred, get_authority(self.authority)))
- call_args.append(creds)
-
- # set options and callid
- print self.server_supports_options_arg(server)
- if self.server_supports_options_arg(server):
- api_options = {}
- if args:
- hrn = args[0]
- api_options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
- if options.info:
- api_options['info'] = options.info
- if options.rspec_version:
- version_manager = VersionManager()
- server_version = self.get_cached_server_version(server)
- if 'sfa' in server_version:
- # just request the version the client wants
- api_options['geni_rspec_version'] = version_manager.get_version(options.rspec_version).to_dict()
- else:
- # this must be a protogeni aggregate. We should request a v2 ad rspec
- # regardless of what the client user requested
- api_options['geni_rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()
+
+ # no need to check if server accepts the options argument since the options has
+ # been a required argument since v1 API
+ api_options = {}
+ # always send call_id to v2 servers
+ api_options ['call_id'] = unique_call_id()
+ # ask for cached value if available
+ api_options ['cached'] = True
+ if args:
+ hrn = args[0]
+ api_options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
+ if options.info:
+ api_options['info'] = options.info
+ if options.current:
+ if options.current == True:
+ api_options['cached'] = False
+ else:
+ api_options['cached'] = True
+ if options.rspec_version:
+ version_manager = VersionManager()
+ server_version = self.get_cached_server_version(server)
+ if 'sfa' in server_version:
+ # just request the version the client wants
+ api_options['geni_rspec_version'] = version_manager.get_version(options.rspec_version).to_dict()
else:
api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}
- api_options ['call_id'] = unique_call_id()
- call_args.append(api_options)
else:
- if args:
- hrn = args[0]
- call_args.append(hrn)
- if self.server_supports_call_id_arg(server):
- call_args.append(unique_call_id)
- result = server.ListResources(*call_args)
+ api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}
+ result = server.ListResources (creds, api_options)
value = ReturnValue.get_value(result)
if options.file is None:
display_rspec(value, options.format)
create or update named slice with given rspec
"""
server = self.sliceapi()
- call_args = []
- # set slice urn
+
+ # xxx do we need to check usage (len(args)) ?
+ # slice urn
slice_hrn = args[0]
slice_urn = hrn_to_urn(slice_hrn, 'slice')
- call_args.append(slice_urn)
- # set credentials
+
+ # credentials
creds = [self.slice_credential_string(slice_hrn)]
- call_args.append(creds)
delegated_cred = None
server_version = self.get_cached_server_version(server)
if server_version.get('interface') == 'slicemgr':
#elif server_version.get('urn'):
# delegated_cred = self.delegate_cred(slice_cred, urn_to_hrn(server_version['urn']))
- # set rspec
+ # rspec
rspec_file = self.get_rspec_file(args[1])
rspec = open(rspec_file).read()
- # set users
+
+ # users
# need to pass along user keys to the aggregate.
# users = [
# { urn: urn:publicid:IDN+emulab.net+user+alice
else:
users = sfa_users_arg(user_records, slice_record)
- call_args.append(rspec)
- call_args.append(users)
# do not append users, keys, or slice tags. Anything
# not contained in this request will be removed from the slice
# CreateSliver has supported the options argument for a while now so it should
- # be safe to assume this server support it
+ # be safe to assume this server support it
api_options = {}
api_options ['append'] = False
api_options ['call_id'] = unique_call_id()
- call_args.append(api_options)
- result = server.CreateSliver(*call_args)
+
+ result = server.CreateSliver(slice_urn, creds, rspec, users, *self.ois(server, api_options))
value = ReturnValue.get_value(result)
if options.file is None:
print value
delete named slice (DeleteSliver)
"""
server = self.sliceapi()
- call_args = []
- # set slice urn
+
+ # slice urn
slice_hrn = args[0]
slice_urn = hrn_to_urn(slice_hrn, 'slice')
- call_args.append(slice_urn)
- # set creds
+
+ # creds
slice_cred = self.slice_credential_string(slice_hrn)
creds = [slice_cred]
if options.delegate:
delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
creds.append(delegated_cred)
- call_args.append(creds)
- if self.server_supports_options_arg(server):
- api_options = {}
- api_options ['call_id'] = unique_call_id()
- call_args.append(api_options)
- elif self.server_supports_call_id_arg(server):
- call_args.append(unique_call_id())
- return server.DeleteSliver(*call_args)
+
+ # options and call_id when supported
+ api_options = {}
+ api_options ['call_id'] = unique_call_id()
+ result = server.DeleteSliver(slice_urn, creds, *self.ois(server, api_options ) )
+ # xxx no ReturnValue ??
+ return result
def status(self, options, args):
"""
retrieve slice status (SliverStatus)
"""
server = self.sliceapi()
- call_args = []
- # set slice urn
+
+ # slice urn
slice_hrn = args[0]
slice_urn = hrn_to_urn(slice_hrn, 'slice')
- call_args.append(slice_urn)
- # set creds
+
+ # creds
slice_cred = self.slice_credential_string(slice_hrn)
creds = [slice_cred]
if options.delegate:
delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
creds.append(delegated_cred)
- call_args.append(creds)
- # set options and call id
- if self.server_supports_options_arg(server):
- api_options = {}
- api_options ['call_id'] = unique_call_id()
- call_args.append(api_options)
- elif self.server_supports_call_id_arg(server):
- call_args.append(unique_call_id())
- result = server.SliverStatus(*call_args)
+
+ # options and call_id when supported
+ api_options = {}
+ api_options['call_id']=unique_call_id()
+ result = server.SliverStatus(slice_urn, creds, *self.ois(server,api_options))
value = ReturnValue.get_value(result)
print value
if options.file:
start named slice (Start)
"""
server = self.sliceapi()
- call_args = []
- # set the slice urn
+
+ # the slice urn
slice_hrn = args[0]
slice_urn = hrn_to_urn(slice_hrn, 'slice')
- call_args.append(slice_urn)
+
+ # cred
slice_cred = self.slice_credential_string(args[0])
creds = [slice_cred]
if options.delegate:
"""
stop named slice (Stop)
"""
+ server = self.sliceapi()
+ # slice urn
slice_hrn = args[0]
slice_urn = hrn_to_urn(slice_hrn, 'slice')
+ # cred
slice_cred = self.slice_credential_string(args[0])
creds = [slice_cred]
if options.delegate:
delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
creds.append(delegated_cred)
- server = self.sliceapi()
return server.Stop(slice_urn, creds)
# reset named slice
"""
reset named slice (reset_slice)
"""
+ server = self.sliceapi()
+ # slice urn
slice_hrn = args[0]
slice_urn = hrn_to_urn(slice_hrn, 'slice')
- server = self.sliceapi()
+ # cred
slice_cred = self.slice_credential_string(args[0])
creds = [slice_cred]
if options.delegate:
renew slice (RenewSliver)
"""
server = self.sliceapi()
- call_args = []
- # set the slice urn
+ # slice urn
slice_hrn = args[0]
slice_urn = hrn_to_urn(slice_hrn, 'slice')
- call_args.append(slice_urn)
- # set the creds
+ # creds
slice_cred = self.slice_credential_string(args[0])
creds = [slice_cred]
if options.delegate:
delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
creds.append(delegated_cred)
- call_args.append(creds)
+ # time
time = args[1]
- call_args.append(time)
- if self.server_supports_options_arg(server):
- api_options = {}
- api_options ['call_id'] = unique_call_id()
- call_args.append(api_options)
- elif self.server_supports_call_id_arg(server):
- call_args.append(unique_call_id())
- result = server.RenewSliver(*call_args)
+ # options and call_id when supported
+ api_options = {}
+ api_options['call_id']=unique_call_id()
+ result = server.RenewSliver(slice_urn, creds, time, *self.ois(server,api_options))
value = ReturnValue.get_value(result)
return value
"""
shutdown named slice (Shutdown)
"""
+ server = self.sliceapi()
+ # slice urn
slice_hrn = args[0]
slice_urn = hrn_to_urn(slice_hrn, 'slice')
+ # creds
slice_cred = self.slice_credential_string(slice_hrn)
creds = [slice_cred]
if options.delegate:
delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
creds.append(delegated_cred)
- server = self.sliceapi()
return server.Shutdown(slice_urn, creds)
"""
get a ticket for the specified slice
"""
+ server = self.sliceapi()
+ # slice urn
slice_hrn, rspec_path = args[0], args[1]
slice_urn = hrn_to_urn(slice_hrn, 'slice')
+ # creds
slice_cred = self.slice_credential_string(slice_hrn)
creds = [slice_cred]
if options.delegate:
delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
creds.append(delegated_cred)
+ # rspec
rspec_file = self.get_rspec_file(rspec_path)
rspec = open(rspec_file).read()
- server = self.sliceapi()
- ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
+ # options and call_id when supported
+ api_options = {}
+ api_options['call_id']=unique_call_id()
+ # get ticket at the server
+ ticket_string = server.GetTicket(slice_urn, creds, rspec, *self.ois(server,api_options))
+ # save
file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
self.logger.info("writing ticket to %s"%file)
ticket = SfaTicket(string=ticket_string)
# use this to get the right slice credential
ticket = SfaTicket(filename=ticket_file)
ticket.decode()
+ ticket_string = ticket.save_to_string(save_parents=True)
+
slice_hrn = ticket.gidObject.get_hrn()
slice_urn = hrn_to_urn(slice_hrn, 'slice')
#slice_hrn = ticket.attributes['slivers'][0]['hrn']
for hostname in hostnames:
try:
self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
- server = self.server_proxy(hostname, CM_PORT, self.private_key, \
- self.my_gid, verbose=self.options.debug)
- server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
+ cm_url="http://%s:%s/"%(hostname,CM_PORT)
+ server = SfaServerProxy(cm_url, self.private_key, self.my_gid)
+ server = self.server_proxy(hostname, CM_PORT, self.private_key,
+ timeout=self.options.timeout, verbose=self.options.debug)
+ server.RedeemTicket(ticket_string, slice_cred)
self.logger.info("Success")
except socket.gaierror:
- self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
+ self.logger.error("redeem_ticket failed on %s: Component Manager not accepting requests"%hostname)
except Exception, e:
self.logger.log_exc(e.message)
return