From cfaeaaf7db3b2289c693f48dece03a345fa6d04b Mon Sep 17 00:00:00 2001
From: Michael Hanselmann <hansmi@google.com>
Date: Tue, 4 Jan 2011 17:29:50 +0100
Subject: [PATCH] baserlib: Add function for filling opcodes

This function makes use of the opcode parameters which now live
directly in the opcode. A number of RAPI resources can now be simplified.

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 Makefile.am                           |  1 +
 lib/rapi/baserlib.py                  | 40 +++++++++++++
 test/ganeti.rapi.baserlib_unittest.py | 86 +++++++++++++++++++++++++++
 3 files changed, 127 insertions(+)
 create mode 100755 test/ganeti.rapi.baserlib_unittest.py

diff --git a/Makefile.am b/Makefile.am
index 9f1e1a65b..fab0ee8df 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -461,6 +461,7 @@ python_tests = \
 	test/ganeti.opcodes_unittest.py \
 	test/ganeti.qlang_unittest.py \
 	test/ganeti.query_unittest.py \
+	test/ganeti.rapi.baserlib_unittest.py \
 	test/ganeti.rapi.client_unittest.py \
 	test/ganeti.rapi.resources_unittest.py \
 	test/ganeti.rapi.rlib2_unittest.py \
diff --git a/lib/rapi/baserlib.py b/lib/rapi/baserlib.py
index e59681654..d30f0cddf 100644
--- a/lib/rapi/baserlib.py
+++ b/lib/rapi/baserlib.py
@@ -170,6 +170,46 @@ def MakeParamsDict(opts, params):
   return result
 
 
+def FillOpcode(opcls, body, static):
+  """Fills an opcode with body parameters.
+
+  Parameter types are checked.
+
+  @type opcls: L{opcodes.OpCode}
+  @param opcls: Opcode class
+  @type body: dict
+  @param body: Body parameters as received from client
+  @type static: dict
+  @param static: Static parameters which can't be modified by client
+  @return: Opcode object
+
+  """
+  CheckType(body, dict, "Body contents")
+
+  if static:
+    overwritten = set(body.keys()) & set(static.keys())
+    if overwritten:
+      raise http.HttpBadRequest("Can't overwrite static parameters %r" %
+                                overwritten)
+
+  # Combine parameters
+  params = body.copy()
+
+  if static:
+    params.update(static)
+
+  # Convert keys to strings (simplejson decodes them as unicode)
+  params = dict((str(key), value) for (key, value) in params.items())
+
+  try:
+    op = opcls(**params) # pylint: disable-msg=W0142
+    op.Validate(False)
+  except (errors.OpPrereqError, TypeError), err:
+    raise http.HttpBadRequest("Invalid body parameters: %s" % err)
+
+  return op
+
+
 def SubmitJob(op, cl=None):
   """Generic wrapper for submit job, for better http compatibility.
 
diff --git a/test/ganeti.rapi.baserlib_unittest.py b/test/ganeti.rapi.baserlib_unittest.py
new file mode 100755
index 000000000..570636fa7
--- /dev/null
+++ b/test/ganeti.rapi.baserlib_unittest.py
@@ -0,0 +1,86 @@
+#!/usr/bin/python
+#
+
+# Copyright (C) 2011 Google Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+
+"""Script for testing ganeti.rapi.baserlib"""
+
+import unittest
+
+from ganeti import errors
+from ganeti import opcodes
+from ganeti import ht
+from ganeti import http
+from ganeti.rapi import baserlib
+
+import testutils
+
+
+class TestFillOpcode(unittest.TestCase):
+  class _TestOp(opcodes.OpCode):
+    OP_ID = "RAPI_TEST_OP"
+    OP_PARAMS = [
+      ("test", None, ht.TMaybeString),
+      ]
+
+  def test(self):
+    for static in [None, {}]:
+      op = baserlib.FillOpcode(self._TestOp, {}, static)
+      self.assertTrue(isinstance(op, self._TestOp))
+      self.assertFalse(hasattr(op, "test"))
+
+  def testStatic(self):
+    op = baserlib.FillOpcode(self._TestOp, {}, {"test": "abc"})
+    self.assertTrue(isinstance(op, self._TestOp))
+    self.assertEqual(op.test, "abc")
+
+    # Overwrite static parameter
+    self.assertRaises(http.HttpBadRequest, baserlib.FillOpcode,
+                      self._TestOp, {"test": 123}, {"test": "abc"})
+
+  def testType(self):
+    self.assertRaises(http.HttpBadRequest, baserlib.FillOpcode,
+                      self._TestOp, {"test": [1, 2, 3]}, {})
+
+  def testStaticType(self):
+    self.assertRaises(http.HttpBadRequest, baserlib.FillOpcode,
+                      self._TestOp, {}, {"test": [1, 2, 3]})
+
+  def testUnicode(self):
+    op = baserlib.FillOpcode(self._TestOp, {u"test": "abc"}, {})
+    self.assertTrue(isinstance(op, self._TestOp))
+    self.assertEqual(op.test, "abc")
+
+    op = baserlib.FillOpcode(self._TestOp, {}, {u"test": "abc"})
+    self.assertTrue(isinstance(op, self._TestOp))
+    self.assertEqual(op.test, "abc")
+
+  def testUnknownParameter(self):
+    self.assertRaises(http.HttpBadRequest, baserlib.FillOpcode,
+                      self._TestOp, {"othervalue": 123}, None)
+
+  def testInvalidBody(self):
+    self.assertRaises(http.HttpBadRequest, baserlib.FillOpcode,
+                      self._TestOp, "", None)
+    self.assertRaises(http.HttpBadRequest, baserlib.FillOpcode,
+                      self._TestOp, range(10), None)
+
+
+if __name__ == "__main__":
+  testutils.GanetiTestProgram()
-- 
GitLab