161059b4b180f931a424352fab6b8adf5a6d6369
[ganeti-github.git] / lib / client / gnt_network.py
1 #
2 #
3
4 # Copyright (C) 2011 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 """IP pool related commands"""
22
23 # pylint: disable-msg=W0401,W0614
24 # W0401: Wildcard import ganeti.cli
25 # W0614: Unused import %s from wildcard import (since we need cli)
26
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
32
33
34 #: default list of fields for L{ListNetworks}
35 _LIST_DEF_FIELDS = ["name", "network", "gateway",
36 "network_type", "mac_prefix", "group_list"]
37
38
39 def _HandleReservedIPs(ips):
40 if ips is not None:
41 if ips == "":
42 return []
43 else:
44 return utils.UnescapeAndSplit(ips, sep=",")
45 return None
46
47 def AddNetwork(opts, args):
48 """Add a network to the cluster.
49
50 @param opts: the command line options selected by the user
51 @type args: list
52 @param args: a list of length 1 with the network name to create
53 @rtype: int
54 @return: the desired exit code
55
56 """
57 (network_name, ) = args
58
59 op = opcodes.OpNetworkAdd(network_name=network_name,
60 gateway=opts.gateway,
61 network=opts.network,
62 gateway6=opts.gateway6,
63 network6=opts.network6,
64 mac_prefix=opts.mac_prefix,
65 network_type=opts.network_type,
66 add_reserved_ips=_HandleReservedIPs(opts.add_reserved_ips))
67 SubmitOpCode(op, opts=opts)
68
69
70 def MapNetwork(opts, args):
71 """Map a network to a node group.
72
73 @param opts: the command line options selected by the user
74 @type args: list
75 @param args: a list of length 3 with network, nodegroup, mode, physlink
76 @rtype: int
77 @return: the desired exit code
78
79 """
80 network = args[0]
81 groups = args[1]
82 mode = args[2]
83 link = args[3]
84
85 #TODO: allow comma separated group names
86 if groups == 'all':
87 cl = GetClient()
88 (groups, ) = cl.QueryGroups([], ['name'], False)
89 else:
90 groups = [groups]
91
92 for group in groups:
93 op = opcodes.OpNetworkConnect(group_name=group,
94 network_name=network,
95 network_mode=mode,
96 network_link=link,
97 conflicts_check=opts.conflicts_check)
98 SubmitOpCode(op, opts=opts)
99
100
101 def UnmapNetwork(opts, args):
102 """Unmap a network from a node group.
103
104 @param opts: the command line options selected by the user
105 @type args: list
106 @param args: a list of length 3 with network, nodegorup
107 @rtype: int
108 @return: the desired exit code
109
110 """
111 network = args[0]
112 groups = args[1]
113
114 #TODO: allow comma separated group names
115 if groups == 'all':
116 cl = GetClient()
117 (groups, ) = cl.QueryGroups([], ['name'], False)
118 else:
119 groups = [groups]
120
121 for group in groups:
122 op = opcodes.OpNetworkDisconnect(group_name=group,
123 network_name=network,
124 conflicts_check=opts.conflicts_check)
125 SubmitOpCode(op, opts=opts)
126
127
128 def ListNetworks(opts, args):
129 """List Ip pools and their properties.
130
131 @param opts: the command line options selected by the user
132 @type args: list
133 @param args: networks to list, or empty for all
134 @rtype: int
135 @return: the desired exit code
136
137 """
138 desired_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
139 fmtoverride = {
140 "group_list": (",".join, False),
141 "inst_list": (",".join, False),
142 }
143
144 return GenericList(constants.QR_NETWORK, desired_fields, args, None,
145 opts.separator, not opts.no_headers,
146 verbose=opts.verbose, format_override=fmtoverride)
147
148
149 def ListNetworkFields(opts, args):
150 """List network fields.
151
152 @param opts: the command line options selected by the user
153 @type args: list
154 @param args: fields to list, or empty for all
155 @rtype: int
156 @return: the desired exit code
157
158 """
159 return GenericListFields(constants.QR_NETWORK, args, opts.separator,
160 not opts.no_headers)
161
162
163 def ShowNetworkConfig(opts, args):
164 """Show network information.
165
166 @param opts: the command line options selected by the user
167 @type args: list
168 @param args: should either be an empty list, in which case
169 we show information about all nodes, or should contain
170 a list of networks (names or UUIDs) to be queried for information
171 @rtype: int
172 @return: the desired exit code
173
174 """
175 cl = GetClient()
176 result = cl.QueryNetworks(fields=["name", "network", "gateway",
177 "network6", "gateway6",
178 "mac_prefix", "network_type",
179 "free_count", "reserved_count",
180 "map", "group_list", "inst_list",
181 "external_reservations"],
182 names=args, use_locking=False)
183
184 for (name, network, gateway, network6, gateway6,
185 mac_prefix, network_type, free_count, reserved_count,
186 map, group_list, instances, ext_res) in result:
187 size = free_count + reserved_count
188 ToStdout("Network name: %s", name)
189 ToStdout(" subnet: %s", network)
190 ToStdout(" gateway: %s", gateway)
191 ToStdout(" subnet6: %s", network6)
192 ToStdout(" gateway6: %s", gateway6)
193 ToStdout(" mac prefix: %s", mac_prefix)
194 ToStdout(" type: %s", network_type)
195 ToStdout(" size: %d", size)
196 ToStdout(" free: %d (%.2f%%)", free_count,
197 100 * float(free_count)/float(size))
198 ToStdout(" usage map:")
199 idx = 0
200 for line in wrap(map, width=64):
201 ToStdout(" %s %s %d", str(idx).rjust(3), line.ljust(64), idx + 63)
202 idx += 64
203 ToStdout(" (X) used (.) free")
204
205 if ext_res:
206 ToStdout(" externally reserved IPs:")
207 for line in wrap(ext_res, width=64):
208 ToStdout(" %s" % line)
209
210 if group_list:
211 ToStdout(" connected to node groups:")
212 for group in group_list:
213 ToStdout(" %s", group)
214 else:
215 ToStdout(" not connected to any node group")
216
217 if instances:
218 ToStdout(" used by %d instances:", len(instances))
219 for inst in instances:
220 ((ips, networks), ) = cl.QueryInstances([inst],
221 ["nic.ips", "nic.networks"],
222 use_locking=False)
223
224 l = lambda value: ", ".join(`idx`+":"+str(ip)
225 for idx, (ip, net) in enumerate(value)
226 if net == name)
227
228 ToStdout(" %s : %s", inst, l(zip(ips,networks)))
229 else:
230 ToStdout(" not used by any instances")
231
232
233 def SetNetworkParams(opts, args):
234 """Modifies an IP address pool's parameters.
235
236 @param opts: the command line options selected by the user
237 @type args: list
238 @param args: should contain only one element, the node group name
239
240 @rtype: int
241 @return: the desired exit code
242
243 """
244
245 # TODO: add "network": opts.network,
246 all_changes = {
247 "gateway": opts.gateway,
248 "add_reserved_ips": _HandleReservedIPs(opts.add_reserved_ips),
249 "remove_reserved_ips": _HandleReservedIPs(opts.remove_reserved_ips),
250 "mac_prefix": opts.mac_prefix,
251 "network_type": opts.network_type,
252 "gateway6": opts.gateway6,
253 "network6": opts.network6,
254 }
255
256 if all_changes.values().count(None) == len(all_changes):
257 ToStderr("Please give at least one of the parameters.")
258 return 1
259
260 op = opcodes.OpNetworkSetParams(network_name=args[0],
261 # pylint: disable-msg=W0142
262 **all_changes)
263
264 # TODO: add feedback to user, e.g. list the modifications
265 SubmitOrSend(op, opts)
266
267
268 def RemoveNetwork(opts, args):
269 """Remove an IP address pool from the cluster.
270
271 @param opts: the command line options selected by the user
272 @type args: list
273 @param args: a list of length 1 with the id of the IP address pool to remove
274 @rtype: int
275 @return: the desired exit code
276
277 """
278 (network_name,) = args
279 op = opcodes.OpNetworkRemove(network_name=network_name, force=opts.force)
280 SubmitOpCode(op, opts=opts)
281
282
283 commands = {
284 "add": (
285 AddNetwork, ARGS_ONE_NETWORK,
286 [DRY_RUN_OPT, NETWORK_OPT, GATEWAY_OPT, ADD_RESERVED_IPS_OPT,
287 MAC_PREFIX_OPT, NETWORK_TYPE_OPT, NETWORK6_OPT, GATEWAY6_OPT],
288 "<network_name>", "Add a new IP network to the cluster"),
289 "list": (
290 ListNetworks, ARGS_MANY_NETWORKS,
291 [NOHDR_OPT, SEP_OPT, FIELDS_OPT, VERBOSE_OPT],
292 "[<network_id>...]",
293 "Lists the IP networks in the cluster. The available fields can be shown"
294 " using the \"list-fields\" command (see the man page for details)."
295 " The default list is (in order): %s." % utils.CommaJoin(_LIST_DEF_FIELDS)),
296 "list-fields": (
297 ListNetworkFields, [ArgUnknown()], [NOHDR_OPT, SEP_OPT], "[fields...]",
298 "Lists all available fields for networks"),
299 "info": (
300 ShowNetworkConfig, ARGS_MANY_NETWORKS, [],
301 "[<network_name>...]", "Show information about the network(s)"),
302 "modify": (
303 SetNetworkParams, ARGS_ONE_NETWORK,
304 [DRY_RUN_OPT, SUBMIT_OPT, ADD_RESERVED_IPS_OPT, REMOVE_RESERVED_IPS_OPT,
305 GATEWAY_OPT, MAC_PREFIX_OPT, NETWORK_TYPE_OPT, NETWORK6_OPT, GATEWAY6_OPT],
306 "<network_name>", "Alters the parameters of a network"),
307 "connect": (
308 MapNetwork,
309 [ArgNetwork(min=1, max=1), ArgGroup(min=1, max=1),
310 ArgUnknown(min=1, max=1), ArgUnknown(min=1, max=1)],
311 [NOCONFLICTSCHECK_OPT],
312 "<network_name> <node_group> <mode> <link>",
313 "Map a given network to the specified node group"
314 " with given mode and link (netparams)"),
315 "disconnect": (
316 UnmapNetwork,
317 [ArgNetwork(min=1, max=1), ArgGroup(min=1, max=1)],
318 [NOCONFLICTSCHECK_OPT],
319 "<network_name> <node_group>",
320 "Unmap a given network from a specified node group"),
321 "remove": (
322 RemoveNetwork, ARGS_ONE_NETWORK, [FORCE_OPT, DRY_RUN_OPT],
323 "[--dry-run] <network_id>",
324 "Remove an (empty) network from the cluster"),
325 }
326
327
328 def Main():
329 return GenericMain(commands)