check in all bootmanager sources
[bootmanager.git] / source / steps / CheckHardwareRequirements.py
diff --git a/source/steps/CheckHardwareRequirements.py b/source/steps/CheckHardwareRequirements.py
new file mode 100644 (file)
index 0000000..1344161
--- /dev/null
@@ -0,0 +1,293 @@
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+
+#     * Neither the name of the Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+import os
+import popen2
+import string
+
+from systeminfo import systeminfo
+from Exceptions import *
+import utils
+import notify_messages
+import BootAPI
+
+
+def Run( vars, log ):
+    """
+    Make sure the hardware we are running on is sufficient for
+    the PlanetLab OS to be installed on. In the process, identify
+    the list of block devices that may be used for a node installation,
+    and identify the cdrom device that we booted off of.
+
+    Return 1 if requiremenst met, 0 if requirements not met. Raise
+    BootManagerException if any problems occur that prevent the requirements
+    from being checked.
+
+    Expect the following variables from the store:
+
+    MINIMUM_MEMORY          minimum amount of memory in kb required
+                            for install
+    NODE_ID                 the node_id from the database for this node
+    MINIMUM_DISK_SIZE       any disks smaller than this size, in GB, are not used
+    TOTAL_MINIMUM_DISK_SIZE total disk size in GB, if all usable disks
+                            meet this number, there isn't enough disk space for
+                            this node to be usable after install
+    SKIP_HARDWARE_REQUIREMENT_CHECK
+                            If set, don't check if minimum requirements are met
+    BOOT_CD_VERSION          A tuple of the current bootcd version                            
+    Sets the following variables:
+    INSTALL_BLOCK_DEVICES    list of block devices to install onto
+    """
+
+    log.write( "\n\nStep: Checking if hardware requirements met.\n" )        
+        
+    try:
+        MINIMUM_MEMORY= int(vars["MINIMUM_MEMORY"])
+        if MINIMUM_MEMORY == "":
+            raise ValueError, "MINIMUM_MEMORY"
+
+        NODE_ID= vars["NODE_ID"]
+        if NODE_ID == "":
+            raise ValueError("NODE_ID")
+
+        MINIMUM_DISK_SIZE= int(vars["MINIMUM_DISK_SIZE"])
+
+        TOTAL_MINIMUM_DISK_SIZE= \
+                   int(vars["TOTAL_MINIMUM_DISK_SIZE"])
+
+        SKIP_HARDWARE_REQUIREMENT_CHECK= \
+                   int(vars["SKIP_HARDWARE_REQUIREMENT_CHECK"])
+        
+        BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+        if BOOT_CD_VERSION == "":
+            raise ValueError, "BOOT_CD_VERSION"
+
+    except KeyError, var:
+        raise BootManagerException, \
+              "Missing variable in install store: %s" % var
+    except ValueError, var:
+        raise BootManagerException, \
+              "Variable in install store blank, shouldn't be: %s" % var
+
+    sysinfo= systeminfo()
+    
+    # lets see if we have enough memory to run
+    log.write( "Checking for available memory.\n" )
+
+    total_mem= sysinfo.get_total_phsyical_mem()
+    if total_mem is None:
+        raise BootManagerException, "Unable to read total physical memory"
+        
+    if total_mem < MINIMUM_MEMORY:
+        if not SKIP_HARDWARE_REQUIREMENT_CHECK:
+            log.write( "Insufficient memory to run node: %s kb\n" % total_mem )
+            log.write( "Required memory: %s kb\n" % MINIMUM_MEMORY )
+
+            include_pis= 0
+            include_techs= 1
+            include_support= 0
+            
+            sent= 0
+            try:
+                sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
+                                         (notify_messages.MSG_INSUFFICIENT_MEMORY,
+                                          include_pis,
+                                          include_techs,
+                                          include_support) )
+            except BootManagerException, e:
+                log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
+                
+            if sent == 0:
+                log.write( "Unable to notify site contacts of problem.\n" )
+            else:
+                log.write( "Notified contacts of problem.\n" )
+                
+            return 0
+        else:
+            log.write( "Memory requirements not met, but running anyway: %s kb\n"
+                       % total_mem )
+    else:
+        log.write( "Looks like we have enough memory: %s kb\n" % total_mem )
+
+
+
+    # get a list of block devices to attempt to install on
+    # (may include cdrom devices)
+    install_devices= sysinfo.get_block_device_list()
+
+    # save the list of block devices in the log
+    log.write( "Detected block devices:\n" )
+    log.write( repr(install_devices) + "\n" )
+
+    if not install_devices or len(install_devices) == 0:
+        log.write( "No block devices detected.\n" )
+        
+        include_pis= 0
+        include_techs= 1
+        include_support= 0
+        
+        sent= 0
+        try:
+            sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
+                                       (notify_messages.MSG_INSUFFICIENT_DISK,
+                                        include_pis,
+                                        include_techs,
+                                        include_support) )
+        except BootManagerException, e:
+            log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
+            
+        if sent == 0:
+            log.write( "Unable to notify site contacts of problem.\n" )
+
+        return 0
+
+    # now, lets remove any block devices we know won't work (readonly,cdroms),
+    # or could be other writable removable disks (usb keychains, zip disks, etc)
+    # i'm not aware of anything that helps with the latter test, so,
+    # what we'll probably do is simply not use any block device below
+    # some size threshold (set in installstore)
+
+    # also, keep track of the total size for all devices that appear usable
+    total_size= 0
+
+    for device in install_devices.keys():
+
+        (major,minor,blocks,gb_size,readonly)= install_devices[device]
+        
+        # if the device string starts with
+        # planetlab, ignore it (could be old lvm setup)
+        if device[:14] == "/dev/planetlab":
+            del install_devices[device]
+            continue
+
+        if gb_size < MINIMUM_DISK_SIZE:
+            log.write( "Device is too small to use: %s \n(appears" \
+                           " to be %4.2f GB)\n" % (device,gb_size) )
+            try:
+                del install_devices[device]
+            except KeyError, e:
+                pass
+            continue
+
+        if readonly:
+            log.write( "Device is readonly, not using: %s\n" % device )
+            try:
+                del install_devices[device]
+            except KeyError, e:
+                pass
+            continue
+            
+        # add this sector count to the total count of usable
+        # sectors we've found.
+        total_size= total_size + gb_size
+
+
+    if len(install_devices) == 0:
+        log.write( "No suitable block devices found for install.\n" )
+
+        include_pis= 0
+        include_techs= 1
+        include_support= 0
+        
+        sent= 0
+        try:
+            sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
+                                       (notify_messages.MSG_INSUFFICIENT_DISK,
+                                        include_pis,
+                                        include_techs,
+                                        include_support) )
+        except BootManagerException, e:
+            log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
+            
+        if sent == 0:
+            log.write( "Unable to notify site contacts of problem.\n" )
+
+        return 0
+
+
+    # show the devices we found that are usable
+    log.write( "Usable block devices:\n" )
+    log.write( repr(install_devices.keys()) + "\n" )
+
+    # save the list of devices for the following steps
+    vars["INSTALL_BLOCK_DEVICES"]= install_devices.keys()
+
+
+    # ensure the total disk size is large enough. if
+    # not, we need to email the tech contacts the problem, and
+    # put the node into debug mode.
+    if total_size < TOTAL_MINIMUM_DISK_SIZE:
+        if not SKIP_HARDWARE_REQUIREMENT_CHECK:
+            log.write( "The total usable disk size of all disks is " \
+                       "insufficient to be usable as a PlanetLab node.\n" )
+            include_pis= 0
+            include_techs= 1
+            include_support= 0
+            
+            sent= 0
+            try:
+                sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
+                                            (notify_messages.MSG_INSUFFICIENT_DISK,
+                                             include_pis,
+                                             include_techs,
+                                             include_support) )
+            except BootManagerException, e:
+                log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
+            
+            if sent == 0:
+                log.write( "Unable to notify site contacts of problem.\n" )
+
+            return 0
+        
+        else:
+            log.write( "The total usable disk size of all disks is " \
+                       "insufficient, but running anyway.\n" )
+            
+    log.write( "Total size for all usable block devices: %4.2f GB\n" % total_size )
+
+    # turn off UDMA for all block devices on 2.x cds (2.4 kernel)
+    if BOOT_CD_VERSION[0] == 2:
+        for device in install_devices:
+            log.write( "Disabling UDMA on %s\n" % device )
+            utils.sysexec_noerr( "/sbin/hdparm -d0 %s" % device, log )
+
+    return 1