root / autotools / build-rpc @ 688b5752
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() |