use Notify API function
[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             techs=[]
91             
92             sent= 0
93             try:
94                 #sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
95                 #                         (notify_messages.MSG_INSUFFICIENT_MEMORY,
96                 #                          include_pis,
97                 #                          include_techs,
98                 #                          include_support) )
99                 params = {"hostname" : vars['hostname'] + vars['domainname']}
100                 person_ids = BootAPI.call_api_function( vars, "GetSites", 
101                                             (vars['SITE_ID'], ['person_ids']))[0]
102                 persons = BootAPI.call_api_function( vars, "GetPersons", 
103                                             (person_ids, ['person_id', 'roles']))
104                 for person in persons:
105                     if "tech" in person['roles']: techs.append(person['person_id'])
106                 msg = BootAPI.call_api_function( vars, "GetMessages", 
107                                    ({"message_id": notify_messages.MSG_INSUFFICIENT_MEMORY}),)[0]
108                 sent= BootAPI.call_api_function( vars, "NotifyPersons",
109                                          (techs, msg['subject'] % params, msg['body'] % params))
110  
111             except BootManagerException, e:
112                 log.write( "Call to NotifyPersons failed: %s.\n" % e )
113                 
114             if sent == 0:
115                 log.write( "Unable to notify site contacts of problem.\n" )
116             else:
117                 log.write( "Notified contacts of problem.\n" )
118                 
119             return 0
120         else:
121             log.write( "Memory requirements not met, but running anyway: %s kb\n"
122                        % total_mem )
123     else:
124         log.write( "Looks like we have enough memory: %s kb\n" % total_mem )
125
126
127
128     # get a list of block devices to attempt to install on
129     # (may include cdrom devices)
130     install_devices= systeminfo.get_block_device_list(vars, log)
131
132     # save the list of block devices in the log
133     log.write( "Detected block devices:\n" )
134     log.write( repr(install_devices) + "\n" )
135
136     if not install_devices or len(install_devices) == 0:
137         log.write( "No block devices detected.\n" )
138         
139         include_pis= 0
140         include_techs= 1
141         include_support= 0
142         
143         sent= 0
144         try:
145             sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
146                                        (notify_messages.MSG_INSUFFICIENT_DISK,
147                                         include_pis,
148                                         include_techs,
149                                         include_support) )
150         except BootManagerException, e:
151             log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
152             
153         if sent == 0:
154             log.write( "Unable to notify site contacts of problem.\n" )
155
156         return 0
157
158     # now, lets remove any block devices we know won't work (readonly,cdroms),
159     # or could be other writable removable disks (usb keychains, zip disks, etc)
160     # i'm not aware of anything that helps with the latter test, so,
161     # what we'll probably do is simply not use any block device below
162     # some size threshold (set in installstore)
163
164     # also, keep track of the total size for all devices that appear usable
165     total_size= 0
166
167     for device in install_devices.keys():
168
169         (major,minor,blocks,gb_size,readonly)= install_devices[device]
170         
171         # if the device string starts with
172         # planetlab or dm- (device mapper), ignore it (could be old lvm setup)
173         if device[:14] == "/dev/planetlab" or device[:8] == "/dev/dm-":
174             del install_devices[device]
175             continue
176
177         if gb_size < MINIMUM_DISK_SIZE:
178             log.write( "Device is too small to use: %s \n(appears" \
179                            " to be %4.2f GB)\n" % (device,gb_size) )
180             try:
181                 del install_devices[device]
182             except KeyError, e:
183                 pass
184             continue
185
186         if readonly:
187             log.write( "Device is readonly, not using: %s\n" % device )
188             try:
189                 del install_devices[device]
190             except KeyError, e:
191                 pass
192             continue
193             
194         # add this sector count to the total count of usable
195         # sectors we've found.
196         total_size= total_size + gb_size
197
198
199     if len(install_devices) == 0:
200         log.write( "No suitable block devices found for install.\n" )
201
202         include_pis= 0
203         include_techs= 1
204         include_support= 0
205         
206         sent= 0
207         try:
208             sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
209                                        (notify_messages.MSG_INSUFFICIENT_DISK,
210                                         include_pis,
211                                         include_techs,
212                                         include_support) )
213         except BootManagerException, e:
214             log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
215             
216         if sent == 0:
217             log.write( "Unable to notify site contacts of problem.\n" )
218
219         return 0
220
221
222     # show the devices we found that are usable
223     log.write( "Usable block devices:\n" )
224     log.write( repr(install_devices.keys()) + "\n" )
225
226     # save the list of devices for the following steps
227     vars["INSTALL_BLOCK_DEVICES"]= install_devices.keys()
228
229
230     # ensure the total disk size is large enough. if
231     # not, we need to email the tech contacts the problem, and
232     # put the node into debug mode.
233     if total_size < TOTAL_MINIMUM_DISK_SIZE:
234         if not SKIP_HARDWARE_REQUIREMENT_CHECK:
235             log.write( "The total usable disk size of all disks is " \
236                        "insufficient to be usable as a PlanetLab node.\n" )
237             include_pis= 0
238             include_techs= 1
239             include_support= 0
240             
241             sent= 0
242             try:
243                 sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
244                                             (notify_messages.MSG_INSUFFICIENT_DISK,
245                                              include_pis,
246                                              include_techs,
247                                              include_support) )
248             except BootManagerException, e:
249                 log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
250             
251             if sent == 0:
252                 log.write( "Unable to notify site contacts of problem.\n" )
253
254             return 0
255         
256         else:
257             log.write( "The total usable disk size of all disks is " \
258                        "insufficient, but running anyway.\n" )
259             
260     log.write( "Total size for all usable block devices: %4.2f GB\n" % total_size )
261
262     # turn off UDMA for all block devices on 2.x cds (2.4 kernel)
263     if BOOT_CD_VERSION[0] == 2:
264         for device in install_devices:
265             log.write( "Disabling UDMA on %s\n" % device )
266             utils.sysexec_noerr( "/sbin/hdparm -d0 %s" % device, log )
267
268     return 1