commit f629a26246ade0887d282ae31e4e426d2d3c3d21
Author: Dimitris Aragiorgis <dimara@grnet.gr>
Date:   Mon Jun 4 23:20:09 2012 +0300

    Rapi support for networks
    
    Support:
     - GetNetwork(s)
     - CreateNetwork
     - ConnectNetwork
     - DisconnectNetwork
     - RemoveNetwork
    
    Signed-off-by: Dimitris Aragiorgis <dimara@grnet.gr>

diff --git a/lib/rapi/client.py b/lib/rapi/client.py
index b5a4df5..5138bb0 100644
--- a/lib/rapi/client.py
+++ b/lib/rapi/client.py
@@ -1625,6 +1625,117 @@ class GanetiRapiClient(object): # pylint: disable=R0904
                              ("/%s/nodes/%s/tags" %
                               (GANETI_RAPI_VERSION, node)), query, None)
 
+  def GetNetworks(self, bulk=False):
+    """Gets all networks in the cluster.
+
+    @type bulk: bool
+    @param bulk: whether to return all information about the networks
+
+    @rtype: list of dict or str
+    @return: if bulk is true, a list of dictionaries with info about all
+        networks in the cluster, else a list of names of those networks
+
+    """
+    query = []
+    _AppendIf(query, bulk, ("bulk", 1))
+
+    networks = self._SendRequest(HTTP_GET, "/%s/networks" % GANETI_RAPI_VERSION,
+                               query, None)
+    if bulk:
+      return networks
+    else:
+      return [n["name"] for n in networks]
+
+  def GetNetwork(self, network):
+    """Gets information about a network.
+
+    @type group: str
+    @param group: name of the network whose info to return
+
+    @rtype: dict
+    @return: info about the network
+
+    """
+    return self._SendRequest(HTTP_GET,
+                             "/%s/networks/%s" % (GANETI_RAPI_VERSION, network),
+                             None, None)
+
+  def CreateNetwork(self, network_name, network, gateway=None, network6=None,
+                    gateway6=None, mac_prefix=None, network_type=None,
+                    add_reserved_ips=None, dry_run=False):
+    """Creates a new network.
+
+    @type name: str
+    @param name: the name of network to create
+    @type dry_run: bool
+    @param dry_run: whether to peform a dry run
+
+    @rtype: string
+    @return: job id
+
+    """
+    query = []
+    _AppendDryRunIf(query, dry_run)
+
+    body = {
+      "network_name": network_name,
+      "gateway": gateway,
+      "network": network,
+      "gateway6": gateway6,
+      "network6": network6,
+      "mac_prefix": mac_prefix,
+      "network_type": network_type,
+      "add_reserved_ips": add_reserved_ips
+      }
+
+    return self._SendRequest(HTTP_POST, "/%s/networks" % GANETI_RAPI_VERSION,
+                             query, body)
+
+  def ConnectNetwork(self, network_name, group_name, mode, link):
+    """Connects a Network to a NodeGroup with the given netparams
+
+    """
+    body = {
+      "group_name": group_name,
+      "network_mode": mode,
+      "network_link": link
+      }
+
+    return self._SendRequest(HTTP_PUT,
+                             ("/%s/networks/%s/connect" %
+                             (GANETI_RAPI_VERSION, network_name)), None, body)
+
+  def DisconnectNetwork(self, network_name, group_name):
+    """Connects a Network to a NodeGroup with the given netparams
+
+    """
+    body = {
+      "group_name": group_name
+      }
+    return self._SendRequest(HTTP_PUT,
+                             ("/%s/networks/%s/disconnect" %
+                             (GANETI_RAPI_VERSION, network_name)), None, body)
+
+
+  def DeleteNetwork(self, network, dry_run=False):
+    """Deletes a network.
+
+    @type group: str
+    @param group: the network to delete
+    @type dry_run: bool
+    @param dry_run: whether to peform a dry run
+
+    @rtype: string
+    @return: job id
+
+    """
+    query = []
+    _AppendDryRunIf(query, dry_run)
+
+    return self._SendRequest(HTTP_DELETE,
+                             ("/%s/networks/%s" %
+                              (GANETI_RAPI_VERSION, network)), query, None)
+
   def GetGroups(self, bulk=False):
     """Gets all node groups in the cluster.
 
diff --git a/lib/rapi/connector.py b/lib/rapi/connector.py
index b701d71..a833fcf 100644
--- a/lib/rapi/connector.py
+++ b/lib/rapi/connector.py
@@ -89,7 +89,8 @@ class Mapper:
 
 
 def GetHandlers(node_name_pattern, instance_name_pattern,
-                group_name_pattern, job_id_pattern, disk_pattern,
+                group_name_pattern, network_name_pattern,
+                job_id_pattern, disk_pattern,
                 query_res_pattern):
   """Returns all supported resources and their handlers.
 
@@ -167,6 +168,14 @@ def GetHandlers(node_name_pattern, instance_name_pattern,
     re.compile(r"^/2/instances/(%s)/console$" % instance_name_pattern):
       rlib2.R_2_instances_name_console,
 
+    "/2/networks": rlib2.R_2_networks,
+    re.compile(r"^/2/networks/(%s)$" % network_name_pattern):
+      rlib2.R_2_networks_name,
+    re.compile(r"^/2/networks/(%s)/connect$" % network_name_pattern):
+      rlib2.R_2_networks_name_connect,
+    re.compile(r"^/2/networks/(%s)/disconnect$" % network_name_pattern):
+      rlib2.R_2_networks_name_disconnect,
+
     "/2/groups": rlib2.R_2_groups,
     re.compile(r"^/2/groups/(%s)$" % group_name_pattern):
       rlib2.R_2_groups_name,
@@ -197,6 +206,7 @@ def GetHandlers(node_name_pattern, instance_name_pattern,
     }
 
 
-CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN, _NAME_PATTERN,
+CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN,
+                             _NAME_PATTERN, _NAME_PATTERN,
                              constants.JOB_ID_TEMPLATE, _DISK_PATTERN,
                              _NAME_PATTERN))
diff --git a/lib/rapi/rlib2.py b/lib/rapi/rlib2.py
index e434340..9201a82 100644
--- a/lib/rapi/rlib2.py
+++ b/lib/rapi/rlib2.py
@@ -70,7 +70,8 @@ _COMMON_FIELDS = ["ctime", "mtime", "uuid", "serial_no", "tags"]
 I_FIELDS = ["name", "admin_state", "os",
             "pnode", "snodes",
             "disk_template",
-            "nic.ips", "nic.macs", "nic.modes", "nic.links", "nic.bridges",
+            "nic.ips", "nic.macs", "nic.modes",
+            "nic.links", "nic.networks", "nic.bridges",
             "network_port",
             "disk.sizes", "disk_usage",
             "beparams", "hvparams",
@@ -90,6 +91,14 @@ N_FIELDS = ["name", "offline", "master_candidate", "drained",
             "group.uuid",
             ] + _COMMON_FIELDS
 
+NET_FIELDS = ["name", "network", "gateway",
+              "network6", "gateway6",
+              "mac_prefix", "network_type",
+              "free_count", "reserved_count",
+              "map", "group_list", "inst_list",
+              "external_reservations",
+             ] 
+
 G_FIELDS = [
   "alloc_policy",
   "name",
@@ -642,6 +651,101 @@ class R_2_nodes_name_storage_repair(baserlib.OpcodeResource):
       })
 
 
+class R_2_networks(baserlib.OpcodeResource):
+  """/2/networks resource.
+
+  """
+  GET_OPCODE = opcodes.OpNetworkQuery
+  POST_OPCODE = opcodes.OpNetworkAdd
+  POST_RENAME = {
+    "name": "network_name",
+    }
+
+  def GetPostOpInput(self):
+    """Create a network.
+
+    """
+    assert not self.items
+    return (self.request_body, {
+      "dry_run": self.dryRun(),
+      })
+
+  def GET(self):
+    """Returns a list of all networks.
+
+    """
+    client = self.GetClient()
+
+    if self.useBulk():
+      bulkdata = client.QueryNetworks([], NET_FIELDS, False)
+      return baserlib.MapBulkFields(bulkdata, NET_FIELDS)
+    else:
+      data = client.QueryNetworks([], ["name"], False)
+      networknames = [row[0] for row in data]
+      return baserlib.BuildUriList(networknames, "/2/networks/%s",
+                                   uri_fields=("name", "uri"))
+
+
+class R_2_networks_name(baserlib.OpcodeResource):
+  """/2/network/[network_name] resource.
+
+  """
+  DELETE_OPCODE = opcodes.OpNetworkRemove
+
+  def GET(self):
+    """Send information about a network.
+
+    """
+    network_name = self.items[0]
+    client = self.GetClient()
+
+    result = baserlib.HandleItemQueryErrors(client.QueryNetworks,
+                                            names=[network_name],
+                                            fields=NET_FIELDS,
+                                            use_locking=self.useLocking())
+
+    return baserlib.MapFields(NET_FIELDS, result[0])
+
+  def GetDeleteOpInput(self):
+    """Delete a network.
+
+    """
+    assert len(self.items) == 1
+    return (self.request_body, {
+      "network_name": self.items[0],
+      "dry_run": self.dryRun(),
+      })
+
+class R_2_networks_name_connect(baserlib.OpcodeResource):
+  """/2/network/[network_name]/connect.
+
+  """
+  PUT_OPCODE = opcodes.OpNetworkConnect
+
+  def GetPutOpInput(self):
+    """Changes some parameters of node group.
+
+    """
+    assert self.items
+    return (self.request_body, {
+      "network_name": self.items[0],
+      })
+
+class R_2_networks_name_disconnect(baserlib.OpcodeResource):
+  """/2/network/[network_name]/disconnect.
+
+  """
+  PUT_OPCODE = opcodes.OpNetworkDisconnect
+
+  def GetPutOpInput(self):
+    """Changes some parameters of node group.
+
+    """
+    assert self.items
+    return (self.request_body, {
+      "network_name": self.items[0],
+      })
+
 class R_2_groups(baserlib.OpcodeResource):
   """/2/groups resource.
 
@@ -655,6 +759,7 @@ class R_2_groups(baserlib.OpcodeResource):
   def GetPostOpInput(self):
     """Create a node group.
 
+
     """
     assert not self.items
     return (self.request_body, {
