commit d6a7518ad5e0ea38ddba3cc4549a35b0617ad425
Author: Jose A. Lopes <jabolopes@google.com>
Date:   Mon Feb 10 13:13:18 2014 +0100

    'LUClusterSetParams' creates the instance communication net
    
    Extend 'LUClusterSetParams' to create the user-supplied instance
    communication network in case this network does not exist.  Note that
    if the user-supplied network already exists, nothing needs to be done
    as 'CheckPrereq' already checks this network's configuration.
    
    With this patch, Ganeti will be able to create the instance
    communication network automatically.  The following example shows the
    command line options that instruct Ganeti to enable the instance
    communication network and, if this network does not exist, then Ganeti
    creates it.
    
      gnt-cluster modify --instance-communication-network=mynetwork
    
    The instance communication network can be disabled by setting the
    parameter to the empty string, for example:
    
      gnt-cluster modify --instance-communication-network=
    
    This will not destroy the network itself or modify any running
    instances.  This will have to be done manually.
    
    In this patch:
    
    * 'LUClusterSetParams._EnsureInstanceCommunicationNetwork' creates and
      connects to all groups the instance communication network by
      resorting the 'OpNetworkAdd' and 'OpNetworkConnect'.
    
    * 'LUClusterSetParams.ModifyInstanceCommunicationNetwork' compares the
      previous configured 'instance_communication_network' with the
      user-supplied one and determines whether the opcodes is changing the
      configuration, which might require creating the instance
      communication network.
    
    * Extend 'LUClusterSetParams.Exec' to call
      'ModifyInstanceCommunicationNetwork' and handle the user-supplied
      'instance_communication_network'.
    
    * Because 'ClusterSetParams' now may return a list of jobs, the type
      of the opcode must be updated in 'Ganeti.OpCodes'.
    
    * Add network related constants to 'Ganeti.Constants'.
    
    Signed-off-by: Jose A. Lopes <jabolopes@google.com>
    Reviewed-by: Helga Velroyen <helgav@google.com>

diff --git a/lib/cmdlib/cluster.py b/lib/cmdlib/cluster.py
index 7c4c351..33433cc 100644
--- a/lib/cmdlib/cluster.py
+++ b/lib/cmdlib/cluster.py
@@ -1360,6 +1360,133 @@ class LUClusterSetParams(LogicalUnit):
         feedback_fn("Cluster DRBD helper already in desired state,"
                     " not changing")
 
+  @staticmethod
+  def _EnsureInstanceCommunicationNetwork(cfg, network_name):
+    """Ensure that the instance communication network exists and is
+    connected to all groups.
+
+    The instance communication network given by L{network_name} it is
+    created, if necessary, via the opcode 'OpNetworkAdd'.  Also, the
+    instance communication network is connected to all existing node
+    groups, if necessary, via the opcode 'OpNetworkConnect'.
+
+    @type cfg: L{ganeti.config.ConfigWriter}
+    @param cfg: Ganeti configuration
+
+    @type network_name: string
+    @param network_name: instance communication network name
+
+    @rtype: L{ganeti.cmdlib.ResultWithJobs} or L{None}
+    @return: L{ganeti.cmdlib.ResultWithJobs} if the instance
+             communication needs to be created or it needs to be
+             connected to a group, otherwise L{None}
+
+    """
+    jobs = []
+
+    try:
+      network_uuid = cfg.LookupNetwork(network_name)
+      network_exists = True
+    except errors.OpPrereqError:
+      network_exists = False
+
+    if not network_exists:
+      op = opcodes.OpNetworkAdd(
+        network_name=network_name,
+        gateway=None,
+        network=constants.INSTANCE_COMMUNICATION_NETWORK4,
+        gateway6=None,
+        network6=constants.INSTANCE_COMMUNICATION_NETWORK6,
+        mac_prefix=constants.INSTANCE_COMMUNICATION_MAC_PREFIX,
+        add_reserved_ips=None,
+        conflicts_check=True,
+        tags=[])
+      jobs.append(op)
+
+    for group_uuid in cfg.GetNodeGroupList():
+      group = cfg.GetNodeGroup(group_uuid)
+
+      if network_exists:
+        network_connected = network_uuid in group.networks
+      else:
+        # The network was created asynchronously by the previous
+        # opcode and, therefore, we don't have access to its
+        # network_uuid.  As a result, we assume that the network is
+        # not connected to any group yet.
+        network_connected = False
+
+      if not network_connected:
+        op = opcodes.OpNetworkConnect(
+          group_name=group_uuid,
+          network_name=network_name,
+          network_mode=constants.NIC_MODE_ROUTED,
+          network_link=constants.INSTANCE_COMMUNICATION_NETWORK_LINK,
+          conflicts_check=True)
+        jobs.append(op)
+
+    if jobs:
+      return ResultWithJobs([jobs])
+    else:
+      return None
+
+  @staticmethod
+  def _ModifyInstanceCommunicationNetwork(cfg, cluster, network_name,
+                                          feedback_fn):
+    """Update the instance communication network stored in the cluster
+    configuration.
+
+    Compares the user-supplied instance communication network against
+    the one stored in the Ganeti cluster configuration.  If there is a
+    change, the instance communication network may be possibly created
+    and connected to all groups (see
+    L{LUClusterSetParams._EnsureInstanceCommunicationNetwork}).
+
+    @type cfg: L{ganeti.config.ConfigWriter}
+    @param cfg: Ganeti configuration
+
+    @type cluster: L{ganeti.objects.Cluster}
+    @param cluster: Ganeti cluster
+
+    @type network_name: string
+    @param network_name: instance communication network name
+
+    @type feedback_fn: function
+    @param feedback_fn: see L{ganeti.cmdlist.base.LogicalUnit}
+
+    @rtype: L{LUClusterSetParams._EnsureInstanceCommunicationNetwork} or L{None}
+    @return: see L{LUClusterSetParams._EnsureInstanceCommunicationNetwork}
+
+    """
+    config_network_name = cfg.GetInstanceCommunicationNetwork()
+
+    if network_name == config_network_name:
+      feedback_fn("Instance communication network already is '%s', nothing to"
+                  " do." % network_name)
+    else:
+      try:
+        cfg.LookupNetwork(config_network_name)
+        feedback_fn("Previous instance communication network '%s'"
+                    " should be removed manually." % config_network_name)
+      except errors.OpPrereqError:
+        pass
+
+      if network_name:
+        feedback_fn("Changing instance communication network to '%s', only new"
+                    " instances will be affected."
+                    % network_name)
+      else:
+        feedback_fn("Disabling instance communication network, only new"
+                    " instances will be affected.")
+
+      cluster.instance_communication_network = network_name
+
+      if network_name:
+        return LUClusterSetParams._EnsureInstanceCommunicationNetwork(
+          cfg,
+          network_name)
+      else:
+        return None
+
   def Exec(self, feedback_fn):
     """Change the parameters of the cluster.
 
@@ -1502,6 +1629,13 @@ class LUClusterSetParams(LogicalUnit):
       result.Warn("Could not re-enable the master ip on the master,"
                   " please restart manually", self.LogWarning)
 
+    network_name = self.op.instance_communication_network
+    if network_name is not None:
+      return self._ModifyInstanceCommunicationNetwork(self.cfg, self.cluster,
+                                                      network_name, feedback_fn)
+    else:
+      return None
+
 
 class LUClusterVerify(NoHooksLU):
   """Submits all jobs necessary to verify the cluster.
diff --git a/src/Ganeti/Constants.hs b/src/Ganeti/Constants.hs
index 068610f..3d53dbe 100644
--- a/src/Ganeti/Constants.hs
+++ b/src/Ganeti/Constants.hs
@@ -4759,13 +4759,35 @@ glusterPortDefault :: Int
 glusterPortDefault = 24007
 
 -- * Instance communication
+--
+-- The instance communication attaches an additional NIC, named
+-- @instanceCommunicationNicPrefix@:@instanceName@ and prefixed by
+-- @instanceCommunicationMacPrefix@, to the instances that have
+-- instance communication enabled.  This NIC is part of the network
+-- @instanceCommunicationNetworkName@, which is in turn created by
+-- 'gnt-network'.  This network is defined as
+-- @instanceCommunicationNetwork4@ for IPv4 and
+-- @instanceCommunicationNetwork6@ for IPv6.
 
 instanceCommunicationDoc :: String
 instanceCommunicationDoc =
   "Enable or disable the communication mechanism for an instance"
 
-instanceCommunicationNetwork :: String
-instanceCommunicationNetwork = "ganeti:network:communication"
+instanceCommunicationMacPrefix :: String
+instanceCommunicationMacPrefix = "52:54:00"
+
+-- | The instance communication network is a link-local IPv4/IPv6
+-- network because the communication is meant to be exclusive between
+-- the host and the guest and not routed outside the node.
+instanceCommunicationNetwork4 :: String
+instanceCommunicationNetwork4 = "169.254.0.0/16"
+
+-- | See 'instanceCommunicationNetwork4'.
+instanceCommunicationNetwork6 :: String
+instanceCommunicationNetwork6 = "fe80::/10"
+
+instanceCommunicationNetworkLink :: String
+instanceCommunicationNetworkLink = "communication_rt"
 
 instanceCommunicationNicPrefix :: String
 instanceCommunicationNicPrefix = "ganeti:communication:"
diff --git a/src/Ganeti/OpCodes.hs b/src/Ganeti/OpCodes.hs
index 3e24403..f5760ed 100644
--- a/src/Ganeti/OpCodes.hs
+++ b/src/Ganeti/OpCodes.hs
@@ -202,7 +202,7 @@ $(genOpCode "OpCode"
      ],
      "name")
   , ("OpClusterSetParams",
-     [t| () |],
+     [t| Either () JobIdListOnly |],
      OpDoc.opClusterSetParams,
      [ pForce
      , pHvState
