Error creating new logical drive; hw_raid_cli.py exited with 3.

315 views
Skip to first unread message

Allen Underdown

unread,
May 7, 2018, 8:30:07 PM5/7/18
to esos-users
Hardware - Dell 2950 Bios 2.7.0 PERC 5i  -

This is the initial install ESOS 1.3.6

looked in /var/log - messages (empty), dmseg doesn't show anything, nor does syslog.

The wiki is a bit confusing about which hardware raid I should be using.  Currently using perccli64 - is this correct for this version?

Attached is support bundle log.

I'm sure it's something simple I missed.

Allen
esos_support_pkg-1525738918.tgz

Marc Smith

unread,
May 8, 2018, 9:38:18 AM5/8/18
to esos-...@googlegroups.com
On Mon, May 7, 2018 at 8:30 PM, Allen Underdown
<aunde...@star2star.com> wrote:
> Hardware - Dell 2950 Bios 2.7.0 PERC 5i -
>
> This is the initial install ESOS 1.3.6
>
> looked in /var/log - messages (empty), dmseg doesn't show anything, nor does
> syslog.
>
> The wiki is a bit confusing about which hardware raid I should be using.
> Currently using perccli64 - is this correct for this version?

Agreed... its not clear to us either exactly which PERC adapters
perccli64 should be used with. Before there was ever perccli64 (from
Dell) we had always used MegaCli64 for PERC adapters.


>
> Attached is support bundle log.
>
> I'm sure it's something simple I missed.

Maybe run the perccli64 command at the shell with your same desired
volume-creation parameters and let's see what the error message is.
The TUI only catches the exit status, so not all that helpful when the
command fails.

--Marc


>
> Allen
>
> --
> You received this message because you are subscribed to the Google Groups
> "esos-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to esos-users+...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Allen Underdown

unread,
May 8, 2018, 5:33:06 PM5/8/18
to esos-users


On Tuesday, May 8, 2018 at 8:38:18 AM UTC-5, marc.smith wrote:
On Mon, May 7, 2018 at 8:30 PM, Allen Underdown
<aunde...@star2star.com> wrote:
> Hardware - Dell 2950 Bios 2.7.0 PERC 5i  -
>
> This is the initial install ESOS 1.3.6
>
> looked in /var/log - messages (empty), dmseg doesn't show anything, nor does
> syslog.
>
> The wiki is a bit confusing about which hardware raid I should be using.
> Currently using perccli64 - is this correct for this version?

Agreed... its not clear to us either exactly which PERC adapters
perccli64 should be used with. Before there was ever perccli64 (from
Dell) we had always used MegaCli64 for PERC adapters.

That's what I was expecting - I didn't even know that there was a separate perc driver/cli.  I always used (the incredibly cryptic) MegaCLI.  




Maybe run the perccli64 command at the shell with your same desired
volume-creation parameters and let's see what the error message is.
The TUI only catches the exit status, so not all that helpful when the
command fails.

That assumes that I can get a good cli command to work. Below is what I have tried.  I have also tried loading the StorCLI and the old MegaCLI, Neither detects my controller.
I did find that there is a (much) newer perccli out.  I just downloaded it, but the installer failed to find it and install it.  

This seems strange since the install.sh script only looks for perccli -
elif [ "${i}" = "perccli" ]; then
            tar xvfz ${PKG_DIR}/perccli-*.tar.gz && \
            ${rpm2cpio} perccli-*.noarch.rpm | cpio -idmv && \

If I'm reading the script above it correctly - 

# Mount it and inject all (if any) of the tools
    if [ "${this_os}" = "${LINUX}" ]; then
        if [ -f "/etc/esos-release" ]; then
            MNT_DIR=""
        else
            mount ${esos_conf} ${MNT_DIR} || exit 1
            mkdir -p ${MNT_DIR}/opt/{sbin,lib} || exit 1
        fi
I should be able to on esos_conf do a mkdir /opt/sbin and mkdir /opt/lib and copy the *newer* perccli64 to the flash drive?  /opt/sbin?

Here are the commands that I've tried to get a VD built:

[root@localhost sbin]# perccli64 /c0 add vd r5 Size=all name=Raid5 drives=8:0-5 Strip=64
Controller = 0
Status = Failure
Description = invalid arguments , Invalid parameter

[root@localhost sbin]# perccli64 /c0 add vd r5 Size=all name=Raid5 drives=8:0 8:1 8:2 8:3 8:4 8:5  Strip=1024
syntax error, unexpected TOKEN_NUMBER, expecting $end

perccli64 /c0 add vd r5 Size=all name=Raid5 drives=8:0 8:1 8:2 8:3 8:4 8:5 Strip=1024
syntax error, unexpected TOKEN_NUMBER, expecting $end

[root@localhost sbin]# perccli64 /c0 add vd r5 Size=all name=Raid5 drives=8:0,8:1,8:2,8:3,8:4,8:5 Strip=1024
Adapter Doesn't support the given Strip size
Controller = 0
Status = Failure
Description = None

[root@localhost sbin]# perccli64 /c0 add vd r5 Size=all name=Raid5 drives=8:0,8:1,8:2,8:3,8:4,8:5 Strip=256
Adapter Doesn't support the given Strip size
Controller = 0
Status = Failure
Description = None

[root@localhost sbin]# perccli64 /c0 add vd r5 Size=all name=Raid5 drives=8:0,8:1,8:2,8:3,8:4,8:5 Strip=128
Controller = 0
Status = Failure
Description = invalid arguments , Invalid parameter

[root@localhost sbin]# perccli64 /c0 add vd r5 Size=all name=Raid5 drives=8:0,8:1,8:2,8:3,8:4,8:5
Controller = 0
Status = Failure
Description = invalid arguments , Invalid parameter

[root@localhost sbin]# perccli64 /c0 add vd r5 Size=all name=Raid5 drives=8:0,8:1,8:2,8:3,8:4,8:5 pdcache=default
Controller = 0
Status = Failure
Description = invalid arguments , Invalid parameter

[root@localhost sbin]# perccli64 /c0 add vd r5 Size=all name=Raid5 drives=8:0,8:1,8:2,8:3,8:4,8:5 PDperArray=6 pdcache=default
Controller = 0
Status = Failure
Description = invalid arguments , Invalid parameter

[root@localhost sbin]# perccli64 /c0 add vd r5 Size=all name=Raid5 drives=8:0,8:1,8:2,8:3,8:4,8:5 PDperArray=6
Controller = 0
Status = Failure
Description = invalid arguments , Invalid parameter

[root@localhost sbin]# perccli64 /c0 add vd r5 Size=all name=Raid5 drives=8:0,8:1,8:2,8:3,8:4,8:5 pdcache=default dimmerswitch=none wb ra direct strip=64
Controller = 0
Status = Failure
Description = invalid arguments , Invalid parameter

Allen Underdown

unread,
May 8, 2018, 8:45:01 PM5/8/18
to esos-users
Now this is interesting too:

 login as: root
ro...@10.1.1.120's password:
Access denied
ro...@10.1.1.120's password:
[root@daffy ~]# ls
dead.letter
[root@daffy ~]# cd /
[root@daffy /]# ls
bin      etc      lib64    opt      run      tmp
boot     home     linuxrc  proc     sbin     usr
dev      lib      mnt      root     sys      var
[root@daffy /]# cd usr
[root@daffy usr]# ls
bin      include  lib      lib64    libexec  local    sbin     share
[root@daffy usr]# cd local
[root@daffy local]# ls
bin         perf-agent  sbin        share
[root@daffy local]# cd sbin
[root@daffy sbin]# ls
archive_logs.sh  health_chk.sh    startup.sh       usb_sync.sh
conf_sync.sh     hw_raid_cli.py   support_pkg.sh
[root@daffy sbin]# cat hw_raid_cli.py|more
#! /usr/bin/python2.7

# A simple Python wrapper script for the propietary CLI RAID tools. The purpose
# of this script is abstract the provisioning of hardware RAID, so we can use
# the same command syntax for creating logical drives, hot spares, etc.

from optparse import OptionParser, OptionGroup
import os
import subprocess
import sys


# Common stuff
STORCLI_BIN = '/opt/sbin/storcli64'
PERCCLI_BIN = '/opt/sbin/perccli64'
ARCCONF_BIN = '/opt/sbin/arcconf'
CTRLR_TYPES = ['MegaRAID', 'PERC', 'AACRAID']


class MegaRAID():
    def __init__(self):
        self.working = self.__is_tool_avail()

    def __is_tool_avail(self):
        # File has to exist and be executable
        return os.path.isfile(STORCLI_BIN) and os.access(STORCLI_BIN, os.X_OK)

    def __get_ctrlr_cnt(self):
        # No controllers exist if the tool isn't available
        if not self.__is_tool_avail():
            return 0
        # Get the number of controllers
        command = STORCLI_BIN + ' show ctrlcount 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit == 0:
            for line in iter(stdout.splitlines()):
                if 'Controller Count =' in line:
                    count = line.split('=')[1]
                    return int(count)

    def list_ctrlrs(self, id_num=-1):
        # Either for all, or a specific controller
        if id_num == -1:
            last_id = self.__get_ctrlr_cnt()
            first_id = 0
        else:
            last_id = id_num + 1
            first_id = id_num
        # Get the controller information and print it
        for each in range(first_id, last_id):
            command = STORCLI_BIN + ' /c' + str(each) + ' show 2>&1'
            process = subprocess.Popen(command, stdout=subprocess.PIPE,
                                       shell=True)
            stdout, stderr = process.communicate()
            cmd_exit = process.returncode
            if cmd_exit == 0:
                model = serial = ''
                for line in iter(stdout.splitlines()):
                    if 'Product Name =' in line:
                        model = line.split('=')[1].strip()
                    elif 'Serial Number =' in line:
                        serial = line.split('=')[1].strip()
                print 'MegaRAID,%s,%s,%s' % (each, model, serial)

    def list_phy_drives(self, id_num=-1, avail_only=False):
        # Either for all, or a specific controller
        if id_num == -1:
            last_id = self.__get_ctrlr_cnt()
            first_id = 0
        else:
            last_id = id_num + 1
            first_id = id_num
        # Get the physical drives and print them
        for each in range(first_id, last_id):
            command = STORCLI_BIN + ' /c' + str(each) + '/eall/sall show 2>&1'
            process = subprocess.Popen(command, stdout=subprocess.PIPE,
                                       shell=True)
            stdout, stderr = process.communicate()
            cmd_exit = process.returncode
            if cmd_exit == 0:
                dash_line_cnt = 0
                encl_id = slot_num = state = size = model = ''
                for line in iter(stdout.splitlines()):
                    if '----------' in line:
                        dash_line_cnt += 1
                        continue
                    if dash_line_cnt == 2:
                        # Each line is physical drive
                        p_drive_info = line.split()
                        if avail_only:
                            if p_drive_info[3] != '-':
                                continue
                        encl_slot = p_drive_info[0].split(':')
                        encl_id = encl_slot[0]
                        slot_num = encl_slot[1]
                        state = p_drive_info[2]
                        size = p_drive_info[4] + ' ' + p_drive_info[5]
                        model = p_drive_info[11]
                        print 'MegaRAID,%s,%s,%s,%s,%s,%s' % (each, encl_id,
                                                              slot_num, state,
                                                              size, model)

    def list_log_drives(self, id_num=-1):
        # Either for all, or a specific controller
        if id_num == -1:
            last_id = self.__get_ctrlr_cnt()
            first_id = 0
        else:
            last_id = id_num + 1
            first_id = id_num
        # Get the logical drives and print them
        for each in range(first_id, last_id):
            command = STORCLI_BIN + ' /c' + str(each) + '/vall show 2>&1'
            process = subprocess.Popen(command, stdout=subprocess.PIPE,
                                       shell=True)
            stdout, stderr = process.communicate()
            cmd_exit = process.returncode
            if cmd_exit == 0:
                dash_line_cnt = 0
                ld_id = raid_lvl = state = size = name = ''
                for line in iter(stdout.splitlines()):
                    if '----------' in line:
                        dash_line_cnt += 1
                        continue
                    if dash_line_cnt == 2:
                        # Each line is logical drive drive
                        l_drive_info = line.split()
                        dg_vd = l_drive_info[0].split('/')
                        ld_id = dg_vd[1]
                        raid_lvl = l_drive_info[1]
                        state = l_drive_info[2]
                        size = l_drive_info[7] + ' ' + l_drive_info[8]
                        if len(l_drive_info) == 10:
                            name = l_drive_info[9]
                        print 'MegaRAID,%s,%s,%s,%s,%s,%s' % (each, ld_id,
                                                              raid_lvl, state,
[root@daffy sbin]# ls
archive_logs.sh  health_chk.sh    startup.sh       usb_sync.sh
conf_sync.sh     hw_raid_cli.py   support_pkg.sh
[root@daffy sbin]# ./hw_raid_cli.py
Usage: hw_raid_cli.py [options]

hw_raid_cli.py: error: you must specify one command option
[root@daffy sbin]# ./hw_raid_cli.py perccli
Usage: hw_raid_cli.py [options]

hw_raid_cli.py: error: you must specify one command option
[root@daffy sbin]# cat hw_raid_cli.py|more
#! /usr/bin/python2.7

# A simple Python wrapper script for the propietary CLI RAID tools. The purpose
# of this script is abstract the provisioning of hardware RAID, so we can use
# the same command syntax for creating logical drives, hot spares, etc.

from optparse import OptionParser, OptionGroup
import os
import subprocess
import sys


# Common stuff
STORCLI_BIN = '/opt/sbin/storcli64'
PERCCLI_BIN = '/opt/sbin/perccli64'
ARCCONF_BIN = '/opt/sbin/arcconf'
CTRLR_TYPES = ['MegaRAID', 'PERC', 'AACRAID']


class MegaRAID():
    def __init__(self):
        self.working = self.__is_tool_avail()

    def __is_tool_avail(self):
        # File has to exist and be executable
        return os.path.isfile(STORCLI_BIN) and os.access(STORCLI_BIN, os.X_OK)

    def __get_ctrlr_cnt(self):
        # No controllers exist if the tool isn't available
        if not self.__is_tool_avail():
            return 0
        # Get the number of controllers
        command = STORCLI_BIN + ' show ctrlcount 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit == 0:
            for line in iter(stdout.splitlines()):
                if 'Controller Count =' in line:
                    count = line.split('=')[1]
                    return int(count)

    def list_ctrlrs(self, id_num=-1):
        # Either for all, or a specific controller
        if id_num == -1:
            last_id = self.__get_ctrlr_cnt()
            first_id = 0
        else:
            last_id = id_num + 1
            first_id = id_num
        # Get the controller information and print it
        for each in range(first_id, last_id):
            command = STORCLI_BIN + ' /c' + str(each) + ' show 2>&1'
            process = subprocess.Popen(command, stdout=subprocess.PIPE,
                                       shell=True)
            stdout, stderr = process.communicate()
            cmd_exit = process.returncode
            if cmd_exit == 0:
                model = serial = ''
                for line in iter(stdout.splitlines()):
                    if 'Product Name =' in line:
                        model = line.split('=')[1].strip()
                    elif 'Serial Number =' in line:
                        serial = line.split('=')[1].strip()
                print 'MegaRAID,%s,%s,%s' % (each, model, serial)

    def list_phy_drives(self, id_num=-1, avail_only=False):
        # Either for all, or a specific controller
        if id_num == -1:
            last_id = self.__get_ctrlr_cnt()
            first_id = 0
        else:
            last_id = id_num + 1
            first_id = id_num
        # Get the physical drives and print them
        for each in range(first_id, last_id):
            command = STORCLI_BIN + ' /c' + str(each) + '/eall/sall show 2>&1'
            process = subprocess.Popen(command, stdout=subprocess.PIPE,
                                       shell=True)
            stdout, stderr = process.communicate()
            cmd_exit = process.returncode
            if cmd_exit == 0:
                dash_line_cnt = 0
                encl_id = slot_num = state = size = model = ''
                for line in iter(stdout.splitlines()):
                    if '----------' in line:
                        dash_line_cnt += 1
                        continue
                    if dash_line_cnt == 2:
                        # Each line is physical drive
                        p_drive_info = line.split()
                        if avail_only:
                            if p_drive_info[3] != '-':
                                continue
                        encl_slot = p_drive_info[0].split(':')
                        encl_id = encl_slot[0]
                        slot_num = encl_slot[1]
                        state = p_drive_info[2]
                        size = p_drive_info[4] + ' ' + p_drive_info[5]
                        model = p_drive_info[11]
                        print 'MegaRAID,%s,%s,%s,%s,%s,%s' % (each, encl_id,
                                                              slot_num, state,
                                                              size, model)

    def list_log_drives(self, id_num=-1):
        # Either for all, or a specific controller
        if id_num == -1:
            last_id = self.__get_ctrlr_cnt()
            first_id = 0
        else:
            last_id = id_num + 1
            first_id = id_num
        # Get the logical drives and print them
        for each in range(first_id, last_id):
            command = STORCLI_BIN + ' /c' + str(each) + '/vall show 2>&1'
            process = subprocess.Popen(command, stdout=subprocess.PIPE,
                                       shell=True)
            stdout, stderr = process.communicate()
            cmd_exit = process.returncode
            if cmd_exit == 0:
                dash_line_cnt = 0
                ld_id = raid_lvl = state = size = name = ''
                for line in iter(stdout.splitlines()):
                    if '----------' in line:
                        dash_line_cnt += 1
                        continue
                    if dash_line_cnt == 2:
                        # Each line is logical drive drive
                        l_drive_info = line.split()
                        dg_vd = l_drive_info[0].split('/')
                        ld_id = dg_vd[1]
                        raid_lvl = l_drive_info[1]
                        state = l_drive_info[2]
                        size = l_drive_info[7] + ' ' + l_drive_info[8]
                        if len(l_drive_info) == 10:
                            name = l_drive_info[9]
                        print 'MegaRAID,%s,%s,%s,%s,%s,%s' % (each, ld_id,
                                                              raid_lvl, state,
                                                              size, name)

    def add_log_drive(self, ctrlr_id, raid_lvl, phys_drives, read_cache,
                      write_cache):
        # All arguments are required, so build the command and execute it
        if read_cache:
            read_opt = "ra"
        else:
            read_opt = "nora"
        if write_cache:
            write_opt = "wb"
        else:
            write_opt = "wt"
        command = STORCLI_BIN + ' /c' + str(ctrlr_id) + ' add vd r' + \
                  raid_lvl + ' drives=' + phys_drives + ' ' + read_opt + \
                  ' ' + write_opt + ' 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit != 0:
            print stdout
            sys.exit(cmd_exit)

    def rem_log_drive(self, ctrlr_id, ld_id):
        # All arguments are required, so build the command and execute it
        command = STORCLI_BIN + ' /c' + str(ctrlr_id) + '/v' + \
                  str(ld_id) + ' del force 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit != 0:
            print stdout
            sys.exit(cmd_exit)

    def add_hsp_drive(self, ctrlr_id, encl_id, slot_num):
        # All arguments are required, so build the command and execute it
        command = STORCLI_BIN + ' /c' + str(ctrlr_id) + '/e' + \
                  str(encl_id) + '/s' + str(slot_num) + \
                  ' add hotsparedrive 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit != 0:
            print stdout
            sys.exit(cmd_exit)

    def rem_hsp_drive(self, ctrlr_id, encl_id, slot_num):
        # All arguments are required, so build the command and execute it
        command = STORCLI_BIN + ' /c' + str(ctrlr_id) + '/e' + \
                  str(encl_id) + '/s' + str(slot_num) + \
                  ' delete hotsparedrive 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit != 0:
            print stdout
            sys.exit(cmd_exit)


class PERC():
    def __init__(self):
        self.working = self.__is_tool_avail()

    def __is_tool_avail(self):
        # File has to exist and be executable
        return os.path.isfile(PERCCLI_BIN) and os.access(PERCCLI_BIN, os.X_OK)

    def __get_ctrlr_cnt(self):
        # No controllers exist if the tool isn't available
        if not self.__is_tool_avail():
            return 0
        # Get the number of controllers
        command = PERCCLI_BIN + ' show ctrlcount 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit == 0:
            for line in iter(stdout.splitlines()):
                if 'Controller Count =' in line:
                    count = line.split('=')[1]
                    return int(count)

    def list_ctrlrs(self, id_num=-1):
        # Either for all, or a specific controller
        if id_num == -1:
            last_id = self.__get_ctrlr_cnt()
            first_id = 0
        else:
            last_id = id_num + 1
            first_id = id_num
        # Get the controller information and print it
        for each in range(first_id, last_id):
            command = PERCCLI_BIN + ' /c' + str(each) + ' show 2>&1'
            process = subprocess.Popen(command, stdout=subprocess.PIPE,
                                       shell=True)
            stdout, stderr = process.communicate()
            cmd_exit = process.returncode
            if cmd_exit == 0:
                model = serial = ''
                for line in iter(stdout.splitlines()):
                    if 'Product Name =' in line:
                        model = line.split('=')[1].strip()
                    elif 'Serial Number =' in line:
                        serial = line.split('=')[1].strip()
                print 'PERC,%s,%s,%s' % (each, model, serial)

    def list_phy_drives(self, id_num=-1, avail_only=False):
        # Either for all, or a specific controller
        if id_num == -1:
            last_id = self.__get_ctrlr_cnt()
            first_id = 0
        else:
            last_id = id_num + 1
            first_id = id_num
        # Get the physical drives and print them
        for each in range(first_id, last_id):
            command = PERCCLI_BIN + ' /c' + str(each) + '/eall/sall show 2>&1'
            process = subprocess.Popen(command, stdout=subprocess.PIPE,
                                       shell=True)
            stdout, stderr = process.communicate()
            cmd_exit = process.returncode
            if cmd_exit == 0:
                dash_line_cnt = 0
                encl_id = slot_num = state = size = model = ''
                for line in iter(stdout.splitlines()):
                    if '----------' in line:
                        dash_line_cnt += 1
                        continue
                    if dash_line_cnt == 2:
                        # Each line is physical drive
                        p_drive_info = line.split()
                        if avail_only:
                            if p_drive_info[3] != '-':
                                continue
                        encl_slot = p_drive_info[0].split(':')
                        encl_id = encl_slot[0]
                        slot_num = encl_slot[1]
                        state = p_drive_info[2]
                        size = p_drive_info[4] + ' ' + p_drive_info[5]
                        model = p_drive_info[11]
                        print 'PERC,%s,%s,%s,%s,%s,%s' % (each, encl_id,
                                                          slot_num, state,
                                                          size, model)

    def list_log_drives(self, id_num=-1):
        # Either for all, or a specific controller
        if id_num == -1:
            last_id = self.__get_ctrlr_cnt()
            first_id = 0
        else:
            last_id = id_num + 1
            first_id = id_num
        # Get the logical drives and print them
        for each in range(first_id, last_id):
            command = PERCCLI_BIN + ' /c' + str(each) + '/vall show 2>&1'
            process = subprocess.Popen(command, stdout=subprocess.PIPE,
                                       shell=True)
            stdout, stderr = process.communicate()
            cmd_exit = process.returncode
            if cmd_exit == 0:
                dash_line_cnt = 0
                ld_id = raid_lvl = state = size = name = ''
                for line in iter(stdout.splitlines()):
                    if '----------' in line:
                        dash_line_cnt += 1
                        continue
                    if dash_line_cnt == 2:
                        # Each line is logical drive drive
                        l_drive_info = line.split()
                        dg_vd = l_drive_info[0].split('/')
                        ld_id = dg_vd[1]
                        raid_lvl = l_drive_info[1]
                        state = l_drive_info[2]
                        size = l_drive_info[7] + ' ' + l_drive_info[8]
                        if len(l_drive_info) == 10:
                            name = l_drive_info[9]
                        print 'PERC,%s,%s,%s,%s,%s,%s' % (each, ld_id,
                                                          raid_lvl, state,
                                                          size, name)

    def add_log_drive(self, ctrlr_id, raid_lvl, phys_drives, read_cache,
                      write_cache):
        # All arguments are required, so build the command and execute it
        if read_cache:
            read_opt = "ra"
        else:
            read_opt = "nora"
        if write_cache:
            write_opt = "wb"
        else:
            write_opt = "wt"
        command = PERCCLI_BIN + ' /c' + str(ctrlr_id) + ' add vd r' + \
                  raid_lvl + ' drives=' + phys_drives + ' ' + read_opt + \
                  ' ' + write_opt + ' 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit != 0:
            print stdout
            sys.exit(cmd_exit)

    def rem_log_drive(self, ctrlr_id, ld_id):
        # All arguments are required, so build the command and execute it
        command = PERCCLI_BIN + ' /c' + str(ctrlr_id) + '/v' + \
                  str(ld_id) + ' del force 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit != 0:
            print stdout
            sys.exit(cmd_exit)

    def add_hsp_drive(self, ctrlr_id, encl_id, slot_num):
        # All arguments are required, so build the command and execute it
        command = PERCCLI_BIN + ' /c' + str(ctrlr_id) + '/e' + \
                  str(encl_id) + '/s' + str(slot_num) + \
                  ' add hotsparedrive 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit != 0:
            print stdout
            sys.exit(cmd_exit)

    def rem_hsp_drive(self, ctrlr_id, encl_id, slot_num):
        # All arguments are required, so build the command and execute it
        command = PERCCLI_BIN + ' /c' + str(ctrlr_id) + '/e' + \
                  str(encl_id) + '/s' + str(slot_num) + \
                  ' delete hotsparedrive 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit != 0:
            print stdout
            sys.exit(cmd_exit)


class AACRAID():
    def __init__(self):
        self.working = self.__is_tool_avail()

    def __is_tool_avail(self):
        # File has to exist and be executable
        return os.path.isfile(ARCCONF_BIN) and os.access(ARCCONF_BIN, os.X_OK)

    def __get_ctrlr_cnt(self):
        # No controllers exist if the tool isn't available
        if not self.__is_tool_avail():
            return 0
        # Get the number of controllers
        command = ARCCONF_BIN + ' getversion 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit == 0:
            for line in iter(stdout.splitlines()):
                if 'Controllers found:' in line:
                    count = line.split(':')[1]
                    return int(count)

    def list_ctrlrs(self, id_num=-1):
        # Either for all, or a specific controller
        if id_num == -1:
            last_id = self.__get_ctrlr_cnt() + 1
            first_id = 1
        else:
            last_id = id_num + 1
            first_id = id_num
        # Get the controller information and print it
        for each in range(first_id, last_id):
            command = ARCCONF_BIN + ' getconfig ' + str(each) + ' ad 2>&1'
            process = subprocess.Popen(command, stdout=subprocess.PIPE,
                                       shell=True)
            stdout, stderr = process.communicate()
            cmd_exit = process.returncode
            if cmd_exit == 0:
                model = serial = ''
                for line in iter(stdout.splitlines()):
                    if 'Controller Model' in line:
                        model = line.split(':')[1].strip()
                    elif 'Controller Serial Number' in line:
                        serial = line.split(':')[1].strip()
                print 'AACRAID,%s,%s,%s' % (each, model, serial)

    def list_phy_drives(self, id_num=-1, avail_only=False):
        # Either for all, or a specific controller
        if id_num == -1:
            last_id = self.__get_ctrlr_cnt() + 1
            first_id = 1
        else:
            last_id = id_num + 1
            first_id = id_num
        # Get the physical drives and print them
        for each in range(first_id, last_id):
            command = ARCCONF_BIN + ' getconfig ' + str(each) + ' pd 2>&1'
            process = subprocess.Popen(command, stdout=subprocess.PIPE,
                                       shell=True)
            stdout, stderr = process.communicate()
            cmd_exit = process.returncode
            if cmd_exit == 0:
                found_drive = False
                encl_id = slot_num = state = size = model = ''
                pd_in_use = False
                for line in iter(stdout.splitlines()):
                    if 'Device is a Hard drive' in line:
                        found_drive = True
                        continue
                    if found_drive and '         State' in line:
                        state = line.split(':')[1].strip()
                        continue
                    if found_drive and 'Reported Channel,Device(T:L)' in line:
                        encl_slot = line.split(':')[2].strip()
                        encl_slot_2 = encl_slot.split('(')[0]
                        encl_id = encl_slot_2.split(',')[0]
                        slot_num = encl_slot_2.split(',')[1]
                        continue
                    if found_drive and 'Model' in line:
                        model = line.split(':')[1].strip()
                        continue
                    if found_drive and 'Used Size' in line:
                        if line.split(':')[1].strip() == '0 MB':
                            pd_in_use = False
                        else:
                            pd_in_use = True
                    if found_drive and 'Total Size' in line:
                        size = line.split(':')[1].strip()
                        # This is the last line to find, so we're done here
                        found_drive = False
                        if avail_only:
                            if pd_in_use:
                                continue
                        print 'AACRAID,%s,%s,%s,%s,%s,%s' % (each, encl_id,
                                                             slot_num, state,
                                                             size, model)

    def list_log_drives(self, id_num=-1, avail_only=False):
        # Either for all, or a specific controller
        if id_num == -1:
            last_id = self.__get_ctrlr_cnt() + 1
            first_id = 1
        else:
            last_id = id_num + 1
            first_id = id_num
        # Get the logical drives and print them
        for each in range(first_id, last_id):
            command = ARCCONF_BIN + ' getconfig ' + str(each) + ' ld 2>&1'
            process = subprocess.Popen(command, stdout=subprocess.PIPE,
                                       shell=True)
            stdout, stderr = process.communicate()
            cmd_exit = process.returncode
            if cmd_exit == 0:
                found_drive = False
                ld_id = raid_lvl = state = size = name = ''
                pd_in_use = False
                for line in iter(stdout.splitlines()):
                    if 'Logical device number' in line:
                        ld_id = line.split(' ')[3].strip()
                        found_drive = True
                        continue
                    if found_drive and 'Logical device name' in line:
                        name = line.split(':')[1].strip()
                        continue
                    if found_drive and 'RAID level' in line:
                        raid_lvl = 'RAID' + line.split(':')[1].strip()
                        continue
                    if found_drive and 'Status of logical device' in line:
                        state = line.split(':')[1].strip()
                        continue
                    if found_drive and '   Size' in line:
                        size = line.split(':')[1].strip()
                        # This is the last line to find, so we're done here
                        found_drive = False
                        print 'AACRAID,%s,%s,%s,%s,%s,%s' % (each, ld_id,
                                                             raid_lvl, state,
                                                             size, name)

    def add_log_drive(self, ctrlr_id, raid_lvl, phys_drives, read_cache,
                      write_cache):
        # All arguments are required, so build the command and execute it
        if read_cache:
            read_opt = "ron"
        else:
            read_opt = "roff"
        if write_cache:
            write_opt = "wb"
        else:
            write_opt = "wt"
        command = ARCCONF_BIN + ' create ' + str(ctrlr_id) + \
                  ' logicaldrive ' + read_opt + ' ' + write_opt + \
                  ' max ' + raid_lvl
        for each in phys_drives.split(','):
            encl_slot = each.split(':')
            command = command + ' ' + encl_slot[0] + ' ' + encl_slot[1]
        command = command + ' 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit != 0:
            print stdout
            sys.exit(cmd_exit)

    def rem_log_drive(self, ctrlr_id, ld_id):
        # All arguments are required, so build the command and execute it
        command = ARCCONF_BIN + ' delete ' + str(ctrlr_id) + \
                  ' logicaldrive ' + str(ld_id) + ' noprompt 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit != 0:
            print stdout
            sys.exit(cmd_exit)

    def add_hsp_drive(self, ctrlr_id, encl_id, slot_num):
        # All arguments are required, so build the command and execute it
        command = ARCCONF_BIN + ' setstate ' + str(ctrlr_id) + \
                  ' device ' + str(encl_id) + ' ' + str(slot_num) + \
                  ' hsp noprompt 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit != 0:
            print stdout
            sys.exit(cmd_exit)

    def rem_hsp_drive(self, ctrlr_id, encl_id, slot_num):
        # All arguments are required, so build the command and execute it
        command = ARCCONF_BIN + ' setstate ' + str(ctrlr_id) + \
                  ' device ' + str(encl_id) + ' ' + str(slot_num) + \
                  ' rdy noprompt 2>&1'
        process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        stdout, stderr = process.communicate()
        cmd_exit = process.returncode
        if cmd_exit != 0:
            print stdout
            sys.exit(cmd_exit)


def main():
    # Parse options
    parser = OptionParser(conflict_handler='error')
    command_group = OptionGroup(parser, 'Commands', 'Use only one command '
                                                    'option at a time; combine '
                                                    'with other options below.')
    command_group.add_option('--list-controllers', dest='list_controllers',
                             action='store_true',
                             help='list available RAID controllers')
    command_group.add_option('--list-physical-drives',
                             dest='list_physical_drives', action='store_true',
                             help='list all physical drives')
    command_group.add_option('--list-logical-drives',
                             dest='list_logical_drives', action='store_true',
                             help='list all logical drives')
    command_group.add_option('--add-logical-drive', dest='add_logical_drive',
                             action='store_true',
                             help='add a new logical drive')
    command_group.add_option('--rem-logical-drive', dest='rem_logical_drive',
                             action='store_true',
                             help='remove an existing logical drive')
    command_group.add_option('--add-hot-spare', dest='add_hot_spare',
                             action='store_true',
                             help='add a new global hot spare drive')
    command_group.add_option('--rem-hot-spare', dest='rem_hot_spare',
                             action='store_true',
                             help='remove an existing global hot spare drive')
    parser.add_option_group(command_group)

    common_group = OptionGroup(parser, 'Options Available for All Commands')
    common_group.add_option('--type', dest='type',
                            help='the RAID controller hardware type',
                            metavar='TYPE', type='choice', choices=CTRLR_TYPES)
    common_group.add_option('--ctrlr-id', dest='ctrlr_id',
                            help='the RAID controller ID',
                            metavar='ID_NUM', type='int')
    parser.add_option_group(common_group)

    pdrives_group = OptionGroup(parser, 'Specific Options for the '
                                        '"--list-physical-drives" Command')
    pdrives_group.add_option('--avail-only', dest='avail_only',
                             action='store_true',
                             help='only display available/unused '
                                  'physical drives')
    parser.add_option_group(pdrives_group)

    add_ld_group = OptionGroup(parser, 'Specific Options for the '
                                       '"--add-logical-drive" Command')
    add_ld_group.add_option('--raid-level', dest='raid_level',
                            help='the RAID level of the new logical drive',
                            metavar='LEVEL', type='string')
    add_ld_group.add_option('--phys-drives', dest='phys_drives',
                            help='the enclosure/slot string of the physical '
                                 'drives (eg, "0:1,0:2") for the new '
                                 'logical drive',
                            metavar='DRIVES', type='string')
    add_ld_group.add_option('--no-read-cache', dest='no_read_cache',
                            action='store_true',
                            help='don\'t enable read-ahead cache '
                                 '(default is enabled)')
    add_ld_group.add_option('--no-write-cache', dest='no_write_cache',
                            action='store_true',
                            help='don\'t enable write-back cache '
                                 '(default is enabled)')
    parser.add_option_group(add_ld_group)

    rem_ld_group = OptionGroup(parser, 'Specific Options for the '
                                       '"--rem-logical-drive" Command')
    rem_ld_group.add_option('--rem-ld-id', dest='rem_ld_id',
                            help='the logical drive ID number of '
                                 'the LD to remove',
                            metavar='ID_NUM', type='int')
    parser.add_option_group(rem_ld_group)

    add_hsp_group = OptionGroup(parser, 'Specific Options for the '
                                        '"--add-hot-spare" Command')
    add_hsp_group.add_option('--add-encl-id', dest='add_encl_id',
                             help='the enclosure ID of the physical '
                                  'drive to add',
                             metavar='ID_NUM', type='int')
    add_hsp_group.add_option('--add-slot-num', dest='add_slot_num',
                             help='the slot number of the physical '
                                  'drive to add',
                             metavar='ID_NUM', type='int')
    parser.add_option_group(add_hsp_group)

    rem_hsp_group = OptionGroup(parser, 'Specific Options for the '
                                        '"--rem-hot-spare" Command')
    rem_hsp_group.add_option('--rem-encl-id', dest='rem_encl_id',
                             help='the enclosure ID of the hot spare to remove',
                             metavar='ID_NUM', type='int')
    rem_hsp_group.add_option('--rem-slot-num', dest='rem_slot_num',
                             help='the slot number of the hot spare to remove',
                             metavar='ID_NUM', type='int')
    parser.add_option_group(rem_hsp_group)
    (options, args) = parser.parse_args()

    # Make sure we only (or at least) got one command option
    cmd_count = 0
    if options.list_controllers:
        cmd_count += 1
    if options.list_physical_drives:
        cmd_count += 1
    if options.list_logical_drives:
        cmd_count += 1
    if options.add_logical_drive:
        cmd_count += 1
    if options.rem_logical_drive:
        cmd_count += 1
    if options.add_hot_spare:
        cmd_count += 1
    if options.rem_hot_spare:
        cmd_count += 1
    if cmd_count < 1:
        parser.error('you must specify one command option')
    if cmd_count > 1:
        parser.error('all command options are mutually exclusive, '
                     'pick only one')

    # Create objects for the RAID CLI tools
    megaraid = MegaRAID()
    perc = PERC()
    aacraid = AACRAID()

    # Perform checks for the specific command option,
    # and execute the action if it's all good
    if options.list_controllers:
        if options.type is not None or options.ctrlr_id is not None:
            if not (options.type is not None and options.ctrlr_id is not None):
                parser.error('--type and --ctrlr-id must both be specified')
            else:
                if options.type == 'MegaRAID':
                    if megaraid.working:
                        megaraid.list_ctrlrs(options.ctrlr_id)
                elif options.type == 'PERC':
                    if perc.working:
                        perc.list_ctrlrs(options.ctrlr_id)
                elif options.type == 'AACRAID':
[root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive
Usage: hw_raid_cli.py [options]

hw_raid_cli.py: error: --type and --ctrlr-id are required options
[root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=raid5 --ctrlr-id=0
Usage: hw_raid_cli.py [options]

hw_raid_cli.py: error: option --type: invalid choice: 'raid5' (choose from 'MegaRAID', 'PERC', 'AACRAID')
[root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0
Usage: hw_raid_cli.py [options]

hw_raid_cli.py: error: --raid-level and --phys-drives are required options
[root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0--raid-level=5 --phys-drives=8:0 8:1 8:2 8:3 8:4 8:5
Usage: hw_raid_cli.py [options]

hw_raid_cli.py: error: option --ctrlr-id: invalid integer value: '0--raid-level=5'
[root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0 --raid-level=5 --phys-drives=8:0 8:1 8:2 8:3 8:4 8:5
Controller = 0
Status = Failure
Description = Cannot create configuration with 1 drives



[root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0 --raid-level=5 --phys-drives=8:0,8:1,8:2,8:3,8:4,8:5
Controller = 0
Status = Failure
Description = Cannot create configuration with 6 drives



[root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0 --raid-level=5 --phys-drives=8:0,8:1,8:2
Controller = 0
Status = Failure
Description = Cannot create configuration with 3 drives



[root@daffy sbin]# [root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0 --raid-level=5 --phys-drives=8:0,8:1,8:2,8:3,8:4,8:5
bash: [root@daffy: command not found
[root@daffy sbin]# Controller = 0
bash: Controller: command not found
[root@daffy sbin]# Status = Failure
bash: Status: command not found
[root@daffy sbin]# Description = Cannot create configuration with 6 drives
bash: Description: command not found
[root@daffy sbin]#
[root@daffy sbin]#
[root@daffy sbin]#
[root@daffy sbin]# [root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0 --raid-level=5 --phys-drives=8:0,8:1,8:2
bash: [root@daffy: command not found
[root@daffy sbin]# Controller = 0
bash: Controller: command not found
[root@daffy sbin]# Status = Failure
bash: Status: command not found
[root@daffy sbin]# Description = Cannot create configuration with 3 drives
bash: Description: command not found
[root@daffy sbin]# \
>
[root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0 --raid-level=5 --phys-drives=8:0,8:1,8:2,8:3,8:4,8:5
Controller = 0
Status = Failure
Description = Cannot create configuration with 6 drives



[root@daffy sbin]# ^C
[root@daffy sbin]# [root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0 --raid-level=5 --phys-drives=8:0,8:1,8:2,8:3,8:4,8:5
bash: [root@daffy: command not found
[root@daffy sbin]# Controller = 0
bash: Controller: command not found
[root@daffy sbin]# Status = Failure
bash: Status: command not found
[root@daffy sbin]# Description = Cannot create configuration with 6 drives
bash: Description: command not found
[root@daffy sbin]# [root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0 --raid-level=5 --phys-drives=8:0,8:1,8:2,8:3,8:4,8:5
bash: [root@daffy: command not found
[root@daffy sbin]# [root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0 --raid-level=5 --phys-drives=8:0,8:1,8:2,8:3,8:4,8:5
bash: [root@daffy: command not found
[root@daffy sbin]# ls
archive_logs.sh  health_chk.sh    startup.sh       usb_sync.sh
conf_sync.sh     hw_raid_cli.py   support_pkg.sh
[root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0 --raid-level=5 --phys-drives=8:0,8:1,8:2,8:3,8:4,8:5
Controller = 0
Status = Failure
Description = Cannot create configuration with 6 drives



[root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0 --raid-level=5 --phys-drives=8:0,8:1,8:2
Controller = 0
Status = Failure
Description = Cannot create configuration with 3 drives


[root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0 --raid-level=5 --phys-drives=8:0,8:1,8:2,8:3,8:4,8:5
Controller = 0
Status = Failure
Description = Cannot create configuration with 6 drives

[root@daffy sbin]# ./hw_raid_cli.py --add-logical-drive --type=PERC --ctrlr-id=0 --raid-level=5 --phys-drives=8:0,8:1,8:2
Controller = 0
Status = Failure
Description = Cannot create configuration with 3 drives



[root@daffy sbin]#

Marc Smith

unread,
May 9, 2018, 8:56:31 AM5/9/18
to esos-...@googlegroups.com
Maybe modify the 'hw_raid_cli.py' script on your machine to print the
command it's running when attempting to add a logical drive:

$ diff -Naur hw_raid_cli.py{.orig,}
--- hw_raid_cli.py.orig 2018-05-09 08:52:08.604974594 -0400
+++ hw_raid_cli.py 2018-05-09 08:53:13.134392798 -0400
@@ -330,6 +330,7 @@
command = PERCCLI_BIN + ' /c' + str(ctrlr_id) + ' add vd r' + \
raid_lvl + ' drives=' + phys_drives + ' ' + read_opt + \
' ' + write_opt + ' 2>&1'
+ print "command:", command
process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
stdout, stderr = process.communicate()
cmd_exit = process.returncode


The "Description = Cannot create configuration with 3 drives" error
messages from perccli64 are interesting, so do the above so we can see
what command it's actually attempting to run. Could be a bug in that
Python script.

Maybe try RAID level 0 too, just to see what it says.


--Marc


On Tue, May 8, 2018 at 8:45 PM, Allen Underdown

Allen Underdown

unread,
May 22, 2018, 12:31:25 PM5/22/18
to esos-users
Well, I've given up on this.  It looks as if both Perc and MegaCLI will work, but not fully, i.e. I could not build the array and finally just built it in the Perc Bios.
Reply all
Reply to author
Forward
0 new messages