1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 """Node group related commands"""
31
32
33
34
35
36 from cStringIO import StringIO
37
38 from ganeti.cli import *
39 from ganeti import constants
40 from ganeti import opcodes
41 from ganeti import utils
42 from ganeti import compat
43 from ganeti.client import base
44
45
46
47 _LIST_DEF_FIELDS = ["name", "node_cnt", "pinst_cnt", "alloc_policy", "ndparams"]
48
49 _ENV_OVERRIDE = compat.UniqueFrozenset(["list"])
50
51
53 """Add a node group to the cluster.
54
55 @param opts: the command line options selected by the user
56 @type args: list
57 @param args: a list of length 1 with the name of the group to create
58 @rtype: int
59 @return: the desired exit code
60
61 """
62 ipolicy = CreateIPolicyFromOpts(
63 minmax_ispecs=opts.ipolicy_bounds_specs,
64 ipolicy_vcpu_ratio=opts.ipolicy_vcpu_ratio,
65 ipolicy_spindle_ratio=opts.ipolicy_spindle_ratio,
66 ipolicy_disk_templates=opts.ipolicy_disk_templates,
67 group_ipolicy=True)
68
69 (group_name,) = args
70 diskparams = dict(opts.diskparams)
71
72 if opts.disk_state:
73 disk_state = utils.FlatToDict(opts.disk_state)
74 else:
75 disk_state = {}
76 hv_state = dict(opts.hv_state)
77
78 op = opcodes.OpGroupAdd(group_name=group_name, ndparams=opts.ndparams,
79 alloc_policy=opts.alloc_policy,
80 diskparams=diskparams, ipolicy=ipolicy,
81 hv_state=hv_state,
82 disk_state=disk_state)
83 return base.GetResult(None, opts, SubmitOrSend(op, opts))
84
85
87 """Assign nodes to a group.
88
89 @param opts: the command line options selected by the user
90 @type args: list
91 @param args: args[0]: group to assign nodes to; args[1:]: nodes to assign
92 @rtype: int
93 @return: the desired exit code
94
95 """
96 group_name = args[0]
97 node_names = args[1:]
98
99 op = opcodes.OpGroupAssignNodes(group_name=group_name, nodes=node_names,
100 force=opts.force)
101 SubmitOrSend(op, opts)
102
103
105 """Format dict data into command-line format.
106
107 @param data: The input dict to be formatted
108 @return: The formatted dict
109
110 """
111 if not data:
112 return "(empty)"
113
114 return utils.CommaJoin(["%s=%s" % (key, value)
115 for key, value in data.items()])
116
117
119 """List node groups and their properties.
120
121 @param opts: the command line options selected by the user
122 @type args: list
123 @param args: groups to list, or empty for all
124 @rtype: int
125 @return: the desired exit code
126
127 """
128 desired_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
129 fmtoverride = {
130 "node_list": (",".join, False),
131 "pinst_list": (",".join, False),
132 "ndparams": (_FmtDict, False),
133 }
134
135 cl = GetClient()
136
137 return GenericList(constants.QR_GROUP, desired_fields, args, None,
138 opts.separator, not opts.no_headers,
139 format_override=fmtoverride, verbose=opts.verbose,
140 force_filter=opts.force_filter, cl=cl)
141
142
144 """List node fields.
145
146 @param opts: the command line options selected by the user
147 @type args: list
148 @param args: fields to list, or empty for all
149 @rtype: int
150 @return: the desired exit code
151
152 """
153 cl = GetClient()
154
155 return GenericListFields(constants.QR_GROUP, args, opts.separator,
156 not opts.no_headers, cl=cl)
157
158
160 """Modifies a node group's parameters.
161
162 @param opts: the command line options selected by the user
163 @type args: list
164 @param args: should contain only one element, the node group name
165
166 @rtype: int
167 @return: the desired exit code
168
169 """
170 allmods = [opts.ndparams, opts.alloc_policy, opts.diskparams, opts.hv_state,
171 opts.disk_state, opts.ipolicy_bounds_specs,
172 opts.ipolicy_vcpu_ratio, opts.ipolicy_spindle_ratio,
173 opts.diskparams, opts.ipolicy_disk_templates]
174 if allmods.count(None) == len(allmods):
175 ToStderr("Please give at least one of the parameters.")
176 return 1
177
178 if opts.disk_state:
179 disk_state = utils.FlatToDict(opts.disk_state)
180 else:
181 disk_state = {}
182
183 hv_state = dict(opts.hv_state)
184
185 diskparams = dict(opts.diskparams)
186
187
188 ipolicy = CreateIPolicyFromOpts(
189 minmax_ispecs=opts.ipolicy_bounds_specs,
190 ipolicy_disk_templates=opts.ipolicy_disk_templates,
191 ipolicy_vcpu_ratio=opts.ipolicy_vcpu_ratio,
192 ipolicy_spindle_ratio=opts.ipolicy_spindle_ratio,
193 group_ipolicy=True,
194 allowed_values=[constants.VALUE_DEFAULT])
195
196 op = opcodes.OpGroupSetParams(group_name=args[0],
197 ndparams=opts.ndparams,
198 alloc_policy=opts.alloc_policy,
199 hv_state=hv_state,
200 disk_state=disk_state,
201 diskparams=diskparams,
202 ipolicy=ipolicy)
203
204 result = SubmitOrSend(op, opts)
205
206 if result:
207 ToStdout("Modified node group %s", args[0])
208 for param, data in result:
209 ToStdout(" - %-5s -> %s", param, data)
210
211 return 0
212
213
215 """Remove a node group from the cluster.
216
217 @param opts: the command line options selected by the user
218 @type args: list
219 @param args: a list of length 1 with the name of the group to remove
220 @rtype: int
221 @return: the desired exit code
222
223 """
224 (group_name,) = args
225 op = opcodes.OpGroupRemove(group_name=group_name)
226 SubmitOrSend(op, opts)
227
228
230 """Rename a node group.
231
232 @param opts: the command line options selected by the user
233 @type args: list
234 @param args: a list of length 2, [old_name, new_name]
235 @rtype: int
236 @return: the desired exit code
237
238 """
239 group_name, new_name = args
240 op = opcodes.OpGroupRename(group_name=group_name, new_name=new_name)
241 SubmitOrSend(op, opts)
242
243
245 """Evacuate a node group.
246
247 """
248 (group_name, ) = args
249
250 cl = GetClient()
251
252 op = opcodes.OpGroupEvacuate(group_name=group_name,
253 iallocator=opts.iallocator,
254 target_groups=opts.to,
255 early_release=opts.early_release,
256 sequential=opts.sequential,
257 force_failover=opts.force_failover)
258 result = SubmitOrSend(op, opts, cl=cl)
259
260
261 jex = JobExecutor(cl=cl, opts=opts)
262
263 for (status, job_id) in result[constants.JOB_IDS_KEY]:
264 jex.AddJobId(None, status, job_id)
265
266 results = jex.GetResults()
267 bad_cnt = len([row for row in results if not row[0]])
268 if bad_cnt == 0:
269 ToStdout("All instances evacuated successfully.")
270 rcode = constants.EXIT_SUCCESS
271 else:
272 ToStdout("There were %s errors during the evacuation.", bad_cnt)
273 rcode = constants.EXIT_FAILURE
274
275 return rcode
276
277
287
288
290 """Shows info about node group.
291
292 """
293 cl = GetClient()
294 selected_fields = ["name",
295 "ndparams", "custom_ndparams",
296 "diskparams", "custom_diskparams",
297 "ipolicy", "custom_ipolicy"]
298 result = cl.QueryGroups(names=args, fields=selected_fields,
299 use_locking=False)
300
301 PrintGenericInfo([
302 _FormatGroupInfo(group) for group in result
303 ])
304
305
314
315
317 """Shows the command that can be used to re-create a node group.
318
319 Currently it works only for ipolicy specs.
320
321 """
322 cl = GetClient()
323 selected_fields = ["name"]
324 if opts.include_defaults:
325 selected_fields += ["ipolicy"]
326 else:
327 selected_fields += ["custom_ipolicy"]
328 result = cl.QueryGroups(names=args, fields=selected_fields,
329 use_locking=False)
330
331 for group in result:
332 ToStdout(_GetCreateCommand(group))
333
334
335 commands = {
336 "add": (
337 AddGroup, ARGS_ONE_GROUP,
338 [DRY_RUN_OPT, ALLOC_POLICY_OPT, NODE_PARAMS_OPT, DISK_PARAMS_OPT,
339 HV_STATE_OPT, DISK_STATE_OPT, PRIORITY_OPT]
340 + SUBMIT_OPTS + INSTANCE_POLICY_OPTS,
341 "<group_name>", "Add a new node group to the cluster"),
342 "assign-nodes": (
343 AssignNodes, ARGS_ONE_GROUP + ARGS_MANY_NODES,
344 [DRY_RUN_OPT, FORCE_OPT, PRIORITY_OPT] + SUBMIT_OPTS,
345 "<group_name> <node>...", "Assign nodes to a group"),
346 "list": (
347 ListGroups, ARGS_MANY_GROUPS,
348 [NOHDR_OPT, SEP_OPT, FIELDS_OPT, VERBOSE_OPT, FORCE_FILTER_OPT],
349 "[<group_name>...]",
350 "Lists the node groups in the cluster. The available fields can be shown"
351 " using the \"list-fields\" command (see the man page for details)."
352 " The default list is (in order): %s." % utils.CommaJoin(_LIST_DEF_FIELDS)),
353 "list-fields": (
354 ListGroupFields, [ArgUnknown()], [NOHDR_OPT, SEP_OPT], "[fields...]",
355 "Lists all available fields for node groups"),
356 "modify": (
357 SetGroupParams, ARGS_ONE_GROUP,
358 [DRY_RUN_OPT] + SUBMIT_OPTS +
359 [ALLOC_POLICY_OPT, NODE_PARAMS_OPT, HV_STATE_OPT, DISK_STATE_OPT,
360 DISK_PARAMS_OPT, PRIORITY_OPT]
361 + INSTANCE_POLICY_OPTS,
362 "<group_name>", "Alters the parameters of a node group"),
363 "remove": (
364 RemoveGroup, ARGS_ONE_GROUP, [DRY_RUN_OPT, PRIORITY_OPT] + SUBMIT_OPTS,
365 "[--dry-run] <group-name>",
366 "Remove an (empty) node group from the cluster"),
367 "rename": (
368 RenameGroup, [ArgGroup(min=2, max=2)],
369 [DRY_RUN_OPT] + SUBMIT_OPTS + [PRIORITY_OPT],
370 "[--dry-run] <group-name> <new-name>", "Rename a node group"),
371 "evacuate": (
372 EvacuateGroup, [ArgGroup(min=1, max=1)],
373 [TO_GROUP_OPT, IALLOCATOR_OPT, EARLY_RELEASE_OPT, SEQUENTIAL_OPT,
374 FORCE_FAILOVER_OPT]
375 + SUBMIT_OPTS,
376 "[-I <iallocator>] [--to <group>]",
377 "Evacuate all instances within a group"),
378 "list-tags": (
379 ListTags, ARGS_ONE_GROUP, [],
380 "<group_name>", "List the tags of the given group"),
381 "add-tags": (
382 AddTags, [ArgGroup(min=1, max=1), ArgUnknown()],
383 [TAG_SRC_OPT, PRIORITY_OPT] + SUBMIT_OPTS,
384 "<group_name> tag...", "Add tags to the given group"),
385 "remove-tags": (
386 RemoveTags, [ArgGroup(min=1, max=1), ArgUnknown()],
387 [TAG_SRC_OPT, PRIORITY_OPT] + SUBMIT_OPTS,
388 "<group_name> tag...", "Remove tags from the given group"),
389 "info": (
390 GroupInfo, ARGS_MANY_GROUPS, [], "[<group_name>...]",
391 "Show group information"),
392 "show-ispecs-cmd": (
393 ShowCreateCommand, ARGS_MANY_GROUPS, [INCLUDEDEFAULTS_OPT],
394 "[--include-defaults] [<group_name>...]",
395 "Show the command line to re-create a group"),
396 }
397
398
400 return GenericMain(commands,
401 override={"tag_type": constants.TAG_NODEGROUP},
402 env_override=_ENV_OVERRIDE)
403