bugfix
[sfa.git] / sfa / methods / update.py
1 ### $Id$
2 ### $URL$
3
4 from sfa.util.faults import *
5 from sfa.util.method import Method
6 from sfa.util.parameter import Parameter, Mixed
7 from sfa.trust.auth import Auth
8 from sfa.util.record import GeniRecord
9 from sfa.util.genitable import GeniTable
10 from sfa.trust.certificate import Keypair, convert_public_key
11 from sfa.trust.gid import *
12 from sfa.util.debug import log
13
14 class update(Method):
15     """
16     Update an object in the registry. Currently, this only updates the
17     PLC information associated with the record. The Geni fields (name, type,
18     GID) are fixed.
19     
20     @param cred credential string specifying rights of the caller
21     @param record a record dictionary to be updated
22
23     @return 1 if successful, faults otherwise 
24     """
25
26     interfaces = ['registry']
27     
28     accepts = [
29         Parameter(str, "Credential string"),
30         Parameter(dict, "Record dictionary to be updated")
31         ]
32
33     returns = Parameter(int, "1 if successful")
34     
35     def call(self, cred, record_dict):
36         self.api.auth.check(cred, "update")
37         new_record = GeniRecord(dict = record_dict)
38         type = new_record['type']
39         hrn = new_record['hrn']
40         self.api.auth.verify_object_permission(hrn)
41         table = GeniTable()
42         # make sure the record exists
43         records = table.findObjects({'type': type, 'hrn': hrn})
44         if not records:
45             raise RecordNotFound(hrn)
46         record = records[0]
47          
48         # Update_membership needs the membership lists in the existing record
49         # filled in, so it can see if members were added or removed
50         self.api.fill_record_info(record)
51
52          # Use the pointer from the existing record, not the one that the user
53         # gave us. This prevents the user from inserting a forged pointer
54         pointer = record['pointer']
55
56         # update the PLC information that was specified with the record
57
58         if (type == "authority"):
59             self.api.plshell.UpdateSite(self.api.plauth, pointer, new_record)
60
61         elif type == "slice":
62             pl_record=self.api.geni_fields_to_pl_fields(type, hrn, new_record)
63             if 'name' in pl_record:
64                 pl_record.pop('name')
65             self.api.plshell.UpdateSlice(self.api.plauth, pointer, pl_record)
66
67         elif type == "user":
68             # SMBAKER: UpdatePerson only allows a limited set of fields to be
69             #    updated. Ideally we should have a more generic way of doing
70             #    this. I copied the field names from UpdatePerson.py...
71             update_fields = {}
72             all_fields = new_record
73             for key in all_fields.keys():
74                 if key in ['first_name', 'last_name', 'title', 'email',
75                            'password', 'phone', 'url', 'bio', 'accepted_aup',
76                            'enabled']:
77                     update_fields[key] = all_fields[key]
78             self.api.plshell.UpdatePerson(self.api.plauth, pointer, update_fields)
79
80             if 'key' in new_record and new_record['key']:
81                 # must check this key against the previous one if it exists
82                 persons = self.api.plshell.GetPersons(self.api.plauth, [pointer], ['key_ids'])
83                 person = persons[0]
84                 keys = person['key_ids']
85                 keys = self.api.plshell.GetKeys(self.api.plauth, person['key_ids'])
86                 key_exists = False
87                 if isinstance(new_record['key'], list):
88                     new_key = new_record['key'][0]
89                 else:
90                     new_key = new_record['key']
91   
92                 # Delete all stale keys
93                 for key in keys:
94                     if new_record['key'] != key['key']:
95                         self.api.plshell.DeleteKey(self.api.plauth, key['key_id'])
96                     else:
97                         key_exists = True
98                 if not key_exists:
99                     self.api.plshell.AddPersonKey(self.api.plauth, pointer, {'key_type': 'ssh', 'key': new_key})
100
101                 # update the openssl key and gid
102                 pkey = convert_public_key(new_key)
103                 uuid = create_uuid()
104                 gid_object = self.api.auth.hierarchy.create_gid(hrn, uuid, pkey)
105                 gid = gid_object.save_to_string(save_parents=True)
106                 record['gid'] = gid
107                 record = GeniRecord(dict=record)
108                 table.update(record)
109                  
110         elif type == "node":
111             self.api.plshell.UpdateNode(self.api.plauth, pointer, new_record)
112
113         else:
114             raise UnknownGeniType(type)
115
116         # update membership for researchers, pis, owners, operators
117         self.api.update_membership(record, record)
118
119         return 1