Statistics
| Branch: | Tag: | Revision:

root / qa / qa_group.py @ ec996117

History | View | Annotate | Download (9.4 kB)

1
#
2
#
3

    
4
# Copyright (C) 2010, 2011, 2012 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 tests for node groups.
23

24
"""
25

    
26
from ganeti import constants
27
from ganeti import query
28
from ganeti import utils
29

    
30
import qa_config
31
import qa_utils
32

    
33
from qa_utils import AssertCommand, AssertEqual, GetCommandOutput
34

    
35

    
36
def GetDefaultGroup():
37
  """Returns the default node group.
38

39
  """
40
  groups = qa_config.get("groups", {})
41
  return groups.get("group-with-nodes", constants.INITIAL_NODE_GROUP_NAME)
42

    
43

    
44
def TestGroupAddRemoveRename():
45
  """gnt-group add/remove/rename"""
46
  existing_group_with_nodes = GetDefaultGroup()
47

    
48
  (group1, group2, group3) = qa_utils.GetNonexistentGroups(3)
49

    
50
  AssertCommand(["gnt-group", "add", group1])
51
  AssertCommand(["gnt-group", "add", group2])
52
  AssertCommand(["gnt-group", "add", group2], fail=True)
53
  AssertCommand(["gnt-group", "add", existing_group_with_nodes], fail=True)
54

    
55
  AssertCommand(["gnt-group", "rename", group1, group2], fail=True)
56
  AssertCommand(["gnt-group", "rename", group1, group3])
57

    
58
  try:
59
    AssertCommand(["gnt-group", "rename", existing_group_with_nodes, group1])
60

    
61
    AssertCommand(["gnt-group", "remove", group2])
62
    AssertCommand(["gnt-group", "remove", group3])
63
    AssertCommand(["gnt-group", "remove", group1], fail=True)
64
  finally:
65
    # Try to ensure idempotency re groups that already existed.
66
    AssertCommand(["gnt-group", "rename", group1, existing_group_with_nodes])
67

    
68

    
69
def TestGroupAddWithOptions():
70
  """gnt-group add with options"""
71
  (group1, ) = qa_utils.GetNonexistentGroups(1)
72

    
73
  AssertCommand(["gnt-group", "add", "--alloc-policy", "notvalid", group1],
74
                fail=True)
75

    
76
  AssertCommand(["gnt-group", "add", "--alloc-policy", "last_resort",
77
                 "--node-parameters", "oob_program=/bin/true", group1])
78

    
79
  AssertCommand(["gnt-group", "remove", group1])
80

    
81

    
82
def _GetGroupIPolicy(groupname):
83
  """Return the run-time values of the cluster-level instance policy.
84

85
  @type groupname: string
86
  @param groupname: node group name
87
  @rtype: tuple
88
  @return: (policy, specs), where:
89
      - policy is a dictionary of the policy values, instance specs excluded
90
      - specs is dict of dict, specs[key][par] is a spec value, where key is
91
        "min" or "max"
92

93
  """
94
  info = qa_utils.GetObjectInfo(["gnt-group", "info", groupname])
95
  assert len(info) == 1
96
  policy = info[0]["Instance policy"]
97

    
98
  (ret_policy, ret_specs) = qa_utils.ParseIPolicy(policy)
99

    
100
  # Sanity checks
101
  assert "min" in ret_specs and "max" in ret_specs
102
  assert len(ret_policy) > 0
103
  return (ret_policy, ret_specs)
104

    
105

    
106
def _TestGroupSetISpecs(groupname, new_specs=None, diff_specs=None,
107
                        fail=False, old_values=None):
108
  """Change instance specs on a group.
109

110
  At most one of new_specs or diff_specs can be specified.
111

112
  @type groupname: string
113
  @param groupname: group name
114
  @type new_specs: dict
115
  @param new_specs: new complete specs, in the same format returned by
116
      L{_GetGroupIPolicy}
117
  @type diff_specs: dict
118
  @param diff_specs: diff_specs[key][par], where key is "min", "max". It
119
      can be an incomplete specifications or an empty dictionary.
120
  @type fail: bool
121
  @param fail: if the change is expected to fail
122
  @type old_values: tuple
123
  @param old_values: (old_policy, old_specs), as returned by
124
      L{_GetGroupIPolicy}
125
  @return: same as L{_GetGroupIPolicy}
126

127
  """
128
  build_cmd = lambda opts: ["gnt-group", "modify"] + opts + [groupname]
129
  get_policy = lambda: _GetGroupIPolicy(groupname)
130
  return qa_utils.TestSetISpecs(
131
    new_specs=new_specs, diff_specs=diff_specs,
132
    get_policy_fn=get_policy, build_cmd_fn=build_cmd,
133
    fail=fail, old_values=old_values)
134

    
135

    
136
def _TestGroupModifyISpecs(groupname):
137
  # This test is built on the assumption that the default ipolicy holds for
138
  # the node group under test
139
  old_values = _GetGroupIPolicy(groupname)
140
  samevals = dict((p, 4) for p in constants.ISPECS_PARAMETERS)
141
  base_specs = {"min": samevals, "max": samevals}
142
  mod_values = _TestGroupSetISpecs(groupname, new_specs=base_specs,
143
                                   old_values=old_values)
144
  for par in constants.ISPECS_PARAMETERS:
145
    # First make sure that the test works with good values
146
    good_specs = {"min": {par: 8}, "max": {par: 8}}
147
    mod_values = _TestGroupSetISpecs(groupname, diff_specs=good_specs,
148
                                     old_values=mod_values)
149
    bad_specs = {"min": {par: 8}, "max": {par: 4}}
150
    _TestGroupSetISpecs(groupname, diff_specs=bad_specs, fail=True,
151
                        old_values=mod_values)
152
  AssertCommand(["gnt-group", "modify", "--ipolicy-bounds-specs", "default",
153
                 groupname])
154
  AssertEqual(_GetGroupIPolicy(groupname), old_values)
155

    
156
  # Get the ipolicy command (from the cluster config)
157
  mnode = qa_config.GetMasterNode()
158
  addcmd = GetCommandOutput(mnode.primary, utils.ShellQuoteArgs([
159
    "gnt-group", "show-ispecs-cmd", "--include-defaults", groupname,
160
    ]))
161
  modcmd = ["gnt-group", "modify"]
162
  opts = addcmd.split()
163
  assert opts[0:2] == ["gnt-group", "add"]
164
  for k in range(2, len(opts) - 1):
165
    if opts[k].startswith("--ipolicy-"):
166
      assert k + 2 <= len(opts)
167
      modcmd.extend(opts[k:k + 2])
168
  modcmd.append(groupname)
169
  # Apply the ipolicy to the group and verify the result
170
  AssertCommand(modcmd)
171
  new_addcmd = GetCommandOutput(mnode.primary, utils.ShellQuoteArgs([
172
    "gnt-group", "show-ispecs-cmd", groupname,
173
    ]))
174
  AssertEqual(addcmd, new_addcmd)
175

    
176

    
177
def _TestGroupModifyIPolicy(groupname):
178
  _TestGroupModifyISpecs(groupname)
179

    
180
  # We assume that the default ipolicy holds
181
  (old_policy, old_specs) = _GetGroupIPolicy(groupname)
182
  for (par, setval, iname, expval) in [
183
    ("vcpu-ratio", 1.5, None, 1.5),
184
    ("spindle-ratio", 1.5, None, 1.5),
185
    ("disk-templates", constants.DT_PLAIN,
186
     "enabled disk templates", constants.DT_PLAIN)
187
    ]:
188
    if not iname:
189
      iname = par
190
    build_cmdline = lambda val: ["gnt-group", "modify", "--ipolicy-" + par,
191
                                 str(val), groupname]
192

    
193
    AssertCommand(build_cmdline(setval))
194
    (new_policy, new_specs) = _GetGroupIPolicy(groupname)
195
    AssertEqual(new_specs, old_specs)
196
    for (p, val) in new_policy.items():
197
      if p == iname:
198
        AssertEqual(val, expval)
199
      else:
200
        AssertEqual(val, old_policy[p])
201

    
202
    AssertCommand(build_cmdline("default"))
203
    (new_policy, new_specs) = _GetGroupIPolicy(groupname)
204
    AssertEqual(new_specs, old_specs)
205
    AssertEqual(new_policy, old_policy)
206

    
207

    
208
def TestGroupModify():
209
  """gnt-group modify"""
210
  (group1, ) = qa_utils.GetNonexistentGroups(1)
211

    
212
  AssertCommand(["gnt-group", "add", group1])
213

    
214
  try:
215
    _TestGroupModifyIPolicy(group1)
216
    AssertCommand(["gnt-group", "modify", "--alloc-policy", "unallocable",
217
                   "--node-parameters", "oob_program=/bin/false", group1])
218
    AssertCommand(["gnt-group", "modify",
219
                   "--alloc-policy", "notvalid", group1], fail=True)
220
    AssertCommand(["gnt-group", "modify",
221
                   "--node-parameters", "spindle_count=10", group1])
222
    if qa_config.TestEnabled("htools"):
223
      AssertCommand(["hbal", "-L", "-G", group1])
224
    AssertCommand(["gnt-group", "modify",
225
                   "--node-parameters", "spindle_count=default", group1])
226
  finally:
227
    AssertCommand(["gnt-group", "remove", group1])
228

    
229

    
230
def TestGroupList():
231
  """gnt-group list"""
232
  qa_utils.GenericQueryTest("gnt-group", query.GROUP_FIELDS.keys())
233

    
234

    
235
def TestGroupListFields():
236
  """gnt-group list-fields"""
237
  qa_utils.GenericQueryFieldsTest("gnt-group", query.GROUP_FIELDS.keys())
238

    
239

    
240
def TestAssignNodesIncludingSplit(orig_group, node1, node2):
241
  """gnt-group assign-nodes --force
242

243
  Expects node1 and node2 to be primary and secondary for a common instance.
244

245
  """
246
  assert node1 != node2
247

    
248
  (other_group, ) = qa_utils.GetNonexistentGroups(1)
249

    
250
  master_node = qa_config.GetMasterNode().primary
251

    
252
  def AssertInGroup(group, nodes):
253
    real_output = GetCommandOutput(master_node,
254
                                   "gnt-node list --no-headers -o group " +
255
                                   utils.ShellQuoteArgs(nodes))
256
    AssertEqual(real_output.splitlines(), [group] * len(nodes))
257

    
258
  AssertInGroup(orig_group, [node1, node2])
259
  AssertCommand(["gnt-group", "add", other_group])
260

    
261
  try:
262
    AssertCommand(["gnt-group", "assign-nodes", other_group, node1, node2])
263
    AssertInGroup(other_group, [node1, node2])
264

    
265
    # This should fail because moving node1 to orig_group would leave their
266
    # common instance split between orig_group and other_group.
267
    AssertCommand(["gnt-group", "assign-nodes", orig_group, node1], fail=True)
268
    AssertInGroup(other_group, [node1, node2])
269

    
270
    AssertCommand(["gnt-group", "assign-nodes", "--force", orig_group, node1])
271
    AssertInGroup(orig_group, [node1])
272
    AssertInGroup(other_group, [node2])
273

    
274
    AssertCommand(["gnt-group", "assign-nodes", orig_group, node2])
275
    AssertInGroup(orig_group, [node1, node2])
276
  finally:
277
    AssertCommand(["gnt-group", "remove", other_group])