Revision 414ebaf1

b/doc/rapi.rst
497 497
   :exclude: group_name, force, dry_run
498 498

  
499 499

  
500
``/2/groups/[group_name]/tags``
501
+++++++++++++++++++++++++++++++
502

  
503
Manages per-nodegroup tags.
504

  
505
Supports the following commands: ``GET``, ``PUT``, ``DELETE``.
506

  
507
``GET``
508
~~~~~~~
509

  
510
Returns a list of tags.
511

  
512
Example::
513

  
514
    ["tag1", "tag2", "tag3"]
515

  
516
``PUT``
517
~~~~~~~
518

  
519
Add a set of tags.
520

  
521
The request as a list of strings should be ``PUT`` to this URI. The
522
result will be a job id.
523

  
524
It supports the ``dry-run`` argument.
525

  
526

  
527
``DELETE``
528
~~~~~~~~~~
529

  
530
Delete a tag.
531

  
532
In order to delete a set of tags, the DELETE request should be addressed
533
to URI like::
534

  
535
    /tags?tag=[tag]&tag=[tag]
536

  
537
It supports the ``dry-run`` argument.
538

  
539

  
500 540
``/2/instances``
501 541
++++++++++++++++
502 542

  
b/lib/rapi/baserlib.py
92 92
  """Helper function to retrieve tags.
93 93

  
94 94
  """
95
  if kind == constants.TAG_INSTANCE or kind == constants.TAG_NODE:
95
  if kind in (constants.TAG_INSTANCE,
96
              constants.TAG_NODEGROUP,
97
              constants.TAG_NODE):
96 98
    if not name:
97 99
      raise http.HttpBadRequest("Missing name on tag request")
98 100
    cl = GetClient()
99 101
    if kind == constants.TAG_INSTANCE:
100 102
      fn = cl.QueryInstances
103
    elif kind == constants.TAG_NODEGROUP:
104
      fn = cl.QueryGroups
101 105
    else:
102 106
      fn = cl.QueryNodes
103 107
    result = fn(names=[name], fields=["tags"], use_locking=False)
b/lib/rapi/client.py
1620 1620
                             ("/%s/groups/%s/assign-nodes" %
1621 1621
                             (GANETI_RAPI_VERSION, group)), query, body)
1622 1622

  
1623
  def GetGroupTags(self, group):
1624
    """Gets tags for a node group.
1625

  
1626
    @type group: string
1627
    @param group: Node group whose tags to return
1628

  
1629
    @rtype: list of strings
1630
    @return: tags for the group
1631

  
1632
    """
1633
    return self._SendRequest(HTTP_GET,
1634
                             ("/%s/groups/%s/tags" %
1635
                              (GANETI_RAPI_VERSION, group)), None, None)
1636

  
1637
  def AddGroupTags(self, group, tags, dry_run=False):
1638
    """Adds tags to a node group.
1639

  
1640
    @type group: str
1641
    @param group: group to add tags to
1642
    @type tags: list of string
1643
    @param tags: tags to add to the group
1644
    @type dry_run: bool
1645
    @param dry_run: whether to perform a dry run
1646

  
1647
    @rtype: string
1648
    @return: job id
1649

  
1650
    """
1651
    query = [("tag", t) for t in tags]
1652
    if dry_run:
1653
      query.append(("dry-run", 1))
1654

  
1655
    return self._SendRequest(HTTP_PUT,
1656
                             ("/%s/groups/%s/tags" %
1657
                              (GANETI_RAPI_VERSION, group)), query, None)
1658

  
1659
  def DeleteGroupTags(self, group, tags, dry_run=False):
1660
    """Deletes tags from a node group.
1661

  
1662
    @type group: str
1663
    @param group: group to delete tags from
1664
    @type tags: list of string
1665
    @param tags: tags to delete
1666
    @type dry_run: bool
1667
    @param dry_run: whether to perform a dry run
1668
    @rtype: string
1669
    @return: job id
1670

  
1671
    """
1672
    query = [("tag", t) for t in tags]
1673
    if dry_run:
1674
      query.append(("dry-run", 1))
1675

  
1676
    return self._SendRequest(HTTP_DELETE,
1677
                             ("/%s/groups/%s/tags" %
1678
                              (GANETI_RAPI_VERSION, group)), query, None)
1679

  
1623 1680
  def Query(self, what, fields, filter_=None):
1624 1681
    """Retrieves information about resources.
1625 1682

  
b/lib/rapi/connector.py
230 230
      rlib2.R_2_groups_name_rename,
231 231
    re.compile(r'^/2/groups/(%s)/assign-nodes$' % group_name_pattern):
232 232
      rlib2.R_2_groups_name_assign_nodes,
233
    re.compile(r'^/2/groups/(%s)/tags$' % group_name_pattern):
234
      rlib2.R_2_groups_name_tags,
233 235

  
234 236
    "/2/jobs": rlib2.R_2_jobs,
235 237
    re.compile(r"^/2/jobs/(%s)$" % job_id_pattern):
b/lib/rapi/rlib2.py
1375 1375
  TAG_LEVEL = constants.TAG_NODE
1376 1376

  
1377 1377

  
1378
class R_2_groups_name_tags(_R_Tags):
1379
  """ /2/groups/[group_name]/tags resource.
1380

  
1381
  Manages per-nodegroup tags.
1382

  
1383
  """
1384
  TAG_LEVEL = constants.TAG_NODEGROUP
1385

  
1386

  
1378 1387
class R_2_tags(_R_Tags):
1379 1388
  """ /2/tags resource.
1380 1389

  
b/test/ganeti.rapi.client_unittest.py
1087 1087
      self.assertEqual(data["amount"], amount)
1088 1088
      self.assertEqual(self.rapi.CountPending(), 0)
1089 1089

  
1090
  def testGetGroupTags(self):
1091
    self.rapi.AddResponse("[]")
1092
    self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1093
    self.assertHandler(rlib2.R_2_groups_name_tags)
1094
    self.assertItems(["fooGroup"])
1095

  
1096
  def testAddGroupTags(self):
1097
    self.rapi.AddResponse("1234")
1098
    self.assertEqual(1234,
1099
        self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1100
    self.assertHandler(rlib2.R_2_groups_name_tags)
1101
    self.assertItems(["fooGroup"])
1102
    self.assertDryRun()
1103
    self.assertQuery("tag", ["awesome"])
1104

  
1105
  def testDeleteGroupTags(self):
1106
    self.rapi.AddResponse("25826")
1107
    self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1108
                                                        dry_run=True))
1109
    self.assertHandler(rlib2.R_2_groups_name_tags)
1110
    self.assertItems(["foo"])
1111
    self.assertDryRun()
1112
    self.assertQuery("tag", ["awesome"])
1113

  
1090 1114
  def testQuery(self):
1091 1115
    for idx, what in enumerate(constants.QR_VIA_RAPI):
1092 1116
      for idx2, filter_ in enumerate([None, ["?", "name"]]):

Also available in: Unified diff