4 # Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
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.
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.
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
22 """Remote API QA tests.
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
42 import ganeti.rapi.client # pylint: disable=W0611
43 import ganeti.rapi.client_utils
49 from qa_instance import IsFailoverSupported
50 from qa_instance import IsMigrationSupported
51 from qa_instance import IsDiskReplacingSupported
52 from qa_utils import (AssertEqual, AssertIn, AssertMatch, StartLocalCommand)
53 from qa_utils import InstanceCheck, INST_DOWN, INST_UP, FIRST_ARG
62 def Setup(username, password):
63 """Configures the RAPI client.
66 # pylint: disable=W0603
73 _rapi_username = username
74 _rapi_password = password
76 master = qa_config.GetMasterNode()
78 # Load RAPI certificate from master node
79 cmd = ["cat", qa_utils.MakeNodePath(master, pathutils.RAPI_CERT_FILE)]
81 # Write to temporary file
82 _rapi_ca = tempfile.NamedTemporaryFile()
83 _rapi_ca.write(qa_utils.GetCommandOutput(master.primary,
84 utils.ShellQuoteArgs(cmd)))
87 port = qa_config.get("rapi-port", default=constants.DEFAULT_RAPI_PORT)
88 cfg_curl = rapi.client.GenericCurlConfig(cafile=_rapi_ca.name,
91 if qa_config.UseVirtualCluster():
92 # TODO: Implement full support for RAPI on virtual clusters
93 print qa_utils.FormatWarning("RAPI tests are not yet supported on"
94 " virtual clusters and will be disabled")
96 assert _rapi_client is None
98 _rapi_client = rapi.client.GanetiRapiClient(master.primary, port=port,
101 curl_config_fn=cfg_curl)
103 print "RAPI protocol version: %s" % _rapi_client.GetVersion()
106 INSTANCE_FIELDS = ("name", "os", "pnode", "snodes",
108 "disk_template", "disk.sizes", "disk.spindles",
109 "nic.ips", "nic.macs", "nic.modes", "nic.links",
110 "beparams", "hvparams",
111 "oper_state", "oper_ram", "oper_vcpus", "status", "tags")
113 NODE_FIELDS = ("name", "dtotal", "dfree", "sptotal", "spfree",
114 "mtotal", "mnode", "mfree",
115 "pinst_cnt", "sinst_cnt", "tags")
117 GROUP_FIELDS = compat.UniqueFrozenset([
120 "node_cnt", "node_list",
123 JOB_FIELDS = compat.UniqueFrozenset([
124 "id", "ops", "status", "summary",
125 "opstatus", "opresult", "oplog",
126 "received_ts", "start_ts", "end_ts",
129 LIST_FIELDS = ("id", "uri")
133 """Return whether remote API tests should be run.
136 # TODO: Implement RAPI tests for virtual clusters
137 return (qa_config.TestEnabled("rapi") and
138 not qa_config.UseVirtualCluster())
142 # pylint: disable=W0212
143 # due to _SendRequest usage
146 for uri, verify, method, body in uris:
147 assert uri.startswith("/")
149 print "%s %s" % (method, uri)
150 data = _rapi_client._SendRequest(method, uri, None, body)
152 if verify is not None:
156 AssertEqual(data, verify)
163 def _VerifyReturnsJob(data):
164 if not isinstance(data, int):
165 AssertMatch(data, r"^\d+$")
169 """Testing remote API version.
173 ("/version", constants.RAPI_VERSION, "GET", None),
177 def TestEmptyCluster():
178 """Testing remote API on an empty cluster.
181 master = qa_config.GetMasterNode()
182 master_full = qa_utils.ResolveNodeName(master)
184 def _VerifyInfo(data):
185 AssertIn("name", data)
186 AssertIn("master", data)
187 AssertEqual(data["master"], master_full)
189 def _VerifyNodes(data):
192 "uri": "/2/nodes/%s" % master_full,
194 AssertIn(master_entry, data)
196 def _VerifyNodesBulk(data):
198 for entry in NODE_FIELDS:
199 AssertIn(entry, node)
201 def _VerifyGroups(data):
203 "name": constants.INITIAL_NODE_GROUP_NAME,
204 "uri": "/2/groups/" + constants.INITIAL_NODE_GROUP_NAME,
206 AssertIn(default_group, data)
208 def _VerifyGroupsBulk(data):
210 for field in GROUP_FIELDS:
211 AssertIn(field, group)
214 ("/", None, "GET", None),
215 ("/2/info", _VerifyInfo, "GET", None),
216 ("/2/tags", None, "GET", None),
217 ("/2/nodes", _VerifyNodes, "GET", None),
218 ("/2/nodes?bulk=1", _VerifyNodesBulk, "GET", None),
219 ("/2/groups", _VerifyGroups, "GET", None),
220 ("/2/groups?bulk=1", _VerifyGroupsBulk, "GET", None),
221 ("/2/instances", [], "GET", None),
222 ("/2/instances?bulk=1", [], "GET", None),
223 ("/2/os", None, "GET", None),
226 # Test HTTP Not Found
227 for method in ["GET", "PUT", "POST", "DELETE"]:
229 _DoTests([("/99/resource/not/here/99", None, method, None)])
230 except rapi.client.GanetiApiError, err:
231 AssertEqual(err.code, 404)
233 raise qa_error.Error("Non-existent resource didn't return HTTP 404")
235 # Test HTTP Not Implemented
236 for method in ["PUT", "POST", "DELETE"]:
238 _DoTests([("/version", None, method, None)])
239 except rapi.client.GanetiApiError, err:
240 AssertEqual(err.code, 501)
242 raise qa_error.Error("Non-implemented method didn't fail")
246 """Testing resource queries via remote API.
249 # FIXME: the tests are failing if no LVM is enabled, investigate
250 # if it is a bug in the QA or in the code
251 if not qa_config.IsStorageTypeSupported(constants.ST_LVM_VG):
254 master_name = qa_utils.ResolveNodeName(qa_config.GetMasterNode())
255 rnd = random.Random(7818)
257 for what in constants.QR_VIA_RAPI:
258 if what == constants.QR_JOB:
260 elif what == constants.QR_EXPORT:
265 all_fields = query.ALL_FIELDS[what].keys()
266 rnd.shuffle(all_fields)
268 # No fields, should return everything
269 result = _rapi_client.QueryFields(what)
270 qresult = objects.QueryFieldsResponse.FromDict(result)
271 AssertEqual(len(qresult.fields), len(all_fields))
274 result = _rapi_client.QueryFields(what, fields=[namefield])
275 qresult = objects.QueryFieldsResponse.FromDict(result)
276 AssertEqual(len(qresult.fields), 1)
278 # Specify all fields, order must be correct
279 result = _rapi_client.QueryFields(what, fields=all_fields)
280 qresult = objects.QueryFieldsResponse.FromDict(result)
281 AssertEqual(len(qresult.fields), len(all_fields))
282 AssertEqual([fdef.name for fdef in qresult.fields], all_fields)
285 result = _rapi_client.QueryFields(what, fields=["_unknown!"])
286 qresult = objects.QueryFieldsResponse.FromDict(result)
287 AssertEqual(len(qresult.fields), 1)
288 AssertEqual(qresult.fields[0].name, "_unknown!")
289 AssertEqual(qresult.fields[0].kind, constants.QFT_UNKNOWN)
291 # Try once more, this time without the client
293 ("/2/query/%s/fields" % what, None, "GET", None),
294 ("/2/query/%s/fields?fields=name,name,%s" % (what, all_fields[0]),
298 # Try missing query argument
301 ("/2/query/%s" % what, None, "GET", None),
303 except rapi.client.GanetiApiError, err:
304 AssertEqual(err.code, 400)
306 raise qa_error.Error("Request missing 'fields' parameter didn't fail")
308 def _Check(exp_fields, data):
309 qresult = objects.QueryResponse.FromDict(data)
310 AssertEqual([fdef.name for fdef in qresult.fields], exp_fields)
311 if not isinstance(qresult.data, list):
312 raise qa_error.Error("Query did not return a list")
315 # Specify fields in query
316 ("/2/query/%s?fields=%s" % (what, ",".join(all_fields)),
317 compat.partial(_Check, all_fields), "GET", None),
319 ("/2/query/%s?fields=%s" % (what, namefield),
320 compat.partial(_Check, [namefield]), "GET", None),
323 ("/2/query/%s?fields=%s,%%20%s%%09,%s%%20" %
324 (what, namefield, namefield, namefield),
325 compat.partial(_Check, [namefield] * 3), "GET", None),
327 # PUT with fields in query
328 ("/2/query/%s?fields=%s" % (what, namefield),
329 compat.partial(_Check, [namefield]), "PUT", {}),
331 ("/2/query/%s" % what, compat.partial(_Check, [namefield] * 4), "PUT", {
332 "fields": [namefield] * 4,
335 ("/2/query/%s" % what, compat.partial(_Check, all_fields), "PUT", {
336 "fields": all_fields,
339 ("/2/query/%s" % what, compat.partial(_Check, [namefield] * 4), "PUT", {
340 "fields": [namefield] * 4
346 ("/2/query/%s" % what, compat.partial(_Check, all_fields), "PUT", {
347 "fields": all_fields,
348 "filter": [qlang.OP_TRUE, namefield],
352 if what == constants.QR_LOCK:
353 # Locks can't be filtered
356 except rapi.client.GanetiApiError, err:
357 AssertEqual(err.code, 500)
359 raise qa_error.Error("Filtering locks didn't fail")
363 if what == constants.QR_NODE:
365 (nodes, ) = _DoTests(
366 [("/2/query/%s" % what,
367 compat.partial(_Check, ["name", "master"]), "PUT",
368 {"fields": ["name", "master"],
369 "filter": [qlang.OP_TRUE, "master"],
371 qresult = objects.QueryResponse.FromDict(nodes)
372 AssertEqual(qresult.data, [
373 [[constants.RS_NORMAL, master_name], [constants.RS_NORMAL, True]],
377 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
378 def TestInstance(instance):
379 """Testing getting instance(s) info via remote API.
382 def _VerifyInstance(data):
383 for entry in INSTANCE_FIELDS:
384 AssertIn(entry, data)
386 def _VerifyInstancesList(data):
387 for instance in data:
388 for entry in LIST_FIELDS:
389 AssertIn(entry, instance)
391 def _VerifyInstancesBulk(data):
392 for instance_data in data:
393 _VerifyInstance(instance_data)
396 ("/2/instances/%s" % instance.name, _VerifyInstance, "GET", None),
397 ("/2/instances", _VerifyInstancesList, "GET", None),
398 ("/2/instances?bulk=1", _VerifyInstancesBulk, "GET", None),
399 ("/2/instances/%s/activate-disks" % instance.name,
400 _VerifyReturnsJob, "PUT", None),
401 ("/2/instances/%s/deactivate-disks" % instance.name,
402 _VerifyReturnsJob, "PUT", None),
405 # Test OpBackupPrepare
406 (job_id, ) = _DoTests([
407 ("/2/instances/%s/prepare-export?mode=%s" %
408 (instance.name, constants.EXPORT_MODE_REMOTE),
409 _VerifyReturnsJob, "PUT", None),
412 result = _WaitForRapiJob(job_id)[0]
413 AssertEqual(len(result["handshake"]), 3)
414 AssertEqual(result["handshake"][0], constants.RIE_VERSION)
415 AssertEqual(len(result["x509_key_name"]), 3)
416 AssertIn("-----BEGIN CERTIFICATE-----", result["x509_ca"])
420 """Testing getting node(s) info via remote API.
423 def _VerifyNode(data):
424 for entry in NODE_FIELDS:
425 AssertIn(entry, data)
427 def _VerifyNodesList(data):
429 for entry in LIST_FIELDS:
430 AssertIn(entry, node)
432 def _VerifyNodesBulk(data):
433 for node_data in data:
434 _VerifyNode(node_data)
437 ("/2/nodes/%s" % node.primary, _VerifyNode, "GET", None),
438 ("/2/nodes", _VerifyNodesList, "GET", None),
439 ("/2/nodes?bulk=1", _VerifyNodesBulk, "GET", None),
443 def _FilterTags(seq):
444 """Removes unwanted tags from a sequence.
447 ignore_re = qa_config.get("ignore-tags-re", None)
450 return itertools.ifilterfalse(re.compile(ignore_re).match, seq)
455 def TestTags(kind, name, tags):
456 """Tests .../tags resources.
459 if kind == constants.TAG_CLUSTER:
461 elif kind == constants.TAG_NODE:
462 uri = "/2/nodes/%s/tags" % name
463 elif kind == constants.TAG_INSTANCE:
464 uri = "/2/instances/%s/tags" % name
465 elif kind == constants.TAG_NODEGROUP:
466 uri = "/2/groups/%s/tags" % name
467 elif kind == constants.TAG_NETWORK:
468 uri = "/2/networks/%s/tags" % name
470 raise errors.ProgrammerError("Unknown tag kind")
472 def _VerifyTags(data):
473 AssertEqual(sorted(tags), sorted(_FilterTags(data)))
475 queryargs = "&".join("tag=%s" % i for i in tags)
478 (job_id, ) = _DoTests([
479 ("%s?%s" % (uri, queryargs), _VerifyReturnsJob, "PUT", None),
481 _WaitForRapiJob(job_id)
485 (uri, _VerifyTags, "GET", None),
489 (job_id, ) = _DoTests([
490 ("%s?%s" % (uri, queryargs), _VerifyReturnsJob, "DELETE", None),
492 _WaitForRapiJob(job_id)
495 def _WaitForRapiJob(job_id):
496 """Waits for a job to finish.
499 def _VerifyJob(data):
500 AssertEqual(data["id"], job_id)
501 for field in JOB_FIELDS:
502 AssertIn(field, data)
505 ("/2/jobs/%s" % job_id, _VerifyJob, "GET", None),
508 return rapi.client_utils.PollJob(_rapi_client, job_id,
509 cli.StdioJobPollReportCb())
512 def TestRapiNodeGroups():
513 """Test several node group operations using RAPI.
516 (group1, group2, group3) = qa_utils.GetNonexistentGroups(3)
518 # Create a group with no attributes
523 (job_id, ) = _DoTests([
524 ("/2/groups", _VerifyReturnsJob, "POST", body),
527 _WaitForRapiJob(job_id)
529 # Create a group specifying alloc_policy
532 "alloc_policy": constants.ALLOC_POLICY_UNALLOCABLE,
535 (job_id, ) = _DoTests([
536 ("/2/groups", _VerifyReturnsJob, "POST", body),
539 _WaitForRapiJob(job_id)
541 # Modify alloc_policy
543 "alloc_policy": constants.ALLOC_POLICY_UNALLOCABLE,
546 (job_id, ) = _DoTests([
547 ("/2/groups/%s/modify" % group1, _VerifyReturnsJob, "PUT", body),
550 _WaitForRapiJob(job_id)
557 (job_id, ) = _DoTests([
558 ("/2/groups/%s/rename" % group2, _VerifyReturnsJob, "PUT", body),
561 _WaitForRapiJob(job_id)
564 for group in [group1, group3]:
565 (job_id, ) = _DoTests([
566 ("/2/groups/%s" % group, _VerifyReturnsJob, "DELETE", None),
569 _WaitForRapiJob(job_id)
572 def TestRapiInstanceAdd(node, use_client):
573 """Test adding a new instance via RAPI"""
574 if not qa_config.IsTemplateSupported(constants.DT_PLAIN):
576 instance = qa_config.AcquireInstance()
577 instance.SetDiskTemplate(constants.DT_PLAIN)
579 disks = [{"size": utils.ParseUnit(d.get("size")),
580 "name": str(d.get("name"))}
581 for d in qa_config.GetDiskOptions()]
582 nic0_mac = instance.GetNicMacAddr(0, constants.VALUE_GENERATE)
584 constants.INIC_MAC: nic0_mac,
588 constants.BE_MAXMEM: utils.ParseUnit(qa_config.get(constants.BE_MAXMEM)),
589 constants.BE_MINMEM: utils.ParseUnit(qa_config.get(constants.BE_MINMEM)),
593 job_id = _rapi_client.CreateInstance(constants.INSTANCE_CREATE,
597 os=qa_config.get("os"),
603 "mode": constants.INSTANCE_CREATE,
604 "name": instance.name,
605 "os_type": qa_config.get("os"),
606 "disk_template": constants.DT_PLAIN,
607 "pnode": node.primary,
608 "beparams": beparams,
613 (job_id, ) = _DoTests([
614 ("/2/instances", _VerifyReturnsJob, "POST", body),
617 _WaitForRapiJob(job_id)
625 @InstanceCheck(None, INST_DOWN, FIRST_ARG)
626 def TestRapiInstanceRemove(instance, use_client):
627 """Test removing instance via RAPI"""
628 # FIXME: this does not work if LVM is not enabled. Find out if this is a bug
629 # in RAPI or in the test
630 if not qa_config.IsStorageTypeSupported(constants.ST_LVM_VG):
634 job_id = _rapi_client.DeleteInstance(instance.name)
636 (job_id, ) = _DoTests([
637 ("/2/instances/%s" % instance.name, _VerifyReturnsJob, "DELETE", None),
640 _WaitForRapiJob(job_id)
643 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
644 def TestRapiInstanceMigrate(instance):
645 """Test migrating instance via RAPI"""
646 if not IsMigrationSupported(instance):
647 print qa_utils.FormatInfo("Instance doesn't support migration, skipping"
650 # Move to secondary node
651 _WaitForRapiJob(_rapi_client.MigrateInstance(instance.name))
652 qa_utils.RunInstanceCheck(instance, True)
653 # And back to previous primary
654 _WaitForRapiJob(_rapi_client.MigrateInstance(instance.name))
657 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
658 def TestRapiInstanceFailover(instance):
659 """Test failing over instance via RAPI"""
660 if not IsFailoverSupported(instance):
661 print qa_utils.FormatInfo("Instance doesn't support failover, skipping"
664 # Move to secondary node
665 _WaitForRapiJob(_rapi_client.FailoverInstance(instance.name))
666 qa_utils.RunInstanceCheck(instance, True)
667 # And back to previous primary
668 _WaitForRapiJob(_rapi_client.FailoverInstance(instance.name))
671 @InstanceCheck(INST_UP, INST_DOWN, FIRST_ARG)
672 def TestRapiInstanceShutdown(instance):
673 """Test stopping an instance via RAPI"""
674 _WaitForRapiJob(_rapi_client.ShutdownInstance(instance.name))
677 @InstanceCheck(INST_DOWN, INST_UP, FIRST_ARG)
678 def TestRapiInstanceStartup(instance):
679 """Test starting an instance via RAPI"""
680 _WaitForRapiJob(_rapi_client.StartupInstance(instance.name))
683 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
684 def TestRapiInstanceRenameAndBack(rename_source, rename_target):
685 """Test renaming instance via RAPI
687 This must leave the instance with the original name (in the
691 _WaitForRapiJob(_rapi_client.RenameInstance(rename_source, rename_target))
692 qa_utils.RunInstanceCheck(rename_source, False)
693 qa_utils.RunInstanceCheck(rename_target, False)
694 _WaitForRapiJob(_rapi_client.RenameInstance(rename_target, rename_source))
695 qa_utils.RunInstanceCheck(rename_target, False)
698 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
699 def TestRapiInstanceReinstall(instance):
700 """Test reinstalling an instance via RAPI"""
701 if instance.disk_template == constants.DT_DISKLESS:
702 print qa_utils.FormatInfo("Test not supported for diskless instances")
705 _WaitForRapiJob(_rapi_client.ReinstallInstance(instance.name))
706 # By default, the instance is started again
707 qa_utils.RunInstanceCheck(instance, True)
709 # Reinstall again without starting
710 _WaitForRapiJob(_rapi_client.ReinstallInstance(instance.name,
714 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
715 def TestRapiInstanceReplaceDisks(instance):
716 """Test replacing instance disks via RAPI"""
717 if not IsDiskReplacingSupported(instance):
718 print qa_utils.FormatInfo("Instance doesn't support disk replacing,"
721 fn = _rapi_client.ReplaceInstanceDisks
722 _WaitForRapiJob(fn(instance.name,
723 mode=constants.REPLACE_DISK_AUTO, disks=[]))
724 _WaitForRapiJob(fn(instance.name,
725 mode=constants.REPLACE_DISK_SEC, disks="0"))
728 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
729 def TestRapiInstanceModify(instance):
730 """Test modifying instance via RAPI"""
731 default_hv = qa_config.GetDefaultHypervisor()
733 def _ModifyInstance(**kwargs):
734 _WaitForRapiJob(_rapi_client.ModifyInstance(instance.name, **kwargs))
736 _ModifyInstance(beparams={
737 constants.BE_VCPUS: 3,
740 _ModifyInstance(beparams={
741 constants.BE_VCPUS: constants.VALUE_DEFAULT,
744 if default_hv == constants.HT_XEN_PVM:
745 _ModifyInstance(hvparams={
746 constants.HV_KERNEL_ARGS: "single",
748 _ModifyInstance(hvparams={
749 constants.HV_KERNEL_ARGS: constants.VALUE_DEFAULT,
751 elif default_hv == constants.HT_XEN_HVM:
752 _ModifyInstance(hvparams={
753 constants.HV_BOOT_ORDER: "acn",
755 _ModifyInstance(hvparams={
756 constants.HV_BOOT_ORDER: constants.VALUE_DEFAULT,
760 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
761 def TestRapiInstanceConsole(instance):
762 """Test getting instance console information via RAPI"""
763 result = _rapi_client.GetInstanceConsole(instance.name)
764 console = objects.InstanceConsole.FromDict(result)
765 AssertEqual(console.Validate(), True)
766 AssertEqual(console.instance, qa_utils.ResolveInstanceName(instance.name))
769 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
770 def TestRapiStoppedInstanceConsole(instance):
771 """Test getting stopped instance's console information via RAPI"""
773 _rapi_client.GetInstanceConsole(instance.name)
774 except rapi.client.GanetiApiError, err:
775 AssertEqual(err.code, 503)
777 raise qa_error.Error("Getting console for stopped instance didn't"
781 def GetOperatingSystems():
782 """Retrieves a list of all available operating systems.
785 return _rapi_client.GetOperatingSystems()
788 def TestInterClusterInstanceMove(src_instance, dest_instance,
790 """Test tools/move-instance"""
791 master = qa_config.GetMasterNode()
793 rapi_pw_file = tempfile.NamedTemporaryFile()
794 rapi_pw_file.write(_rapi_password)
797 dest_instance.SetDiskTemplate(src_instance.disk_template)
799 # TODO: Run some instance tests before moving back
802 # No disk template currently requires more than 1 secondary node. If this
803 # changes, either this test must be skipped or the script must be updated.
804 assert len(inodes) == 2
807 # instance is not redundant, but we still need to pass a node
808 # (which will be ignored)
811 # note: pnode:snode are the *current* nodes, so we move it first to
812 # tnode:pnode, then back to pnode:snode
813 for si, di, pn, sn in [(src_instance.name, dest_instance.name,
814 tnode.primary, pnode.primary),
815 (dest_instance.name, src_instance.name,
816 pnode.primary, snode.primary)]:
818 "../tools/move-instance",
820 "--src-ca-file=%s" % _rapi_ca.name,
821 "--src-username=%s" % _rapi_username,
822 "--src-password-file=%s" % rapi_pw_file.name,
823 "--dest-instance-name=%s" % di,
824 "--dest-primary-node=%s" % pn,
825 "--dest-secondary-node=%s" % sn,
826 "--net=0:mac=%s" % constants.VALUE_GENERATE,
832 qa_utils.RunInstanceCheck(di, False)
833 AssertEqual(StartLocalCommand(cmd).wait(), 0)
834 qa_utils.RunInstanceCheck(si, False)
835 qa_utils.RunInstanceCheck(di, True)