Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_network.py @ 870c9855

History | View | Annotate | Download (11.2 kB)

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", "tags"]
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
  if opts.tags is not None:
60
    tags = opts.tags.split(",")
61
  else:
62
    tags = []
63

    
64
  op = opcodes.OpNetworkAdd(network_name=network_name,
65
                            gateway=opts.gateway,
66
                            network=opts.network,
67
                            gateway6=opts.gateway6,
68
                            network6=opts.network6,
69
                            mac_prefix=opts.mac_prefix,
70
                            network_type=opts.network_type,
71
                            add_reserved_ips=_HandleReservedIPs(opts.add_reserved_ips),
72
                            tags=tags)
73
  SubmitOpCode(op, opts=opts)
74

    
75

    
76
def MapNetwork(opts, args):
77
  """Map a network to a node group.
78

79
  @param opts: the command line options selected by the user
80
  @type args: list
81
  @param args: a list of length 3 with network, nodegroup, mode, physlink
82
  @rtype: int
83
  @return: the desired exit code
84

85
  """
86
  network = args[0]
87
  groups = args[1]
88
  mode = args[2]
89
  link = args[3]
90

    
91
  #TODO: allow comma separated group names
92
  if groups == 'all':
93
    cl = GetClient()
94
    (groups, ) = cl.QueryGroups([], ['name'], False)
95
  else:
96
    groups = [groups]
97

    
98
  for group in groups:
99
    op = opcodes.OpNetworkConnect(group_name=group,
100
                                  network_name=network,
101
                                  network_mode=mode,
102
                                  network_link=link,
103
                                  conflicts_check=opts.conflicts_check)
104
    SubmitOpCode(op, opts=opts)
105

    
106

    
107
def UnmapNetwork(opts, args):
108
  """Unmap a network from a node group.
109

110
  @param opts: the command line options selected by the user
111
  @type args: list
112
  @param args: a list of length 3 with network, nodegorup
113
  @rtype: int
114
  @return: the desired exit code
115

116
  """
117
  network = args[0]
118
  groups = args[1]
119

    
120
  #TODO: allow comma separated group names
121
  if groups == 'all':
122
    cl = GetClient()
123
    (groups, ) = cl.QueryGroups([], ['name'], False)
124
  else:
125
    groups = [groups]
126

    
127
  for group in groups:
128
    op = opcodes.OpNetworkDisconnect(group_name=group,
129
                                     network_name=network,
130
                                     conflicts_check=opts.conflicts_check)
131
    SubmitOpCode(op, opts=opts)
132

    
133

    
134
def ListNetworks(opts, args):
135
  """List Ip pools and their properties.
136

137
  @param opts: the command line options selected by the user
138
  @type args: list
139
  @param args: networks to list, or empty for all
140
  @rtype: int
141
  @return: the desired exit code
142

143
  """
144
  desired_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
145
  fmtoverride = {
146
    "group_list": (",".join, False),
147
    "inst_list": (",".join, False),
148
    "tags": (",".join, False),
149
  }
150

    
151
  return GenericList(constants.QR_NETWORK, desired_fields, args, None,
152
                     opts.separator, not opts.no_headers,
153
                     verbose=opts.verbose, format_override=fmtoverride)
154

    
155

    
156
def ListNetworkFields(opts, args):
157
  """List network fields.
158

159
  @param opts: the command line options selected by the user
160
  @type args: list
161
  @param args: fields to list, or empty for all
162
  @rtype: int
163
  @return: the desired exit code
164

165
  """
166
  return GenericListFields(constants.QR_NETWORK, args, opts.separator,
167
                           not opts.no_headers)
168

    
169

    
170
def ShowNetworkConfig(opts, args):
171
  """Show network information.
172

173
  @param opts: the command line options selected by the user
174
  @type args: list
175
  @param args: should either be an empty list, in which case
176
      we show information about all nodes, or should contain
177
      a list of networks (names or UUIDs) to be queried for information
178
  @rtype: int
179
  @return: the desired exit code
180

181
  """
182
  cl = GetClient()
183
  result = cl.QueryNetworks(fields=["name", "network", "gateway",
184
                                    "network6", "gateway6",
185
                                    "mac_prefix", "network_type",
186
                                    "free_count", "reserved_count",
187
                                    "map", "group_list", "inst_list",
188
                                    "external_reservations"],
189
                            names=args, use_locking=False)
190

    
191
  for (name, network, gateway, network6, gateway6,
192
       mac_prefix, network_type, free_count, reserved_count,
193
       map, group_list, instances, ext_res) in result:
194
    size = free_count + reserved_count
195
    ToStdout("Network name: %s", name)
196
    ToStdout("  subnet: %s", network)
197
    ToStdout("  gateway: %s", gateway)
198
    ToStdout("  subnet6: %s", network6)
199
    ToStdout("  gateway6: %s", gateway6)
200
    ToStdout("  mac prefix: %s", mac_prefix)
201
    ToStdout("  type: %s", network_type)
202
    ToStdout("  size: %d", size)
203
    ToStdout("  free: %d (%.2f%%)", free_count,
204
             100 * float(free_count)/float(size))
205
    ToStdout("  usage map:")
206
    idx = 0
207
    for line in wrap(map, width=64):
208
      ToStdout("     %s %s %d", str(idx).rjust(3), line.ljust(64), idx + 63)
209
      idx += 64
210
    ToStdout("         (X) used    (.) free")
211

    
212
    if ext_res:
213
      ToStdout("  externally reserved IPs:")
214
      for line in wrap(ext_res, width=64):
215
        ToStdout("    %s" % line)
216

    
217
    if group_list:
218
      ToStdout("  connected to node groups:")
219
      for group in group_list:
220
        ToStdout("    %s", group)
221
    else:
222
      ToStdout("  not connected to any node group")
223

    
224
    if instances:
225
      ToStdout("  used by %d instances:", len(instances))
226
      for inst in instances:
227
        ((ips, networks), ) = cl.QueryInstances([inst],
228
                                                ["nic.ips", "nic.networks"],
229
                                                use_locking=False)
230

    
231
        l = lambda value: ", ".join(`idx`+":"+str(ip)
232
                                    for idx, (ip, net) in enumerate(value)
233
                                      if net == name)
234

    
235
        ToStdout("    %s : %s", inst, l(zip(ips,networks)))
236
    else:
237
      ToStdout("  not used by any instances")
238

    
239

    
240
def SetNetworkParams(opts, args):
241
  """Modifies an IP address pool's parameters.
242

243
  @param opts: the command line options selected by the user
244
  @type args: list
245
  @param args: should contain only one element, the node group name
246

247
  @rtype: int
248
  @return: the desired exit code
249

250
  """
251

    
252
  # TODO: add "network": opts.network,
253
  all_changes = {
254
    "gateway": opts.gateway,
255
    "add_reserved_ips": _HandleReservedIPs(opts.add_reserved_ips),
256
    "remove_reserved_ips": _HandleReservedIPs(opts.remove_reserved_ips),
257
    "mac_prefix": opts.mac_prefix,
258
    "network_type": opts.network_type,
259
    "gateway6": opts.gateway6,
260
    "network6": opts.network6,
261
  }
262

    
263
  if all_changes.values().count(None) == len(all_changes):
264
    ToStderr("Please give at least one of the parameters.")
265
    return 1
266

    
267
  op = opcodes.OpNetworkSetParams(network_name=args[0],
268
                                  # pylint: disable-msg=W0142
269
                                  **all_changes)
270

    
271
  # TODO: add feedback to user, e.g. list the modifications
272
  SubmitOrSend(op, opts)
273

    
274

    
275
def RemoveNetwork(opts, args):
276
  """Remove an IP address pool from the cluster.
277

278
  @param opts: the command line options selected by the user
279
  @type args: list
280
  @param args: a list of length 1 with the id of the IP address pool to remove
281
  @rtype: int
282
  @return: the desired exit code
283

284
  """
285
  (network_name,) = args
286
  op = opcodes.OpNetworkRemove(network_name=network_name, force=opts.force)
287
  SubmitOpCode(op, opts=opts)
288

    
289

    
290
commands = {
291
  "add": (
292
    AddNetwork, ARGS_ONE_NETWORK,
293
    [DRY_RUN_OPT, NETWORK_OPT, GATEWAY_OPT, ADD_RESERVED_IPS_OPT,
294
     MAC_PREFIX_OPT, NETWORK_TYPE_OPT, NETWORK6_OPT, GATEWAY6_OPT,
295
     TAG_ADD_OPT, NOCONFLICTSCHECK_OPT],
296
    "<network_name>", "Add a new IP network to the cluster"),
297
  "list": (
298
    ListNetworks, ARGS_MANY_NETWORKS,
299
    [NOHDR_OPT, SEP_OPT, FIELDS_OPT, VERBOSE_OPT],
300
    "[<network_id>...]",
301
    "Lists the IP networks in the cluster. The available fields can be shown"
302
    " using the \"list-fields\" command (see the man page for details)."
303
    " The default list is (in order): %s." % utils.CommaJoin(_LIST_DEF_FIELDS)),
304
  "list-fields": (
305
    ListNetworkFields, [ArgUnknown()], [NOHDR_OPT, SEP_OPT], "[fields...]",
306
    "Lists all available fields for networks"),
307
  "info": (
308
    ShowNetworkConfig, ARGS_MANY_NETWORKS, [],
309
    "[<network_name>...]", "Show information about the network(s)"),
310
  "modify": (
311
    SetNetworkParams, ARGS_ONE_NETWORK,
312
    [DRY_RUN_OPT, SUBMIT_OPT, ADD_RESERVED_IPS_OPT, REMOVE_RESERVED_IPS_OPT,
313
     GATEWAY_OPT, MAC_PREFIX_OPT, NETWORK_TYPE_OPT, NETWORK6_OPT, GATEWAY6_OPT],
314
    "<network_name>", "Alters the parameters of a network"),
315
  "connect": (
316
    MapNetwork,
317
    [ArgNetwork(min=1, max=1), ArgGroup(min=1, max=1),
318
     ArgUnknown(min=1, max=1), ArgUnknown(min=1, max=1)],
319
    [NOCONFLICTSCHECK_OPT],
320
    "<network_name> <node_group> <mode> <link>",
321
    "Map a given network to the specified node group"
322
    " with given mode and link (netparams)"),
323
  "disconnect": (
324
    UnmapNetwork,
325
    [ArgNetwork(min=1, max=1), ArgGroup(min=1, max=1)],
326
    [NOCONFLICTSCHECK_OPT],
327
    "<network_name> <node_group>",
328
    "Unmap a given network from a specified node group"),
329
  "remove": (
330
    RemoveNetwork, ARGS_ONE_NETWORK, [FORCE_OPT, DRY_RUN_OPT],
331
    "[--dry-run] <network_id>",
332
    "Remove an (empty) network from the cluster"),
333
  "list-tags": (
334
    ListTags, ARGS_ONE_NETWORK, [],
335
    "<network_name>", "List the tags of the given network"),
336
  "add-tags": (
337
    AddTags, [ArgNetwork(min=1, max=1), ArgUnknown()],
338
    [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
339
    "<network_name> tag...", "Add tags to the given network"),
340
  "remove-tags": (
341
    RemoveTags, [ArgNetwork(min=1, max=1), ArgUnknown()],
342
    [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
343
    "<network_name> tag...", "Remove tags from given network"),
344
}
345

    
346

    
347
def Main():
348
  return GenericMain(commands, override={"tag_type": constants.TAG_NETWORK})