Skip to content
Apr 16 12

List fiber channel luns and controllers on a Mac

by jprice

Mac is pretty, and very GUI, but getting real data about what’s going on can be a PITA.

Want to know how to list the luns and storage controllers that your Mac client can see?

fibreconfig -l

(and you can rescan with -r!).  Note the english spelling of fibre.

–Jason

Jan 25 12

When did I last run FSCK?

by jprice

aka ‘how long has it been since I ran fsck?’

Answer: run ‘tune2fs -l <device>’ and look at

Mount count: 2
Maximum mount count: 36
Last checked: Tue Sep 6 23:12:36 2011
Check interval: 15552000 (6 months)
Next check after: Sun Mar 4 23:12:36 2012

If the mount count = max mount count, you’re due for an FSCK.  If you’re booting after the ‘Check interval’, (which is helpfully calculated for you on the ‘Next check after:’ line), you’re due for an FSCK.

Knowing if your scheduled reboot will take several hours in order to run the FSCK?  Priceless.

Jan 19 12

PIPA letter to Georgia Senators

by jprice

(Not directly Sysadmin related, but important none the less. Here are letters I’m sending to my Senators, both of whom are co-sponsors of the PIPA or Protect IP Act)

Please use these as templates or replace <NAME> and <ADDRESS> with the appropriate values.

###########################################################################

The Honorable Saxby Chambliss
416 Russell Senate Office Building
United States Senate
Washington DC 20510

Dear Senator:

My name is <NAME> and my address is <ADDRESS>.  I am writing you because I am deeply disappointed that you are not only supporting the Protect IP Act (aka PIPA, aka S.968), but are actually a co-sponsor of the proposed legislation.

As written, PIPA would destroy the progress of the Internet over the past 15 years. You well know how important that growth has been to the country as a whole, and Atlanta/Columbus/Savannah in particular.  The entire ‘Web 2.0′ movement is founded on user generated content as well as enabling small entities (businesses and persons) to work together and build amazing things.  The provisions of PIPA would work to destroy this foundation by significantly decreasing due process for ‘take down’ requests, while drastically increasing the ‘damage radius’ of such requests (such as forcing Ad-networks, search engines, DNS servers, etc to ‘delist’ entire sites for having a single bit of infringing content.)

No one denies that intellectual property piracy is a real problem. There are possible legal remedies to these challenges, however PIPA is a very dangerous solution to these problems.

Please retract your support and sponsorship of the PIPA (S.968) immediately.

Thank you,

<NAME>

###########################################################################

The Honorable Johnny Isakson
131 Russell Senate Office Building
United States Senate
Washington DC 20510

Dear Senator:

My name is <NAME> and my address is <ADDRESS>.  I am writing you because I am deeply disappointed that you are not only supporting the Protect IP Act (aka PIPA, aka S.968), but are actually a co-sponsor of the proposed legislation.

As written, PIPA would destroy the progress of the Internet over the past 15 years. You well know how important that growth has been to the country as a whole, and Atlanta/Columbus/Savannah in particular.  The entire ‘Web 2.0′ movement is founded on user generated content as well as enabling small entities (businesses and persons) to work together and build amazing things.  The provisions of PIPA would work to destroy this foundation by significantly decreasing due process for ‘take down’ requests, while drastically increasing the ‘damage radius’ of such requests (such as forcing Ad-networks, search engines, DNS servers, etc to ‘delist’ entire sites for having a single bit of infringing content.)

No one denies that intellectual property piracy is a real problem. There are possible legal remedies to these challenges, however PIPA is a very dangerous solution to these problems.

Please retract your support and sponsorship of the PIPA (S.968) immediately.

Thank you,

<NAME>

 

Dec 29 11

NPIV and XEN under CentOS 5 does not work

by jprice

boo.

(double boo for not posting anything in nearly 6 months)

From what I can tell, Xen 3.0.3 (shipped with CentOS / RHEL 5) does NOT support NPIV for SAN attached storage. Looks like it works just fine with CentOS 6 though. The frustrating thing is that all the pieces are there for it to work… /sys/class/scsi_host/host?/vport_create and _destroy work as they should, you can zone storage to the new vports… you just can’t present the lun form:

npiv:----

to the guest.

boo. SysOps will upgrade the xen stuff next year at some point.

Jul 13 11

Linux multipath is making me tired (part 2)

by jprice

Follow up from an earlier post

Turns out to be a known issue. hooray.

http://oss.oracle.com/ol5/docs/RELEASE-NOTES-U6-en

–Jason

Jun 6 11

If any of you run SSL sites…

by jprice

Use this tool to check the SSL config.

You’ll be happy.

May 25 11

linux multipath is making me tired.

by jprice

So, I’ve got a multipath setup that claims to be working:

# multipath -ll
vrp (360060e8010053b90052fb06900000190) dm-8 HITACHI,DF600F
size=70G features=’0′ hwhandler=’0′ wp=rw
`-+- policy=’round-robin 0′ prio=1 status=active
|- 6:0:0:0 sdc 8:32 active ready running
`- 5:0:0:0 sdb 8:16 active ready running

sweet right?

Until you test it. For some reason, the above setup isn’t ’round-robin’, it’s only using one path. If you kill the inactive link (unplug, port disable, whatever), it works fine. Reconnect, and it recovers. If you kill the active link, well, the world blows up on you (read-only file system, etc).

The above is with Oracle Enterprise Linux 5.6 (aka oracle unbreakable linux) and device-mapper-multipath-0.4.9-23.0.8.el5 (which is the latest supported version AFAICT). I’ll update or post again when/if I get this solved.

ETA: Turns out to be a known issue

Apr 15 11

lvresize is my friend

by jprice

Everyone is fearful of resizing volumes.

Linux has made it pretty easy though, provided you’re using LVM (lvm2 that is), and ext3 filesystems.  Tested on Redhat 5.6 (aka Oracle Enterprise Linux aka CentOS).  One command which will grow or shrink both the volume and the file system.

lvresize!

Note: if you’re resizing down (shrinking), you’ll need to umount the shrinking volume first.  If it is mounted, it’ll ask you to do it for you.

Say you need to move 20GB from /home, to /var, and they’re in the same VG:

umount /home
lvresize --resizefs -L -20G /dev/mapper/localdisks-home
lvresize --resizefs -L +20G /dev/mapper/localdisk-var
mount /home

Done!  (though the shrink command will take a little bit of time to finish)

Mar 26 11

tcpdump and error 1448

by jprice

If you use tcpdump, and see ‘reply ERR 1448′, you’re hitting a bug in tcpdump.  Use tshark instead.

Tcpdump isn’t reassembling NFS packets correctly.

FYI

Mar 10 11

Create Luns in an AMS2500 easily.

by jprice

If you’re like me, you’ve got an AMS2000 series (2100, 2300, 2500) array, and you’re using HDP pools, since they’re SO MUCH EASIER than regular RAID groups.

If you’re also like me, you’re using SNM2[1] to manage this thing, and it is an amazingly slow GUI.  But SNM2 has a CLI! So that’s better, right?  Sorta… you have to log in with each command you want to run…

So I’ve written a python script which creates LU[2] of specified size.  You can download my lu-maker.py here, or you can look at it below.

–Jason

[1] Storage Navigator Modular 2

[2] or LUNS (not presented to the hosts yet), or LDEV’s if you’re from USP land…

 
#!/usr/bin/python
 
import os
import os.path
import subprocess
import sys
import time
 
unit = 'tc3ams2500'
user = 'my_username_you_silly_boy'
passwd = 'my_password_you_silly_boy'
 
def usage() :
    """print usage information and exit"""
    print "USAGE:"
    print "%s -p <pool#> size1 [size2 ... sizeN] [-p <pool#> size1 ...] ..." % sys.argv[0]
    print 'a size can be either:'
    print '"100" for 100gb or'
    print '"10x50" for creating ten different 50gb luns'
    sys.exit(-1)
 
def whereis(program):
    """Validate if a program is in your $PATH variable"""
    for path in os.environ.get('PATH', '').split(':'):
        if os.path.exists(os.path.join(path, program)) and \
           not os.path.isdir(os.path.join(path, program)):
               return os.path.join(path, program)
    return None
 
def isint(arg) :
    """Validate if a string passed on the command line is an integer."""
    try :
        int(arg)
    except ValueError :
        return False
    return True
 
def validsize(arg) :
    """validate if an argument is a valid size argument.
    Either it must be an integer (indicating a size of one lun)
    or it must be in the form #x# or <number>x<number> which indicates
    a count of luns to be created of a specific size. For example:
    10x50 would mean 10 luns of size 50gb should be created
    """
    if isint(arg) :
        return True
    elif 'x' in arg :
        try :
            count, size = arg.split('x')
        except :
            return False
        if isint(count) and isint(size) :
            return True
    return False
 
def parsesize(arg) :
    """once a size specification is validated, it can be more easily parsed.
    Run as a generator to yeild the right number of sizes
    """
    if isint(arg) :
        yield arg
    else :
        count,size = arg.split('x')
        for i in range(int(count)) :
            yield size
 
def runcmd(cmdstr, dashy=False) :
    """run command abstracts away the subprocess module, and the vagarities
    of the SNM2 CLI.  Deals with the login prompt and the password prompt.
    if dashy is True, also respond the a third question with a 'y\n' to
    deal with 'are you sure' type prompts.
    """
    sleeptime = .2
    cmdlist = cmdstr.split()
    if whereis(cmdlist[0]) == None :
        print "%s is not found in $PATH" % cmdlist[0]
        sys.exit(-1)
    p = subprocess.Popen( cmdlist,
                          stdin = subprocess.PIPE,
                          stdout = subprocess.PIPE,
                          stderr = subprocess.PIPE )
    time.sleep(sleeptime)
    p.stdin.write(user + '\n')
    time.sleep(sleeptime)
    p.stdin.write(passwd + '\n')
    if dashy :
        time.sleep(sleeptime)
        p.stdin.write('y\n')
    stdout, stderr = p.communicate()
    return stdout, stderr, p.returncode
 
def parselus(output) :
    """Takes the output of auluref, and finds any gaps in the list of LU's,
    and also gives the next free lu number.  First parse the output, then
    find the gaps, then add 1 to the top lu number in existance, and return
    the holelist, and the next free.
    """
    lulist = []
    holelist = []
    last = 0
    for line in (line for line in output.split(os.linesep)) :
        uline = line.strip()
        words = uline.split()
        if len(words) > 0 and isint(words[0]) :
            lu = int(words[0])
            lulist.append(lu)
    #find the gaps in lulist:
    last = 0
    holelist = []
    for lu in lulist :
        while True :
            tlast = last
            last += 1
            if tlast >= lu :
                break
            holelist.append(tlast)
    return holelist, lulist[-1] + 1
 
def genlunumbers() :
    """Creates a generator to yield the next available lu number.  First
    tries to fill any holes, and then just adds to the top.  Uses auluref as
    a datasource.
    """
    cmdstr = "auluref -unit %s" % unit
    stdout, stderr, returncode = runcmd(cmdstr)
    holelist, next = parselus(stdout)
 
    for lu in holelist :
        yield str(lu)
 
    lu = next
    while True :
        yield str(lu)
        lu += 1
 
def getpools() :
    """uses audppool to list the available DP pools.  Used to validate if the
    passed pool numbers are valid.  NOTE: The format of the audppool command
    is a little crazy.  Short version of what follows: if the first 10 chars
    of any line start with a number (if the 10 chars are run through .split(),
    it's a valid pool.
    """
    cmdstr = "audppool -unit %s -refer" % unit
    stdout, stderr, returncode = runcmd(cmdstr)
    poollist = []
    for line in (line for line in stdout.split(os.linesep)) :
        uline = line[:10]
        words = uline.split()
        if len(words) == 0 :
            continue
        if isint(words[0]) :
            poollist.append(words[0])
    return poollist
 
def makelun(pool, size, lu) :
    """Actually makes a given lun in a specified pool, with a given size.
    """
    #auluadd -unit tc3ams2500 [ -lu lun ] -dppoolno pool -size size + 'g'
    cmdstr = "auluadd -unit %s -lu %s -dppoolno %s -size %s" % (unit,
                                                                lu,
                                                                pool,
                                                                size + 'g')
    print "making LU number %s from pool %s of size %s" % (lu, pool, size)
    #stdout, stderr, returncode = runcmd(cmdstr, dashy=True)
    print "NOTE: program currently nutered. Uncomment above line (and \ncomment out this line) to activate.\n I would normally run this command: \n", cmdstr
 
def main() :
    """ Main: calls getpool, parses the command line arguments (in a way I'm
    not fully happy with).  The last three lines make the luns.
    """
    poollist = getpools()
    lunlist = []
    #parse cmdline, build list of pool,size pairs
    if sys.argv[1] != '-p' :
        print 'must specify -p <pool number> first'
        usage()
    if isint(sys.argv[2]) and sys.argv[2] in poollist :
        pool = sys.argv[2]
    else :
        print 'pool number %s must be a valid pool number' % sys.argv[2]
        print 'valid pools are %s' % poollist
        usage()
    if validsize(sys.argv[3]) :
        for size in parsesize(sys.argv[3]) :
            lunlist.append( (pool, size) )
    else :
        print 'invalid size specification: %s' % sys.argv[3]
        usage()
    nextispool = False
    for arg in sys.argv[4:] :
        if nextispool :
            if isint(arg) and arg in poollist :
                pool = arg
                nextispool = False
            else :
                print 'pool number %s must be a valid pool number' % sys.argv[2]
                print 'valid pools are %s' % poollist
                usage()
        elif arg == '-p' :
            nextispool = True
        elif validsize(arg) :
            for size in parsesize(arg) :
                lunlist.append( (pool,size) )
        else :
            'unknown error with arg %s' % arg
            usage()
    lu = genlunumbers()
    for pool,size in lunlist :
        makelun(pool, size, lu.next())
 
if __name__ == '__main__' :
    main()