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