Revision 8140e24f

b/lib/cli.py
435 435
    retval = kind, None
436 436
  elif kind in (constants.TAG_NODEGROUP,
437 437
                constants.TAG_NODE,
438
                constants.TAG_NETWORK,
438 439
                constants.TAG_INSTANCE):
439 440
    if not args:
440 441
      raise errors.OpPrereqError("no arguments passed to the command",
b/lib/client/gnt_network.py
33 33

  
34 34
#: default list of fields for L{ListNetworks}
35 35
_LIST_DEF_FIELDS = ["name", "network", "gateway",
36
                    "network_type", "mac_prefix", "group_list"]
36
                    "network_type", "mac_prefix", "group_list", "tags"]
37 37

  
38 38

  
39 39
def _HandleReservedIPs(ips):
......
56 56
  """
57 57
  (network_name, ) = args
58 58

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

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

  
69 75

  
......
139 145
  fmtoverride = {
140 146
    "group_list": (",".join, False),
141 147
    "inst_list": (",".join, False),
148
    "tags": (",".join, False),
142 149
  }
143 150

  
144 151
  return GenericList(constants.QR_NETWORK, desired_fields, args, None,
......
283 290
commands = {
284 291
  "add": (
285 292
    AddNetwork, ARGS_ONE_NETWORK,
286
    [DRY_RUN_OPT, NETWORK_OPT, GATEWAY_OPT, ADD_RESERVED_IPS_OPT,
293
    [DRY_RUN_OPT, NETWORK_OPT, GATEWAY_OPT, ADD_RESERVED_IPS_OPT, TAG_ADD_OPT,
287 294
     MAC_PREFIX_OPT, NETWORK_TYPE_OPT, NETWORK6_OPT, GATEWAY6_OPT],
288 295
    "<network_name>", "Add a new IP network to the cluster"),
289 296
  "list": (
......
322 329
    RemoveNetwork, ARGS_ONE_NETWORK, [FORCE_OPT, DRY_RUN_OPT],
323 330
    "[--dry-run] <network_id>",
324 331
    "Remove an (empty) network from the cluster"),
332
  "list-tags": (
333
    ListTags, ARGS_ONE_NETWORK, [],
334
    "<network_name>", "List the tags of the given network"),
335
  "add-tags": (
336
    AddTags, [ArgNetwork(min=1, max=1), ArgUnknown()],
337
    [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
338
    "<network_name> tag...", "Add tags to the given network"),
339
  "remove-tags": (
340
    RemoveTags, [ArgNetwork(min=1, max=1), ArgUnknown()],
341
    [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
342
    "<network_name> tag...", "Remove tags from given network"),
325 343
}
326 344

  
327 345

  
328 346
def Main():
329
  return GenericMain(commands)
347
  return GenericMain(commands, override={"tag_type": constants.TAG_NETWORK})
b/lib/cmdlib.py
1316 1316
  return _ExpandItemName(cfg.ExpandInstanceName, name, "Instance")
1317 1317

  
1318 1318
def _BuildNetworkHookEnv(name, network, gateway, network6, gateway6,
1319
                         network_type, mac_prefix):
1319
                         network_type, mac_prefix, tags):
1320 1320
  env = dict()
1321 1321
  if name:
1322 1322
    env["NETWORK_NAME"] = name
......
1332 1332
    env["NETWORK_MAC_PREFIX"] = mac_prefix
1333 1333
  if network_type:
1334 1334
    env["NETWORK_TYPE"] = network_type
1335
  if tags:
1336
    env["NETWORK_TAGS"] = " ".join(tags)
1335 1337

  
1336 1338
  return env
1337 1339

  
......
1345 1347
    "gateway6": network.gateway6,
1346 1348
    "network_type": network.network_type,
1347 1349
    "mac_prefix": network.mac_prefix,
1350
    "tags" : network.tags,
1348 1351
  }
1349 1352
  return _BuildNetworkHookEnv(**args)
1350 1353

  
......
1431 1434
            env["INSTANCE_NIC%d_NETWORK_MAC_PREFIX" % idx] = nobj.mac_prefix
1432 1435
          if nobj.network_type:
1433 1436
            env["INSTANCE_NIC%d_NETWORK_TYPE" % idx] = nobj.network_type
1437
          if nobj.tags:
1438
            env["INSTANCE_NIC%d_NETWORK_TAGS" % idx] = " ".join(nobj.tags)
1434 1439
      if mode == constants.NIC_MODE_BRIDGED:
1435 1440
        env["INSTANCE_NIC%d_BRIDGE" % idx] = link
1436 1441
  else:
......
15017 15022
      self.group_uuid = self.cfg.LookupNodeGroup(self.op.name)
15018 15023
      lock_level = locking.LEVEL_NODEGROUP
15019 15024
      lock_name = self.group_uuid
15025
    elif self.op.kind == constants.TAG_NETWORK:
15026
      self.network_uuid = self.cfg.LookupNetwork(self.op.name)
15027
      lock_level = locking.LEVEL_NETWORK
15028
      lock_name = self.network_uuid
15020 15029
    else:
15021 15030
      lock_level = None
15022 15031
      lock_name = None
......
15039 15048
      self.target = self.cfg.GetInstanceInfo(self.op.name)
15040 15049
    elif self.op.kind == constants.TAG_NODEGROUP:
15041 15050
      self.target = self.cfg.GetNodeGroup(self.group_uuid)
15051
    elif self.op.kind == constants.TAG_NETWORK:
15052
      self.target = self.cfg.GetNetwork(self.network_uuid)
15042 15053
    else:
15043 15054
      raise errors.OpPrereqError("Wrong tag type requested (%s)" %
15044 15055
                                 str(self.op.kind), errors.ECODE_INVAL)
......
15549 15560
    if self.op.mac_prefix:
15550 15561
      utils.NormalizeAndValidateMac(self.op.mac_prefix+":00:00:00")
15551 15562

  
15563
    # Check tag validity
15564
    for tag in self.op.tags:
15565
      objects.TaggableObject.ValidateTag(tag)
15566

  
15567

  
15552 15568
  def BuildHooksEnv(self):
15553 15569
    """Build hooks env.
15554 15570

  
......
15561 15577
      "gateway6": self.op.gateway6,
15562 15578
      "mac_prefix": self.op.mac_prefix,
15563 15579
      "network_type": self.op.network_type,
15580
      "tags": self.op.tags,
15564 15581
      }
15565 15582
    return _BuildNetworkHookEnv(**args)
15566 15583

  
......
15609 15626
        except errors.AddressPoolError, e:
15610 15627
          raise errors.OpExecError("Cannot reserve IP %s. %s " % (ip, e))
15611 15628

  
15629
    if self.op.tags:
15630
      for tag in self.op.tags:
15631
        nobj.AddTag(tag)
15632

  
15612 15633
    self.cfg.AddNetwork(nobj, self.proc.GetECId(), check_uuid=False)
15613 15634
    del self.remove_locks[locking.LEVEL_NETWORK]
15614 15635

  
......
15714 15735
    self.mac_prefix = self.network.mac_prefix
15715 15736
    self.network6 = self.network.network6
15716 15737
    self.gateway6 = self.network.gateway6
15738
    self.tags = self.network.tags
15717 15739

  
15718 15740
    self.pool = network.AddressPool(self.network)
15719 15741

  
......
15765 15787
      "gateway6": self.gateway6,
15766 15788
      "mac_prefix": self.mac_prefix,
15767 15789
      "network_type": self.network_type,
15790
      "tags": self.tags,
15768 15791
      }
15769 15792
    return _BuildNetworkHookEnv(**args)
15770 15793

  
b/lib/constants.py
538 538
TAG_NODEGROUP = "nodegroup"
539 539
TAG_NODE = "node"
540 540
TAG_INSTANCE = "instance"
541
TAG_NETWORK = "network"
541 542
VALID_TAG_TYPES = frozenset([
542 543
  TAG_CLUSTER,
543 544
  TAG_NODEGROUP,
544 545
  TAG_NODE,
545 546
  TAG_INSTANCE,
547
  TAG_NETWORK,
546 548
  ])
547 549
MAX_TAG_LEN = 128
548 550
MAX_TAGS_PER_OBJ = 4096
b/lib/objects.py
1997 1997
    return True
1998 1998

  
1999 1999

  
2000
class Network(ConfigObject):
2000
class Network(TaggableObject):
2001 2001
  """Object representing a network definition for ganeti.
2002 2002

  
2003 2003
  """
b/lib/opcodes.py
2018 2018
    ("mac_prefix", None, ht.TMaybeString, None),
2019 2019
    ("add_reserved_ips", None,
2020 2020
     ht.TOr(ht.TNone, ht.TListOf(_CheckCIDRAddrNotation)), None),
2021
    ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Network tags"),
2021 2022
    ]
2022 2023

  
2023 2024
class OpNetworkRemove(OpCode):
b/lib/query.py
2532 2532
  """Builds list of fields for network queries.
2533 2533

  
2534 2534
  """
2535
  # Add simple fields
2536 2535
  fields = [
2536
    (_MakeField("tags", "Tags", QFT_OTHER, "Tags"), IQ_CONFIG, 0,
2537
     lambda ctx, inst: list(inst.GetTags())),
2538
    ]
2539

  
2540
  # Add simple fields
2541
  fields.extend([
2537 2542
    (_MakeField(name, title, kind, doc),
2538 2543
     NETQ_CONFIG, 0, _GetItemAttr(name))
2539
    for (name, (title, kind, flags, doc)) in _NETWORK_SIMPLE_FIELDS.items()]
2544
     for (name, (title, kind, flags, doc)) in _NETWORK_SIMPLE_FIELDS.items()
2545
    ])
2540 2546

  
2541 2547
  def _GetLength(getter):
2542 2548
    return lambda ctx, network: len(getter(ctx)[network.uuid])
b/lib/rapi/client.py
1725 1725

  
1726 1726
  def CreateNetwork(self, network_name, network, gateway=None, network6=None,
1727 1727
                    gateway6=None, mac_prefix=None, network_type=None,
1728
                    add_reserved_ips=None, dry_run=False):
1728
                    add_reserved_ips=None, tags=None, dry_run=False):
1729 1729
    """Creates a new network.
1730 1730

  
1731 1731
    @type name: str
......
1740 1740
    query = []
1741 1741
    _AppendDryRunIf(query, dry_run)
1742 1742

  
1743
    if add_reserved_ips:
1744
      add_reserved_ips = add_reserved_ips.split(',')
1745

  
1746
    if tags:
1747
      tags = tags.split(',')
1748

  
1743 1749
    body = {
1744 1750
      "network_name": network_name,
1745 1751
      "gateway": gateway,
......
1748 1754
      "network6": network6,
1749 1755
      "mac_prefix": mac_prefix,
1750 1756
      "network_type": network_type,
1751
      "add_reserved_ips": add_reserved_ips
1757
      "add_reserved_ips": add_reserved_ips,
1758
      "tags": tags,
1752 1759
      }
1753 1760

  
1754 1761
    return self._SendRequest(HTTP_POST, "/%s/networks" % GANETI_RAPI_VERSION,
b/lib/rapi/rlib2.py
97 97
              "mac_prefix", "network_type",
98 98
              "free_count", "reserved_count",
99 99
              "map", "group_list", "inst_list",
100
              "external_reservations",
100
              "external_reservations", "tags",
101 101
             ] 
102 102

  
103 103
G_FIELDS = [

Also available in: Unified diff