| # |
| # |
| |
| # Copyright (C) 2007, 2008, 2009, 2010, 2011 Google Inc. |
| # All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are |
| # met: |
| # |
| # 1. Redistributions of source code must retain the above copyright notice, |
| # this list of conditions and the following disclaimer. |
| # |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
| # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| |
| """OS related QA tests. |
| |
| """ |
| |
| import os |
| import os.path |
| |
| from ganeti import utils |
| from ganeti import constants |
| from ganeti import pathutils |
| |
| import qa_config |
| import qa_utils |
| import qa_error |
| |
| from qa_utils import AssertCommand, AssertIn, AssertNotIn |
| |
| |
| _TEMP_OS_NAME = "TEMP-Ganeti-QA-OS" |
| _TEMP_OS_PATH = os.path.join(pathutils.OS_SEARCH_PATH[0], _TEMP_OS_NAME) |
| |
| (_ALL_VALID, |
| _ALL_INVALID, |
| _PARTIALLY_VALID) = range(1, 4) |
| |
| |
| def TestOsList(): |
| """gnt-os list""" |
| AssertCommand(["gnt-os", "list"]) |
| |
| |
| def TestOsDiagnose(): |
| """gnt-os diagnose""" |
| AssertCommand(["gnt-os", "diagnose"]) |
| |
| |
| def _TestOsModify(hvp_dict, fail=False): |
| """gnt-os modify""" |
| cmd = ["gnt-os", "modify"] |
| |
| for hv_name, hv_params in hvp_dict.items(): |
| cmd.append("-H") |
| options = [] |
| for key, value in hv_params.items(): |
| options.append("%s=%s" % (key, value)) |
| cmd.append("%s:%s" % (hv_name, ",".join(options))) |
| |
| cmd.append(_TEMP_OS_NAME) |
| AssertCommand(cmd, fail=fail) |
| |
| |
| def _TestOsStates(os_name): |
| """gnt-os modify, more stuff""" |
| cmd = ["gnt-os", "modify"] |
| |
| for param in ["hidden", "blacklisted"]: |
| for val in ["yes", "no"]: |
| new_cmd = cmd + ["--%s" % param, val, os_name] |
| AssertCommand(new_cmd) |
| # check that double-running the command is OK |
| AssertCommand(new_cmd) |
| |
| |
| 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 _RemoveTempOs(node, dirname): |
| """Removes a temporary OS definition. |
| |
| """ |
| AssertCommand(["rm", "-rf", dirname], node=node) |
| |
| |
| def _TestOs(mode, rapi_cb): |
| """Generic function for OS definition testing |
| |
| """ |
| master = qa_config.GetMasterNode() |
| |
| name = _TEMP_OS_NAME |
| variant = "default" |
| fullname = "%s+%s" % (name, variant) |
| dirname = _TEMP_OS_PATH |
| |
| # Ensure OS is usable |
| cmd = ["gnt-os", "modify", "--hidden=no", "--blacklisted=no", name] |
| AssertCommand(cmd) |
| |
| nodes = [] |
| try: |
| for i, node in enumerate(qa_config.get("nodes")): |
| nodes.append(node) |
| if mode == _ALL_INVALID: |
| valid = False |
| elif mode == _ALL_VALID: |
| valid = True |
| elif mode == _PARTIALLY_VALID: |
| valid = bool(i % 2) |
| else: |
| raise AssertionError("Unknown mode %s" % mode) |
| _SetupTempOs(node, dirname, variant, valid) |
| |
| # TODO: Use Python 2.6's itertools.permutations |
| for (hidden, blacklisted) in [(False, False), (True, False), |
| (False, True), (True, True)]: |
| # Change OS' visibility |
| cmd = ["gnt-os", "modify", "--hidden", ["no", "yes"][int(hidden)], |
| "--blacklisted", ["no", "yes"][int(blacklisted)], name] |
| AssertCommand(cmd) |
| |
| # Diagnose, checking exit status |
| AssertCommand(["gnt-os", "diagnose"], fail=(mode != _ALL_VALID)) |
| |
| # Diagnose again, ignoring exit status |
| output = qa_utils.GetCommandOutput(master.primary, |
| "gnt-os diagnose || :") |
| for line in output.splitlines(): |
| if line.startswith("OS: %s [global status:" % name): |
| break |
| else: |
| raise qa_error.Error("Didn't find OS '%s' in 'gnt-os diagnose'" % name) |
| |
| # Check info for all |
| cmd = ["gnt-os", "info"] |
| output = qa_utils.GetCommandOutput(master.primary, |
| utils.ShellQuoteArgs(cmd)) |
| AssertIn("%s:" % name, output.splitlines()) |
| |
| # Check info for OS |
| cmd = ["gnt-os", "info", name] |
| output = qa_utils.GetCommandOutput(master.primary, |
| utils.ShellQuoteArgs(cmd)).splitlines() |
| AssertIn("%s:" % name, output) |
| for (field, value) in [("valid", mode == _ALL_VALID), |
| ("hidden", hidden), |
| ("blacklisted", blacklisted)]: |
| AssertIn(" - %s: %s" % (field, value), output) |
| |
| # Only valid OSes should be listed |
| cmd = ["gnt-os", "list", "--no-headers"] |
| output = qa_utils.GetCommandOutput(master.primary, |
| utils.ShellQuoteArgs(cmd)) |
| if mode == _ALL_VALID and not (hidden or blacklisted): |
| assert_fn = AssertIn |
| else: |
| assert_fn = AssertNotIn |
| assert_fn(fullname, output.splitlines()) |
| |
| # Check via RAPI |
| if rapi_cb: |
| assert_fn(fullname, rapi_cb()) |
| finally: |
| for node in nodes: |
| _RemoveTempOs(node, dirname) |
| |
| |
| def TestOsValid(rapi_cb): |
| """Testing valid OS definition""" |
| return _TestOs(_ALL_VALID, rapi_cb) |
| |
| |
| def TestOsInvalid(rapi_cb): |
| """Testing invalid OS definition""" |
| return _TestOs(_ALL_INVALID, rapi_cb) |
| |
| |
| def TestOsPartiallyValid(rapi_cb): |
| """Testing partially valid OS definition""" |
| return _TestOs(_PARTIALLY_VALID, rapi_cb) |
| |
| |
| def TestOsModifyValid(): |
| """Testing a valid os modify invocation""" |
| hv_dict = { |
| constants.HT_XEN_PVM: { |
| constants.HV_ROOT_PATH: "/dev/sda5", |
| }, |
| constants.HT_XEN_HVM: { |
| constants.HV_ACPI: False, |
| constants.HV_PAE: True, |
| }, |
| } |
| |
| return _TestOsModify(hv_dict) |
| |
| |
| def TestOsModifyInvalid(): |
| """Testing an invalid os modify invocation""" |
| hv_dict = { |
| "blahblahblubb": {"bar": ""}, |
| } |
| |
| return _TestOsModify(hv_dict, fail=True) |
| |
| |
| def TestOsStatesNonExisting(): |
| """Testing OS states with non-existing OS""" |
| AssertCommand(["test", "-e", _TEMP_OS_PATH], fail=True) |
| return _TestOsStates(_TEMP_OS_NAME) |