summaryrefslogtreecommitdiffstats
path: root/src/spdk/scripts/rpc/__init__.py
blob: f764d7ae5657cfe0737fde62542bd2dfd06b7886 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import json
import os
import sys

from io import IOBase as io

from . import app
from . import bdev
from . import blobfs
from . import env_dpdk
from . import idxd
from . import ioat
from . import iscsi
from . import log
from . import lvol
from . import nbd
from . import net
from . import notify
from . import nvme
from . import nvmf
from . import pmem
from . import subsystem
from . import trace
from . import vhost
from . import vmd
from . import sock
from . import client as rpc_client
from .helpers import deprecated_alias


@deprecated_alias('start_subsystem_init')
def framework_start_init(client):
    """Start initialization of subsystems"""
    return client.call('framework_start_init')


@deprecated_alias('wait_subsystem_init')
def framework_wait_init(client):
    """Block until subsystems have been initialized"""
    return client.call('framework_wait_init')


@deprecated_alias("get_rpc_methods")
def rpc_get_methods(client, current=None, include_aliases=None):
    """Get list of supported RPC methods.
    Args:
        current: Get list of RPC methods only callable in the current state.
        include_aliases: Include aliases in the list with RPC methods.
    """
    params = {}

    if current:
        params['current'] = current
    if include_aliases:
        params['include_aliases'] = include_aliases

    return client.call('rpc_get_methods', params)


@deprecated_alias("get_spdk_version")
def spdk_get_version(client):
    """Get SPDK version"""
    return client.call('spdk_get_version')


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):
    """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.
    """
    config = {
        'subsystems': []
    }

    for elem in client.call('framework_get_subsystems'):
        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:
        framework_start_init(client)
        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['method'], elem['params'])
                config.remove(elem)
                allowed_found = True

            if not config:
                subsystems.remove(subsystem)

        if 'framework_start_init' in allowed_methods:
            framework_start_init(client)
            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['method'], elem['params'])
        config.remove(elem)

    if config:
        print("Some configs were skipped because they cannot be called in the current RPC state.")