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