commit 415a730479b67a69e75f1c756fa4c84a2a5b4116
Author: Michael Hanselmann <hansmi@google.com>
Date:   Tue Oct 25 21:00:16 2011 +0200

    rpc: Convert last two calls to generated code
    
    These two calls, “upload_file” and “write_ssconf_files” are treated
    separated as they're used by the configuration, where we can't use the
    normal resolver.
    
    There's still some duplicated code in rpc.py, but that will be taken
    care of in future patches.
    
    Signed-off-by: Michael Hanselmann <hansmi@google.com>
    Reviewed-by: Iustin Pop <iustin@google.com>

diff --git a/lib/build/rpc_definitions.py b/lib/build/rpc_definitions.py
index 821d6bd..499df60 100644
--- a/lib/build/rpc_definitions.py
+++ b/lib/build/rpc_definitions.py
@@ -403,4 +403,12 @@ CALLS = {
     ("master_info", MULTI, TMO_URGENT, [], None, "Query master info"),
     ("version", MULTI, TMO_URGENT, [], None, "Query node version"),
     ],
+  "RpcClientConfig": [
+    ("upload_file", MULTI, TMO_NORMAL, [
+      ("file_name", "self._PrepareFileUpload(%s)", None),
+      ], None, "Upload a file"),
+    ("write_ssconf_files", MULTI, TMO_NORMAL, [
+      ("values", None, None),
+      ], None, "Write ssconf files"),
+    ],
   }
diff --git a/lib/config.py b/lib/config.py
index 268304f..7ca7c55 100644
--- a/lib/config.py
+++ b/lib/config.py
@@ -1723,8 +1723,9 @@ class ConfigWriter:
       node_list.append(node_info.name)
       addr_list.append(node_info.primary_ip)
 
-    result = rpc.RpcRunner.call_upload_file(node_list, self._cfg_file,
-                                            address_list=addr_list)
+    # TODO: Use dedicated resolver talking to config writer for name resolution
+    result = \
+      rpc.ConfigRunner(addr_list).call_upload_file(node_list, self._cfg_file)
     for to_node, to_result in result.items():
       msg = to_result.fail_msg
       if msg:
@@ -1783,7 +1784,7 @@ class ConfigWriter:
     # Write ssconf files on all nodes (including locally)
     if self._last_cluster_serial < self._config_data.cluster.serial_no:
       if not self._offline:
-        result = rpc.RpcRunner.call_write_ssconf_files(
+        result = rpc.ConfigRunner(None).call_write_ssconf_files(
           self._UnlockedGetOnlineNodeList(),
           self._UnlockedGetSsconfValues())
 
diff --git a/lib/rpc.py b/lib/rpc.py
index 1ecff15..8e235ed 100644
--- a/lib/rpc.py
+++ b/lib/rpc.py
@@ -438,7 +438,8 @@ class _RpcProcessor:
 
 
 class RpcRunner(_generated_rpc.RpcClientDefault,
-                _generated_rpc.RpcClientBootstrap):
+                _generated_rpc.RpcClientBootstrap,
+                _generated_rpc.RpcClientConfig):
   """RPC runner class.
 
   """
@@ -453,6 +454,7 @@ class RpcRunner(_generated_rpc.RpcClientDefault,
     # <http://www.logilab.org/ticket/36586> and
     # <http://www.logilab.org/ticket/35642>
     # pylint: disable=W0233
+    _generated_rpc.RpcClientConfig.__init__(self)
     _generated_rpc.RpcClientBootstrap.__init__(self)
     _generated_rpc.RpcClientDefault.__init__(self)
 
@@ -639,47 +641,20 @@ class RpcRunner(_generated_rpc.RpcClientDefault,
 
     return ieioargs
 
-  #
-  # Begin RPC calls
-  #
-
-  @classmethod
-  @_RpcTimeout(_TMO_NORMAL)
-  def call_upload_file(cls, node_list, file_name, address_list=None):
-    """Upload a file.
-
-    The node will refuse the operation in case the file is not on the
-    approved file list.
-
-    This is a multi-node call.
-
-    @type node_list: list
-    @param node_list: the list of node names to upload to
-    @type file_name: str
-    @param file_name: the filename to upload
-    @type address_list: list or None
-    @keyword address_list: an optional list of node addresses, in order
-        to optimize the RPC speed
+  @staticmethod
+  def _PrepareFileUpload(filename):
+    """Loads a file and prepares it for an upload to nodes.
 
     """
-    file_contents = utils.ReadFile(file_name)
-    data = _Compress(file_contents)
-    st = os.stat(file_name)
+    data = _Compress(utils.ReadFile(filename))
+    st = os.stat(filename)
     getents = runtime.GetEnts()
-    params = [file_name, data, st.st_mode, getents.LookupUid(st.st_uid),
-              getents.LookupGid(st.st_gid), st.st_atime, st.st_mtime]
-    return cls._StaticMultiNodeCall(node_list, "upload_file", params,
-                                    address_list=address_list)
-
-  @classmethod
-  @_RpcTimeout(_TMO_NORMAL)
-  def call_write_ssconf_files(cls, node_list, values):
-    """Write ssconf files.
-
-    This is a multi-node call.
+    return [filename, data, st.st_mode, getents.LookupUid(st.st_uid),
+            getents.LookupGid(st.st_gid), st.st_atime, st.st_mtime]
 
-    """
-    return cls._StaticMultiNodeCall(node_list, "write_ssconf_files", [values])
+  #
+  # Begin RPC calls
+  #
 
   def call_test_delay(self, node_list, duration, read_timeout=None):
     """Sleep for a fixed time on given node(s).
@@ -743,3 +718,34 @@ class BootstrapRunner(_generated_rpc.RpcClientBootstrap):
     body = serializer.DumpJson(args, indent=False)
 
     return self._proc(node_list, procedure, body, read_timeout=timeout)
+
+
+class ConfigRunner(_generated_rpc.RpcClientConfig):
+  """RPC wrappers for L{config}.
+
+  """
+  _PrepareFileUpload = \
+    staticmethod(RpcRunner._PrepareFileUpload) # pylint: disable=W0212
+
+  def __init__(self, address_list):
+    """Initializes this class.
+
+    """
+    _generated_rpc.RpcClientConfig.__init__(self)
+
+    if address_list is None:
+      resolver = _SsconfResolver
+    else:
+      # Caller provided an address list
+      resolver = _StaticResolver(address_list)
+
+    self._proc = _RpcProcessor(resolver,
+                               netutils.GetDaemonPort(constants.NODED))
+
+  def _Call(self, node_list, procedure, timeout, args):
+    """Entry point for automatically generated RPC wrappers.
+
+    """
+    body = serializer.DumpJson(args, indent=False)
+
+    return self._proc(node_list, procedure, body, read_timeout=timeout)
diff --git a/lib/server/noded.py b/lib/server/noded.py
index 384807b..90d879f 100644
--- a/lib/server/noded.py
+++ b/lib/server/noded.py
@@ -770,7 +770,7 @@ class NodeHttpServer(http.server.HttpServer):
     files are accepted.
 
     """
-    return backend.UploadFile(*params)
+    return backend.UploadFile(*(params[0]))
 
   @staticmethod
   def perspective_master_info(params):
