3e8b0b56d63762a44b9e7a34a01b4831abf9ec50
[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         TOTAL_MINIMUM_DISK_SIZE= \
61                    int(vars["TOTAL_MINIMUM_DISK_SIZE"])
62
63         SKIP_HARDWARE_REQUIREMENT_CHECK= \
64                    int(vars["SKIP_HARDWARE_REQUIREMENT_CHECK"])
65         
66     except KeyError, var:
67         raise BootManagerException, \
68               "Missing variable in install store: %s" % var
69     except ValueError, var:
70         raise BootManagerException, \
71               "Variable in install store blank, shouldn't be: %s" % var
72
73     # lets see if we have enough memory to run
74     log.write( "Checking for available memory.\n" )
75
76     total_mem= systeminfo.get_total_phsyical_mem(vars, log)
77     if total_mem is None:
78         raise BootManagerException, "Unable to read total physical memory"
79         
80     if total_mem < MINIMUM_MEMORY:
81         if not SKIP_HARDWARE_REQUIREMENT_CHECK:
82             log.write( "Insufficient memory to run node: %s kb\n" % total_mem )
83             log.write( "Required memory: %s kb\n" % MINIMUM_MEMORY )
84
85             include_pis= 0
86             include_techs= 1
87             include_support= 0
88             
89             sent= 0
90             try:
91                 sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
92                                          (notify_messages.MSG_INSUFFICIENT_MEMORY,
93                                           include_pis,
94                                           include_techs,
95                                           include_support) )
96             except BootManagerException, e:
97                 log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
98                 
99             if sent == 0:
100                 log.write( "Unable to notify site contacts of problem.\n" )
101             else:
102                 log.write( "Notified contacts of problem.\n" )
103                 
104             return 0
105         else:
106             log.write( "Memory requirements not met, but running anyway: %s kb\n"
107                        % total_mem )
108     else:
109         log.write( "Looks like we have enough memory: %s kb\n" % total_mem )
110
111
112
113     # get a list of block devices to attempt to install on
114     # (may include cdrom devices)
115     install_devices= systeminfo.get_block_device_list(vars, log)
116
117     # save the list of block devices in the log
118     log.write( "Detected block devices:\n" )
119     log.write( repr(install_devices) + "\n" )
120
121     if not install_devices or len(install_devices) == 0:
122         log.write( "No block devices detected.\n" )
123         
124         include_pis= 0
125         include_techs= 1
126         include_support= 0
127         
128         sent= 0
129         try:
130             sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
131                                        (notify_messages.MSG_INSUFFICIENT_DISK,
132                                         include_pis,
133                                         include_techs,
134                                         include_support) )
135         except BootManagerException, e:
136             log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
137             
138         if sent == 0:
139             log.write( "Unable to notify site contacts of problem.\n" )
140
141         return 0
142
143     # now, lets remove any block devices we know won't work (readonly,cdroms),
144     # or could be other writable removable disks (usb keychains, zip disks, etc)
145     # i'm not aware of anything that helps with the latter test, so,
146     # what we'll probably do is simply not use any block device below
147     # some size threshold (set in installstore)
148
149     # also, keep track of the total size for all devices that appear usable
150     total_size= 0
151
152     for device in install_devices.keys():
153
154         (major,minor,blocks,gb_size,readonly)= install_devices[device]
155         
156         # if the device string starts with
157         # planetlab or dm- (device mapper), ignore it (could be old lvm setup)
158         if device[:14] == "/dev/planetlab" or device[:8] == "/dev/dm-":
159             del install_devices[device]
160             continue
161
162         if gb_size < MINIMUM_DISK_SIZE:
163             log.write( "Device is too small to use: %s \n(appears" \
164                            " to be %4.2f GB)\n" % (device,gb_size) )
165             try:
166                 del install_devices[device]
167             except KeyError, e:
168                 pass
169             continue
170
171         if readonly:
172             log.write( "Device is readonly, not using: %s\n" % device )
173             try:
174                 del install_devices[device]
175             except KeyError, e:
176                 pass
177             continue
178             
179         # add this sector count to the total count of usable
180         # sectors we've found.
181         total_size= total_size + gb_size
182
183
184     if len(install_devices) == 0:
185         log.write( "No suitable block devices found for install.\n" )
186
187         include_pis= 0
188         include_techs= 1
189         include_support= 0
190         
191         sent= 0
192         try:
193             sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
194                                        (notify_messages.MSG_INSUFFICIENT_DISK,
195                                         include_pis,
196                                         include_techs,
197                                         include_support) )
198         except BootManagerException, e:
199             log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
200             
201         if sent == 0:
202             log.write( "Unable to notify site contacts of problem.\n" )
203
204         return 0
205
206
207     # show the devices we found that are usable
208     log.write( "Usable block devices:\n" )
209     log.write( repr(install_devices.keys()) + "\n" )
210
211     # save the list of devices for the following steps
212     vars["INSTALL_BLOCK_DEVICES"]= install_devices.keys()
213
214
215     # ensure the total disk size is large enough. if
216     # not, we need to email the tech contacts the problem, and
217     # put the node into debug mode.
218     if total_size < TOTAL_MINIMUM_DISK_SIZE:
219         if not SKIP_HARDWARE_REQUIREMENT_CHECK:
220             log.write( "The total usable disk size of all disks is " \
221                        "insufficient to be usable as a PlanetLab node.\n" )
222             include_pis= 0
223             include_techs= 1
224             include_support= 0
225             
226             sent= 0
227             try:
228                 sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
229                                             (notify_messages.MSG_INSUFFICIENT_DISK,
230                                              include_pis,
231                                              include_techs,
232                                              include_support) )
233             except BootManagerException, e:
234                 log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
235             
236             if sent == 0:
237                 log.write( "Unable to notify site contacts of problem.\n" )
238
239             return 0
240         
241         else:
242             log.write( "The total usable disk size of all disks is " \
243                        "insufficient, but running anyway.\n" )
244             
245     log.write( "Total size for all usable block devices: %4.2f GB\n" % total_size )
246
247     return 1