gnt_network.py 11.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#
#

# Copyright (C) 2011 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

"""IP pool related commands"""

23
# pylint: disable=W0401,W0614
24
25
26
27
28
29
30
31
32
33
34
# W0401: Wildcard import ganeti.cli
# W0614: Unused import %s from wildcard import (since we need cli)

from ganeti.cli import *
from ganeti import constants
from ganeti import opcodes
from ganeti import utils
from textwrap import wrap


#: 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
40
41
42
43
44
45
46


def _HandleReservedIPs(ips):
  if ips is not None:
    if ips == "":
      return []
    else:
      return utils.UnescapeAndSplit(ips, sep=",")
  return None

47

48
49
50
51
52
53
54
55
56
57
58
59
def AddNetwork(opts, args):
  """Add a network to the cluster.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: a list of length 1 with the network name to create
  @rtype: int
  @return: the desired exit code

  """
  (network_name, ) = args

60
61
62
63
64
  if opts.tags is not None:
    tags = opts.tags.split(",")
  else:
    tags = []

65
66
67
68
69
70
71
72
73
74
  op = opcodes.OpNetworkAdd(
                    network_name=network_name,
                    gateway=opts.gateway,
                    network=opts.network,
                    gateway6=opts.gateway6,
                    network6=opts.network6,
                    mac_prefix=opts.mac_prefix,
                    network_type=opts.network_type,
                    add_reserved_ips=_HandleReservedIPs(opts.add_reserved_ips),
                    tags=tags)
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  SubmitOpCode(op, opts=opts)


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

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

  """
  network = args[0]
  groups = args[1]
  mode = args[2]
  link = args[3]

  #TODO: allow comma separated group names
  if groups == 'all':
    cl = GetClient()
    (groups, ) = cl.QueryGroups([], ['name'], False)
  else:
    groups = [groups]

  for group in groups:
    op = opcodes.OpNetworkConnect(group_name=group,
                                  network_name=network,
                                  network_mode=mode,
                                  network_link=link,
                                  conflicts_check=opts.conflicts_check)
    SubmitOpCode(op, opts=opts)


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

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

  """
  network = args[0]
  groups = args[1]

  #TODO: allow comma separated group names
  if groups == 'all':
    cl = GetClient()
    (groups, ) = cl.QueryGroups([], ['name'], False)
  else:
    groups = [groups]

  for group in groups:
    op = opcodes.OpNetworkDisconnect(group_name=group,
                                     network_name=network,
                                     conflicts_check=opts.conflicts_check)
    SubmitOpCode(op, opts=opts)


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

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

  """
  desired_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
  fmtoverride = {
    "group_list": (",".join, False),
    "inst_list": (",".join, False),
150
    "tags": (",".join, False),
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  }

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


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

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

  """
  return GenericListFields(constants.QR_NETWORK, args, opts.separator,
                           not opts.no_headers)


172
def ShowNetworkConfig(_, args):
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  """Show network information.

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

  """
  cl = GetClient()
  result = cl.QueryNetworks(fields=["name", "network", "gateway",
                                    "network6", "gateway6",
                                    "mac_prefix", "network_type",
                                    "free_count", "reserved_count",
                                    "map", "group_list", "inst_list",
                                    "external_reservations"],
                            names=args, use_locking=False)

  for (name, network, gateway, network6, gateway6,
       mac_prefix, network_type, free_count, reserved_count,
195
       mapping, group_list, instances, ext_res) in result:
196
197
198
199
200
201
202
203
204
205
    size = free_count + reserved_count
    ToStdout("Network name: %s", name)
    ToStdout("  subnet: %s", network)
    ToStdout("  gateway: %s", gateway)
    ToStdout("  subnet6: %s", network6)
    ToStdout("  gateway6: %s", gateway6)
    ToStdout("  mac prefix: %s", mac_prefix)
    ToStdout("  type: %s", network_type)
    ToStdout("  size: %d", size)
    ToStdout("  free: %d (%.2f%%)", free_count,
206
             100 * float(free_count) / float(size))
207
208
    ToStdout("  usage map:")
    idx = 0
209
    for line in wrap(mapping, width=64):
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
      ToStdout("     %s %s %d", str(idx).rjust(3), line.ljust(64), idx + 63)
      idx += 64
    ToStdout("         (X) used    (.) free")

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

    if group_list:
      ToStdout("  connected to node groups:")
      for group in group_list:
        ToStdout("    %s", group)
    else:
      ToStdout("  not connected to any node group")

    if instances:
      ToStdout("  used by %d instances:", len(instances))
      for inst in instances:
        ((ips, networks), ) = cl.QueryInstances([inst],
                                                ["nic.ips", "nic.networks"],
                                                use_locking=False)

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

237
        ToStdout("    %s : %s", inst, l(zip(ips, networks)))
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
    else:
      ToStdout("  not used by any instances")


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

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

  @rtype: int
  @return: the desired exit code

  """

  # TODO: add "network": opts.network,
  all_changes = {
    "gateway": opts.gateway,
    "add_reserved_ips": _HandleReservedIPs(opts.add_reserved_ips),
    "remove_reserved_ips": _HandleReservedIPs(opts.remove_reserved_ips),
    "mac_prefix": opts.mac_prefix,
    "network_type": opts.network_type,
    "gateway6": opts.gateway6,
    "network6": opts.network6,
  }

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

269
270
  # pylint: disable=W0142
  op = opcodes.OpNetworkSetParams(network_name=args[0], **all_changes)
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293

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


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

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

  """
  (network_name,) = args
  op = opcodes.OpNetworkRemove(network_name=network_name, force=opts.force)
  SubmitOpCode(op, opts=opts)


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


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