Commit e942c023 authored by Boris Glimcher's avatar Boris Glimcher Committed by Jim Harris
Browse files

python/rpc: move functions out of __init__.py



Per Python best practices, __init__.py should not contain functional code.
Moved existing functions to a dedicated module for better structure and clarity.

Change-Id: I3433a680bbcf19f0d2af075d4c1c51eda36af0f2
Signed-off-by: default avatarBoris Glimcher <Boris.Glimcher@emc.com>
Reviewed-on: https://review.spdk.io/c/spdk/spdk/+/26829


Reviewed-by: default avatarTomasz Zawadzki <tomasz@tzawadzki.com>
Reviewed-by: default avatarKarol Latecki <karol.latecki@nutanix.com>
Reviewed-by: default avatarJim Harris <jim.harris@nvidia.com>
Tested-by: default avatarSPDK Automated Test System <spdkbot@gmail.com>
parent 0e571138
Loading
Loading
Loading
Loading
+13 −14
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@
#

import sys
import spdk.rpc as rpc  # noqa
from spdk.rpc import config
from spdk.rpc.client import print_dict, print_json, print_array  # noqa


@@ -19,7 +19,7 @@ def add_parser(subparsers):
    p.set_defaults(func=spdk_get_version)

    def save_config(args):
        rpc.save_config(args.client,
        config.save_config(args.client,
                           fd=sys.stdout,
                           indent=args.indent,
                           subsystems=args.subsystems)
@@ -32,7 +32,7 @@ def add_parser(subparsers):
    p.set_defaults(func=save_config)

    def load_config(args):
        rpc.load_config(args.client,
        config.load_config(args.client,
                           fd=args.json_conf,
                           include_aliases=args.include_aliases)

@@ -42,7 +42,7 @@ def add_parser(subparsers):
    p.set_defaults(func=load_config)

    def save_subsystem_config(args):
        rpc.save_subsystem_config(args.client,
        config.save_subsystem_config(args.client,
                                     fd=sys.stdout,
                                     indent=args.indent,
                                     name=args.name)
@@ -55,8 +55,7 @@ def add_parser(subparsers):
    p.set_defaults(func=save_subsystem_config)

    def load_subsystem_config(args):
        rpc.load_subsystem_config(args.client,
                                  fd=args.json_conf)
        config.load_subsystem_config(args.client, fd=args.json_conf)

    p = subparsers.add_parser('load_subsystem_config', help="""Configure SPDK subsystem using JSON RPC.""")
    p.add_argument('-j', '--json-conf', help='Valid JSON configuration', default=sys.stdin)
+1 −168
Original line number Diff line number Diff line
#  SPDX-License-Identifier: BSD-3-Clause
#  Copyright (C) 2017 Intel Corporation.
#  Copyright (C) 2025 Dell Inc, or its subsidiaries.
#  All rights reserved.

import json
import os
import sys

from io import IOBase as io

from . import client as rpc_client


def _json_dump(config, fd, indent):
    if indent is None:
        indent = 2
    elif indent < 0:
        indent = None
    json.dump(config, fd, indent=indent)
    fd.write('\n')


def _json_load(j):
    if j == sys.stdin or isinstance(j, io):
        json_conf = json.load(j)
    elif os.path.exists(j):
        with open(j, "r") as j:
            json_conf = json.load(j)
    else:
        json_conf = json.loads(j)
    return json_conf


def save_config(client, fd, indent=2, subsystems=None):
    """Write current (live) configuration of SPDK subsystems and targets to stdout.
    Args:
        fd: opened file descriptor where data will be saved
        indent: Indent level. Value less than 0 mean compact mode.
            Default indent level is 2.
        subsystems: subsystems (and their dependencies) to save
    """
    config = {
        'subsystems': []
    }

    subsystems_json = client.call('framework_get_subsystems')

    # Build a dictionary of all subsystems to their fully expanded set of
    # dependencies.
    dependencies = dict()
    for elem in subsystems_json:
        subsystem = elem['subsystem']
        dependencies[subsystem] = {subsystem}
        for d in elem['depends_on']:
            dependencies[subsystem].update(dependencies[d])

    # Build a set of all of the subsystems to print based on the
    # subsystems parameter.
    to_print = set()
    if subsystems is None:
        to_print = dependencies.keys()
    else:
        for s in subsystems.split(','):
            to_print.update(dependencies[s])

    def _print(x): return x['subsystem'] in to_print
    for elem in filter(_print, subsystems_json):
        cfg = {
            'subsystem': elem['subsystem'],
            'config': client.call('framework_get_config', {"name": elem['subsystem']})
        }
        config['subsystems'].append(cfg)

    _json_dump(config, fd, indent)


def load_config(client, fd, include_aliases=False):
    """Configure SPDK subsystems and targets using JSON RPC read from stdin.
    Args:
        fd: opened file descriptor where data will be taken from
    """
    json_config = _json_load(fd)

    # remove subsystems with no config
    subsystems = json_config['subsystems']
    for subsystem in list(subsystems):
        if not subsystem['config']:
            subsystems.remove(subsystem)

    # check if methods in the config file are known
    allowed_methods = client.call('rpc_get_methods', {'include_aliases': include_aliases})
    if not subsystems and 'framework_start_init' in allowed_methods:
        client.framework_start_init()
        return

    for subsystem in list(subsystems):
        config = subsystem['config']
        for elem in list(config):
            if 'method' not in elem or elem['method'] not in allowed_methods:
                raise rpc_client.JSONRPCException("Unknown method was included in the config file")

    while subsystems:
        allowed_methods = client.call('rpc_get_methods', {'current': True,
                                                          'include_aliases': include_aliases})
        allowed_found = False

        for subsystem in list(subsystems):
            config = subsystem['config']
            for elem in list(config):
                if 'method' not in elem or elem['method'] not in allowed_methods:
                    continue

                client.call(**elem)
                config.remove(elem)
                allowed_found = True

            if not config:
                subsystems.remove(subsystem)

        if 'framework_start_init' in allowed_methods:
            client.framework_start_init()
            allowed_found = True

        if not allowed_found:
            break

    if subsystems:
        print("Some configs were skipped because the RPC state that can call them passed over.")


def save_subsystem_config(client, fd, indent=2, name=None):
    """Write current (live) configuration of SPDK subsystem to stdout.
    Args:
        fd: opened file descriptor where data will be saved
        indent: Indent level. Value less than 0 mean compact mode.
            Default is indent level 2.
    """
    cfg = {
        'subsystem': name,
        'config': client.call('framework_get_config', {"name": name})
    }

    _json_dump(cfg, fd, indent)


def load_subsystem_config(client, fd):
    """Configure SPDK subsystem using JSON RPC read from stdin.
    Args:
        fd: opened file descriptor where data will be taken from
    """
    subsystem = _json_load(fd)

    if not subsystem['config']:
        return

    allowed_methods = client.call('rpc_get_methods')
    config = subsystem['config']
    for elem in list(config):
        if 'method' not in elem or elem['method'] not in allowed_methods:
            raise rpc_client.JSONRPCException("Unknown method was included in the config file")

    allowed_methods = client.call('rpc_get_methods', {'current': True})
    for elem in list(config):
        if 'method' not in elem or elem['method'] not in allowed_methods:
            continue

        client.call(**elem)
        config.remove(elem)

    if config:
        print("Some configs were skipped because they cannot be called in the current RPC state.")
+172 −0
Original line number Diff line number Diff line
#  SPDX-License-Identifier: BSD-3-Clause
#  Copyright (C) 2017 Intel Corporation.
#  Copyright (C) 2025 Dell Inc, or its subsidiaries.
#  All rights reserved.

import json
import os
import sys

from io import IOBase as io

from . import client as rpc_client


def _json_dump(config, fd, indent):
    if indent is None:
        indent = 2
    elif indent < 0:
        indent = None
    json.dump(config, fd, indent=indent)
    fd.write('\n')


def _json_load(j):
    if j == sys.stdin or isinstance(j, io):
        json_conf = json.load(j)
    elif os.path.exists(j):
        with open(j, "r") as j:
            json_conf = json.load(j)
    else:
        json_conf = json.loads(j)
    return json_conf


def save_config(client, fd, indent=2, subsystems=None):
    """Write current (live) configuration of SPDK subsystems and targets to stdout.
    Args:
        fd: opened file descriptor where data will be saved
        indent: Indent level. Value less than 0 mean compact mode.
            Default indent level is 2.
        subsystems: subsystems (and their dependencies) to save
    """
    config = {
        'subsystems': []
    }

    subsystems_json = client.call('framework_get_subsystems')

    # Build a dictionary of all subsystems to their fully expanded set of
    # dependencies.
    dependencies = dict()
    for elem in subsystems_json:
        subsystem = elem['subsystem']
        dependencies[subsystem] = {subsystem}
        for d in elem['depends_on']:
            dependencies[subsystem].update(dependencies[d])

    # Build a set of all of the subsystems to print based on the
    # subsystems parameter.
    to_print = set()
    if subsystems is None:
        to_print = dependencies.keys()
    else:
        for s in subsystems.split(','):
            to_print.update(dependencies[s])

    def _print(x): return x['subsystem'] in to_print
    for elem in filter(_print, subsystems_json):
        cfg = {
            'subsystem': elem['subsystem'],
            'config': client.call('framework_get_config', {"name": elem['subsystem']})
        }
        config['subsystems'].append(cfg)

    _json_dump(config, fd, indent)


def load_config(client, fd, include_aliases=False):
    """Configure SPDK subsystems and targets using JSON RPC read from stdin.
    Args:
        fd: opened file descriptor where data will be taken from
    """
    json_config = _json_load(fd)

    # remove subsystems with no config
    subsystems = json_config['subsystems']
    for subsystem in list(subsystems):
        if not subsystem['config']:
            subsystems.remove(subsystem)

    # check if methods in the config file are known
    allowed_methods = client.call('rpc_get_methods', {'include_aliases': include_aliases})
    if not subsystems and 'framework_start_init' in allowed_methods:
        client.framework_start_init()
        return

    for subsystem in list(subsystems):
        config = subsystem['config']
        for elem in list(config):
            if 'method' not in elem or elem['method'] not in allowed_methods:
                raise rpc_client.JSONRPCException("Unknown method was included in the config file")

    while subsystems:
        allowed_methods = client.call('rpc_get_methods', {'current': True,
                                                          'include_aliases': include_aliases})
        allowed_found = False

        for subsystem in list(subsystems):
            config = subsystem['config']
            for elem in list(config):
                if 'method' not in elem or elem['method'] not in allowed_methods:
                    continue

                client.call(**elem)
                config.remove(elem)
                allowed_found = True

            if not config:
                subsystems.remove(subsystem)

        if 'framework_start_init' in allowed_methods:
            client.framework_start_init()
            allowed_found = True

        if not allowed_found:
            break

    if subsystems:
        print("Some configs were skipped because the RPC state that can call them passed over.")


def save_subsystem_config(client, fd, indent=2, name=None):
    """Write current (live) configuration of SPDK subsystem to stdout.
    Args:
        fd: opened file descriptor where data will be saved
        indent: Indent level. Value less than 0 mean compact mode.
            Default is indent level 2.
    """
    cfg = {
        'subsystem': name,
        'config': client.call('framework_get_config', {"name": name})
    }

    _json_dump(cfg, fd, indent)


def load_subsystem_config(client, fd):
    """Configure SPDK subsystem using JSON RPC read from stdin.
    Args:
        fd: opened file descriptor where data will be taken from
    """
    subsystem = _json_load(fd)

    if not subsystem['config']:
        return

    allowed_methods = client.call('rpc_get_methods')
    config = subsystem['config']
    for elem in list(config):
        if 'method' not in elem or elem['method'] not in allowed_methods:
            raise rpc_client.JSONRPCException("Unknown method was included in the config file")

    allowed_methods = client.call('rpc_get_methods', {'current': True})
    for elem in list(config):
        if 'method' not in elem or elem['method'] not in allowed_methods:
            continue

        client.call(**elem)
        config.remove(elem)

    if config:
        print("Some configs were skipped because they cannot be called in the current RPC state.")
+5 −5
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
from .ui_node import UINode, UIBdevs, UILvolStores, UIVhosts
from .ui_node_nvmf import UINVMf
from .ui_node_iscsi import UIISCSI
from .. import rpc
from ..rpc import config
from ..rpc.cmd_parser import strip_globals, apply_defaults, group_as, remove_null
from functools import wraps

@@ -86,19 +86,19 @@ class UIRoot(UINode):

    def ui_command_load_config(self, filename):
        with open(filename, "r") as fd:
            rpc.load_config(self.client, fd)
            config.load_config(self.client, fd)

    def ui_command_load_subsystem_config(self, filename):
        with open(filename, "r") as fd:
            rpc.load_subsystem_config(self.client, fd)
            config.load_subsystem_config(self.client, fd)

    def ui_command_save_config(self, filename, indent=2):
        with open(filename, "w") as fd:
            rpc.save_config(self.client, fd, indent)
            config.save_config(self.client, fd, indent)

    def ui_command_save_subsystem_config(self, filename, subsystem, indent=2):
        with open(filename, "w") as fd:
            rpc.save_subsystem_config(self.client, fd, indent, subsystem)
            config.save_subsystem_config(self.client, fd, indent, subsystem)

    def rpc_get_methods(self, current=False):
        return self.client.rpc_get_methods(current=current)