Initial checkin of new API implementation
[plcapi.git] / PLC / Methods / AdmAddNode.py
1 from PLC.Faults import *
2 from PLC.Method import Method
3 from PLC.Parameter import Parameter, Mixed
4 from PLC.Nodes import Node, Nodes
5 from PLC.Sites import Site, Sites
6 from PLC.Auth import PasswordAuth
7
8 class AdmAddNode(Method):
9     """
10     Adds a new node. Any values specified in optional_vals are used,
11     otherwise defaults are used.
12
13     PIs and techs may only add nodes to their own sites. Admins may
14     add nodes to any site.
15
16     Returns the new node_id (> 0) if successful, faults otherwise.
17     """
18
19     roles = ['admin', 'pi', 'tech']
20
21     can_update = lambda (field, value): field in \
22                  ['model', 'version']
23     update_fields = dict(filter(can_update, Node.fields.items()))
24
25     accepts = [
26         PasswordAuth(),
27         Mixed(Site.fields['site_id'],
28               Site.fields['login_base']),
29         Node.fields['hostname'],
30         Node.fields['boot_state'],
31         update_fields
32         ]
33
34     returns = Parameter(int, '1 if successful')
35
36     def call(self, auth, site_id_or_login_base, hostname, boot_state, optional_vals = {}):
37         if filter(lambda field: field not in self.update_fields, optional_vals):
38             raise PLCInvalidArgument, "Invalid fields specified"
39
40         # Get site information
41         sites = Sites(self.api, [site_id_or_login_base])
42         if not sites:
43             raise PLCInvalidArgument, "No such site"
44
45         site = sites.values()[0]
46
47         # Authenticated function
48         assert self.caller is not None
49
50         # If we are not an admin, make sure that the caller is a
51         # member of the site.
52         if 'admin' not in self.caller['roles']:
53             if site['site_id'] not in self.caller['site_ids']:
54                 assert self.caller['person_id'] not in site['person_ids']
55                 raise PLCPermissionDenied, "Not allowed to add nodes to specified site"
56             else:
57                 assert self.caller['person_id'] in site['person_ids']
58
59         node = Node(self.api, optional_vals)
60         node['hostname'] = hostname
61         node['boot_state'] = boot_state
62         node.flush()
63
64         # Now associate the node with the site
65         node_id = node['node_id']
66         nodegroup_id = site['nodegroup_id']
67         self.api.db.do("INSERT INTO nodegroup_nodes (nodegroup_id, node_id)" \
68                        " VALUES(%(nodegroup_id)d, %(node_id)d)",
69                        locals())
70
71         return node['node_id']