rapi: Implement /2/nodes/[node_name]/role resource
authorMichael Hanselmann <hansmi@google.com>
Mon, 13 Jul 2009 13:48:29 +0000 (15:48 +0200)
committerMichael Hanselmann <hansmi@google.com>
Mon, 13 Jul 2009 14:59:09 +0000 (16:59 +0200)
This resource can be used to retrieve and set the role of a node.

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>

doc/rapi.rst
lib/rapi/connector.py
lib/rapi/rlib2.py

index 0e74912..a913b32 100644 (file)
@@ -464,6 +464,40 @@ Example::
       ...
     ]
 
+``/2/nodes/[node_name]/role``
++++++++++++++++++++++++++++++
+
+Manages node role.
+
+It supports the following commands: ``GET``, ``PUT``.
+
+The role is always one of the following:
+
+  - drained
+  - master
+  - master-candidate
+  - offline
+  - regular
+
+``GET``
+~~~~~~~
+
+Returns the current node role.
+
+Example::
+
+    "master-candidate"
+
+``PUT``
+~~~~~~~
+
+Change the node role.
+
+The request is a string which should be PUT to this URI. The result will be a
+job id.
+
+It supports the ``force`` argument.
+
 ``/2/nodes/[node_name]/tags``
 +++++++++++++++++++++++++++++
 
index 43c15c0..9c99dcf 100644 (file)
@@ -154,6 +154,7 @@ CONNECTOR.update({
   "/2/nodes": rlib2.R_2_nodes,
   re.compile(r'^/2/nodes/([\w\._-]+)$'): rlib2.R_2_nodes_name,
   re.compile(r'^/2/nodes/([\w\._-]+)/tags$'): rlib2.R_2_nodes_name_tags,
+  re.compile(r'^/2/nodes/([\w\._-]+)/role$'): rlib2.R_2_nodes_name_role,
   "/2/instances": rlib2.R_2_instances,
   re.compile(r'^/2/instances/([\w\._-]+)$'): rlib2.R_2_instances_name,
   re.compile(r'^/2/instances/([\w\._-]+)/tags$'): rlib2.R_2_instances_name_tags,
index d79a0fc..550692a 100644 (file)
@@ -30,7 +30,6 @@ from ganeti import cli
 from ganeti.rapi import baserlib
 
 
-
 I_FIELDS = ["name", "admin_state", "os",
             "pnode", "snodes",
             "disk_template",
@@ -48,6 +47,20 @@ N_FIELDS = ["name", "offline", "master_candidate", "drained",
             "ctotal", "cnodes", "csockets",
             ]
 
+_NR_DRAINED = "drained"
+_NR_MASTER_CANDIATE = "master-candidate"
+_NR_MASTER = "master"
+_NR_OFFLINE = "offline"
+_NR_REGULAR = "regular"
+
+_NR_MAP = {
+  "M": _NR_MASTER,
+  "C": _NR_MASTER_CANDIATE,
+  "D": _NR_DRAINED,
+  "O": _NR_OFFLINE,
+  "R": _NR_REGULAR,
+  }
+
 
 class R_version(baserlib.R_Generic):
   """/version resource.
@@ -190,6 +203,64 @@ class R_2_nodes_name(baserlib.R_Generic):
     return baserlib.MapFields(N_FIELDS, result[0])
 
 
+class R_2_nodes_name_role(baserlib.R_Generic):
+  """ /2/nodes/[node_name]/role resource.
+
+  """
+  def GET(self):
+    """Returns the current node role.
+
+    @return: Node role
+
+    """
+    node_name = self.items[0]
+    client = baserlib.GetClient()
+    result = client.QueryNodes(names=[node_name], fields=["role"],
+                               use_locking=self.useLocking())
+
+    return _NR_MAP[result[0][0]]
+
+  def PUT(self):
+    """Sets the node role.
+
+    @return: a job id
+
+    """
+    if not isinstance(self.req.request_body, basestring):
+      raise http.HttpBadRequest("Invalid body contents, not a string")
+
+    node_name = self.items[0]
+    role = self.req.request_body
+
+    if role == _NR_REGULAR:
+      candidate = False
+      offline = False
+      drained = False
+
+    elif role == _NR_MASTER_CANDIATE:
+      candidate = True
+      offline = drained = None
+
+    elif role == _NR_DRAINED:
+      drained = True
+      candidate = offline = None
+
+    elif role == _NR_OFFLINE:
+      offline = True
+      candidate = drained = None
+
+    else:
+      raise http.HttpBadRequest("Can't set '%s' role" % role)
+
+    op = opcodes.OpSetNodeParams(node_name=node_name,
+                                 master_candidate=candidate,
+                                 offline=offline,
+                                 drained=drained,
+                                 force=bool(self.useForce()))
+
+    return baserlib.SubmitJob([op])
+
+
 class R_2_instances(baserlib.R_Generic):
   """/2/instances resource.