check in all bootmanager sources
[bootmanager.git] / source / steps / CheckHardwareRequirements.py
1 # Copyright (c) 2003 Intel Corporation
2 # All rights reserved.
3
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7
8 #     * Redistributions of source code must retain the above copyright
9 #       notice, this list of conditions and the following disclaimer.
10
11 #     * Redistributions in binary form must reproduce the above
12 #       copyright notice, this list of conditions and the following
13 #       disclaimer in the documentation and/or other materials provided
14 #       with the distribution.
15
16 #     * Neither the name of the Intel Corporation nor the names of its
17 #       contributors may be used to endorse or promote products derived
18 #       from this software without specific prior written permission.
19
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
24 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 # EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
33 # YOUR JURISDICTION. It is licensee's responsibility to comply with any
34 # export regulations applicable in licensee's jurisdiction. Under
35 # CURRENT (May 2000) U.S. export regulations this software is eligible
36 # for export from the U.S. and can be downloaded by or otherwise
37 # exported or reexported worldwide EXCEPT to U.S. embargoed destinations
38 # which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
39 # Afghanistan and any other country to which the U.S. has embargoed
40 # goods and services.
41
42
43 import os
44 import popen2
45 import string
46
47 from systeminfo import systeminfo
48 from Exceptions import *
49 import utils
50 import notify_messages
51 import BootAPI
52
53
54 def Run( vars, log ):
55     """
56     Make sure the hardware we are running on is sufficient for
57     the PlanetLab OS to be installed on. In the process, identify
58     the list of block devices that may be used for a node installation,
59     and identify the cdrom device that we booted off of.
60
61     Return 1 if requiremenst met, 0 if requirements not met. Raise
62     BootManagerException if any problems occur that prevent the requirements
63     from being checked.
64
65     Expect the following variables from the store:
66
67     MINIMUM_MEMORY          minimum amount of memory in kb required
68                             for install
69     NODE_ID                 the node_id from the database for this node
70     MINIMUM_DISK_SIZE       any disks smaller than this size, in GB, are not used
71     TOTAL_MINIMUM_DISK_SIZE total disk size in GB, if all usable disks
72                             meet this number, there isn't enough disk space for
73                             this node to be usable after install
74     SKIP_HARDWARE_REQUIREMENT_CHECK
75                             If set, don't check if minimum requirements are met
76     BOOT_CD_VERSION          A tuple of the current bootcd version                            
77     Sets the following variables:
78     INSTALL_BLOCK_DEVICES    list of block devices to install onto
79     """
80
81     log.write( "\n\nStep: Checking if hardware requirements met.\n" )        
82         
83     try:
84         MINIMUM_MEMORY= int(vars["MINIMUM_MEMORY"])
85         if MINIMUM_MEMORY == "":
86             raise ValueError, "MINIMUM_MEMORY"
87
88         NODE_ID= vars["NODE_ID"]
89         if NODE_ID == "":
90             raise ValueError("NODE_ID")
91
92         MINIMUM_DISK_SIZE= int(vars["MINIMUM_DISK_SIZE"])
93
94         TOTAL_MINIMUM_DISK_SIZE= \
95                    int(vars["TOTAL_MINIMUM_DISK_SIZE"])
96
97         SKIP_HARDWARE_REQUIREMENT_CHECK= \
98                    int(vars["SKIP_HARDWARE_REQUIREMENT_CHECK"])
99         
100         BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
101         if BOOT_CD_VERSION == "":
102             raise ValueError, "BOOT_CD_VERSION"
103
104     except KeyError, var:
105         raise BootManagerException, \
106               "Missing variable in install store: %s" % var
107     except ValueError, var:
108         raise BootManagerException, \
109               "Variable in install store blank, shouldn't be: %s" % var
110
111     sysinfo= systeminfo()
112     
113     # lets see if we have enough memory to run
114     log.write( "Checking for available memory.\n" )
115
116     total_mem= sysinfo.get_total_phsyical_mem()
117     if total_mem is None:
118         raise BootManagerException, "Unable to read total physical memory"
119         
120     if total_mem < MINIMUM_MEMORY:
121         if not SKIP_HARDWARE_REQUIREMENT_CHECK:
122             log.write( "Insufficient memory to run node: %s kb\n" % total_mem )
123             log.write( "Required memory: %s kb\n" % MINIMUM_MEMORY )
124
125             include_pis= 0
126             include_techs= 1
127             include_support= 0
128             
129             sent= 0
130             try:
131                 sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
132                                          (notify_messages.MSG_INSUFFICIENT_MEMORY,
133                                           include_pis,
134                                           include_techs,
135                                           include_support) )
136             except BootManagerException, e:
137                 log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
138                 
139             if sent == 0:
140                 log.write( "Unable to notify site contacts of problem.\n" )
141             else:
142                 log.write( "Notified contacts of problem.\n" )
143                 
144             return 0
145         else:
146             log.write( "Memory requirements not met, but running anyway: %s kb\n"
147                        % total_mem )
148     else:
149         log.write( "Looks like we have enough memory: %s kb\n" % total_mem )
150
151
152
153     # get a list of block devices to attempt to install on
154     # (may include cdrom devices)
155     install_devices= sysinfo.get_block_device_list()
156
157     # save the list of block devices in the log
158     log.write( "Detected block devices:\n" )
159     log.write( repr(install_devices) + "\n" )
160
161     if not install_devices or len(install_devices) == 0:
162         log.write( "No block devices detected.\n" )
163         
164         include_pis= 0
165         include_techs= 1
166         include_support= 0
167         
168         sent= 0
169         try:
170             sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
171                                        (notify_messages.MSG_INSUFFICIENT_DISK,
172                                         include_pis,
173                                         include_techs,
174                                         include_support) )
175         except BootManagerException, e:
176             log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
177             
178         if sent == 0:
179             log.write( "Unable to notify site contacts of problem.\n" )
180
181         return 0
182
183     # now, lets remove any block devices we know won't work (readonly,cdroms),
184     # or could be other writable removable disks (usb keychains, zip disks, etc)
185     # i'm not aware of anything that helps with the latter test, so,
186     # what we'll probably do is simply not use any block device below
187     # some size threshold (set in installstore)
188
189     # also, keep track of the total size for all devices that appear usable
190     total_size= 0
191
192     for device in install_devices.keys():
193
194         (major,minor,blocks,gb_size,readonly)= install_devices[device]
195         
196         # if the device string starts with
197         # planetlab, ignore it (could be old lvm setup)
198         if device[:14] == "/dev/planetlab":
199             del install_devices[device]
200             continue
201
202         if gb_size < MINIMUM_DISK_SIZE:
203             log.write( "Device is too small to use: %s \n(appears" \
204                            " to be %4.2f GB)\n" % (device,gb_size) )
205             try:
206                 del install_devices[device]
207             except KeyError, e:
208                 pass
209             continue
210
211         if readonly:
212             log.write( "Device is readonly, not using: %s\n" % device )
213             try:
214                 del install_devices[device]
215             except KeyError, e:
216                 pass
217             continue
218             
219         # add this sector count to the total count of usable
220         # sectors we've found.
221         total_size= total_size + gb_size
222
223
224     if len(install_devices) == 0:
225         log.write( "No suitable block devices found for install.\n" )
226
227         include_pis= 0
228         include_techs= 1
229         include_support= 0
230         
231         sent= 0
232         try:
233             sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
234                                        (notify_messages.MSG_INSUFFICIENT_DISK,
235                                         include_pis,
236                                         include_techs,
237                                         include_support) )
238         except BootManagerException, e:
239             log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
240             
241         if sent == 0:
242             log.write( "Unable to notify site contacts of problem.\n" )
243
244         return 0
245
246
247     # show the devices we found that are usable
248     log.write( "Usable block devices:\n" )
249     log.write( repr(install_devices.keys()) + "\n" )
250
251     # save the list of devices for the following steps
252     vars["INSTALL_BLOCK_DEVICES"]= install_devices.keys()
253
254
255     # ensure the total disk size is large enough. if
256     # not, we need to email the tech contacts the problem, and
257     # put the node into debug mode.
258     if total_size < TOTAL_MINIMUM_DISK_SIZE:
259         if not SKIP_HARDWARE_REQUIREMENT_CHECK:
260             log.write( "The total usable disk size of all disks is " \
261                        "insufficient to be usable as a PlanetLab node.\n" )
262             include_pis= 0
263             include_techs= 1
264             include_support= 0
265             
266             sent= 0
267             try:
268                 sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
269                                             (notify_messages.MSG_INSUFFICIENT_DISK,
270                                              include_pis,
271                                              include_techs,
272                                              include_support) )
273             except BootManagerException, e:
274                 log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
275             
276             if sent == 0:
277                 log.write( "Unable to notify site contacts of problem.\n" )
278
279             return 0
280         
281         else:
282             log.write( "The total usable disk size of all disks is " \
283                        "insufficient, but running anyway.\n" )
284             
285     log.write( "Total size for all usable block devices: %4.2f GB\n" % total_size )
286
287     # turn off UDMA for all block devices on 2.x cds (2.4 kernel)
288     if BOOT_CD_VERSION[0] == 2:
289         for device in install_devices:
290             log.write( "Disabling UDMA on %s\n" % device )
291             utils.sysexec_noerr( "/sbin/hdparm -d0 %s" % device, log )
292
293     return 1