summaryrefslogtreecommitdiffstats
path: root/src/pybind/ceph_mgr_repl.py
blob: 159abdc99a5e4409b316fcd013f88201fa05a466 (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
#!/usr/bin/python3
# -*- mode:python -*-
# vim: ts=4 sw=4 smarttab expandtab

__all__ = ['ConsoleOptions', 'MgrModuleInterpreter']

import readline
import sys
from code import InteractiveConsole
from collections import namedtuple
from pathlib import Path

from ceph_argparse import json_command


ConsoleOptions = namedtuple('ConsoleOptions',
                            ['name', 'conffile', 'prefix', 'timeout'])


class MgrModuleInteractiveConsole(InteractiveConsole):
    def __init__(self, rados, opt, filename="<console>"):
        super().__init__(filename)
        self.cmd_prefix = opt.prefix
        self.timeout = opt.timeout
        self.cluster = rados.Rados(name=opt.name,
                                   conffile=opt.conffile)
        self.cluster.connect(timeout=opt.timeout)

    def _do_runsource(self, source):
        ret, buf, s = json_command(self.cluster,
                                   prefix=self.cmd_prefix,
                                   target=('mon-mgr',),
                                   inbuf=source.encode(),
                                   timeout=self.timeout)
        if ret == 0:
            # TODO: better way to encode the outputs
            sys.stdout.write(buf.decode())
            sys.stderr.write(s)
        else:
            # needs more
            self.write("the input is not complete")

    def runsource(self, source, filename='<input>', symbol='single'):
        try:
            # just validate the syntax
            code = self.compile(source, filename, symbol)
        except (OverflowError, SyntaxError, ValueError):
            # Case 1
            self.showsyntaxerror(filename)
            return False

        if code is None:
            # Case 2
            return True

        # Case 3
        self._do_runsource(source)
        return False

    def runcode(self, code):
        # code object cannot be pickled
        raise NotImplementedError()


def show_env():
    prog = Path(__file__).resolve()
    ceph_dir = prog.parents[2]
    python_path = ':'.join([f'{ceph_dir}/src/pybind',
                            f'{ceph_dir}/build/lib/cython_modules/lib.3',
                            f'{ceph_dir}/src/python-common',
                            '$PYTHONPATH'])
    ld_library_path = ':'.join([f'{ceph_dir}/build/lib',
                                '$LD_LIBRARY_PATH'])
    return f'''
    $ export PYTHONPATH={python_path}
    $ export LD_LIBRARY_PATH={ld_library_path}'''.strip('\n')


def main():
    import argparse
    try:
        import rados
    except ImportError:
        print(f'''Unable to import rados python binding.
Please set the environment variables first:
{show_env()}''',
              file=sys.stderr)
        exit(1)

    prog = Path(__file__).name
    epilog = f'''Usage:
    {prog} -c "print(mgr.release_name)"'''
    parser = argparse.ArgumentParser(epilog=epilog)
    parser.add_argument('--name', action='store',
                        default='client.admin',
                        help='user name for connecting to cluster')
    parser.add_argument('--conffile', action='store',
                        default=rados.Rados.DEFAULT_CONF_FILES,
                        help='path to ceph.conf')
    parser.add_argument('--prefix', action='store',
                        default='mgr self-test eval',
                        help='command prefix for eval the source')
    parser.add_argument('--timeout', action='store',
                        type=int,
                        default=10,
                        help='timeout in seconds')
    parser.add_argument('--show-env', action='store_true',
                        help='show instructions to set environment variables')
    group = parser.add_mutually_exclusive_group()
    group.add_argument('-c', action='store',
                       help='optional statement',
                       dest='command')
    group.add_argument('script', nargs='?', type=argparse.FileType('r'))
    args = parser.parse_args()
    options = ConsoleOptions(name=args.name,
                             conffile=args.conffile,
                             prefix=args.prefix,
                             timeout=args.timeout)
    console = MgrModuleInteractiveConsole(rados, options)
    if args.show_env:
        print(show_env())
    elif args.command:
        console.runsource(args.command)
    elif args.script:
        console.runsource(args.script.read())
    else:
        sys.ps1 = f'[{args.prefix}] >>> '
        console.interact()


if __name__ == '__main__':
    main()