root / qa / qa_instance_utils.py @ 95155a8c
History | View | Annotate | Download (6.7 kB)
1 |
#
|
---|---|
2 |
#
|
3 |
|
4 |
# Copyright (C) 2013 Google Inc.
|
5 |
#
|
6 |
# This program is free software; you can redistribute it and/or modify
|
7 |
# it under the terms of the GNU General Public License as published by
|
8 |
# the Free Software Foundation; either version 2 of the License, or
|
9 |
# (at your option) any later version.
|
10 |
#
|
11 |
# This program is distributed in the hope that it will be useful, but
|
12 |
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 |
# General Public License for more details.
|
15 |
#
|
16 |
# You should have received a copy of the GNU General Public License
|
17 |
# along with this program; if not, write to the Free Software
|
18 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 |
# 02110-1301, USA.
|
20 |
|
21 |
|
22 |
"""QA utility functions for managing instances
|
23 |
|
24 |
"""
|
25 |
|
26 |
import operator |
27 |
|
28 |
from ganeti import utils |
29 |
from ganeti import constants |
30 |
from ganeti import pathutils |
31 |
|
32 |
import qa_config |
33 |
import qa_error |
34 |
import qa_utils |
35 |
|
36 |
from qa_utils import AssertIn, AssertCommand |
37 |
|
38 |
|
39 |
def RemoveInstance(instance): |
40 |
AssertCommand(["gnt-instance", "remove", "-f", instance.name]) |
41 |
|
42 |
|
43 |
def GetGenericAddParameters(inst, disk_template, force_mac=None): |
44 |
params = ["-B"]
|
45 |
params.append("%s=%s,%s=%s" % (constants.BE_MINMEM,
|
46 |
qa_config.get(constants.BE_MINMEM), |
47 |
constants.BE_MAXMEM, |
48 |
qa_config.get(constants.BE_MAXMEM))) |
49 |
|
50 |
if disk_template != constants.DT_DISKLESS:
|
51 |
for idx, disk in enumerate(qa_config.GetDiskOptions()): |
52 |
size = disk.get("size")
|
53 |
name = disk.get("name")
|
54 |
diskparams = "%s:size=%s" % (idx, size)
|
55 |
if name:
|
56 |
diskparams += ",name=%s" % name
|
57 |
if qa_config.AreSpindlesSupported():
|
58 |
spindles = disk.get("spindles")
|
59 |
if spindles is None: |
60 |
raise qa_error.Error("'spindles' is a required parameter for disks" |
61 |
" when you enable exclusive storage tests")
|
62 |
diskparams += ",spindles=%s" % spindles
|
63 |
params.extend(["--disk", diskparams])
|
64 |
|
65 |
# Set static MAC address if configured
|
66 |
if force_mac:
|
67 |
nic0_mac = force_mac |
68 |
else:
|
69 |
nic0_mac = inst.GetNicMacAddr(0, None) |
70 |
|
71 |
if nic0_mac:
|
72 |
params.extend(["--net", "0:mac=%s" % nic0_mac]) |
73 |
|
74 |
return params
|
75 |
|
76 |
|
77 |
def _CreateInstanceByDiskTemplateRaw(nodes_spec, disk_template, fail=False): |
78 |
"""Creates an instance with the given disk template on the given nodes(s).
|
79 |
Note that this function does not check if enough nodes are given for
|
80 |
the respective disk template.
|
81 |
|
82 |
@type nodes_spec: string
|
83 |
@param nodes_spec: string specification of one node (by node name) or several
|
84 |
nodes according to the requirements of the disk template
|
85 |
@type disk_template: string
|
86 |
@param disk_template: the disk template to be used by the instance
|
87 |
@return: the created instance
|
88 |
|
89 |
"""
|
90 |
instance = qa_config.AcquireInstance() |
91 |
try:
|
92 |
cmd = (["gnt-instance", "add", |
93 |
"--os-type=%s" % qa_config.get("os"), |
94 |
"--disk-template=%s" % disk_template,
|
95 |
"--node=%s" % nodes_spec] +
|
96 |
GetGenericAddParameters(instance, disk_template)) |
97 |
cmd.append(instance.name) |
98 |
|
99 |
AssertCommand(cmd, fail=fail) |
100 |
|
101 |
if not fail: |
102 |
CheckSsconfInstanceList(instance.name) |
103 |
instance.SetDiskTemplate(disk_template) |
104 |
|
105 |
return instance
|
106 |
except:
|
107 |
instance.Release() |
108 |
raise
|
109 |
|
110 |
# Handle the case where creation is expected to fail
|
111 |
assert fail
|
112 |
instance.Release() |
113 |
return None |
114 |
|
115 |
|
116 |
def CreateInstanceDrbd8(nodes, fail=False): |
117 |
"""Creates an instance using disk template 'drbd' on the given nodes.
|
118 |
|
119 |
@type nodes: list of nodes
|
120 |
@param nodes: nodes to be used by the instance
|
121 |
@return: the created instance
|
122 |
|
123 |
"""
|
124 |
assert len(nodes) > 1 |
125 |
return _CreateInstanceByDiskTemplateRaw(
|
126 |
":".join(map(operator.attrgetter("primary"), nodes)), |
127 |
constants.DT_DRBD8, fail=fail) |
128 |
|
129 |
|
130 |
def CreateInstanceByDiskTemplateOneNode(nodes, disk_template, fail=False): |
131 |
"""Creates an instance using the given disk template for disk templates
|
132 |
for which one given node is sufficient. These templates are for example:
|
133 |
plain, diskless, file, sharedfile, blockdev, rados.
|
134 |
|
135 |
@type nodes: list of nodes
|
136 |
@param nodes: a list of nodes, whose first element is used to create the
|
137 |
instance
|
138 |
@type disk_template: string
|
139 |
@param disk_template: the disk template to be used by the instance
|
140 |
@return: the created instance
|
141 |
|
142 |
"""
|
143 |
assert len(nodes) > 0 |
144 |
return _CreateInstanceByDiskTemplateRaw(nodes[0].primary, disk_template, |
145 |
fail=fail) |
146 |
|
147 |
|
148 |
def CreateInstanceByDiskTemplate(nodes, disk_template, fail=False): |
149 |
"""Given a disk template, this function creates an instance using
|
150 |
the template. It uses the required number of nodes depending on
|
151 |
the disk template. This function is intended to be used by tests
|
152 |
that don't care about the specifics of the instance other than
|
153 |
that it uses the given disk template.
|
154 |
|
155 |
Note: If you use this function, make sure to call
|
156 |
'TestInstanceRemove' at the end of your tests to avoid orphaned
|
157 |
instances hanging around and interfering with the following tests.
|
158 |
|
159 |
@type nodes: list of nodes
|
160 |
@param nodes: the list of the nodes on which the instance will be placed;
|
161 |
it needs to have sufficiently many elements for the given
|
162 |
disk template
|
163 |
@type disk_template: string
|
164 |
@param disk_template: the disk template to be used by the instance
|
165 |
@return: the created instance
|
166 |
|
167 |
"""
|
168 |
if disk_template == constants.DT_DRBD8:
|
169 |
return CreateInstanceDrbd8(nodes, fail=fail)
|
170 |
elif disk_template in [constants.DT_DISKLESS, constants.DT_PLAIN, |
171 |
constants.DT_FILE]: |
172 |
return CreateInstanceByDiskTemplateOneNode(nodes, disk_template, fail=fail)
|
173 |
else:
|
174 |
# FIXME: This assumes that for all other disk templates, we only need one
|
175 |
# node and no disk template specific parameters. This else-branch is
|
176 |
# currently only used in cases where we expect failure. Extend it when
|
177 |
# QA needs for these templates change.
|
178 |
return CreateInstanceByDiskTemplateOneNode(nodes, disk_template, fail=fail)
|
179 |
|
180 |
|
181 |
def _ReadSsconfInstanceList(): |
182 |
"""Reads ssconf_instance_list from the master node.
|
183 |
|
184 |
"""
|
185 |
master = qa_config.GetMasterNode() |
186 |
|
187 |
ssconf_path = utils.PathJoin(pathutils.DATA_DIR, |
188 |
"ssconf_%s" % constants.SS_INSTANCE_LIST)
|
189 |
|
190 |
cmd = ["cat", qa_utils.MakeNodePath(master, ssconf_path)]
|
191 |
|
192 |
return qa_utils.GetCommandOutput(master.primary,
|
193 |
utils.ShellQuoteArgs(cmd)).splitlines() |
194 |
|
195 |
|
196 |
def CheckSsconfInstanceList(instance): |
197 |
"""Checks if a certain instance is in the ssconf instance list.
|
198 |
|
199 |
@type instance: string
|
200 |
@param instance: Instance name
|
201 |
|
202 |
"""
|
203 |
AssertIn(qa_utils.ResolveInstanceName(instance), |
204 |
_ReadSsconfInstanceList()) |