no real change, just made prettier with a more standard layout - half of steps
[bootmanager.git] / source / steps / CheckHardwareRequirements.py
1 #!/usr/bin/python
2 #
3 # Copyright (c) 2003 Intel Corporation
4 # All rights reserved.
5 #
6 # Copyright (c) 2004-2006 The Trustees of Princeton University
7 # All rights reserved.
8 # expected /proc/partitions format
9
10 import os
11 import popen2
12 import string
13
14 import systeminfo
15 from Exceptions import *
16 import utils
17 import notify_messages
18 import BootAPI
19
20
21 def Run(vars, log):
22     """
23     Make sure the hardware we are running on is sufficient for
24     the PlanetLab OS to be installed on. In the process, identify
25     the list of block devices that may be used for a node installation,
26     and identify the cdrom device that we booted off of.
27
28     Return 1 if requiremenst met, 0 if requirements not met. Raise
29     BootManagerException if any problems occur that prevent the requirements
30     from being checked.
31
32     Expect the following variables from the store:
33
34     MINIMUM_MEMORY          minimum amount of memory in kb required
35                             for install
36     NODE_ID                 the node_id from the database for this node
37     MINIMUM_DISK_SIZE       any disks smaller than this size, in GB, are not used
38     TOTAL_MINIMUM_DISK_SIZE total disk size in GB, if all usable disks
39                             meet this number, there isn't enough disk space for
40                             this node to be usable after install
41     SKIP_HARDWARE_REQUIREMENT_CHECK
42                             If set, don't check if minimum requirements are met
43     Sets the following variables:
44     INSTALL_BLOCK_DEVICES    list of block devices to install onto
45     """
46
47     log.write("\n\nStep: Checking if hardware requirements met.\n")        
48         
49     try:
50         MINIMUM_MEMORY = int(vars["MINIMUM_MEMORY"])
51         if MINIMUM_MEMORY == "":
52             raise ValueError("MINIMUM_MEMORY")
53
54         NODE_ID = vars["NODE_ID"]
55         if NODE_ID == "":
56             raise ValueError("NODE_ID")
57
58         MINIMUM_DISK_SIZE = int(vars["MINIMUM_DISK_SIZE"])
59
60         # use vs_ or lxc_variants
61         varname = vars['virt'] + "_TOTAL_MINIMUM_DISK_SIZE"
62         TOTAL_MINIMUM_DISK_SIZE = int(vars[varname])
63
64         SKIP_HARDWARE_REQUIREMENT_CHECK = int(vars["SKIP_HARDWARE_REQUIREMENT_CHECK"])
65         
66     except KeyError as var:
67         raise BootManagerException("Missing variable in install store: {}".format(var))
68     except ValueError as var:
69         raise BootManagerException("Variable in install store blank, shouldn't be: {}".format(var))
70
71     # lets see if we have enough memory to run
72     log.write("Checking for available memory.\n")
73
74     total_mem = systeminfo.get_total_phsyical_mem(vars, log)
75     if total_mem is None:
76         raise BootManagerException("Unable to read total physical memory")
77         
78     if total_mem < MINIMUM_MEMORY:
79         if not SKIP_HARDWARE_REQUIREMENT_CHECK:
80             log.write("Insufficient memory to run node: {} kb\n".format(total_mem))
81             log.write("Required memory: {} kb\n".format(MINIMUM_MEMORY))
82
83             include_pis = 0
84             include_techs = 1
85             include_support = 0
86             
87             sent = 0
88             try:
89                 sent = BootAPI.call_api_function(vars, "BootNotifyOwners",
90                                                  (notify_messages.MSG_INSUFFICIENT_MEMORY,
91                                                   include_pis,
92                                                   include_techs,
93                                                   include_support))
94             except BootManagerException as e:
95                 log.write("Call to BootNotifyOwners failed: {}.\n".format(e))
96                 
97             if sent == 0:
98                 log.write("Unable to notify site contacts of problem.\n")
99             else:
100                 log.write("Notified contacts of problem.\n")
101                 
102             return 0
103         else:
104             log.write("Memory requirements not met, but running anyway: {} kb\n"
105                       .format(total_mem))
106     else:
107         log.write("Looks like we have enough memory: {} kb\n".format(total_mem))
108
109
110
111     # get a list of block devices to attempt to install on
112     # (may include cdrom devices)
113     install_devices = systeminfo.get_block_device_list(vars, log)
114
115     # save the list of block devices in the log
116     log.write("Detected block devices:\n")
117     log.write(repr(install_devices) + "\n")
118
119     if not install_devices or len(install_devices) == 0:
120         log.write("No block devices detected.\n")
121         
122         include_pis = 0
123         include_techs = 1
124         include_support = 0
125         
126         sent = 0
127         try:
128             sent = BootAPI.call_api_function(vars, "BootNotifyOwners",
129                                              (notify_messages.MSG_INSUFFICIENT_DISK,
130                                               include_pis,
131                                               include_techs,
132                                               include_support))
133         except BootManagerException as e:
134             log.write("Call to BootNotifyOwners failed: {}.\n".format(e))
135             
136         if sent == 0:
137             log.write("Unable to notify site contacts of problem.\n")
138
139         return 0
140
141     # now, lets remove any block devices we know won't work (readonly,cdroms),
142     # or could be other writable removable disks (usb keychains, zip disks, etc)
143     # i'm not aware of anything that helps with the latter test, so,
144     # what we'll probably do is simply not use any block device below
145     # some size threshold (set in installstore)
146
147     # also, keep track of the total size for all devices that appear usable
148     total_size = 0
149
150     for device in install_devices.keys():
151
152         major, minor, blocks, gb_size, readonly = install_devices[device]
153         
154         # if the device string starts with
155         # planetlab or dm- (device mapper), ignore it (could be old lvm setup)
156         if device[:14] == "/dev/planetlab" or device[:8] == "/dev/dm-":
157             del install_devices[device]
158             continue
159
160         if gb_size < MINIMUM_DISK_SIZE:
161             log.write("Device is too small to use: {} \n"
162                       "(appears to be {:4.2f} Gb)\n".format(device, gb_size))
163             try:
164                 del install_devices[device]
165             except KeyError as e:
166                 pass
167             continue
168
169         if readonly:
170             log.write("Device is readonly, not using: {}\n".format(device))
171             try:
172                 del install_devices[device]
173             except KeyError as e:
174                 pass
175             continue
176             
177         # add this sector count to the total count of usable
178         # sectors we've found.
179         total_size = total_size + gb_size
180
181
182     if len(install_devices) == 0:
183         log.write("No suitable block devices found for install.\n")
184
185         include_pis = 0
186         include_techs = 1
187         include_support = 0
188         
189         sent = 0
190         try:
191             sent = BootAPI.call_api_function(vars, "BootNotifyOwners",
192                                              (notify_messages.MSG_INSUFFICIENT_DISK,
193                                               include_pis,
194                                               include_techs,
195                                               include_support))
196         except BootManagerException as e:
197             log.write("Call to BootNotifyOwners failed: {}.\n".format(e))
198             
199         if sent == 0:
200             log.write("Unable to notify site contacts of problem.\n")
201
202         return 0
203
204
205     # show the devices we found that are usable
206     log.write("Usable block devices:\n")
207     log.write(repr(install_devices.keys()) + "\n")
208
209     # save the list of devices for the following steps
210     vars["INSTALL_BLOCK_DEVICES"] = install_devices.keys()
211
212
213     # ensure the total disk size is large enough. if
214     # not, we need to email the tech contacts the problem, and
215     # put the node into debug mode.
216     if total_size < TOTAL_MINIMUM_DISK_SIZE:
217         if not SKIP_HARDWARE_REQUIREMENT_CHECK:
218             log.write("The total usable disk size of all disks is " \
219                        "insufficient to be usable as a PlanetLab node.\n")
220             include_pis = 0
221             include_techs = 1
222             include_support = 0
223             
224             sent = 0
225             try:
226                 sent = BootAPI.call_api_function(vars, "BootNotifyOwners",
227                                                  (notify_messages.MSG_INSUFFICIENT_DISK,
228                                                   include_pis,
229                                                   include_techs,
230                                                   include_support))
231             except BootManagerException as e:
232                 log.write("Call to BootNotifyOwners failed: {}.\n".format(e))
233             
234             if sent == 0:
235                 log.write("Unable to notify site contacts of problem.\n")
236
237             return 0
238         
239         else:
240             log.write("The total usable disk size of all disks is " \
241                        "insufficient, but running anyway.\n")
242             
243     log.write("Total size for all usable block devices: {:4.2f} Gb\n".format(total_size))
244
245     return 1