Statistics
| Branch: | Tag: | Revision:

root / qa / rapi-workload.py @ 67bd83ae

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 3eea40a0 Hrvoje Ribicic
    @type fn: arbitrary function
107 3eea40a0 Hrvoje Ribicic
    @param fn: The function to invoke later.
108 3eea40a0 Hrvoje Ribicic
    @type name: string
109 3eea40a0 Hrvoje Ribicic
    @param name: The name of the function, for debugging purposes.
110 3eea40a0 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 3eea40a0 Hrvoje Ribicic
  @type client: C{GanetiRapiClientWrapper}
177 3eea40a0 Hrvoje Ribicic
  @param client: The client wrapper.
178 3eea40a0 Hrvoje Ribicic
  @type fn: function
179 3eea40a0 Hrvoje Ribicic
  @param fn: A client method returning a job id.
180 b87948f5 Hrvoje Ribicic

181 3eea40a0 Hrvoje Ribicic
  @rtype: tuple of bool, any object
182 3eea40a0 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 3eea40a0 Hrvoje Ribicic
  @type client: C{GanetiRapiClientWrapper}
213 3eea40a0 Hrvoje Ribicic
  @param client: The client wrapper.
214 3eea40a0 Hrvoje Ribicic
  @type get_fn: function
215 3eea40a0 Hrvoje Ribicic
  @param get_fn: A Get*Tags function of the client.
216 3eea40a0 Hrvoje Ribicic
  @type add_fn: function
217 3eea40a0 Hrvoje Ribicic
  @param add_fn: An Add*Tags function of the client.
218 3eea40a0 Hrvoje Ribicic
  @type delete_fn: function
219 3eea40a0 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 3eea40a0 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 3eea40a0 Hrvoje Ribicic
  @type client: C{GanetiRapiClientWrapper}
272 3eea40a0 Hrvoje Ribicic
  @param client: A wrapped RAPI client.
273 3eea40a0 Hrvoje Ribicic
  @type resource_name: string
274 3eea40a0 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 3eea40a0 Hrvoje Ribicic
  @type client: C{GanetiRapiClientWrapper}
298 3eea40a0 Hrvoje Ribicic
  @param client: A wrapped RAPI client.
299 3eea40a0 Hrvoje Ribicic
  @type master_name: string
300 3eea40a0 Hrvoje Ribicic
  @param master_name: The hostname of the master node.
301 4236968a Hrvoje Ribicic

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

321 3eea40a0 Hrvoje Ribicic
  @type client: C{GanetiRapiClientWrapper}
322 3eea40a0 Hrvoje Ribicic
  @param client: A wrapped RAPI client.
323 a9e3e04d Hrvoje Ribicic

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

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

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

443 3eea40a0 Hrvoje Ribicic
  @type client: C{GanetiRapiClientWrapper}
444 3eea40a0 Hrvoje Ribicic
  @param client: A wrapped RAPI client.
445 3eea40a0 Hrvoje Ribicic
  @type node: string
446 3eea40a0 Hrvoje Ribicic
  @type state: string
447 6b710ec0 Hrvoje Ribicic

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

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

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

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

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

573 3eea40a0 Hrvoje Ribicic
  @type network_name: string
574 3eea40a0 Hrvoje Ribicic
  @param network_name: The name of an existing and unconnected network.
575 3eea40a0 Hrvoje Ribicic
  @type mode: string
576 3eea40a0 Hrvoje Ribicic
  @param mode: The network mode.
577 3eea40a0 Hrvoje Ribicic
  @type link: string
578 3eea40a0 Hrvoje Ribicic
  @param link: The network link.
579 82a8bf3e Hrvoje Ribicic

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

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

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

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

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

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

704 3eea40a0 Hrvoje Ribicic
  @rtype: list of dict
705 3eea40a0 Hrvoje Ribicic
  @return: Dictionaries of NIC information.
706 17733ecb Hrvoje Ribicic

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

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

763 3eea40a0 Hrvoje Ribicic
  @rtype: bool
764 3eea40a0 Hrvoje Ribicic
  @return: Whether the instance was moved successfully
765 17733ecb Hrvoje Ribicic

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

838 3eea40a0 Hrvoje Ribicic
  @type node: C{_QaNode}
839 3eea40a0 Hrvoje Ribicic
  @param node: A node configuration object.
840 3eea40a0 Hrvoje Ribicic
  @type instance: C{_QaInstance}
841 3eea40a0 Hrvoje Ribicic
  @param instance: An instance configuration object.
842 17733ecb Hrvoje Ribicic

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

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

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

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

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

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

944 3eea40a0 Hrvoje Ribicic
  @type node_one: string
945 3eea40a0 Hrvoje Ribicic
  @param node_one: The name of a node in the cluster.
946 3eea40a0 Hrvoje Ribicic
  @type node_two: string
947 3eea40a0 Hrvoje Ribicic
  @param node_two: The name of another node in the cluster.
948 3eea40a0 Hrvoje Ribicic
  @type instance_one: string
949 3eea40a0 Hrvoje Ribicic
  @param instance_one: An available instance name.
950 3eea40a0 Hrvoje Ribicic
  @type instance_two: string
951 3eea40a0 Hrvoje Ribicic
  @param instance_two: An available instance name.
952 dd2bc9b6 Hrvoje Ribicic

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

991 3eea40a0 Hrvoje Ribicic
  @type client: C{GanetiRapiClientWrapper}
992 3eea40a0 Hrvoje Ribicic
  @param client: A wrapped RAPI client.
993 a9e3e04d Hrvoje Ribicic

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