def _SetupTempOs(node, dirname, variant, valid): """Creates a temporary OS definition on the given node. """ sq = utils.ShellQuoteArgs parts = [ sq(["rm", "-rf", dirname]), sq(["mkdir", "-p", dirname]), sq(["cd", dirname]), sq(["ln", "-fs", "/bin/true", "export"]), sq(["ln", "-fs", "/bin/true", "import"]), sq(["ln", "-fs", "/bin/true", "rename"]), sq(["ln", "-fs", "/bin/true", "verify"]), ] if valid: parts.append(sq(["ln", "-fs", "/bin/true", "create"])) parts.append( sq(["echo", str(constants.OS_API_V20)]) + " >ganeti_api_version") parts.append(sq(["echo", variant]) + " >variants.list") parts.append(sq(["echo", "funny this is funny"]) + " >parameters.list") cmd = " && ".join(parts) print qa_utils.FormatInfo( "Setting up %s with %s OS definition" % (node.primary, ["an invalid", "a valid"][int(valid)])) AssertCommand(cmd, node=node)
def TestInstanceGrowDisk(instance): """gnt-instance grow-disk""" if instance.disk_template == constants.DT_DISKLESS: print qa_utils.FormatInfo("Test not supported for diskless instances") return name = instance.name disks = qa_config.GetDiskOptions() all_size = [d.get("size") for d in disks] all_grow = [d.get("growth") for d in disks] if not all_grow: # missing disk sizes but instance grow disk has been enabled, # let's set fixed/nomimal growth all_grow = ["128M" for _ in all_size] for idx, (size, grow) in enumerate(zip(all_size, all_grow)): # succeed in grow by amount AssertCommand(["gnt-instance", "grow-disk", name, str(idx), grow]) # fail in grow to the old size AssertCommand( ["gnt-instance", "grow-disk", "--absolute", name, str(idx), size], fail=True) # succeed to grow to old size + 2 * growth int_size = utils.ParseUnit(size) int_grow = utils.ParseUnit(grow) AssertCommand([ "gnt-instance", "grow-disk", "--absolute", name, str(idx), str(int_size + 2 * int_grow) ])
def TestInstanceDeviceNames(instance): if instance.disk_template == constants.DT_DISKLESS: print qa_utils.FormatInfo("Test not supported for diskless instances") return name = instance.name for dev_type in ["disk", "net"]: if dev_type == "disk": options = ",size=512M" if qa_config.AreSpindlesSupported(): options += ",spindles=1" else: options = "" # succeed in adding a device named 'test_device' AssertCommand([ "gnt-instance", "modify", "--%s=-1:add,name=test_device%s" % (dev_type, options), name ]) # succeed in removing the 'test_device' AssertCommand([ "gnt-instance", "modify", "--%s=test_device:remove" % dev_type, name ]) # fail to add two devices with the same name AssertCommand([ "gnt-instance", "modify", "--%s=-1:add,name=test_device%s" % (dev_type, options), "--%s=-1:add,name=test_device%s" % (dev_type, options), name ], fail=True) # fail to add a device with invalid name AssertCommand([ "gnt-instance", "modify", "--%s=-1:add,name=2%s" % (dev_type, options), name ], fail=True) # Rename disks disks = qa_config.GetDiskOptions() disk_names = [d.get("name") for d in disks] for idx, disk_name in enumerate(disk_names): # Refer to disk by idx AssertCommand([ "gnt-instance", "modify", "--disk=%s:modify,name=renamed" % idx, name ]) # Refer to by name and rename to original name AssertCommand([ "gnt-instance", "modify", "--disk=renamed:modify,name=%s" % disk_name, name ]) if len(disks) >= 2: # fail in renaming to disks to the same name AssertCommand([ "gnt-instance", "modify", "--disk=0:modify,name=same_name", "--disk=1:modify,name=same_name", name ], fail=True)
def TestRapiInstanceReplaceDisks(instance): """Test replacing instance disks via RAPI""" if not IsDiskReplacingSupported(instance): print qa_utils.FormatInfo("Instance doesn't support disk replacing," " skipping test") return fn = _rapi_client.ReplaceInstanceDisks _WaitForRapiJob( fn(instance.name, mode=constants.REPLACE_DISK_AUTO, disks=[])) _WaitForRapiJob( fn(instance.name, mode=constants.REPLACE_DISK_SEC, disks="0"))
def TestRapiInstanceFailover(instance): """Test failing over instance via RAPI""" if not IsFailoverSupported(instance): print qa_utils.FormatInfo("Instance doesn't support failover, skipping" " test") return # Move to secondary node _WaitForRapiJob(_rapi_client.FailoverInstance(instance.name)) qa_utils.RunInstanceCheck(instance, True) # And back to previous primary _WaitForRapiJob(_rapi_client.FailoverInstance(instance.name))
def TestRapiInstanceMigrate(instance): """Test migrating instance via RAPI""" if not IsMigrationSupported(instance): print qa_utils.FormatInfo( "Instance doesn't support migration, skipping" " test") return # Move to secondary node _WaitForRapiJob(_rapi_client.MigrateInstance(instance.name)) qa_utils.RunInstanceCheck(instance, True) # And back to previous primary _WaitForRapiJob(_rapi_client.MigrateInstance(instance.name))
def TestRapiInstanceReinstall(instance): """Test reinstalling an instance via RAPI""" if instance.disk_template == constants.DT_DISKLESS: print qa_utils.FormatInfo("Test not supported for diskless instances") return _WaitForRapiJob(_rapi_client.ReinstallInstance(instance.name)) # By default, the instance is started again qa_utils.RunInstanceCheck(instance, True) # Reinstall again without starting _WaitForRapiJob( _rapi_client.ReinstallInstance(instance.name, no_startup=True))
def TestInstanceDataCensorship(instance, inodes): """Test protection of sensitive instance data.""" if instance.disk_template != constants.DT_DRBD8: print qa_utils.FormatInfo( "Only the DRBD secret is a sensitive parameter" " right now, skipping for non-DRBD instance.") return drbd_secret = _RetrieveSecret(instance, inodes[0]) job_id = _rapi_client.GetInstanceInfo(instance.name) if not _rapi_client.WaitForJobCompletion(job_id): raise qa_error.Error("Could not fetch instance info for instance %s" % instance.name) info_dict = _rapi_client.GetJobStatus(job_id) if drbd_secret in str(info_dict): print qa_utils.FormatInfo("DRBD secret: %s" % drbd_secret) print qa_utils.FormatInfo("Retrieved data\n%s" % str(info_dict)) raise qa_error.Error( "Found DRBD secret in contents of RAPI instance info" " call; see above.")
def TestInstanceReinstall(instance): """gnt-instance reinstall""" if instance.disk_template == constants.DT_DISKLESS: print qa_utils.FormatInfo("Test not supported for diskless instances") return AssertCommand(["gnt-instance", "reinstall", "-f", instance.name]) # Test with non-existant OS definition AssertCommand([ "gnt-instance", "reinstall", "-f", "--os-type=NonExistantOsForQa", instance.name ], fail=True)
def TestInstanceFailover(instance): """gnt-instance failover""" if not IsFailoverSupported(instance): print qa_utils.FormatInfo("Instance doesn't support failover, skipping" " test") return cmd = ["gnt-instance", "failover", "--force", instance.name] # failover ... AssertCommand(cmd) qa_utils.RunInstanceCheck(instance, True) # ... and back AssertCommand(cmd)
def TestInstanceConvertDiskToPlain(instance, inodes): """gnt-instance modify -t""" name = instance.name template = instance.disk_template if template != constants.DT_DRBD8: print qa_utils.FormatInfo( "Unsupported template %s, skipping conversion" " test" % template) return assert len(inodes) == 2 AssertCommand(["gnt-instance", "modify", "-t", constants.DT_PLAIN, name]) AssertCommand([ "gnt-instance", "modify", "-t", constants.DT_DRBD8, "-n", inodes[1].primary, name ])
def TestUpgrade(): """Test gnt-cluster upgrade. This tests the 'gnt-cluster upgrade' command by flipping between the current and a different version of Ganeti. To also recover subtile points in the configuration up/down grades, instances are left over both upgrades. """ this_version = qa_config.get("dir-version") other_version = qa_config.get("other-dir-version") if this_version is None or other_version is None: print qa_utils.FormatInfo("Test not run, as versions not specified") return inst_creates = [] upgrade_instances = qa_config.get("upgrade-instances", []) live_instances = [] for (test_name, templ, cf, n) in qa_instance.available_instance_tests: if (qa_config.TestEnabled(test_name) and qa_config.IsTemplateSupported(templ) and templ in upgrade_instances): inst_creates.append((cf, n)) for (cf, n) in inst_creates: nodes = qa_config.AcquireManyNodes(n) live_instances.append(cf(nodes)) AssertCommand(["gnt-cluster", "upgrade", "--to", other_version]) AssertCommand(["gnt-cluster", "verify"]) for instance in live_instances: qa_instance.TestInstanceRemove(instance) instance.Release() live_instances = [] for (cf, n) in inst_creates: nodes = qa_config.AcquireManyNodes(n) live_instances.append(cf(nodes)) AssertCommand(["gnt-cluster", "upgrade", "--to", this_version]) AssertCommand(["gnt-cluster", "verify"]) for instance in live_instances: qa_instance.TestInstanceRemove(instance) instance.Release()
def TestReplaceDisks(instance, curr_nodes, other_nodes): """gnt-instance replace-disks""" def buildcmd(args): cmd = ["gnt-instance", "replace-disks"] cmd.extend(args) cmd.append(instance.name) return cmd if not IsDiskReplacingSupported(instance): print qa_utils.FormatInfo("Instance doesn't support disk replacing," " skipping test") return # Currently all supported templates have one primary and one secondary node assert len(curr_nodes) == 2 snode = curr_nodes[1] assert len(other_nodes) == 1 othernode = other_nodes[0] options = qa_config.get("options", {}) use_ialloc = options.get("use-iallocators", True) for data in [ ["-p"], ["-s"], # A placeholder; the actual command choice depends on use_ialloc None, # Restore the original secondary ["--new-secondary=%s" % snode.primary], ]: if data is None: if use_ialloc: data = ["-I", constants.DEFAULT_IALLOCATOR_SHORTCUT] else: data = ["--new-secondary=%s" % othernode.primary] AssertCommand(buildcmd(data)) AssertCommand(buildcmd(["-a"])) AssertCommand(["gnt-instance", "stop", instance.name]) AssertCommand(buildcmd(["-a"]), fail=True) AssertCommand(["gnt-instance", "activate-disks", instance.name]) AssertCommand( ["gnt-instance", "activate-disks", "--wait-for-sync", instance.name]) AssertCommand(buildcmd(["-a"])) AssertCommand(["gnt-instance", "start", instance.name])
def TestInstanceModifyPrimaryAndBack(instance, currentnode, othernode): """gnt-instance modify --new-primary This will leave the instance on its original primary node, not other node. """ if instance.disk_template != constants.DT_FILE: print qa_utils.FormatInfo( "Test only supported for the file disk template") return cluster_name = qa_config.get("name") name = instance.name current = currentnode.primary other = othernode.primary filestorage = qa_config.get("file-storage-dir", pathutils.DEFAULT_FILE_STORAGE_DIR) disk = os.path.join(filestorage, name) AssertCommand(["gnt-instance", "modify", "--new-primary=%s" % other, name], fail=True) AssertCommand(["gnt-instance", "shutdown", name]) AssertCommand([ "scp", "-oGlobalKnownHostsFile=%s" % pathutils.SSH_KNOWN_HOSTS_FILE, "-oCheckHostIp=no", "-oStrictHostKeyChecking=yes", "-oHashKnownHosts=no", "-oHostKeyAlias=%s" % cluster_name, "-r", disk, "%s:%s" % (other, filestorage) ], node=current) AssertCommand(["gnt-instance", "modify", "--new-primary=%s" % other, name]) AssertCommand(["gnt-instance", "startup", name]) # and back AssertCommand(["gnt-instance", "shutdown", name]) AssertCommand(["rm", "-rf", disk], node=other) AssertCommand( ["gnt-instance", "modify", "--new-primary=%s" % current, name]) AssertCommand(["gnt-instance", "startup", name])
def TestInstanceModifyDisks(instance): """gnt-instance modify --disk""" if not IsDiskSupported(instance): print qa_utils.FormatInfo( "Instance doesn't support disks, skipping test") return disk_conf = qa_config.GetDiskOptions()[-1] size = disk_conf.get("size") name = instance.name build_cmd = lambda arg: ["gnt-instance", "modify", "--disk", arg, name] if qa_config.AreSpindlesSupported(): spindles = disk_conf.get("spindles") spindles_supported = True else: # Any number is good for spindles in this case spindles = 1 spindles_supported = False AssertCommand(build_cmd("add:size=%s,spindles=%s" % (size, spindles)), fail=not spindles_supported) AssertCommand(build_cmd("add:size=%s" % size), fail=spindles_supported) # Exactly one of the above commands has succeded, so we need one remove AssertCommand(build_cmd("remove"))
def TestInstanceMigrate(instance, toggle_always_failover=True): """gnt-instance migrate""" if not IsMigrationSupported(instance): print qa_utils.FormatInfo( "Instance doesn't support migration, skipping" " test") return cmd = ["gnt-instance", "migrate", "--force", instance.name] af_par = constants.BE_ALWAYS_FAILOVER af_field = "be/" + constants.BE_ALWAYS_FAILOVER af_init_val = _GetBoolInstanceField(instance.name, af_field) # migrate ... AssertCommand(cmd) # TODO: Verify the choice between failover and migration qa_utils.RunInstanceCheck(instance, True) # ... and back (possibly with always_failover toggled) if toggle_always_failover: AssertCommand([ "gnt-instance", "modify", "-B", ("%s=%s" % (af_par, not af_init_val)), instance.name ]) AssertCommand(cmd) # TODO: Verify the choice between failover and migration qa_utils.RunInstanceCheck(instance, True) if toggle_always_failover: AssertCommand([ "gnt-instance", "modify", "-B", ("%s=%s" % (af_par, af_init_val)), instance.name ]) # TODO: Split into multiple tests AssertCommand(["gnt-instance", "shutdown", instance.name]) qa_utils.RunInstanceCheck(instance, False) AssertCommand(cmd, fail=True) AssertCommand([ "gnt-instance", "migrate", "--force", "--allow-failover", instance.name ]) AssertCommand(["gnt-instance", "start", instance.name]) AssertCommand(cmd) # @InstanceCheck enforces the check that the instance is running qa_utils.RunInstanceCheck(instance, True) AssertCommand([ "gnt-instance", "modify", "-B", ("%s=%s" % (constants.BE_ALWAYS_FAILOVER, constants.VALUE_TRUE)), instance.name ]) AssertCommand(cmd) qa_utils.RunInstanceCheck(instance, True) # TODO: Verify that a failover has been done instead of a migration # TODO: Verify whether the default value is restored here (not hardcoded) AssertCommand([ "gnt-instance", "modify", "-B", ("%s=%s" % (constants.BE_ALWAYS_FAILOVER, constants.VALUE_FALSE)), instance.name ]) AssertCommand(cmd) qa_utils.RunInstanceCheck(instance, True)