3 from PLC.Faults import *
4 from PLC.Method import Method
5 from PLC.Parameter import Parameter, Mixed
6 from PLC.Table import Row
7 from PLC.Auth import Auth
8 from PLC.Namespace import hostname_to_hrn
9 from PLC.Peers import Peers
10 from PLC.Sites import Sites
11 from PLC.Nodes import Node, Nodes
12 from PLC.TagTypes import TagTypes
13 from PLC.NodeTags import NodeTags, NodeTag
14 from PLC.Methods.AddNodeTag import AddNodeTag
15 from PLC.Methods.UpdateNodeTag import UpdateNodeTag
17 admin_only = [ 'key', 'session', 'boot_nonce', 'site_id']
18 can_update = ['hostname', 'node_type', 'boot_state', 'model', 'version'] + admin_only
20 legacy_node_fields = {
21 'node_id': Parameter(int, "Node identifier"),
22 'node_type': Parameter(str,"Node type",max=20),
23 'hostname': Parameter(str, "Fully qualified hostname", max = 255),
24 'site_id': Parameter(int, "Site at which this node is located"),
25 'boot_state': Parameter(str, "Boot state", max = 20),
26 'run_level': Parameter(str, "Run level", max = 20),
27 'model': Parameter(str, "Make and model of the actual machine", max = 255, nullok = True),
28 'boot_nonce': Parameter(str, "(Admin only) Random value generated by the node at last boot", max = 128),
29 'version': Parameter(str, "Apparent Boot CD version", max = 64),
30 'ssh_rsa_key': Parameter(str, "Last known SSH host key", max = 1024),
31 'date_created': Parameter(int, "Date and time when node entry was created", ro = True),
32 'last_updated': Parameter(int, "Date and time when node entry was created", ro = True),
33 'last_contact': Parameter(int, "Date and time when node last contacted plc", ro = True),
34 'last_boot': Parameter(int, "Date and time when node last booted", ro = True),
35 'last_download': Parameter(int, "Date and time when node boot image was created", ro = True),
36 'last_pcu_reboot': Parameter(int, "Date and time when PCU reboot was attempted", ro = True),
37 'last_pcu_confirmation': Parameter(int, "Date and time when PCU reboot was confirmed", ro = True),
38 'last_time_spent_online': Parameter(int, "Length of time the node was last online before shutdown/failure", ro = True),
39 'last_time_spent_offline': Parameter(int, "Length of time the node was last offline after failure and before reboot", ro = True),
40 'verified': Parameter(bool, "Whether the node configuration is verified correct", ro=False),
41 'key': Parameter(str, "(Admin only) Node key", max = 256),
42 'session': Parameter(str, "(Admin only) Node session value", max = 256, ro = True),
43 'interface_ids': Parameter([int], "List of network interfaces that this node has"),
44 'conf_file_ids': Parameter([int], "List of configuration files specific to this node"),
45 # 'root_person_ids': Parameter([int], "(Admin only) List of people who have root access to this node"),
46 'slice_ids': Parameter([int], "List of slices on this node"),
47 'slice_ids_whitelist': Parameter([int], "List of slices allowed on this node"),
48 'pcu_ids': Parameter([int], "List of PCUs that control this node"),
49 'ports': Parameter([int], "List of PCU ports that this node is connected to"),
50 'peer_id': Parameter(int, "Peer to which this node belongs", nullok = True),
51 'peer_node_id': Parameter(int, "Foreign node identifier at peer", nullok = True),
52 'node_tag_ids' : Parameter ([int], "List of tags attached to this node"),
53 'nodegroup_ids': Parameter([int], "List of node groups that this node is in"),
57 class UpdateNode(Method):
59 Updates a node. Only the fields specified in node_fields are
60 updated, all other fields are left untouched.
62 PIs and techs can update only the nodes at their sites. Only
63 admins can update the key, session, and boot_nonce fields.
65 Returns 1 if successful, faults otherwise.
68 roles = ['admin', 'pi', 'tech']
70 accepted_fields = Row.accepted_fields(can_update,legacy_node_fields)
71 # xxx check the related_fields feature
72 accepted_fields.update(Node.related_fields)
73 accepted_fields.update(Node.tags)
77 Mixed(Node.fields['node_id'],
78 Node.fields['hostname']),
82 returns = Parameter(int, '1 if successful')
84 def call(self, auth, node_id_or_hostname, node_fields):
86 # split provided fields
87 [native,related,tags,rejected] = Row.split_fields(node_fields,[legacy_node_fields,Node.related_fields,Node.tags])
90 native = Row.check_fields (native, self.accepted_fields)
92 raise PLCInvalidArgument, "Cannot update Node column(s) %r"%rejected
94 # Authenticated function
95 assert self.caller is not None
97 # Remove admin only fields
98 if 'admin' not in self.caller['roles']:
99 for key in admin_only:
100 if native.has_key(key):
103 # Get account information
104 nodes = Nodes(self.api, [node_id_or_hostname])
106 raise PLCInvalidArgument, "No such node %r"%node_id_or_hostname
109 if node['peer_id'] is not None:
110 raise PLCInvalidArgument, "Not a local node %r"%node_id_or_hostname
112 # If we are not an admin, make sure that the caller is a
113 # member of the site at which the node is located.
114 if 'admin' not in self.caller['roles']:
115 if node['site_id'] not in self.caller['site_ids']:
116 raise PLCPermissionDenied, "Not allowed to delete nodes from specified site"
118 # Make requested associations
119 for (k,v) in related.iteritems():
120 node.associate(auth, k,v)
123 node.update_last_updated(commit=False)
124 node.sync(commit=True)
126 # if hostname was modifed make sure to update the hrn
128 if 'hostname' in native:
129 root_auth = self.api.config.PLC_HRN_ROOT
130 # sub auth is the login base of this node's site
131 sites = Sites(self.api, node['site_id'], ['login_base'])
133 login_base = site['login_base']
134 tags['hrn'] = hostname_to_hrn(root_auth, login_base, node['hostname'])
136 for (tagname,value) in tags.iteritems():
137 # the tagtype instance is assumed to exist, just check that
138 tag_types = TagTypes(self.api,{'tagname':tagname})
140 raise PLCInvalidArgument,"No such TagType %s"%tagname
141 tag_type = tag_types[0]
142 node_tags=NodeTags(self.api,{'tagname':tagname,'node_id':node['node_id']})
144 node_tag = NodeTag(self.api)
145 node_tag['node_id'] = node['node_id']
146 node_tag['tag_type_id'] = tag_type['tag_type_id']
147 node_tag['tagname'] = tagname
148 node_tag['value'] = value
151 node_tag = node_tags[0]
152 node_tag['value'] = value
155 self.event_objects = {'Node': [node['node_id']]}
156 if 'hostname' in node:
157 self.message = 'Node %s updated'%node['hostname']
159 self.message = 'Node %d updated'%node['node_id']
160 self.message += " [%s]." % (", ".join(node_fields.keys()),)
161 if 'boot_state' in node_fields.keys():
162 self.message += ' boot_state updated to %s' % node_fields['boot_state']