#!/usr/bin/python
# Copyright (c) 2015 The New Mexico Consortium
# 
# {{{NMC-LICENSE
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. 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.
#
# 3. Neither the name of the copyright holder 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
# COPYRIGHT HOLDER 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.
#
# }}}

from nmc_probe.disk import Disk
from nmc_probe.lsi import LSI
import os,sys,getopt,pprint

def main():
    """
    Program entry point
    """
    options    = read_options()

    lsi = LSI()
    controllers = lsi.list_controllers()

    locate_disk(controllers, options)

def locate_disk(controllers, options):
    dev = options.get('dev', None)
    serial_number = options.get('serial_number', None)
    zfs = options.get('zfs', None)
    on = options.get('on', None)
    off = options.get('off', None)

    if dev is not None:
        try:
            os.stat(dev)
        except OSError as e:
            print e
            sys.exit(1)

    found = None
    for controller in controllers:
        for num, disk in controller.disks.iteritems(): 
#            print disk.protocol
#            print disk.serial_number
#            print disk.model_number

            if found is None:
                if dev is not None:
                    if dev == disk.dev or dev == disk.dev_by_pci or dev == disk.dev_by_id_protocol:
                        found = True
                elif serial_number is not None:
                    if serial_number == disk.serial_number:
                        found = True
                elif zfs is not None:
                    if zfs == disk.id_protocol:
                        found = True

                if found is not None:
                    print '%s:%s:%s' % (controller.index, disk.enclosure.index, disk.bay)

                    if on is not None:
                        controller.locate_bay(disk.enclosure.index, 'on')
                    elif off is not None:
                        controller.locate_bay(disk.enclosure.index, 'off')

    if found is None:
        print '%s does not appear to be part of an external JBOD. Maybe this is an onboard disk?' % dev
 
def usage(prog_name):
    print ('Usage %s [options]' % prog_name)
    print
    print ('Locate a disk in a JBOD. This prints out the controller index, disk enclosure index')
    print ('and the drive bay index')
    print
    print (' --dev | -d\tThe /dev name of the device')
    print (' --serial | -s\tThe serial number of the device')
    print (' --zfs | -z\tThe zfs identifier for the drive')
    print (' --on\tTurn on locate LED')
    print (' --off\tTurn off locate LED')
    print (' --help | -h\tPrint this usage message')
    
def read_options():
    prog_name = sys.argv[0]

    optlist = None
    args = None

    options = {}

    try:
        optlist, args = getopt.getopt(sys.argv[1:], 'd:s:z:h', ['dev=', 'serial=', 'zfs=', 'help', 'on', 'off'])

    except getopt.GetoptError as err:
        print(err)
        usage(prog_name)
        sys.exit(0)

    num=None

    # Process the options
    for (opt,value) in optlist:
        if opt == '--dev' or opt == '-d':
            options['dev'] = value

        if opt == '--serial' or opt == '-s':
            options['serial_number'] = value

        if opt == '--zfs' or opt == '-z':
            options['zfs'] = value

        if opt == '--on':
            options['on'] = True

        if opt == '--off':
            options['off'] = True

        if opt == '--help' or opt == '-h':
            usage(prog_name)
            sys.exit(0)


    if options.get('dev', None) is None and options.get('serial_number', None) is None and options.get('zfs', None) is None:
        print ('--device, --serial or --zfs must be specified')
        usage(prog_name)
        sys.exit(1)

    if options.get('dev', None) is not None and options.get('serial_number', None) is not None and options.get('zfs', None) is not None:
        print ('Only use one of --device, --serial or --zfs')
        usage(prog_name)
        sys.exit(1)

    if options.get('on', None) is not None and options.get('off', None) is not None:
        print ('Cowardly refusing to turn the LED locate light both on and off at the same time')
        usage(prog_name)
        sys.exit(1)

    return options

# Program entry point
if __name__ == "__main__":
    main()

