def set_iscsi_options(
        client,
        auth_file=None,
        node_base=None,
        nop_timeout=None,
        nop_in_interval=None,
        disable_chap=None,
        require_chap=None,
        mutual_chap=None,
        chap_group=None,
        max_sessions=None,
        max_queue_depth=None,
        max_connections_per_session=None,
        default_time2wait=None,
        default_time2retain=None,
        first_burst_length=None,
        immediate_data=None,
        error_recovery_level=None,
        allow_duplicated_isid=None,
        min_connections_per_core=None):
    """Set iSCSI target options.

    Args:
        auth_file: Path to CHAP shared secret file (optional)
        node_base: Prefix of the name of iSCSI target node (optional)
        nop_timeout: Timeout in seconds to nop-in request to the initiator (optional)
        nop_in_interval: Time interval in secs between nop-in requests by the target (optional)
        disable_chap: CHAP for discovery session should be disabled (optional)
        require_chap: CHAP for discovery session should be required
        mutual_chap: CHAP for discovery session should be mutual
        chap_group: Authentication group ID for discovery session
        max_sessions: Maximum number of sessions in the host
        max_queue_depth: Maximum number of outstanding I/Os per queue
        max_connections_per_session: Negotiated parameter, MaxConnections
        default_time2wait: Negotiated parameter, DefaultTime2Wait
        default_time2retain: Negotiated parameter, DefaultTime2Retain
        first_burst_length: Negotiated parameter, FirstBurstLength
        immediate_data: Negotiated parameter, ImmediateData
        error_recovery_level: Negotiated parameter, ErrorRecoveryLevel
        allow_duplicated_isid: Allow duplicated initiator session ID
        min_connections_per_core: Allocation unit of connections per core

    Returns:
        True or False
    """
    params = {}

    if auth_file:
        params['auth_file'] = auth_file
    if node_base:
        params['node_base'] = node_base
    if nop_timeout:
        params['nop_timeout'] = nop_timeout
    if nop_in_interval:
        params['nop_in_interval'] = nop_in_interval
    if disable_chap:
        params['disable_chap'] = disable_chap
    if require_chap:
        params['require_chap'] = require_chap
    if mutual_chap:
        params['mutual_chap'] = mutual_chap
    if chap_group:
        params['chap_group'] = chap_group
    if max_sessions:
        params['max_sessions'] = max_sessions
    if max_queue_depth:
        params['max_queue_depth'] = max_queue_depth
    if max_connections_per_session:
        params['max_connections_per_session'] = max_connections_per_session
    if default_time2wait:
        params['default_time2wait'] = default_time2wait
    if default_time2retain:
        params['default_time2retain'] = default_time2retain
    if first_burst_length:
        params['first_burst_length'] = first_burst_length
    if immediate_data:
        params['immediate_data'] = immediate_data
    if error_recovery_level:
        params['error_recovery_level'] = error_recovery_level
    if allow_duplicated_isid:
        params['allow_duplicated_isid'] = allow_duplicated_isid
    if min_connections_per_core:
        params['min_connections_per_core'] = min_connections_per_core

    return client.call('set_iscsi_options', params)


def set_iscsi_discovery_auth(
        client,
        disable_chap=None,
        require_chap=None,
        mutual_chap=None,
        chap_group=None):
    """Set CHAP authentication for discovery service.

    Args:
        disable_chap: CHAP for discovery session should be disabled (optional)
        require_chap: CHAP for discovery session should be required (optional)
        mutual_chap: CHAP for discovery session should be mutual (optional)
        chap_group: Authentication group ID for discovery session (optional)

    Returns:
        True or False
    """
    params = {}

    if disable_chap:
        params['disable_chap'] = disable_chap
    if require_chap:
        params['require_chap'] = require_chap
    if mutual_chap:
        params['mutual_chap'] = mutual_chap
    if chap_group:
        params['chap_group'] = chap_group

    return client.call('set_iscsi_discovery_auth', params)


def get_iscsi_auth_groups(client):
    """Display current authentication group configuration.

    Returns:
        List of current authentication group configuration.
    """
    return client.call('get_iscsi_auth_groups')


def get_portal_groups(client):
    """Display current portal group configuration.

    Returns:
        List of current portal group configuration.
    """
    return client.call('get_portal_groups')


def get_initiator_groups(client):
    """Display current initiator group configuration.

    Returns:
        List of current initiator group configuration.
    """
    return client.call('get_initiator_groups')


def get_target_nodes(client):
    """Display target nodes.

    Returns:
        List of ISCSI target node objects.
    """
    return client.call('get_target_nodes')


def construct_target_node(
        client,
        luns,
        pg_ig_maps,
        name,
        alias_name,
        queue_depth,
        chap_group=None,
        disable_chap=None,
        require_chap=None,
        mutual_chap=None,
        header_digest=None,
        data_digest=None):
    """Add a target node.

    Args:
        luns: List of bdev_name_id_pairs, e.g. [{"bdev_name": "Malloc1", "lun_id": 1}]
        pg_ig_maps: List of pg_ig_mappings, e.g. [{"pg_tag": pg, "ig_tag": ig}]
        name: Target node name (ASCII)
        alias_name: Target node alias name (ASCII)
        queue_depth: Desired target queue depth
        chap_group: Authentication group ID for this target node
        disable_chap: CHAP authentication should be disabled for this target node
        require_chap: CHAP authentication should be required for this target node
        mutual_chap: CHAP authentication should be mutual/bidirectional
        header_digest: Header Digest should be required for this target node
        data_digest: Data Digest should be required for this target node

    Returns:
        True or False
    """
    params = {
        'name': name,
        'alias_name': alias_name,
        'pg_ig_maps': pg_ig_maps,
        'luns': luns,
        'queue_depth': queue_depth,
    }

    if chap_group:
        params['chap_group'] = chap_group
    if disable_chap:
        params['disable_chap'] = disable_chap
    if require_chap:
        params['require_chap'] = require_chap
    if mutual_chap:
        params['mutual_chap'] = mutual_chap
    if header_digest:
        params['header_digest'] = header_digest
    if data_digest:
        params['data_digest'] = data_digest
    return client.call('construct_target_node', params)


def target_node_add_lun(client, name, bdev_name, lun_id=None):
    """Add LUN to the target node.

    Args:
        name: Target node name (ASCII)
        bdev_name: bdev name
        lun_id: LUN ID (integer >= 0)

    Returns:
        True or False
    """
    params = {
        'name': name,
        'bdev_name': bdev_name,
    }
    if lun_id:
        params['lun_id'] = lun_id
    return client.call('target_node_add_lun', params)


def set_iscsi_target_node_auth(
        client,
        name,
        chap_group=None,
        disable_chap=None,
        require_chap=None,
        mutual_chap=None):
    """Set CHAP authentication for the target node.

    Args:
        name: Target node name (ASCII)
        chap_group: Authentication group ID for this target node
        disable_chap: CHAP authentication should be disabled for this target node
        require_chap: CHAP authentication should be required for this target node
        mutual_chap: CHAP authentication should be mutual/bidirectional

    Returns:
        True or False
    """
    params = {
        'name': name,
    }

    if chap_group:
        params['chap_group'] = chap_group
    if disable_chap:
        params['disable_chap'] = disable_chap
    if require_chap:
        params['require_chap'] = require_chap
    if mutual_chap:
        params['mutual_chap'] = mutual_chap
    return client.call('set_iscsi_target_node_auth', params)


def add_iscsi_auth_group(client, tag, secrets=None):
    """Add authentication group for CHAP authentication.

    Args:
        tag: Authentication group tag (unique, integer > 0).
        secrets: Array of secrets objects (optional).

    Returns:
        True or False
    """
    params = {'tag': tag}

    if secrets:
        params['secrets'] = secrets
    return client.call('add_iscsi_auth_group', params)


def delete_iscsi_auth_group(client, tag):
    """Delete an authentication group.

    Args:
        tag: Authentication group tag (unique, integer > 0)

    Returns:
        True or False
    """
    params = {'tag': tag}
    return client.call('delete_iscsi_auth_group', params)


def add_secret_to_iscsi_auth_group(client, tag, user, secret, muser=None, msecret=None):
    """Add a secret to an authentication group.

    Args:
        tag: Authentication group tag (unique, integer > 0)
        user: User name for one-way CHAP authentication
        secret: Secret for one-way CHAP authentication
        muser: User name for mutual CHAP authentication (optional)
        msecret: Secret for mutual CHAP authentication (optional)

    Returns:
        True or False
    """
    params = {'tag': tag, 'user': user, 'secret': secret}

    if muser:
        params['muser'] = muser
    if msecret:
        params['msecret'] = msecret
    return client.call('add_secret_to_iscsi_auth_group', params)


def delete_secret_from_iscsi_auth_group(client, tag, user):
    """Delete a secret from an authentication group.

    Args:
        tag: Authentication group tag (unique, integer > 0)
        user: User name for one-way CHAP authentication

    Returns:
        True or False
    """
    params = {'tag': tag, 'user': user}
    return client.call('delete_secret_from_iscsi_auth_group', params)


def delete_pg_ig_maps(client, pg_ig_maps, name):
    """Delete PG-IG maps from the target node.

    Args:
        pg_ig_maps: List of pg_ig_mappings, e.g. [{"pg_tag": pg, "ig_tag": ig}]
        name: Target node alias name (ASCII)

    Returns:
        True or False
    """
    params = {
        'name': name,
        'pg_ig_maps': pg_ig_maps,
    }
    return client.call('delete_pg_ig_maps', params)


def add_pg_ig_maps(client, pg_ig_maps, name):
    """Add PG-IG maps to the target node.

    Args:
        pg_ig_maps: List of pg_ig_mappings, e.g. [{"pg_tag": pg, "ig_tag": ig}]
        name: Target node alias name (ASCII)

    Returns:
        True or False
    """
    params = {
        'name': name,
        'pg_ig_maps': pg_ig_maps,
    }
    return client.call('add_pg_ig_maps', params)


def add_portal_group(client, portals, tag):
    """Add a portal group.

    Args:
        portals: List of portals, e.g. [{'host': ip, 'port': port}] or [{'host': ip, 'port': port, 'cpumask': cpumask}]
        tag: Initiator group tag (unique, integer > 0)

    Returns:
        True or False
    """
    params = {'tag': tag, 'portals': portals}
    return client.call('add_portal_group', params)


def add_initiator_group(client, tag, initiators, netmasks):
    """Add an initiator group.

    Args:
        tag: Initiator group tag (unique, integer > 0)
        initiators: List of initiator hostnames or IP addresses, e.g. ["127.0.0.1","192.168.200.100"]
        netmasks: List of initiator netmasks, e.g. ["255.255.0.0","255.248.0.0"]

    Returns:
        True or False
    """
    params = {'tag': tag, 'initiators': initiators, 'netmasks': netmasks}
    return client.call('add_initiator_group', params)


def add_initiators_to_initiator_group(
        client,
        tag,
        initiators=None,
        netmasks=None):
    """Add initiators to an existing initiator group.

    Args:
        tag: Initiator group tag (unique, integer > 0)
        initiators: List of initiator hostnames or IP addresses, e.g. ["127.0.0.1","192.168.200.100"]
        netmasks: List of initiator netmasks, e.g. ["255.255.0.0","255.248.0.0"]

    Returns:
        True or False
    """
    params = {'tag': tag}

    if initiators:
        params['initiators'] = initiators
    if netmasks:
        params['netmasks'] = netmasks
    return client.call('add_initiators_to_initiator_group', params)


def delete_initiators_from_initiator_group(
        client, tag, initiators=None, netmasks=None):
    """Delete initiators from an existing initiator group.

    Args:
        tag: Initiator group tag (unique, integer > 0)
        initiators: List of initiator hostnames or IP addresses, e.g. ["127.0.0.1","192.168.200.100"]
        netmasks: List of initiator netmasks, e.g. ["255.255.0.0","255.248.0.0"]

    Returns:
        True or False
    """
    params = {'tag': tag}

    if initiators:
        params['initiators'] = initiators
    if netmasks:
        params['netmasks'] = netmasks
    return client.call('delete_initiators_from_initiator_group', params)


def delete_target_node(client, target_node_name):
    """Delete a target node.

    Args:
        target_node_name: Target node name to be deleted. Example: iqn.2016-06.io.spdk:disk1.

    Returns:
        True or False
    """
    params = {'name': target_node_name}
    return client.call('delete_target_node', params)


def delete_portal_group(client, tag):
    """Delete a portal group.

    Args:
        tag: Portal group tag (unique, integer > 0)

    Returns:
        True or False
    """
    params = {'tag': tag}
    return client.call('delete_portal_group', params)


def delete_initiator_group(client, tag):
    """Delete an initiator group.

    Args:
        tag: Initiator group tag (unique, integer > 0)

    Returns:
        True or False
    """
    params = {'tag': tag}
    return client.call('delete_initiator_group', params)


def get_iscsi_connections(client):
    """Display iSCSI connections.

    Returns:
        List of iSCSI connection.
    """
    return client.call('get_iscsi_connections')


def get_iscsi_global_params(client):
    """Display iSCSI global parameters.

    Returns:
        List of iSCSI global parameter.
    """
    return client.call('get_iscsi_global_params')


def get_scsi_devices(client):
    """Display SCSI devices.

    Returns:
        List of SCSI device.
    """
    return client.call('get_scsi_devices')