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