Revision 067dda99

b/util/rapi.py
34 34
# be standalone.
35 35

  
36 36
import logging
37
import simplejson
37 38
import socket
38 39
import urllib
39 40
import threading
40 41
import pycurl
41 42

  
42 43
try:
43
  import simplejson as json
44
except ImportError:
45
  import json
46

  
47
try:
48 44
  from cStringIO import StringIO
49 45
except ImportError:
50 46
  from StringIO import StringIO
......
75 71
# Internal constants
76 72
_REQ_DATA_VERSION_FIELD = "__version__"
77 73
_INST_CREATE_REQV1 = "instance-create-reqv1"
74
_INST_REINSTALL_REQV1 = "instance-reinstall-reqv1"
78 75
_INST_NIC_PARAMS = frozenset(["mac", "ip", "mode", "link", "bridge"])
79 76
_INST_CREATE_V0_DISK_PARAMS = frozenset(["size"])
80 77
_INST_CREATE_V0_PARAMS = frozenset([
......
239 236
  return _ConfigCurl
240 237

  
241 238

  
242
class GanetiRapiClient(object):
239
class GanetiRapiClient(object): # pylint: disable-msg=R0904
243 240
  """Ganeti RAPI client.
244 241

  
245 242
  """
246 243
  USER_AGENT = "Ganeti RAPI Client"
247
  _json_encoder = json.JSONEncoder(sort_keys=True)
244
  _json_encoder = simplejson.JSONEncoder(sort_keys=True)
248 245

  
249 246
  def __init__(self, host, port=GANETI_RAPI_PORT,
250 247
               username=None, password=None, logger=logging,
......
421 418

  
422 419
    # Was anything written to the response buffer?
423 420
    if encoded_resp_body.tell():
424
      response_content = json.loads(encoded_resp_body.getvalue())
421
      response_content = simplejson.loads(encoded_resp_body.getvalue())
425 422
    else:
426 423
      response_content = None
427 424

  
......
484 481
    return self._SendRequest(HTTP_GET, "/%s/info" % GANETI_RAPI_VERSION,
485 482
                             None, None)
486 483

  
484
  def RedistributeConfig(self):
485
    """Tells the cluster to redistribute its configuration files.
486

  
487
    @return: job id
488

  
489
    """
490
    return self._SendRequest(HTTP_PUT,
491
                             "/%s/redistribute-config" % GANETI_RAPI_VERSION,
492
                             None, None)
493

  
494
  def ModifyCluster(self, **kwargs):
495
    """Modifies cluster parameters.
496

  
497
    More details for parameters can be found in the RAPI documentation.
498

  
499
    @rtype: int
500
    @return: job id
501

  
502
    """
503
    body = kwargs
504

  
505
    return self._SendRequest(HTTP_PUT,
506
                             "/%s/modify" % GANETI_RAPI_VERSION, None, body)
507

  
487 508
  def GetClusterTags(self):
488 509
    """Gets the cluster tags.
489 510

  
......
746 767
                             ("/%s/instances/%s/modify" %
747 768
                              (GANETI_RAPI_VERSION, instance)), None, body)
748 769

  
770
  def ActivateInstanceDisks(self, instance, ignore_size=None):
771
    """Activates an instance's disks.
772

  
773
    @type instance: string
774
    @param instance: Instance name
775
    @type ignore_size: bool
776
    @param ignore_size: Whether to ignore recorded size
777
    @return: job id
778

  
779
    """
780
    query = []
781
    if ignore_size:
782
      query.append(("ignore_size", 1))
783

  
784
    return self._SendRequest(HTTP_PUT,
785
                             ("/%s/instances/%s/activate-disks" %
786
                              (GANETI_RAPI_VERSION, instance)), query, None)
787

  
788
  def DeactivateInstanceDisks(self, instance):
789
    """Deactivates an instance's disks.
790

  
791
    @type instance: string
792
    @param instance: Instance name
793
    @return: job id
794

  
795
    """
796
    return self._SendRequest(HTTP_PUT,
797
                             ("/%s/instances/%s/deactivate-disks" %
798
                              (GANETI_RAPI_VERSION, instance)), None, None)
799

  
800
  def GrowInstanceDisk(self, instance, disk, amount, wait_for_sync=None):
801
    """Grows a disk of an instance.
802

  
803
    More details for parameters can be found in the RAPI documentation.
804

  
805
    @type instance: string
806
    @param instance: Instance name
807
    @type disk: integer
808
    @param disk: Disk index
809
    @type amount: integer
810
    @param amount: Grow disk by this amount (MiB)
811
    @type wait_for_sync: bool
812
    @param wait_for_sync: Wait for disk to synchronize
813
    @rtype: int
814
    @return: job id
815

  
816
    """
817
    body = {
818
      "amount": amount,
819
      }
820

  
821
    if wait_for_sync is not None:
822
      body["wait_for_sync"] = wait_for_sync
823

  
824
    return self._SendRequest(HTTP_POST,
825
                             ("/%s/instances/%s/disk/%s/grow" %
826
                              (GANETI_RAPI_VERSION, instance, disk)),
827
                             None, body)
828

  
749 829
  def GetInstanceTags(self, instance):
750 830
    """Gets tags for an instance.
751 831

  
......
862 942
                             ("/%s/instances/%s/startup" %
863 943
                              (GANETI_RAPI_VERSION, instance)), query, None)
864 944

  
865
  def ReinstallInstance(self, instance, os=None, no_startup=False):
945
  def ReinstallInstance(self, instance, os=None, no_startup=False,
946
                        osparams=None):
866 947
    """Reinstalls an instance.
867 948

  
868 949
    @type instance: str
......
874 955
    @param no_startup: Whether to start the instance automatically
875 956

  
876 957
    """
958
    if _INST_REINSTALL_REQV1 in self.GetFeatures():
959
      body = {
960
        "start": not no_startup,
961
        }
962
      if os is not None:
963
        body["os"] = os
964
      if osparams is not None:
965
        body["osparams"] = osparams
966
      return self._SendRequest(HTTP_POST,
967
                               ("/%s/instances/%s/reinstall" %
968
                                (GANETI_RAPI_VERSION, instance)), None, body)
969

  
970
    # Use old request format
971
    if osparams:
972
      raise GanetiApiError("Server does not support specifying OS parameters"
973
                           " for instance reinstallation")
974

  
877 975
    query = []
878 976
    if os:
879 977
      query.append(("os", os))
......
1026 1124
                             ("/%s/instances/%s/rename" %
1027 1125
                              (GANETI_RAPI_VERSION, instance)), None, body)
1028 1126

  
1127
  def GetInstanceConsole(self, instance):
1128
    """Request information for connecting to instance's console.
1129

  
1130
    @type instance: string
1131
    @param instance: Instance name
1132

  
1133
    """
1134
    return self._SendRequest(HTTP_GET,
1135
                             ("/%s/instances/%s/console" %
1136
                              (GANETI_RAPI_VERSION, instance)), None, None)
1137

  
1029 1138
  def GetJobs(self):
1030 1139
    """Gets all jobs for the cluster.
1031 1140

  
......
1356 1465
    return self._SendRequest(HTTP_DELETE,
1357 1466
                             ("/%s/nodes/%s/tags" %
1358 1467
                              (GANETI_RAPI_VERSION, node)), query, None)
1468

  
1469
  def GetGroups(self, bulk=False):
1470
    """Gets all node groups in the cluster.
1471

  
1472
    @type bulk: bool
1473
    @param bulk: whether to return all information about the groups
1474

  
1475
    @rtype: list of dict or str
1476
    @return: if bulk is true, a list of dictionaries with info about all node
1477
        groups in the cluster, else a list of names of those node groups
1478

  
1479
    """
1480
    query = []
1481
    if bulk:
1482
      query.append(("bulk", 1))
1483

  
1484
    groups = self._SendRequest(HTTP_GET, "/%s/groups" % GANETI_RAPI_VERSION,
1485
                               query, None)
1486
    if bulk:
1487
      return groups
1488
    else:
1489
      return [g["name"] for g in groups]
1490

  
1491
  def GetGroup(self, group):
1492
    """Gets information about a node group.
1493

  
1494
    @type group: str
1495
    @param group: name of the node group whose info to return
1496

  
1497
    @rtype: dict
1498
    @return: info about the node group
1499

  
1500
    """
1501
    return self._SendRequest(HTTP_GET,
1502
                             "/%s/groups/%s" % (GANETI_RAPI_VERSION, group),
1503
                             None, None)
1504

  
1505
  def CreateGroup(self, name, alloc_policy=None, dry_run=False):
1506
    """Creates a new node group.
1507

  
1508
    @type name: str
1509
    @param name: the name of node group to create
1510
    @type alloc_policy: str
1511
    @param alloc_policy: the desired allocation policy for the group, if any
1512
    @type dry_run: bool
1513
    @param dry_run: whether to peform a dry run
1514

  
1515
    @rtype: int
1516
    @return: job id
1517

  
1518
    """
1519
    query = []
1520
    if dry_run:
1521
      query.append(("dry-run", 1))
1522

  
1523
    body = {
1524
      "name": name,
1525
      "alloc_policy": alloc_policy
1526
      }
1527

  
1528
    return self._SendRequest(HTTP_POST, "/%s/groups" % GANETI_RAPI_VERSION,
1529
                             query, body)
1530

  
1531
  def ModifyGroup(self, group, **kwargs):
1532
    """Modifies a node group.
1533

  
1534
    More details for parameters can be found in the RAPI documentation.
1535

  
1536
    @type group: string
1537
    @param group: Node group name
1538
    @rtype: int
1539
    @return: job id
1540

  
1541
    """
1542
    return self._SendRequest(HTTP_PUT,
1543
                             ("/%s/groups/%s/modify" %
1544
                              (GANETI_RAPI_VERSION, group)), None, kwargs)
1545

  
1546
  def DeleteGroup(self, group, dry_run=False):
1547
    """Deletes a node group.
1548

  
1549
    @type group: str
1550
    @param group: the node group to delete
1551
    @type dry_run: bool
1552
    @param dry_run: whether to peform a dry run
1553

  
1554
    @rtype: int
1555
    @return: job id
1556

  
1557
    """
1558
    query = []
1559
    if dry_run:
1560
      query.append(("dry-run", 1))
1561

  
1562
    return self._SendRequest(HTTP_DELETE,
1563
                             ("/%s/groups/%s" %
1564
                              (GANETI_RAPI_VERSION, group)), query, None)
1565

  
1566
  def RenameGroup(self, group, new_name):
1567
    """Changes the name of a node group.
1568

  
1569
    @type group: string
1570
    @param group: Node group name
1571
    @type new_name: string
1572
    @param new_name: New node group name
1573

  
1574
    @rtype: int
1575
    @return: job id
1576

  
1577
    """
1578
    body = {
1579
      "new_name": new_name,
1580
      }
1581

  
1582
    return self._SendRequest(HTTP_PUT,
1583
                             ("/%s/groups/%s/rename" %
1584
                              (GANETI_RAPI_VERSION, group)), None, body)
1585

  
1586

  
1587
  def AssignGroupNodes(self, group, nodes, force=False, dry_run=False):
1588
    """Assigns nodes to a group.
1589

  
1590
    @type group: string
1591
    @param group: Node gropu name
1592
    @type nodes: list of strings
1593
    @param nodes: List of nodes to assign to the group
1594

  
1595
    @rtype: int
1596
    @return: job id
1597

  
1598
    """
1599
    query = []
1600

  
1601
    if force:
1602
      query.append(("force", 1))
1603

  
1604
    if dry_run:
1605
      query.append(("dry-run", 1))
1606

  
1607
    body = {
1608
      "nodes": nodes,
1609
      }
1610

  
1611
    return self._SendRequest(HTTP_PUT,
1612
                             ("/%s/groups/%s/assign-nodes" %
1613
                             (GANETI_RAPI_VERSION, group)), query, body)

Also available in: Unified diff