

from __future__ import absolute_import

import glob
import logging
import os

from vdsm import constants
from vdsm.config import config
from vdsm.common import commands
from vdsm.common import supervdsm
from vdsm.common import zombiereaper
from vdsm.storage import misc

log = logging.getLogger("storage.HBA")

ISCSI_INITIATOR_NAME = "/etc/iscsi/initiatorname.iscsi"
INITIATOR_NAME = "InitiatorName"

FC_HOST_MASK = "/sys/class/fc_host/host*"

PORT_NAME = "port_name"
NODE_NAME = "node_name"


class Error(Exception):
    """ hba operation failed """


@misc.samplingmethod
def rescan():
    log.debug("Starting scan")
    try:
        supervdsm.getProxy().hbaRescan()
    except Error as e:
        log.error("Scan failed: %s", e)
    else:
        log.debug("Scan finished")


def _rescan():
    timeout = config.getint('irs', 'scsi_rescan_maximal_timeout')

    proc = commands.execCmd([constants.EXT_FC_SCAN], sync=False,
                            execCmdLogger=log)
    try:
        proc.wait(timeout)
    finally:
        if proc.returncode is None:
            zombiereaper.autoReapPID(proc.pid)
            raise Error("Timeout scanning (pid=%s)" % proc.pid)
        elif proc.returncode != 0:
            stderr = proc.stderr.read(512)
            raise Error("Scan failed: %r" % stderr)


def getiSCSIInitiators():
    hbas = []
    try:
        with open(ISCSI_INITIATOR_NAME) as f:
            for line in f:
                if line.startswith(INITIATOR_NAME):
                    hba = {'InitiatorName': line.split("=")[1].strip()}
                    hbas.append(hba)
                    break
    except EnvironmentError:
        pass

    return hbas


def getModelDesc(fch, host):
    names = ("modelname", "model", "model_name")
    descs = ("modeldesc", "model_description", "model_desc")

    model_name = "Unknown"
    model_desc = "Unknown"
    for name, desc in zip(names, descs):
        name_path = os.path.join(fch, "device", "scsi_host", host, name)
        desc_path = os.path.join(fch, "device", "scsi_host", host, desc)
        try:
            with open(name_path) as name_file:
                model_name = name_file.read().strip()
            with open(desc_path) as desc_file:
                model_desc = desc_file.read().strip()
        except IOError:

    return (model_name, model_desc)


def getFCInitiators():
    hbas = []
    fcHosts = glob.glob(FC_HOST_MASK)
    for fch in fcHosts:
        host = os.path.basename(fch)
        portName = os.path.join(fch, PORT_NAME)
        with open(portName) as port_file:
            wwpn = port_file.read().strip().lstrip("0x")
        nodeName = os.path.join(fch, NODE_NAME)
        with open(nodeName) as node_file:
            wwnn = node_file.read().strip().lstrip("0x")
        model = "%s - %s" % getModelDesc(fch, host)
        hbas.append({"wwpn": wwpn, "wwnn": wwnn, "model": model})
    return hbas


def HBAInventory():
    inv = {'iSCSI': getiSCSIInitiators(), 'FC': getFCInitiators()}

    return inv
