379c4151a8b26f852fca9e9f717da38c14b370b4
[sfa.git] / component / component.py
1 ##
2 # Geni Component Wrapper
3 #
4 # This wrapper implements the Geni Slice and Mgmt Interfaces on a node.
5 #
6 ##
7
8 import tempfile
9 import os
10
11 import sys
12
13 from cert import *
14 from gid import *
15 from geniserver import *
16 from excep import *
17 from trustedroot import *
18 from misc import *
19 from record import *
20 from geniticket import *
21
22 import accounts
23 import database
24 import sm
25 import database
26
27 ##
28 # ComponentManager is a GeniServer that serves slice and
29 # management operations at a node.
30
31 class ComponentManager(GeniServer):
32     def __init__(self, ip, port, key_file, cert_file):
33         GeniServer.__init__(self, ip, port, key_file, cert_file)
34
35     def register_functions(self):
36         GeniServer.register_functions(self)
37         self.server.register_function(self.stop_slice)
38         self.server.register_function(self.start_slice)
39         self.server.register_function(self.reset_slice)
40         self.server.register_function(self.delete_slice)
41         self.server.register_function(self.list_slices)
42         self.server.register_function(self.redeem_ticket)
43         self.server.register_function(self.reboot)
44
45     # Slice Interface
46
47     def stop_slice(self, cred_str):
48         self.decode_authentication(cred_str, "stopslice")
49         slicename = hrn_to_pl_slicename(self.object_gid.get_hrn())
50         print "stopslice:", slicename
51         accounts.get(slicename).start()
52
53     def start_slice(self, cred_str):
54         self.decode_authentication(cred_str, "startslice")
55         slicename = hrn_to_pl_slicename(self.object_gid.get_hrn())
56         print "startslice:", slicename
57         accounts.get(slicename).start()
58
59     def reset_slice(self, cred_str):
60         self.decode_authentication(cred_str, "resetslice")
61         slicename = hrn_to_pl_slicename(self.object_gid.get_hrn())
62         print "resetslice:", slicename
63
64         # find the existing record for the slice
65         try:
66             rec = database.db[slicename]
67         except KeyError:
68             raise SliverDoesNotExist(slicename)
69
70         accounts.get(slicename).stop()
71         accounts.get(slicename).ensure_destroyed()
72         accounts.get(slicename).ensure_created(rec)
73
74     def delete_slice(self, cred_str):
75         self.decode_authentication(cred_str, "deleteslice")
76         slicename = hrn_to_pl_slicename(self.object_gid.get_hrn())
77         print "deleteslice:", slicename
78         accounts.get(slicename).ensure_destroyed()
79
80     # this is similar to geniserver.decode_authentication
81     def decode_ticket(self, ticket_string):
82         self.client_ticket = Ticket(string = ticket_string)
83         self.client_gid = self.client_ticket.get_gid_caller()
84         self.object_gid = self.client_ticket.get_gid_object()
85
86         # make sure the client_gid is not blank
87         if not self.client_gid:
88             raise MissingCallerGID(self.client_ticket.get_subject())
89
90         # make sure the client_gid matches the certificate that the client is using
91         peer_cert = self.server.peer_cert
92         if not peer_cert.is_pubkey(self.client_gid.get_pubkey()):
93             raise ConnectionKeyGIDMismatch(self.client_gid.get_subject())
94
95         if self.trusted_cert_list:
96             self.client_ticket.verify_chain(self.trusted_cert_list)
97             if self.client_gid:
98                 self.client_gid.verify_chain(self.trusted_cert_list)
99             if self.object_gid:
100                 self.object_gid.verify_chain(self.trusted_cert_list)
101
102     def geni_ticket_to_plc_rec(self, ticket):
103         ticket_attrs = ticket.get_attributes()
104         ticket_rspec = ticket.get_rspec()
105         rec = {}
106
107         rec["name"] = ticket_attrs.get("name")
108         rec["keys"] = '\n'.join(ticket_attrs.get("keys",[]))
109         rec["initscript"] = ticket_attrs.get("initscript", "")
110         rec["vref"] = ticket_attrs.get("vref", "default")
111         rec["timestamp"] = ticket_attrs.get("timestamp")    # should there be a default timestamp?
112
113         rspec = {}
114         rec['rspec'] = rspec
115         for resname, default_amt in sm.DEFAULT_ALLOCATION.iteritems():
116             try:
117                 t = type(default_amt)
118                 amt = t.__new__(t, ticket_attrs[resname])
119             except (KeyError, ValueError):
120                 amt = default_amt
121             rspec[resname] = amt
122
123         return rec
124
125     def redeem_ticket(self, ticket_str):
126         self.decode_ticket(ticket_str)
127         ticket = self.client_ticket
128
129         print "ticket received for", self.object_gid.get_hrn()
130
131         rec = self.geni_ticket_to_plc_rec(ticket)
132
133         print "record", rec
134
135         database.db.deliver_record(rec)
136
137     # Slice Information
138
139     def list_slices(self, cred_str):
140         self.decode_authentication(cred_str, "listslices")
141         slice_names = database.db.keys()
142         return slice_names
143
144     # Management Interface
145
146     def reboot(self, cred_str):
147         self.decode_authentication(cred_str, "reboot")
148         system("/sbin/reboot")
149
150
151 if __name__ == "__main__":
152     global TrustedRoots
153
154     key_file = "component.key"
155     cert_file = "component.cert"
156
157     # if no key is specified, then make one up
158     if (not os.path.exists(key_file)) or (not os.path.exists(cert_file)):
159         key = Keypair(create=True)
160         key.save_to_file(key_file)
161
162         cert = Certificate(subject="component")
163         cert.set_issuer(key=key, subject="component")
164         cert.set_pubkey(key)
165         cert.sign()
166         cert.save_to_file(cert_file)
167
168     TrustedRoots = TrustedRootList()
169
170     # XXX: does this conflict with the nodemanager's database? I don't think
171     # so because there are locks, but double check...
172     database.start()
173
174     s = ComponentManager("", 12345, key_file, cert_file)
175     s.trusted_cert_list = TrustedRoots.get_list()
176     s.run()
177