we were better off creating the record at sfa after it has been created at plc. That...
[sfa.git] / sfa / methods / register.py
1 ### $Id$
2 ### $URL$
3
4 from sfa.trust.certificate import Keypair, convert_public_key
5 from sfa.trust.gid import *
6
7 from sfa.util.faults import *
8 from sfa.util.misc import *
9 from sfa.util.method import Method
10 from sfa.util.parameter import Parameter, Mixed
11 from sfa.util.record import GeniRecord
12 from sfa.util.genitable import GeniTable
13 from sfa.util.debug import log
14 from sfa.trust.auth import Auth
15 from sfa.trust.gid import create_uuid
16 from sfa.trust.credential import Credential
17
18 class register(Method):
19     """
20     Register an object with the registry. In addition to being stored in the
21     Geni database, the appropriate records will also be created in the
22     PLC databases
23     
24     @param cred credential string
25     @param record_dict dictionary containing record fields
26     
27     @return gid string representation
28     """
29
30     interfaces = ['registry']
31     
32     accepts = [
33         Parameter(str, "Credential string"),
34         Parameter(dict, "Record dictionary containing record fields"),
35         Parameter(str, "Request hash")
36         ]
37
38     returns = Parameter(int, "String representation of gid object")
39     
40     def call(self, cred, record_dict, request_hash, caller_cred=None):
41         # This cred will be an authority cred, not a user, so we cant use it to 
42         # authenticate the caller's request_hash. Let just get the caller's gid
43         # from the cred and authenticate using that 
44         client_gid = Credential(string=cred).get_gid_caller()
45         client_gid_str = client_gid.save_to_string(save_parents=True)
46         self.api.auth.authenticateGid(client_gid_str, [cred], request_hash)
47         self.api.auth.check(cred, "register")
48         if caller_cred==None:
49                 caller_cred=cred
50         
51         #log the call
52         self.api.logger.info("interface: %s\tcaller-hrn: %s\ttarget-hrn: %s\tmethod-name: %s"%(self.api.interface, Credential(string=caller_cred).get_gid_caller().get_hrn(), None, self.name))
53         record = GeniRecord(dict = record_dict)
54         record['authority'] = get_authority(record['hrn'])
55         type = record['type']
56         hrn = record['hrn']
57         self.api.auth.verify_object_permission(hrn)
58         auth_info = self.api.auth.get_auth_info(record['authority'])
59         pub_key = None  
60         # make sure record has a gid
61         if 'gid' not in record:
62             uuid = create_uuid()
63             pkey = Keypair(create=True)
64             if 'key' in record and record['key']:
65                 if isinstance(record['key'], list):
66                     pub_key = record['key'][0]
67                 else:
68                     pub_key = record['key']
69                 pkey = convert_public_key(pub_key)
70             
71             gid_object = self.api.auth.hierarchy.create_gid(hrn, uuid, pkey)
72             gid = gid_object.save_to_string(save_parents=True)
73             record['gid'] = gid
74             record.set_gid(gid)
75
76         # check if record already exists
77         table = GeniTable()
78         existing_records = table.find({'type': type, 'hrn': hrn})
79         if existing_records:
80             raise ExistingRecord(hrn)
81  
82         if type in ["authority"]:
83             # update the tree
84             if not self.api.auth.hierarchy.auth_exists(hrn):
85                 self.api.auth.hierarchy.create_auth(hrn)
86
87             # authorities are special since they are managed by the registry
88             # rather than by the caller. We create our own GID for the
89             # authority rather than relying on the caller to supply one.
90
91             # get the GID from the newly created authority
92             gid = auth_info.get_gid_object()
93             record.set_gid(gid.save_to_string(save_parents=True))
94
95             pl_record = self.api.geni_fields_to_pl_fields(type, hrn, record)
96             sites = self.api.plshell.GetSites(self.api.plauth, [pl_record['login_base']])
97             if not sites:    
98                 pointer = self.api.plshell.AddSite(self.api.plauth, pl_record)
99             else:
100                 pointer = sites[0]['site_id']
101
102             record.set_pointer(pointer)
103             record['pointer'] = pointer
104
105         elif (type == "slice"):
106             pl_record = self.api.geni_fields_to_pl_fields(type, hrn, record)
107             slices = self.api.plshell.GetSlices(self.api.plauth, [pl_record['name']])
108             if not slices: 
109                 pointer = self.api.plshell.AddSlice(self.api.plauth, pl_record)
110             else:
111                 pointer = slices[0]['slice_id']
112             record.set_pointer(pointer)
113             record['pointer'] = pointer
114
115         elif  (type == "user"):
116             persons = self.api.plshell.GetPersons(self.api.plauth, [record['email']])
117             if not persons:
118                 pointer = self.api.plshell.AddPerson(self.api.plauth, dict(record))
119             else:
120                 pointer = persons[0]['person_id']
121  
122             if 'enabled' in record and record['enabled']:
123                 self.api.plshell.UpdatePerson(self.api.plauth, pointer, {'enabled': record['enabled']})
124             # add this persons to the site only if he is being added for the first
125             # time by sfa and doesont already exist in plc     
126             if not persons or not persons[0]['site_ids']:
127                 login_base = get_leaf(record['authority'])
128                 self.api.plshell.AddPersonToSite(self.api.plauth, pointer, login_base)
129         
130             # What roles should this user have?
131             self.api.plshell.AddRoleToPerson(self.api.plauth, 'user', pointer) 
132             record.set_pointer(pointer)
133             record['pointer'] = pointer
134             # Add the user's key
135             if pub_key:
136                 self.api.plshell.AddPersonKey(self.api.plauth, pointer, {'key_type' : 'ssh', 'key' : pub_key})
137
138         elif (type == "node"):
139             pl_record = self.api.geni_fields_to_pl_fields(type, hrn, record)
140             login_base = hrn_to_pl_login_base(record['authority'])
141             nodes = self.api.plshell.GetNodes(self.api.plauth, [pl_record['hostname']])
142             if not nodes:
143                 pointer = self.api.plshell.AddNode(self.api.plauth, login_base, pl_record)
144             else:
145                 pointer = nodes[0]['node_id']
146             record['pointer'] = pointer
147             record.set_pointer(pointer)
148
149         else:
150             raise UnknownGeniType(type)
151
152         record_id = table.insert(record)
153         record['record_id'] = record_id
154
155         # update membership for researchers, pis, owners, operators
156         self.api.update_membership(None, record)
157
158         return record.get_gid_object().save_to_string(save_parents=True)