Statistics
| Branch: | Tag: | Revision:

root / autotools / build-rpc @ f2bca93e

History | View | Annotate | Download (5.3 kB)

1 d5a2a550 Michael Hanselmann
#!/usr/bin/python
2 d5a2a550 Michael Hanselmann
#
3 d5a2a550 Michael Hanselmann
4 d5a2a550 Michael Hanselmann
# Copyright (C) 2011 Google Inc.
5 d5a2a550 Michael Hanselmann
#
6 d5a2a550 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 d5a2a550 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 d5a2a550 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 d5a2a550 Michael Hanselmann
# (at your option) any later version.
10 d5a2a550 Michael Hanselmann
#
11 d5a2a550 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 d5a2a550 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 d5a2a550 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 d5a2a550 Michael Hanselmann
# General Public License for more details.
15 d5a2a550 Michael Hanselmann
#
16 d5a2a550 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 d5a2a550 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 d5a2a550 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 d5a2a550 Michael Hanselmann
# 02110-1301, USA.
20 d5a2a550 Michael Hanselmann
21 d5a2a550 Michael Hanselmann
22 d5a2a550 Michael Hanselmann
"""Script to generate RPC code.
23 d5a2a550 Michael Hanselmann
24 d5a2a550 Michael Hanselmann
"""
25 d5a2a550 Michael Hanselmann
26 d5a2a550 Michael Hanselmann
# pylint: disable=C0103
27 d5a2a550 Michael Hanselmann
# [C0103] Invalid name
28 d5a2a550 Michael Hanselmann
29 d5a2a550 Michael Hanselmann
import sys
30 d5a2a550 Michael Hanselmann
import re
31 d5a2a550 Michael Hanselmann
import itertools
32 d5a2a550 Michael Hanselmann
import textwrap
33 d5a2a550 Michael Hanselmann
from cStringIO import StringIO
34 d5a2a550 Michael Hanselmann
35 d5a2a550 Michael Hanselmann
from ganeti import utils
36 d5a2a550 Michael Hanselmann
from ganeti import compat
37 d5a2a550 Michael Hanselmann
from ganeti import build
38 d5a2a550 Michael Hanselmann
39 d5a2a550 Michael Hanselmann
40 d5a2a550 Michael Hanselmann
_SINGLE = "single-node"
41 d5a2a550 Michael Hanselmann
_MULTI = "multi-node"
42 d5a2a550 Michael Hanselmann
43 60154921 Iustin Pop
#: Expected length of a rpc definition
44 dd6d2d09 Michael Hanselmann
_RPC_DEF_LEN = 8
45 60154921 Iustin Pop
46 d5a2a550 Michael Hanselmann
47 d5a2a550 Michael Hanselmann
def _WritePreamble(sw):
48 d5a2a550 Michael Hanselmann
  """Writes a preamble for the RPC wrapper output.
49 d5a2a550 Michael Hanselmann
50 d5a2a550 Michael Hanselmann
  """
51 d5a2a550 Michael Hanselmann
  sw.Write("# This code is automatically generated at build time.")
52 d5a2a550 Michael Hanselmann
  sw.Write("# Do not modify manually.")
53 d5a2a550 Michael Hanselmann
  sw.Write("")
54 d5a2a550 Michael Hanselmann
  sw.Write("\"\"\"Automatically generated RPC client wrappers.")
55 d5a2a550 Michael Hanselmann
  sw.Write("")
56 d5a2a550 Michael Hanselmann
  sw.Write("\"\"\"")
57 d5a2a550 Michael Hanselmann
  sw.Write("")
58 702abcf9 Michael Hanselmann
  sw.Write("from ganeti import rpc_defs")
59 702abcf9 Michael Hanselmann
  sw.Write("")
60 d5a2a550 Michael Hanselmann
61 d5a2a550 Michael Hanselmann
62 d5a2a550 Michael Hanselmann
def _WrapCode(line):
63 d5a2a550 Michael Hanselmann
  """Wraps Python code.
64 d5a2a550 Michael Hanselmann
65 d5a2a550 Michael Hanselmann
  """
66 d5a2a550 Michael Hanselmann
  return textwrap.wrap(line, width=70, expand_tabs=False,
67 d5a2a550 Michael Hanselmann
                       fix_sentence_endings=False, break_long_words=False,
68 d5a2a550 Michael Hanselmann
                       replace_whitespace=True,
69 d5a2a550 Michael Hanselmann
                       subsequent_indent=utils.ShellWriter.INDENT_STR)
70 d5a2a550 Michael Hanselmann
71 d5a2a550 Michael Hanselmann
72 d5a2a550 Michael Hanselmann
def _WriteDocstring(sw, name, timeout, kind, args, desc):
73 d5a2a550 Michael Hanselmann
  """Writes a docstring for an RPC wrapper.
74 d5a2a550 Michael Hanselmann
75 d5a2a550 Michael Hanselmann
  """
76 d5a2a550 Michael Hanselmann
  sw.Write("\"\"\"Wrapper for RPC call '%s'", name)
77 d5a2a550 Michael Hanselmann
  sw.Write("")
78 d5a2a550 Michael Hanselmann
  if desc:
79 d5a2a550 Michael Hanselmann
    sw.Write(desc)
80 d5a2a550 Michael Hanselmann
    sw.Write("")
81 d5a2a550 Michael Hanselmann
82 d5a2a550 Michael Hanselmann
  note = ["This is a %s call" % kind]
83 f68cc544 Michael Hanselmann
  if timeout and not callable(timeout):
84 d5a2a550 Michael Hanselmann
    note.append(" with a timeout of %s" % utils.FormatSeconds(timeout))
85 d5a2a550 Michael Hanselmann
  sw.Write("@note: %s", "".join(note))
86 d5a2a550 Michael Hanselmann
87 d5a2a550 Michael Hanselmann
  if kind == _SINGLE:
88 d5a2a550 Michael Hanselmann
    sw.Write("@type node: string")
89 d5a2a550 Michael Hanselmann
    sw.Write("@param node: Node name")
90 d5a2a550 Michael Hanselmann
  else:
91 d5a2a550 Michael Hanselmann
    sw.Write("@type node_list: list of string")
92 d5a2a550 Michael Hanselmann
    sw.Write("@param node_list: List of node names")
93 d5a2a550 Michael Hanselmann
94 d5a2a550 Michael Hanselmann
  if args:
95 d5a2a550 Michael Hanselmann
    for (argname, _, argtext) in args:
96 d5a2a550 Michael Hanselmann
      if argtext:
97 d5a2a550 Michael Hanselmann
        docline = "@param %s: %s" % (argname, argtext)
98 d5a2a550 Michael Hanselmann
        for line in _WrapCode(docline):
99 d5a2a550 Michael Hanselmann
          sw.Write(line)
100 d5a2a550 Michael Hanselmann
  sw.Write("")
101 d5a2a550 Michael Hanselmann
  sw.Write("\"\"\"")
102 d5a2a550 Michael Hanselmann
103 d5a2a550 Michael Hanselmann
104 d5a2a550 Michael Hanselmann
def _WriteBaseClass(sw, clsname, calls):
105 d5a2a550 Michael Hanselmann
  """Write RPC wrapper class.
106 d5a2a550 Michael Hanselmann
107 d5a2a550 Michael Hanselmann
  """
108 d5a2a550 Michael Hanselmann
  sw.Write("")
109 d5a2a550 Michael Hanselmann
  sw.Write("class %s(object):", clsname)
110 d5a2a550 Michael Hanselmann
  sw.IncIndent()
111 d5a2a550 Michael Hanselmann
  try:
112 d5a2a550 Michael Hanselmann
    sw.Write("# E1101: Non-existent members")
113 d5a2a550 Michael Hanselmann
    sw.Write("# R0904: Too many public methods")
114 d5a2a550 Michael Hanselmann
    sw.Write("# pylint: disable=E1101,R0904")
115 d5a2a550 Michael Hanselmann
116 d5a2a550 Michael Hanselmann
    if not calls:
117 d5a2a550 Michael Hanselmann
      sw.Write("pass")
118 d5a2a550 Michael Hanselmann
      return
119 d5a2a550 Michael Hanselmann
120 702abcf9 Michael Hanselmann
    sw.Write("_CALLS = rpc_defs.CALLS[%r]", clsname)
121 702abcf9 Michael Hanselmann
    sw.Write("")
122 702abcf9 Michael Hanselmann
123 60154921 Iustin Pop
    for v in calls:
124 60154921 Iustin Pop
      if len(v) != _RPC_DEF_LEN:
125 60154921 Iustin Pop
        raise ValueError("Procedure %s has only %d elements, expected %d" %
126 60154921 Iustin Pop
                         (v[0], len(v), _RPC_DEF_LEN))
127 60154921 Iustin Pop
128 ecd11bb0 Michael Hanselmann
    for (name, kind, _, timeout, args, _, _, desc) in sorted(calls):
129 d5a2a550 Michael Hanselmann
      funcargs = ["self"]
130 d5a2a550 Michael Hanselmann
131 d5a2a550 Michael Hanselmann
      if kind == _SINGLE:
132 d5a2a550 Michael Hanselmann
        funcargs.append("node")
133 d5a2a550 Michael Hanselmann
      elif kind == _MULTI:
134 d5a2a550 Michael Hanselmann
        funcargs.append("node_list")
135 d5a2a550 Michael Hanselmann
      else:
136 d5a2a550 Michael Hanselmann
        raise Exception("Unknown kind '%s'" % kind)
137 d5a2a550 Michael Hanselmann
138 d5a2a550 Michael Hanselmann
      funcargs.extend(map(compat.fst, args))
139 d5a2a550 Michael Hanselmann
140 702abcf9 Michael Hanselmann
      funcargs.append("_def=_CALLS[%r]" % name)
141 702abcf9 Michael Hanselmann
142 d5a2a550 Michael Hanselmann
      funcdef = "def call_%s(%s):" % (name, utils.CommaJoin(funcargs))
143 d5a2a550 Michael Hanselmann
      for line in _WrapCode(funcdef):
144 d5a2a550 Michael Hanselmann
        sw.Write(line)
145 d5a2a550 Michael Hanselmann
146 d5a2a550 Michael Hanselmann
      sw.IncIndent()
147 d5a2a550 Michael Hanselmann
      try:
148 d5a2a550 Michael Hanselmann
        _WriteDocstring(sw, name, timeout, kind, args, desc)
149 d5a2a550 Michael Hanselmann
150 d5a2a550 Michael Hanselmann
        buf = StringIO()
151 d5a2a550 Michael Hanselmann
        buf.write("return ")
152 d5a2a550 Michael Hanselmann
153 d5a2a550 Michael Hanselmann
        # In case line gets too long and is wrapped in a bad spot
154 f2bca93e Michael Hanselmann
        buf.write("(")
155 d5a2a550 Michael Hanselmann
156 702abcf9 Michael Hanselmann
        buf.write("self._Call(_def, ")
157 d5a2a550 Michael Hanselmann
        if kind == _SINGLE:
158 d5a2a550 Michael Hanselmann
          buf.write("[node]")
159 d5a2a550 Michael Hanselmann
        else:
160 d5a2a550 Michael Hanselmann
          buf.write("node_list")
161 cd40dc53 Michael Hanselmann
162 f7d9b3aa Michael Hanselmann
        buf.write(", [%s])" %
163 702abcf9 Michael Hanselmann
                  # Function arguments
164 702abcf9 Michael Hanselmann
                  utils.CommaJoin(map(compat.fst, args)))
165 cd40dc53 Michael Hanselmann
166 d5a2a550 Michael Hanselmann
        if kind == _SINGLE:
167 d5a2a550 Michael Hanselmann
          buf.write("[node]")
168 d5a2a550 Michael Hanselmann
        buf.write(")")
169 d5a2a550 Michael Hanselmann
170 d5a2a550 Michael Hanselmann
        for line in _WrapCode(buf.getvalue()):
171 d5a2a550 Michael Hanselmann
          sw.Write(line)
172 d5a2a550 Michael Hanselmann
      finally:
173 d5a2a550 Michael Hanselmann
        sw.DecIndent()
174 d5a2a550 Michael Hanselmann
      sw.Write("")
175 d5a2a550 Michael Hanselmann
  finally:
176 d5a2a550 Michael Hanselmann
    sw.DecIndent()
177 d5a2a550 Michael Hanselmann
178 d5a2a550 Michael Hanselmann
179 d5a2a550 Michael Hanselmann
def main():
180 d5a2a550 Michael Hanselmann
  """Main function.
181 d5a2a550 Michael Hanselmann
182 d5a2a550 Michael Hanselmann
  """
183 d5a2a550 Michael Hanselmann
  buf = StringIO()
184 d5a2a550 Michael Hanselmann
  sw = utils.ShellWriter(buf)
185 d5a2a550 Michael Hanselmann
186 d5a2a550 Michael Hanselmann
  _WritePreamble(sw)
187 d5a2a550 Michael Hanselmann
188 d5a2a550 Michael Hanselmann
  for filename in sys.argv[1:]:
189 d5a2a550 Michael Hanselmann
    sw.Write("# Definitions from '%s'", filename)
190 d5a2a550 Michael Hanselmann
191 d5a2a550 Michael Hanselmann
    module = build.LoadModule(filename)
192 d5a2a550 Michael Hanselmann
193 d5a2a550 Michael Hanselmann
    # Call types are re-defined in definitions file to avoid imports. Verify
194 d5a2a550 Michael Hanselmann
    # here to ensure they're equal to local constants.
195 d5a2a550 Michael Hanselmann
    assert module.SINGLE == _SINGLE
196 d5a2a550 Michael Hanselmann
    assert module.MULTI == _MULTI
197 d5a2a550 Michael Hanselmann
198 99cafe0f Michael Hanselmann
    dups = utils.FindDuplicates(itertools.chain(*map(lambda value: value.keys(),
199 99cafe0f Michael Hanselmann
                                                     module.CALLS.values())))
200 99cafe0f Michael Hanselmann
    if dups:
201 99cafe0f Michael Hanselmann
      raise Exception("Found duplicate RPC definitions for '%s'" %
202 99cafe0f Michael Hanselmann
                      utils.CommaJoin(sorted(dups)))
203 99cafe0f Michael Hanselmann
204 ecd11bb0 Michael Hanselmann
    for (clsname, calls) in sorted(module.CALLS.items()):
205 a09f9847 Michael Hanselmann
      _WriteBaseClass(sw, clsname, calls.values())
206 d5a2a550 Michael Hanselmann
207 d5a2a550 Michael Hanselmann
  print buf.getvalue()
208 d5a2a550 Michael Hanselmann
209 d5a2a550 Michael Hanselmann
210 d5a2a550 Michael Hanselmann
if __name__ == "__main__":
211 d5a2a550 Michael Hanselmann
  main()