Statistics
| Branch: | Tag: | Revision:

root / qa / rapi-workload.py @ 82ce55fa

History | View | Annotate | Download (35.3 kB)

1 56803e14 Hrvoje Ribicic
#!/usr/bin/python -u
2 56803e14 Hrvoje Ribicic
#
3 56803e14 Hrvoje Ribicic
4 56803e14 Hrvoje Ribicic
# Copyright (C) 2013 Google Inc.
5 56803e14 Hrvoje Ribicic
#
6 56803e14 Hrvoje Ribicic
# This program is free software; you can redistribute it and/or modify
7 56803e14 Hrvoje Ribicic
# it under the terms of the GNU General Public License as published by
8 56803e14 Hrvoje Ribicic
# the Free Software Foundation; either version 2 of the License, or
9 56803e14 Hrvoje Ribicic
# (at your option) any later version.
10 56803e14 Hrvoje Ribicic
#
11 56803e14 Hrvoje Ribicic
# This program is distributed in the hope that it will be useful, but
12 56803e14 Hrvoje Ribicic
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 56803e14 Hrvoje Ribicic
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 56803e14 Hrvoje Ribicic
# General Public License for more details.
15 56803e14 Hrvoje Ribicic
#
16 56803e14 Hrvoje Ribicic
# You should have received a copy of the GNU General Public License
17 56803e14 Hrvoje Ribicic
# along with this program; if not, write to the Free Software
18 56803e14 Hrvoje Ribicic
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 56803e14 Hrvoje Ribicic
# 02110-1301, USA.
20 56803e14 Hrvoje Ribicic
21 56803e14 Hrvoje Ribicic
22 56803e14 Hrvoje Ribicic
"""Script for providing a large amount of RAPI calls to Ganeti.
23 56803e14 Hrvoje Ribicic

24 56803e14 Hrvoje Ribicic
"""
25 56803e14 Hrvoje Ribicic
26 56803e14 Hrvoje Ribicic
# pylint: disable=C0103
27 56803e14 Hrvoje Ribicic
# due to invalid name
28 56803e14 Hrvoje Ribicic
29 396c5dfb Hrvoje Ribicic
import inspect
30 82ce55fa Hrvoje Ribicic
import optparse
31 56803e14 Hrvoje Ribicic
import sys
32 396c5dfb Hrvoje Ribicic
import types
33 56803e14 Hrvoje Ribicic
34 6b710ec0 Hrvoje Ribicic
import ganeti.constants as constants
35 c2e22e7b Hrvoje Ribicic
from ganeti.rapi.client import GanetiApiError, NODE_EVAC_PRI, NODE_EVAC_SEC
36 56803e14 Hrvoje Ribicic
37 56803e14 Hrvoje Ribicic
import qa_config
38 17733ecb Hrvoje Ribicic
import qa_error
39 56803e14 Hrvoje Ribicic
import qa_node
40 56803e14 Hrvoje Ribicic
import qa_rapi
41 56803e14 Hrvoje Ribicic
42 56803e14 Hrvoje Ribicic
43 56803e14 Hrvoje Ribicic
# The purpose of this file is to provide a stable and extensive RAPI workload
44 56803e14 Hrvoje Ribicic
# that manipulates the cluster only using RAPI commands, with the assumption
45 56803e14 Hrvoje Ribicic
# that an empty cluster was set up beforehand. All the nodes that can be added
46 56803e14 Hrvoje Ribicic
# to the cluster should be a part of it, and no instances should be present.
47 56803e14 Hrvoje Ribicic
#
48 56803e14 Hrvoje Ribicic
# Its intended use is in RAPI compatibility tests, where different versions with
49 56803e14 Hrvoje Ribicic
# possibly vastly different QAs must be compared. Running the QA on both
50 56803e14 Hrvoje Ribicic
# versions of the cluster will produce RAPI calls, but there is no guarantee
51 56803e14 Hrvoje Ribicic
# that they will match, or that functions invoked in between will not change the
52 56803e14 Hrvoje Ribicic
# results.
53 56803e14 Hrvoje Ribicic
#
54 56803e14 Hrvoje Ribicic
# By using only RAPI functions, we are sure to be able to capture and log all
55 56803e14 Hrvoje Ribicic
# the changes in cluster state, and be able to compare them afterwards.
56 56803e14 Hrvoje Ribicic
#
57 56803e14 Hrvoje Ribicic
# The functionality of the QA is still used to generate a functioning,
58 56803e14 Hrvoje Ribicic
# RAPI-enabled cluster, and to set up a C{GanetiRapiClient} capable of issuing
59 56803e14 Hrvoje Ribicic
# commands to the cluster.
60 56803e14 Hrvoje Ribicic
#
61 56803e14 Hrvoje Ribicic
# Due to the fact that not all calls issued as a part of the workload might be
62 56803e14 Hrvoje Ribicic
# implemented in the different versions of Ganeti, the client does not halt or
63 56803e14 Hrvoje Ribicic
# produce a non-zero exit code upon encountering a RAPI error. Instead, it
64 56803e14 Hrvoje Ribicic
# reports it and moves on. Any utility comparing the requests should account for
65 56803e14 Hrvoje Ribicic
# this.
66 56803e14 Hrvoje Ribicic
67 56803e14 Hrvoje Ribicic
68 56803e14 Hrvoje Ribicic
def MockMethod(*_args, **_kwargs):
69 56803e14 Hrvoje Ribicic
  """ Absorbs all arguments, does nothing, returns None.
70 56803e14 Hrvoje Ribicic

71 56803e14 Hrvoje Ribicic
  """
72 56803e14 Hrvoje Ribicic
  return None
73 56803e14 Hrvoje Ribicic
74 56803e14 Hrvoje Ribicic
75 56803e14 Hrvoje Ribicic
RAPI_USERNAME = "ganeti-qa"
76 56803e14 Hrvoje Ribicic
77 56803e14 Hrvoje Ribicic
78 56803e14 Hrvoje Ribicic
class GanetiRapiClientWrapper(object):
79 56803e14 Hrvoje Ribicic
  """ Creates and initializes a GanetiRapiClient, and acts as a wrapper invoking
80 56803e14 Hrvoje Ribicic
  only the methods that the version of the client actually uses.
81 56803e14 Hrvoje Ribicic

82 56803e14 Hrvoje Ribicic
  """
83 56803e14 Hrvoje Ribicic
  def __init__(self):
84 56803e14 Hrvoje Ribicic
    self._client = qa_rapi.Setup(RAPI_USERNAME,
85 56803e14 Hrvoje Ribicic
                                 qa_rapi.LookupRapiSecret(RAPI_USERNAME))
86 56803e14 Hrvoje Ribicic
87 396c5dfb Hrvoje Ribicic
    self._method_invocations = {}
88 396c5dfb Hrvoje Ribicic
89 396c5dfb Hrvoje Ribicic
  def _RecordMethodInvocation(self, name, arg_dict):
90 396c5dfb Hrvoje Ribicic
    """ Records the invocation of a C{GanetiRAPIClient} method, noting the
91 396c5dfb Hrvoje Ribicic
    argument and the method names.
92 396c5dfb Hrvoje Ribicic

93 396c5dfb Hrvoje Ribicic
    """
94 396c5dfb Hrvoje Ribicic
    if name not in self._method_invocations:
95 396c5dfb Hrvoje Ribicic
      self._method_invocations[name] = set()
96 396c5dfb Hrvoje Ribicic
97 396c5dfb Hrvoje Ribicic
    for named_arg in arg_dict:
98 396c5dfb Hrvoje Ribicic
      self._method_invocations[name].add(named_arg)
99 396c5dfb Hrvoje Ribicic
100 396c5dfb Hrvoje Ribicic
  def _InvokerCreator(self, fn, name):
101 396c5dfb Hrvoje Ribicic
    """ Returns an invoker function that will invoke the given function
102 396c5dfb Hrvoje Ribicic
    with any arguments passed to the invoker at a later time, while
103 396c5dfb Hrvoje Ribicic
    catching any specific non-fatal errors we would like to know more
104 396c5dfb Hrvoje Ribicic
    about.
105 396c5dfb Hrvoje Ribicic

106 396c5dfb Hrvoje Ribicic
    @type fn arbitrary function
107 396c5dfb Hrvoje Ribicic
    @param fn The function to invoke later.
108 396c5dfb Hrvoje Ribicic
    @type name string
109 396c5dfb Hrvoje Ribicic
    @param name The name of the function, for debugging purposes.
110 396c5dfb Hrvoje Ribicic
    @rtype function
111 396c5dfb Hrvoje Ribicic

112 396c5dfb Hrvoje Ribicic
    """
113 396c5dfb Hrvoje Ribicic
    def decoratedFn(*args, **kwargs):
114 396c5dfb Hrvoje Ribicic
      result = None
115 396c5dfb Hrvoje Ribicic
      try:
116 396c5dfb Hrvoje Ribicic
        print "Using method %s" % name
117 396c5dfb Hrvoje Ribicic
        self._RecordMethodInvocation(name, kwargs)
118 396c5dfb Hrvoje Ribicic
        result = fn(*args, **kwargs)
119 396c5dfb Hrvoje Ribicic
      except GanetiApiError as e:
120 396c5dfb Hrvoje Ribicic
        print "RAPI error while performing function %s : %s" % \
121 396c5dfb Hrvoje Ribicic
              (name, str(e))
122 396c5dfb Hrvoje Ribicic
      return result
123 396c5dfb Hrvoje Ribicic
124 396c5dfb Hrvoje Ribicic
    return decoratedFn
125 396c5dfb Hrvoje Ribicic
126 56803e14 Hrvoje Ribicic
  def __getattr__(self, attr):
127 56803e14 Hrvoje Ribicic
    """ Fetches an attribute from the underlying client if necessary.
128 56803e14 Hrvoje Ribicic

129 56803e14 Hrvoje Ribicic
    """
130 56803e14 Hrvoje Ribicic
    # Assuming that this method exposes no public methods of its own,
131 56803e14 Hrvoje Ribicic
    # and that any private methods are named according to the style
132 56803e14 Hrvoje Ribicic
    # guide, this will stop infinite loops in attribute fetches.
133 56803e14 Hrvoje Ribicic
    if attr.startswith("_"):
134 56803e14 Hrvoje Ribicic
      return self.__getattribute__(attr)
135 396c5dfb Hrvoje Ribicic
136 396c5dfb Hrvoje Ribicic
    # We also want to expose non-methods
137 396c5dfb Hrvoje Ribicic
    if hasattr(self._client, attr) and \
138 396c5dfb Hrvoje Ribicic
       not isinstance(getattr(self._client, attr), types.MethodType):
139 396c5dfb Hrvoje Ribicic
      return getattr(self._client, attr)
140 396c5dfb Hrvoje Ribicic
141 56803e14 Hrvoje Ribicic
    try:
142 396c5dfb Hrvoje Ribicic
      return self._InvokerCreator(self._client.__getattribute__(attr), attr)
143 56803e14 Hrvoje Ribicic
    except AttributeError:
144 56803e14 Hrvoje Ribicic
      print "Missing method %s; supplying mock method" % attr
145 56803e14 Hrvoje Ribicic
      return MockMethod
146 56803e14 Hrvoje Ribicic
147 396c5dfb Hrvoje Ribicic
  def _OutputMethodInvocationDetails(self):
148 396c5dfb Hrvoje Ribicic
    """ Attempts to output as much information as possible about the methods
149 396c5dfb Hrvoje Ribicic
    that have and have not been invoked, including which arguments have not
150 396c5dfb Hrvoje Ribicic
    been used.
151 396c5dfb Hrvoje Ribicic

152 396c5dfb Hrvoje Ribicic
    """
153 396c5dfb Hrvoje Ribicic
    print "\nMethod usage:\n"
154 396c5dfb Hrvoje Ribicic
    for method in [n for n in dir(self._client)
155 396c5dfb Hrvoje Ribicic
                     if not n.startswith('_') and
156 396c5dfb Hrvoje Ribicic
                        isinstance(self.__getattr__(n), types.FunctionType)]:
157 396c5dfb Hrvoje Ribicic
      if method not in self._method_invocations:
158 396c5dfb Hrvoje Ribicic
        print "Method unused: %s" % method
159 396c5dfb Hrvoje Ribicic
      else:
160 396c5dfb Hrvoje Ribicic
        arg_spec, _, _, default_arg_spec = \
161 396c5dfb Hrvoje Ribicic
          inspect.getargspec(getattr(self._client, method))
162 396c5dfb Hrvoje Ribicic
        default_args = []
163 396c5dfb Hrvoje Ribicic
        if default_arg_spec is not None:
164 396c5dfb Hrvoje Ribicic
          default_args = arg_spec[-len(default_arg_spec):]
165 396c5dfb Hrvoje Ribicic
        used_arg_set = self._method_invocations[method]
166 396c5dfb Hrvoje Ribicic
        unused_args = [arg for arg in default_args if arg not in used_arg_set]
167 396c5dfb Hrvoje Ribicic
        if unused_args:
168 396c5dfb Hrvoje Ribicic
          print "Method %s used, but arguments unused: %s" % \
169 396c5dfb Hrvoje Ribicic
                (method, ", ".join(unused_args))
170 396c5dfb Hrvoje Ribicic
171 56803e14 Hrvoje Ribicic
172 b87948f5 Hrvoje Ribicic
def Finish(client, fn, *args, **kwargs):
173 b87948f5 Hrvoje Ribicic
  """ When invoked with a job-starting RAPI client method, it passes along any
174 b87948f5 Hrvoje Ribicic
  additional arguments and waits until its completion.
175 b87948f5 Hrvoje Ribicic

176 b87948f5 Hrvoje Ribicic
  @type client C{GanetiRapiClientWrapper}
177 b87948f5 Hrvoje Ribicic
  @param client The client wrapper.
178 b87948f5 Hrvoje Ribicic
  @type fn function
179 b87948f5 Hrvoje Ribicic
  @param fn A client method returning a job id.
180 b87948f5 Hrvoje Ribicic

181 e5351ee9 Hrvoje Ribicic
  @rtype tuple of bool, any object
182 e5351ee9 Hrvoje Ribicic
  @return The success status and the result of the operation, if any
183 e5351ee9 Hrvoje Ribicic

184 b87948f5 Hrvoje Ribicic
  """
185 b87948f5 Hrvoje Ribicic
  possible_job_id = fn(*args, **kwargs)
186 b87948f5 Hrvoje Ribicic
  try:
187 b87948f5 Hrvoje Ribicic
    # The job ids are returned as both ints and ints represented by strings.
188 b87948f5 Hrvoje Ribicic
    # This is a pythonic check to see if the content is an int.
189 b87948f5 Hrvoje Ribicic
    int(possible_job_id)
190 b87948f5 Hrvoje Ribicic
  except (ValueError, TypeError):
191 b87948f5 Hrvoje Ribicic
    # As a rule of thumb, failures will return None, and other methods are
192 b87948f5 Hrvoje Ribicic
    # expected to return at least something
193 b87948f5 Hrvoje Ribicic
    if possible_job_id is not None:
194 b87948f5 Hrvoje Ribicic
      print ("Finish called with a method not producing a job id, "
195 b87948f5 Hrvoje Ribicic
             "returning %s" % possible_job_id)
196 b87948f5 Hrvoje Ribicic
    return possible_job_id
197 b87948f5 Hrvoje Ribicic
198 b87948f5 Hrvoje Ribicic
  success = client.WaitForJobCompletion(possible_job_id)
199 b87948f5 Hrvoje Ribicic
200 b87948f5 Hrvoje Ribicic
  result = client.GetJobStatus(possible_job_id)["opresult"][0]
201 b87948f5 Hrvoje Ribicic
  if success:
202 e5351ee9 Hrvoje Ribicic
    return success, result
203 b87948f5 Hrvoje Ribicic
  else:
204 b87948f5 Hrvoje Ribicic
    print "Error encountered while performing operation: "
205 b87948f5 Hrvoje Ribicic
    print result
206 e5351ee9 Hrvoje Ribicic
    return success, None
207 b87948f5 Hrvoje Ribicic
208 b87948f5 Hrvoje Ribicic
209 9f22ba9a Hrvoje Ribicic
def TestTags(client, get_fn, add_fn, delete_fn, *args):
210 9f22ba9a Hrvoje Ribicic
  """ Tests whether tagging works.
211 9f22ba9a Hrvoje Ribicic

212 9f22ba9a Hrvoje Ribicic
  @type client C{GanetiRapiClientWrapper}
213 9f22ba9a Hrvoje Ribicic
  @param client The client wrapper.
214 9f22ba9a Hrvoje Ribicic
  @type get_fn function
215 9f22ba9a Hrvoje Ribicic
  @param get_fn A Get*Tags function of the client.
216 9f22ba9a Hrvoje Ribicic
  @type add_fn function
217 9f22ba9a Hrvoje Ribicic
  @param add_fn An Add*Tags function of the client.
218 9f22ba9a Hrvoje Ribicic
  @type delete_fn function
219 9f22ba9a Hrvoje Ribicic
  @param delete_fn A Delete*Tags function of the client.
220 9f22ba9a Hrvoje Ribicic

221 9f22ba9a Hrvoje Ribicic
  To allow this method to work for all tagging functions of the client, use
222 9f22ba9a Hrvoje Ribicic
  named methods.
223 9f22ba9a Hrvoje Ribicic

224 9f22ba9a Hrvoje Ribicic
  """
225 9f22ba9a Hrvoje Ribicic
  get_fn(*args)
226 9f22ba9a Hrvoje Ribicic
227 9f22ba9a Hrvoje Ribicic
  tags = ["tag1", "tag2", "tag3"]
228 9f22ba9a Hrvoje Ribicic
  Finish(client, add_fn, *args, tags=tags, dry_run=True)
229 9f22ba9a Hrvoje Ribicic
  Finish(client, add_fn, *args, tags=tags)
230 9f22ba9a Hrvoje Ribicic
231 9f22ba9a Hrvoje Ribicic
  get_fn(*args)
232 9f22ba9a Hrvoje Ribicic
233 9f22ba9a Hrvoje Ribicic
  Finish(client, delete_fn, *args, tags=tags[:1], dry_run=True)
234 9f22ba9a Hrvoje Ribicic
  Finish(client, delete_fn, *args, tags=tags[:1])
235 9f22ba9a Hrvoje Ribicic
236 9f22ba9a Hrvoje Ribicic
  get_fn(*args)
237 9f22ba9a Hrvoje Ribicic
238 9f22ba9a Hrvoje Ribicic
  Finish(client, delete_fn, *args, tags=tags[1:])
239 9f22ba9a Hrvoje Ribicic
240 9f22ba9a Hrvoje Ribicic
  get_fn(*args)
241 9f22ba9a Hrvoje Ribicic
242 9f22ba9a Hrvoje Ribicic
243 a9e3e04d Hrvoje Ribicic
def TestGetters(client):
244 a9e3e04d Hrvoje Ribicic
  """ Tests the various get functions which only retrieve information about the
245 a9e3e04d Hrvoje Ribicic
  cluster.
246 56803e14 Hrvoje Ribicic

247 56803e14 Hrvoje Ribicic
  @type client C{GanetiRapiClientWrapper}
248 56803e14 Hrvoje Ribicic

249 56803e14 Hrvoje Ribicic
  """
250 94981c7a Hrvoje Ribicic
  client.GetVersion()
251 94981c7a Hrvoje Ribicic
  client.GetFeatures()
252 94981c7a Hrvoje Ribicic
  client.GetOperatingSystems()
253 94981c7a Hrvoje Ribicic
  client.GetInfo()
254 94981c7a Hrvoje Ribicic
  client.GetClusterTags()
255 94981c7a Hrvoje Ribicic
  client.GetInstances()
256 94981c7a Hrvoje Ribicic
  client.GetInstances(bulk=True)
257 94981c7a Hrvoje Ribicic
  client.GetJobs()
258 94981c7a Hrvoje Ribicic
  client.GetJobs(bulk=True)
259 94981c7a Hrvoje Ribicic
  client.GetNodes()
260 94981c7a Hrvoje Ribicic
  client.GetNodes(bulk=True)
261 94981c7a Hrvoje Ribicic
  client.GetNetworks()
262 94981c7a Hrvoje Ribicic
  client.GetNetworks(bulk=True)
263 94981c7a Hrvoje Ribicic
  client.GetGroups()
264 94981c7a Hrvoje Ribicic
  client.GetGroups(bulk=True)
265 94981c7a Hrvoje Ribicic
266 a9e3e04d Hrvoje Ribicic
267 9749bd5e Hrvoje Ribicic
def TestQueries(client, resource_name):
268 9749bd5e Hrvoje Ribicic
  """ Finds out which fields are present for a given resource type, and attempts
269 9749bd5e Hrvoje Ribicic
  to retrieve their values for all present resources.
270 9749bd5e Hrvoje Ribicic

271 9749bd5e Hrvoje Ribicic
  @type client C{GanetiRapiClientWrapper}
272 9749bd5e Hrvoje Ribicic
  @param client A wrapped RAPI client.
273 9749bd5e Hrvoje Ribicic
  @type resource_name string
274 9749bd5e Hrvoje Ribicic
  @param resource_name The name of the resource to use.
275 9749bd5e Hrvoje Ribicic

276 9749bd5e Hrvoje Ribicic
  """
277 9749bd5e Hrvoje Ribicic
278 9749bd5e Hrvoje Ribicic
  FIELDS_KEY = "fields"
279 9749bd5e Hrvoje Ribicic
280 9749bd5e Hrvoje Ribicic
  query_res = client.QueryFields(resource_name)
281 9749bd5e Hrvoje Ribicic
282 9749bd5e Hrvoje Ribicic
  if query_res is None or FIELDS_KEY not in query_res or \
283 9749bd5e Hrvoje Ribicic
    len(query_res[FIELDS_KEY]) == 0:
284 9749bd5e Hrvoje Ribicic
    return
285 9749bd5e Hrvoje Ribicic
286 9749bd5e Hrvoje Ribicic
  field_entries = query_res[FIELDS_KEY]
287 9749bd5e Hrvoje Ribicic
288 9749bd5e Hrvoje Ribicic
  fields = map(lambda e: e["name"], field_entries)
289 9749bd5e Hrvoje Ribicic
290 9749bd5e Hrvoje Ribicic
  client.Query(resource_name, fields)
291 9749bd5e Hrvoje Ribicic
292 9749bd5e Hrvoje Ribicic
293 4236968a Hrvoje Ribicic
def TestQueryFiltering(client, master_name):
294 4236968a Hrvoje Ribicic
  """ Performs queries by playing around with the only guaranteed resource, the
295 4236968a Hrvoje Ribicic
  master node.
296 4236968a Hrvoje Ribicic

297 4236968a Hrvoje Ribicic
  @type client C{GanetiRapiClientWrapper}
298 4236968a Hrvoje Ribicic
  @param client A wrapped RAPI client.
299 4236968a Hrvoje Ribicic
  @type master_name string
300 4236968a Hrvoje Ribicic
  @param master_name The hostname of the master node.
301 4236968a Hrvoje Ribicic

302 4236968a Hrvoje Ribicic
  """
303 4236968a Hrvoje Ribicic
  client.Query("node", ["name"],
304 4236968a Hrvoje Ribicic
               ["|",
305 4236968a Hrvoje Ribicic
                ["=", "name", master_name],
306 4236968a Hrvoje Ribicic
                [">", "dtotal", 0],
307 4236968a Hrvoje Ribicic
               ])
308 4236968a Hrvoje Ribicic
309 4236968a Hrvoje Ribicic
  client.Query("instance", ["name"],
310 4236968a Hrvoje Ribicic
               ["|",
311 4236968a Hrvoje Ribicic
                ["=", "name", "NonexistentInstance"],
312 4236968a Hrvoje Ribicic
                [">", "oper_ram", 0],
313 4236968a Hrvoje Ribicic
               ])
314 4236968a Hrvoje Ribicic
315 4236968a Hrvoje Ribicic
316 a9e3e04d Hrvoje Ribicic
def RemoveAllInstances(client):
317 a9e3e04d Hrvoje Ribicic
  """ Queries for a list of instances, then removes them all.
318 a9e3e04d Hrvoje Ribicic

319 a9e3e04d Hrvoje Ribicic
  @type client C{GanetiRapiClientWrapper}
320 a9e3e04d Hrvoje Ribicic
  @param client A wrapped RAPI client.
321 a9e3e04d Hrvoje Ribicic

322 a9e3e04d Hrvoje Ribicic
  """
323 a9e3e04d Hrvoje Ribicic
  instances = client.GetInstances()
324 a9e3e04d Hrvoje Ribicic
  for inst in instances:
325 a9e3e04d Hrvoje Ribicic
    Finish(client, client.DeleteInstance, inst)
326 a9e3e04d Hrvoje Ribicic
327 a9e3e04d Hrvoje Ribicic
  instances = client.GetInstances()
328 a9e3e04d Hrvoje Ribicic
  assert len(instances) == 0
329 a9e3e04d Hrvoje Ribicic
330 a9e3e04d Hrvoje Ribicic
331 a9e3e04d Hrvoje Ribicic
def TestSingleInstance(client, instance_name, alternate_name, node_one,
332 a9e3e04d Hrvoje Ribicic
                       node_two):
333 a9e3e04d Hrvoje Ribicic
  """ Creates an instance, performs operations involving it, and then deletes
334 a9e3e04d Hrvoje Ribicic
  it.
335 a9e3e04d Hrvoje Ribicic

336 a9e3e04d Hrvoje Ribicic
  @type client C{GanetiRapiClientWrapper}
337 a9e3e04d Hrvoje Ribicic
  @param client A wrapped RAPI client.
338 a9e3e04d Hrvoje Ribicic
  @type instance_name string
339 a9e3e04d Hrvoje Ribicic
  @param instance_name The hostname to use.
340 a9e3e04d Hrvoje Ribicic
  @type instance_name string
341 a9e3e04d Hrvoje Ribicic
  @param instance_name Another valid hostname to use.
342 a9e3e04d Hrvoje Ribicic
  @type node_one string
343 a9e3e04d Hrvoje Ribicic
  @param node_one A node on which an instance can be added.
344 a9e3e04d Hrvoje Ribicic
  @type node_two string
345 a9e3e04d Hrvoje Ribicic
  @param node_two A node on which an instance can be added.
346 a9e3e04d Hrvoje Ribicic

347 a9e3e04d Hrvoje Ribicic
  """
348 a9e3e04d Hrvoje Ribicic
349 a9e3e04d Hrvoje Ribicic
  # Check that a dry run works, use string with size and unit
350 a9e3e04d Hrvoje Ribicic
  Finish(client, client.CreateInstance,
351 a9e3e04d Hrvoje Ribicic
         "create", instance_name, "plain", [{"size":"1gb"}], [], dry_run=True,
352 a9e3e04d Hrvoje Ribicic
          os="debian-image", pnode=node_one)
353 a9e3e04d Hrvoje Ribicic
354 a9e3e04d Hrvoje Ribicic
  # Another dry run, numeric size, should work, but still a dry run
355 a9e3e04d Hrvoje Ribicic
  Finish(client, client.CreateInstance,
356 a9e3e04d Hrvoje Ribicic
         "create", instance_name, "plain", [{"size": "1000"}], [{}],
357 a9e3e04d Hrvoje Ribicic
         dry_run=True, os="debian-image", pnode=node_one)
358 a9e3e04d Hrvoje Ribicic
359 a9e3e04d Hrvoje Ribicic
  # Create a smaller instance, and delete it immediately
360 a9e3e04d Hrvoje Ribicic
  Finish(client, client.CreateInstance,
361 a9e3e04d Hrvoje Ribicic
         "create", instance_name, "plain", [{"size":800}], [{}],
362 a9e3e04d Hrvoje Ribicic
         os="debian-image", pnode=node_one)
363 a9e3e04d Hrvoje Ribicic
364 a9e3e04d Hrvoje Ribicic
  Finish(client, client.DeleteInstance, instance_name)
365 a9e3e04d Hrvoje Ribicic
366 a9e3e04d Hrvoje Ribicic
  # Create one instance to use in further tests
367 a9e3e04d Hrvoje Ribicic
  Finish(client, client.CreateInstance,
368 a9e3e04d Hrvoje Ribicic
         "create", instance_name, "plain", [{"size":1200}], [{}],
369 a9e3e04d Hrvoje Ribicic
         os="debian-image", pnode=node_one)
370 a9e3e04d Hrvoje Ribicic
371 a9e3e04d Hrvoje Ribicic
  client.GetInstance(instance_name)
372 a9e3e04d Hrvoje Ribicic
373 a9e3e04d Hrvoje Ribicic
  Finish(client, client.GetInstanceInfo, instance_name)
374 a9e3e04d Hrvoje Ribicic
375 a9e3e04d Hrvoje Ribicic
  Finish(client, client.GetInstanceInfo, instance_name, static=True)
376 a9e3e04d Hrvoje Ribicic
377 9749bd5e Hrvoje Ribicic
  TestQueries(client, "instance")
378 9749bd5e Hrvoje Ribicic
379 a9e3e04d Hrvoje Ribicic
  TestTags(client, client.GetInstanceTags, client.AddInstanceTags,
380 a9e3e04d Hrvoje Ribicic
           client.DeleteInstanceTags, instance_name)
381 a9e3e04d Hrvoje Ribicic
382 a9e3e04d Hrvoje Ribicic
  Finish(client, client.GrowInstanceDisk,
383 a9e3e04d Hrvoje Ribicic
         instance_name, 0, 100, wait_for_sync=True)
384 a9e3e04d Hrvoje Ribicic
385 a9e3e04d Hrvoje Ribicic
  Finish(client, client.RebootInstance,
386 a9e3e04d Hrvoje Ribicic
         instance_name, "soft", ignore_secondaries=True, dry_run=True,
387 a9e3e04d Hrvoje Ribicic
         reason="Hulk smash gently!")
388 a9e3e04d Hrvoje Ribicic
389 a9e3e04d Hrvoje Ribicic
  Finish(client, client.ShutdownInstance,
390 a9e3e04d Hrvoje Ribicic
         instance_name, dry_run=True, no_remember=False,
391 a9e3e04d Hrvoje Ribicic
         reason="Hulk smash hard!")
392 a9e3e04d Hrvoje Ribicic
393 a9e3e04d Hrvoje Ribicic
  Finish(client, client.StartupInstance,
394 a9e3e04d Hrvoje Ribicic
         instance_name, dry_run=True, no_remember=False,
395 a9e3e04d Hrvoje Ribicic
         reason="Not hard enough!")
396 a9e3e04d Hrvoje Ribicic
397 a9e3e04d Hrvoje Ribicic
  Finish(client, client.RebootInstance,
398 a9e3e04d Hrvoje Ribicic
         instance_name, "soft", ignore_secondaries=True, dry_run=False)
399 a9e3e04d Hrvoje Ribicic
400 a9e3e04d Hrvoje Ribicic
  Finish(client, client.ShutdownInstance,
401 a9e3e04d Hrvoje Ribicic
         instance_name, dry_run=False, no_remember=False)
402 a9e3e04d Hrvoje Ribicic
403 a9e3e04d Hrvoje Ribicic
  Finish(client, client.ModifyInstance,
404 a9e3e04d Hrvoje Ribicic
         instance_name, disk_template="drbd", remote_node=node_two)
405 a9e3e04d Hrvoje Ribicic
406 a9e3e04d Hrvoje Ribicic
  Finish(client, client.ModifyInstance,
407 a9e3e04d Hrvoje Ribicic
         instance_name, disk_template="plain")
408 a9e3e04d Hrvoje Ribicic
409 a9e3e04d Hrvoje Ribicic
  Finish(client, client.RenameInstance,
410 a9e3e04d Hrvoje Ribicic
         instance_name, alternate_name, ip_check=True, name_check=True)
411 a9e3e04d Hrvoje Ribicic
412 a9e3e04d Hrvoje Ribicic
  Finish(client, client.RenameInstance, alternate_name, instance_name)
413 a9e3e04d Hrvoje Ribicic
414 a9e3e04d Hrvoje Ribicic
  Finish(client, client.DeactivateInstanceDisks, instance_name)
415 a9e3e04d Hrvoje Ribicic
416 a9e3e04d Hrvoje Ribicic
  Finish(client, client.ActivateInstanceDisks, instance_name)
417 a9e3e04d Hrvoje Ribicic
418 89d52c9a Hrvoje Ribicic
  # Note that the RecreateInstanceDisks command will always fail, as there is
419 89d52c9a Hrvoje Ribicic
  # no way to induce the necessary prerequisites (removal of LV) via RAPI.
420 89d52c9a Hrvoje Ribicic
  # Keeping it around allows us to at least know that it still exists.
421 a9e3e04d Hrvoje Ribicic
  Finish(client, client.RecreateInstanceDisks,
422 a9e3e04d Hrvoje Ribicic
         instance_name, [0], [node_one])
423 a9e3e04d Hrvoje Ribicic
424 a9e3e04d Hrvoje Ribicic
  Finish(client, client.StartupInstance,
425 a9e3e04d Hrvoje Ribicic
         instance_name, dry_run=False, no_remember=False)
426 a9e3e04d Hrvoje Ribicic
427 a9e3e04d Hrvoje Ribicic
  client.GetInstanceConsole(instance_name)
428 a9e3e04d Hrvoje Ribicic
429 a9e3e04d Hrvoje Ribicic
  Finish(client, client.ReinstallInstance,
430 a9e3e04d Hrvoje Ribicic
         instance_name, os=None, no_startup=False, osparams={})
431 a9e3e04d Hrvoje Ribicic
432 a9e3e04d Hrvoje Ribicic
  Finish(client, client.DeleteInstance, instance_name, dry_run=True)
433 a9e3e04d Hrvoje Ribicic
434 a9e3e04d Hrvoje Ribicic
  Finish(client, client.DeleteInstance, instance_name)
435 a9e3e04d Hrvoje Ribicic
436 a9e3e04d Hrvoje Ribicic
437 6b710ec0 Hrvoje Ribicic
def MarkUnmarkNode(client, node, state):
438 6b710ec0 Hrvoje Ribicic
  """ Given a certain node state, marks a node as being in that state, and then
439 6b710ec0 Hrvoje Ribicic
  unmarks it.
440 6b710ec0 Hrvoje Ribicic

441 6b710ec0 Hrvoje Ribicic
  @type client C{GanetiRapiClientWrapper}
442 6b710ec0 Hrvoje Ribicic
  @param client A wrapped RAPI client.
443 6b710ec0 Hrvoje Ribicic
  @type node string
444 6b710ec0 Hrvoje Ribicic
  @type state string
445 6b710ec0 Hrvoje Ribicic

446 6b710ec0 Hrvoje Ribicic
  """
447 6b710ec0 Hrvoje Ribicic
  # pylint: disable=W0142
448 6b710ec0 Hrvoje Ribicic
  Finish(client, client.ModifyNode, node, **{state: True})
449 6b710ec0 Hrvoje Ribicic
  Finish(client, client.ModifyNode, node, **{state: False})
450 6b710ec0 Hrvoje Ribicic
  # pylint: enable=W0142
451 6b710ec0 Hrvoje Ribicic
452 6b710ec0 Hrvoje Ribicic
453 6b710ec0 Hrvoje Ribicic
def TestNodeOperations(client, non_master_node):
454 6b710ec0 Hrvoje Ribicic
  """ Tests various operations related to nodes only
455 6b710ec0 Hrvoje Ribicic

456 6b710ec0 Hrvoje Ribicic
  @type client C{GanetiRapiClientWrapper}
457 6b710ec0 Hrvoje Ribicic
  @param client A wrapped RAPI client.
458 6b710ec0 Hrvoje Ribicic
  @type non_master_node string
459 6b710ec0 Hrvoje Ribicic
  @param non_master_node The name of a non-master node in the cluster.
460 6b710ec0 Hrvoje Ribicic

461 6b710ec0 Hrvoje Ribicic
  """
462 6b710ec0 Hrvoje Ribicic
463 6b710ec0 Hrvoje Ribicic
  client.GetNode(non_master_node)
464 6b710ec0 Hrvoje Ribicic
465 6b710ec0 Hrvoje Ribicic
  old_role = client.GetNodeRole(non_master_node)
466 6b710ec0 Hrvoje Ribicic
467 6b710ec0 Hrvoje Ribicic
  # Should fail
468 6b710ec0 Hrvoje Ribicic
  Finish(client, client.SetNodeRole,
469 6b710ec0 Hrvoje Ribicic
         non_master_node, "master", False, auto_promote=True)
470 6b710ec0 Hrvoje Ribicic
471 6b710ec0 Hrvoje Ribicic
  Finish(client, client.SetNodeRole,
472 6b710ec0 Hrvoje Ribicic
         non_master_node, "regular", False, auto_promote=True)
473 6b710ec0 Hrvoje Ribicic
474 6b710ec0 Hrvoje Ribicic
  Finish(client, client.SetNodeRole,
475 6b710ec0 Hrvoje Ribicic
         non_master_node, "master-candidate", False, auto_promote=True)
476 6b710ec0 Hrvoje Ribicic
477 6b710ec0 Hrvoje Ribicic
  Finish(client, client.SetNodeRole,
478 6b710ec0 Hrvoje Ribicic
         non_master_node, "drained", False, auto_promote=True)
479 6b710ec0 Hrvoje Ribicic
480 6b710ec0 Hrvoje Ribicic
  Finish(client, client.SetNodeRole,
481 6b710ec0 Hrvoje Ribicic
         non_master_node, old_role, False, auto_promote=True)
482 6b710ec0 Hrvoje Ribicic
483 6b710ec0 Hrvoje Ribicic
  Finish(client, client.PowercycleNode,
484 6b710ec0 Hrvoje Ribicic
         non_master_node, force=False)
485 6b710ec0 Hrvoje Ribicic
486 6b710ec0 Hrvoje Ribicic
  storage_units_fields = [
487 6b710ec0 Hrvoje Ribicic
    "name", "allocatable", "free", "node", "size", "type", "used",
488 6b710ec0 Hrvoje Ribicic
  ]
489 6b710ec0 Hrvoje Ribicic
490 6b710ec0 Hrvoje Ribicic
  for storage_type in constants.STS_REPORT:
491 e5351ee9 Hrvoje Ribicic
    success, storage_units = Finish(client, client.GetNodeStorageUnits,
492 e5351ee9 Hrvoje Ribicic
                                    non_master_node, storage_type,
493 e5351ee9 Hrvoje Ribicic
                                    ",".join(storage_units_fields))
494 6b710ec0 Hrvoje Ribicic
495 e5351ee9 Hrvoje Ribicic
    if success and len(storage_units) > 0 and len(storage_units[0]) > 0:
496 6b710ec0 Hrvoje Ribicic
      # Name is the first entry of the first result, allocatable the other
497 6b710ec0 Hrvoje Ribicic
      unit_name = storage_units[0][0]
498 6b710ec0 Hrvoje Ribicic
      Finish(client, client.ModifyNodeStorageUnits,
499 6b710ec0 Hrvoje Ribicic
             non_master_node, storage_type, unit_name,
500 6b710ec0 Hrvoje Ribicic
             allocatable=not storage_units[0][1])
501 6b710ec0 Hrvoje Ribicic
      Finish(client, client.ModifyNodeStorageUnits,
502 6b710ec0 Hrvoje Ribicic
             non_master_node, storage_type, unit_name,
503 6b710ec0 Hrvoje Ribicic
             allocatable=storage_units[0][1])
504 6b710ec0 Hrvoje Ribicic
      Finish(client, client.RepairNodeStorageUnits,
505 6b710ec0 Hrvoje Ribicic
             non_master_node, storage_type, unit_name)
506 6b710ec0 Hrvoje Ribicic
507 6b710ec0 Hrvoje Ribicic
  MarkUnmarkNode(client, non_master_node, "drained")
508 6b710ec0 Hrvoje Ribicic
  MarkUnmarkNode(client, non_master_node, "powered")
509 6b710ec0 Hrvoje Ribicic
  MarkUnmarkNode(client, non_master_node, "offline")
510 6b710ec0 Hrvoje Ribicic
511 9749bd5e Hrvoje Ribicic
  TestQueries(client, "node")
512 9749bd5e Hrvoje Ribicic
513 6b710ec0 Hrvoje Ribicic
514 1086027a Hrvoje Ribicic
def TestGroupOperations(client, node, another_node):
515 1086027a Hrvoje Ribicic
  """ Tests various operations related to groups only.
516 1086027a Hrvoje Ribicic

517 1086027a Hrvoje Ribicic
  @type client C{GanetiRapiClientWrapper}
518 1086027a Hrvoje Ribicic
  @param client A Ganeti RAPI client to use.
519 1086027a Hrvoje Ribicic
  @type node string
520 1086027a Hrvoje Ribicic
  @param node The name of a node in the cluster.
521 1086027a Hrvoje Ribicic
  @type another_node string
522 1086027a Hrvoje Ribicic
  @param another_node The name of another node in the cluster.
523 1086027a Hrvoje Ribicic

524 1086027a Hrvoje Ribicic
  """
525 1086027a Hrvoje Ribicic
526 1086027a Hrvoje Ribicic
  DEFAULT_GROUP_NAME = constants.INITIAL_NODE_GROUP_NAME
527 1086027a Hrvoje Ribicic
  TEST_GROUP_NAME = "TestGroup"
528 1086027a Hrvoje Ribicic
  ALTERNATE_GROUP_NAME = "RenamedTestGroup"
529 1086027a Hrvoje Ribicic
530 1086027a Hrvoje Ribicic
  Finish(client, client.CreateGroup,
531 1086027a Hrvoje Ribicic
         TEST_GROUP_NAME, alloc_policy=constants.ALLOC_POLICY_PREFERRED,
532 1086027a Hrvoje Ribicic
         dry_run=True)
533 1086027a Hrvoje Ribicic
534 1086027a Hrvoje Ribicic
  Finish(client, client.CreateGroup,
535 1086027a Hrvoje Ribicic
         TEST_GROUP_NAME, alloc_policy=constants.ALLOC_POLICY_PREFERRED)
536 1086027a Hrvoje Ribicic
537 1086027a Hrvoje Ribicic
  client.GetGroup(TEST_GROUP_NAME)
538 1086027a Hrvoje Ribicic
539 9749bd5e Hrvoje Ribicic
  TestQueries(client, "group")
540 9749bd5e Hrvoje Ribicic
541 1086027a Hrvoje Ribicic
  TestTags(client, client.GetGroupTags, client.AddGroupTags,
542 1086027a Hrvoje Ribicic
           client.DeleteGroupTags, TEST_GROUP_NAME)
543 1086027a Hrvoje Ribicic
544 1086027a Hrvoje Ribicic
  Finish(client, client.ModifyGroup,
545 1086027a Hrvoje Ribicic
         TEST_GROUP_NAME, alloc_policy=constants.ALLOC_POLICY_PREFERRED,
546 1086027a Hrvoje Ribicic
         depends=None)
547 1086027a Hrvoje Ribicic
548 1086027a Hrvoje Ribicic
  Finish(client, client.AssignGroupNodes,
549 1086027a Hrvoje Ribicic
         TEST_GROUP_NAME, [node, another_node], force=False, dry_run=True)
550 1086027a Hrvoje Ribicic
551 1086027a Hrvoje Ribicic
  Finish(client, client.AssignGroupNodes,
552 1086027a Hrvoje Ribicic
         TEST_GROUP_NAME, [another_node], force=False)
553 1086027a Hrvoje Ribicic
554 1086027a Hrvoje Ribicic
  Finish(client, client.RenameGroup,
555 1086027a Hrvoje Ribicic
         TEST_GROUP_NAME, ALTERNATE_GROUP_NAME)
556 1086027a Hrvoje Ribicic
557 1086027a Hrvoje Ribicic
  Finish(client, client.RenameGroup,
558 1086027a Hrvoje Ribicic
         ALTERNATE_GROUP_NAME, TEST_GROUP_NAME)
559 1086027a Hrvoje Ribicic
560 1086027a Hrvoje Ribicic
  Finish(client, client.AssignGroupNodes,
561 1086027a Hrvoje Ribicic
         DEFAULT_GROUP_NAME, [another_node], force=False)
562 1086027a Hrvoje Ribicic
563 1086027a Hrvoje Ribicic
  Finish(client, client.DeleteGroup, TEST_GROUP_NAME, dry_run=True)
564 1086027a Hrvoje Ribicic
565 1086027a Hrvoje Ribicic
  Finish(client, client.DeleteGroup, TEST_GROUP_NAME)
566 1086027a Hrvoje Ribicic
567 1086027a Hrvoje Ribicic
568 82a8bf3e Hrvoje Ribicic
def TestNetworkConnectDisconnect(client, network_name, mode, link):
569 82a8bf3e Hrvoje Ribicic
  """ Test connecting and disconnecting the network to a new node group.
570 82a8bf3e Hrvoje Ribicic

571 82a8bf3e Hrvoje Ribicic
  @type network_name string
572 82a8bf3e Hrvoje Ribicic
  @param network_name The name of an existing and unconnected network.
573 82a8bf3e Hrvoje Ribicic
  @type mode string
574 82a8bf3e Hrvoje Ribicic
  @param mode The network mode.
575 82a8bf3e Hrvoje Ribicic
  @type link string
576 82a8bf3e Hrvoje Ribicic
  @param link The network link.
577 82a8bf3e Hrvoje Ribicic

578 82a8bf3e Hrvoje Ribicic
  """
579 82a8bf3e Hrvoje Ribicic
  # For testing the connect/disconnect calls, a group is needed
580 82a8bf3e Hrvoje Ribicic
  TEST_GROUP_NAME = "TestGroup"
581 82a8bf3e Hrvoje Ribicic
  Finish(client, client.CreateGroup,
582 82a8bf3e Hrvoje Ribicic
         TEST_GROUP_NAME, alloc_policy=constants.ALLOC_POLICY_PREFERRED)
583 82a8bf3e Hrvoje Ribicic
584 82a8bf3e Hrvoje Ribicic
  Finish(client, client.ConnectNetwork,
585 82a8bf3e Hrvoje Ribicic
         network_name, TEST_GROUP_NAME, mode, link, dry_run=True)
586 82a8bf3e Hrvoje Ribicic
587 82a8bf3e Hrvoje Ribicic
  Finish(client, client.ConnectNetwork,
588 82a8bf3e Hrvoje Ribicic
         network_name, TEST_GROUP_NAME, mode, link)
589 82a8bf3e Hrvoje Ribicic
590 82a8bf3e Hrvoje Ribicic
  Finish(client, client.DisconnectNetwork,
591 82a8bf3e Hrvoje Ribicic
         network_name, TEST_GROUP_NAME, dry_run=True)
592 82a8bf3e Hrvoje Ribicic
593 82a8bf3e Hrvoje Ribicic
  Finish(client, client.DisconnectNetwork,
594 82a8bf3e Hrvoje Ribicic
         network_name, TEST_GROUP_NAME)
595 82a8bf3e Hrvoje Ribicic
596 82a8bf3e Hrvoje Ribicic
  # Clean up the group
597 82a8bf3e Hrvoje Ribicic
  Finish(client, client.DeleteGroup, TEST_GROUP_NAME)
598 82a8bf3e Hrvoje Ribicic
599 82a8bf3e Hrvoje Ribicic
600 82a8bf3e Hrvoje Ribicic
def TestNetworks(client):
601 82a8bf3e Hrvoje Ribicic
  """ Add some networks of different sizes, using RFC5737 addresses like in the
602 82a8bf3e Hrvoje Ribicic
  QA.
603 82a8bf3e Hrvoje Ribicic

604 82a8bf3e Hrvoje Ribicic
  """
605 82a8bf3e Hrvoje Ribicic
606 82a8bf3e Hrvoje Ribicic
  NETWORK_NAME = "SurelyCertainlyNonexistentNetwork"
607 82a8bf3e Hrvoje Ribicic
608 82a8bf3e Hrvoje Ribicic
  Finish(client, client.CreateNetwork,
609 82a8bf3e Hrvoje Ribicic
         NETWORK_NAME, "192.0.2.0/30", tags=[], dry_run=True)
610 82a8bf3e Hrvoje Ribicic
611 82a8bf3e Hrvoje Ribicic
  Finish(client, client.CreateNetwork,
612 82a8bf3e Hrvoje Ribicic
         NETWORK_NAME, "192.0.2.0/30", tags=[])
613 82a8bf3e Hrvoje Ribicic
614 82a8bf3e Hrvoje Ribicic
  client.GetNetwork(NETWORK_NAME)
615 82a8bf3e Hrvoje Ribicic
616 82a8bf3e Hrvoje Ribicic
  TestTags(client, client.GetNetworkTags, client.AddNetworkTags,
617 82a8bf3e Hrvoje Ribicic
           client.DeleteNetworkTags, NETWORK_NAME)
618 82a8bf3e Hrvoje Ribicic
619 82a8bf3e Hrvoje Ribicic
  Finish(client, client.ModifyNetwork,
620 82a8bf3e Hrvoje Ribicic
         NETWORK_NAME, mac_prefix=None)
621 82a8bf3e Hrvoje Ribicic
622 82a8bf3e Hrvoje Ribicic
  TestQueries(client, "network")
623 82a8bf3e Hrvoje Ribicic
624 82a8bf3e Hrvoje Ribicic
  default_nicparams = qa_config.get("default-nicparams", None)
625 82a8bf3e Hrvoje Ribicic
626 82a8bf3e Hrvoje Ribicic
  # The entry might not be present in the QA config
627 82a8bf3e Hrvoje Ribicic
  if default_nicparams is not None:
628 82a8bf3e Hrvoje Ribicic
    mode = default_nicparams.get("mode", None)
629 82a8bf3e Hrvoje Ribicic
    link = default_nicparams.get("link", None)
630 82a8bf3e Hrvoje Ribicic
    if mode is not None and link is not None:
631 82a8bf3e Hrvoje Ribicic
      TestNetworkConnectDisconnect(client, NETWORK_NAME, mode, link)
632 82a8bf3e Hrvoje Ribicic
633 82a8bf3e Hrvoje Ribicic
  # Clean up the network
634 82a8bf3e Hrvoje Ribicic
  Finish(client, client.DeleteNetwork,
635 82a8bf3e Hrvoje Ribicic
         NETWORK_NAME, dry_run=True)
636 82a8bf3e Hrvoje Ribicic
637 82a8bf3e Hrvoje Ribicic
  Finish(client, client.DeleteNetwork, NETWORK_NAME)
638 82a8bf3e Hrvoje Ribicic
639 82a8bf3e Hrvoje Ribicic
640 c2e22e7b Hrvoje Ribicic
def CreateDRBDInstance(client, node_one, node_two, instance_name):
641 c2e22e7b Hrvoje Ribicic
  """ Creates a DRBD-enabled instance on the given nodes.
642 c2e22e7b Hrvoje Ribicic

643 c2e22e7b Hrvoje Ribicic
  """
644 c2e22e7b Hrvoje Ribicic
  Finish(client, client.CreateInstance,
645 c2e22e7b Hrvoje Ribicic
         "create", instance_name, "drbd", [{"size": "1000"}], [{}],
646 c2e22e7b Hrvoje Ribicic
         os="debian-image", pnode=node_one, snode=node_two)
647 c2e22e7b Hrvoje Ribicic
648 c2e22e7b Hrvoje Ribicic
649 c2e22e7b Hrvoje Ribicic
def TestInstanceMigrations(client, node_one, node_two, node_three,
650 c2e22e7b Hrvoje Ribicic
                           instance_name):
651 c2e22e7b Hrvoje Ribicic
  """ Test various operations related to migrating instances.
652 c2e22e7b Hrvoje Ribicic

653 c2e22e7b Hrvoje Ribicic
  @type node_one string
654 c2e22e7b Hrvoje Ribicic
  @param node_one The name of a node in the cluster.
655 c2e22e7b Hrvoje Ribicic
  @type node_two string
656 c2e22e7b Hrvoje Ribicic
  @param node_two The name of another node in the cluster.
657 c2e22e7b Hrvoje Ribicic
  @type node_three string
658 c2e22e7b Hrvoje Ribicic
  @param node_three The name of yet another node in the cluster.
659 c2e22e7b Hrvoje Ribicic
  @type instance_name string
660 c2e22e7b Hrvoje Ribicic
  @param instance_name An instance name that can be used.
661 c2e22e7b Hrvoje Ribicic

662 c2e22e7b Hrvoje Ribicic
  """
663 c2e22e7b Hrvoje Ribicic
664 c2e22e7b Hrvoje Ribicic
  CreateDRBDInstance(client, node_one, node_two, instance_name)
665 c2e22e7b Hrvoje Ribicic
  Finish(client, client.FailoverInstance, instance_name)
666 c2e22e7b Hrvoje Ribicic
  Finish(client, client.DeleteInstance, instance_name)
667 c2e22e7b Hrvoje Ribicic
668 c2e22e7b Hrvoje Ribicic
  CreateDRBDInstance(client, node_one, node_two, instance_name)
669 c2e22e7b Hrvoje Ribicic
  Finish(client, client.EvacuateNode,
670 c2e22e7b Hrvoje Ribicic
         node_two, early_release=False, mode=NODE_EVAC_SEC,
671 c2e22e7b Hrvoje Ribicic
         remote_node=node_three)
672 c2e22e7b Hrvoje Ribicic
  Finish(client, client.DeleteInstance, instance_name)
673 c2e22e7b Hrvoje Ribicic
674 c2e22e7b Hrvoje Ribicic
  CreateDRBDInstance(client, node_one, node_two, instance_name)
675 c2e22e7b Hrvoje Ribicic
  Finish(client, client.EvacuateNode,
676 c2e22e7b Hrvoje Ribicic
         node_one, early_release=False, mode=NODE_EVAC_PRI, iallocator="hail")
677 c2e22e7b Hrvoje Ribicic
  Finish(client, client.DeleteInstance, instance_name)
678 c2e22e7b Hrvoje Ribicic
679 c2e22e7b Hrvoje Ribicic
  CreateDRBDInstance(client, node_one, node_two, instance_name)
680 c2e22e7b Hrvoje Ribicic
  Finish(client, client.MigrateInstance,
681 c2e22e7b Hrvoje Ribicic
         instance_name, cleanup=True, target_node=node_two)
682 c2e22e7b Hrvoje Ribicic
  Finish(client, client.DeleteInstance, instance_name)
683 c2e22e7b Hrvoje Ribicic
684 c2e22e7b Hrvoje Ribicic
  CreateDRBDInstance(client, node_one, node_two, instance_name)
685 c2e22e7b Hrvoje Ribicic
  Finish(client, client.MigrateNode,
686 c2e22e7b Hrvoje Ribicic
         node_one, iallocator="hail", mode="non-live")
687 c2e22e7b Hrvoje Ribicic
  Finish(client, client.DeleteInstance, instance_name)
688 c2e22e7b Hrvoje Ribicic
689 c2e22e7b Hrvoje Ribicic
  CreateDRBDInstance(client, node_one, node_two, instance_name)
690 c2e22e7b Hrvoje Ribicic
  Finish(client, client.MigrateNode,
691 c2e22e7b Hrvoje Ribicic
         node_one, target_node=node_two, mode="non-live")
692 c2e22e7b Hrvoje Ribicic
  Finish(client, client.DeleteInstance, instance_name)
693 c2e22e7b Hrvoje Ribicic
694 c2e22e7b Hrvoje Ribicic
695 17733ecb Hrvoje Ribicic
def ExtractAllNicInformationPossible(nics, replace_macs=True):
696 17733ecb Hrvoje Ribicic
  """ Extracts NIC information as a dictionary.
697 9578de1c Hrvoje Ribicic

698 17733ecb Hrvoje Ribicic
  @type nics list of tuples of varying structure
699 17733ecb Hrvoje Ribicic
  @param nics The network interfaces, as received from the instance info RAPI
700 17733ecb Hrvoje Ribicic
              call.
701 17733ecb Hrvoje Ribicic

702 17733ecb Hrvoje Ribicic
  @rtype list of dict
703 17733ecb Hrvoje Ribicic
  @return Dictionaries of NIC information.
704 17733ecb Hrvoje Ribicic

705 17733ecb Hrvoje Ribicic
  The NIC information is returned in a different format across versions, and to
706 17733ecb Hrvoje Ribicic
  try and see if the execution of commands is still compatible, this function
707 17733ecb Hrvoje Ribicic
  attempts to grab all the info that it can.
708 9578de1c Hrvoje Ribicic

709 9578de1c Hrvoje Ribicic
  """
710 9578de1c Hrvoje Ribicic
711 17733ecb Hrvoje Ribicic
  desired_entries = [
712 17733ecb Hrvoje Ribicic
    constants.INIC_IP,
713 17733ecb Hrvoje Ribicic
    constants.INIC_MAC,
714 17733ecb Hrvoje Ribicic
    constants.INIC_MODE,
715 17733ecb Hrvoje Ribicic
    constants.INIC_LINK,
716 17733ecb Hrvoje Ribicic
    constants.INIC_VLAN,
717 17733ecb Hrvoje Ribicic
    constants.INIC_NETWORK,
718 17733ecb Hrvoje Ribicic
    constants.INIC_NAME,
719 17733ecb Hrvoje Ribicic
    ]
720 9578de1c Hrvoje Ribicic
721 17733ecb Hrvoje Ribicic
  nic_dicts = []
722 17733ecb Hrvoje Ribicic
  for nic_index in range(len(nics)):
723 17733ecb Hrvoje Ribicic
    nic_raw_data = nics[nic_index]
724 9578de1c Hrvoje Ribicic
725 17733ecb Hrvoje Ribicic
    # Fill dictionary with None-s as defaults
726 17733ecb Hrvoje Ribicic
    nic_dict = dict([(key, None) for key in desired_entries])
727 17733ecb Hrvoje Ribicic
728 17733ecb Hrvoje Ribicic
    try:
729 17733ecb Hrvoje Ribicic
      # The 2.6 format
730 17733ecb Hrvoje Ribicic
      ip, mac, mode, link = nic_raw_data
731 17733ecb Hrvoje Ribicic
    except ValueError:
732 17733ecb Hrvoje Ribicic
      # If there is yet another ValueError here, let it go through as it is
733 17733ecb Hrvoje Ribicic
      # legitimate - we are out of versions
734 17733ecb Hrvoje Ribicic
735 17733ecb Hrvoje Ribicic
      # The 2.11 format
736 17733ecb Hrvoje Ribicic
      nic_name, _, ip, mac, mode, link, vlan, network, _ = nic_raw_data
737 17733ecb Hrvoje Ribicic
      nic_dict[constants.INIC_VLAN] = vlan
738 17733ecb Hrvoje Ribicic
      nic_dict[constants.INIC_NETWORK] = network
739 17733ecb Hrvoje Ribicic
      nic_dict[constants.INIC_NAME] = nic_name
740 17733ecb Hrvoje Ribicic
741 17733ecb Hrvoje Ribicic
    # These attributes will be present in either version
742 17733ecb Hrvoje Ribicic
    nic_dict[constants.INIC_IP] = ip
743 17733ecb Hrvoje Ribicic
    nic_dict[constants.INIC_MAC] = mac
744 17733ecb Hrvoje Ribicic
    nic_dict[constants.INIC_MODE] = mode
745 17733ecb Hrvoje Ribicic
    nic_dict[constants.INIC_LINK] = link
746 17733ecb Hrvoje Ribicic
747 17733ecb Hrvoje Ribicic
    # Very simple mac generation, which should work as the setup cluster should
748 17733ecb Hrvoje Ribicic
    # have no mac prefix restrictions in the default network, and there is a
749 17733ecb Hrvoje Ribicic
    # hard and reasonable limit of only 8 NICs
750 17733ecb Hrvoje Ribicic
    if replace_macs:
751 17733ecb Hrvoje Ribicic
      nic_dict[constants.INIC_MAC] = "00:00:00:00:00:%02x" % nic_index
752 17733ecb Hrvoje Ribicic
753 17733ecb Hrvoje Ribicic
    nic_dicts.append(nic_dict)
754 17733ecb Hrvoje Ribicic
755 17733ecb Hrvoje Ribicic
  return nic_dicts
756 9578de1c Hrvoje Ribicic
757 9578de1c Hrvoje Ribicic
758 17733ecb Hrvoje Ribicic
def MoveInstance(client, src_instance, dst_instance, src_node, dst_node):
759 17733ecb Hrvoje Ribicic
  """ Moves a single instance, compatible with 2.6.
760 17733ecb Hrvoje Ribicic

761 17733ecb Hrvoje Ribicic
  @rtype bool
762 17733ecb Hrvoje Ribicic
  @return Whether the instance was moved successfully
763 17733ecb Hrvoje Ribicic

764 17733ecb Hrvoje Ribicic
  """
765 17733ecb Hrvoje Ribicic
  success, inst_info_all = Finish(client, client.GetInstanceInfo,
766 17733ecb Hrvoje Ribicic
                                  src_instance.name, static=True)
767 17733ecb Hrvoje Ribicic
768 17733ecb Hrvoje Ribicic
  if not success or src_instance.name not in inst_info_all:
769 17733ecb Hrvoje Ribicic
    raise Exception("Did not find the source instance information!")
770 17733ecb Hrvoje Ribicic
771 17733ecb Hrvoje Ribicic
  inst_info = inst_info_all[src_instance.name]
772 17733ecb Hrvoje Ribicic
773 17733ecb Hrvoje Ribicic
  # Try to extract NICs first, as this is the operation most likely to fail
774 17733ecb Hrvoje Ribicic
  try:
775 17733ecb Hrvoje Ribicic
    nic_info = ExtractAllNicInformationPossible(inst_info["nics"])
776 17733ecb Hrvoje Ribicic
  except ValueError:
777 17733ecb Hrvoje Ribicic
    # Without the NIC info, there is very little we can do
778 17733ecb Hrvoje Ribicic
    return False
779 17733ecb Hrvoje Ribicic
780 17733ecb Hrvoje Ribicic
  NIC_COMPONENTS_26 = [
781 17733ecb Hrvoje Ribicic
    constants.INIC_IP,
782 17733ecb Hrvoje Ribicic
    constants.INIC_MAC,
783 17733ecb Hrvoje Ribicic
    constants.INIC_MODE,
784 17733ecb Hrvoje Ribicic
    constants.INIC_LINK,
785 17733ecb Hrvoje Ribicic
    ]
786 17733ecb Hrvoje Ribicic
787 17733ecb Hrvoje Ribicic
  nic_converter = lambda old: dict((k, old[k]) for k in NIC_COMPONENTS_26)
788 17733ecb Hrvoje Ribicic
  nics = map(nic_converter, nic_info)
789 17733ecb Hrvoje Ribicic
790 17733ecb Hrvoje Ribicic
  # Prepare the parameters
791 17733ecb Hrvoje Ribicic
  disks = []
792 17733ecb Hrvoje Ribicic
  for idisk in inst_info["disks"]:
793 17733ecb Hrvoje Ribicic
    odisk = {
794 17733ecb Hrvoje Ribicic
      constants.IDISK_SIZE: idisk["size"],
795 17733ecb Hrvoje Ribicic
      constants.IDISK_MODE: idisk["mode"],
796 17733ecb Hrvoje Ribicic
      }
797 17733ecb Hrvoje Ribicic
798 17733ecb Hrvoje Ribicic
    spindles = idisk.get("spindles")
799 17733ecb Hrvoje Ribicic
    if spindles is not None:
800 17733ecb Hrvoje Ribicic
      odisk[constants.IDISK_SPINDLES] = spindles
801 17733ecb Hrvoje Ribicic
802 17733ecb Hrvoje Ribicic
    # Disk name may be present, but must not be supplied in 2.6!
803 17733ecb Hrvoje Ribicic
    disks.append(odisk)
804 17733ecb Hrvoje Ribicic
805 17733ecb Hrvoje Ribicic
  # With all the parameters properly prepared, try the export
806 17733ecb Hrvoje Ribicic
  success, exp_info = Finish(client, client.PrepareExport,
807 17733ecb Hrvoje Ribicic
                             src_instance.name, constants.EXPORT_MODE_REMOTE)
808 17733ecb Hrvoje Ribicic
809 9578de1c Hrvoje Ribicic
  if not success:
810 17733ecb Hrvoje Ribicic
    # The instance will still have to be deleted
811 17733ecb Hrvoje Ribicic
    return False
812 17733ecb Hrvoje Ribicic
813 17733ecb Hrvoje Ribicic
  success, _ = Finish(client, client.CreateInstance,
814 17733ecb Hrvoje Ribicic
                      constants.INSTANCE_REMOTE_IMPORT, dst_instance.name,
815 17733ecb Hrvoje Ribicic
                      inst_info["disk_template"], disks, nics,
816 17733ecb Hrvoje Ribicic
                      os=inst_info["os"],
817 17733ecb Hrvoje Ribicic
                      pnode=dst_node.primary,
818 17733ecb Hrvoje Ribicic
                      snode=src_node.primary, # Ignored as no DRBD
819 17733ecb Hrvoje Ribicic
                      start=(inst_info["config_state"] == "up"),
820 17733ecb Hrvoje Ribicic
                      ip_check=False,
821 17733ecb Hrvoje Ribicic
                      iallocator=inst_info.get("iallocator", None),
822 17733ecb Hrvoje Ribicic
                      hypervisor=inst_info["hypervisor"],
823 17733ecb Hrvoje Ribicic
                      source_handshake=exp_info["handshake"],
824 17733ecb Hrvoje Ribicic
                      source_x509_ca=exp_info["x509_ca"],
825 17733ecb Hrvoje Ribicic
                      source_instance_name=inst_info["name"],
826 17733ecb Hrvoje Ribicic
                      beparams=inst_info["be_instance"],
827 17733ecb Hrvoje Ribicic
                      hvparams=inst_info["hv_instance"],
828 17733ecb Hrvoje Ribicic
                      osparams=inst_info["os_instance"])
829 17733ecb Hrvoje Ribicic
830 17733ecb Hrvoje Ribicic
  return success
831 17733ecb Hrvoje Ribicic
832 17733ecb Hrvoje Ribicic
833 17733ecb Hrvoje Ribicic
def CreateInstanceForMoveTest(client, node, instance):
834 17733ecb Hrvoje Ribicic
  """ Creates a single shutdown instance to move about in tests.
835 17733ecb Hrvoje Ribicic

836 17733ecb Hrvoje Ribicic
  @type node C{_QaNode}
837 17733ecb Hrvoje Ribicic
  @param node A node configuration object.
838 17733ecb Hrvoje Ribicic
  @type instance C{_QaInstance}
839 17733ecb Hrvoje Ribicic
  @param instance An instance configuration object.
840 17733ecb Hrvoje Ribicic

841 17733ecb Hrvoje Ribicic
  """
842 17733ecb Hrvoje Ribicic
  Finish(client, client.CreateInstance,
843 17733ecb Hrvoje Ribicic
         "create", instance.name, "plain", [{"size": "2000"}], [{}],
844 17733ecb Hrvoje Ribicic
         os="debian-image", pnode=node.primary)
845 9578de1c Hrvoje Ribicic
846 17733ecb Hrvoje Ribicic
  Finish(client, client.ShutdownInstance,
847 17733ecb Hrvoje Ribicic
         instance.name, dry_run=False, no_remember=False)
848 9578de1c Hrvoje Ribicic
849 17733ecb Hrvoje Ribicic
850 17733ecb Hrvoje Ribicic
def Test26InstanceMove(client, node_one, node_two, instance_to_create,
851 17733ecb Hrvoje Ribicic
                       new_instance):
852 17733ecb Hrvoje Ribicic
  """ Tests instance moves using commands that work in 2.6.
853 17733ecb Hrvoje Ribicic

854 17733ecb Hrvoje Ribicic
  """
855 17733ecb Hrvoje Ribicic
856 17733ecb Hrvoje Ribicic
  # First create the instance to move
857 17733ecb Hrvoje Ribicic
  CreateInstanceForMoveTest(client, node_one, instance_to_create)
858 17733ecb Hrvoje Ribicic
859 17733ecb Hrvoje Ribicic
  # The cleanup should be conditional on operation success
860 17733ecb Hrvoje Ribicic
  if MoveInstance(client, instance_to_create, new_instance, node_one, node_two):
861 17733ecb Hrvoje Ribicic
    Finish(client, client.DeleteInstance, new_instance.name)
862 17733ecb Hrvoje Ribicic
  else:
863 17733ecb Hrvoje Ribicic
    Finish(client, client.DeleteInstance, instance_to_create.name)
864 17733ecb Hrvoje Ribicic
865 17733ecb Hrvoje Ribicic
866 17733ecb Hrvoje Ribicic
def Test211InstanceMove(client, node_one, node_two, instance_to_create,
867 17733ecb Hrvoje Ribicic
                        new_instance):
868 17733ecb Hrvoje Ribicic
  """ Tests instance moves using the QA-provided move test.
869 17733ecb Hrvoje Ribicic

870 17733ecb Hrvoje Ribicic
  """
871 17733ecb Hrvoje Ribicic
872 17733ecb Hrvoje Ribicic
  # First create the instance to move
873 17733ecb Hrvoje Ribicic
  CreateInstanceForMoveTest(client, node_one, instance_to_create)
874 17733ecb Hrvoje Ribicic
875 17733ecb Hrvoje Ribicic
  instance_to_create.SetDiskTemplate("plain")
876 17733ecb Hrvoje Ribicic
877 17733ecb Hrvoje Ribicic
  try:
878 17733ecb Hrvoje Ribicic
    qa_rapi.TestInterClusterInstanceMove(instance_to_create, new_instance,
879 17733ecb Hrvoje Ribicic
                                         [node_one], node_two,
880 17733ecb Hrvoje Ribicic
                                         perform_checks=False)
881 17733ecb Hrvoje Ribicic
  except qa_error.Error:
882 17733ecb Hrvoje Ribicic
    # A failure is sad, but requires no special actions to be undertaken
883 17733ecb Hrvoje Ribicic
    pass
884 17733ecb Hrvoje Ribicic
885 17733ecb Hrvoje Ribicic
  # Try to delete the instance when done - either the move has failed, or
886 17733ecb Hrvoje Ribicic
  # a double move was performed - the instance to delete is one and the same
887 17733ecb Hrvoje Ribicic
  Finish(client, client.DeleteInstance, instance_to_create.name)
888 9578de1c Hrvoje Ribicic
889 9578de1c Hrvoje Ribicic
890 9578de1c Hrvoje Ribicic
def TestInstanceMoves(client, node_one, node_two, instance_to_create,
891 9578de1c Hrvoje Ribicic
                      new_instance):
892 17733ecb Hrvoje Ribicic
  """ Performs two types of instance moves, one compatible with 2.6, the other
893 17733ecb Hrvoje Ribicic
  with 2.11.
894 9578de1c Hrvoje Ribicic

895 9578de1c Hrvoje Ribicic
  @type node_one C{_QaNode}
896 9578de1c Hrvoje Ribicic
  @param node_one A node configuration object.
897 9578de1c Hrvoje Ribicic
  @type node_two C{_QaNode}
898 9578de1c Hrvoje Ribicic
  @param node_two A node configuration object.
899 9578de1c Hrvoje Ribicic
  @type instance_to_create C{_QaInstance}
900 9578de1c Hrvoje Ribicic
  @param instance_to_create An instance configuration object.
901 9578de1c Hrvoje Ribicic
  @type new_instance C{_QaInstance}
902 9578de1c Hrvoje Ribicic
  @param new_instance An instance configuration object.
903 9578de1c Hrvoje Ribicic

904 9578de1c Hrvoje Ribicic
  """
905 9578de1c Hrvoje Ribicic
906 17733ecb Hrvoje Ribicic
  Test26InstanceMove(client, node_one, node_two, instance_to_create,
907 17733ecb Hrvoje Ribicic
                     new_instance)
908 17733ecb Hrvoje Ribicic
  Test211InstanceMove(client, node_one, node_two, instance_to_create,
909 17733ecb Hrvoje Ribicic
                      new_instance)
910 9578de1c Hrvoje Ribicic
911 9578de1c Hrvoje Ribicic
912 b896bb66 Hrvoje Ribicic
def TestClusterParameterModification(client):
913 b896bb66 Hrvoje Ribicic
  """ Try to modify some of the cluster parameters using RAPI.
914 b896bb66 Hrvoje Ribicic

915 b896bb66 Hrvoje Ribicic
  """
916 b896bb66 Hrvoje Ribicic
  cluster_info = client.GetInfo()
917 b896bb66 Hrvoje Ribicic
918 b896bb66 Hrvoje Ribicic
  # Each attribute has several safe choices we can use
919 b896bb66 Hrvoje Ribicic
  ATTRIBUTES_TO_MODIFY = [
920 b896bb66 Hrvoje Ribicic
    ("default_iallocator", ["hail", ""]), # Use "" to reset
921 b896bb66 Hrvoje Ribicic
    ("candidate_pool_size", [1, 5]),
922 b896bb66 Hrvoje Ribicic
    ("maintain_node_health", [True, False]),
923 b896bb66 Hrvoje Ribicic
    ]
924 b896bb66 Hrvoje Ribicic
925 b896bb66 Hrvoje Ribicic
  for attribute, options in ATTRIBUTES_TO_MODIFY:
926 b896bb66 Hrvoje Ribicic
    current_value = cluster_info[attribute]
927 b896bb66 Hrvoje Ribicic
928 b896bb66 Hrvoje Ribicic
    if current_value in options:
929 b896bb66 Hrvoje Ribicic
      value_to_use = options[1 - options.index(current_value)]
930 b896bb66 Hrvoje Ribicic
    else:
931 b896bb66 Hrvoje Ribicic
      value_to_use = options[0]
932 b896bb66 Hrvoje Ribicic
933 b896bb66 Hrvoje Ribicic
    #pylint: disable=W0142
934 b896bb66 Hrvoje Ribicic
    Finish(client, client.ModifyCluster, **{attribute: value_to_use})
935 b896bb66 Hrvoje Ribicic
    Finish(client, client.ModifyCluster, **{attribute: current_value})
936 b896bb66 Hrvoje Ribicic
    #pylint: enable=W0142
937 b896bb66 Hrvoje Ribicic
938 b896bb66 Hrvoje Ribicic
939 dd2bc9b6 Hrvoje Ribicic
def TestJobCancellation(client, node_one, node_two, instance_one, instance_two):
940 dd2bc9b6 Hrvoje Ribicic
  """ Test if jobs can be cancelled.
941 dd2bc9b6 Hrvoje Ribicic

942 dd2bc9b6 Hrvoje Ribicic
  @type node_one string
943 dd2bc9b6 Hrvoje Ribicic
  @param node_one The name of a node in the cluster.
944 dd2bc9b6 Hrvoje Ribicic
  @type node_two string
945 dd2bc9b6 Hrvoje Ribicic
  @param node_two The name of a node in the cluster.
946 dd2bc9b6 Hrvoje Ribicic
  @type instance_one string
947 dd2bc9b6 Hrvoje Ribicic
  @param instance_one An available instance name.
948 dd2bc9b6 Hrvoje Ribicic
  @type instance_two string
949 dd2bc9b6 Hrvoje Ribicic
  @param instance_two An available instance name.
950 dd2bc9b6 Hrvoje Ribicic

951 dd2bc9b6 Hrvoje Ribicic
  """
952 dd2bc9b6 Hrvoje Ribicic
953 dd2bc9b6 Hrvoje Ribicic
  # Just in case, remove all previously present instances
954 dd2bc9b6 Hrvoje Ribicic
  RemoveAllInstances(client)
955 dd2bc9b6 Hrvoje Ribicic
956 dd2bc9b6 Hrvoje Ribicic
  # Let us issue a job that is sure to both succeed and last for a while
957 dd2bc9b6 Hrvoje Ribicic
  running_job = client.CreateInstance("create", instance_one, "drbd",
958 dd2bc9b6 Hrvoje Ribicic
                                      [{"size": "5000"}], [{}],
959 dd2bc9b6 Hrvoje Ribicic
                                      os="debian-image", pnode=node_one,
960 dd2bc9b6 Hrvoje Ribicic
                                      snode=node_two)
961 dd2bc9b6 Hrvoje Ribicic
962 dd2bc9b6 Hrvoje Ribicic
  # And immediately afterwards, another very similar one
963 dd2bc9b6 Hrvoje Ribicic
  job_to_cancel = client.CreateInstance("create", instance_two, "drbd",
964 dd2bc9b6 Hrvoje Ribicic
                                        [{"size": "5000"}], [{}],
965 dd2bc9b6 Hrvoje Ribicic
                                        os="debian-image", pnode=node_one,
966 dd2bc9b6 Hrvoje Ribicic
                                        snode=node_two)
967 dd2bc9b6 Hrvoje Ribicic
968 dd2bc9b6 Hrvoje Ribicic
  # Try to cancel, which should fail as the job is already running
969 dd2bc9b6 Hrvoje Ribicic
  success, msg = client.CancelJob(running_job)
970 dd2bc9b6 Hrvoje Ribicic
  if success:
971 dd2bc9b6 Hrvoje Ribicic
    print "Job succeeded: this should not have happened as it is running!"
972 dd2bc9b6 Hrvoje Ribicic
    print "Message: %s" % msg
973 dd2bc9b6 Hrvoje Ribicic
974 dd2bc9b6 Hrvoje Ribicic
  success, msg = client.CancelJob(job_to_cancel)
975 dd2bc9b6 Hrvoje Ribicic
  if not success:
976 dd2bc9b6 Hrvoje Ribicic
    print "Job failed: this was unexpected as it was not a dry run"
977 dd2bc9b6 Hrvoje Ribicic
    print "Message: %s" % msg
978 dd2bc9b6 Hrvoje Ribicic
979 dd2bc9b6 Hrvoje Ribicic
  # And wait for the proper job
980 dd2bc9b6 Hrvoje Ribicic
  client.WaitForJobCompletion(running_job)
981 dd2bc9b6 Hrvoje Ribicic
982 dd2bc9b6 Hrvoje Ribicic
  # Remove all the leftover instances, success or no success
983 dd2bc9b6 Hrvoje Ribicic
  RemoveAllInstances(client)
984 dd2bc9b6 Hrvoje Ribicic
985 dd2bc9b6 Hrvoje Ribicic
986 a9e3e04d Hrvoje Ribicic
def Workload(client):
987 a9e3e04d Hrvoje Ribicic
  """ The actual RAPI workload used for tests.
988 a9e3e04d Hrvoje Ribicic

989 a9e3e04d Hrvoje Ribicic
  @type client C{GanetiRapiClientWrapper}
990 a9e3e04d Hrvoje Ribicic
  @param client A wrapped RAPI client.
991 a9e3e04d Hrvoje Ribicic

992 a9e3e04d Hrvoje Ribicic
  """
993 a9e3e04d Hrvoje Ribicic
994 a9e3e04d Hrvoje Ribicic
  # First just the simple information retrievals
995 a9e3e04d Hrvoje Ribicic
  TestGetters(client)
996 a9e3e04d Hrvoje Ribicic
997 a9e3e04d Hrvoje Ribicic
  # Then the only remaining function which is parameter-free
998 b87948f5 Hrvoje Ribicic
  Finish(client, client.RedistributeConfig)
999 56803e14 Hrvoje Ribicic
1000 b896bb66 Hrvoje Ribicic
  # Try changing the cluster parameters
1001 b896bb66 Hrvoje Ribicic
  TestClusterParameterModification(client)
1002 b896bb66 Hrvoje Ribicic
1003 9f22ba9a Hrvoje Ribicic
  TestTags(client, client.GetClusterTags, client.AddClusterTags,
1004 9f22ba9a Hrvoje Ribicic
           client.DeleteClusterTags)
1005 9f22ba9a Hrvoje Ribicic
1006 9f22ba9a Hrvoje Ribicic
  # Generously assume the master is present
1007 9f22ba9a Hrvoje Ribicic
  node = qa_config.AcquireNode()
1008 9f22ba9a Hrvoje Ribicic
  TestTags(client, client.GetNodeTags, client.AddNodeTags,
1009 9f22ba9a Hrvoje Ribicic
           client.DeleteNodeTags, node.primary)
1010 9f22ba9a Hrvoje Ribicic
  node.Release()
1011 9f22ba9a Hrvoje Ribicic
1012 a9e3e04d Hrvoje Ribicic
  # Instance tests
1013 a9e3e04d Hrvoje Ribicic
1014 a9e3e04d Hrvoje Ribicic
  # First remove all instances the QA might have created
1015 a9e3e04d Hrvoje Ribicic
  RemoveAllInstances(client)
1016 a9e3e04d Hrvoje Ribicic
1017 a9e3e04d Hrvoje Ribicic
  nodes = qa_config.AcquireManyNodes(2)
1018 c2e22e7b Hrvoje Ribicic
  instances = qa_config.AcquireManyInstances(2)
1019 c2e22e7b Hrvoje Ribicic
  TestSingleInstance(client, instances[0].name, instances[1].name,
1020 a9e3e04d Hrvoje Ribicic
                     nodes[0].primary, nodes[1].primary)
1021 c2e22e7b Hrvoje Ribicic
  qa_config.ReleaseManyInstances(instances)
1022 a9e3e04d Hrvoje Ribicic
  qa_config.ReleaseManyNodes(nodes)
1023 a9e3e04d Hrvoje Ribicic
1024 9749bd5e Hrvoje Ribicic
  # Test all the queries which involve resources that do not have functions
1025 9749bd5e Hrvoje Ribicic
  # of their own
1026 9749bd5e Hrvoje Ribicic
  TestQueries(client, "lock")
1027 9749bd5e Hrvoje Ribicic
  TestQueries(client, "job")
1028 9749bd5e Hrvoje Ribicic
  TestQueries(client, "export")
1029 9749bd5e Hrvoje Ribicic
1030 6b710ec0 Hrvoje Ribicic
  node = qa_config.AcquireNode(exclude=qa_config.GetMasterNode())
1031 6b710ec0 Hrvoje Ribicic
  TestNodeOperations(client, node.primary)
1032 4236968a Hrvoje Ribicic
  TestQueryFiltering(client, node.primary)
1033 6b710ec0 Hrvoje Ribicic
  node.Release()
1034 82a8bf3e Hrvoje Ribicic
1035 1086027a Hrvoje Ribicic
  nodes = qa_config.AcquireManyNodes(2)
1036 1086027a Hrvoje Ribicic
  TestGroupOperations(client, nodes[0].primary, nodes[1].primary)
1037 1086027a Hrvoje Ribicic
  qa_config.ReleaseManyNodes(nodes)
1038 1086027a Hrvoje Ribicic
1039 82a8bf3e Hrvoje Ribicic
  TestNetworks(client)
1040 82a8bf3e Hrvoje Ribicic
1041 c2e22e7b Hrvoje Ribicic
  nodes = qa_config.AcquireManyNodes(3)
1042 c2e22e7b Hrvoje Ribicic
  instance = qa_config.AcquireInstance()
1043 c2e22e7b Hrvoje Ribicic
  TestInstanceMigrations(client, nodes[0].primary, nodes[1].primary,
1044 c2e22e7b Hrvoje Ribicic
                         nodes[2].primary, instance.name)
1045 c2e22e7b Hrvoje Ribicic
  instance.Release()
1046 c2e22e7b Hrvoje Ribicic
  qa_config.ReleaseManyNodes(nodes)
1047 c2e22e7b Hrvoje Ribicic
1048 9578de1c Hrvoje Ribicic
  nodes = qa_config.AcquireManyNodes(2)
1049 9578de1c Hrvoje Ribicic
  instances = qa_config.AcquireManyInstances(2)
1050 9578de1c Hrvoje Ribicic
  TestInstanceMoves(client, nodes[0], nodes[1], instances[0], instances[1])
1051 dd2bc9b6 Hrvoje Ribicic
  TestJobCancellation(client, nodes[0].primary, nodes[1].primary,
1052 dd2bc9b6 Hrvoje Ribicic
                      instances[0].name, instances[1].name)
1053 9578de1c Hrvoje Ribicic
  qa_config.ReleaseManyInstances(instances)
1054 9578de1c Hrvoje Ribicic
  qa_config.ReleaseManyNodes(nodes)
1055 9578de1c Hrvoje Ribicic
1056 56803e14 Hrvoje Ribicic
1057 56803e14 Hrvoje Ribicic
def Main():
1058 82ce55fa Hrvoje Ribicic
  parser = optparse.OptionParser(usage="%prog [options] <config-file>")
1059 82ce55fa Hrvoje Ribicic
  parser.add_option("--yes-do-it", dest="yes_do_it",
1060 82ce55fa Hrvoje Ribicic
                    action="store_true",
1061 82ce55fa Hrvoje Ribicic
                    help="Really execute the tests")
1062 82ce55fa Hrvoje Ribicic
  parser.add_option("--show-invocations", dest="show_invocations",
1063 82ce55fa Hrvoje Ribicic
                    action="store_true",
1064 82ce55fa Hrvoje Ribicic
                    help="Show which client methods have and have not been "
1065 82ce55fa Hrvoje Ribicic
                         "called")
1066 82ce55fa Hrvoje Ribicic
  (opts, args) = parser.parse_args()
1067 82ce55fa Hrvoje Ribicic
1068 82ce55fa Hrvoje Ribicic
  if not opts.yes_do_it:
1069 82ce55fa Hrvoje Ribicic
    print ("Executing this script irreversibly destroys any Ganeti\n"
1070 82ce55fa Hrvoje Ribicic
           "configuration on all nodes involved. If you really want\n"
1071 82ce55fa Hrvoje Ribicic
           "to start testing, supply the --yes-do-it option.")
1072 82ce55fa Hrvoje Ribicic
    sys.exit(1)
1073 82ce55fa Hrvoje Ribicic
1074 82ce55fa Hrvoje Ribicic
  qa_config.Load(args[0])
1075 56803e14 Hrvoje Ribicic
1076 56803e14 Hrvoje Ribicic
  # Only the master will be present after a fresh QA cluster setup, so we have
1077 56803e14 Hrvoje Ribicic
  # to invoke this to get all the other nodes.
1078 56803e14 Hrvoje Ribicic
  qa_node.TestNodeAddAll()
1079 56803e14 Hrvoje Ribicic
1080 56803e14 Hrvoje Ribicic
  client = GanetiRapiClientWrapper()
1081 56803e14 Hrvoje Ribicic
1082 56803e14 Hrvoje Ribicic
  Workload(client)
1083 56803e14 Hrvoje Ribicic
1084 56803e14 Hrvoje Ribicic
  qa_node.TestNodeRemoveAll()
1085 56803e14 Hrvoje Ribicic
1086 396c5dfb Hrvoje Ribicic
  # The method invoked has the naming of the protected method, and pylint does
1087 396c5dfb Hrvoje Ribicic
  # not like this. Disabling the warning is healthier than explicitly adding and
1088 396c5dfb Hrvoje Ribicic
  # maintaining an exception for this method in the wrapper.
1089 82ce55fa Hrvoje Ribicic
  if opts.show_invocations:
1090 82ce55fa Hrvoje Ribicic
    # pylint: disable=W0212
1091 82ce55fa Hrvoje Ribicic
    client._OutputMethodInvocationDetails()
1092 82ce55fa Hrvoje Ribicic
    # pylint: enable=W0212
1093 56803e14 Hrvoje Ribicic
1094 56803e14 Hrvoje Ribicic
if __name__ == "__main__":
1095 56803e14 Hrvoje Ribicic
  Main()