diff --git a/lib/rapi/rlib2.py b/lib/rapi/rlib2.py
index 5074fcefbf5ce774caf25309c4b890d701a60b0f..771f918edd9cb21605bd537ba2d7165be5eb3b67 100644
--- a/lib/rapi/rlib2.py
+++ b/lib/rapi/rlib2.py
@@ -571,29 +571,24 @@ class R_2_nodes_name_storage_repair(baserlib.ResourceBase):
     return self.SubmitJob([op])
 
 
-def _ParseCreateGroupRequest(data, dry_run):
-  """Parses a request for creating a node group.
-
-  @rtype: L{opcodes.OpGroupAdd}
-  @return: Group creation opcode
+class R_2_groups(baserlib.OpcodeResource):
+  """/2/groups resource.
 
   """
-  override = {
-    "dry_run": dry_run,
-    }
-
-  rename = {
+  POST_OPCODE = opcodes.OpGroupAdd
+  POST_RENAME = {
     "name": "group_name",
     }
 
-  return baserlib.FillOpcode(opcodes.OpGroupAdd, data, override,
-                             rename=rename)
-
+  def GetPostOpInput(self):
+    """Create a node group.
 
-class R_2_groups(baserlib.ResourceBase):
-  """/2/groups resource.
+    """
+    assert not self.items
+    return (self.request_body, {
+      "dry_run": self.dryRun(),
+      })
 
-  """
   def GET(self):
     """Returns a list of all node groups.
 
@@ -609,16 +604,6 @@ class R_2_groups(baserlib.ResourceBase):
       return baserlib.BuildUriList(groupnames, "/2/groups/%s",
                                    uri_fields=("name", "uri"))
 
-  def POST(self):
-    """Create a node group.
-
-    @return: a job id
-
-    """
-    baserlib.CheckType(self.request_body, dict, "Body contents")
-    op = _ParseCreateGroupRequest(self.request_body, self.dryRun())
-    return self.SubmitJob([op])
-
 
 class R_2_groups_name(baserlib.ResourceBase):
   """/2/groups/[group_name] resource.
diff --git a/test/ganeti.rapi.rlib2_unittest.py b/test/ganeti.rapi.rlib2_unittest.py
index 95ab354ec712a5c7c181f8c15c21bce255798ef5..db2d67fc95b262232d5a83915c4cebfbf4184c7c 100755
--- a/test/ganeti.rapi.rlib2_unittest.py
+++ b/test/ganeti.rapi.rlib2_unittest.py
@@ -786,12 +786,10 @@ class TestParseModifyGroupRequest(unittest.TestCase):
     self.assertFalse(hasattr(op, "alloc_policy"))
 
 
-class TestParseCreateGroupRequest(unittest.TestCase):
-  def setUp(self):
-    self.Parse = rlib2._ParseCreateGroupRequest
-
+class TestGroupAdd(unittest.TestCase):
   def test(self):
     name = "group3618"
+    clfactory = _FakeClientFactory(_FakeClient)
 
     for policy in constants.VALID_ALLOC_POLICIES:
       data = {
@@ -799,40 +797,78 @@ class TestParseCreateGroupRequest(unittest.TestCase):
         "alloc_policy": policy,
         }
 
-      op = self.Parse(data, False)
-      self.assert_(isinstance(op, opcodes.OpGroupAdd))
+      handler = _CreateHandler(rlib2.R_2_groups, [], {}, data,
+                               clfactory)
+      job_id = handler.POST()
+
+      cl = clfactory.GetNextClient()
+      self.assertRaises(IndexError, clfactory.GetNextClient)
+
+      (exp_job_id, (op, )) = cl.GetNextSubmittedJob()
+      self.assertEqual(job_id, exp_job_id)
+
+      self.assertTrue(isinstance(op, opcodes.OpGroupAdd))
       self.assertEqual(op.group_name, name)
       self.assertEqual(op.alloc_policy, policy)
       self.assertFalse(op.dry_run)
+      self.assertRaises(IndexError, cl.GetNextSubmittedJob)
 
   def testUnknownPolicy(self):
+    clfactory = _FakeClientFactory(_FakeClient)
+
     data = {
       "alloc_policy": "_unknown_policy_",
       }
 
-    self.assertRaises(http.HttpBadRequest, self.Parse, "name", data)
+    handler = _CreateHandler(rlib2.R_2_groups, [], {}, data, clfactory)
+    self.assertRaises(http.HttpBadRequest, handler.POST)
+    self.assertRaises(IndexError, clfactory.GetNextClient)
 
   def testDefaults(self):
+    clfactory = _FakeClientFactory(_FakeClient)
+
     name = "group15395"
     data = {
       "group_name": name,
       }
 
-    op = self.Parse(data, True)
-    self.assert_(isinstance(op, opcodes.OpGroupAdd))
+    handler = _CreateHandler(rlib2.R_2_groups, [], {}, data, clfactory)
+    job_id = handler.POST()
+
+    cl = clfactory.GetNextClient()
+    self.assertRaises(IndexError, clfactory.GetNextClient)
+
+    (exp_job_id, (op, )) = cl.GetNextSubmittedJob()
+    self.assertEqual(job_id, exp_job_id)
+
+    self.assertTrue(isinstance(op, opcodes.OpGroupAdd))
     self.assertEqual(op.group_name, name)
     self.assertFalse(hasattr(op, "alloc_policy"))
-    self.assertTrue(op.dry_run)
+    self.assertFalse(op.dry_run)
 
   def testLegacyName(self):
+    clfactory = _FakeClientFactory(_FakeClient)
+
     name = "group29852"
     data = {
       "name": name,
       }
 
-    op = self.Parse(data, True)
-    self.assert_(isinstance(op, opcodes.OpGroupAdd))
+    handler = _CreateHandler(rlib2.R_2_groups, [], {
+      "dry-run": ["1"],
+      }, data, clfactory)
+    job_id = handler.POST()
+
+    cl = clfactory.GetNextClient()
+    self.assertRaises(IndexError, clfactory.GetNextClient)
+
+    (exp_job_id, (op, )) = cl.GetNextSubmittedJob()
+    self.assertEqual(job_id, exp_job_id)
+
+    self.assertTrue(isinstance(op, opcodes.OpGroupAdd))
     self.assertEqual(op.group_name, name)
+    self.assertFalse(hasattr(op, "alloc_policy"))
+    self.assertTrue(op.dry_run)
 
 
 if __name__ == '__main__':