1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 """IP pool related commands"""
22
23
24
25
26
27 import textwrap
28 import itertools
29
30 from ganeti.cli import *
31 from ganeti import constants
32 from ganeti import opcodes
33 from ganeti import utils
34 from ganeti import errors
35
36
37
38 _LIST_DEF_FIELDS = ["name", "network", "gateway",
39 "mac_prefix", "group_list", "tags"]
40
41
43 if ips is None:
44 return None
45 elif not ips:
46 return []
47 else:
48 return utils.UnescapeAndSplit(ips, sep=",")
49
50
52 """Add a network to the cluster.
53
54 @param opts: the command line options selected by the user
55 @type args: list
56 @param args: a list of length 1 with the network name to create
57 @rtype: int
58 @return: the desired exit code
59
60 """
61 (network_name, ) = args
62
63 if opts.network is None:
64 raise errors.OpPrereqError("The --network option must be given",
65 errors.ECODE_INVAL)
66
67 if opts.tags is not None:
68 tags = opts.tags.split(",")
69 else:
70 tags = []
71
72 reserved_ips = _HandleReservedIPs(opts.add_reserved_ips)
73
74 op = opcodes.OpNetworkAdd(network_name=network_name,
75 gateway=opts.gateway,
76 network=opts.network,
77 gateway6=opts.gateway6,
78 network6=opts.network6,
79 mac_prefix=opts.mac_prefix,
80 add_reserved_ips=reserved_ips,
81 conflicts_check=opts.conflicts_check,
82 tags=tags)
83 SubmitOrSend(op, opts)
84
85
87 """Gets list of groups to operate on.
88
89 If C{groups} doesn't contain groups, a list of all groups in the cluster is
90 returned.
91
92 @type cl: L{luxi.Client}
93 @type groups: list
94 @rtype: list
95
96 """
97 if groups:
98 return groups
99
100 return list(itertools.chain(*cl.QueryGroups([], ["uuid"], False)))
101
102
104 """Map a network to a node group.
105
106 @param opts: the command line options selected by the user
107 @type args: list
108 @param args: Network, mode, physlink and node groups
109 @rtype: int
110 @return: the desired exit code
111
112 """
113 cl = GetClient()
114
115 (network, mode, link) = args[:3]
116 groups = _GetDefaultGroups(cl, args[3:])
117
118
119 for group in groups:
120 op = opcodes.OpNetworkConnect(group_name=group,
121 network_name=network,
122 network_mode=mode,
123 network_link=link,
124 conflicts_check=opts.conflicts_check)
125 SubmitOpCode(op, opts=opts, cl=cl)
126
127
129 """Unmap a network from a node group.
130
131 @param opts: the command line options selected by the user
132 @type args: list
133 @param args: Network and node groups
134 @rtype: int
135 @return: the desired exit code
136
137 """
138 cl = GetClient()
139
140 (network, ) = args[:1]
141 groups = _GetDefaultGroups(cl, args[1:])
142
143
144 for group in groups:
145 op = opcodes.OpNetworkDisconnect(group_name=group,
146 network_name=network)
147 SubmitOpCode(op, opts=opts, cl=cl)
148
149
151 """List Ip pools and their properties.
152
153 @param opts: the command line options selected by the user
154 @type args: list
155 @param args: networks to list, or empty for all
156 @rtype: int
157 @return: the desired exit code
158
159 """
160 desired_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
161 fmtoverride = {
162 "group_list":
163 (lambda data: utils.CommaJoin("%s (%s, %s)" % (name, mode, link)
164 for (name, mode, link) in data),
165 False),
166 "inst_list": (",".join, False),
167 "tags": (",".join, False),
168 }
169
170 cl = GetClient(query=True)
171 return GenericList(constants.QR_NETWORK, desired_fields, args, None,
172 opts.separator, not opts.no_headers,
173 verbose=opts.verbose, format_override=fmtoverride,
174 cl=cl)
175
176
178 """List network fields.
179
180 @param opts: the command line options selected by the user
181 @type args: list
182 @param args: fields to list, or empty for all
183 @rtype: int
184 @return: the desired exit code
185
186 """
187 cl = GetClient(query=True)
188
189 return GenericListFields(constants.QR_NETWORK, args, opts.separator,
190 not opts.no_headers, cl=cl)
191
192
194 """Show network information.
195
196 @type args: list
197 @param args: should either be an empty list, in which case
198 we show information about all nodes, or should contain
199 a list of networks (names or UUIDs) to be queried for information
200 @rtype: int
201 @return: the desired exit code
202
203 """
204 cl = GetClient()
205 result = cl.QueryNetworks(fields=["name", "network", "gateway",
206 "network6", "gateway6",
207 "mac_prefix",
208 "free_count", "reserved_count",
209 "map", "group_list", "inst_list",
210 "external_reservations",
211 "serial_no", "uuid"],
212 names=args, use_locking=False)
213
214 for (name, network, gateway, network6, gateway6,
215 mac_prefix, free_count, reserved_count,
216 mapping, group_list, instances, ext_res, serial, uuid) in result:
217 size = free_count + reserved_count
218 ToStdout("Network name: %s", name)
219 ToStdout("UUID: %s", uuid)
220 ToStdout("Serial number: %d", serial)
221 ToStdout(" Subnet: %s", network)
222 ToStdout(" Gateway: %s", gateway)
223 ToStdout(" IPv6 Subnet: %s", network6)
224 ToStdout(" IPv6 Gateway: %s", gateway6)
225 ToStdout(" Mac Prefix: %s", mac_prefix)
226 ToStdout(" Size: %d", size)
227 ToStdout(" Free: %d (%.2f%%)", free_count,
228 100 * float(free_count) / float(size))
229 ToStdout(" Usage map:")
230 idx = 0
231 for line in textwrap.wrap(mapping, width=64):
232 ToStdout(" %s %s %d", str(idx).rjust(3), line.ljust(64), idx + 63)
233 idx += 64
234 ToStdout(" (X) used (.) free")
235
236 if ext_res:
237 ToStdout(" externally reserved IPs:")
238 for line in textwrap.wrap(ext_res, width=64):
239 ToStdout(" %s" % line)
240
241 if group_list:
242 ToStdout(" connected to node groups:")
243 for group, nic_mode, nic_link in group_list:
244 ToStdout(" %s (%s on %s)", group, nic_mode, nic_link)
245 else:
246 ToStdout(" not connected to any node group")
247
248 if instances:
249 idata = cl.QueryInstances([], ["uuid", "name"], False)
250 uuid2name = dict(idata)
251
252 ToStdout(" used by %d instances:", len(instances))
253 for inst in instances:
254 name = uuid2name[inst]
255 ((ips, networks), ) = cl.QueryInstances([name],
256 ["nic.ips", "nic.networks"],
257 use_locking=False)
258
259 l = lambda value: ", ".join(str(idx) + ":" + str(ip)
260 for idx, (ip, net) in enumerate(value)
261 if net == uuid)
262
263 ToStdout(" %s: %s", name, l(zip(ips, networks)))
264 else:
265 ToStdout(" not used by any instances")
266
267
269 """Modifies an IP address pool's parameters.
270
271 @param opts: the command line options selected by the user
272 @type args: list
273 @param args: should contain only one element, the node group name
274
275 @rtype: int
276 @return: the desired exit code
277
278 """
279
280 all_changes = {
281 "gateway": opts.gateway,
282 "add_reserved_ips": _HandleReservedIPs(opts.add_reserved_ips),
283 "remove_reserved_ips": _HandleReservedIPs(opts.remove_reserved_ips),
284 "mac_prefix": opts.mac_prefix,
285 "gateway6": opts.gateway6,
286 "network6": opts.network6,
287 }
288
289 if all_changes.values().count(None) == len(all_changes):
290 ToStderr("Please give at least one of the parameters.")
291 return 1
292
293
294 op = opcodes.OpNetworkSetParams(network_name=args[0], **all_changes)
295
296
297 SubmitOrSend(op, opts)
298
299
301 """Remove an IP address pool from the cluster.
302
303 @param opts: the command line options selected by the user
304 @type args: list
305 @param args: a list of length 1 with the id of the IP address pool to remove
306 @rtype: int
307 @return: the desired exit code
308
309 """
310 (network_name,) = args
311 op = opcodes.OpNetworkRemove(network_name=network_name, force=opts.force)
312 SubmitOrSend(op, opts)
313
314
315 commands = {
316 "add": (
317 AddNetwork, ARGS_ONE_NETWORK,
318 [DRY_RUN_OPT, NETWORK_OPT, GATEWAY_OPT, ADD_RESERVED_IPS_OPT,
319 MAC_PREFIX_OPT, NETWORK6_OPT, GATEWAY6_OPT,
320 NOCONFLICTSCHECK_OPT, TAG_ADD_OPT, PRIORITY_OPT] + SUBMIT_OPTS,
321 "<network_name>", "Add a new IP network to the cluster"),
322 "list": (
323 ListNetworks, ARGS_MANY_NETWORKS,
324 [NOHDR_OPT, SEP_OPT, FIELDS_OPT, VERBOSE_OPT],
325 "[<network_id>...]",
326 "Lists the IP networks in the cluster. The available fields can be shown"
327 " using the \"list-fields\" command (see the man page for details)."
328 " The default list is (in order): %s." % utils.CommaJoin(_LIST_DEF_FIELDS)),
329 "list-fields": (
330 ListNetworkFields, [ArgUnknown()], [NOHDR_OPT, SEP_OPT], "[fields...]",
331 "Lists all available fields for networks"),
332 "info": (
333 ShowNetworkConfig, ARGS_MANY_NETWORKS, [],
334 "[<network_name>...]", "Show information about the network(s)"),
335 "modify": (
336 SetNetworkParams, ARGS_ONE_NETWORK,
337 [DRY_RUN_OPT] + SUBMIT_OPTS +
338 [ADD_RESERVED_IPS_OPT,
339 REMOVE_RESERVED_IPS_OPT, GATEWAY_OPT, MAC_PREFIX_OPT, NETWORK6_OPT,
340 GATEWAY6_OPT, PRIORITY_OPT],
341 "<network_name>", "Alters the parameters of a network"),
342 "connect": (
343 ConnectNetwork,
344 [ArgNetwork(min=1, max=1),
345 ArgChoice(min=1, max=1, choices=constants.NIC_VALID_MODES),
346 ArgUnknown(min=1, max=1),
347 ArgGroup()],
348 [NOCONFLICTSCHECK_OPT, PRIORITY_OPT],
349 "<network_name> <mode> <link> [<node_group>...]",
350 "Map a given network to the specified node group"
351 " with given mode and link (netparams)"),
352 "disconnect": (
353 DisconnectNetwork,
354 [ArgNetwork(min=1, max=1), ArgGroup()],
355 [PRIORITY_OPT],
356 "<network_name> [<node_group>...]",
357 "Unmap a given network from a specified node group"),
358 "remove": (
359 RemoveNetwork, ARGS_ONE_NETWORK,
360 [FORCE_OPT, DRY_RUN_OPT] + SUBMIT_OPTS + [PRIORITY_OPT],
361 "[--dry-run] <network_id>",
362 "Remove an (empty) network from the cluster"),
363 "list-tags": (
364 ListTags, ARGS_ONE_NETWORK, [],
365 "<network_name>", "List the tags of the given network"),
366 "add-tags": (
367 AddTags, [ArgNetwork(min=1, max=1), ArgUnknown()],
368 [TAG_SRC_OPT, PRIORITY_OPT] + SUBMIT_OPTS,
369 "<network_name> tag...", "Add tags to the given network"),
370 "remove-tags": (
371 RemoveTags, [ArgNetwork(min=1, max=1), ArgUnknown()],
372 [TAG_SRC_OPT, PRIORITY_OPT] + SUBMIT_OPTS,
373 "<network_name> tag...", "Remove tags from given network"),
374 }
375
376
378 return GenericMain(commands, override={"tag_type": constants.TAG_NETWORK})
379