Statistics
| Branch: | Tag: | Revision:

root / qa / qa_rapi.py @ 946e553b

History | View | Annotate | Download (22.2 kB)

1
#
2
#
3

    
4
# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""Remote API QA tests.
23

24
"""
25

    
26
import tempfile
27
import random
28
import re
29
import itertools
30

    
31
from ganeti import utils
32
from ganeti import constants
33
from ganeti import errors
34
from ganeti import cli
35
from ganeti import rapi
36
from ganeti import objects
37
from ganeti import query
38
from ganeti import compat
39
from ganeti import qlang
40
from ganeti import pathutils
41

    
42
import ganeti.rapi.client        # pylint: disable=W0611
43
import ganeti.rapi.client_utils
44

    
45
import qa_config
46
import qa_utils
47
import qa_error
48

    
49
from qa_utils import (AssertEqual, AssertIn, AssertMatch, StartLocalCommand)
50
from qa_utils import InstanceCheck, INST_DOWN, INST_UP, FIRST_ARG
51

    
52

    
53
_rapi_ca = None
54
_rapi_client = None
55
_rapi_username = None
56
_rapi_password = None
57

    
58

    
59
def Setup(username, password):
60
  """Configures the RAPI client.
61

62
  """
63
  # pylint: disable=W0603
64
  # due to global usage
65
  global _rapi_ca
66
  global _rapi_client
67
  global _rapi_username
68
  global _rapi_password
69

    
70
  _rapi_username = username
71
  _rapi_password = password
72

    
73
  master = qa_config.GetMasterNode()
74

    
75
  # Load RAPI certificate from master node
76
  cmd = ["cat", pathutils.RAPI_CERT_FILE]
77

    
78
  # Write to temporary file
79
  _rapi_ca = tempfile.NamedTemporaryFile()
80
  _rapi_ca.write(qa_utils.GetCommandOutput(master["primary"],
81
                                           utils.ShellQuoteArgs(cmd)))
82
  _rapi_ca.flush()
83

    
84
  port = qa_config.get("rapi-port", default=constants.DEFAULT_RAPI_PORT)
85
  cfg_curl = rapi.client.GenericCurlConfig(cafile=_rapi_ca.name,
86
                                           proxy="")
87

    
88
  _rapi_client = rapi.client.GanetiRapiClient(master["primary"], port=port,
89
                                              username=username,
90
                                              password=password,
91
                                              curl_config_fn=cfg_curl)
92

    
93
  print "RAPI protocol version: %s" % _rapi_client.GetVersion()
94

    
95

    
96
INSTANCE_FIELDS = ("name", "os", "pnode", "snodes",
97
                   "admin_state",
98
                   "disk_template", "disk.sizes",
99
                   "nic.ips", "nic.macs", "nic.modes", "nic.links",
100
                   "beparams", "hvparams",
101
                   "oper_state", "oper_ram", "oper_vcpus", "status", "tags")
102

    
103
NODE_FIELDS = ("name", "dtotal", "dfree",
104
               "mtotal", "mnode", "mfree",
105
               "pinst_cnt", "sinst_cnt", "tags")
106

    
107
GROUP_FIELDS = frozenset([
108
  "name", "uuid",
109
  "alloc_policy",
110
  "node_cnt", "node_list",
111
  ])
112

    
113
JOB_FIELDS = frozenset([
114
  "id", "ops", "status", "summary",
115
  "opstatus", "opresult", "oplog",
116
  "received_ts", "start_ts", "end_ts",
117
  ])
118

    
119
LIST_FIELDS = ("id", "uri")
120

    
121

    
122
def Enabled():
123
  """Return whether remote API tests should be run.
124

125
  """
126
  return qa_config.TestEnabled("rapi")
127

    
128

    
129
def _DoTests(uris):
130
  # pylint: disable=W0212
131
  # due to _SendRequest usage
132
  results = []
133

    
134
  for uri, verify, method, body in uris:
135
    assert uri.startswith("/")
136

    
137
    print "%s %s" % (method, uri)
138
    data = _rapi_client._SendRequest(method, uri, None, body)
139

    
140
    if verify is not None:
141
      if callable(verify):
142
        verify(data)
143
      else:
144
        AssertEqual(data, verify)
145

    
146
    results.append(data)
147

    
148
  return results
149

    
150

    
151
def _VerifyReturnsJob(data):
152
  if not isinstance(data, int):
153
    AssertMatch(data, r"^\d+$")
154

    
155

    
156
def TestVersion():
157
  """Testing remote API version.
158

159
  """
160
  _DoTests([
161
    ("/version", constants.RAPI_VERSION, "GET", None),
162
    ])
163

    
164

    
165
def TestEmptyCluster():
166
  """Testing remote API on an empty cluster.
167

168
  """
169
  master = qa_config.GetMasterNode()
170
  master_full = qa_utils.ResolveNodeName(master)
171

    
172
  def _VerifyInfo(data):
173
    AssertIn("name", data)
174
    AssertIn("master", data)
175
    AssertEqual(data["master"], master_full)
176

    
177
  def _VerifyNodes(data):
178
    master_entry = {
179
      "id": master_full,
180
      "uri": "/2/nodes/%s" % master_full,
181
      }
182
    AssertIn(master_entry, data)
183

    
184
  def _VerifyNodesBulk(data):
185
    for node in data:
186
      for entry in NODE_FIELDS:
187
        AssertIn(entry, node)
188

    
189
  def _VerifyGroups(data):
190
    default_group = {
191
      "name": constants.INITIAL_NODE_GROUP_NAME,
192
      "uri": "/2/groups/" + constants.INITIAL_NODE_GROUP_NAME,
193
      }
194
    AssertIn(default_group, data)
195

    
196
  def _VerifyGroupsBulk(data):
197
    for group in data:
198
      for field in GROUP_FIELDS:
199
        AssertIn(field, group)
200

    
201
  _DoTests([
202
    ("/", None, "GET", None),
203
    ("/2/info", _VerifyInfo, "GET", None),
204
    ("/2/tags", None, "GET", None),
205
    ("/2/nodes", _VerifyNodes, "GET", None),
206
    ("/2/nodes?bulk=1", _VerifyNodesBulk, "GET", None),
207
    ("/2/groups", _VerifyGroups, "GET", None),
208
    ("/2/groups?bulk=1", _VerifyGroupsBulk, "GET", None),
209
    ("/2/instances", [], "GET", None),
210
    ("/2/instances?bulk=1", [], "GET", None),
211
    ("/2/os", None, "GET", None),
212
    ])
213

    
214
  # Test HTTP Not Found
215
  for method in ["GET", "PUT", "POST", "DELETE"]:
216
    try:
217
      _DoTests([("/99/resource/not/here/99", None, method, None)])
218
    except rapi.client.GanetiApiError, err:
219
      AssertEqual(err.code, 404)
220
    else:
221
      raise qa_error.Error("Non-existent resource didn't return HTTP 404")
222

    
223
  # Test HTTP Not Implemented
224
  for method in ["PUT", "POST", "DELETE"]:
225
    try:
226
      _DoTests([("/version", None, method, None)])
227
    except rapi.client.GanetiApiError, err:
228
      AssertEqual(err.code, 501)
229
    else:
230
      raise qa_error.Error("Non-implemented method didn't fail")
231

    
232

    
233
def TestRapiQuery():
234
  """Testing resource queries via remote API.
235

236
  """
237
  master_name = qa_utils.ResolveNodeName(qa_config.GetMasterNode())
238
  rnd = random.Random(7818)
239

    
240
  for what in constants.QR_VIA_RAPI:
241
    if what == constants.QR_JOB:
242
      namefield = "id"
243
    elif what == constants.QR_EXPORT:
244
      namefield = "export"
245
    else:
246
      namefield = "name"
247

    
248
    all_fields = query.ALL_FIELDS[what].keys()
249
    rnd.shuffle(all_fields)
250

    
251
    # No fields, should return everything
252
    result = _rapi_client.QueryFields(what)
253
    qresult = objects.QueryFieldsResponse.FromDict(result)
254
    AssertEqual(len(qresult.fields), len(all_fields))
255

    
256
    # One field
257
    result = _rapi_client.QueryFields(what, fields=[namefield])
258
    qresult = objects.QueryFieldsResponse.FromDict(result)
259
    AssertEqual(len(qresult.fields), 1)
260

    
261
    # Specify all fields, order must be correct
262
    result = _rapi_client.QueryFields(what, fields=all_fields)
263
    qresult = objects.QueryFieldsResponse.FromDict(result)
264
    AssertEqual(len(qresult.fields), len(all_fields))
265
    AssertEqual([fdef.name for fdef in qresult.fields], all_fields)
266

    
267
    # Unknown field
268
    result = _rapi_client.QueryFields(what, fields=["_unknown!"])
269
    qresult = objects.QueryFieldsResponse.FromDict(result)
270
    AssertEqual(len(qresult.fields), 1)
271
    AssertEqual(qresult.fields[0].name, "_unknown!")
272
    AssertEqual(qresult.fields[0].kind, constants.QFT_UNKNOWN)
273

    
274
    # Try once more, this time without the client
275
    _DoTests([
276
      ("/2/query/%s/fields" % what, None, "GET", None),
277
      ("/2/query/%s/fields?fields=name,name,%s" % (what, all_fields[0]),
278
       None, "GET", None),
279
      ])
280

    
281
    # Try missing query argument
282
    try:
283
      _DoTests([
284
        ("/2/query/%s" % what, None, "GET", None),
285
        ])
286
    except rapi.client.GanetiApiError, err:
287
      AssertEqual(err.code, 400)
288
    else:
289
      raise qa_error.Error("Request missing 'fields' parameter didn't fail")
290

    
291
    def _Check(exp_fields, data):
292
      qresult = objects.QueryResponse.FromDict(data)
293
      AssertEqual([fdef.name for fdef in qresult.fields], exp_fields)
294
      if not isinstance(qresult.data, list):
295
        raise qa_error.Error("Query did not return a list")
296

    
297
    _DoTests([
298
      # Specify fields in query
299
      ("/2/query/%s?fields=%s" % (what, ",".join(all_fields)),
300
       compat.partial(_Check, all_fields), "GET", None),
301

    
302
      ("/2/query/%s?fields=%s" % (what, namefield),
303
       compat.partial(_Check, [namefield]), "GET", None),
304

    
305
      # Note the spaces
306
      ("/2/query/%s?fields=%s,%%20%s%%09,%s%%20" %
307
       (what, namefield, namefield, namefield),
308
       compat.partial(_Check, [namefield] * 3), "GET", None),
309

    
310
      # PUT with fields in query
311
      ("/2/query/%s?fields=%s" % (what, namefield),
312
       compat.partial(_Check, [namefield]), "PUT", {}),
313

    
314
      # Fields in body
315
      ("/2/query/%s" % what, compat.partial(_Check, all_fields), "PUT", {
316
         "fields": all_fields,
317
         }),
318

    
319
      ("/2/query/%s" % what, compat.partial(_Check, [namefield] * 4), "PUT", {
320
         "fields": [namefield] * 4,
321
         }),
322
      ])
323

    
324
    def _CheckFilter():
325
      _DoTests([
326
        # With filter
327
        ("/2/query/%s" % what, compat.partial(_Check, all_fields), "PUT", {
328
           "fields": all_fields,
329
           "filter": [qlang.OP_TRUE, namefield],
330
           }),
331
        ])
332

    
333
    if what == constants.QR_LOCK:
334
      # Locks can't be filtered
335
      try:
336
        _CheckFilter()
337
      except rapi.client.GanetiApiError, err:
338
        AssertEqual(err.code, 500)
339
      else:
340
        raise qa_error.Error("Filtering locks didn't fail")
341
    else:
342
      _CheckFilter()
343

    
344
    if what == constants.QR_NODE:
345
      # Test with filter
346
      (nodes, ) = _DoTests(
347
        [("/2/query/%s" % what,
348
          compat.partial(_Check, ["name", "master"]), "PUT",
349
          {"fields": ["name", "master"],
350
           "filter": [qlang.OP_TRUE, "master"],
351
           })])
352
      qresult = objects.QueryResponse.FromDict(nodes)
353
      AssertEqual(qresult.data, [
354
        [[constants.RS_NORMAL, master_name], [constants.RS_NORMAL, True]],
355
        ])
356

    
357

    
358
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
359
def TestInstance(instance):
360
  """Testing getting instance(s) info via remote API.
361

362
  """
363
  def _VerifyInstance(data):
364
    for entry in INSTANCE_FIELDS:
365
      AssertIn(entry, data)
366

    
367
  def _VerifyInstancesList(data):
368
    for instance in data:
369
      for entry in LIST_FIELDS:
370
        AssertIn(entry, instance)
371

    
372
  def _VerifyInstancesBulk(data):
373
    for instance_data in data:
374
      _VerifyInstance(instance_data)
375

    
376
  _DoTests([
377
    ("/2/instances/%s" % instance["name"], _VerifyInstance, "GET", None),
378
    ("/2/instances", _VerifyInstancesList, "GET", None),
379
    ("/2/instances?bulk=1", _VerifyInstancesBulk, "GET", None),
380
    ("/2/instances/%s/activate-disks" % instance["name"],
381
     _VerifyReturnsJob, "PUT", None),
382
    ("/2/instances/%s/deactivate-disks" % instance["name"],
383
     _VerifyReturnsJob, "PUT", None),
384
    ])
385

    
386
  # Test OpBackupPrepare
387
  (job_id, ) = _DoTests([
388
    ("/2/instances/%s/prepare-export?mode=%s" %
389
     (instance["name"], constants.EXPORT_MODE_REMOTE),
390
     _VerifyReturnsJob, "PUT", None),
391
    ])
392

    
393
  result = _WaitForRapiJob(job_id)[0]
394
  AssertEqual(len(result["handshake"]), 3)
395
  AssertEqual(result["handshake"][0], constants.RIE_VERSION)
396
  AssertEqual(len(result["x509_key_name"]), 3)
397
  AssertIn("-----BEGIN CERTIFICATE-----", result["x509_ca"])
398

    
399

    
400
def TestNode(node):
401
  """Testing getting node(s) info via remote API.
402

403
  """
404
  def _VerifyNode(data):
405
    for entry in NODE_FIELDS:
406
      AssertIn(entry, data)
407

    
408
  def _VerifyNodesList(data):
409
    for node in data:
410
      for entry in LIST_FIELDS:
411
        AssertIn(entry, node)
412

    
413
  def _VerifyNodesBulk(data):
414
    for node_data in data:
415
      _VerifyNode(node_data)
416

    
417
  _DoTests([
418
    ("/2/nodes/%s" % node["primary"], _VerifyNode, "GET", None),
419
    ("/2/nodes", _VerifyNodesList, "GET", None),
420
    ("/2/nodes?bulk=1", _VerifyNodesBulk, "GET", None),
421
    ])
422

    
423

    
424
def _FilterTags(seq):
425
  """Removes unwanted tags from a sequence.
426

427
  """
428
  ignore_re = qa_config.get("ignore-tags-re", None)
429

    
430
  if ignore_re:
431
    return itertools.ifilterfalse(re.compile(ignore_re).match, seq)
432
  else:
433
    return seq
434

    
435

    
436
def TestTags(kind, name, tags):
437
  """Tests .../tags resources.
438

439
  """
440
  if kind == constants.TAG_CLUSTER:
441
    uri = "/2/tags"
442
  elif kind == constants.TAG_NODE:
443
    uri = "/2/nodes/%s/tags" % name
444
  elif kind == constants.TAG_INSTANCE:
445
    uri = "/2/instances/%s/tags" % name
446
  elif kind == constants.TAG_NODEGROUP:
447
    uri = "/2/groups/%s/tags" % name
448
  else:
449
    raise errors.ProgrammerError("Unknown tag kind")
450

    
451
  def _VerifyTags(data):
452
    AssertEqual(sorted(tags), sorted(_FilterTags(data)))
453

    
454
  queryargs = "&".join("tag=%s" % i for i in tags)
455

    
456
  # Add tags
457
  (job_id, ) = _DoTests([
458
    ("%s?%s" % (uri, queryargs), _VerifyReturnsJob, "PUT", None),
459
    ])
460
  _WaitForRapiJob(job_id)
461

    
462
  # Retrieve tags
463
  _DoTests([
464
    (uri, _VerifyTags, "GET", None),
465
    ])
466

    
467
  # Remove tags
468
  (job_id, ) = _DoTests([
469
    ("%s?%s" % (uri, queryargs), _VerifyReturnsJob, "DELETE", None),
470
    ])
471
  _WaitForRapiJob(job_id)
472

    
473

    
474
def _WaitForRapiJob(job_id):
475
  """Waits for a job to finish.
476

477
  """
478
  def _VerifyJob(data):
479
    AssertEqual(data["id"], job_id)
480
    for field in JOB_FIELDS:
481
      AssertIn(field, data)
482

    
483
  _DoTests([
484
    ("/2/jobs/%s" % job_id, _VerifyJob, "GET", None),
485
    ])
486

    
487
  return rapi.client_utils.PollJob(_rapi_client, job_id,
488
                                   cli.StdioJobPollReportCb())
489

    
490

    
491
def TestRapiNodeGroups():
492
  """Test several node group operations using RAPI.
493

494
  """
495
  groups = qa_config.get("groups", {})
496
  group1, group2, group3 = groups.get("inexistent-groups",
497
                                      ["group1", "group2", "group3"])[:3]
498

    
499
  # Create a group with no attributes
500
  body = {
501
    "name": group1,
502
    }
503

    
504
  (job_id, ) = _DoTests([
505
    ("/2/groups", _VerifyReturnsJob, "POST", body),
506
    ])
507

    
508
  _WaitForRapiJob(job_id)
509

    
510
  # Create a group specifying alloc_policy
511
  body = {
512
    "name": group2,
513
    "alloc_policy": constants.ALLOC_POLICY_UNALLOCABLE,
514
    }
515

    
516
  (job_id, ) = _DoTests([
517
    ("/2/groups", _VerifyReturnsJob, "POST", body),
518
    ])
519

    
520
  _WaitForRapiJob(job_id)
521

    
522
  # Modify alloc_policy
523
  body = {
524
    "alloc_policy": constants.ALLOC_POLICY_UNALLOCABLE,
525
    }
526

    
527
  (job_id, ) = _DoTests([
528
    ("/2/groups/%s/modify" % group1, _VerifyReturnsJob, "PUT", body),
529
    ])
530

    
531
  _WaitForRapiJob(job_id)
532

    
533
  # Rename a group
534
  body = {
535
    "new_name": group3,
536
    }
537

    
538
  (job_id, ) = _DoTests([
539
    ("/2/groups/%s/rename" % group2, _VerifyReturnsJob, "PUT", body),
540
    ])
541

    
542
  _WaitForRapiJob(job_id)
543

    
544
  # Delete groups
545
  for group in [group1, group3]:
546
    (job_id, ) = _DoTests([
547
      ("/2/groups/%s" % group, _VerifyReturnsJob, "DELETE", None),
548
      ])
549

    
550
    _WaitForRapiJob(job_id)
551

    
552

    
553
def TestRapiInstanceAdd(node, use_client):
554
  """Test adding a new instance via RAPI"""
555
  instance = qa_config.AcquireInstance()
556
  try:
557
    disk_sizes = [utils.ParseUnit(size) for size in qa_config.get("disk")]
558
    disks = [{"size": size} for size in disk_sizes]
559
    nic0_mac = qa_config.GetInstanceNicMac(instance,
560
                                           default=constants.VALUE_GENERATE)
561
    nics = [{
562
      constants.INIC_MAC: nic0_mac,
563
      }]
564

    
565
    beparams = {
566
      constants.BE_MAXMEM: utils.ParseUnit(qa_config.get(constants.BE_MAXMEM)),
567
      constants.BE_MINMEM: utils.ParseUnit(qa_config.get(constants.BE_MINMEM)),
568
      }
569

    
570
    if use_client:
571
      job_id = _rapi_client.CreateInstance(constants.INSTANCE_CREATE,
572
                                           instance["name"],
573
                                           constants.DT_PLAIN,
574
                                           disks, nics,
575
                                           os=qa_config.get("os"),
576
                                           pnode=node["primary"],
577
                                           beparams=beparams)
578
    else:
579
      body = {
580
        "__version__": 1,
581
        "mode": constants.INSTANCE_CREATE,
582
        "name": instance["name"],
583
        "os_type": qa_config.get("os"),
584
        "disk_template": constants.DT_PLAIN,
585
        "pnode": node["primary"],
586
        "beparams": beparams,
587
        "disks": disks,
588
        "nics": nics,
589
        }
590

    
591
      (job_id, ) = _DoTests([
592
        ("/2/instances", _VerifyReturnsJob, "POST", body),
593
        ])
594

    
595
    _WaitForRapiJob(job_id)
596

    
597
    return instance
598
  except:
599
    qa_config.ReleaseInstance(instance)
600
    raise
601

    
602

    
603
@InstanceCheck(None, INST_DOWN, FIRST_ARG)
604
def TestRapiInstanceRemove(instance, use_client):
605
  """Test removing instance via RAPI"""
606
  if use_client:
607
    job_id = _rapi_client.DeleteInstance(instance["name"])
608
  else:
609
    (job_id, ) = _DoTests([
610
      ("/2/instances/%s" % instance["name"], _VerifyReturnsJob, "DELETE", None),
611
      ])
612

    
613
  _WaitForRapiJob(job_id)
614

    
615
  qa_config.ReleaseInstance(instance)
616

    
617

    
618
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
619
def TestRapiInstanceMigrate(instance):
620
  """Test migrating instance via RAPI"""
621
  # Move to secondary node
622
  _WaitForRapiJob(_rapi_client.MigrateInstance(instance["name"]))
623
  qa_utils.RunInstanceCheck(instance, True)
624
  # And back to previous primary
625
  _WaitForRapiJob(_rapi_client.MigrateInstance(instance["name"]))
626

    
627

    
628
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
629
def TestRapiInstanceFailover(instance):
630
  """Test failing over instance via RAPI"""
631
  # Move to secondary node
632
  _WaitForRapiJob(_rapi_client.FailoverInstance(instance["name"]))
633
  qa_utils.RunInstanceCheck(instance, True)
634
  # And back to previous primary
635
  _WaitForRapiJob(_rapi_client.FailoverInstance(instance["name"]))
636

    
637

    
638
@InstanceCheck(INST_UP, INST_DOWN, FIRST_ARG)
639
def TestRapiInstanceShutdown(instance):
640
  """Test stopping an instance via RAPI"""
641
  _WaitForRapiJob(_rapi_client.ShutdownInstance(instance["name"]))
642

    
643

    
644
@InstanceCheck(INST_DOWN, INST_UP, FIRST_ARG)
645
def TestRapiInstanceStartup(instance):
646
  """Test starting an instance via RAPI"""
647
  _WaitForRapiJob(_rapi_client.StartupInstance(instance["name"]))
648

    
649

    
650
@InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
651
def TestRapiInstanceRenameAndBack(rename_source, rename_target):
652
  """Test renaming instance via RAPI
653

654
  This must leave the instance with the original name (in the
655
  non-failure case).
656

657
  """
658
  _WaitForRapiJob(_rapi_client.RenameInstance(rename_source, rename_target))
659
  qa_utils.RunInstanceCheck(rename_source, False)
660
  qa_utils.RunInstanceCheck(rename_target, False)
661
  _WaitForRapiJob(_rapi_client.RenameInstance(rename_target, rename_source))
662
  qa_utils.RunInstanceCheck(rename_target, False)
663

    
664

    
665
@InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
666
def TestRapiInstanceReinstall(instance):
667
  """Test reinstalling an instance via RAPI"""
668
  _WaitForRapiJob(_rapi_client.ReinstallInstance(instance["name"]))
669
  # By default, the instance is started again
670
  qa_utils.RunInstanceCheck(instance, True)
671

    
672
  # Reinstall again without starting
673
  _WaitForRapiJob(_rapi_client.ReinstallInstance(instance["name"],
674
                                                 no_startup=True))
675

    
676

    
677
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
678
def TestRapiInstanceReplaceDisks(instance):
679
  """Test replacing instance disks via RAPI"""
680
  fn = _rapi_client.ReplaceInstanceDisks
681
  _WaitForRapiJob(fn(instance["name"],
682
                     mode=constants.REPLACE_DISK_AUTO, disks=[]))
683
  _WaitForRapiJob(fn(instance["name"],
684
                     mode=constants.REPLACE_DISK_SEC, disks="0"))
685

    
686

    
687
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
688
def TestRapiInstanceModify(instance):
689
  """Test modifying instance via RAPI"""
690
  default_hv = qa_config.GetDefaultHypervisor()
691

    
692
  def _ModifyInstance(**kwargs):
693
    _WaitForRapiJob(_rapi_client.ModifyInstance(instance["name"], **kwargs))
694

    
695
  _ModifyInstance(beparams={
696
    constants.BE_VCPUS: 3,
697
    })
698

    
699
  _ModifyInstance(beparams={
700
    constants.BE_VCPUS: constants.VALUE_DEFAULT,
701
    })
702

    
703
  if default_hv == constants.HT_XEN_PVM:
704
    _ModifyInstance(hvparams={
705
      constants.HV_KERNEL_ARGS: "single",
706
      })
707
    _ModifyInstance(hvparams={
708
      constants.HV_KERNEL_ARGS: constants.VALUE_DEFAULT,
709
      })
710
  elif default_hv == constants.HT_XEN_HVM:
711
    _ModifyInstance(hvparams={
712
      constants.HV_BOOT_ORDER: "acn",
713
      })
714
    _ModifyInstance(hvparams={
715
      constants.HV_BOOT_ORDER: constants.VALUE_DEFAULT,
716
      })
717

    
718

    
719
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
720
def TestRapiInstanceConsole(instance):
721
  """Test getting instance console information via RAPI"""
722
  result = _rapi_client.GetInstanceConsole(instance["name"])
723
  console = objects.InstanceConsole.FromDict(result)
724
  AssertEqual(console.Validate(), True)
725
  AssertEqual(console.instance, qa_utils.ResolveInstanceName(instance["name"]))
726

    
727

    
728
@InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
729
def TestRapiStoppedInstanceConsole(instance):
730
  """Test getting stopped instance's console information via RAPI"""
731
  try:
732
    _rapi_client.GetInstanceConsole(instance["name"])
733
  except rapi.client.GanetiApiError, err:
734
    AssertEqual(err.code, 503)
735
  else:
736
    raise qa_error.Error("Getting console for stopped instance didn't"
737
                         " return HTTP 503")
738

    
739

    
740
def GetOperatingSystems():
741
  """Retrieves a list of all available operating systems.
742

743
  """
744
  return _rapi_client.GetOperatingSystems()
745

    
746

    
747
def TestInterClusterInstanceMove(src_instance, dest_instance,
748
                                 pnode, snode, tnode):
749
  """Test tools/move-instance"""
750
  master = qa_config.GetMasterNode()
751

    
752
  rapi_pw_file = tempfile.NamedTemporaryFile()
753
  rapi_pw_file.write(_rapi_password)
754
  rapi_pw_file.flush()
755

    
756
  # TODO: Run some instance tests before moving back
757

    
758
  if snode is None:
759
    # instance is not redundant, but we still need to pass a node
760
    # (which will be ignored)
761
    fsec = tnode
762
  else:
763
    fsec = snode
764
  # note: pnode:snode are the *current* nodes, so we move it first to
765
  # tnode:pnode, then back to pnode:snode
766
  for si, di, pn, sn in [(src_instance["name"], dest_instance["name"],
767
                          tnode["primary"], pnode["primary"]),
768
                         (dest_instance["name"], src_instance["name"],
769
                          pnode["primary"], fsec["primary"])]:
770
    cmd = [
771
      "../tools/move-instance",
772
      "--verbose",
773
      "--src-ca-file=%s" % _rapi_ca.name,
774
      "--src-username=%s" % _rapi_username,
775
      "--src-password-file=%s" % rapi_pw_file.name,
776
      "--dest-instance-name=%s" % di,
777
      "--dest-primary-node=%s" % pn,
778
      "--dest-secondary-node=%s" % sn,
779
      "--net=0:mac=%s" % constants.VALUE_GENERATE,
780
      master["primary"],
781
      master["primary"],
782
      si,
783
      ]
784

    
785
    qa_utils.RunInstanceCheck(di, False)
786
    AssertEqual(StartLocalCommand(cmd).wait(), 0)
787
    qa_utils.RunInstanceCheck(si, False)
788
    qa_utils.RunInstanceCheck(di, True)