Statistics
| Branch: | Tag: | Revision:

root / doc / rapi.rst @ a194dc28

History | View | Annotate | Download (36 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
                                     constants.IPOLICY_SPINDLE_RATIO])
190

    
191

    
192
.. pyassert::
193

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

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

    
205

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

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

    
227
Usage examples
228
--------------
229

    
230
You can access the API using your favorite programming language as long
231
as it supports network connections.
232

    
233
Ganeti RAPI client
234
++++++++++++++++++
235

    
236
Ganeti includes a standalone RAPI client, ``lib/rapi/client.py``.
237

    
238
Shell
239
+++++
240

    
241
.. highlight:: sh
242

    
243
Using wget::
244

    
245
   wget -q -O - https://CLUSTERNAME:5080/2/info
246

    
247
or curl::
248

    
249
  curl https://CLUSTERNAME:5080/2/info
250

    
251

    
252
Python
253
++++++
254

    
255
.. highlight:: python
256

    
257
::
258

    
259
  import urllib2
260
  f = urllib2.urlopen('https://CLUSTERNAME:5080/2/info')
261
  print f.read()
262

    
263

    
264
JavaScript
265
++++++++++
266

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

    
272
.. highlight:: javascript
273

    
274
::
275

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

    
292
Resources
293
---------
294

    
295
.. highlight:: javascript
296

    
297
``/``
298
+++++
299

    
300
The root resource. Has no function, but for legacy reasons the ``GET``
301
method is supported.
302

    
303
``/2``
304
++++++
305

    
306
Has no function, but for legacy reasons the ``GET`` method is supported.
307

    
308
``/2/info``
309
+++++++++++
310

    
311
Cluster information resource.
312

    
313
It supports the following commands: ``GET``.
314

    
315
``GET``
316
~~~~~~~
317

    
318
Returns cluster information.
319

    
320
Example::
321

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

    
351

    
352
``/2/redistribute-config``
353
++++++++++++++++++++++++++
354

    
355
Redistribute configuration to all nodes.
356

    
357
It supports the following commands: ``PUT``.
358

    
359
``PUT``
360
~~~~~~~
361

    
362
Redistribute configuration to all nodes. The result will be a job id.
363

    
364

    
365
``/2/features``
366
+++++++++++++++
367

    
368
``GET``
369
~~~~~~~
370

    
371
Returns a list of features supported by the RAPI server. Available
372
features:
373

    
374
.. pyassert::
375

    
376
  rlib2.ALL_FEATURES == set([rlib2._INST_CREATE_REQV1,
377
                             rlib2._INST_REINSTALL_REQV1,
378
                             rlib2._NODE_MIGRATE_REQV1,
379
                             rlib2._NODE_EVAC_RES1])
380

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

    
392

    
393
``/2/modify``
394
++++++++++++++++++++++++++++++++++++++++
395

    
396
Modifies cluster parameters.
397

    
398
Supports the following commands: ``PUT``.
399

    
400
``PUT``
401
~~~~~~~
402

    
403
Returns a job ID.
404

    
405
Body parameters:
406

    
407
.. opcode_params:: OP_CLUSTER_SET_PARAMS
408

    
409

    
410
``/2/groups``
411
+++++++++++++
412

    
413
The groups resource.
414

    
415
It supports the following commands: ``GET``, ``POST``.
416

    
417
``GET``
418
~~~~~~~
419

    
420
Returns a list of all existing node groups.
421

    
422
Example::
423

    
424
    [
425
      {
426
        "name": "group1",
427
        "uri": "\/2\/groups\/group1"
428
      },
429
      {
430
        "name": "group2",
431
        "uri": "\/2\/groups\/group2"
432
      }
433
    ]
434

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

    
439
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.G_FIELDS))`
440

    
441
Example::
442

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

    
463
``POST``
464
~~~~~~~~
465

    
466
Creates a node group.
467

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

    
471
Returns: a job ID that can be used later for polling.
472

    
473
Body parameters:
474

    
475
.. opcode_params:: OP_GROUP_ADD
476

    
477
Earlier versions used a parameter named ``name`` which, while still
478
supported, has been renamed to ``group_name``.
479

    
480

    
481
``/2/groups/[group_name]``
482
++++++++++++++++++++++++++
483

    
484
Returns information about a node group.
485

    
486
It supports the following commands: ``GET``, ``DELETE``.
487

    
488
``GET``
489
~~~~~~~
490

    
491
Returns information about a node group, similar to the bulk output from
492
the node group list.
493

    
494
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.G_FIELDS))`
495

    
496
``DELETE``
497
~~~~~~~~~~
498

    
499
Deletes a node group.
500

    
501
It supports the ``dry-run`` argument.
502

    
503

    
504
``/2/groups/[group_name]/modify``
505
+++++++++++++++++++++++++++++++++
506

    
507
Modifies the parameters of a node group.
508

    
509
Supports the following commands: ``PUT``.
510

    
511
``PUT``
512
~~~~~~~
513

    
514
Returns a job ID.
515

    
516
Body parameters:
517

    
518
.. opcode_params:: OP_GROUP_SET_PARAMS
519
   :exclude: group_name
520

    
521
Job result:
522

    
523
.. opcode_result:: OP_GROUP_SET_PARAMS
524

    
525

    
526
``/2/groups/[group_name]/rename``
527
+++++++++++++++++++++++++++++++++
528

    
529
Renames a node group.
530

    
531
Supports the following commands: ``PUT``.
532

    
533
``PUT``
534
~~~~~~~
535

    
536
Returns a job ID.
537

    
538
Body parameters:
539

    
540
.. opcode_params:: OP_GROUP_RENAME
541
   :exclude: group_name
542

    
543
Job result:
544

    
545
.. opcode_result:: OP_GROUP_RENAME
546

    
547

    
548
``/2/groups/[group_name]/assign-nodes``
549
+++++++++++++++++++++++++++++++++++++++
550

    
551
Assigns nodes to a group.
552

    
553
Supports the following commands: ``PUT``.
554

    
555
``PUT``
556
~~~~~~~
557

    
558
Returns a job ID. It supports the ``dry-run`` and ``force`` arguments.
559

    
560
Body parameters:
561

    
562
.. opcode_params:: OP_GROUP_ASSIGN_NODES
563
   :exclude: group_name, force, dry_run
564

    
565

    
566
``/2/groups/[group_name]/tags``
567
+++++++++++++++++++++++++++++++
568

    
569
Manages per-nodegroup tags.
570

    
571
Supports the following commands: ``GET``, ``PUT``, ``DELETE``.
572

    
573
``GET``
574
~~~~~~~
575

    
576
Returns a list of tags.
577

    
578
Example::
579

    
580
    ["tag1", "tag2", "tag3"]
581

    
582
``PUT``
583
~~~~~~~
584

    
585
Add a set of tags.
586

    
587
The request as a list of strings should be ``PUT`` to this URI. The
588
result will be a job id.
589

    
590
It supports the ``dry-run`` argument.
591

    
592

    
593
``DELETE``
594
~~~~~~~~~~
595

    
596
Delete a tag.
597

    
598
In order to delete a set of tags, the DELETE request should be addressed
599
to URI like::
600

    
601
    /tags?tag=[tag]&tag=[tag]
602

    
603
It supports the ``dry-run`` argument.
604

    
605

    
606
``/2/instances``
607
++++++++++++++++
608

    
609
The instances resource.
610

    
611
It supports the following commands: ``GET``, ``POST``.
612

    
613
``GET``
614
~~~~~~~
615

    
616
Returns a list of all available instances.
617

    
618
Example::
619

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

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

    
635
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.I_FIELDS))`
636

    
637
Example::
638

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

    
666

    
667
``POST``
668
~~~~~~~~
669

    
670
Creates an instance.
671

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

    
677
Returns: a job ID that can be used later for polling.
678

    
679
Body parameters:
680

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

    
686
.. opcode_params:: OP_INSTANCE_CREATE
687

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

    
692
Job result:
693

    
694
.. opcode_result:: OP_INSTANCE_CREATE
695

    
696

    
697
``/2/instances/[instance_name]``
698
++++++++++++++++++++++++++++++++
699

    
700
Instance-specific resource.
701

    
702
It supports the following commands: ``GET``, ``DELETE``.
703

    
704
``GET``
705
~~~~~~~
706

    
707
Returns information about an instance, similar to the bulk output from
708
the instance list.
709

    
710
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.I_FIELDS))`
711

    
712
``DELETE``
713
~~~~~~~~~~
714

    
715
Deletes an instance.
716

    
717
It supports the ``dry-run`` argument.
718

    
719

    
720
``/2/instances/[instance_name]/info``
721
+++++++++++++++++++++++++++++++++++++++
722

    
723
It supports the following commands: ``GET``.
724

    
725
``GET``
726
~~~~~~~
727

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

    
733

    
734
``/2/instances/[instance_name]/reboot``
735
+++++++++++++++++++++++++++++++++++++++
736

    
737
Reboots URI for an instance.
738

    
739
It supports the following commands: ``POST``.
740

    
741
``POST``
742
~~~~~~~~
743

    
744
Reboots the instance.
745

    
746
The URI takes optional ``type=soft|hard|full`` and
747
``ignore_secondaries=0|1`` parameters.
748

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

    
756
``ignore_secondaries`` is a bool argument indicating if we start the
757
instance even if secondary disks are failing.
758

    
759
It supports the ``dry-run`` argument.
760

    
761

    
762
``/2/instances/[instance_name]/shutdown``
763
+++++++++++++++++++++++++++++++++++++++++
764

    
765
Instance shutdown URI.
766

    
767
It supports the following commands: ``PUT``.
768

    
769
``PUT``
770
~~~~~~~
771

    
772
Shutdowns an instance.
773

    
774
It supports the ``dry-run`` argument.
775

    
776
.. opcode_params:: OP_INSTANCE_SHUTDOWN
777
   :exclude: instance_name, dry_run
778

    
779

    
780
``/2/instances/[instance_name]/startup``
781
++++++++++++++++++++++++++++++++++++++++
782

    
783
Instance startup URI.
784

    
785
It supports the following commands: ``PUT``.
786

    
787
``PUT``
788
~~~~~~~
789

    
790
Startup an instance.
791

    
792
The URI takes an optional ``force=1|0`` parameter to start the
793
instance even if secondary disks are failing.
794

    
795
It supports the ``dry-run`` argument.
796

    
797
``/2/instances/[instance_name]/reinstall``
798
++++++++++++++++++++++++++++++++++++++++++++++
799

    
800
Installs the operating system again.
801

    
802
It supports the following commands: ``POST``.
803

    
804
``POST``
805
~~~~~~~~
806

    
807
Returns a job ID.
808

    
809
Body parameters:
810

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

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

    
822

    
823
``/2/instances/[instance_name]/replace-disks``
824
++++++++++++++++++++++++++++++++++++++++++++++
825

    
826
Replaces disks on an instance.
827

    
828
It supports the following commands: ``POST``.
829

    
830
``POST``
831
~~~~~~~~
832

    
833
Returns a job ID.
834

    
835
Body parameters:
836

    
837
.. opcode_params:: OP_INSTANCE_REPLACE_DISKS
838
   :exclude: instance_name
839

    
840
Ganeti 2.4 and below used query parameters. Those are deprecated and
841
should no longer be used.
842

    
843

    
844
``/2/instances/[instance_name]/activate-disks``
845
+++++++++++++++++++++++++++++++++++++++++++++++
846

    
847
Activate disks on an instance.
848

    
849
It supports the following commands: ``PUT``.
850

    
851
``PUT``
852
~~~~~~~
853

    
854
Takes the bool parameter ``ignore_size``. When set ignore the recorded
855
size (useful for forcing activation when recorded size is wrong).
856

    
857

    
858
``/2/instances/[instance_name]/deactivate-disks``
859
+++++++++++++++++++++++++++++++++++++++++++++++++
860

    
861
Deactivate disks on an instance.
862

    
863
It supports the following commands: ``PUT``.
864

    
865
``PUT``
866
~~~~~~~
867

    
868
Takes no parameters.
869

    
870

    
871
``/2/instances/[instance_name]/recreate-disks``
872
+++++++++++++++++++++++++++++++++++++++++++++++++
873

    
874
Recreate disks of an instance. Supports the following commands:
875
``POST``.
876

    
877
``POST``
878
~~~~~~~~
879

    
880
Returns a job ID.
881

    
882
Body parameters:
883

    
884
.. opcode_params:: OP_INSTANCE_RECREATE_DISKS
885
   :exclude: instance_name
886

    
887

    
888
``/2/instances/[instance_name]/disk/[disk_index]/grow``
889
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
890

    
891
Grows one disk of an instance.
892

    
893
Supports the following commands: ``POST``.
894

    
895
``POST``
896
~~~~~~~~
897

    
898
Returns a job ID.
899

    
900
Body parameters:
901

    
902
.. opcode_params:: OP_INSTANCE_GROW_DISK
903
   :exclude: instance_name, disk
904

    
905

    
906
``/2/instances/[instance_name]/prepare-export``
907
+++++++++++++++++++++++++++++++++++++++++++++++++
908

    
909
Prepares an export of an instance.
910

    
911
It supports the following commands: ``PUT``.
912

    
913
``PUT``
914
~~~~~~~
915

    
916
Takes one parameter, ``mode``, for the export mode. Returns a job ID.
917

    
918

    
919
``/2/instances/[instance_name]/export``
920
+++++++++++++++++++++++++++++++++++++++++++++++++
921

    
922
Exports an instance.
923

    
924
It supports the following commands: ``PUT``.
925

    
926
``PUT``
927
~~~~~~~
928

    
929
Returns a job ID.
930

    
931
Body parameters:
932

    
933
.. opcode_params:: OP_BACKUP_EXPORT
934
   :exclude: instance_name
935
   :alias: target_node=destination
936

    
937

    
938
``/2/instances/[instance_name]/migrate``
939
++++++++++++++++++++++++++++++++++++++++
940

    
941
Migrates an instance.
942

    
943
Supports the following commands: ``PUT``.
944

    
945
``PUT``
946
~~~~~~~
947

    
948
Returns a job ID.
949

    
950
Body parameters:
951

    
952
.. opcode_params:: OP_INSTANCE_MIGRATE
953
   :exclude: instance_name, live
954

    
955

    
956
``/2/instances/[instance_name]/failover``
957
+++++++++++++++++++++++++++++++++++++++++
958

    
959
Does a failover of an instance.
960

    
961
Supports the following commands: ``PUT``.
962

    
963
``PUT``
964
~~~~~~~
965

    
966
Returns a job ID.
967

    
968
Body parameters:
969

    
970
.. opcode_params:: OP_INSTANCE_FAILOVER
971
   :exclude: instance_name
972

    
973

    
974
``/2/instances/[instance_name]/rename``
975
++++++++++++++++++++++++++++++++++++++++
976

    
977
Renames an instance.
978

    
979
Supports the following commands: ``PUT``.
980

    
981
``PUT``
982
~~~~~~~
983

    
984
Returns a job ID.
985

    
986
Body parameters:
987

    
988
.. opcode_params:: OP_INSTANCE_RENAME
989
   :exclude: instance_name
990

    
991
Job result:
992

    
993
.. opcode_result:: OP_INSTANCE_RENAME
994

    
995

    
996
``/2/instances/[instance_name]/modify``
997
++++++++++++++++++++++++++++++++++++++++
998

    
999
Modifies an instance.
1000

    
1001
Supports the following commands: ``PUT``.
1002

    
1003
``PUT``
1004
~~~~~~~
1005

    
1006
Returns a job ID.
1007

    
1008
Body parameters:
1009

    
1010
.. opcode_params:: OP_INSTANCE_SET_PARAMS
1011
   :exclude: instance_name
1012

    
1013
Job result:
1014

    
1015
.. opcode_result:: OP_INSTANCE_SET_PARAMS
1016

    
1017

    
1018
``/2/instances/[instance_name]/console``
1019
++++++++++++++++++++++++++++++++++++++++
1020

    
1021
Request information for connecting to instance's console.
1022

    
1023
Supports the following commands: ``GET``.
1024

    
1025
``GET``
1026
~~~~~~~
1027

    
1028
Returns a dictionary containing information about the instance's
1029
console. Contained keys:
1030

    
1031
.. pyassert::
1032

    
1033
   constants.CONS_ALL == frozenset([
1034
     constants.CONS_MESSAGE,
1035
     constants.CONS_SSH,
1036
     constants.CONS_VNC,
1037
     constants.CONS_SPICE,
1038
     ])
1039

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

    
1061

    
1062
``/2/instances/[instance_name]/tags``
1063
+++++++++++++++++++++++++++++++++++++
1064

    
1065
Manages per-instance tags.
1066

    
1067
It supports the following commands: ``GET``, ``PUT``, ``DELETE``.
1068

    
1069
``GET``
1070
~~~~~~~
1071

    
1072
Returns a list of tags.
1073

    
1074
Example::
1075

    
1076
    ["tag1", "tag2", "tag3"]
1077

    
1078
``PUT``
1079
~~~~~~~
1080

    
1081
Add a set of tags.
1082

    
1083
The request as a list of strings should be ``PUT`` to this URI. The
1084
result will be a job id.
1085

    
1086
It supports the ``dry-run`` argument.
1087

    
1088

    
1089
``DELETE``
1090
~~~~~~~~~~
1091

    
1092
Delete a tag.
1093

    
1094
In order to delete a set of tags, the DELETE request should be addressed
1095
to URI like::
1096

    
1097
    /tags?tag=[tag]&tag=[tag]
1098

    
1099
It supports the ``dry-run`` argument.
1100

    
1101

    
1102
``/2/jobs``
1103
+++++++++++
1104

    
1105
The ``/2/jobs`` resource.
1106

    
1107
It supports the following commands: ``GET``.
1108

    
1109
``GET``
1110
~~~~~~~
1111

    
1112
Returns a dictionary of jobs.
1113

    
1114
Returns: a dictionary with jobs id and uri.
1115

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

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

    
1124
``/2/jobs/[job_id]``
1125
++++++++++++++++++++
1126

    
1127

    
1128
Individual job URI.
1129

    
1130
It supports the following commands: ``GET``, ``DELETE``.
1131

    
1132
``GET``
1133
~~~~~~~
1134

    
1135
Returns a dictionary with job parameters, containing the fields
1136
:pyeval:`utils.CommaJoin(sorted(rlib2.J_FIELDS))`.
1137

    
1138
The result includes:
1139

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

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

    
1152
- first element the error type (the Ganeti internal error name)
1153
- second element a list of either one or two elements:
1154

    
1155
  - the first element is the textual error description
1156
  - the second element, if any, will hold an error classification
1157

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

    
1164
.. pyassert::
1165

    
1166
   errors.ECODE_ALL == set([errors.ECODE_RESOLVER, errors.ECODE_NORES,
1167
     errors.ECODE_INVAL, errors.ECODE_STATE, errors.ECODE_NOENT,
1168
     errors.ECODE_EXISTS, errors.ECODE_NOTUNIQUE, errors.ECODE_FAULT,
1169
     errors.ECODE_ENVIRON])
1170

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

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

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

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

    
1190
:pyeval:`errors.ECODE_NOENT`
1191
  Entity not found. For example, information has been requested for an
1192
  unknown instance.
1193

    
1194
:pyeval:`errors.ECODE_EXISTS`
1195
  Entity already exists. For example, instance creation has been
1196
  requested for an already-existing instance.
1197

    
1198
:pyeval:`errors.ECODE_NOTUNIQUE`
1199
  Resource not unique (e.g. MAC or IP duplication).
1200

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

    
1206
:pyeval:`errors.ECODE_ENVIRON`
1207
  Environment error (e.g. node disk error). A ``gnt-cluster verify``
1208
  should be run.
1209

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

    
1213

    
1214
``DELETE``
1215
~~~~~~~~~~
1216

    
1217
Cancel a not-yet-started job.
1218

    
1219

    
1220
``/2/jobs/[job_id]/wait``
1221
+++++++++++++++++++++++++
1222

    
1223
``GET``
1224
~~~~~~~
1225

    
1226
Waits for changes on a job. Takes the following body parameters in a
1227
dict:
1228

    
1229
``fields``
1230
  The job fields on which to watch for changes.
1231

    
1232
``previous_job_info``
1233
  Previously received field values or None if not yet available.
1234

    
1235
``previous_log_serial``
1236
  Highest log serial number received so far or None if not yet
1237
  available.
1238

    
1239
Returns None if no changes have been detected and a dict with two keys,
1240
``job_info`` and ``log_entries`` otherwise.
1241

    
1242

    
1243
``/2/nodes``
1244
++++++++++++
1245

    
1246
Nodes resource.
1247

    
1248
It supports the following commands: ``GET``.
1249

    
1250
``GET``
1251
~~~~~~~
1252

    
1253
Returns a list of all nodes.
1254

    
1255
Example::
1256

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

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

    
1272
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.N_FIELDS))`
1273

    
1274
Example::
1275

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

    
1292
``/2/nodes/[node_name]``
1293
+++++++++++++++++++++++++++++++++
1294

    
1295
Returns information about a node.
1296

    
1297
It supports the following commands: ``GET``.
1298

    
1299
Returned fields: :pyeval:`utils.CommaJoin(sorted(rlib2.N_FIELDS))`
1300

    
1301
``/2/nodes/[node_name]/powercycle``
1302
+++++++++++++++++++++++++++++++++++
1303

    
1304
Powercycles a node. Supports the following commands: ``POST``.
1305

    
1306
``POST``
1307
~~~~~~~~
1308

    
1309
Returns a job ID.
1310

    
1311

    
1312
``/2/nodes/[node_name]/evacuate``
1313
+++++++++++++++++++++++++++++++++
1314

    
1315
Evacuates instances off a node.
1316

    
1317
It supports the following commands: ``POST``.
1318

    
1319
``POST``
1320
~~~~~~~~
1321

    
1322
Returns a job ID. The result of the job will contain the IDs of the
1323
individual jobs submitted to evacuate the node.
1324

    
1325
Body parameters:
1326

    
1327
.. opcode_params:: OP_NODE_EVACUATE
1328
   :exclude: nodes
1329

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

    
1334
Job result:
1335

    
1336
.. opcode_result:: OP_NODE_EVACUATE
1337

    
1338

    
1339
``/2/nodes/[node_name]/migrate``
1340
+++++++++++++++++++++++++++++++++
1341

    
1342
Migrates all primary instances from a node.
1343

    
1344
It supports the following commands: ``POST``.
1345

    
1346
``POST``
1347
~~~~~~~~
1348

    
1349
If no mode is explicitly specified, each instances' hypervisor default
1350
migration mode will be used. Body parameters:
1351

    
1352
.. opcode_params:: OP_NODE_MIGRATE
1353
   :exclude: node_name
1354

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

    
1359
Job result:
1360

    
1361
.. opcode_result:: OP_NODE_MIGRATE
1362

    
1363

    
1364
``/2/nodes/[node_name]/role``
1365
+++++++++++++++++++++++++++++
1366

    
1367
Manages node role.
1368

    
1369
It supports the following commands: ``GET``, ``PUT``.
1370

    
1371
The role is always one of the following:
1372

    
1373
  - drained
1374
  - master-candidate
1375
  - offline
1376
  - regular
1377

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

    
1382
``GET``
1383
~~~~~~~
1384

    
1385
Returns the current node role.
1386

    
1387
Example::
1388

    
1389
    "master-candidate"
1390

    
1391
``PUT``
1392
~~~~~~~
1393

    
1394
Change the node role.
1395

    
1396
The request is a string which should be PUT to this URI. The result will
1397
be a job id.
1398

    
1399
It supports the bool ``force`` argument.
1400

    
1401

    
1402
``/2/nodes/[node_name]/modify``
1403
+++++++++++++++++++++++++++++++
1404

    
1405
Modifies the parameters of a node. Supports the following commands:
1406
``POST``.
1407

    
1408
``POST``
1409
~~~~~~~~
1410

    
1411
Returns a job ID.
1412

    
1413
Body parameters:
1414

    
1415
.. opcode_params:: OP_NODE_SET_PARAMS
1416
   :exclude: node_name
1417

    
1418
Job result:
1419

    
1420
.. opcode_result:: OP_NODE_SET_PARAMS
1421

    
1422

    
1423
``/2/nodes/[node_name]/storage``
1424
++++++++++++++++++++++++++++++++
1425

    
1426
Manages storage units on the node.
1427

    
1428
``GET``
1429
~~~~~~~
1430

    
1431
.. pyassert::
1432

    
1433
   constants.VALID_STORAGE_TYPES == set([constants.ST_FILE,
1434
                                         constants.ST_LVM_PV,
1435
                                         constants.ST_LVM_VG])
1436

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

    
1443
``/2/nodes/[node_name]/storage/modify``
1444
+++++++++++++++++++++++++++++++++++++++
1445

    
1446
Modifies storage units on the node.
1447

    
1448
``PUT``
1449
~~~~~~~
1450

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

    
1458
``/2/nodes/[node_name]/storage/repair``
1459
+++++++++++++++++++++++++++++++++++++++
1460

    
1461
Repairs a storage unit on the node.
1462

    
1463
``PUT``
1464
~~~~~~~
1465

    
1466
.. pyassert::
1467

    
1468
   constants.VALID_STORAGE_OPERATIONS == {
1469
    constants.ST_LVM_VG: set([constants.SO_FIX_CONSISTENCY]),
1470
    }
1471

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

    
1477
``/2/nodes/[node_name]/tags``
1478
+++++++++++++++++++++++++++++
1479

    
1480
Manages per-node tags.
1481

    
1482
It supports the following commands: ``GET``, ``PUT``, ``DELETE``.
1483

    
1484
``GET``
1485
~~~~~~~
1486

    
1487
Returns a list of tags.
1488

    
1489
Example::
1490

    
1491
    ["tag1", "tag2", "tag3"]
1492

    
1493
``PUT``
1494
~~~~~~~
1495

    
1496
Add a set of tags.
1497

    
1498
The request as a list of strings should be PUT to this URI. The result
1499
will be a job id.
1500

    
1501
It supports the ``dry-run`` argument.
1502

    
1503
``DELETE``
1504
~~~~~~~~~~
1505

    
1506
Deletes tags.
1507

    
1508
In order to delete a set of tags, the DELETE request should be addressed
1509
to URI like::
1510

    
1511
    /tags?tag=[tag]&tag=[tag]
1512

    
1513
It supports the ``dry-run`` argument.
1514

    
1515

    
1516
``/2/query/[resource]``
1517
+++++++++++++++++++++++
1518

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

    
1524
Supports the following commands: ``GET``, ``PUT``.
1525

    
1526
``GET``
1527
~~~~~~~
1528

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

    
1533
``PUT``
1534
~~~~~~~
1535

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

    
1542

    
1543
``/2/query/[resource]/fields``
1544
++++++++++++++++++++++++++++++
1545

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

    
1550
Supports the following commands: ``GET``.
1551

    
1552
``GET``
1553
~~~~~~~
1554

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

    
1559

    
1560
``/2/os``
1561
+++++++++
1562

    
1563
OS resource.
1564

    
1565
It supports the following commands: ``GET``.
1566

    
1567
``GET``
1568
~~~~~~~
1569

    
1570
Return a list of all OSes.
1571

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

    
1575
Example::
1576

    
1577
    ["debian-etch"]
1578

    
1579
``/2/tags``
1580
+++++++++++
1581

    
1582
Manages cluster tags.
1583

    
1584
It supports the following commands: ``GET``, ``PUT``, ``DELETE``.
1585

    
1586
``GET``
1587
~~~~~~~
1588

    
1589
Returns the cluster tags.
1590

    
1591
Example::
1592

    
1593
    ["tag1", "tag2", "tag3"]
1594

    
1595
``PUT``
1596
~~~~~~~
1597

    
1598
Adds a set of tags.
1599

    
1600
The request as a list of strings should be PUT to this URI. The result
1601
will be a job id.
1602

    
1603
It supports the ``dry-run`` argument.
1604

    
1605

    
1606
``DELETE``
1607
~~~~~~~~~~
1608

    
1609
Deletes tags.
1610

    
1611
In order to delete a set of tags, the DELETE request should be addressed
1612
to URI like::
1613

    
1614
    /tags?tag=[tag]&tag=[tag]
1615

    
1616
It supports the ``dry-run`` argument.
1617

    
1618

    
1619
``/version``
1620
++++++++++++
1621

    
1622
The version resource.
1623

    
1624
This resource should be used to determine the remote API version and to
1625
adapt clients accordingly.
1626

    
1627
It supports the following commands: ``GET``.
1628

    
1629
``GET``
1630
~~~~~~~
1631

    
1632
Returns the remote API version. Ganeti 1.2 returned ``1`` and Ganeti 2.0
1633
returns ``2``.
1634

    
1635
.. vim: set textwidth=72 :
1636
.. Local Variables:
1637
.. mode: rst
1638
.. fill-column: 72
1639
.. End: