def _TestGroupModifyIPolicy(groupname): _TestGroupModifyISpecs(groupname) # We assume that the default ipolicy holds (old_policy, old_specs) = _GetGroupIPolicy(groupname) for (par, setval, iname, expval) in [ ("vcpu-ratio", 1.5, None, 1.5), ("spindle-ratio", 1.5, None, 1.5), ("disk-templates", constants.DT_PLAIN, "allowed disk templates", constants.DT_PLAIN) ]: if not iname: iname = par build_cmdline = lambda val: ["gnt-group", "modify", "--ipolicy-" + par, str(val), groupname] AssertCommand(build_cmdline(setval)) (new_policy, new_specs) = _GetGroupIPolicy(groupname) AssertEqual(new_specs, old_specs) for (p, val) in new_policy.items(): if p == iname: AssertEqual(val, expval) else: AssertEqual(val, old_policy[p]) AssertCommand(build_cmdline("default")) (new_policy, new_specs) = _GetGroupIPolicy(groupname) AssertEqual(new_specs, old_specs) AssertEqual(new_policy, old_policy)
def _TestGroupModifyISpecs(groupname): # This test is built on the assumption that the default ipolicy holds for # the node group under test old_values = _GetGroupIPolicy(groupname) samevals = dict((p, 4) for p in constants.ISPECS_PARAMETERS) base_specs = { constants.ISPECS_MINMAX: [{ constants.ISPECS_MIN: samevals, constants.ISPECS_MAX: samevals, }], } mod_values = _TestGroupSetISpecs(groupname, new_specs=base_specs, old_values=old_values) for par in constants.ISPECS_PARAMETERS: # First make sure that the test works with good values good_specs = { constants.ISPECS_MINMAX: [{ constants.ISPECS_MIN: {par: 8}, constants.ISPECS_MAX: {par: 8}, }], } mod_values = _TestGroupSetISpecs(groupname, diff_specs=good_specs, old_values=mod_values) bad_specs = { constants.ISPECS_MINMAX: [{ constants.ISPECS_MIN: {par: 8}, constants.ISPECS_MAX: {par: 4}, }], } _TestGroupSetISpecs(groupname, diff_specs=bad_specs, fail=True, old_values=mod_values) AssertCommand(["gnt-group", "modify", "--ipolicy-bounds-specs", "default", groupname]) AssertEqual(_GetGroupIPolicy(groupname), old_values) # Get the ipolicy command (from the cluster config) mnode = qa_config.GetMasterNode() addcmd = GetCommandOutput(mnode.primary, utils.ShellQuoteArgs([ "gnt-group", "show-ispecs-cmd", "--include-defaults", groupname, ])) modcmd = ["gnt-group", "modify"] opts = addcmd.split() assert opts[0:2] == ["gnt-group", "add"] for k in range(2, len(opts) - 1): if opts[k].startswith("--ipolicy-"): assert k + 2 <= len(opts) modcmd.extend(opts[k:k + 2]) modcmd.append(groupname) # Apply the ipolicy to the group and verify the result AssertCommand(modcmd) new_addcmd = GetCommandOutput(mnode.primary, utils.ShellQuoteArgs([ "gnt-group", "show-ispecs-cmd", groupname, ])) AssertEqual(addcmd, new_addcmd)
def _CheckFileOnAllNodes(filename, content): """Verifies the content of the given file on all nodes. """ cmd = utils.ShellQuoteArgs(["cat", filename]) for node in qa_config.get("nodes"): AssertEqual(qa_utils.GetCommandOutput(node.primary, cmd), content)
def TestInterClusterInstanceMove(src_instance, dest_instance, inodes, tnode, perform_checks=True): """Test tools/move-instance""" master = qa_config.GetMasterNode() rapi_pw_file = tempfile.NamedTemporaryFile() rapi_pw_file.write(_rapi_password) rapi_pw_file.flush() # Needed only if checks are to be performed if perform_checks: dest_instance.SetDiskTemplate(src_instance.disk_template) # TODO: Run some instance tests before moving back if len(inodes) > 1: # No disk template currently requires more than 1 secondary node. If this # changes, either this test must be skipped or the script must be updated. assert len(inodes) == 2 snode = inodes[1] else: # instance is not redundant, but we still need to pass a node # (which will be ignored) snode = tnode pnode = inodes[0] # note: pnode:snode are the *current* nodes, so we move it first to # tnode:pnode, then back to pnode:snode for current_src_inst, current_dest_inst, target_pnode, target_snode in \ [(src_instance.name, dest_instance.name, tnode.primary, pnode.primary), (dest_instance.name, src_instance.name, pnode.primary, snode.primary)]: cmd = [ "../tools/move-instance", "--verbose", "--src-ca-file=%s" % _rapi_ca.name, "--src-username=%s" % _rapi_username, "--src-password-file=%s" % rapi_pw_file.name, "--dest-instance-name=%s" % current_dest_inst, "--dest-primary-node=%s" % target_pnode, "--dest-secondary-node=%s" % target_snode, "--net=0:mac=%s" % constants.VALUE_GENERATE, master.primary, master.primary, current_src_inst, ] # Some uses of this test might require that RAPI-only commands are used, # and the checks are command-line based. if perform_checks: qa_utils.RunInstanceCheck(current_dest_inst, False) AssertEqual(StartLocalCommand(cmd).wait(), 0) if perform_checks: qa_utils.RunInstanceCheck(current_src_inst, False) qa_utils.RunInstanceCheck(current_dest_inst, True)
def TestEmptyCluster(): """Testing remote API on an empty cluster. """ master = qa_config.GetMasterNode() master_full = qa_utils.ResolveNodeName(master) def _VerifyInfo(data): AssertIn("name", data) AssertIn("master", data) AssertEqual(data["master"], master_full) def _VerifyNodes(data): master_entry = { "id": master_full, "uri": "/2/nodes/%s" % master_full, } AssertIn(master_entry, data) def _VerifyNodesBulk(data): for node in data: for entry in NODE_FIELDS: AssertIn(entry, node) def _VerifyGroups(data): default_group = { "name": constants.INITIAL_NODE_GROUP_NAME, "uri": "/2/groups/" + constants.INITIAL_NODE_GROUP_NAME, } AssertIn(default_group, data) def _VerifyGroupsBulk(data): for group in data: for field in GROUP_FIELDS: AssertIn(field, group) _DoTests([ ("/", None, "GET", None), ("/2/info", _VerifyInfo, "GET", None), ("/2/tags", None, "GET", None), ("/2/nodes", _VerifyNodes, "GET", None), ("/2/nodes?bulk=1", _VerifyNodesBulk, "GET", None), ("/2/groups", _VerifyGroups, "GET", None), ("/2/groups?bulk=1", _VerifyGroupsBulk, "GET", None), ("/2/instances", [], "GET", None), ("/2/instances?bulk=1", [], "GET", None), ("/2/os", None, "GET", None), ]) # Test HTTP Not Found for method in ["GET", "PUT", "POST", "DELETE"]: try: _DoTests([("/99/resource/not/here/99", None, method, None)]) except rapi.client.GanetiApiError, err: AssertEqual(err.code, 404) else: raise qa_error.Error( "Non-existent resource didn't return HTTP 404")
def _AssertOobCall(verify_path, expected_args): """Assert the OOB call was performed with expetected args.""" master = qa_config.GetMasterNode() verify_output_cmd = utils.ShellQuoteArgs(["cat", verify_path]) output = qa_utils.GetCommandOutput(master.primary, verify_output_cmd, tty=False) AssertEqual(expected_args, output.strip())
def TestHookFailed(): """Checks whether the global hooks have been executed (status error). - Global post hook should with status *error* should has been executed. - Global post hook with other statuses shouldn't have been executed. """ master = GetMasterNode().primary job_id = ExecuteJobProducingCommand("gnt-debug delay --submit 0") time.sleep(1) AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post", constants.POST_HOOKS_STATUS_SUCCESS)), False, "Global post hook has been executed with status *success*") AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post", constants.POST_HOOKS_STATUS_ERROR)), True, "Global post hook hasn't been executed with status *error*") AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post", constants.POST_HOOKS_STATUS_DISAPPEARED)), False, "Global post hook has been executed with status *disappeared*")
def TestRapiStoppedInstanceConsole(instance): """Test getting stopped instance's console information via RAPI""" try: _rapi_client.GetInstanceConsole(instance.name) except rapi.client.GanetiApiError as err: AssertEqual(err.code, 503) else: raise qa_error.Error("Getting console for stopped instance didn't" " return HTTP 503")
def TestClusterEpo(): """gnt-cluster epo""" master = qa_config.GetMasterNode() # Assert that OOB is unavailable for all nodes result_output = GetCommandOutput( master.primary, "gnt-node list --verbose --no-headers -o" " powered") AssertEqual( compat.all(powered == "(unavail)" for powered in result_output.splitlines()), True) # Conflicting AssertCommand(["gnt-cluster", "epo", "--groups", "--all"], fail=True) # --all doesn't expect arguments AssertCommand(["gnt-cluster", "epo", "--all", "some_arg"], fail=True) # Unless --all is given master is not allowed to be in the list AssertCommand(["gnt-cluster", "epo", "-f", master.primary], fail=True) # This shouldn't fail AssertCommand(["gnt-cluster", "epo", "-f", "--all"]) # All instances should have been stopped now result_output = GetCommandOutput( master.primary, "gnt-instance list --no-headers -o status") # ERROR_down because the instance is stopped but not recorded as such AssertEqual( compat.all(status == "ERROR_down" for status in result_output.splitlines()), True) # Now start everything again AssertCommand(["gnt-cluster", "epo", "--on", "-f", "--all"]) # All instances should have been started now result_output = GetCommandOutput( master.primary, "gnt-instance list --no-headers -o status") AssertEqual( compat.all(status == "running" for status in result_output.splitlines()), True)
def _TestInstanceUserDown(instance, master, hv_shutdown_fn): # Shutdown instance and bring instance status to 'USER_down' hv_shutdown_fn() cmd = [ "gnt-instance", "list", "--no-headers", "-o", "status", instance.name ] result_output = qa_utils.GetCommandOutput(master.primary, utils.ShellQuoteArgs(cmd)) AssertEqual(result_output.strip(), constants.INSTST_USERDOWN) # Fail to bring instance status to 'running' AssertCommand(["gnt-instance", "start", instance.name], fail=True) cmd = [ "gnt-instance", "list", "--no-headers", "-o", "status", instance.name ] result_output = qa_utils.GetCommandOutput(master.primary, utils.ShellQuoteArgs(cmd)) AssertEqual(result_output.strip(), constants.INSTST_USERDOWN) # Bring instance status to 'ADMIN_down' AssertCommand(["gnt-instance", "shutdown", instance.name]) cmd = [ "gnt-instance", "list", "--no-headers", "-o", "status", instance.name ] result_output = qa_utils.GetCommandOutput(master.primary, utils.ShellQuoteArgs(cmd)) AssertEqual(result_output.strip(), constants.INSTST_ADMINDOWN) # Bring instance status to 'running' AssertCommand(["gnt-instance", "start", instance.name]) cmd = [ "gnt-instance", "list", "--no-headers", "-o", "status", instance.name ] result_output = qa_utils.GetCommandOutput(master.primary, utils.ShellQuoteArgs(cmd)) AssertEqual(result_output.strip(), constants.INSTST_RUNNING) # Bring instance status to 'ADMIN_down' forcibly AssertCommand(["gnt-instance", "shutdown", "-f", instance.name]) cmd = [ "gnt-instance", "list", "--no-headers", "-o", "status", instance.name ] result_output = qa_utils.GetCommandOutput(master.primary, utils.ShellQuoteArgs(cmd)) AssertEqual(result_output.strip(), constants.INSTST_ADMINDOWN) # Bring instance status to 'running' AssertCommand(["gnt-instance", "start", instance.name]) cmd = [ "gnt-instance", "list", "--no-headers", "-o", "status", instance.name ] result_output = qa_utils.GetCommandOutput(master.primary, utils.ShellQuoteArgs(cmd)) AssertEqual(result_output.strip(), constants.INSTST_RUNNING)
def TestClusterModifyIPolicy(): """gnt-cluster modify --ipolicy-*""" basecmd = ["gnt-cluster", "modify"] (old_policy, old_specs) = _GetClusterIPolicy() for par in ["vcpu-ratio", "spindle-ratio"]: curr_val = float(old_policy[par]) test_values = [ (True, 1.0), (True, 1.5), (True, 2), (False, "a"), # Restore the old value (True, curr_val), ] for (good, val) in test_values: cmd = basecmd + ["--ipolicy-%s=%s" % (par, val)] AssertCommand(cmd, fail=not good) if good: curr_val = val # Check the affected parameter (eff_policy, eff_specs) = _GetClusterIPolicy() AssertEqual(float(eff_policy[par]), curr_val) # Check everything else AssertEqual(eff_specs, old_specs) for p in eff_policy.keys(): if p == par: continue AssertEqual(eff_policy[p], old_policy[p]) # Allowing disk templates via ipolicy requires them to be # enabled on the cluster. if not (qa_config.IsTemplateSupported(constants.DT_PLAIN) and qa_config.IsTemplateSupported(constants.DT_DRBD8)): return # Disk templates are treated slightly differently par = "disk-templates" disp_str = "allowed disk templates" curr_val = old_policy[disp_str] test_values = [ (True, constants.DT_PLAIN), (True, "%s,%s" % (constants.DT_PLAIN, constants.DT_DRBD8)), (False, "thisisnotadisktemplate"), (False, ""), # Restore the old value (True, curr_val.replace(" ", "")), ] for (good, val) in test_values: cmd = basecmd + ["--ipolicy-%s=%s" % (par, val)] AssertCommand(cmd, fail=not good) if good: curr_val = val # Check the affected parameter (eff_policy, eff_specs) = _GetClusterIPolicy() AssertEqual(eff_policy[disp_str].replace(" ", ""), curr_val) # Check everything else AssertEqual(eff_specs, old_specs) for p in eff_policy.keys(): if p == disp_str: continue AssertEqual(eff_policy[p], old_policy[p])
def TestInstance(instance): """Testing getting instance(s) info via remote API. """ def _VerifyInstance(data): for entry in INSTANCE_FIELDS: AssertIn(entry, data) def _VerifyInstancesList(data): for instance in data: for entry in LIST_FIELDS: AssertIn(entry, instance) def _VerifyInstancesBulk(data): for instance_data in data: _VerifyInstance(instance_data) _DoTests([ ("/2/instances/%s" % instance.name, _VerifyInstance, "GET", None), ("/2/instances", _VerifyInstancesList, "GET", None), ("/2/instances?bulk=1", _VerifyInstancesBulk, "GET", None), ("/2/instances/%s/activate-disks" % instance.name, _VerifyReturnsJob, "PUT", None), ("/2/instances/%s/deactivate-disks" % instance.name, _VerifyReturnsJob, "PUT", None), ]) # Test OpBackupPrepare (job_id, ) = _DoTests([ ("/2/instances/%s/prepare-export?mode=%s" % (instance.name, constants.EXPORT_MODE_REMOTE), _VerifyReturnsJob, "PUT", None), ]) result = _WaitForRapiJob(job_id)[0] AssertEqual(len(result["handshake"]), 3) AssertEqual(result["handshake"][0], constants.RIE_VERSION) AssertEqual(len(result["x509_key_name"]), 3) AssertIn("-----BEGIN CERTIFICATE-----", result["x509_ca"])
def TestFilterAddRemove(): """gnt-filter add/delete""" uuid1 = stdout_of(["gnt-filter", "add", "--reason", "reason1"]) TestFilterList() TestFilterListFields() uuid2 = stdout_of(["gnt-filter", "list", "--no-headers", "--output=uuid"]) AssertEqual(uuid1, uuid2) AssertCommand(["gnt-filter", "delete", uuid1]) TestFilterList()
def TestAdHocReasonRateLimit(): """Tests that ad-hoc rate limiting using --reason="rate-limit:n:..." works. """ # Make sure our test is not constrained by "max-running-jobs" # (simply set it to the default). AssertCommand(["gnt-cluster", "modify", "--max-running-jobs=20"]) AssertCommand(["gnt-cluster", "modify", "--max-tracked-jobs=25"]) # Only the first 2 jobs must be scheduled. jid1 = int( stdout_of([ "gnt-debug", "delay", "--print-jobid", "--submit", "--reason=rate-limit:2:hello", "20", ])) jid2 = int( stdout_of([ "gnt-debug", "delay", "--print-jobid", "--submit", "--reason=rate-limit:2:hello", "20", ])) jid3 = int( stdout_of([ "gnt-debug", "delay", "--print-jobid", "--submit", "--reason=rate-limit:2:hello", "20", ])) time.sleep(0.1) # give the scheduler some time to notice AssertIn(GetJobStatus(jid1), ["running", "waiting"], msg="Job should not be rate-limited") AssertIn(GetJobStatus(jid2), ["running", "waiting"], msg="Job should not be rate-limited") AssertEqual(GetJobStatus(jid3), "queued", msg="Job should be rate-limited") # Clean up. KillWaitJobs([jid1, jid2, jid3])
def _InvokeMoveInstance(current_dest_inst, current_src_inst, rapi_pw_filename, joint_master, perform_checks, target_nodes=None): """ Invokes the move-instance tool for testing purposes. """ # Some uses of this test might require that RAPI-only commands are used, # and the checks are command-line based. if perform_checks: qa_utils.RunInstanceCheck(current_dest_inst, False) cmd = [ "../tools/move-instance", "--verbose", "--src-ca-file=%s" % _rapi_ca.name, "--src-username=%s" % _rapi_username, "--src-password-file=%s" % rapi_pw_filename, "--dest-instance-name=%s" % current_dest_inst, ] if target_nodes: pnode, snode = target_nodes cmd.extend([ "--dest-primary-node=%s" % pnode, "--dest-secondary-node=%s" % snode, ]) else: cmd.extend([ "--iallocator=%s" % constants.IALLOC_HAIL, "--opportunistic-tries=1", ]) cmd.extend([ "--net=0:mac=%s" % constants.VALUE_GENERATE, joint_master, joint_master, current_src_inst, ]) AssertEqual(StartLocalCommand(cmd).wait(), 0) if perform_checks: qa_utils.RunInstanceCheck(current_src_inst, False) qa_utils.RunInstanceCheck(current_dest_inst, True)
def TestInstanceReboot(instance): """gnt-instance reboot""" options = qa_config.get("options", {}) reboot_types = options.get("reboot-types", constants.REBOOT_TYPES) name = instance.name for rtype in reboot_types: AssertCommand(["gnt-instance", "reboot", "--type=%s" % rtype, name]) AssertCommand(["gnt-instance", "shutdown", name]) qa_utils.RunInstanceCheck(instance, False) AssertCommand(["gnt-instance", "reboot", name]) master = qa_config.GetMasterNode() cmd = ["gnt-instance", "list", "--no-headers", "-o", "status", name] result_output = qa_utils.GetCommandOutput(master.primary, utils.ShellQuoteArgs(cmd)) AssertEqual(result_output.strip(), constants.INSTST_RUNNING)
def _DoTests(uris): # pylint: disable=W0212 # due to _SendRequest usage results = [] for uri, verify, method, body in uris: assert uri.startswith("/") print("%s %s" % (method, uri)) data = _rapi_client._SendRequest(method, uri, None, body) if verify is not None: if callable(verify): verify(data) else: AssertEqual(data, verify) results.append(data) return results
def TestFilterRateLimit(): """Tests that the RATE_LIMIT filter does reject new jobs when all rate-limiting buckets are taken. """ # Make sure our test is not constrained by "max-running-jobs" # (simply set it to the default). AssertCommand(["gnt-cluster", "modify", "--max-running-jobs=20"]) AssertCommand(["gnt-cluster", "modify", "--max-tracked-jobs=25"]) AssertCommand(["gnt-cluster", "watcher", "pause", "600"]) # Add a filter that rejects all new jobs. uuid = stdout_of([ "gnt-filter", "add", '--predicates=[["jobid", [">", "id", "watermark"]]]', "--action=RATE_LIMIT 2", ]) # Now only the first 2 jobs must be scheduled. jid1 = int( stdout_of(["gnt-debug", "delay", "--print-jobid", "--submit", "200"])) jid2 = int( stdout_of(["gnt-debug", "delay", "--print-jobid", "--submit", "200"])) jid3 = int( stdout_of(["gnt-debug", "delay", "--print-jobid", "--submit", "200"])) time.sleep(5) # give the scheduler some time to notice AssertIn(GetJobStatus(jid1), ["running", "waiting"], msg="Job should not be rate-limited") AssertIn(GetJobStatus(jid2), ["running", "waiting"], msg="Job should not be rate-limited") AssertEqual(GetJobStatus(jid3), "queued", msg="Job should be rate-limited") # Clean up. AssertCommand(["gnt-filter", "delete", uuid]) KillWaitJobs([jid1, jid2, jid3]) AssertCommand(["gnt-cluster", "watcher", "continue"])
def TestNodeListDrbd(node, is_drbd): """gnt-node list-drbd""" master = qa_config.GetMasterNode() result_output = GetCommandOutput(master.primary, "gnt-node list-drbd --no-header %s" % node.primary) # Meaningful to note: there is but one instance, and the node is either the # primary or one of the secondaries if is_drbd: # Invoked for both primary and secondary per_disk_info = result_output.splitlines() for line in per_disk_info: try: drbd_node, _, _, _, _, drbd_peer = line.split() except ValueError: raise qa_error.Error("Could not examine list-drbd output: expected a" " single row of 6 entries, found the following:" " %s" % line) AssertIn(node.primary, [drbd_node, drbd_peer], msg="The output %s does not contain the node" % line) else: # Output should be empty, barring newlines AssertEqual(result_output.strip(), "")
# Test HTTP Not Found for method in ["GET", "PUT", "POST", "DELETE"]: try: _DoTests([("/99/resource/not/here/99", None, method, None)]) except rapi.client.GanetiApiError, err: AssertEqual(err.code, 404) else: raise qa_error.Error( "Non-existent resource didn't return HTTP 404") # Test HTTP Not Implemented for method in ["PUT", "POST", "DELETE"]: try: _DoTests([("/version", None, method, None)]) except rapi.client.GanetiApiError, err: AssertEqual(err.code, 501) else: raise qa_error.Error("Non-implemented method didn't fail") # Test GET/PUT symmetry LEGITIMATELY_MISSING = [ "force", # Standard option "add_uids", # Modifies UID pool, is not a param itself "remove_uids", # Same as above "osparams_private_cluster", # Should not be returned ] NOT_EXPOSED_YET = ["hv_state", "disk_state", "modify_etc_hosts"] # The nicparams are returned under the default entry, yet accepted as they # are - this is a TODO to fix! DEFAULT_ISSUES = ["nicparams"] # Cannot be set over RAPI due to security issues
def _Check(exp_fields, data): qresult = objects.QueryResponse.FromDict(data) AssertEqual([fdef.name for fdef in qresult.fields], exp_fields) if not isinstance(qresult.data, list): raise qa_error.Error("Query did not return a list")
def TestRapiQuery(): """Testing resource queries via remote API. """ # FIXME: the tests are failing if no LVM is enabled, investigate # if it is a bug in the QA or in the code if not qa_config.IsStorageTypeSupported(constants.ST_LVM_VG): return master_name = qa_utils.ResolveNodeName(qa_config.GetMasterNode()) rnd = random.Random(7818) for what in constants.QR_VIA_RAPI: namefield = { constants.QR_JOB: "id", constants.QR_EXPORT: "export", constants.QR_FILTER: "uuid", }.get(what, "name") all_fields = list(query.ALL_FIELDS[what]) rnd.shuffle(all_fields) # No fields, should return everything result = _rapi_client.QueryFields(what) qresult = objects.QueryFieldsResponse.FromDict(result) AssertEqual(len(qresult.fields), len(all_fields)) # One field result = _rapi_client.QueryFields(what, fields=[namefield]) qresult = objects.QueryFieldsResponse.FromDict(result) AssertEqual(len(qresult.fields), 1) # Specify all fields, order must be correct result = _rapi_client.QueryFields(what, fields=all_fields) qresult = objects.QueryFieldsResponse.FromDict(result) AssertEqual(len(qresult.fields), len(all_fields)) AssertEqual([fdef.name for fdef in qresult.fields], all_fields) # Unknown field result = _rapi_client.QueryFields(what, fields=["_unknown!"]) qresult = objects.QueryFieldsResponse.FromDict(result) AssertEqual(len(qresult.fields), 1) AssertEqual(qresult.fields[0].name, "_unknown!") AssertEqual(qresult.fields[0].kind, constants.QFT_UNKNOWN) # Try once more, this time without the client _DoTests([ ("/2/query/%s/fields" % what, None, "GET", None), ("/2/query/%s/fields?fields=%s,%s,%s" % (what, namefield, namefield, all_fields[0]), None, "GET", None), ]) # Try missing query argument try: _DoTests([ ("/2/query/%s" % what, None, "GET", None), ]) except rapi.client.GanetiApiError as err: AssertEqual(err.code, 400) else: raise qa_error.Error( "Request missing 'fields' parameter didn't fail") def _Check(exp_fields, data): qresult = objects.QueryResponse.FromDict(data) AssertEqual([fdef.name for fdef in qresult.fields], exp_fields) if not isinstance(qresult.data, list): raise qa_error.Error("Query did not return a list") _DoTests([ # Specify fields in query ("/2/query/%s?fields=%s" % (what, ",".join(all_fields)), compat.partial(_Check, all_fields), "GET", None), ("/2/query/%s?fields=%s" % (what, namefield), compat.partial(_Check, [namefield]), "GET", None), # Note the spaces ("/2/query/%s?fields=%s,%%20%s%%09,%s%%20" % (what, namefield, namefield, namefield), compat.partial(_Check, [namefield] * 3), "GET", None) ]) if what in constants.QR_VIA_RAPI_PUT: _DoTests([ # PUT with fields in query ("/2/query/%s?fields=%s" % (what, namefield), compat.partial(_Check, [namefield]), "PUT", {}), ("/2/query/%s" % what, compat.partial(_Check, [namefield] * 4), "PUT", { "fields": [namefield] * 4, }), ("/2/query/%s" % what, compat.partial(_Check, all_fields), "PUT", { "fields": all_fields, }), ("/2/query/%s" % what, compat.partial(_Check, [namefield] * 4), "PUT", { "fields": [namefield] * 4 }) ]) if what in constants.QR_VIA_RAPI_PUT: trivial_filter = { constants.QR_JOB: [qlang.OP_GE, namefield, 0], }.get(what, [qlang.OP_REGEXP, namefield, ".*"]) _DoTests([ # With filter ("/2/query/%s" % what, compat.partial(_Check, all_fields), "PUT", { "fields": all_fields, "filter": trivial_filter }), ]) if what == constants.QR_NODE: # Test with filter (nodes, ) = _DoTests([("/2/query/%s" % what, compat.partial(_Check, ["name", "master"]), "PUT", { "fields": ["name", "master"], "filter": [qlang.OP_TRUE, "master"], })]) qresult = objects.QueryResponse.FromDict(nodes) AssertEqual(qresult.data, [ [[constants.RS_NORMAL, master_name], [constants.RS_NORMAL, True]], ])
def _VerifyInfo(data): AssertIn("name", data) AssertIn("master", data) AssertEqual(data["master"], master_full)
def TestEmptyCluster(): """Testing remote API on an empty cluster. """ master = qa_config.GetMasterNode() master_full = qa_utils.ResolveNodeName(master) def _VerifyInfo(data): AssertIn("name", data) AssertIn("master", data) AssertEqual(data["master"], master_full) def _VerifyNodes(data): master_entry = { "id": master_full, "uri": "/2/nodes/%s" % master_full, } AssertIn(master_entry, data) def _VerifyNodesBulk(data): for node in data: for entry in NODE_FIELDS: AssertIn(entry, node) def _VerifyGroups(data): default_group = { "name": constants.INITIAL_NODE_GROUP_NAME, "uri": "/2/groups/" + constants.INITIAL_NODE_GROUP_NAME, } AssertIn(default_group, data) def _VerifyGroupsBulk(data): for group in data: for field in GROUP_FIELDS: AssertIn(field, group) def _VerifyFiltersBulk(data): for group in data: for field in FILTER_FIELDS: AssertIn(field, group) _DoTests([ ("/", None, "GET", None), ("/2/info", _VerifyInfo, "GET", None), ("/2/tags", None, "GET", None), ("/2/nodes", _VerifyNodes, "GET", None), ("/2/nodes?bulk=1", _VerifyNodesBulk, "GET", None), ("/2/groups", _VerifyGroups, "GET", None), ("/2/groups?bulk=1", _VerifyGroupsBulk, "GET", None), ("/2/instances", [], "GET", None), ("/2/instances?bulk=1", [], "GET", None), ("/2/os", None, "GET", None), ("/2/filters", [], "GET", None), ("/2/filters?bulk=1", _VerifyFiltersBulk, "GET", None), ]) # Test HTTP Not Found for method in ["GET", "PUT", "POST", "DELETE"]: try: _DoTests([("/99/resource/not/here/99", None, method, None)]) except rapi.client.GanetiApiError as err: AssertEqual(err.code, 404) else: raise qa_error.Error( "Non-existent resource didn't return HTTP 404") # Test HTTP Not Implemented for method in ["PUT", "POST", "DELETE"]: try: _DoTests([("/version", None, method, None)]) except rapi.client.GanetiApiError as err: AssertEqual(err.code, 501) else: raise qa_error.Error("Non-implemented method didn't fail") # Test GET/PUT symmetry LEGITIMATELY_MISSING = [ "force", # Standard option "add_uids", # Modifies UID pool, is not a param itself "remove_uids", # Same as above "osparams_private_cluster", # Should not be returned ] NOT_EXPOSED_YET = ["hv_state", "disk_state", "modify_etc_hosts"] # The nicparams are returned under the default entry, yet accepted as they # are - this is a TODO to fix! DEFAULT_ISSUES = ["nicparams"] # Cannot be set over RAPI due to security issues FORBIDDEN_PARAMS = ["compression_tools"] _DoGetPutTests("/2/info", "/2/modify", opcodes.OpClusterSetParams.OP_PARAMS, exceptions=(LEGITIMATELY_MISSING + NOT_EXPOSED_YET), set_exceptions=DEFAULT_ISSUES + FORBIDDEN_PARAMS)
# Test HTTP Not Found for method in ["GET", "PUT", "POST", "DELETE"]: try: _DoTests([("/99/resource/not/here/99", None, method, None)]) except rapi.client.GanetiApiError, err: AssertEqual(err.code, 404) else: raise qa_error.Error( "Non-existent resource didn't return HTTP 404") # Test HTTP Not Implemented for method in ["PUT", "POST", "DELETE"]: try: _DoTests([("/version", None, method, None)]) except rapi.client.GanetiApiError, err: AssertEqual(err.code, 501) else: raise qa_error.Error("Non-implemented method didn't fail") def TestRapiQuery(): """Testing resource queries via remote API. """ # FIXME: the tests are failing if no LVM is enabled, investigate # if it is a bug in the QA or in the code if not qa_config.IsStorageTypeSupported(constants.ST_LVM_VG): return master_name = qa_utils.ResolveNodeName(qa_config.GetMasterNode()) rnd = random.Random(7818)
def _VerifyTags(data): AssertEqual(sorted(tags), sorted(_FilterTags(data)))
def TestNodeStorage(): """gnt-node storage""" master = qa_config.GetMasterNode() # FIXME: test all storage_types in constants.STORAGE_TYPES # as soon as they are implemented. enabled_storage_types = qa_config.GetEnabledStorageTypes() testable_storage_types = list(set(enabled_storage_types).intersection( set([constants.ST_FILE, constants.ST_LVM_VG, constants.ST_LVM_PV]))) for storage_type in testable_storage_types: cmd = ["gnt-node", "list-storage", "--storage-type", storage_type] # Test simple list AssertCommand(cmd) # Test all storage fields cmd = ["gnt-node", "list-storage", "--storage-type", storage_type, "--output=%s" % ",".join(list(constants.VALID_STORAGE_FIELDS))] AssertCommand(cmd) # Get list of valid storage devices cmd = ["gnt-node", "list-storage", "--storage-type", storage_type, "--output=node,name,allocatable", "--separator=|", "--no-headers"] output = qa_utils.GetCommandOutput(master.primary, utils.ShellQuoteArgs(cmd)) # Test with up to two devices testdevcount = 2 for line in output.splitlines()[:testdevcount]: (node_name, st_name, st_allocatable) = line.split("|") # Dummy modification without any changes cmd = ["gnt-node", "modify-storage", node_name, storage_type, st_name] AssertCommand(cmd) # Make sure we end up with the same value as before if st_allocatable.lower() == "y": test_allocatable = ["no", "yes"] else: test_allocatable = ["yes", "no"] fail = (constants.SF_ALLOCATABLE not in constants.MODIFIABLE_STORAGE_FIELDS.get(storage_type, [])) for i in test_allocatable: AssertCommand(["gnt-node", "modify-storage", "--allocatable", i, node_name, storage_type, st_name], fail=fail) # Verify list output cmd = ["gnt-node", "list-storage", "--storage-type", storage_type, "--output=name,allocatable", "--separator=|", "--no-headers", node_name] listout = qa_utils.GetCommandOutput(master.primary, utils.ShellQuoteArgs(cmd)) for line in listout.splitlines(): (vfy_name, vfy_allocatable) = line.split("|") if vfy_name == st_name and not fail: AssertEqual(vfy_allocatable, i[0].upper()) else: AssertEqual(vfy_allocatable, st_allocatable) # Test repair functionality fail = (constants.SO_FIX_CONSISTENCY not in constants.VALID_STORAGE_OPERATIONS.get(storage_type, [])) AssertCommand(["gnt-node", "repair-storage", node_name, storage_type, st_name], fail=fail)
def TestRapiInstanceConsole(instance): """Test getting instance console information via RAPI""" result = _rapi_client.GetInstanceConsole(instance.name) console = objects.InstanceConsole.FromDict(result) AssertEqual(console.Validate(), None) AssertEqual(console.instance, qa_utils.ResolveInstanceName(instance.name))
def _VerifyJob(data): AssertEqual(data["id"], job_id) for field in JOB_FIELDS: AssertIn(field, data)
def TestRapiStoppedInstanceConsole(instance): """Test getting stopped instance's console information via RAPI""" try: _rapi_client.GetInstanceConsole(instance.name) except rapi.client.GanetiApiError, err: AssertEqual(err.code, 503)