On Wed, May 12, 2010 at 7:08 PM, Michael Hanselmann <[email protected]> wrote:
> Currently this only supports the new instance creation request
> data format version 1, but support for the old version will be
> easily implemented.

s/will/can/ unless you're going to do it. :)

>
> Most arguments are optional and documented in the RAPI documentation.
>
> Signed-off-by: Michael Hanselmann <[email protected]>
> ---
>  lib/rapi/client.py                  |   55 +++++++++++++++++++++++++++++++---
>  test/ganeti.rapi.client_unittest.py |   42 +++++++++++++++++++++++++-
>  2 files changed, 90 insertions(+), 7 deletions(-)
>
> diff --git a/lib/rapi/client.py b/lib/rapi/client.py
> index 97d89e0..dadb820 100644
> --- a/lib/rapi/client.py
> +++ b/lib/rapi/client.py
> @@ -56,6 +56,10 @@ NODE_ROLE_MASTER = "master"
>  NODE_ROLE_OFFLINE = "offline"
>  NODE_ROLE_REGULAR = "regular"
>
> +# Internal constants
> +_REQ_DATA_VERSION_FIELD = "__version__"
> +_INST_CREATE_REQV1 = "instance-create-reqv1"
> +
>
>  class Error(Exception):
>   """Base error class for this module.
> @@ -555,23 +559,64 @@ class GanetiRapiClient(object):
>                              ("/%s/instances/%s" %
>                               (GANETI_RAPI_VERSION, instance)), None, None)
>
> -  def CreateInstance(self, dry_run=False):
> +  def CreateInstance(self, mode, name, disk_template, disks, nics,
> +                     **kwargs):
>     """Creates a new instance.
>
> +    More details for parameters can be found in the RAPI documentation.
> +
> +   �...@type mode: string
> +   �...@param mode: Instance creation mode
> +   �...@type name: string
> +   �...@param name: Hostname of the instance to create
> +   �...@type disk_template: string
> +   �...@param disk_template: Disk template for instance (e.g. plain, 
> diskless,
> +                          file, or drbd)
> +   �...@type disks: list of dicts
> +   �...@param disks: List of disk definitions
> +   �...@type nics: list of dicts
> +   �...@param nics: List of NIC definitions
>     @type dry_run: bool
> -   �...@param dry_run: whether to perform a dry run
> +   �...@keyword dry_run: whether to perform a dry run
>
>     @rtype: int
>     @return: job id
>
>     """
> -    # TODO: Pass arguments needed to actually create an instance.
>     query = []
> -    if dry_run:
> +
> +    if kwargs.get("dry_run"):
>       query.append(("dry-run", 1))
>
> +    if _INST_CREATE_REQV1 in self.GetFeatures():
> +      # All required fields for request data version 1
> +      body = {
> +        _REQ_DATA_VERSION_FIELD: 1,
> +        "mode": mode,
> +        "name": name,
> +        "disk_template": disk_template,
> +        "disks": disks,
> +        "nics": nics,
> +        }
> +
> +      conflicts = set(kwargs.iterkeys()) & set(body.iterkeys())
> +      if conflicts:
> +        raise GanetiApiError("Required fields can not be specified as"
> +                             " keywords: %s" % ", ".join(conflicts))
> +
> +      body.update((key, value) for key, value in kwargs.iteritems()
> +                  if key != "dry_run")
> +    else:
> +      # TODO: Implement instance creation request data version 0
> +      # When implementing version 0, care should be taken to refuse unknown
> +      # parameters and invalid values. The interface of this function must 
> stay
> +      # exactly the same for version 0 and 1 (e.g. they aren't allowed to
> +      # require different data types).
> +      raise NotImplementedError("Support for instance creation request data"
> +                                " version 0 is not yet implemented")
> +
>     return self._SendRequest(HTTP_POST, "/%s/instances" % GANETI_RAPI_VERSION,
> -                             query, None)
> +                             query, body)
>
>   def DeleteInstance(self, instance, dry_run=False):
>     """Deletes an instance.
> diff --git a/test/ganeti.rapi.client_unittest.py 
> b/test/ganeti.rapi.client_unittest.py
> index 8840a4b..f06a5bf 100755
> --- a/test/ganeti.rapi.client_unittest.py
> +++ b/test/ganeti.rapi.client_unittest.py
> @@ -239,12 +239,50 @@ class GanetiRapiClientTests(testutils.GanetiTestCase):
>     self.assertHandler(rlib2.R_2_instances_name)
>     self.assertItems(["instance"])
>
> +  def testCreateInstanceOldVersion(self):
> +    self.rapi.AddResponse(serializer.DumpJson([]))
> +    self.assertRaises(NotImplementedError, self.client.CreateInstance,
> +                      "create", "inst1.example.com", "plain", [], [],
> +                      dry_run=True)
> +
>   def testCreateInstance(self):
> -    self.rapi.AddResponse("1234")
> -    self.assertEqual(1234, self.client.CreateInstance(dry_run=True))
> +    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
> +    self.rapi.AddResponse("23030")
> +    job_id = self.client.CreateInstance("create", "inst1.example.com",
> +                                        "plain", [], [], dry_run=True)
> +    self.assertEqual(job_id, 23030)
>     self.assertHandler(rlib2.R_2_instances)
>     self.assertDryRun()
>
> +    data = serializer.LoadJson(self.http.last_request.data)
> +
> +    for field in ["dry_run", "beparams", "hvparams", "start"]:
> +      self.assertFalse(field in data)
> +
> +    self.assertEqual(data["name"], "inst1.example.com")
> +    self.assertEqual(data["disk_template"], "plain")
> +
> +  def testCreateInstance2(self):
> +    self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
> +    self.rapi.AddResponse("24740")
> +    job_id = self.client.CreateInstance("import", "inst2.example.com",
> +                                        "drbd8", [{"size": 100,}],
> +                                        [{}, {"bridge": "br1", }],
> +                                        dry_run=False, start=True,
> +                                        pnode="node1", snode="node9",
> +                                        ip_check=False)
> +    self.assertEqual(job_id, 24740)
> +    self.assertHandler(rlib2.R_2_instances)
> +
> +    data = serializer.LoadJson(self.http.last_request.data)
> +    self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
> +    self.assertEqual(data["name"], "inst2.example.com")
> +    self.assertEqual(data["disk_template"], "drbd8")
> +    self.assertEqual(data["start"], True)
> +    self.assertEqual(data["ip_check"], False)
> +    self.assertEqualValues(data["disks"], [{"size": 100,}])
> +    self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
> +
>   def testDeleteInstance(self):
>     self.rapi.AddResponse("1234")
>     self.assertEqual(1234, self.client.DeleteInstance("instance", 
> dry_run=True))
> --
> 1.7.0.4
>

LGTM for the rest

Thanks,

Guido

Reply via email to