Beispiel #1
0
def adjustCommandsToParted(commands):
    """
    Adjusts commands to use 'parted' tool expected inputs.

    @type  commands: list
    @param commands: Conventional Disk operations to be performed

    @rtype: list
    @returns: disk operations using parted command expected input
    """
    # report operation
    llecho('Adjusting conventional disk operations to be used by parted command')

    # update commands
    for command in commands:

        # update disk name to use full path
        if command['mpath_master'] is not None:
            command['disk_name'] = MPATH_PATH % command
        else:
            command['disk_name'] = DEVICE_PATH % command

        # command has partition type: update it
        if 'type' in command:
            command['type'] = TYPE[command['type']]
Beispiel #2
0
def stop():
    """
    Stops all RAID arrays so that all resources (partitions) are released and
    disks partitioning can be done

    FIXME: There is a know bug (73870) that happens when installing an
    automatic partitioning scheme after a previous RAID parition in multiple
    disks. It was added a loop with a sleep trying to stop until 10 times if
    it fails. A better solution should be investigated here.

    @rtype: None
    @returns: nothing
    """
    # report operation
    llecho('Stopping all RAID arrays')

    # stop the raid device
    status = 0

    for i in range(0, 10):
        # run the command to stop raid
        status = run(CMD_STOP_MDADM)

        # raid stopped successfully: quit
        if status == 0:
            break

        # wait 1 second before another try
        time.sleep(1)

    # problems to stop raid: exit -1
    if status != 0:
        llecho('Error: cannot stop RAID arrays')
        raise PKVMError('PARTITIONER', 'RAID', 'STOP_SWRAID')
Beispiel #3
0
def start():
    """
    Activate all existing RAID arrays so that RAID operations can be performed

    @rtype: None
    @returns: nothing
    """
    # report operation
    llecho('Activating all existing RAID arrays')

    # failed creating the array: exit
    status = run(CMD_START_MDADM)

    if status != 0 and status != 1:
        llecho('Error: cannot activate RAID arrays')
        sys.exit(1)
Beispiel #4
0
def deleteArrays(commands):
    """
    Processes RAID operations as specified by the passed list of commands and
    performs the ones which delete RAID arrays

    @type  commands: list
    @param commands: list of commands to be processed

    @rtype: None
    @returns: nothing
    """
    # report operation
    llecho('Deleting RAID arrays')

    # delete raid arrays
    for cmd in commands:
        if cmd['command'] == 'delete:raid':
            _delete(cmd)
Beispiel #5
0
def _fixDiskLabel(device):
    """
    Fixes disk label so it can be properly partitioned afterwards.

    @type  device: basestring
    @param device: passed device (e.g. '/dev/sda', '/dev/sdb', ...)

    @rtype: None
    @returns: Nothing
    """
    # disk label could not be fixed: report error
    status = run(CMD_FIX_DISK_LABEL % {'disk': device})

    if status != 0:
        llecho(ERROR_FIX % device)
        sys.exit(1)

    # partition table was reset: report operation
    llecho('Partition table for %s was reset' % device)
Beispiel #6
0
def loadCommands(path):
    """
    Loads from the pickle file at the passed path conventional disk operations to be
    performed

    @type  path: basestring
    @param path: path of the pickle file to be loaded

    @rtype: dict
    @returns: Conventional Disk operations to be performed
    """
    # report operation
    llecho('Loading Conventional disk operations to be performed')

    # cannot locate list of commands to be processed: report and exit
    if os.path.exists(path) == False:
        llecho('Error: cannot locate list of operations to be done')
        sys.exit(1)

    # load the list of commands
    try:
        stream = open(path)
        commands = cPickle.load(stream)
        stream.close()

    # loading error: report and exit
    except (EnvironmentError, cPickle.PickleError):
        llecho('Error: cannot load list of operations to be done')
        sys.exit(1)

    # adjust commands to be used by parted
    adjustCommandsToParted(commands)

    # return loaded commands
    return commands
Beispiel #7
0
def loadCommands(path):
    """
    Loads from the pickle file at the passed path RAID operations to be
    performed

    @type  path: basestring
    @param path: path of the pickle file to be loaded

    @rtype: dict
    @returns: RAID operations to be performed
    """
    # report operation
    llecho('Loading RAID operations to be performed')

    # cannot locate list of commands to be processed: report and exit
    if os.path.exists(path) == False:
        llecho('Error: cannot locate list of operations to be done')
        sys.exit(1)

    # load the list of commands
    try:
        stream = open(path)
        commands = cPickle.load(stream)
        stream.close()

    # loading error: report and exit
    except:
        llecho('Error: cannot load list of operations to be done')
        sys.exit(1)

    return commands
Beispiel #8
0
def _setPartType(device):
    """
    Sets the partition type of the passed device as linux_raid_auto

    @type  devices: basestring
    @param devices: device whose partition type is to be set

    @rtype: None
    @returns: nothing
    """
    # report the operation
    llecho('Setting the partition type of %s as linux_raid_auto' % device)

    # not a valid device name: error
    match = PATTERN_PART.match(device)

    if match == None:
        llecho('Error: cannot parse %s into a device name '
              'and partition number' % device)
        sys.exit(1)

    # get device name and partition number
    info = match.groupdict()

    # cannot set partition type: error
    status = run(CMD_SET_PART_TYPE % info)

    if status != 0:
        llecho('Error: cannot set the partition type of '
              '/dev/%(device)s Id %(number)s' % info)
        sys.exit(1)
Beispiel #9
0
def _delete(cmd):
    """
    Deletes a RAID array as specified in the passed command

    @type  cmd: dict
    @param cmd: command to be performed

    @rtype: None
    @returns: nothing
    """
    # report the operation
    llecho('Deleting RAID array /dev/%(name)s' % cmd)

    # umount the raid partition
    run(CMD_UMOUNT_RAID % cmd)

    # failed stopping the array: report and exit
    status = run(CMD_STOP_RAID % cmd)

    if status != 0:
        llecho('Error: cannot stop the array')
        sys.exit(1)

    # failed zeroing the superblock of the raid devices: report and exit
    status = run(CMD_ZERO_RAID % {
        'devices': ' '.join(['/dev/%s' % d for d in cmd['devices']]),
    })

    if status != 0:
        llecho('Error: cannot zero the superblocks of the RAID devices')
        sys.exit(1)
Beispiel #10
0
def _runPartedCommand(partedCommand, disk, errorMessage, hasMultipath=False, tolerant=False):
    """
    Runs a parted command and re-read disk partition table.

    @type  partedCommand: basestring
    @param partedCommand: parted command to run

    @type  disk: basestring
    @param disk: disk path

    @type  errorMessage: basestring
    @param errorMessage: error message to user in case of a failure

    @type  hasMultipath: bool
    @param hasMultipath: flag that informs if system has multipath

    @type  tolerant: bool
    @param tolerant: True to not exit if error found, False otherwise

    @rtype: None
    @returns: nothing
    """
    # runs command
    (status, output) = getstatusoutput(partedCommand)

    # log command line
    llecho("Running: %s" % partedCommand)

    # log exit status and output
    llecho("Status: %d" % status)
    llecho("Output:\n%s\n" % output)

    if hasMultipath:
        return

    # FIXME: use a safer check here, i.e., a regular expression to match the
    # desired output.
    # partition table needs to be re-read: do it
    if 're-read' in output:

        # partition table was successfully re-read: change status accordingly
        if _reReadPartitionTable(disk, hasMultipath):
            status = 0

    # command failed: log and exit
    if status != 0:
        llecho(errorMessage)
        if not tolerant:
            sys.exit(1)
Beispiel #11
0
def deletePartitions(diskCommands, hasMultipath, tolerant=False):
    """
    Deletes all partitions.

    @type  diskCommands: dict
    @param diskCommands: abstract commands for conventional disks

    @type  hasMultipath: bool
    @param hasMultipath: info about multipath on machine

    @type  tolerant: bool
    @param tolerant: True to not exit if error found, False otherwise

    @rtype: None
    @returns: Nothing
    """
    # report the operation
    llecho('Deleting Partitions')

    # reverse order the list of deletion commands. this is necessary because
    # the parted tool reorder the logical partitions when they are removed in
    # order. for example, if you remove logical partition 5, 6 will become 5, 7
    # will become 6 and so on.
    deleteCommands = _reverseOrderDeleteCommands(diskCommands)

    # delete partitions
    for cmd in deleteCommands:

        # report operation and run it
        llecho('Deleting partition /dev/%(name)s' % cmd)

        # get parameters to delete partition
        partedCommand = CMD_DELETE_PARTITION % cmd
        disk = cmd['disk_name']
        errorMessage = ERROR_DELETE  % cmd

        # delete partition
        _runPartedCommand(partedCommand, disk, errorMessage, hasMultipath, tolerant)
Beispiel #12
0
def _reReadPartitionTable(disk, hasMultipath = False):
    """
    Asks the kernel to re-read the partition table before trying
    to format it

    @type  disk: basestring
    @param disk: disk device name

    @type  hasMultipath: bool
    @param hasMultipath: info about multipath on machine

    @rtype: bool
    @return: True if partition table sync successfull. False otherwise
    """
    # give some opportunities to sync the partition table before
    # returning false
    for i in range(1, MAX_SYNC_ATTEMPTS):

        # log the number of attempts
        llecho('Re-reading partition table for %s (try %d)' % (disk, i))

        # wait 1 second
        time.sleep(1)

        # FIXME: during the attempt to read the partitions, raid should
        # be inactive or it will block devices belonging to its array
        # and will make the next command to fail. It is not clear why
        # raid becomes active here since is has been stopped in
        # manage_parts. It demands further investigation.
        if hasMultipath:
            raid.stop()

        # partition table re-read successfully: return success
        if run(CMD_HDPARM_Z % disk) == 0:
            return True

    return False
Beispiel #13
0
def createPartitions(diskCommands, hasMultipath, sector_size):
    """
    Creates all partitions.

    @type  diskCommands: dict
    @param diskCommands: abstract commands for conventional disks

    @type  hasMultipath: bool
    @param hasMultipath: info about multipath on machine

    @rtype: None
    @returns: Nothing
    """
    # report the operation
    llecho('Creating Partitions')

    # create partitions
    for cmd in diskCommands:

        # command is not create: do nothing
        if cmd['command'] != 'create:partition':
            continue

        # remove any possible LVM garbage from the PVs partition
        llecho('Clear partitions before creating')
        run('dd if=/dev/zero of=%s bs=%d seek=%s count=2048' % (cmd['disk_name'], sector_size, cmd['start']))

        # command is create: report operation and run it
        llecho('Creating partition /dev/%(name)s' % cmd)

        # get parameters to create partition
        cmd['type'] = TYPE[cmd['type']]
        partedCommand = CMD_CREATE_PARTITION % cmd
        disk = cmd['disk_name']
        errorMessage = ERROR_CREATE % cmd

        # create partition
        _runPartedCommand(partedCommand, disk, errorMessage, hasMultipath)

        # partition is PReP: set as bootable
        if cmd['fs'] == 'prep':
            _setFlag(cmd, 'boot', hasMultipath)

        # partition is PReP, RAID or LVM: set respective flag
        if cmd['fs'] in ['prep', 'raid', 'lvm']:
            _setFlag(cmd, cmd['fs'], hasMultipath)

        if cmd['fs'] == 'extended':
            continue
Beispiel #14
0
def _create(cmd):
    """
    Creates a RAID array as specified in the passed command

    @type  cmd: dict
    @param cmd: command to be performed

    @rtype: None
    @returns: nothing
    """
    # report the operation
    llecho('Creating RAID level %(level)d array /dev/%(name)s from %(devices)s' % cmd)

    # FIXME: stop raid before any attempt to create an array to assure
    # that there will not be any blocked device causing error
    stop()

    # build command line to be used to create the array
    cmdLine = CMD_CREATE_RAID[cmd['level']] % {
        'name': cmd['name'],
        'level': cmd['level'],
        'chunkSize': cmd['chunkSize'],
        'nDevices': len(cmd['devices']) - cmd['spares'],
        'nSpares': cmd['spares'],
        'devices': ' '.join(['/dev/%s' % d for d in cmd['devices']]),
        'metadata': cmd['metadata'],
    }

    # failed creating the array: exit
    status = run(cmdLine)

    if status != 0:
        llecho('Error: cannot create the array')
        sys.exit(1)

    # FIXME: start raid again after the command was performed
    # successfully
    start()

    # set the partition type of each device as FD
    for device in cmd['devices']:
        _setPartType(device)

    # reiserfs type not chosen on a RAID 0: make a filesystem on this array
    if cmd['fileSystem'] not in ['reiserfs', 'swap']:
        llecho('Creating filesystem of type %(fileSystem)s on /dev/%(name)s - RAID %(level)d' % cmd)
        run('mkfs\.%(fileSystem)s /dev/%(name)s' % cmd)
Beispiel #15
0
def wait(commands):
    """
    Processes RAID operations as specified by the passed list of commands and
    waits for the RAID arrays set to be created and reused to become clean. An
    array is not clean when, for example, it has just been created and its
    spares are synching.

    @type  commands: list
    @param commands: list of commands to be processed

    @rtype: None
    @returns: nothing
    """
    # report operation
    llecho('Waiting for RAID arrays to become clean')

    # get RAID arrays to be monitored
    mds = []

    for cmd in commands:

        # created or reused array: monitor it
        if cmd['command'] in ('create:raid', 'use:raid'):

            # level 0 array: no need to monitor
            if cmd['level'] != 0:
                mds.append(cmd['name'])

    # show arrays
    llecho('Arrays: %s' % mds)

    # open file objects for each array
    files = {}

    for md in mds:
        files[md] = _openFiles(md)

    # get descriptors for the files to be monitored
    mdsByFd = {}
    status = {}
    names = {}

    for md, fobjs in files.iteritems():
        fd = fobjs['completed']
        mdsByFd[fd] = fobjs
        status[fd] = {}
        names[fd] = md

    fds = mdsByFd.keys()

    # monitor arrays until all are clean
    while True:
        r = _poll(fds, interval = 0.5, timeout = 1.0)

        # read files for the mds with data available
        for fd in r:
            _readFiles(mdsByFd[fd], status[fd])

            # md finished sync: stop monitoring it
            if status[fd]['recovery'] == 'idle':
                llecho('Array /dev/%s is clean' % names[fd])
                fds.remove(fd)

        # no more mds to be monitored: done
        if len(fds) == 0:
            break