4 # Copyright (C) 2011, 2012 Google Inc.
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.
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.
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
21 """IP pool related commands"""
23 # pylint: disable=W0401,W0614
24 # W0401: Wildcard import ganeti.cli
25 # W0614: Unused import %s from wildcard import (since we need cli)
27 from ganeti.cli import *
28 from ganeti import constants
29 from ganeti import opcodes
30 from ganeti import utils
31 from textwrap import wrap
34 #: default list of fields for L{ListNetworks}
35 _LIST_DEF_FIELDS = ["name", "network", "gateway",
36 "network_type", "mac_prefix", "group_list", "tags"]
39 def _HandleReservedIPs(ips):
44 return utils.UnescapeAndSplit(ips, sep=",")
48 def AddNetwork(opts, args):
49 """Add a network to the cluster.
51 @param opts: the command line options selected by the user
53 @param args: a list of length 1 with the network name to create
55 @return: the desired exit code
58 (network_name, ) = args
60 if opts.tags is not None:
61 tags = opts.tags.split(",")
65 op = opcodes.OpNetworkAdd(
66 network_name=network_name,
69 gateway6=opts.gateway6,
70 network6=opts.network6,
71 mac_prefix=opts.mac_prefix,
72 network_type=opts.network_type,
73 add_reserved_ips=_HandleReservedIPs(opts.add_reserved_ips),
74 conflicts_check=opts.conflicts_check,
76 SubmitOpCode(op, opts=opts)
79 def MapNetwork(opts, args):
80 """Map a network to a node group.
82 @param opts: the command line options selected by the user
84 @param args: a list of length 3 with network, nodegroup, mode, physlink
86 @return: the desired exit code
94 # TODO: allow comma separated group names
97 (groups, ) = cl.QueryGroups([], ["name"], False)
102 op = opcodes.OpNetworkConnect(group_name=group,
103 network_name=network,
106 conflicts_check=opts.conflicts_check)
107 SubmitOpCode(op, opts=opts)
110 def UnmapNetwork(opts, args):
111 """Unmap a network from a node group.
113 @param opts: the command line options selected by the user
115 @param args: a list of length 3 with network, nodegorup
117 @return: the desired exit code
123 #TODO: allow comma separated group names
126 (groups, ) = cl.QueryGroups([], ["name"], False)
131 op = opcodes.OpNetworkDisconnect(group_name=group,
132 network_name=network,
133 conflicts_check=opts.conflicts_check)
134 SubmitOpCode(op, opts=opts)
137 def ListNetworks(opts, args):
138 """List Ip pools and their properties.
140 @param opts: the command line options selected by the user
142 @param args: networks to list, or empty for all
144 @return: the desired exit code
147 desired_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
149 "group_list": (",".join, False),
150 "inst_list": (",".join, False),
151 "tags": (",".join, False),
154 return GenericList(constants.QR_NETWORK, desired_fields, args, None,
155 opts.separator, not opts.no_headers,
156 verbose=opts.verbose, format_override=fmtoverride)
159 def ListNetworkFields(opts, args):
160 """List network fields.
162 @param opts: the command line options selected by the user
164 @param args: fields to list, or empty for all
166 @return: the desired exit code
169 return GenericListFields(constants.QR_NETWORK, args, opts.separator,
173 def ShowNetworkConfig(_, args):
174 """Show network information.
177 @param args: should either be an empty list, in which case
178 we show information about all nodes, or should contain
179 a list of networks (names or UUIDs) to be queried for information
181 @return: the desired exit code
185 result = cl.QueryNetworks(fields=["name", "network", "gateway",
186 "network6", "gateway6",
187 "mac_prefix", "network_type",
188 "free_count", "reserved_count",
189 "map", "group_list", "inst_list",
190 "external_reservations",
191 "serial_no", "uuid"],
192 names=args, use_locking=False)
194 for (name, network, gateway, network6, gateway6,
195 mac_prefix, network_type, free_count, reserved_count,
196 mapping, group_list, instances, ext_res, serial, uuid) in result:
197 size = free_count + reserved_count
198 ToStdout("Network name: %s", name)
199 ToStdout("UUID: %s", uuid)
200 ToStdout("Serial number: %d", serial)
201 ToStdout(" Subnet: %s", network)
202 ToStdout(" Gateway: %s", gateway)
203 ToStdout(" IPv6 Subnet: %s", network6)
204 ToStdout(" IPv6 Gateway: %s", gateway6)
205 ToStdout(" Mac Prefix: %s", mac_prefix)
206 ToStdout(" Type: %s", network_type)
207 ToStdout(" Size: %d", size)
208 ToStdout(" Free: %d (%.2f%%)", free_count,
209 100 * float(free_count) / float(size))
210 ToStdout(" Usage map:")
212 for line in wrap(mapping, width=64):
213 ToStdout(" %s %s %d", str(idx).rjust(3), line.ljust(64), idx + 63)
215 ToStdout(" (X) used (.) free")
218 ToStdout(" externally reserved IPs:")
219 for line in wrap(ext_res, width=64):
220 ToStdout(" %s" % line)
223 ToStdout(" connected to node groups:")
224 for group in group_list:
225 ToStdout(" %s", group)
227 ToStdout(" not connected to any node group")
230 ToStdout(" used by %d instances:", len(instances))
231 for inst in instances:
232 ((ips, networks), ) = cl.QueryInstances([inst],
233 ["nic.ips", "nic.networks"],
236 l = lambda value: ", ".join(str(idx) + ":" + str(ip)
237 for idx, (ip, net) in enumerate(value)
240 ToStdout(" %s : %s", inst, l(zip(ips, networks)))
242 ToStdout(" not used by any instances")
245 def SetNetworkParams(opts, args):
246 """Modifies an IP address pool's parameters.
248 @param opts: the command line options selected by the user
250 @param args: should contain only one element, the node group name
253 @return: the desired exit code
257 # TODO: add "network": opts.network,
259 "gateway": opts.gateway,
260 "add_reserved_ips": _HandleReservedIPs(opts.add_reserved_ips),
261 "remove_reserved_ips": _HandleReservedIPs(opts.remove_reserved_ips),
262 "mac_prefix": opts.mac_prefix,
263 "network_type": opts.network_type,
264 "gateway6": opts.gateway6,
265 "network6": opts.network6,
268 if all_changes.values().count(None) == len(all_changes):
269 ToStderr("Please give at least one of the parameters.")
272 # pylint: disable=W0142
273 op = opcodes.OpNetworkSetParams(network_name=args[0], **all_changes)
275 # TODO: add feedback to user, e.g. list the modifications
276 SubmitOrSend(op, opts)
279 def RemoveNetwork(opts, args):
280 """Remove an IP address pool from the cluster.
282 @param opts: the command line options selected by the user
284 @param args: a list of length 1 with the id of the IP address pool to remove
286 @return: the desired exit code
289 (network_name,) = args
290 op = opcodes.OpNetworkRemove(network_name=network_name, force=opts.force)
291 SubmitOpCode(op, opts=opts)
296 AddNetwork, ARGS_ONE_NETWORK,
297 [DRY_RUN_OPT, NETWORK_OPT, GATEWAY_OPT, ADD_RESERVED_IPS_OPT,
298 MAC_PREFIX_OPT, NETWORK_TYPE_OPT, NETWORK6_OPT, GATEWAY6_OPT,
299 NOCONFLICTSCHECK_OPT, TAG_ADD_OPT],
300 "<network_name>", "Add a new IP network to the cluster"),
302 ListNetworks, ARGS_MANY_NETWORKS,
303 [NOHDR_OPT, SEP_OPT, FIELDS_OPT, VERBOSE_OPT],
305 "Lists the IP networks in the cluster. The available fields can be shown"
306 " using the \"list-fields\" command (see the man page for details)."
307 " The default list is (in order): %s." % utils.CommaJoin(_LIST_DEF_FIELDS)),
309 ListNetworkFields, [ArgUnknown()], [NOHDR_OPT, SEP_OPT], "[fields...]",
310 "Lists all available fields for networks"),
312 ShowNetworkConfig, ARGS_MANY_NETWORKS, [],
313 "[<network_name>...]", "Show information about the network(s)"),
315 SetNetworkParams, ARGS_ONE_NETWORK,
316 [DRY_RUN_OPT, SUBMIT_OPT, ADD_RESERVED_IPS_OPT, REMOVE_RESERVED_IPS_OPT,
317 GATEWAY_OPT, MAC_PREFIX_OPT, NETWORK_TYPE_OPT, NETWORK6_OPT, GATEWAY6_OPT],
318 "<network_name>", "Alters the parameters of a network"),
321 [ArgNetwork(min=1, max=1), ArgGroup(min=1, max=1),
322 ArgUnknown(min=1, max=1), ArgUnknown(min=1, max=1)],
323 [NOCONFLICTSCHECK_OPT],
324 "<network_name> <node_group> <mode> <link>",
325 "Map a given network to the specified node group"
326 " with given mode and link (netparams)"),
329 [ArgNetwork(min=1, max=1), ArgGroup(min=1, max=1)],
330 [NOCONFLICTSCHECK_OPT],
331 "<network_name> <node_group>",
332 "Unmap a given network from a specified node group"),
334 RemoveNetwork, ARGS_ONE_NETWORK, [FORCE_OPT, DRY_RUN_OPT],
335 "[--dry-run] <network_id>",
336 "Remove an (empty) network from the cluster"),
338 ListTags, ARGS_ONE_NETWORK, [],
339 "<network_name>", "List the tags of the given network"),
341 AddTags, [ArgNetwork(min=1, max=1), ArgUnknown()],
342 [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
343 "<network_name> tag...", "Add tags to the given network"),
345 RemoveTags, [ArgNetwork(min=1, max=1), ArgUnknown()],
346 [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
347 "<network_name> tag...", "Remove tags from given network"),
352 return GenericMain(commands, override={"tag_type": constants.TAG_NETWORK})