Revision daff2f81

b/doc/rapi.rst
2340 2340
Returns the remote API version. Ganeti 1.2 returned ``1`` and Ganeti 2.0
2341 2341
returns ``2``.
2342 2342

  
2343

  
2344
Access permissions
2345
------------------
2346

  
2347
The following list describes the access permissions required for each
2348
resource. See :ref:`rapi-users` for more details.
2349

  
2350
.. rapi_access_table::
2351

  
2352

  
2343 2353
.. vim: set textwidth=72 :
2344 2354
.. Local Variables:
2345 2355
.. mode: rst
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