a562ac3cf955bec214669b28477fd040a5e8cf0c
[plcapi.git] / PLC / Methods / UpdateNode.py
1 # $Id$
2 from PLC.Faults import *
3 from PLC.Method import Method
4 from PLC.Parameter import Parameter, Mixed
5 from PLC.Table import Row
6 from PLC.Nodes import Node, Nodes
7 from PLC.Auth import Auth
8
9 can_update = ['hostname', 'boot_state', 'model', 'version','key', 'session', 'boot_nonce', 'site_id'] + \
10               Node.related_fields.keys()
11
12 class UpdateNode(Method):
13     """
14     Updates a node. Only the fields specified in node_fields are
15     updated, all other fields are left untouched.
16     
17     PIs and techs can update only the nodes at their sites. Only
18     admins can update the key, session, and boot_nonce fields.
19
20     Returns 1 if successful, faults otherwise.
21     """
22
23     roles = ['admin', 'pi', 'tech']
24
25     node_fields = Row.accepted_fields(can_update,[Node.fields,Node.related_fields,Node.tags])
26
27     accepts = [
28         Auth(),
29         Mixed(Node.fields['node_id'],
30               Node.fields['hostname']),
31         node_fields
32         ]
33
34     returns = Parameter(int, '1 if successful')
35
36     def call(self, auth, node_id_or_hostname, node_fields):
37         
38         # split provided fields 
39         [native,related,tags,rejected] = Row.split_fields(node_fields,[Node.fields,Node.related_fields,Node.tags])
40
41         if rejected:
42             raise PLCInvalidArgument, "Cannot update column(s) %r"%rejected
43
44         # Remove admin only fields
45         if 'admin' not in self.caller['roles']:
46             for key in 'key', 'session', 'boot_nonce', 'site_id':
47                 if native.has_key(key):
48                     del native[key]
49
50         # Get account information
51         nodes = Nodes(self.api, [node_id_or_hostname])
52         if not nodes:
53             raise PLCInvalidArgument, "No such node %r"%node_id_or_hostname
54         node = nodes[0]
55
56         if node['peer_id'] is not None:
57             raise PLCInvalidArgument, "Not a local node %r"%node_id_or_hostname
58
59         # Authenticated function
60         assert self.caller is not None
61
62         # If we are not an admin, make sure that the caller is a
63         # member of the site at which the node is located.
64         if 'admin' not in self.caller['roles']:
65             if node['site_id'] not in self.caller['site_ids']:
66                 raise PLCPermissionDenied, "Not allowed to delete nodes from specified site"
67
68         # Make requested associations
69         for (k,v) in related.iteritems():
70             node.associate(auth, k,v)
71
72         if tags:
73             print 'UpdateNode: warning, tags not handled yet',
74             for (k,v) in tags.iteritems(): print k
75
76         node.update(native)
77         node.update_last_updated(commit=False)
78         node.sync(commit=True)
79         
80         # Logging variables
81         self.event_objects = {'Node': [node['node_id']]}
82         self.message = 'Node %d updated: %s.' % \
83                 (node['node_id'], ", ".join(node_fields.keys()))
84         if 'boot_state' in node_fields.keys():
85                 self.message += ' boot_state updated to %s' %  node_fields['boot_state']
86
87         return 1