1 from PLC.Faults import *
2 from PLC.Method import Method
3 from PLC.Parameter import Parameter, Mixed
4 from PLC.Table import Row
5 from PLC.Auth import Auth
6 from PLC.Namespace import hostname_to_hrn
7 from PLC.Peers import Peers
8 from PLC.Sites import Sites
9 from PLC.Nodes import Node, Nodes
10 from PLC.TagTypes import TagTypes
11 from PLC.NodeTags import NodeTags, NodeTag
13 admin_only = [ 'key', 'session', 'boot_nonce', 'site_id']
14 can_update = ['hostname', 'node_type', 'boot_state', 'model', 'version'] + admin_only
16 class UpdateNode(Method):
18 Updates a node. Only the fields specified in node_fields are
19 updated, all other fields are left untouched.
21 PIs and techs can update only the nodes at their sites. Only
22 admins can update the key, session, and boot_nonce fields.
24 Returns 1 if successful, faults otherwise.
27 roles = ['admin', 'pi', 'tech']
29 accepted_fields = Row.accepted_fields(can_update,Node.fields)
30 # xxx check the related_fields feature
31 accepted_fields.update(Node.related_fields)
32 accepted_fields.update(Node.tags)
36 Mixed(Node.fields['node_id'],
37 Node.fields['hostname']),
41 returns = Parameter(int, '1 if successful')
43 def call(self, auth, node_id_or_hostname, node_fields):
45 # split provided fields
46 [native,related,tags,rejected] = Row.split_fields(node_fields,[Node.fields,Node.related_fields,Node.tags])
49 native = Row.check_fields (native, self.accepted_fields)
51 raise PLCInvalidArgument("Cannot update Node column(s) %r"%rejected)
53 # Authenticated function
54 assert self.caller is not None
56 # Remove admin only fields
57 if 'admin' not in self.caller['roles']:
58 for key in admin_only:
62 # Get account information
63 nodes = Nodes(self.api, [node_id_or_hostname])
65 raise PLCInvalidArgument("No such node %r"%node_id_or_hostname)
68 if node['peer_id'] is not None:
69 raise PLCInvalidArgument("Not a local node %r"%node_id_or_hostname)
71 # If we are not an admin, make sure that the caller is a
72 # member of the site at which the node is located.
73 if 'admin' not in self.caller['roles']:
74 if node['site_id'] not in self.caller['site_ids']:
75 raise PLCPermissionDenied("Not allowed to delete nodes from specified site")
77 # Make requested associations
78 for (k,v) in related.items():
79 node.associate(auth, k,v)
82 node.update_last_updated(commit=False)
83 node.sync(commit=True)
85 # if hostname was modifed make sure to update the hrn
87 if 'hostname' in native:
88 root_auth = self.api.config.PLC_HRN_ROOT
89 # sub auth is the login base of this node's site
90 sites = Sites(self.api, node['site_id'], ['login_base'])
92 login_base = site['login_base']
93 tags['hrn'] = hostname_to_hrn(root_auth, login_base, node['hostname'])
95 for (tagname,value) in tags.items():
96 # the tagtype instance is assumed to exist, just check that
97 tag_types = TagTypes(self.api,{'tagname':tagname})
99 raise PLCInvalidArgument("No such TagType %s"%tagname)
100 tag_type = tag_types[0]
101 node_tags=NodeTags(self.api,{'tagname':tagname,'node_id':node['node_id']})
103 node_tag = NodeTag(self.api)
104 node_tag['node_id'] = node['node_id']
105 node_tag['tag_type_id'] = tag_type['tag_type_id']
106 node_tag['tagname'] = tagname
107 node_tag['value'] = value
110 node_tag = node_tags[0]
111 node_tag['value'] = value
115 self.event_objects = {'Node': [node['node_id']]}
116 if 'hostname' in node:
117 self.message = 'Node %s updated'%node['hostname']
119 self.message = 'Node %d updated'%node['node_id']
120 self.message += " [%s]." % (", ".join(list(node_fields.keys())),)
121 if 'boot_state' in list(node_fields.keys()):
122 self.message += ' boot_state updated to %s' % node_fields['boot_state']