add support for kvm balloon in ganeti

A patch against the devel-4.2 branch of ganeti was implemented to support the balloon memory driver KVM.

experiment with balloon


The control file created by ganeti for each KVM is located in the directory /var/run/ganeti/kvm-hypervisor/ctrl and named after the instance name with the control suffix. It can be used to send a balloon command to the KVM and check that it works as
expected:

echo balloon 256 |
 socat - UNIX-CLIENT:/var/run/ganeti/kvm-hypervisor/ctrl/trac.tetaneutral.net.monitor

development environment

The mailing list had no previous discussions about kvm balloon and the primary developer of the project Iustin Pop wrote on #ganeti that it would be welcome:

(01:25:43 PM) dachary: Hi. I'm going to give a shot at implementing kvm ballooning support. Unless there is a good reason not to.
(01:26:39 PM) iustin: patches welcome
(01:26:53 PM) iustin: but mind the CLA
(01:28:54 PM) dachary: iustin: thanks for the reminder.
(01:29:57 PM) dachary: iustin: I would be impressed if you remember the discussion we had a few years ago on this topic ;-)
(01:30:11 PM) iustin: probably not, I tend to flush buffers often :)
(01:31:00 PM) iustin: all I meant is, if you didn't sign the CLA, please do so before sending the patches; I know some people refuse to do so *after* they send patches, which is awkward

The developer guidelines say
Development of new features for the next major or minor version goes on in the master branch. Bug fixes and small changes are done on the devel-x.y branch and then merged into master.
therefore

git checkout origin/devel-2.4

Before doing anything the tests are run after de-installing ganeti2:

make commit-check

There is a test file decicated to the KVM hypervisor code and it can be run as follows:

make TESTS=test/ganeti.hypervisor.hv_kvm_unittest.py check

implementation

In order to preserve backward compatibility, the -balloon option is not added unless the balloon hypervisor parameter is explicitly specified. The KVM may be compiled to activate ballooning by default or not and forcing the option would change this behavior and produce unexpected results.

--- a/lib/hypervisor/hv_kvm.py
+++ b/lib/hypervisor/hv_kvm.py
@@ -191,6 +191,8 @@ class KVMHypervisor(hv_base.BaseHypervisor):
       hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
     constants.HV_VHOST_NET: hv_base.NO_CHECK,
     constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
+    constants.HV_KVM_BALLOON:
+      hv_base.ParamInSet(True, constants.HT_KVM_VALID_BALLOON_TYPES),
     constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
     }

@@ -688,6 +690,10 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     if hvp[constants.HV_KVM_USE_CHROOT]:
       kvm_cmd.extend(['-chroot', self._InstanceChrootDir(instance.name)])

+    balloon = hvp[constants.HV_KVM_BALLOON]
+    if balloon:
+      kvm_cmd.extend(['-balloon', balloon])
+
     # Save the current instance nics, but defer their expansion as parameters,
     # as we'll need to generate executable temp files for them.
     kvm_nics = instance.nics
diff --git a/man/gnt-instance.rst b/man/gnt-instance.rst
index f4dc84e..9d47ac4 100644
--- a/man/gnt-instance.rst
+++ b/man/gnt-instance.rst
@@ -405,6 +405,19 @@ use\_chroot

     It is set to ``false`` by default.

+balloon
+    Valid for the KVM hypervisor.
+
+    This string option determines wether to run the KVM instance with
+    a balloon device or not. If omitted the presence of the device in
+    the instance depends on the KVM compilation defaults.
+
+    If it is set to ``none`` the instance will have no ballooning
+    device.
+
+    If it is set to ``virtio`` the instance will a virtio ballooning
+    device.
+
 migration\_downtime
     Valid for the KVM hypervisor.

diff --git a/test/ganeti.hypervisor.hv_kvm_unittest.py b/test/ganeti.hypervisor.hv_kvm_unittest.py
index 166d7dd..8801124 100755
--- a/test/ganeti.hypervisor.hv_kvm_unittest.py
+++ b/test/ganeti.hypervisor.hv_kvm_unittest.py
@@ -21,6 +21,7 @@

 """Script for testing the hypervisor.hv_kvm module"""

+import copy
 import unittest

 from ganeti import constants
@@ -65,6 +66,36 @@ class TestConsole(unittest.TestCase):
     self.assertEqual(cons.port, constants.VNC_BASE_PORT + 10)
     self.assertEqual(cons.display, 10)

+  def testBalloon(self):
+    instance = objects.Instance(name="kvm.example.com",
+                                primary_node="node7235")
+    _DIRS = hv_kvm.KVMHypervisor._DIRS
+    hv_kvm.KVMHypervisor._DIRS = []
+    instance.hvparams = copy.deepcopy(constants.HVC_DEFAULTS[constants.HT_KVM])
+    instance.beparams = constants.BEC_DEFAULTS
+    #
+    # by default -balloon is omitted, for backward compatibility
+    #
+    (kvm_cmd, kvm_nics, hvparams) = hv_kvm.KVMHypervisor()._GenerateKVMRuntime(instance, [])
+    self.assertEqual(hvparams[constants.HV_KVM_BALLOON], constants.HT_BALLOON_DEFAULT)
+    found = False
+    for i in range(len(kvm_cmd)):
+      if kvm_cmd[i] == '-balloon':
+        found = True
+    self.assertFalse(found)
+    #
+    # if balloon=virtio or balloon=none it translates into -balloon none and -balloon virtio
+    #
+    for value in ( constants.HT_BALLOON_NONE, constants.HT_BALLOON_VIRTIO ):
+      instance.hvparams[constants.HV_KVM_BALLOON] = value
+      (kvm_cmd, kvm_nics, hvparams) = hv_kvm.KVMHypervisor()._GenerateKVMRuntime(instance, [])
+      found = False
+      for i in range(len(kvm_cmd)):
+        if kvm_cmd[i] == '-balloon' and kvm_cmd[i + 1] == value:
+          found = True
+      self.assertTrue(found)
+    hv_kvm.KVMHypervisor._DIRS = _DIRS
+
   def testNoConsole(self):
     instance = objects.Instance(name="kvm.example.com",
                                 primary_node="node24325",

submission

The google CLA does not promise that the contributed code will be Free Software. It clearly states that it may be released under a proprietary license for the benefit of google. Authorizing a company to create proprietary software from a volunteer contribution has no advantage. In the case of the above contribution, it is so trivial that it is not covered by copyright law and could be inserted in the codebase without asking for permission or even mentioning the name of the original author. However, the google lawers refuse to make such a distinction and have instructed the project leaders to even refuse contributions that fall under this category.
This policy forbids the ganeti developers from using the patch above. Interestingly it also prevents them from implementing it because it is so trivial that there is only one way to implement it. Which is the reason why it is not covered by copyright in the first place. There is little doubt that support for balloon will eventually be implemented in ganeti and this will demonstrate that the google policy regarding trivial patches cannot be upheld.