fix PLCAPI doc that was whining about duplicate ids in docbook xml output
[plcapi.git] / PLC / Methods / Legacy / GetNodes.py
1 # $Id$
2 # $URL$
3 from PLC.Faults import *
4 from PLC.Method import Method
5 from PLC.Parameter import Parameter, Mixed
6 from PLC.Filter import Filter
7 from PLC.Nodes import Node, Nodes
8 from PLC.Persons import Person, Persons
9 from PLC.Auth import Auth
10
11 admin_only = ['key', 'session', 'boot_nonce' ]
12
13 legacy_node_fields = {
14     'node_id': Parameter(int, "Node identifier"),
15     'node_type': Parameter(str,"Node type",max=20),
16     'hostname': Parameter(str, "Fully qualified hostname", max = 255),
17     'site_id': Parameter(int, "Site at which this node is located"),
18     'boot_state': Parameter(str, "Boot state", max = 20),
19     'run_level': Parameter(str, "Run level", max = 20),
20     'model': Parameter(str, "Make and model of the actual machine", max = 255, nullok = True),
21     'boot_nonce': Parameter(str, "(Admin only) Random value generated by the node at last boot", max = 128),
22     'version': Parameter(str, "Apparent Boot CD version", max = 64),
23     'ssh_rsa_key': Parameter(str, "Last known SSH host key", max = 1024),
24     'date_created': Parameter(int, "Date and time when node entry was created", ro = True),
25     'last_updated': Parameter(int, "Date and time when node entry was created", ro = True),
26     'last_contact': Parameter(int, "Date and time when node last contacted plc", ro = True),
27     'last_boot': Parameter(int, "Date and time when node last booted", ro = True),
28     'last_download': Parameter(int, "Date and time when node boot image was created", ro = True),
29     'last_pcu_reboot': Parameter(int, "Date and time when PCU reboot was attempted", ro = True),
30     'last_pcu_confirmation': Parameter(int, "Date and time when PCU reboot was confirmed", ro = True),
31     'last_time_spent_online': Parameter(int, "Length of time the node was last online before shutdown/failure", ro = True),
32     'last_time_spent_offline': Parameter(int, "Length of time the node was last offline after failure and before reboot", ro = True),
33     'verified': Parameter(bool, "Whether the node configuration is verified correct", ro=False),
34     'key': Parameter(str, "(Admin only) Node key", max = 256),
35     'session': Parameter(str, "(Admin only) Node session value", max = 256, ro = True),
36     'interface_ids': Parameter([int], "List of network interfaces that this node has"),
37     'conf_file_ids': Parameter([int], "List of configuration files specific to this node"),
38     # 'root_person_ids': Parameter([int], "(Admin only) List of people who have root access to this node"),
39     'slice_ids': Parameter([int], "List of slices on this node"),
40     'slice_ids_whitelist': Parameter([int], "List of slices allowed on this node"),
41     'pcu_ids': Parameter([int], "List of PCUs that control this node"),
42     'ports': Parameter([int], "List of PCU ports that this node is connected to"),
43     'peer_id': Parameter(int, "Peer to which this node belongs", nullok = True),
44     'peer_node_id': Parameter(int, "Foreign node identifier at peer", nullok = True),
45     'node_tag_ids' : Parameter ([int], "List of tags attached to this node"),
46     'nodegroup_ids': Parameter([int], "List of node groups that this node is in"),
47     }
48
49 def clean_node_fields(node):
50     remove_keys = [key for key in node.keys() if key not in legacy_node_fields.keys()]
51     for key in remove_keys:
52         del node[key]
53     return node
54
55
56 class GetNodes(Method):
57     """
58     Returns an array of structs containing details about nodes. If
59     node_filter is specified and is an array of node identifiers or
60     hostnames, or a struct of node attributes, only nodes matching the
61     filter will be returned.
62
63     If return_fields is specified, only the specified details will be
64     returned. NOTE that if return_fields is unspecified, the complete
65     set of native fields are returned, which DOES NOT include tags at
66     this time.
67
68     Some fields may only be viewed by admins.
69     """
70
71     roles = ['admin', 'pi', 'user', 'tech', 'node', 'anonymous']
72
73     accepts = [
74         Auth(),
75         Mixed([Mixed(Node.fields['node_id'],
76                      Node.fields['hostname'])],
77               Parameter(str,"hostname"),
78               Parameter(int,"node_id"),
79               Filter(legacy_node_fields)),
80         Parameter([str], "List of fields to return", nullok = True),
81         ]
82
83     returns = [legacy_node_fields]
84
85     # needed for generating the doc and prevent conflicts in the xml ids
86     status = 'legacy'
87
88     def call(self, auth, node_filter = None, return_fields = None):
89
90         # Must query at least slice_ids_whitelist
91         if return_fields is not None:
92             added_fields = set(['slice_ids_whitelist', 'site_id']).difference(return_fields)
93             return_fields += added_fields
94         else:
95             added_fields =[]
96
97         # Get node information
98         nodes = Nodes(self.api, node_filter, return_fields)
99
100         # Remove admin only fields
101         if not isinstance(self.caller, Person) or \
102            'admin' not in self.caller['roles']:
103             slice_ids = set()
104             site_ids = set()
105
106             if self.caller:
107                 slice_ids.update(self.caller['slice_ids'])
108                 if isinstance(self.caller, Node):
109                     site_ids.update([self.caller['site_id']])
110                 else:
111                     site_ids.update(self.caller['site_ids'])
112
113             # if node has whitelist, only return it if users is at
114             # the same site or user has a slice on the whitelist
115             for node in nodes[:]:
116                 if 'site_id' in node and \
117                    site_ids.intersection([node['site_id']]):
118                     continue
119                 if 'slice_ids_whitelist' in node and \
120                    node['slice_ids_whitelist'] and \
121                    not slice_ids.intersection(node['slice_ids_whitelist']):
122                     nodes.remove(node)
123
124             # remove remaining admin only fields
125             for node in nodes:
126                 for field in admin_only:
127                     if field in node:
128                         del node[field]
129
130         # remove added fields if not specified
131         if added_fields:
132             for node in nodes:
133                 for field in added_fields:
134                     del node[field]
135
136         for node in nodes:
137             node = clean_node_fields(node)
138
139         return nodes