Revision daff2f81 lib/build/sphinx_ext.py
b/lib/build/sphinx_ext.py | ||
---|---|---|
58 | 58 |
from ganeti import _autoconf |
59 | 59 |
|
60 | 60 |
import ganeti.rapi.rlib2 # pylint: disable=W0611 |
61 |
import ganeti.rapi.connector # pylint: disable=W0611 |
|
61 | 62 |
|
62 | 63 |
|
63 | 64 |
#: Regular expression for man page names |
... | ... | |
65 | 66 |
|
66 | 67 |
_TAB_WIDTH = 2 |
67 | 68 |
|
69 |
RAPI_URI_ENCODE_RE = re.compile("[^_a-z0-9]+", re.I) |
|
70 |
|
|
71 |
RAPI_ACCESS_TEXT = { |
|
72 |
rapi.RAPI_ACCESS_WRITE: "write", |
|
73 |
rapi.RAPI_ACCESS_READ: "read", |
|
74 |
} |
|
75 |
|
|
76 |
assert frozenset(RAPI_ACCESS_TEXT.keys()) == rapi.RAPI_ACCESS_ALL |
|
77 |
|
|
68 | 78 |
|
69 | 79 |
class ReSTError(Exception): |
70 | 80 |
"""Custom class for generating errors in Sphinx. |
... | ... | |
425 | 435 |
options=options, content=content) |
426 | 436 |
|
427 | 437 |
|
438 |
def _EncodeRapiResourceLink(method, uri): |
|
439 |
"""Encodes a RAPI resource URI for use as a link target. |
|
440 |
|
|
441 |
""" |
|
442 |
parts = [RAPI_URI_ENCODE_RE.sub("-", uri.lower()).strip("-")] |
|
443 |
|
|
444 |
if method is not None: |
|
445 |
parts.append(method.lower()) |
|
446 |
|
|
447 |
return "rapi-res-%s" % "+".join(filter(None, parts)) |
|
448 |
|
|
449 |
|
|
450 |
def _MakeRapiResourceLink(method, uri): |
|
451 |
"""Generates link target name for RAPI resource. |
|
452 |
|
|
453 |
""" |
|
454 |
if uri in ["/", "/2"]: |
|
455 |
# Don't link these |
|
456 |
return None |
|
457 |
|
|
458 |
elif uri == "/version": |
|
459 |
return _EncodeRapiResourceLink(method, uri) |
|
460 |
|
|
461 |
elif uri.startswith("/2/"): |
|
462 |
return _EncodeRapiResourceLink(method, uri[len("/2/"):]) |
|
463 |
|
|
464 |
else: |
|
465 |
raise ReSTError("Unhandled URI '%s'" % uri) |
|
466 |
|
|
467 |
|
|
468 |
def _BuildRapiAccessTable(res): |
|
469 |
"""Build a table with access permissions needed for all RAPI resources. |
|
470 |
|
|
471 |
""" |
|
472 |
for (uri, handler) in utils.NiceSort(res.items(), key=compat.fst): |
|
473 |
reslink = _MakeRapiResourceLink(None, uri) |
|
474 |
if not reslink: |
|
475 |
# No link was generated |
|
476 |
continue |
|
477 |
|
|
478 |
yield ":ref:`%s <%s>`" % (uri, reslink) |
|
479 |
|
|
480 |
for (method, op_attr, _, _) in sorted(rapi.baserlib.OPCODE_ATTRS): |
|
481 |
if not (hasattr(handler, method) or hasattr(handler, op_attr)): |
|
482 |
# Handler doesn't support method |
|
483 |
continue |
|
484 |
|
|
485 |
access = rapi.baserlib.GetHandlerAccess(handler, method) |
|
486 |
|
|
487 |
perms = map(RAPI_ACCESS_TEXT.__getitem__, access) |
|
488 |
|
|
489 |
if not perms: |
|
490 |
perms.append("*everyone*") |
|
491 |
|
|
492 |
yield (" | :ref:`%s <%s>`: %s" % |
|
493 |
(method, _MakeRapiResourceLink(method, uri), |
|
494 |
utils.CommaJoin(perms))) |
|
495 |
|
|
496 |
|
|
497 |
class RapiAccessTable(s_compat.Directive): |
|
498 |
"""Custom directive to generate table of all RAPI resources. |
|
499 |
|
|
500 |
See also <http://docutils.sourceforge.net/docs/howto/rst-directives.html>. |
|
501 |
|
|
502 |
""" |
|
503 |
has_content = False |
|
504 |
required_arguments = 0 |
|
505 |
optional_arguments = 0 |
|
506 |
final_argument_whitespace = False |
|
507 |
option_spec = {} |
|
508 |
|
|
509 |
def run(self): |
|
510 |
resources = \ |
|
511 |
rapi.connector.GetHandlers("[node_name]", "[instance_name]", |
|
512 |
"[group_name]", "[network_name]", "[job_id]", |
|
513 |
"[disk_index]", "[resource]", |
|
514 |
translate=self._TranslateResourceUri) |
|
515 |
|
|
516 |
include_text = "\n".join(_BuildRapiAccessTable(resources)) |
|
517 |
|
|
518 |
# Inject into state machine |
|
519 |
include_lines = docutils.statemachine.string2lines(include_text, _TAB_WIDTH, |
|
520 |
convert_whitespace=1) |
|
521 |
self.state_machine.insert_input(include_lines, self.__class__.__name__) |
|
522 |
|
|
523 |
return [] |
|
524 |
|
|
525 |
@classmethod |
|
526 |
def _TranslateResourceUri(cls, *args): |
|
527 |
"""Translates a resource URI for use in documentation. |
|
528 |
|
|
529 |
@see: L{rapi.connector.GetHandlers} |
|
530 |
|
|
531 |
""" |
|
532 |
return "".join(map(cls._UriPatternToString, args)) |
|
533 |
|
|
534 |
@staticmethod |
|
535 |
def _UriPatternToString(value): |
|
536 |
"""Converts L{rapi.connector.UriPattern} to strings. |
|
537 |
|
|
538 |
""" |
|
539 |
if isinstance(value, rapi.connector.UriPattern): |
|
540 |
return value.content |
|
541 |
else: |
|
542 |
return value |
|
543 |
|
|
544 |
|
|
428 | 545 |
def setup(app): |
429 | 546 |
"""Sphinx extension callback. |
430 | 547 |
|
... | ... | |
434 | 551 |
app.add_directive("opcode_result", OpcodeResult) |
435 | 552 |
app.add_directive("pyassert", PythonAssert) |
436 | 553 |
app.add_role("pyeval", PythonEvalRole) |
554 |
app.add_directive("rapi_access_table", RapiAccessTable) |
|
437 | 555 |
|
438 | 556 |
app.add_config_value("enable_manpages", False, True) |
439 | 557 |
app.add_role("manpage", _ManPageRole) |
Also available in: Unified diff