<commit_before>#
# iscsi.py - iscsi class
#
# Copyright (C) 2005, 2006  IBM, Inc.  All rights reserved.
# Copyright (C) 2006  Red Hat, Inc.  All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

from . import udev
from . import util
from .flags import flags
from .i18n import _
from .storage_log import log_exception_info
from multiprocessing import Process, Pipe
import os
import logging
import shutil
import time
import itertools
log = logging.getLogger("blivet")

has_libiscsi = True
try:
    import libiscsi
except ImportError:
    has_libiscsi = False

# Note that stage2 copies all files under /sbin to /usr/sbin
ISCSID=""
INITIATOR_FILE="/etc/iscsi/initiatorname.iscsi"

ISCSI_MODULES=['cxgb3i', 'bnx2i', 'be2iscsi']

def has_iscsi():
    global ISCSID

    if not os.access("/sys/module/iscsi_tcp", os.X_OK):
        return False

    if not ISCSID:
        location = util.find_program_in_path("iscsid")
        if not location:
            return False
        ISCSID = location
        log.info("ISCSID is %s", ISCSID)

    return True


def _call_discover_targets(con_write, con_recv, ipaddr, port, authinfo):
    """ Function to separate iscsi :py:func:`libiscsi.discover_sendtargets` call to it's own process.

        The call must be started on special process because the :py:mod:`libiscsi`
        library is not thread safe. When thread is used or it's called on
        main thread the main thread will freeze.

        Also the discover is about four times slower (only for timeout)
        this is caused by signals which are delivered to bad (python)
        thread instead of C library thread.

        .. note::

            To transfer data to main process ``con_write`` (write only) is used.
            Pipe returns tuple (ok, data).

            ``con_recv`` should be immediately closed so that the reading end
            of the pipe is not used in the child process.

            * ``ok``: True if everything was ok
            * ``data``: Dictionary with :py:func:`libiscsi.node` parameters if ``ok`` was True.
              Exception if ``ok`` was False

        :param con_write: Pipe to the main process (write only)
        :type con_write: :py:func:`multiprocessing.Pipe`
        :param con_recv: Reading end of pipe from main process (close only)
        :type con_recv: :py:func:`multiprocessing.Pipe`
        :param str ipaddr: target IP address
        :param str port: target port
        :param authinfo: CHAP authentication data for node login
        :type authinfo: Object returned by :py:func:`libiscsi.chapAuthInfo` or None
    """

    # Close the reading end of the pipe in the child process
    con_recv.close()

    with con_write:
        try:
            found_nodes = libiscsi.discover_sendtargets(address=ipaddr,
                                                        port=int(port),
                                                        authinfo=authinfo)
            if found_nodes is None:
                found_nodes = []

        except IOError as ex:
            con_write.send((False, ex))
            return

        nodes = []

        # the node object is not pickable so it can't be send with pipe
        # TODO: change libiscsi.node to pickable object
        for node in found_nodes:
            nodes.append({'name': node.name,
                         'tpgt': node.tpgt,
                         'address': node.address,
                         'port': node.port,
                         'iface': node.iface})

        con_write.send((True, nodes))

class iscsi(object):
    """ iSCSI utility class.

        This class will automatically discover and login to iBFT (or
        other firmware) configured iscsi devices when the startup() method
        gets called. It can also be used to manually configure iscsi devices
        through the addTarget() method.

        As this class needs to make sure certain things like starting iscsid
        and logging in to firmware discovered disks only happens once
        and as it keeps a global list of all iSCSI devices it is implemented as
        a Singleton.
    """
<commit_msg>Catch and relay more exception types from the iscsi process<commit_after>#
# iscsi.py - iscsi class
#
# Copyright (C) 2005, 2006  IBM, Inc.  All rights reserved.
# Copyright (C) 2006  Red Hat, Inc.  All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

from . import udev
from . import util
from .flags import flags
from .i18n import _
from .storage_log import log_exception_info
from multiprocessing import Process, Pipe
import os
import logging
import shutil
import time
import itertools
log = logging.getLogger("blivet")

has_libiscsi = True
try:
    import libiscsi
except ImportError:
    has_libiscsi = False

# Note that stage2 copies all files under /sbin to /usr/sbin
ISCSID=""
INITIATOR_FILE="/etc/iscsi/initiatorname.iscsi"

ISCSI_MODULES=['cxgb3i', 'bnx2i', 'be2iscsi']

def has_iscsi():
    global ISCSID

    if not os.access("/sys/module/iscsi_tcp", os.X_OK):
        return False

    if not ISCSID:
        location = util.find_program_in_path("iscsid")
        if not location:
            return False
        ISCSID = location
        log.info("ISCSID is %s", ISCSID)

    return True


def _call_discover_targets(con_write, con_recv, ipaddr, port, authinfo):
    """ Function to separate iscsi :py:func:`libiscsi.discover_sendtargets` call to it's own process.

        The call must be started on special process because the :py:mod:`libiscsi`
        library is not thread safe. When thread is used or it's called on
        main thread the main thread will freeze.

        Also the discover is about four times slower (only for timeout)
        this is caused by signals which are delivered to bad (python)
        thread instead of C library thread.

        .. note::

            To transfer data to main process ``con_write`` (write only) is used.
            Pipe returns tuple (ok, data).

            ``con_recv`` should be immediately closed so that the reading end
            of the pipe is not used in the child process.

            * ``ok``: True if everything was ok
            * ``data``: Dictionary with :py:func:`libiscsi.node` parameters if ``ok`` was True.
              Exception if ``ok`` was False

        :param con_write: Pipe to the main process (write only)
        :type con_write: :py:func:`multiprocessing.Pipe`
        :param con_recv: Reading end of pipe from main process (close only)
        :type con_recv: :py:func:`multiprocessing.Pipe`
        :param str ipaddr: target IP address
        :param str port: target port
        :param authinfo: CHAP authentication data for node login
        :type authinfo: Object returned by :py:func:`libiscsi.chapAuthInfo` or None
    """

    # Close the reading end of the pipe in the child process
    con_recv.close()

    with con_write:
        try:
            found_nodes = libiscsi.discover_sendtargets(address=ipaddr,
                                                        port=int(port),
                                                        authinfo=authinfo)
            if found_nodes is None:
                found_nodes = []

            nodes = []

            # the node object is not pickable so it can't be send with pipe
            # TODO: change libiscsi.node to pickable object
            for node in found_nodes:
                nodes.append({'name': node.name,
                             'tpgt': node.tpgt,
                             'address': node.address,
                             'port': node.port,
                             'iface': node.iface})

            con_write.send((True, nodes))

        except Exception as ex: # pylint: disable=broad-except
            con_write.send((False, ex))

class iscsi(object):
    """ iSCSI utility class.

        This class will automatically discover and login to iBFT (or
        other firmware) configured iscsi devices when the startup() method
        gets called. It can also be used to manually configure iscsi devices
        through the addTarget() method.

        As this class needs to make sure certain things like starting iscsid
        and logging in to firmware discovered disks only happens once
        and as it keeps a global list of all iSCSI devices it is implemented as
        a Singleton.
    """

{'fraction_non_alphanumeric': 0.07156348373557188, 'fraction_numerical': 0.003987408184679958, 'mean_word_length': 2.357168016907362, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7080560', 'n_tokens_mistral': 2652, 'n_tokens_neox': 2519, 'n_words': 1086}