Fix QA OS API failure
[ganeti-local] / qa / qa_os.py
1 #
2 #
3
4 # Copyright (C) 2007, 2008, 2009, 2010, 2011 Google Inc.
5 #
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.
10 #
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.
15 #
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
19 # 02110-1301, USA.
20
21
22 """OS related QA tests.
23
24 """
25
26 import os
27 import os.path
28
29 from ganeti import utils
30 from ganeti import constants
31
32 import qa_config
33 import qa_utils
34 import qa_error
35
36 from qa_utils import AssertCommand, AssertIn, AssertNotIn
37
38
39 _TEMP_OS_NAME = "TEMP-Ganeti-QA-OS"
40 _TEMP_OS_PATH = os.path.join(constants.OS_SEARCH_PATH[0], _TEMP_OS_NAME)
41
42 (_ALL_VALID,
43  _ALL_INVALID,
44  _PARTIALLY_VALID) = range(1, 4)
45
46
47 def TestOsList():
48   """gnt-os list"""
49   AssertCommand(["gnt-os", "list"])
50
51
52 def TestOsDiagnose():
53   """gnt-os diagnose"""
54   AssertCommand(["gnt-os", "diagnose"])
55
56
57 def _TestOsModify(hvp_dict, fail=False):
58   """gnt-os modify"""
59   cmd = ["gnt-os", "modify"]
60
61   for hv_name, hv_params in hvp_dict.items():
62     cmd.append("-H")
63     options = []
64     for key, value in hv_params.items():
65       options.append("%s=%s" % (key, value))
66     cmd.append("%s:%s" % (hv_name, ",".join(options)))
67
68   cmd.append(_TEMP_OS_NAME)
69   AssertCommand(cmd, fail=fail)
70
71
72 def _TestOsStates(os_name):
73   """gnt-os modify, more stuff"""
74   cmd = ["gnt-os", "modify"]
75
76   for param in ["hidden", "blacklisted"]:
77     for val in ["yes", "no"]:
78       new_cmd = cmd + ["--%s" % param, val, os_name]
79       AssertCommand(new_cmd)
80       # check that double-running the command is OK
81       AssertCommand(new_cmd)
82
83
84 def _SetupTempOs(node, dirname, variant, valid):
85   """Creates a temporary OS definition on the given node.
86
87   """
88   sq = utils.ShellQuoteArgs
89   parts = [
90     sq(["rm", "-rf", dirname]),
91     sq(["mkdir", "-p", dirname]),
92     sq(["cd", dirname]),
93     sq(["ln", "-fs", "/bin/true", "export"]),
94     sq(["ln", "-fs", "/bin/true", "import"]),
95     sq(["ln", "-fs", "/bin/true", "rename"]),
96     sq(["ln", "-fs", "/bin/true", "verify"]),
97     ]
98
99   if valid:
100     parts.append(sq(["ln", "-fs", "/bin/true", "create"]))
101
102   parts.append(sq(["echo", str(constants.OS_API_V20)]) +
103                " >ganeti_api_version")
104
105   parts.append(sq(["echo", variant]) + " >variants.list")
106   parts.append(sq(["echo", "funny this is funny"]) + " >parameters.list")
107
108   cmd = " && ".join(parts)
109
110   print qa_utils.FormatInfo("Setting up %s with %s OS definition" %
111                             (node["primary"],
112                              ["an invalid", "a valid"][int(valid)]))
113
114   AssertCommand(cmd, node=node)
115
116
117 def _RemoveTempOs(node, dirname):
118   """Removes a temporary OS definition.
119
120   """
121   AssertCommand(["rm", "-rf", dirname], node=node)
122
123
124 def _TestOs(mode, rapi_cb):
125   """Generic function for OS definition testing
126
127   """
128   master = qa_config.GetMasterNode()
129
130   name = _TEMP_OS_NAME
131   variant = "default"
132   fullname = "%s+%s" % (name, variant)
133   dirname = _TEMP_OS_PATH
134
135   # Ensure OS is usable
136   cmd = ["gnt-os", "modify", "--hidden=no", "--blacklisted=no", name]
137   AssertCommand(cmd)
138
139   nodes = []
140   try:
141     for i, node in enumerate(qa_config.get("nodes")):
142       nodes.append(node)
143       if mode == _ALL_INVALID:
144         valid = False
145       elif mode == _ALL_VALID:
146         valid = True
147       elif mode == _PARTIALLY_VALID:
148         valid = bool(i % 2)
149       else:
150         raise AssertionError("Unknown mode %s" % mode)
151       _SetupTempOs(node, dirname, variant, valid)
152
153     # TODO: Use Python 2.6's itertools.permutations
154     for (hidden, blacklisted) in [(False, False), (True, False),
155                                   (False, True), (True, True)]:
156       # Change OS' visibility
157       cmd = ["gnt-os", "modify", "--hidden", ["no", "yes"][int(hidden)],
158              "--blacklisted", ["no", "yes"][int(blacklisted)], name]
159       AssertCommand(cmd)
160
161       # Diagnose, checking exit status
162       AssertCommand(["gnt-os", "diagnose"], fail=(mode != _ALL_VALID))
163
164       # Diagnose again, ignoring exit status
165       output = qa_utils.GetCommandOutput(master["primary"],
166                                          "gnt-os diagnose || :")
167       for line in output.splitlines():
168         if line.startswith("OS: %s [global status:" % name):
169           break
170       else:
171         raise qa_error.Error("Didn't find OS '%s' in 'gnt-os diagnose'" % name)
172
173       # Check info for all
174       cmd = ["gnt-os", "info"]
175       output = qa_utils.GetCommandOutput(master["primary"],
176                                          utils.ShellQuoteArgs(cmd))
177       AssertIn("%s:" % name, output.splitlines())
178
179       # Check info for OS
180       cmd = ["gnt-os", "info", name]
181       output = qa_utils.GetCommandOutput(master["primary"],
182                                          utils.ShellQuoteArgs(cmd)).splitlines()
183       AssertIn("%s:" % name, output)
184       for (field, value) in [("valid", mode == _ALL_VALID),
185                              ("hidden", hidden),
186                              ("blacklisted", blacklisted)]:
187         AssertIn("  - %s: %s" % (field, value), output)
188
189       # Only valid OSes should be listed
190       cmd = ["gnt-os", "list", "--no-headers"]
191       output = qa_utils.GetCommandOutput(master["primary"],
192                                          utils.ShellQuoteArgs(cmd))
193       if mode == _ALL_VALID and not (hidden or blacklisted):
194         assert_fn = AssertIn
195       else:
196         assert_fn = AssertNotIn
197       assert_fn(fullname, output.splitlines())
198
199       # Check via RAPI
200       if rapi_cb:
201         assert_fn(fullname, rapi_cb())
202   finally:
203     for node in nodes:
204       _RemoveTempOs(node, dirname)
205
206
207 def TestOsValid(rapi_cb):
208   """Testing valid OS definition"""
209   return _TestOs(_ALL_VALID, rapi_cb)
210
211
212 def TestOsInvalid(rapi_cb):
213   """Testing invalid OS definition"""
214   return _TestOs(_ALL_INVALID, rapi_cb)
215
216
217 def TestOsPartiallyValid(rapi_cb):
218   """Testing partially valid OS definition"""
219   return _TestOs(_PARTIALLY_VALID, rapi_cb)
220
221
222 def TestOsModifyValid():
223   """Testing a valid os modify invocation"""
224   hv_dict = {
225     constants.HT_XEN_PVM: {
226       constants.HV_ROOT_PATH: "/dev/sda5",
227       },
228     constants.HT_XEN_HVM: {
229       constants.HV_ACPI: False,
230       constants.HV_PAE: True,
231       },
232     }
233
234   return _TestOsModify(hv_dict)
235
236
237 def TestOsModifyInvalid():
238   """Testing an invalid os modify invocation"""
239   hv_dict = {
240     "blahblahblubb": {"bar": ""},
241     }
242
243   return _TestOsModify(hv_dict, fail=True)
244
245
246 def TestOsStatesNonExisting():
247   """Testing OS states with non-existing OS"""
248   AssertCommand(["test", "-e", _TEMP_OS_PATH], fail=True)
249   return _TestOsStates(_TEMP_OS_NAME)