Skip to content

Commit

Permalink
doc/api: Add a generated reference of all mon commands.
Browse files Browse the repository at this point in the history
Generate a ReST document which contains all mon commands.

Signed-off-by: Sebastian Wagner <[email protected]>
  • Loading branch information
sebastian-philipp committed May 5, 2020
1 parent 8098f11 commit 4733080
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 0 deletions.
4 changes: 4 additions & 0 deletions admin/build-doc
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ mkdir -p $vdir/lib
export LD_LIBRARY_PATH="$vdir/lib"
export PYTHONPATH=$TOPDIR/src/pybind


$vdir/bin/python $TOPDIR/doc/scripts/gen_mon_command_api.py > $TOPDIR/doc/api/mon_command_api.rst


# FIXME(sileht): I dunno how to pass the include-dirs correctly with pip
# for build_ext step, it should be:
# --global-option=build_ext --global-option="--cython-include-dirs $TOPDIR/src/pybind/rados/"
Expand Down
3 changes: 3 additions & 0 deletions admin/doc-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ Cython
prettytable
sphinx-autodoc-typehints
typed-ast
pcpp
-e../src/python-common
Jinja2
1 change: 1 addition & 0 deletions doc/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/overview.png
/object_store.png
/api/mon_command_api.rst
12 changes: 12 additions & 0 deletions doc/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ Ceph Object Store APIs
- See `Swift-compatible API`_.
- See `Admin Ops API`_.

Ceph MON Command API
====================

- See `Mon command API`_.

.. _S3-compatible API: ../radosgw/s3/
.. _Swift-compatible API: ../radosgw/swift/
.. _Admin Ops API: ../radosgw/adminops
.. _Mon command API: mon_command_api


.. toctree::
:hidden:

mon_command_api
206 changes: 206 additions & 0 deletions doc/scripts/gen_mon_command_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import os
import json
import sys
from subprocess import check_output

from jinja2 import Template


class Flags:
NOFORWARD = (1 << 0)
OBSOLETE = (1 << 1)
DEPRECATED = (1 << 2)
MGR = (1 << 3)
POLL = (1 << 4)
HIDDEN = (1 << 5)

VALS = {
NOFORWARD: 'no_forward',
OBSOLETE: 'obsolete',
DEPRECATED: 'deprecated',
MGR: 'mgr',
POLL: 'poll',
HIDDEN: 'hidden',
}

def __init__(self, fs):
self.fs = fs

def __contains__(self, other):
return other in str(self)

def __str__(self):
keys = Flags.VALS.keys()
es = {Flags.VALS[k] for k in keys if self.fs & k == k}
return ', '.join(sorted(es))

def __bool__(self):
return bool(str(self))


class CmdParam(object):
t = {
'CephInt': 'int',
'CephString': 'str',
'CephChoices': 'str',
'CephPgid': 'str',
'CephOsdName': 'str',
'CephPoolname': 'str',
'CephObjectname': 'str',
'CephUUID': 'str',
'CephEntityAddr': 'str',
'CephIPAddr': 'str',
'CephName': 'str',
'CephBool': 'bool',
'CephFloat': 'float',
'CephFilepath': 'str',
}

bash_example = {
'CephInt': '1',
'CephString': 'string',
'CephChoices': 'choice',
'CephPgid': '0',
'CephOsdName': 'osd.0',
'CephPoolname': 'poolname',
'CephObjectname': 'objectname',
'CephUUID': 'uuid',
'CephEntityAddr': 'entityaddr',
'CephIPAddr': '0.0.0.0',
'CephName': 'name',
'CephBool': 'true',
'CephFloat': '0.0',
'CephFilepath': '/path/to/file',
}

def __init__(self, type, name, who=None, n=None, req=True, range=None, strings=None,
goodchars=None):
self.type = type
self.name = name
self.who = who
self.n = n == 'N'
self.req = req != 'false'
self.range = range.split('|') if range else []
self.strings = strings.split('|') if strings else []
self.goodchars = goodchars

assert who == None

def help(self):
advanced = []
if self.type != 'CephString':
advanced.append(self.type + ' ')
if self.range:
advanced.append('range= ``{}`` '.format('..'.join(self.range)))
if self.strings:
advanced.append('strings=({}) '.format(' '.join(self.strings)))
if self.goodchars:
advanced.append('goodchars= ``{}`` '.format(self.goodchars))
if self.n:
advanced.append('(can be repeated)')

advanced = advanced or ["(string)"]
return ' '.join(advanced)

def mk_example_value(self):
if self.type == 'CephChoices' and self.strings:
return self.strings[0]
if self.range:
return self.range[0]
return CmdParam.bash_example[self.type]

def mk_bash_example(self, simple):
val = self.mk_example_value()

if self.type == 'CephBool':
return '--' + self.name
if simple:
if self.type == "CephChoices" and self.strings:
return val
elif self.type == "CephString" and self.name != 'who':
return 'my_' + self.name
else:
return CmdParam.bash_example[self.type]
else:
return '--{}={}'.format(self.name, val)


class CmdCommand(object):
def __init__(self, sig, desc, module=None, perm=None, flags=0, poll=None):
self.sig = [s for s in sig if isinstance(s, str)]
self.params = sorted([CmdParam(**s) for s in sig if not isinstance(s, str)],
key=lambda p: p.req, reverse=True)
self.help = desc
self.module = module
self.perm = perm
self.flags = Flags(flags)
self.needs_overload = False

def prefix(self):
return ' '.join(self.sig)

def is_reasonably_simple(self):
if len(self.params) > 3:
return False
if any(p.n for p in self.params):
return False
return True

def mk_bash_example(self):
simple = self.is_reasonably_simple()
line = ' '.join(['ceph', self.prefix()] + [p.mk_bash_example(simple) for p in self.params])
return line


tpl = '''
.. This file is automatically generated. do not modify
{% for command in commands %}
{{ command.prefix() }}
{{ command.prefix() | length * '^' }}
{{ command.help | wordwrap(70)}}
Example command:
.. code-block:: bash
{{ command.mk_bash_example() }}
{% if command.params %}
Parameters:
{% for param in command.params %}* **{{param.name}}**: {{ param.help() | wordwrap(70) | indent(2) }}
{% endfor %}{% endif %}
Ceph Module:
* *{{ command.module }}*
Required Permissions:
* *{{ command.perm }}*
{% if command.flags %}Command Flags:
* *{{ command.flags }}*
{% endif %}
{% endfor %}
'''

def mk_sigs(all):
sigs = [CmdCommand(**e) for e in all]
sigs = [s for s in sigs if 'hidden' not in s.flags]
sigs = sorted(sigs, key=lambda f: f.sig)


tm = Template(tpl)
msg = tm.render(commands=list(sigs))

print(msg)


if __name__ == '__main__':
script_dir = os.path.dirname(os.path.realpath(__file__))
commands = json.loads(check_output([sys.executable, script_dir + '/../../src/script/gen_static_command_descriptions.py']))
mk_sigs(commands)
4 changes: 4 additions & 0 deletions src/script/gen_static_command_descriptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ def cmd_to_sig(cmd):
def list_mgr_module(m_name):
sys.modules['rbd'] = mock.Mock()
sys.modules['cephfs'] = mock.Mock()
sys.modules['dateutil'] = mock.Mock()
sys.modules['dateutil.parser'] = mock.Mock()

# make dashboard happy
sys.modules['OpenSSL'] = mock.Mock()
Expand All @@ -51,6 +53,8 @@ def list_mgr_module(m_name):
sys.modules['rook.rook_client'] = mock.Mock()
sys.modules['rook.rook_client.ceph'] = mock.Mock()

sys.modules['cherrypy'] = mock.Mock(__version__="3.2.3")

# make restful happy:
sys.modules['pecan'] = mock.Mock()
sys.modules['pecan.rest'] = mock.Mock()
Expand Down

0 comments on commit 4733080

Please sign in to comment.