4 # Copyright (C) 2011 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Script to generate RPC code.
26 # pylint: disable=C0103
27 # [C0103] Invalid name
33 from cStringIO import StringIO
35 from ganeti import utils
36 from ganeti import compat
37 from ganeti import build
40 _SINGLE = "single-node"
43 #: Expected length of a rpc definition
47 def _WritePreamble(sw):
48 """Writes a preamble for the RPC wrapper output.
51 sw.Write("# This code is automatically generated at build time.")
52 sw.Write("# Do not modify manually.")
54 sw.Write("\"\"\"Automatically generated RPC client wrappers.")
58 sw.Write("from ganeti import rpc_defs")
66 return textwrap.wrap(line, width=70, expand_tabs=False,
67 fix_sentence_endings=False, break_long_words=False,
68 replace_whitespace=True,
69 subsequent_indent=utils.ShellWriter.INDENT_STR)
72 def _WriteDocstring(sw, name, timeout, kind, args, desc):
73 """Writes a docstring for an RPC wrapper.
76 sw.Write("\"\"\"Wrapper for RPC call '%s'", name)
82 note = ["This is a %s call" % kind]
83 if timeout and not callable(timeout):
84 note.append(" with a timeout of %s" % utils.FormatSeconds(timeout))
85 sw.Write("@note: %s", "".join(note))
88 sw.Write("@type node: string")
89 sw.Write("@param node: Node name")
91 sw.Write("@type node_list: list of string")
92 sw.Write("@param node_list: List of node names")
95 for (argname, _, argtext) in args:
97 docline = "@param %s: %s" % (argname, argtext)
98 for line in _WrapCode(docline):
104 def _WriteBaseClass(sw, clsname, calls):
105 """Write RPC wrapper class.
109 sw.Write("class %s(object):", clsname)
112 sw.Write("# E1101: Non-existent members")
113 sw.Write("# R0904: Too many public methods")
114 sw.Write("# pylint: disable=E1101,R0904")
120 sw.Write("_CALLS = rpc_defs.CALLS[%r]", clsname)
124 if len(v) != _RPC_DEF_LEN:
125 raise ValueError("Procedure %s has only %d elements, expected %d" %
126 (v[0], len(v), _RPC_DEF_LEN))
128 for (name, kind, _, timeout, args, _, _, desc) in sorted(calls):
132 funcargs.append("node")
134 funcargs.append("node_list")
136 raise Exception("Unknown kind '%s'" % kind)
138 funcargs.extend(map(compat.fst, args))
140 funcargs.append("_def=_CALLS[%r]" % name)
142 funcdef = "def call_%s(%s):" % (name, utils.CommaJoin(funcargs))
143 for line in _WrapCode(funcdef):
148 _WriteDocstring(sw, name, timeout, kind, args, desc)
153 # In case line gets too long and is wrapped in a bad spot
156 buf.write("self._Call(_def, ")
160 buf.write("node_list")
162 buf.write(", [%s])" %
164 utils.CommaJoin(map(compat.fst, args)))
170 for line in _WrapCode(buf.getvalue()):
184 sw = utils.ShellWriter(buf)
188 for filename in sys.argv[1:]:
189 sw.Write("# Definitions from '%s'", filename)
191 module = build.LoadModule(filename)
193 # Call types are re-defined in definitions file to avoid imports. Verify
194 # here to ensure they're equal to local constants.
195 assert module.SINGLE == _SINGLE
196 assert module.MULTI == _MULTI
198 dups = utils.FindDuplicates(itertools.chain(*map(lambda value: value.keys(),
199 module.CALLS.values())))
201 raise Exception("Found duplicate RPC definitions for '%s'" %
202 utils.CommaJoin(sorted(dups)))
204 for (clsname, calls) in sorted(module.CALLS.items()):
205 _WriteBaseClass(sw, clsname, calls.values())
210 if __name__ == "__main__":