Statistics
| Branch: | Tag: | Revision:

root / doc / rapi.rst @ 1b01390b

History | View | Annotate | Download (35.8 kB)

1
Ganeti remote API
2
=================
3

    
4
Documents Ganeti version |version|
5

    
6
.. contents::
7

    
8
Introduction
9
------------
10

    
11
Ganeti supports a remote API for enable external tools to easily
12
retrieve information about a cluster's state. The remote API daemon,
13
*ganeti-rapi*, is automatically started on the master node. By default
14
it runs on TCP port 5080, but this can be changed either in
15
``.../constants.py`` or via the command line parameter *-p*. SSL mode,
16
which is used by default, can also be disabled by passing command line
17
parameters.
18

    
19

    
20
Users and passwords
21
-------------------
22

    
23
``ganeti-rapi`` reads users and passwords from a file (usually
24
``/var/lib/ganeti/rapi/users``) on startup. Changes to the file will be
25
read automatically.
26

    
27
Each line consists of two or three fields separated by whitespace. The
28
first two fields are for username and password. The third field is
29
optional and can be used to specify per-user options. Currently,
30
``write`` is the only option supported and enables the user to execute
31
operations modifying the cluster. Lines starting with the hash sign
32
(``#``) are treated as comments.
33

    
34
Passwords can either be written in clear text or as a hash. Clear text
35
passwords may not start with an opening brace (``{``) or they must be
36
prefixed with ``{cleartext}``. To use the hashed form, get the MD5 hash
37
of the string ``$username:Ganeti Remote API:$password`` (e.g. ``echo -n
38
'jack:Ganeti Remote API:abc123' | openssl md5``) [#pwhash]_ and prefix
39
it with ``{ha1}``. Using the scheme prefix for all passwords is
40
recommended. Scheme prefixes are not case sensitive.
41

    
42
Example::
43

    
44
  # Give Jack and Fred read-only access
45
  jack abc123
46
  fred {cleartext}foo555
47

    
48
  # Give write access to an imaginary instance creation script
49
  autocreator xyz789 write
50

    
51
  # Hashed password for Jessica
52
  jessica {HA1}7046452df2cbb530877058712cf17bd4 write
53

    
54

    
55
.. [#pwhash] Using the MD5 hash of username, realm and password is
56
   described in :rfc:`2617` ("HTTP Authentication"), sections 3.2.2.2
57
   and 3.3. The reason for using it over another algorithm is forward
58
   compatibility. If ``ganeti-rapi`` were to implement HTTP Digest
59
   authentication in the future, the same hash could be used.
60
   In the current version ``ganeti-rapi``'s realm, ``Ganeti Remote
61
   API``, can only be changed by modifying the source code.
62

    
63

    
64
Protocol
65
--------
66

    
67
The protocol used is JSON_ over HTTP designed after the REST_ principle.
68
HTTP Basic authentication as per :rfc:`2617` is supported.
69

    
70
.. _JSON: http://www.json.org/
71
.. _REST: http://en.wikipedia.org/wiki/Representational_State_Transfer
72

    
73
HTTP requests with a body (e.g. ``PUT`` or ``POST``) require the request
74
header ``Content-type`` be set to ``application/json`` (see :rfc:`2616`
75
(HTTP/1.1), section 7.2.1).
76

    
77

    
78
A note on JSON as used by RAPI
79
++++++++++++++++++++++++++++++
80

    
81
JSON_ as used by Ganeti RAPI does not conform to the specification in
82
:rfc:`4627`. Section 2 defines a JSON text to be either an object
83
(``{"key": "value", …}``) or an array (``[1, 2, 3, …]``). In violation
84
of this RAPI uses plain strings (``"master-candidate"``, ``"1234"``) for
85
some requests or responses. Changing this now would likely break
86
existing clients and cause a lot of trouble.
87

    
88
.. highlight:: ruby
89

    
90
Unlike Python's `JSON encoder and decoder
91
<http://docs.python.org/library/json.html>`_, other programming
92
languages or libraries may only provide a strict implementation, not
93
allowing plain values. For those, responses can usually be wrapped in an
94
array whose first element is then used, e.g. the response ``"1234"``
95
becomes ``["1234"]``. This works equally well for more complex values.
96
Example in Ruby::
97

    
98
  require "json"
99

    
100
  # Insert code to get response here
101
  response = "\"1234\""
102

    
103
  decoded = JSON.parse("[#{response}]").first
104

    
105
Short of modifying the encoder to allow encoding to a less strict
106
format, requests will have to be formatted by hand. Newer RAPI requests
107
already use a dictionary as their input data and shouldn't cause any
108
problems.
109

    
110

    
111
PUT or POST?
112
------------
113

    
114
According to :rfc:`2616` the main difference between PUT and POST is
115
that POST can create new resources but PUT can only create the resource
116
the URI was pointing to on the PUT request.
117

    
118
Unfortunately, due to historic reasons, the Ganeti RAPI library is not
119
consistent with this usage, so just use the methods as documented below
120
for each resource.
121

    
122
For more details have a look in the source code at
123
``lib/rapi/rlib2.py``.
124

    
125

    
126
Generic parameter types
127
-----------------------
128

    
129
A few generic refered parameter types and the values they allow.
130

    
131
``bool``
132
++++++++
133

    
134
A boolean option will accept ``1`` or ``0`` as numbers but not
135
i.e. ``True`` or ``False``.
136

    
137
Generic parameters
138
------------------
139

    
140
A few parameter mean the same thing across all resources which implement
141
it.
142

    
143
``bulk``
144
++++++++
145

    
146
Bulk-mode means that for the resources which usually return just a list
147
of child resources (e.g. ``/2/instances`` which returns just instance
148
names), the output will instead contain detailed data for all these
149
subresources. This is more efficient than query-ing the sub-resources
150
themselves.
151

    
152
``dry-run``
153
+++++++++++
154

    
155
The boolean *dry-run* argument, if provided and set, signals to Ganeti
156
that the job should not be executed, only the pre-execution checks will
157
be done.
158

    
159
This is useful in trying to determine (without guarantees though, as in
160
the meantime the cluster state could have changed) if the operation is
161
likely to succeed or at least start executing.
162

    
163
``force``
164
+++++++++++
165

    
166
Force operation to continue even if it will cause the cluster to become
167
inconsistent (e.g. because there are not enough master candidates).
168

    
169
Parameter details
170
-----------------
171

    
172
Some parameters are not straight forward, so we describe them in details
173
here.
174

    
175
.. _rapi-ipolicy:
176

    
177
``ipolicy``
178
+++++++++++
179

    
180
The instance policy specification is a dict with the following fields:
181

    
182
.. pyassert::
183

    
184
  constants.IPOLICY_ALL_KEYS == set([constants.ISPECS_MIN,
185
                                     constants.ISPECS_MAX,
186
                                     constants.ISPECS_STD,
187
                                     constants.IPOLICY_DTS,
188
                                     constants.IPOLICY_VCPU_RATIO])
189

    
190

    
191
.. pyassert::
192

    
193
  (set(constants.ISPECS_PARAMETER_TYPES.keys()) ==
194
   set([constants.ISPEC_MEM_SIZE,
195
        constants.ISPEC_DISK_SIZE,
196
        constants.ISPEC_DISK_COUNT,
197
        constants.ISPEC_CPU_COUNT,
198
        constants.ISPEC_NIC_COUNT]))
199

    
200
.. |ispec-min| replace:: :pyeval:`constants.ISPECS_MIN`
201
.. |ispec-max| replace:: :pyeval:`constants.ISPECS_MAX`
202
.. |ispec-std| replace:: :pyeval:`constants.ISPECS_STD`
203

    
204

    
205
|ispec-min|, |ispec-max|, |ispec-std|
206
  A sub- `dict` with the following fields, which sets the limit and standard
207
  values of the instances:
208

    
209
  :pyeval:`constants.ISPEC_MEM_SIZE`
210
    The size in MiB of the memory used
211
  :pyeval:`constants.ISPEC_DISK_SIZE`
212
    The size in MiB of the disk used
213
  :pyeval:`constants.ISPEC_DISK_COUNT`
214
    The numbers of disks used
215
  :pyeval:`constants.ISPEC_CPU_COUNT`
216
    The numbers of cpus used
217
  :pyeval:`constants.ISPEC_NIC_COUNT`
218
    The numbers of nics used
219
:pyeval:`constants.IPOLICY_DTS`
220
  A `list` of disk templates allowed for instances using this policy
221
:pyeval:`constants.IPOLICY_VCPU_RATIO`
222
  Maximum ratio of virtual to physical CPUs (`float`)
223

    
224
Usage examples
225
--------------
226

    
227
You can access the API using your favorite programming language as long
228
as it supports network connections.
229

    
230
Ganeti RAPI client
231
++++++++++++++++++
232

    
233
Ganeti includes a standalone RAPI client, ``lib/rapi/client.py``.
234

    
235
Shell
236
+++++
237

    
238
.. highlight:: sh
239

    
240
Using wget::
241

    
242
   wget -q -O - https://CLUSTERNAME:5080/2/info
243

    
244
or curl::
245

    
246
  curl https://CLUSTERNAME:5080/2/info
247

    
248

    
249
Python
250
++++++
251

    
252
.. highlight:: python
253

    
254
::
255

    
256
  import urllib2
257
  f = urllib2.urlopen('https://CLUSTERNAME:5080/2/info')
258
  print f.read()
259

    
260

    
261
JavaScript
262
++++++++++
263

    
264
.. warning:: While it's possible to use JavaScript, it poses several
265
   potential problems, including browser blocking request due to
266
   non-standard ports or different domain names. Fetching the data on
267
   the webserver is easier.
268

    
269
.. highlight:: javascript
270

    
271
::
272

    
273
  var url = 'https://CLUSTERNAME:5080/2/info';
274
  var info;
275
  var xmlreq = new XMLHttpRequest();
276
  xmlreq.onreadystatechange = function () {
277
    if (xmlreq.readyState != 4) return;
278
    if (xmlreq.status == 200) {
279
      info = eval("(" + xmlreq.responseText + ")");
280
      alert(info);
281
    } else {
282
      alert('Error fetching cluster info');
283
    }
284
    xmlreq = null;
285
  };
286
  xmlreq.open('GET', url, true);
287
  xmlreq.send(null);
288

    
289
Resources
290
---------
291

    
292
.. highlight:: javascript
293

    
294
``/``
295
+++++
296

    
297
The root resource. Has no function, but for legacy reasons the ``GET``
298
method is supported.
299

    
300
``/2``
301
++++++
302

    
303
Has no function, but for legacy reasons the ``GET`` method is supported.
304

    
305
``/2/info``
306
+++++++++++
307

    
308
Cluster information resource.
309

    
310
It supports the following commands: ``GET``.
311

    
312
``GET``
313
~~~~~~~
314

    
315
Returns cluster information.
316

    
317
Example::
318

    
319
  {
320
    "config_version": 2000000,
321
    "name": "cluster",
322
    "software_version": "2.0.0~beta2",
323
    "os_api_version": 10,
324
    "export_version": 0,
325
    "candidate_pool_size": 10,
326
    "enabled_hypervisors": [
327
      "fake"
328
    ],
329
    "hvparams": {
330
      "fake": {}
331
     },
332
    "default_hypervisor": "fake",
333
    "master": "node1.example.com",
334
    "architecture": [
335
      "64bit",
336
      "x86_64"
337
    ],
338
    "protocol_version": 20,
339
    "beparams": {
340
      "default": {
341
        "auto_balance": true,
342
        "vcpus": 1,
343
        "memory": 128
344
       }
345
      }
346
    }
347

    
348

    
349
``/2/redistribute-config``
350
++++++++++++++++++++++++++
351

    
352
Redistribute configuration to all nodes.
353

    
354
It supports the following commands: ``PUT``.
355

    
356
``PUT``
357
~~~~~~~
358

    
359
Redistribute configuration to all nodes. The result will be a job id.
360

    
361

    
362
``/2/features``
363
+++++++++++++++
364

    
365
``GET``
366
~~~~~~~
367

    
368
Returns a list of features supported by the RAPI server. Available
369
features:
370

    
371
.. pyassert::
372

    
373
  rlib2.ALL_FEATURES == set([rlib2._INST_CREATE_REQV1,
374
                             rlib2._INST_REINSTALL_REQV1,
375
                             rlib2._NODE_MIGRATE_REQV1,
376
                             rlib2._NODE_EVAC_RES1])
377

    
378
:pyeval:`rlib2._INST_CREATE_REQV1`
379
  Instance creation request data version 1 supported.
380
:pyeval:`rlib2._INST_REINSTALL_REQV1`
381
  Instance reinstall supports body parameters.
382
:pyeval:`rlib2._NODE_MIGRATE_REQV1`
383
  Whether migrating a node (``/2/nodes/[node_name]/migrate``) supports
384
  request body parameters.
385
:pyeval:`rlib2._NODE_EVAC_RES1`
386
  Whether evacuating a node (``/2/nodes/[node_name]/evacuate``) returns
387
  a new-style result (see resource description)
388

    
389

    
390
``/2/modify``
391
++++++++++++++++++++++++++++++++++++++++
392

    
393
Modifies cluster parameters.
394

    
395
Supports the following commands: ``PUT``.
396

    
397
``PUT``
398
~~~~~~~
399

    
400
Returns a job ID.
401

    
402
Body parameters:
403

    
404
.. opcode_params:: OP_CLUSTER_SET_PARAMS
405

    
406

    
407
``/2/groups``
408
+++++++++++++
409

    
410
The groups resource.
411

    
412
It supports the following commands: ``GET``, ``POST``.
413

    
414
``GET``
415
~~~~~~~
416

    
417
Returns a list of all existing node groups.
418

    
419
Example::
420

    
421
    [
422
      {
423
        "name": "group1",
424
        "uri": "\/2\/groups\/group1"
425
      },
426
      {
427
        "name": "group2",
428
        "uri": "\/2\/groups\/group2"
429
      }
430
    ]
431

    
432
If the optional bool *bulk* argument is provided and set to a true value
433
(i.e ``?bulk=1``), the output contains detailed information about node
434
groups as a list.
435

    
436
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.G_FIELDS))`
437

    
438
Example::
439

    
440
    [
441
      {
442
        "name": "group1",
443
        "node_cnt": 2,
444
        "node_list": [
445
          "node1.example.com",
446
          "node2.example.com"
447
        ],
448
        "uuid": "0d7d407c-262e-49af-881a-6a430034bf43"
449
      },
450
      {
451
        "name": "group2",
452
        "node_cnt": 1,
453
        "node_list": [
454
          "node3.example.com"
455
        ],
456
        "uuid": "f5a277e7-68f9-44d3-a378-4b25ecb5df5c"
457
      }
458
    ]
459

    
460
``POST``
461
~~~~~~~~
462

    
463
Creates a node group.
464

    
465
If the optional bool *dry-run* argument is provided, the job will not be
466
actually executed, only the pre-execution checks will be done.
467

    
468
Returns: a job ID that can be used later for polling.
469

    
470
Body parameters:
471

    
472
.. opcode_params:: OP_GROUP_ADD
473

    
474
Earlier versions used a parameter named ``name`` which, while still
475
supported, has been renamed to ``group_name``.
476

    
477

    
478
``/2/groups/[group_name]``
479
++++++++++++++++++++++++++
480

    
481
Returns information about a node group.
482

    
483
It supports the following commands: ``GET``, ``DELETE``.
484

    
485
``GET``
486
~~~~~~~
487

    
488
Returns information about a node group, similar to the bulk output from
489
the node group list.
490

    
491
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.G_FIELDS))`
492

    
493
``DELETE``
494
~~~~~~~~~~
495

    
496
Deletes a node group.
497

    
498
It supports the ``dry-run`` argument.
499

    
500

    
501
``/2/groups/[group_name]/modify``
502
+++++++++++++++++++++++++++++++++
503

    
504
Modifies the parameters of a node group.
505

    
506
Supports the following commands: ``PUT``.
507

    
508
``PUT``
509
~~~~~~~
510

    
511
Returns a job ID.
512

    
513
Body parameters:
514

    
515
.. opcode_params:: OP_GROUP_SET_PARAMS
516
   :exclude: group_name
517

    
518
Job result:
519

    
520
.. opcode_result:: OP_GROUP_SET_PARAMS
521

    
522

    
523
``/2/groups/[group_name]/rename``
524
+++++++++++++++++++++++++++++++++
525

    
526
Renames a node group.
527

    
528
Supports the following commands: ``PUT``.
529

    
530
``PUT``
531
~~~~~~~
532

    
533
Returns a job ID.
534

    
535
Body parameters:
536

    
537
.. opcode_params:: OP_GROUP_RENAME
538
   :exclude: group_name
539

    
540
Job result:
541

    
542
.. opcode_result:: OP_GROUP_RENAME
543

    
544

    
545
``/2/groups/[group_name]/assign-nodes``
546
+++++++++++++++++++++++++++++++++++++++
547

    
548
Assigns nodes to a group.
549

    
550
Supports the following commands: ``PUT``.
551

    
552
``PUT``
553
~~~~~~~
554

    
555
Returns a job ID. It supports the ``dry-run`` and ``force`` arguments.
556

    
557
Body parameters:
558

    
559
.. opcode_params:: OP_GROUP_ASSIGN_NODES
560
   :exclude: group_name, force, dry_run
561

    
562

    
563
``/2/groups/[group_name]/tags``
564
+++++++++++++++++++++++++++++++
565

    
566
Manages per-nodegroup tags.
567

    
568
Supports the following commands: ``GET``, ``PUT``, ``DELETE``.
569

    
570
``GET``
571
~~~~~~~
572

    
573
Returns a list of tags.
574

    
575
Example::
576

    
577
    ["tag1", "tag2", "tag3"]
578

    
579
``PUT``
580
~~~~~~~
581

    
582
Add a set of tags.
583

    
584
The request as a list of strings should be ``PUT`` to this URI. The
585
result will be a job id.
586

    
587
It supports the ``dry-run`` argument.
588

    
589

    
590
``DELETE``
591
~~~~~~~~~~
592

    
593
Delete a tag.
594

    
595
In order to delete a set of tags, the DELETE request should be addressed
596
to URI like::
597

    
598
    /tags?tag=[tag]&tag=[tag]
599

    
600
It supports the ``dry-run`` argument.
601

    
602

    
603
``/2/instances``
604
++++++++++++++++
605

    
606
The instances resource.
607

    
608
It supports the following commands: ``GET``, ``POST``.
609

    
610
``GET``
611
~~~~~~~
612

    
613
Returns a list of all available instances.
614

    
615
Example::
616

    
617
    [
618
      {
619
        "name": "web.example.com",
620
        "uri": "\/instances\/web.example.com"
621
      },
622
      {
623
        "name": "mail.example.com",
624
        "uri": "\/instances\/mail.example.com"
625
      }
626
    ]
627

    
628
If the optional bool *bulk* argument is provided and set to a true value
629
(i.e ``?bulk=1``), the output contains detailed information about
630
instances as a list.
631

    
632
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.I_FIELDS))`
633

    
634
Example::
635

    
636
    [
637
      {
638
         "status": "running",
639
         "disk_usage": 20480,
640
         "nic.bridges": [
641
           "xen-br0"
642
          ],
643
         "name": "web.example.com",
644
         "tags": ["tag1", "tag2"],
645
         "beparams": {
646
           "vcpus": 2,
647
           "memory": 512
648
         },
649
         "disk.sizes": [
650
             20480
651
         ],
652
         "pnode": "node1.example.com",
653
         "nic.macs": ["01:23:45:67:89:01"],
654
         "snodes": ["node2.example.com"],
655
         "disk_template": "drbd",
656
         "admin_state": true,
657
         "os": "debian-etch",
658
         "oper_state": true
659
      },
660
      ...
661
    ]
662

    
663

    
664
``POST``
665
~~~~~~~~
666

    
667
Creates an instance.
668

    
669
If the optional bool *dry-run* argument is provided, the job will not be
670
actually executed, only the pre-execution checks will be done. Query-ing
671
the job result will return, in both dry-run and normal case, the list of
672
nodes selected for the instance.
673

    
674
Returns: a job ID that can be used later for polling.
675

    
676
Body parameters:
677

    
678
``__version__`` (int, required)
679
  Must be ``1`` (older Ganeti versions used a different format for
680
  instance creation requests, version ``0``, but that format is no
681
  longer supported)
682

    
683
.. opcode_params:: OP_INSTANCE_CREATE
684

    
685
Earlier versions used parameters named ``name`` and ``os``. These have
686
been replaced by ``instance_name`` and ``os_type`` to match the
687
underlying opcode. The old names can still be used.
688

    
689
Job result:
690

    
691
.. opcode_result:: OP_INSTANCE_CREATE
692

    
693

    
694
``/2/instances/[instance_name]``
695
++++++++++++++++++++++++++++++++
696

    
697
Instance-specific resource.
698

    
699
It supports the following commands: ``GET``, ``DELETE``.
700

    
701
``GET``
702
~~~~~~~
703

    
704
Returns information about an instance, similar to the bulk output from
705
the instance list.
706

    
707
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.I_FIELDS))`
708

    
709
``DELETE``
710
~~~~~~~~~~
711

    
712
Deletes an instance.
713

    
714
It supports the ``dry-run`` argument.
715

    
716

    
717
``/2/instances/[instance_name]/info``
718
+++++++++++++++++++++++++++++++++++++++
719

    
720
It supports the following commands: ``GET``.
721

    
722
``GET``
723
~~~~~~~
724

    
725
Requests detailed information about the instance. An optional parameter,
726
``static`` (bool), can be set to return only static information from the
727
configuration without querying the instance's nodes. The result will be
728
a job id.
729

    
730

    
731
``/2/instances/[instance_name]/reboot``
732
+++++++++++++++++++++++++++++++++++++++
733

    
734
Reboots URI for an instance.
735

    
736
It supports the following commands: ``POST``.
737

    
738
``POST``
739
~~~~~~~~
740

    
741
Reboots the instance.
742

    
743
The URI takes optional ``type=soft|hard|full`` and
744
``ignore_secondaries=0|1`` parameters.
745

    
746
``type`` defines the reboot type. ``soft`` is just a normal reboot,
747
without terminating the hypervisor. ``hard`` means full shutdown
748
(including terminating the hypervisor process) and startup again.
749
``full`` is like ``hard`` but also recreates the configuration from
750
ground up as if you would have done a ``gnt-instance shutdown`` and
751
``gnt-instance start`` on it.
752

    
753
``ignore_secondaries`` is a bool argument indicating if we start the
754
instance even if secondary disks are failing.
755

    
756
It supports the ``dry-run`` argument.
757

    
758

    
759
``/2/instances/[instance_name]/shutdown``
760
+++++++++++++++++++++++++++++++++++++++++
761

    
762
Instance shutdown URI.
763

    
764
It supports the following commands: ``PUT``.
765

    
766
``PUT``
767
~~~~~~~
768

    
769
Shutdowns an instance.
770

    
771
It supports the ``dry-run`` argument.
772

    
773
.. opcode_params:: OP_INSTANCE_SHUTDOWN
774
   :exclude: instance_name, dry_run
775

    
776

    
777
``/2/instances/[instance_name]/startup``
778
++++++++++++++++++++++++++++++++++++++++
779

    
780
Instance startup URI.
781

    
782
It supports the following commands: ``PUT``.
783

    
784
``PUT``
785
~~~~~~~
786

    
787
Startup an instance.
788

    
789
The URI takes an optional ``force=1|0`` parameter to start the
790
instance even if secondary disks are failing.
791

    
792
It supports the ``dry-run`` argument.
793

    
794
``/2/instances/[instance_name]/reinstall``
795
++++++++++++++++++++++++++++++++++++++++++++++
796

    
797
Installs the operating system again.
798

    
799
It supports the following commands: ``POST``.
800

    
801
``POST``
802
~~~~~~~~
803

    
804
Returns a job ID.
805

    
806
Body parameters:
807

    
808
``os`` (string, required)
809
  Instance operating system.
810
``start`` (bool, defaults to true)
811
  Whether to start instance after reinstallation.
812
``osparams`` (dict)
813
  Dictionary with (temporary) OS parameters.
814

    
815
For backwards compatbility, this resource also takes the query
816
parameters ``os`` (OS template name) and ``nostartup`` (bool). New
817
clients should use the body parameters.
818

    
819

    
820
``/2/instances/[instance_name]/replace-disks``
821
++++++++++++++++++++++++++++++++++++++++++++++
822

    
823
Replaces disks on an instance.
824

    
825
It supports the following commands: ``POST``.
826

    
827
``POST``
828
~~~~~~~~
829

    
830
Returns a job ID.
831

    
832
Body parameters:
833

    
834
.. opcode_params:: OP_INSTANCE_REPLACE_DISKS
835
   :exclude: instance_name
836

    
837
Ganeti 2.4 and below used query parameters. Those are deprecated and
838
should no longer be used.
839

    
840

    
841
``/2/instances/[instance_name]/activate-disks``
842
+++++++++++++++++++++++++++++++++++++++++++++++
843

    
844
Activate disks on an instance.
845

    
846
It supports the following commands: ``PUT``.
847

    
848
``PUT``
849
~~~~~~~
850

    
851
Takes the bool parameter ``ignore_size``. When set ignore the recorded
852
size (useful for forcing activation when recorded size is wrong).
853

    
854

    
855
``/2/instances/[instance_name]/deactivate-disks``
856
+++++++++++++++++++++++++++++++++++++++++++++++++
857

    
858
Deactivate disks on an instance.
859

    
860
It supports the following commands: ``PUT``.
861

    
862
``PUT``
863
~~~~~~~
864

    
865
Takes no parameters.
866

    
867

    
868
``/2/instances/[instance_name]/recreate-disks``
869
+++++++++++++++++++++++++++++++++++++++++++++++++
870

    
871
Recreate disks of an instance. Supports the following commands:
872
``POST``.
873

    
874
``POST``
875
~~~~~~~~
876

    
877
Returns a job ID.
878

    
879
Body parameters:
880

    
881
.. opcode_params:: OP_INSTANCE_RECREATE_DISKS
882
   :exclude: instance_name
883

    
884

    
885
``/2/instances/[instance_name]/disk/[disk_index]/grow``
886
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
887

    
888
Grows one disk of an instance.
889

    
890
Supports the following commands: ``POST``.
891

    
892
``POST``
893
~~~~~~~~
894

    
895
Returns a job ID.
896

    
897
Body parameters:
898

    
899
.. opcode_params:: OP_INSTANCE_GROW_DISK
900
   :exclude: instance_name, disk
901

    
902

    
903
``/2/instances/[instance_name]/prepare-export``
904
+++++++++++++++++++++++++++++++++++++++++++++++++
905

    
906
Prepares an export of an instance.
907

    
908
It supports the following commands: ``PUT``.
909

    
910
``PUT``
911
~~~~~~~
912

    
913
Takes one parameter, ``mode``, for the export mode. Returns a job ID.
914

    
915

    
916
``/2/instances/[instance_name]/export``
917
+++++++++++++++++++++++++++++++++++++++++++++++++
918

    
919
Exports an instance.
920

    
921
It supports the following commands: ``PUT``.
922

    
923
``PUT``
924
~~~~~~~
925

    
926
Returns a job ID.
927

    
928
Body parameters:
929

    
930
.. opcode_params:: OP_BACKUP_EXPORT
931
   :exclude: instance_name
932
   :alias: target_node=destination
933

    
934

    
935
``/2/instances/[instance_name]/migrate``
936
++++++++++++++++++++++++++++++++++++++++
937

    
938
Migrates an instance.
939

    
940
Supports the following commands: ``PUT``.
941

    
942
``PUT``
943
~~~~~~~
944

    
945
Returns a job ID.
946

    
947
Body parameters:
948

    
949
.. opcode_params:: OP_INSTANCE_MIGRATE
950
   :exclude: instance_name, live
951

    
952

    
953
``/2/instances/[instance_name]/failover``
954
+++++++++++++++++++++++++++++++++++++++++
955

    
956
Does a failover of an instance.
957

    
958
Supports the following commands: ``PUT``.
959

    
960
``PUT``
961
~~~~~~~
962

    
963
Returns a job ID.
964

    
965
Body parameters:
966

    
967
.. opcode_params:: OP_INSTANCE_FAILOVER
968
   :exclude: instance_name
969

    
970

    
971
``/2/instances/[instance_name]/rename``
972
++++++++++++++++++++++++++++++++++++++++
973

    
974
Renames an instance.
975

    
976
Supports the following commands: ``PUT``.
977

    
978
``PUT``
979
~~~~~~~
980

    
981
Returns a job ID.
982

    
983
Body parameters:
984

    
985
.. opcode_params:: OP_INSTANCE_RENAME
986
   :exclude: instance_name
987

    
988
Job result:
989

    
990
.. opcode_result:: OP_INSTANCE_RENAME
991

    
992

    
993
``/2/instances/[instance_name]/modify``
994
++++++++++++++++++++++++++++++++++++++++
995

    
996
Modifies an instance.
997

    
998
Supports the following commands: ``PUT``.
999

    
1000
``PUT``
1001
~~~~~~~
1002

    
1003
Returns a job ID.
1004

    
1005
Body parameters:
1006

    
1007
.. opcode_params:: OP_INSTANCE_SET_PARAMS
1008
   :exclude: instance_name
1009

    
1010
Job result:
1011

    
1012
.. opcode_result:: OP_INSTANCE_SET_PARAMS
1013

    
1014

    
1015
``/2/instances/[instance_name]/console``
1016
++++++++++++++++++++++++++++++++++++++++
1017

    
1018
Request information for connecting to instance's console.
1019

    
1020
Supports the following commands: ``GET``.
1021

    
1022
``GET``
1023
~~~~~~~
1024

    
1025
Returns a dictionary containing information about the instance's
1026
console. Contained keys:
1027

    
1028
.. pyassert::
1029

    
1030
   constants.CONS_ALL == frozenset([
1031
     constants.CONS_MESSAGE,
1032
     constants.CONS_SSH,
1033
     constants.CONS_VNC,
1034
     constants.CONS_SPICE,
1035
     ])
1036

    
1037
``instance``
1038
  Instance name.
1039
``kind``
1040
  Console type, one of :pyeval:`constants.CONS_SSH`,
1041
  :pyeval:`constants.CONS_VNC`, :pyeval:`constants.CONS_SPICE`
1042
  or :pyeval:`constants.CONS_MESSAGE`.
1043
``message``
1044
  Message to display (:pyeval:`constants.CONS_MESSAGE` type only).
1045
``host``
1046
  Host to connect to (:pyeval:`constants.CONS_SSH`,
1047
  :pyeval:`constants.CONS_VNC` or :pyeval:`constants.CONS_SPICE` only).
1048
``port``
1049
  TCP port to connect to (:pyeval:`constants.CONS_VNC` or
1050
  :pyeval:`constants.CONS_SPICE` only).
1051
``user``
1052
  Username to use (:pyeval:`constants.CONS_SSH` only).
1053
``command``
1054
  Command to execute on machine (:pyeval:`constants.CONS_SSH` only)
1055
``display``
1056
  VNC display number (:pyeval:`constants.CONS_VNC` only).
1057

    
1058

    
1059
``/2/instances/[instance_name]/tags``
1060
+++++++++++++++++++++++++++++++++++++
1061

    
1062
Manages per-instance tags.
1063

    
1064
It supports the following commands: ``GET``, ``PUT``, ``DELETE``.
1065

    
1066
``GET``
1067
~~~~~~~
1068

    
1069
Returns a list of tags.
1070

    
1071
Example::
1072

    
1073
    ["tag1", "tag2", "tag3"]
1074

    
1075
``PUT``
1076
~~~~~~~
1077

    
1078
Add a set of tags.
1079

    
1080
The request as a list of strings should be ``PUT`` to this URI. The
1081
result will be a job id.
1082

    
1083
It supports the ``dry-run`` argument.
1084

    
1085

    
1086
``DELETE``
1087
~~~~~~~~~~
1088

    
1089
Delete a tag.
1090

    
1091
In order to delete a set of tags, the DELETE request should be addressed
1092
to URI like::
1093

    
1094
    /tags?tag=[tag]&tag=[tag]
1095

    
1096
It supports the ``dry-run`` argument.
1097

    
1098

    
1099
``/2/jobs``
1100
+++++++++++
1101

    
1102
The ``/2/jobs`` resource.
1103

    
1104
It supports the following commands: ``GET``.
1105

    
1106
``GET``
1107
~~~~~~~
1108

    
1109
Returns a dictionary of jobs.
1110

    
1111
Returns: a dictionary with jobs id and uri.
1112

    
1113
If the optional bool *bulk* argument is provided and set to a true value
1114
(i.e. ``?bulk=1``), the output contains detailed information about jobs
1115
as a list.
1116

    
1117
Returned fields for bulk requests (unlike other bulk requests, these
1118
fields are not the same as for per-job requests):
1119
:pyeval:`utils.CommaJoin(sorted(rlib2.J_FIELDS_BULK))`
1120

    
1121
``/2/jobs/[job_id]``
1122
++++++++++++++++++++
1123

    
1124

    
1125
Individual job URI.
1126

    
1127
It supports the following commands: ``GET``, ``DELETE``.
1128

    
1129
``GET``
1130
~~~~~~~
1131

    
1132
Returns a dictionary with job parameters, containing the fields
1133
:pyeval:`utils.CommaJoin(sorted(rlib2.J_FIELDS))`.
1134

    
1135
The result includes:
1136

    
1137
- id: job ID as a number
1138
- status: current job status as a string
1139
- ops: involved OpCodes as a list of dictionaries for each opcodes in
1140
  the job
1141
- opstatus: OpCodes status as a list
1142
- opresult: OpCodes results as a list
1143

    
1144
For a successful opcode, the ``opresult`` field corresponding to it will
1145
contain the raw result from its :term:`LogicalUnit`. In case an opcode
1146
has failed, its element in the opresult list will be a list of two
1147
elements:
1148

    
1149
- first element the error type (the Ganeti internal error name)
1150
- second element a list of either one or two elements:
1151

    
1152
  - the first element is the textual error description
1153
  - the second element, if any, will hold an error classification
1154

    
1155
The error classification is most useful for the ``OpPrereqError``
1156
error type - these errors happen before the OpCode has started
1157
executing, so it's possible to retry the OpCode without side
1158
effects. But whether it make sense to retry depends on the error
1159
classification:
1160

    
1161
.. pyassert::
1162

    
1163
   errors.ECODE_ALL == set([errors.ECODE_RESOLVER, errors.ECODE_NORES,
1164
     errors.ECODE_INVAL, errors.ECODE_STATE, errors.ECODE_NOENT,
1165
     errors.ECODE_EXISTS, errors.ECODE_NOTUNIQUE, errors.ECODE_FAULT,
1166
     errors.ECODE_ENVIRON])
1167

    
1168
:pyeval:`errors.ECODE_RESOLVER`
1169
  Resolver errors. This usually means that a name doesn't exist in DNS,
1170
  so if it's a case of slow DNS propagation the operation can be retried
1171
  later.
1172

    
1173
:pyeval:`errors.ECODE_NORES`
1174
  Not enough resources (iallocator failure, disk space, memory,
1175
  etc.). If the resources on the cluster increase, the operation might
1176
  succeed.
1177

    
1178
:pyeval:`errors.ECODE_INVAL`
1179
  Wrong arguments (at syntax level). The operation will not ever be
1180
  accepted unless the arguments change.
1181

    
1182
:pyeval:`errors.ECODE_STATE`
1183
  Wrong entity state. For example, live migration has been requested for
1184
  a down instance, or instance creation on an offline node. The
1185
  operation can be retried once the resource has changed state.
1186

    
1187
:pyeval:`errors.ECODE_NOENT`
1188
  Entity not found. For example, information has been requested for an
1189
  unknown instance.
1190

    
1191
:pyeval:`errors.ECODE_EXISTS`
1192
  Entity already exists. For example, instance creation has been
1193
  requested for an already-existing instance.
1194

    
1195
:pyeval:`errors.ECODE_NOTUNIQUE`
1196
  Resource not unique (e.g. MAC or IP duplication).
1197

    
1198
:pyeval:`errors.ECODE_FAULT`
1199
  Internal cluster error. For example, a node is unreachable but not set
1200
  offline, or the ganeti node daemons are not working, etc. A
1201
  ``gnt-cluster verify`` should be run.
1202

    
1203
:pyeval:`errors.ECODE_ENVIRON`
1204
  Environment error (e.g. node disk error). A ``gnt-cluster verify``
1205
  should be run.
1206

    
1207
Note that in the above list, by entity we refer to a node or instance,
1208
while by a resource we refer to an instance's disk, or NIC, etc.
1209

    
1210

    
1211
``DELETE``
1212
~~~~~~~~~~
1213

    
1214
Cancel a not-yet-started job.
1215

    
1216

    
1217
``/2/jobs/[job_id]/wait``
1218
+++++++++++++++++++++++++
1219

    
1220
``GET``
1221
~~~~~~~
1222

    
1223
Waits for changes on a job. Takes the following body parameters in a
1224
dict:
1225

    
1226
``fields``
1227
  The job fields on which to watch for changes.
1228

    
1229
``previous_job_info``
1230
  Previously received field values or None if not yet available.
1231

    
1232
``previous_log_serial``
1233
  Highest log serial number received so far or None if not yet
1234
  available.
1235

    
1236
Returns None if no changes have been detected and a dict with two keys,
1237
``job_info`` and ``log_entries`` otherwise.
1238

    
1239

    
1240
``/2/nodes``
1241
++++++++++++
1242

    
1243
Nodes resource.
1244

    
1245
It supports the following commands: ``GET``.
1246

    
1247
``GET``
1248
~~~~~~~
1249

    
1250
Returns a list of all nodes.
1251

    
1252
Example::
1253

    
1254
    [
1255
      {
1256
        "id": "node1.example.com",
1257
        "uri": "\/nodes\/node1.example.com"
1258
      },
1259
      {
1260
        "id": "node2.example.com",
1261
        "uri": "\/nodes\/node2.example.com"
1262
      }
1263
    ]
1264

    
1265
If the optional bool *bulk* argument is provided and set to a true value
1266
(i.e ``?bulk=1``), the output contains detailed information about nodes
1267
as a list.
1268

    
1269
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.N_FIELDS))`
1270

    
1271
Example::
1272

    
1273
    [
1274
      {
1275
        "pinst_cnt": 1,
1276
        "mfree": 31280,
1277
        "mtotal": 32763,
1278
        "name": "www.example.com",
1279
        "tags": [],
1280
        "mnode": 512,
1281
        "dtotal": 5246208,
1282
        "sinst_cnt": 2,
1283
        "dfree": 5171712,
1284
        "offline": false
1285
      },
1286
      ...
1287
    ]
1288

    
1289
``/2/nodes/[node_name]``
1290
+++++++++++++++++++++++++++++++++
1291

    
1292
Returns information about a node.
1293

    
1294
It supports the following commands: ``GET``.
1295

    
1296
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.N_FIELDS))`
1297

    
1298
``/2/nodes/[node_name]/powercycle``
1299
+++++++++++++++++++++++++++++++++++
1300

    
1301
Powercycles a node. Supports the following commands: ``POST``.
1302

    
1303
``POST``
1304
~~~~~~~~
1305

    
1306
Returns a job ID.
1307

    
1308

    
1309
``/2/nodes/[node_name]/evacuate``
1310
+++++++++++++++++++++++++++++++++
1311

    
1312
Evacuates instances off a node.
1313

    
1314
It supports the following commands: ``POST``.
1315

    
1316
``POST``
1317
~~~~~~~~
1318

    
1319
Returns a job ID. The result of the job will contain the IDs of the
1320
individual jobs submitted to evacuate the node.
1321

    
1322
Body parameters:
1323

    
1324
.. opcode_params:: OP_NODE_EVACUATE
1325
   :exclude: nodes
1326

    
1327
Up to and including Ganeti 2.4 query arguments were used. Those are no
1328
longer supported. The new request can be detected by the presence of the
1329
:pyeval:`rlib2._NODE_EVAC_RES1` feature string.
1330

    
1331
Job result:
1332

    
1333
.. opcode_result:: OP_NODE_EVACUATE
1334

    
1335

    
1336
``/2/nodes/[node_name]/migrate``
1337
+++++++++++++++++++++++++++++++++
1338

    
1339
Migrates all primary instances from a node.
1340

    
1341
It supports the following commands: ``POST``.
1342

    
1343
``POST``
1344
~~~~~~~~
1345

    
1346
If no mode is explicitly specified, each instances' hypervisor default
1347
migration mode will be used. Body parameters:
1348

    
1349
.. opcode_params:: OP_NODE_MIGRATE
1350
   :exclude: node_name
1351

    
1352
The query arguments used up to and including Ganeti 2.4 are deprecated
1353
and should no longer be used. The new request format can be detected by
1354
the presence of the :pyeval:`rlib2._NODE_MIGRATE_REQV1` feature string.
1355

    
1356
Job result:
1357

    
1358
.. opcode_result:: OP_NODE_MIGRATE
1359

    
1360

    
1361
``/2/nodes/[node_name]/role``
1362
+++++++++++++++++++++++++++++
1363

    
1364
Manages node role.
1365

    
1366
It supports the following commands: ``GET``, ``PUT``.
1367

    
1368
The role is always one of the following:
1369

    
1370
  - drained
1371
  - master-candidate
1372
  - offline
1373
  - regular
1374

    
1375
Note that the 'master' role is a special, and currently it can't be
1376
modified via RAPI, only via the command line (``gnt-cluster
1377
master-failover``).
1378

    
1379
``GET``
1380
~~~~~~~
1381

    
1382
Returns the current node role.
1383

    
1384
Example::
1385

    
1386
    "master-candidate"
1387

    
1388
``PUT``
1389
~~~~~~~
1390

    
1391
Change the node role.
1392

    
1393
The request is a string which should be PUT to this URI. The result will
1394
be a job id.
1395

    
1396
It supports the bool ``force`` argument.
1397

    
1398

    
1399
``/2/nodes/[node_name]/modify``
1400
+++++++++++++++++++++++++++++++
1401

    
1402
Modifies the parameters of a node. Supports the following commands:
1403
``POST``.
1404

    
1405
``POST``
1406
~~~~~~~~
1407

    
1408
Returns a job ID.
1409

    
1410
Body parameters:
1411

    
1412
.. opcode_params:: OP_NODE_SET_PARAMS
1413
   :exclude: node_name
1414

    
1415
Job result:
1416

    
1417
.. opcode_result:: OP_NODE_SET_PARAMS
1418

    
1419

    
1420
``/2/nodes/[node_name]/storage``
1421
++++++++++++++++++++++++++++++++
1422

    
1423
Manages storage units on the node.
1424

    
1425
``GET``
1426
~~~~~~~
1427

    
1428
.. pyassert::
1429

    
1430
   constants.VALID_STORAGE_TYPES == set([constants.ST_FILE,
1431
                                         constants.ST_LVM_PV,
1432
                                         constants.ST_LVM_VG])
1433

    
1434
Requests a list of storage units on a node. Requires the parameters
1435
``storage_type`` (one of :pyeval:`constants.ST_FILE`,
1436
:pyeval:`constants.ST_LVM_PV` or :pyeval:`constants.ST_LVM_VG`) and
1437
``output_fields``. The result will be a job id, using which the result
1438
can be retrieved.
1439

    
1440
``/2/nodes/[node_name]/storage/modify``
1441
+++++++++++++++++++++++++++++++++++++++
1442

    
1443
Modifies storage units on the node.
1444

    
1445
``PUT``
1446
~~~~~~~
1447

    
1448
Modifies parameters of storage units on the node. Requires the
1449
parameters ``storage_type`` (one of :pyeval:`constants.ST_FILE`,
1450
:pyeval:`constants.ST_LVM_PV` or :pyeval:`constants.ST_LVM_VG`)
1451
and ``name`` (name of the storage unit).  Parameters can be passed
1452
additionally. Currently only :pyeval:`constants.SF_ALLOCATABLE` (bool)
1453
is supported. The result will be a job id.
1454

    
1455
``/2/nodes/[node_name]/storage/repair``
1456
+++++++++++++++++++++++++++++++++++++++
1457

    
1458
Repairs a storage unit on the node.
1459

    
1460
``PUT``
1461
~~~~~~~
1462

    
1463
.. pyassert::
1464

    
1465
   constants.VALID_STORAGE_OPERATIONS == {
1466
    constants.ST_LVM_VG: set([constants.SO_FIX_CONSISTENCY]),
1467
    }
1468

    
1469
Repairs a storage unit on the node. Requires the parameters
1470
``storage_type`` (currently only :pyeval:`constants.ST_LVM_VG` can be
1471
repaired) and ``name`` (name of the storage unit). The result will be a
1472
job id.
1473

    
1474
``/2/nodes/[node_name]/tags``
1475
+++++++++++++++++++++++++++++
1476

    
1477
Manages per-node tags.
1478

    
1479
It supports the following commands: ``GET``, ``PUT``, ``DELETE``.
1480

    
1481
``GET``
1482
~~~~~~~
1483

    
1484
Returns a list of tags.
1485

    
1486
Example::
1487

    
1488
    ["tag1", "tag2", "tag3"]
1489

    
1490
``PUT``
1491
~~~~~~~
1492

    
1493
Add a set of tags.
1494

    
1495
The request as a list of strings should be PUT to this URI. The result
1496
will be a job id.
1497

    
1498
It supports the ``dry-run`` argument.
1499

    
1500
``DELETE``
1501
~~~~~~~~~~
1502

    
1503
Deletes tags.
1504

    
1505
In order to delete a set of tags, the DELETE request should be addressed
1506
to URI like::
1507

    
1508
    /tags?tag=[tag]&tag=[tag]
1509

    
1510
It supports the ``dry-run`` argument.
1511

    
1512

    
1513
``/2/query/[resource]``
1514
+++++++++++++++++++++++
1515

    
1516
Requests resource information. Available fields can be found in man
1517
pages and using ``/2/query/[resource]/fields``. The resource is one of
1518
:pyeval:`utils.CommaJoin(constants.QR_VIA_RAPI)`. See the :doc:`query2
1519
design document <design-query2>` for more details.
1520

    
1521
Supports the following commands: ``GET``, ``PUT``.
1522

    
1523
``GET``
1524
~~~~~~~
1525

    
1526
Returns list of included fields and actual data. Takes a query parameter
1527
named "fields", containing a comma-separated list of field names. Does
1528
not support filtering.
1529

    
1530
``PUT``
1531
~~~~~~~
1532

    
1533
Returns list of included fields and actual data. The list of requested
1534
fields can either be given as the query parameter "fields" or as a body
1535
parameter with the same name. The optional body parameter "filter" can
1536
be given and must be either ``null`` or a list containing filter
1537
operators.
1538

    
1539

    
1540
``/2/query/[resource]/fields``
1541
++++++++++++++++++++++++++++++
1542

    
1543
Request list of available fields for a resource. The resource is one of
1544
:pyeval:`utils.CommaJoin(constants.QR_VIA_RAPI)`. See the
1545
:doc:`query2 design document <design-query2>` for more details.
1546

    
1547
Supports the following commands: ``GET``.
1548

    
1549
``GET``
1550
~~~~~~~
1551

    
1552
Returns a list of field descriptions for available fields. Takes an
1553
optional query parameter named "fields", containing a comma-separated
1554
list of field names.
1555

    
1556

    
1557
``/2/os``
1558
+++++++++
1559

    
1560
OS resource.
1561

    
1562
It supports the following commands: ``GET``.
1563

    
1564
``GET``
1565
~~~~~~~
1566

    
1567
Return a list of all OSes.
1568

    
1569
Can return error 500 in case of a problem. Since this is a costly
1570
operation for Ganeti 2.0, it is not recommended to execute it too often.
1571

    
1572
Example::
1573

    
1574
    ["debian-etch"]
1575

    
1576
``/2/tags``
1577
+++++++++++
1578

    
1579
Manages cluster tags.
1580

    
1581
It supports the following commands: ``GET``, ``PUT``, ``DELETE``.
1582

    
1583
``GET``
1584
~~~~~~~
1585

    
1586
Returns the cluster tags.
1587

    
1588
Example::
1589

    
1590
    ["tag1", "tag2", "tag3"]
1591

    
1592
``PUT``
1593
~~~~~~~
1594

    
1595
Adds a set of tags.
1596

    
1597
The request as a list of strings should be PUT to this URI. The result
1598
will be a job id.
1599

    
1600
It supports the ``dry-run`` argument.
1601

    
1602

    
1603
``DELETE``
1604
~~~~~~~~~~
1605

    
1606
Deletes tags.
1607

    
1608
In order to delete a set of tags, the DELETE request should be addressed
1609
to URI like::
1610

    
1611
    /tags?tag=[tag]&tag=[tag]
1612

    
1613
It supports the ``dry-run`` argument.
1614

    
1615

    
1616
``/version``
1617
++++++++++++
1618

    
1619
The version resource.
1620

    
1621
This resource should be used to determine the remote API version and to
1622
adapt clients accordingly.
1623

    
1624
It supports the following commands: ``GET``.
1625

    
1626
``GET``
1627
~~~~~~~
1628

    
1629
Returns the remote API version. Ganeti 1.2 returned ``1`` and Ganeti 2.0
1630
returns ``2``.
1631

    
1632
.. vim: set textwidth=72 :
1633
.. Local Variables:
1634
.. mode: rst
1635
.. fill-column: 72
1636
.. End: