On 06/26/2014 02:14 PM, Petr Pudlák wrote:
On Thu, Jun 26, 2014 at 11:55 AM, Dimitris Bliablias <[email protected]>
wrote:

On 06/25/2014 10:57 AM, Petr Pudlák wrote:

On Tue, Jun 24, 2014 at 4:19 PM, Dimitris Bliablias <
[email protected]>
wrote:

  This patch extends the 'cmdlib/instance_storage.py' module with a new
method, named 'ComputeDisksInfo'. This method is used by the disk
template conversion mechanism to compute the disks' information that
will be used for generating the new instance's template. In addition, it
modifies the arguments of the 'ComputeDisks' method to be used from the
'ComputeDisksInfo'.

The computed disks of the instance will match the size, mode and name of
the current instance's disks. It also computes the volume group and the
access parameter for the templates that support them. In addition, for
conversions targeting an extstorage disk template, the mandatory
provider's name or any arbitrary user-provided parameters will also be
included in the result. The output of this method will be used by the
'GenerateDiskTemplate' method to generate the new template of the
instance.

Signed-off-by: Dimitris Bliablias <[email protected]>
---
   lib/cmdlib/instance.py         |    6 ++-
   lib/cmdlib/instance_storage.py |   80
+++++++++++++++++++++++++++++++++++-----
   2 files changed, 74 insertions(+), 12 deletions(-)

diff --git a/lib/cmdlib/instance.py b/lib/cmdlib/instance.py
index 565757f..225510d 100644
--- a/lib/cmdlib/instance.py
+++ b/lib/cmdlib/instance.py
@@ -1038,7 +1038,7 @@ class LUInstanceCreate(LogicalUnit):

       # disk checks/pre-build
       default_vg = self.cfg.GetVGName()
-    self.disks = ComputeDisks(self.op, default_vg)
+    self.disks = ComputeDisks(self.op.disks, self.op.disk_template,
default_vg)

       if self.op.mode == constants.INSTANCE_IMPORT:
         disk_images = []
@@ -2344,7 +2344,9 @@ class LUInstanceMultiAlloc(NoHooksLU):
         else:
           node_whitelist = None

-      insts = [_CreateInstanceAllocRequest(op, ComputeDisks(op,
default_vg),
+      insts = [_CreateInstanceAllocRequest(op, ComputeDisks(op.disks,
+
   op.disk_template,
+                                                            default_vg),
                                              _ComputeNics(op, cluster,
None,
                                                           self.cfg,
ec_id),
                                              _ComputeFullBeParams(op,
cluster),
diff --git a/lib/cmdlib/instance_storage.py
b/lib/cmdlib/instance_storage.py
index 0e3c28e..f31806a 100644
--- a/lib/cmdlib/instance_storage.py
+++ b/lib/cmdlib/instance_storage.py
@@ -317,17 +317,21 @@ def ComputeDiskSizePerVG(disk_template, disks):
     return req_size_dict[disk_template]


-def ComputeDisks(op, default_vg):
+def ComputeDisks(disks, disk_template, default_vg):
     """Computes the instance disks.

-  @param op: The instance opcode
+  @type disks: list of dictionaries
+  @param disks: The disks' input dictionary
+  @type disk_template: string
+  @param disk_template: The disk template of the instance
+  @type default_vg: string
     @param default_vg: The default_vg to assume

     @return: The computed disks

     """
-  disks = []
-  for disk in op.disks:
+  new_disks = []
+  for disk in disks:
       mode = disk.get(constants.IDISK_MODE, constants.DISK_RDWR)
       if mode not in constants.DISK_ACCESS_SET:
         raise errors.OpPrereqError("Invalid disk access mode '%s'" %
@@ -342,11 +346,11 @@ def ComputeDisks(op, default_vg):
                                    errors.ECODE_INVAL)

       ext_provider = disk.get(constants.IDISK_PROVIDER, None)
-    if ext_provider and op.disk_template != constants.DT_EXT:
+    if ext_provider and disk_template != constants.DT_EXT:
         raise errors.OpPrereqError("The '%s' option is only valid for the
%s"
                                    " disk template, not %s" %
                                    (constants.IDISK_PROVIDER,
constants.DT_EXT,
-                                  op.disk_template), errors.ECODE_INVAL)
+                                  disk_template), errors.ECODE_INVAL)

       data_vg = disk.get(constants.IDISK_VG, default_vg)
       name = disk.get(constants.IDISK_NAME, None)
@@ -368,13 +372,13 @@ def ComputeDisks(op, default_vg):
           new_disk[key] = disk[key]

       # Add IDISK_ACCESS parameter for disk templates that support it
-    if (op.disk_template in constants.DTS_HAVE_ACCESS and
+    if (disk_template in constants.DTS_HAVE_ACCESS and
           constants.IDISK_ACCESS in disk):
         new_disk[constants.IDISK_ACCESS] = disk[constants.IDISK_ACCESS]

       # For extstorage, demand the `provider' option and add any
       # additional parameters (ext-params) to the dict
-    if op.disk_template == constants.DT_EXT:
+    if disk_template == constants.DT_EXT:
         if ext_provider:
           new_disk[constants.IDISK_PROVIDER] = ext_provider
           for key in disk:
@@ -384,9 +388,65 @@ def ComputeDisks(op, default_vg):
           raise errors.OpPrereqError("Missing provider for template
'%s'" %
                                      constants.DT_EXT,
errors.ECODE_INVAL)

-    disks.append(new_disk)
+    new_disks.append(new_disk)

-  return disks
+  return new_disks
+
+
+def ComputeDisksInfo(disks, disk_template, default_vg, ext_params):
+  """Computes the new instance's disks for the template conversion.
+
+  This method is used by the disks template conversion mechanism. Using
the
+  'ComputeDisks' method as an auxiliary method computes the disks that
will be
+  used for generating the new disk template of the instance. It computes
the
+  size, mode, and name parameters from the instance's current disks,
such
as
+  the volume group and the access parameters for the templates that
support
+  them. For conversions targeting an extstorage template, the mandatory
+  provider's name or any user-provided extstorage parameters will also
be
+  included in the result.
+
+  @type disks: list of {objects.Disk}
+  @param disks: The current disks of the instance
+  @type disk_template: string
+  @param disk_template: The disk template of the instance
+  @type default_vg: string
+  @param default_vg: The default volume group to assume
+  @type ext_params: dict
+  @param ext_params: The extstorage parameters
+
+  @rtype: list of dictionaries
+  @return: The computed disks' information for the new template
+  @raise errors.OpPrereqError in case of failure
+
+  """
+  # Prepare the disks argument for the 'ComputeDisks' method.
+  inst_disks = [dict((key, value) for key, value in disk.iteritems()
+                     if key in constants.IDISK_PARAMS)
+                for disk in map(objects.Disk.ToDict, disks)]
+
+  # Update disks with the user-provided 'ext_params'.
+  for disk in inst_disks:
+    disk.update(ext_params)

  If 'ext_params' are user-provided, the user can supply keys that could
overwrite some information in 'disk'. Do we want this, or do(/will) we
check for the content of 'ext_params' somewhere?

No, we don't want this. The next patch series will contain the relevant
checks both in the client and LU side.



  +
+  # Compute the new disks' information.
+  new_disks = ComputeDisks(inst_disks, disk_template, default_vg)
+
+  # Add missing parameters to the previously computed disks.
+  for disk, new_disk in zip(disks, new_disks):
+    # Add IDISK_ACCESS parameter for conversions between disk templates
that
+    # support it.
+    if (disk_template in constants.DTS_HAVE_ACCESS and
+        constants.IDISK_ACCESS in disk.params):
+      new_disk[constants.IDISK_ACCESS] =
disk.params[constants.IDISK_ACCESS]
+
+    # For LVM-based conversions (plain <-> drbd) use the same volume
group.
+    if disk_template in constants.DTS_LVM:
+      if disk.dev_type == constants.DT_PLAIN:
+        new_disk[constants.IDISK_VG] = disk.logical_id[0]
+      elif disk.dev_type == constants.DT_DRBD8:
+        new_disk[constants.IDISK_VG] = disk.children[0].logical_id[0]
+
+  return new_disks


   def CheckRADOSFreeSpace():
--
1.7.10.4


  I'd be in favor of adding a unit test for ComputeDisksInfo,
ACK


  including a
check that it correctly replaces the original code for plain/DRBD in the
next patch.

I'm not sure I understand exactly what you mean here. Can you please
elaborate a bit more?

I mean, in patch 3 we have something like:

+    inst_disks = self.cfg.GetInstanceDisks(self.instance.uuid)
+    self.disks_info = ComputeDisksInfo(inst_disks, self.op.disk_template,
+                                       default_vg, ext_params)
+

...

-      disks = [{constants.IDISK_SIZE: d.size,
-                constants.IDISK_VG: d.logical_id[0]}
-               for d in self.cfg.GetInstanceDisks(self.instance.uuid)]
-      required = ComputeDiskSizePerVG(self.op.disk_template, disks)
+      required = ComputeDiskSizePerVG(self.op.disk_template,
self.disks_info)

So we could make a test that takes a value represnting instance disks (just
as if it were produced by cfg.GetInstanceDisks(...)) and test if

   [{constants.IDISK_SIZE: d.size, constants.IDISK_VG: d.logical_id[0]} for
d in inst_disks]

produces the same result as ComputeDisksInfo(...), which means that the
replacement is consistent with the original semantics.

ACK


Thanks,
Dimitris



Thanks,
Dimitris



Rest LGTM, thanks.



Reply via email to