Ganeti currently supports two modes of operation for instance NICs:

- bridged mode, where network interfaces are expected to be attached to bridges
  present on the hardware nodes. In this mode the bridges *must* exist before
  any instance-related action is taken (e.g. startup, migration).

- routed mode, where network interfaces are expected to be routed via some
  policy routing mechanism. For these interfaces, ganeti currently requires an
  IP address.

These two cases cover most of the desired functionality, however there may be
cases where the prerequisites (pre-existing bridges and ip addresses) can be
fulfilled outside the scope of Ganeti. For example, one may rely on KVM's ifup
script to dynamically provision bridges for 802.1q VLANs on trunk ports.

To this end, we add a third mode, "manual", which simply passes the ip and link
parameters directly to the network scripts, without interpreting them or
imposing any kind of requirements. Site-local requirements can be enforced
using pre-hooks, which can in turn deny starting an instance with an abnormal
network configuration.

Signed-off-by: Apollon Oikonomopoulos <[email protected]>
---
 lib/config.py                  |    2 ++
 lib/constants.py               |    4 +++-
 man/gnt-cluster.rst            |    5 +++--
 man/gnt-instance.rst           |    7 +++++--
 test/ganeti.config_unittest.py |    2 ++
 test/ganeti.query_unittest.py  |    7 ++++++-
 6 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/lib/config.py b/lib/config.py
index 0253a23..513009c 100644
--- a/lib/config.py
+++ b/lib/config.py
@@ -573,6 +573,8 @@ class ConfigWriter:
           link = "bridge:%s" % nic_link
         elif nic_mode == constants.NIC_MODE_ROUTED:
           link = "route:%s" % nic_link
+        elif nic_mode == constants.NIC_MODE_MANUAL:
+          link = "manual:%s" % nic_link
         else:
           raise errors.ProgrammerError("NIC mode '%s' not handled" % nic_mode)
 
diff --git a/lib/constants.py b/lib/constants.py
index a33186b..313b6b4 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -745,8 +745,10 @@ NIC_LINK = "link"
 
 NIC_MODE_BRIDGED = "bridged"
 NIC_MODE_ROUTED = "routed"
+NIC_MODE_MANUAL = "manual"
 
-NIC_VALID_MODES = frozenset([NIC_MODE_BRIDGED, NIC_MODE_ROUTED])
+NIC_VALID_MODES = frozenset([NIC_MODE_BRIDGED, NIC_MODE_ROUTED,
+                             NIC_MODE_MANUAL])
 
 NICS_PARAMETER_TYPES = {
     NIC_MODE: VTYPE_STRING,
diff --git a/man/gnt-cluster.rst b/man/gnt-cluster.rst
index d3fcecd..1488cf7 100644
--- a/man/gnt-cluster.rst
+++ b/man/gnt-cluster.rst
@@ -299,14 +299,15 @@ parameters for the cluster. The parameter format is a 
comma-separated
 list of key=value pairs with the following supported keys:
 
 mode
-    The default nic mode, 'routed' or 'bridged'.
+    The default nic mode, 'routed', 'bridged' or 'manual'.
 
 link
     In bridged mode the default NIC bridge. In routed mode it
     represents an hypervisor-vif-script dependent value to allow
     different instance groups. For example under the KVM default
     network script it is interpreted as a routing table number or
-    name.
+    name. In manual mode, the interpration of this parameter is left
+    entirely to the hypervisor network configuration script.
 
 The option ``--maintain-node-health`` allows to enable/disable
 automatic maintenance actions on nodes. Currently these include
diff --git a/man/gnt-instance.rst b/man/gnt-instance.rst
index b08b955..9a632be 100644
--- a/man/gnt-instance.rst
+++ b/man/gnt-instance.rst
@@ -102,13 +102,16 @@ ip
     the node expects the instance to use)
 
 mode
-    specifies the connection mode for this nic: routed or bridged.
+    specifies the connection mode for this nic: routed, bridged or
+    manual.
 
 link
     in bridged mode specifies the bridge to attach this NIC to, in
     routed mode it's intended to differentiate between different
     routing tables/instance groups (but the meaning is dependent on
-    the network script, see gnt-cluster(8) for more details)
+    the network script, see gnt-cluster(8) for more details). In manual
+    mode, the interpretation of this parameter is up to the hypervisor
+    network configuration script.
 
 
 Of these "mode" and "link" are nic parameters, and inherit their
diff --git a/test/ganeti.config_unittest.py b/test/ganeti.config_unittest.py
index a21bfa6..2659d5b 100755
--- a/test/ganeti.config_unittest.py
+++ b/test/ganeti.config_unittest.py
@@ -176,11 +176,13 @@ class TestConfigRunner(unittest.TestCase):
     link = constants.NIC_LINK
     m_bridged = constants.NIC_MODE_BRIDGED
     m_routed = constants.NIC_MODE_ROUTED
+    m_manual = constants.NIC_MODE_MANUAL
     CheckSyntax = objects.NIC.CheckParameterSyntax
 
     CheckSyntax(constants.NICC_DEFAULTS)
     CheckSyntax({mode: m_bridged, link: 'br1'})
     CheckSyntax({mode: m_routed, link: 'default'})
+    CheckSyntax({mode: m_manual, link: 'default'})
     self.assertRaises(errors.ConfigurationError,
                       CheckSyntax, {mode: '000invalid', link: 'any'})
     self.assertRaises(errors.ConfigurationError,
diff --git a/test/ganeti.query_unittest.py b/test/ganeti.query_unittest.py
index 213470a..7b71b7e 100755
--- a/test/ganeti.query_unittest.py
+++ b/test/ganeti.query_unittest.py
@@ -689,6 +689,11 @@ class TestInstanceQuery(unittest.TestCase):
                         constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
                         constants.NIC_LINK: "eth123",
                         }),
+          objects.NIC(ip="192.0.2.5", mac=macs.pop(),
+                      nicparams={
+                        constants.NIC_MODE: constants.NIC_MODE_MANUAL,
+                        constants.NIC_LINK: "eth456",
+                        }),
           ],
         osparams={}),
       objects.Instance(name="inst5", hvparams={}, nics=[],
@@ -739,7 +744,7 @@ class TestInstanceQuery(unittest.TestCase):
     inst_bridges = {
       "inst3": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE],
       "inst4": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE,
-                None, "eth123"],
+                None, "eth123", None],
       }
 
     live_data = {
-- 
1.7.2.5

Reply via email to