0b5cf8e76d210a9dbf3d48eb09441a40d1cfc1f6
[plcapi.git] / PLC / Methods / GenerateNodeConfFile.py
1 import random
2 import base64
3
4 from PLC.Faults import *
5 from PLC.Method import Method
6 from PLC.Parameter import Parameter, Mixed
7 from PLC.Nodes import Node, Nodes
8 from PLC.NodeNetworks import NodeNetwork, NodeNetworks
9 from PLC.Auth import Auth
10
11 class GenerateNodeConfFile(Method):
12     """
13     Creates a new node configuration file if all network settings are
14     present. This function will generate a new node key for the
15     specified node, effectively invalidating any old configuration
16     files.
17
18     Non-admins can only generate files for nodes at their sites.
19
20     Returns the contents of the file if successful, faults otherwise.
21     """
22
23     roles = ['admin', 'pi', 'tech']
24
25     accepts = [
26         Auth(),
27         Mixed(Node.fields['node_id'],
28               Node.fields['hostname']),
29         Parameter(bool, "True if you want to regenerate node key")
30         ]
31
32     returns = Parameter(str, "Node configuration file")
33
34     def call(self, auth, node_id_or_hostname, regenerate_node_key = True):
35         # Get node information
36         nodes = Nodes(self.api, [node_id_or_hostname])
37         if not nodes:
38             raise PLCInvalidArgument, "No such node"
39         node = nodes[0]
40
41         if node['peer_id'] is not None:
42             raise PLCInvalidArgument, "Not a local node"
43
44         # If we are not an admin, make sure that the caller is a
45         # member of the site at which the node is located.
46         if 'admin' not in self.caller['roles']:
47             if node['site_id'] not in self.caller['site_ids']:
48                 raise PLCPermissionDenied, "Not allowed to generate a configuration file for that node"
49
50         # Get node networks for this node
51         primary = None
52         nodenetworks = NodeNetworks(self.api, node['nodenetwork_ids'])
53         for nodenetwork in nodenetworks:
54             if nodenetwork['is_primary']:
55                 primary = nodenetwork
56                 break
57         if primary is None:
58             raise PLCInvalidArgument, "No primary network configured"
59
60         # Split hostname into host and domain parts
61         parts = node['hostname'].split(".", 1)
62         if len(parts) < 2:
63             raise PLCInvalidArgument, "Node hostname is invalid"
64         host = parts[0]
65         domain = parts[1]
66
67         if regenerate_node_key:
68             # Generate 32 random bytes
69             bytes = random.sample(xrange(0, 256), 32)
70             # Base64 encode their string representation
71             node['key'] = base64.b64encode("".join(map(chr, bytes)))
72             # XXX Boot Manager cannot handle = in the key
73             node['key'] = node['key'].replace("=", "")
74             # Save it
75             node.sync()
76
77         # Generate node configuration file suitable for BootCD
78         file = ""
79
80         file += 'NODE_ID="%d"\n' % node['node_id']
81         file += 'NODE_KEY="%s"\n' % node['key']
82
83         if primary['mac']:
84             file += 'NET_DEVICE="%s"\n' % primary['mac'].lower()
85
86         file += 'IP_METHOD="%s"\n' % primary['method']
87
88         if primary['method'] == 'static':
89             file += 'IP_ADDRESS="%s"\n' % primary['ip']
90             file += 'IP_GATEWAY="%s"\n' % primary['gateway']
91             file += 'IP_NETMASK="%s"\n' % primary['netmask']
92             file += 'IP_NETADDR="%s"\n' % primary['network']
93             file += 'IP_BROADCASTADDR="%s"\n' % primary['broadcast']
94             file += 'IP_DNS1="%s"\n' % primary['dns1']
95             file += 'IP_DNS2="%s"\n' % (primary['dns2'] or "")
96
97         file += 'HOST_NAME="%s"\n' % host
98         file += 'DOMAIN_NAME="%s"\n' % domain
99
100         for nodenetwork in nodenetworks:
101             if nodenetwork['method'] == 'ipmi':
102                 file += 'IPMI_ADDRESS="%s"\n' % nodenetwork['ip']
103                 if nodenetwork['mac']:
104                     file += 'IPMI_MAC="%s"\n' % nodenetwork['mac'].lower()
105                 break
106
107         return file