LGTM, thanks
On Fri, Dec 20, 2013 at 1:11 PM, Hrvoje Ribicic <[email protected]> wrote: > The instance move workload present before this patch works on 2.11, but > fails on 2.6. The 2.11 workload will still be useful should any later > version of Ganeti use it as reference, but a 2.6 workload has to be > added to make the moves checked for compatibility. > > Signed-off-by: Hrvoje Ribicic <[email protected]> > --- > qa/rapi-workload.py | 242 > +++++++++++++++++++++++++++++++++++++++++----------- > 1 file changed, 190 insertions(+), 52 deletions(-) > > diff --git a/qa/rapi-workload.py b/qa/rapi-workload.py > index 3af166f..1a68734 100755 > --- a/qa/rapi-workload.py > +++ b/qa/rapi-workload.py > @@ -34,6 +34,7 @@ import ganeti.constants as constants > from ganeti.rapi.client import GanetiApiError, NODE_EVAC_PRI, > NODE_EVAC_SEC > > import qa_config > +import qa_error > import qa_node > import qa_rapi > > @@ -686,56 +687,205 @@ def TestInstanceMigrations(client, node_one, > node_two, node_three, > Finish(client, client.DeleteInstance, instance_name) > > > -def TestJobCancellation(client, node_one, node_two, instance_one, > instance_two): > - """ Test if jobs can be cancelled. > - > - @type node_one string > - @param node_one The name of a node in the cluster. > - @type node_two string > - @param node_two The name of a node in the cluster. > - @type instance_one string > - @param instance_one An available instance name. > - @type instance_two string > - @param instance_two An available instance name. > +def ExtractAllNicInformationPossible(nics, replace_macs=True): > + """ Extracts NIC information as a dictionary. > + > + @type nics list of tuples of varying structure > + @param nics The network interfaces, as received from the instance info > RAPI > + call. > + > + @rtype list of dict > + @return Dictionaries of NIC information. > + > + The NIC information is returned in a different format across versions, > and to > + try and see if the execution of commands is still compatible, this > function > + attempts to grab all the info that it can. > + > + """ > + > + desired_entries = [ > + constants.INIC_IP, > + constants.INIC_MAC, > + constants.INIC_MODE, > + constants.INIC_LINK, > + constants.INIC_VLAN, > + constants.INIC_NETWORK, > + constants.INIC_NAME, > + ] > + > + nic_dicts = [] > + for nic_index in range(len(nics)): > + nic_raw_data = nics[nic_index] > + > + # Fill dictionary with None-s as defaults > + nic_dict = dict([(key, None) for key in desired_entries]) > + > + try: > + # The 2.6 format > + ip, mac, mode, link = nic_raw_data > + except ValueError: > + # If there is yet another ValueError here, let it go through as it > is > + # legitimate - we are out of versions > + > + # The 2.11 format > + nic_name, _, ip, mac, mode, link, vlan, network, _ = nic_raw_data > + nic_dict[constants.INIC_VLAN] = vlan > + nic_dict[constants.INIC_NETWORK] = network > + nic_dict[constants.INIC_NAME] = nic_name > + > + # These attributes will be present in either version > + nic_dict[constants.INIC_IP] = ip > + nic_dict[constants.INIC_MAC] = mac > + nic_dict[constants.INIC_MODE] = mode > + nic_dict[constants.INIC_LINK] = link > + > + # Very simple mac generation, which should work as the setup cluster > should > + # have no mac prefix restrictions in the default network, and there > is a > + # hard and reasonable limit of only 8 NICs > + if replace_macs: > + nic_dict[constants.INIC_MAC] = "00:00:00:00:00:%02x" % nic_index > + > + nic_dicts.append(nic_dict) > + > + return nic_dicts > + > + > +def MoveInstance(client, src_instance, dst_instance, src_node, dst_node): > + """ Moves a single instance, compatible with 2.6. > + > + @rtype bool > + @return Whether the instance was moved successfully > > """ > + success, inst_info_all = Finish(client, client.GetInstanceInfo, > + src_instance.name, static=True) > + > + if not success or src_instance.name not in inst_info_all: > + raise Exception("Did not find the source instance information!") > + > + inst_info = inst_info_all[src_instance.name] > + > + # Try to extract NICs first, as this is the operation most likely to > fail > + try: > + nic_info = ExtractAllNicInformationPossible(inst_info["nics"]) > + except ValueError: > + # Without the NIC info, there is very little we can do > + return False > + > + NIC_COMPONENTS_26 = [ > + constants.INIC_IP, > + constants.INIC_MAC, > + constants.INIC_MODE, > + constants.INIC_LINK, > + ] > + > + nic_converter = lambda old: dict((k, old[k]) for k in NIC_COMPONENTS_26) > + nics = map(nic_converter, nic_info) > > - # Just in case, remove all previously present instances > - RemoveAllInstances(client) > + # Prepare the parameters > + disks = [] > + for idisk in inst_info["disks"]: > + odisk = { > + constants.IDISK_SIZE: idisk["size"], > + constants.IDISK_MODE: idisk["mode"], > + } > > - # Let us issue a job that is sure to both succeed and last for a while > - running_job = client.CreateInstance("create", instance_one, "drbd", > - [{"size": "5000"}], [{}], > - os="debian-image", pnode=node_one, > - snode=node_two) > + spindles = idisk.get("spindles") > + if spindles is not None: > + odisk[constants.IDISK_SPINDLES] = spindles > > - # And immediately afterwards, another very similar one > - job_to_cancel = client.CreateInstance("create", instance_two, "drbd", > - [{"size": "5000"}], [{}], > - os="debian-image", pnode=node_one, > - snode=node_two) > + # Disk name may be present, but must not be supplied in 2.6! > + disks.append(odisk) > > - # Try to cancel, which should fail as the job is already running > - success, msg = client.CancelJob(running_job) > - if success: > - print "Job succeeded: this should not have happened as it is running!" > - print "Message: %s" % msg > + # With all the parameters properly prepared, try the export > + success, exp_info = Finish(client, client.PrepareExport, > + src_instance.name, > constants.EXPORT_MODE_REMOTE) > > - success, msg = client.CancelJob(job_to_cancel) > if not success: > - print "Job failed: this was unexpected as it was not a dry run" > - print "Message: %s" % msg > + # The instance will still have to be deleted > + return False > > - # And wait for the proper job > - client.WaitForJobCompletion(running_job) > + success, _ = Finish(client, client.CreateInstance, > + constants.INSTANCE_REMOTE_IMPORT, dst_instance.name > , > + inst_info["disk_template"], disks, nics, > + os=inst_info["os"], > + pnode=dst_node.primary, > + snode=src_node.primary, # Ignored as no DRBD > + start=(inst_info["config_state"] == "up"), > + ip_check=False, > + iallocator=inst_info.get("iallocator", None), > + hypervisor=inst_info["hypervisor"], > + source_handshake=exp_info["handshake"], > + source_x509_ca=exp_info["x509_ca"], > + source_instance_name=inst_info["name"], > + beparams=inst_info["be_instance"], > + hvparams=inst_info["hv_instance"], > + osparams=inst_info["os_instance"]) > > - # Remove all the leftover instances, success or no success > - RemoveAllInstances(client) > + return success > + > + > +def CreateInstanceForMoveTest(client, node, instance): > + """ Creates a single shutdown instance to move about in tests. > + > + @type node C{_QaNode} > + @param node A node configuration object. > + @type instance C{_QaInstance} > + @param instance An instance configuration object. > + > + """ > + Finish(client, client.CreateInstance, > + "create", instance.name, "plain", [{"size": "2000"}], [{}], > + os="debian-image", pnode=node.primary) > + > + Finish(client, client.ShutdownInstance, > + instance.name, dry_run=False, no_remember=False) > + > + > +def Test26InstanceMove(client, node_one, node_two, instance_to_create, > + new_instance): > + """ Tests instance moves using commands that work in 2.6. > + > + """ > + > + # First create the instance to move > + CreateInstanceForMoveTest(client, node_one, instance_to_create) > + > + # The cleanup should be conditional on operation success > + if MoveInstance(client, instance_to_create, new_instance, node_one, > node_two): > + Finish(client, client.DeleteInstance, new_instance.name) > + else: > + Finish(client, client.DeleteInstance, instance_to_create.name) > + > + > +def Test211InstanceMove(client, node_one, node_two, instance_to_create, > + new_instance): > + """ Tests instance moves using the QA-provided move test. > + > + """ > + > + # First create the instance to move > + CreateInstanceForMoveTest(client, node_one, instance_to_create) > + > + instance_to_create.SetDiskTemplate("plain") > + > + try: > + qa_rapi.TestInterClusterInstanceMove(instance_to_create, new_instance, > + [node_one], node_two, > + perform_checks=False) > + except qa_error.Error: > + # A failure is sad, but requires no special actions to be undertaken > + pass > + > + # Try to delete the instance when done - either the move has failed, or > + # a double move was performed - the instance to delete is one and the > same > + Finish(client, client.DeleteInstance, instance_to_create.name) > > > def TestInstanceMoves(client, node_one, node_two, instance_to_create, > new_instance): > - """ Reuses a part of the QA to test instance moves. > + """ Performs two types of instance moves, one compatible with 2.6, the > other > + with 2.11. > > @type node_one C{_QaNode} > @param node_one A node configuration object. > @@ -748,22 +898,10 @@ def TestInstanceMoves(client, node_one, node_two, > instance_to_create, > > """ > > - # First create the instance to move > - Finish(client, client.CreateInstance, > - "create", instance_to_create.name, "plain", [{"size": "2000"}], > [{}], > - os="debian-image", pnode=node_one.primary) > - > - Finish(client, client.ShutdownInstance, > - instance_to_create.name, dry_run=False, no_remember=False) > - > - instance_to_create.SetDiskTemplate("plain") > - > - qa_rapi.TestInterClusterInstanceMove(instance_to_create, new_instance, > - [node_one], node_two, > - perform_checks=False) > - > - # Finally, cleanup > - RemoveAllInstances(client) > + Test26InstanceMove(client, node_one, node_two, instance_to_create, > + new_instance) > + Test211InstanceMove(client, node_one, node_two, instance_to_create, > + new_instance) > > > def Workload(client): > -- > 1.8.5.1 > > -- -- Helga Velroyen | Software Engineer | [email protected] | Google Germany GmbH Dienerstr. 12 80331 München Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg Geschäftsführer: Graham Law, Christine Elizabeth Flores
