comment
[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.Nodes import Node, Nodes
6 from PLC.Auth import Auth
7
8 related_fields = Node.related_fields.keys()
9 can_update = lambda (field, value): field in \
10              ['hostname', 'boot_state', 'model', 'version',
11               'key', 'session', 'boot_nonce', 'site_id'] + \
12              related_fields
13
14 class UpdateNode(Method):
15     """
16     Updates a node. Only the fields specified in node_fields are
17     updated, all other fields are left untouched.
18     
19     PIs and techs can update only the nodes at their sites. Only
20     admins can update the key, session, and boot_nonce fields.
21
22     Returns 1 if successful, faults otherwise.
23     """
24
25     roles = ['admin', 'pi', 'tech']
26
27     node_fields = dict(filter(can_update, Node.fields.items() + Node.related_fields.items()))
28
29     accepts = [
30         Auth(),
31         Mixed(Node.fields['node_id'],
32               Node.fields['hostname']),
33         node_fields
34         ]
35
36     returns = Parameter(int, '1 if successful')
37
38     def call(self, auth, node_id_or_hostname, node_fields):
39         
40         node_fields = dict(filter(can_update, node_fields.items()))
41
42         # Remove admin only fields
43         if 'admin' not in self.caller['roles']:
44             for key in 'key', 'session', 'boot_nonce', 'site_id':
45                 if node_fields.has_key(key):
46                     del node_fields[key]
47
48         # Get account information
49         nodes = Nodes(self.api, [node_id_or_hostname])
50         if not nodes:
51             raise PLCInvalidArgument, "No such node"
52         node = nodes[0]
53
54         if node['peer_id'] is not None:
55             raise PLCInvalidArgument, "Not a local node"
56
57         # Authenticated function
58         assert self.caller is not None
59
60         # If we are not an admin, make sure that the caller is a
61         # member of the site at which the node is located.
62         if 'admin' not in self.caller['roles']:
63             if node['site_id'] not in self.caller['site_ids']:
64                 raise PLCPermissionDenied, "Not allowed to delete nodes from specified site"
65
66         # Make requested associations
67         for field in related_fields:
68             if field in node_fields:
69                 node.associate(auth, field, node_fields[field])
70                 node_fields.pop(field)
71
72         node.update(node_fields)
73         node.update_last_updated(False)
74         node.sync()
75         
76         # Logging variables
77         self.event_objects = {'Node': [node['node_id']]}
78         self.message = 'Node %d updated: %s.' % \
79                 (node['node_id'], ", ".join(node_fields.keys()))
80         if 'boot_state' in node_fields.keys():
81                 self.message += ' boot_state updated to %s' %  node_fields['boot_state']
82
83         return 1