2 # Sfa Component Wrapper
4 # This wrapper implements the SFA Slice and Mgmt Interfaces on a node.
11 from xmlrpclib import ServerProxy
13 from sfa.trust.certificate import Certificate, Keypair
14 from sfa.trust.gid import *
15 from sfa.trust.trustedroot import *
17 from sfa.util.faults import *
18 from sfa.util.misc import *
19 from sfa.util.record import *
20 from sfa.util.geniticket import *
21 from sfa.util.geniserver import *
24 # ComponentManager is a GeniServer that serves slice and
25 # management operations at a node.
27 class ComponentManager(GeniServer):
30 # Create a new ComponentManager object.
32 # @param ip the ip address to listen on
33 # @param port the port to listen on
34 # @param key_file private key filename of registry
35 # @param cert_file certificate filename containing public key (could be a GID file)
37 def __init__(self, ip, port, key_file, cert_file):
38 GeniServer.__init__(self, ip, port, key_file, cert_file)
39 self.nodemanager = ServerProxy('http://127.0.0.1:812/')
42 # Register the server RPCs for the component
44 def register_functions(self):
45 GeniServer.register_functions(self)
46 self.server.register_function(self.stop_slice)
47 self.server.register_function(self.start_slice)
48 self.server.register_function(self.reset_slice)
49 self.server.register_function(self.delete_slice)
50 self.server.register_function(self.list_slices)
51 self.server.register_function(self.redeem_ticket)
52 self.server.register_function(self.reboot)
54 def sliver_exists(self, slicename):
55 dict = self.nodemanager.GetXIDs()
56 if slicename in dict.keys():
61 # ------------------------------------------------------------------------
67 # @param cred a credential identifying the caller (callerGID) and the slice
70 def stop_slice(self, cred_str):
71 self.decode_authentication(cred_str, "stopslice")
72 slicename = hrn_to_pl_slicename(self.object_gid.get_hrn())
73 print "stopslice:", slicename
74 self.nodemanager.Stop(slicename)
79 # @param cred a credential identifying the caller (callerGID) and the slice
82 def start_slice(self, cred_str):
83 self.decode_authentication(cred_str, "startslice")
84 slicename = hrn_to_pl_slicename(self.object_gid.get_hrn())
85 print "startslice:", slicename
86 self.nodemanager.Start(slicename)
91 # @param cred a credential identifying the caller (callerGID) and the slice
94 def reset_slice(self, cred_str):
95 self.decode_authentication(cred_str, "resetslice")
96 slicename = hrn_to_pl_slicename(self.object_gid.get_hrn())
97 print "resetslice:", slicename
99 # find the existing record for the slice
100 if not self.sliver_exists(slicename):
101 raise SliverDoesNotExist(slicename)
103 self.nodemanager.ReCreate(slicename)
108 # @param cred a credential identifying the caller (callerGID) and the slice
111 def delete_slice(self, cred_str):
112 self.decode_authentication(cred_str, "deleteslice")
113 slicename = hrn_to_pl_slicename(self.object_gid.get_hrn())
114 print "deleteslice:", slicename
115 self.nodemanager.Destroy(slicename)
118 # Examine the ticket that was provided by the caller, check that it is
119 # signed and verified correctly. Throw an exception if something is
120 # wrong with the ticket.
122 # This is similar to geniserver.decode_authentication
124 # @param ticket_string the string representation of the ticket
126 def decode_ticket(self, ticket_string):
127 self.client_ticket = Ticket(string = ticket_string)
128 self.client_gid = self.client_ticket.get_gid_caller()
129 self.object_gid = self.client_ticket.get_gid_object()
131 # make sure the client_gid is not blank
132 if not self.client_gid:
133 raise MissingCallerGID(self.client_ticket.get_subject())
135 # make sure the client_gid matches the certificate that the client is using
136 peer_cert = self.server.peer_cert
137 if not peer_cert.is_pubkey(self.client_gid.get_pubkey()):
138 raise ConnectionKeyGIDMismatch(self.client_gid.get_subject())
140 if self.trusted_cert_list:
141 self.client_ticket.verify_chain(self.trusted_cert_list)
143 self.client_gid.verify_chain(self.trusted_cert_list)
145 self.object_gid.verify_chain(self.trusted_cert_list)
147 def geni_ticket_to_plc_ticket(self, ticket):
148 ticket_attrs = ticket.get_attributes()
149 ticket_rspec = ticket.get_rspec()
155 # sort out the initscript... The NM expects to receive an initscript name
156 # and a dictionary of initscripts. NM ends up discarding the initscript
157 # name and sticking the contents in the slice record. (technically, this
158 # is what we started with, but we have to provide the data in the format
159 # that the NM expects)
160 if ticket_attrs.get("initscript", None):
161 initscript_name = ticket_attrs.get("name") + "_initscript"
162 initscript_body = ticket_attrs.get("initscript")
163 data["initscripts"] = {"name": initscript_name, "script": initscript_body}
164 attr_dict["initscript"] = initscript_name
166 data["initscripts"] = {}
168 # copy the rspec attributes from the geniticket into the plticket
169 # attributes. The NM will later copy them back out and put them into
170 # the rspec field of the slice record
171 for itemname in ticket_rspec.keys():
172 attr = {"name": itemname, "value": ticket_rspec[itemname]}
173 attr_list.append(attr)
175 # NM expects to receive a list of key dictionaries containing the
178 for key in ticket_attrs.get("keys", []):
179 keys.append({"key": key})
182 rec["name"] = ticket_attrs.get("name")
184 rec["attributes"] = attr_list
185 rec["instantiation"] = ticket_attrs["instantiation"]
186 rec["slice_id"] = ticket_attrs["slice_id"]
188 # XXX - this shouldn't be hardcoded; use the actual slice name
189 rec["delegations"] = "pl_genicw"
191 data["timestamp"] = ticket_attrs.get("timestamp")
192 data["slivers"] = [rec]
199 # The ticket is submitted to the node manager, and the slice is instantiated
200 # or updated as appropriate.
202 # TODO: This operation should return a sliver credential and indicate
203 # whether or not the component will accept only sliver credentials, or
204 # will accept both sliver and slice credentials.
206 # @param ticket_str the string representation of a ticket object
208 def redeem_ticket(self, ticket_str):
209 self.decode_ticket(ticket_str)
210 ticket = self.client_ticket
212 print "ticket received for", self.object_gid.get_hrn()
214 pt = self.geni_ticket_to_plc_ticket(ticket)
218 str = xmlrpclib.dumps((pt,), allow_none=True)
219 self.nodemanager.AdminTicket(str)
221 # TODO: should return a sliver credential
223 # ------------------------------------------------------------------------
227 # List the slices on a component.
229 # @param cred_str string representation of a credential object that
230 # authorizes the caller
232 # @return a list of slice names
234 def list_slices(self, cred_str):
235 self.decode_authentication(cred_str, "listslices")
236 slice_names = self.nodemanager.GetXIDs().keys()
239 # ------------------------------------------------------------------------
240 # Management Interface
243 # Reboot the component.
245 # @param cred_str string representation of a credential object that
246 # authorizes the caller
248 def reboot(self, cred_str):
249 self.decode_authentication(cred_str, "reboot")
250 system("/sbin/reboot")
253 if __name__ == "__main__":
256 key_file = "component.key"
257 cert_file = "component.cert"
259 # if no key is specified, then make one up
260 if (not os.path.exists(key_file)) or (not os.path.exists(cert_file)):
261 key = Keypair(create=True)
262 key.save_to_file(key_file)
264 cert = Certificate(subject="component")
265 cert.set_issuer(key=key, subject="component")
268 cert.save_to_file(cert_file)
270 TrustedRoots = TrustedRootList()
272 s = ComponentManager("", 12345, key_file, cert_file)
273 s.trusted_cert_list = TrustedRoots.get_list()