Package ganeti :: Package cmdlib :: Module network
[hide private]
[frames] | no frames]

Source Code for Module ganeti.cmdlib.network

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc. 
  5  # All rights reserved. 
  6  # 
  7  # Redistribution and use in source and binary forms, with or without 
  8  # modification, are permitted provided that the following conditions are 
  9  # met: 
 10  # 
 11  # 1. Redistributions of source code must retain the above copyright notice, 
 12  # this list of conditions and the following disclaimer. 
 13  # 
 14  # 2. Redistributions in binary form must reproduce the above copyright 
 15  # notice, this list of conditions and the following disclaimer in the 
 16  # documentation and/or other materials provided with the distribution. 
 17  # 
 18  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
 19  # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
 20  # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 21  # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 22  # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 23  # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 24  # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 25  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 26  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 27  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 28  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 29   
 30   
 31  """Logical units dealing with networks.""" 
 32   
 33  from ganeti import constants 
 34  from ganeti import errors 
 35  from ganeti import locking 
 36  from ganeti import network 
 37  from ganeti import objects 
 38  from ganeti import utils 
 39  from ganeti.cmdlib.base import LogicalUnit 
 40  from ganeti.cmdlib.common import CheckNodeGroupInstances 
 41   
 42   
43 -def _BuildNetworkHookEnv(name, subnet, gateway, network6, gateway6, 44 mac_prefix, tags):
45 """Builds network related env variables for hooks 46 47 This builds the hook environment from individual variables. 48 49 @type name: string 50 @param name: the name of the network 51 @type subnet: string 52 @param subnet: the ipv4 subnet 53 @type gateway: string 54 @param gateway: the ipv4 gateway 55 @type network6: string 56 @param network6: the ipv6 subnet 57 @type gateway6: string 58 @param gateway6: the ipv6 gateway 59 @type mac_prefix: string 60 @param mac_prefix: the mac_prefix 61 @type tags: list 62 @param tags: the tags of the network 63 64 """ 65 env = {} 66 if name: 67 env["NETWORK_NAME"] = name 68 if subnet: 69 env["NETWORK_SUBNET"] = subnet 70 if gateway: 71 env["NETWORK_GATEWAY"] = gateway 72 if network6: 73 env["NETWORK_SUBNET6"] = network6 74 if gateway6: 75 env["NETWORK_GATEWAY6"] = gateway6 76 if mac_prefix: 77 env["NETWORK_MAC_PREFIX"] = mac_prefix 78 if tags: 79 env["NETWORK_TAGS"] = " ".join(tags) 80 81 return env
82 83
84 -class LUNetworkAdd(LogicalUnit):
85 """Logical unit for creating networks. 86 87 """ 88 HPATH = "network-add" 89 HTYPE = constants.HTYPE_NETWORK 90 REQ_BGL = False 91
92 - def BuildHooksNodes(self):
93 """Build hooks nodes. 94 95 """ 96 mn = self.cfg.GetMasterNode() 97 return ([mn], [mn])
98
99 - def CheckArguments(self):
100 if self.op.mac_prefix: 101 self.op.mac_prefix = \ 102 utils.NormalizeAndValidateThreeOctetMacPrefix(self.op.mac_prefix)
103
104 - def ExpandNames(self):
105 self.network_uuid = self.cfg.GenerateUniqueID(self.proc.GetECId()) 106 107 if self.op.conflicts_check: 108 self.share_locks[locking.LEVEL_NODE] = 1 109 self.share_locks[locking.LEVEL_NODE_ALLOC] = 1 110 self.needed_locks = { 111 locking.LEVEL_NODE: locking.ALL_SET, 112 locking.LEVEL_NODE_ALLOC: locking.ALL_SET, 113 } 114 else: 115 self.needed_locks = {} 116 117 self.add_locks[locking.LEVEL_NETWORK] = self.network_uuid
118
119 - def CheckPrereq(self):
120 if self.op.network is None: 121 raise errors.OpPrereqError("Network must be given", 122 errors.ECODE_INVAL) 123 124 try: 125 existing_uuid = self.cfg.LookupNetwork(self.op.network_name) 126 except errors.OpPrereqError: 127 pass 128 else: 129 raise errors.OpPrereqError("Desired network name '%s' already exists as a" 130 " network (UUID: %s)" % 131 (self.op.network_name, existing_uuid), 132 errors.ECODE_EXISTS) 133 134 # Check tag validity 135 for tag in self.op.tags: 136 objects.TaggableObject.ValidateTag(tag)
137
138 - def BuildHooksEnv(self):
139 """Build hooks env. 140 141 """ 142 args = { 143 "name": self.op.network_name, 144 "subnet": self.op.network, 145 "gateway": self.op.gateway, 146 "network6": self.op.network6, 147 "gateway6": self.op.gateway6, 148 "mac_prefix": self.op.mac_prefix, 149 "tags": self.op.tags, 150 } 151 return _BuildNetworkHookEnv(**args) # pylint: disable=W0142
152
153 - def Exec(self, feedback_fn):
154 """Add the ip pool to the cluster. 155 156 """ 157 nobj = objects.Network(name=self.op.network_name, 158 network=self.op.network, 159 gateway=self.op.gateway, 160 network6=self.op.network6, 161 gateway6=self.op.gateway6, 162 mac_prefix=self.op.mac_prefix, 163 uuid=self.network_uuid) 164 # Initialize the associated address pool 165 try: 166 pool = network.AddressPool.InitializeNetwork(nobj) 167 except errors.AddressPoolError, err: 168 raise errors.OpExecError("Cannot create IP address pool for network" 169 " '%s': %s" % (self.op.network_name, err)) 170 171 # Check if we need to reserve the nodes and the cluster master IP 172 # These may not be allocated to any instances in routed mode, as 173 # they wouldn't function anyway. 174 if self.op.conflicts_check: 175 for node in self.cfg.GetAllNodesInfo().values(): 176 for ip in [node.primary_ip, node.secondary_ip]: 177 try: 178 if pool.Contains(ip): 179 pool.Reserve(ip, external=True) 180 self.LogInfo("Reserved IP address of node '%s' (%s)", 181 node.name, ip) 182 except errors.AddressPoolError, err: 183 self.LogWarning("Cannot reserve IP address '%s' of node '%s': %s", 184 ip, node.name, err) 185 186 master_ip = self.cfg.GetClusterInfo().master_ip 187 try: 188 if pool.Contains(master_ip): 189 pool.Reserve(master_ip, external=True) 190 self.LogInfo("Reserved cluster master IP address (%s)", master_ip) 191 except errors.AddressPoolError, err: 192 self.LogWarning("Cannot reserve cluster master IP address (%s): %s", 193 master_ip, err) 194 195 if self.op.add_reserved_ips: 196 for ip in self.op.add_reserved_ips: 197 try: 198 pool.Reserve(ip, external=True) 199 except errors.AddressPoolError, err: 200 raise errors.OpExecError("Cannot reserve IP address '%s': %s" % 201 (ip, err)) 202 203 if self.op.tags: 204 for tag in self.op.tags: 205 nobj.AddTag(tag) 206 207 self.cfg.AddNetwork(nobj, self.proc.GetECId(), check_uuid=False)
208 209
210 -class LUNetworkRemove(LogicalUnit):
211 HPATH = "network-remove" 212 HTYPE = constants.HTYPE_NETWORK 213 REQ_BGL = False 214
215 - def ExpandNames(self):
216 self.network_uuid = self.cfg.LookupNetwork(self.op.network_name) 217 218 self.share_locks[locking.LEVEL_NODEGROUP] = 1 219 self.needed_locks = { 220 locking.LEVEL_NETWORK: [self.network_uuid], 221 locking.LEVEL_NODEGROUP: locking.ALL_SET, 222 }
223
224 - def CheckPrereq(self):
225 """Check prerequisites. 226 227 This checks that the given network name exists as a network, that is 228 empty (i.e., contains no nodes), and that is not the last group of the 229 cluster. 230 231 """ 232 # Verify that the network is not conncted. 233 node_groups = [group.name 234 for group in self.cfg.GetAllNodeGroupsInfo().values() 235 if self.network_uuid in group.networks] 236 237 if node_groups: 238 self.LogWarning("Network '%s' is connected to the following" 239 " node groups: %s" % 240 (self.op.network_name, 241 utils.CommaJoin(utils.NiceSort(node_groups)))) 242 raise errors.OpPrereqError("Network still connected", errors.ECODE_STATE)
243
244 - def BuildHooksEnv(self):
245 """Build hooks env. 246 247 """ 248 return { 249 "NETWORK_NAME": self.op.network_name, 250 }
251
252 - def BuildHooksNodes(self):
253 """Build hooks nodes. 254 255 """ 256 mn = self.cfg.GetMasterNode() 257 return ([mn], [mn])
258
259 - def Exec(self, feedback_fn):
260 """Remove the network. 261 262 """ 263 try: 264 self.cfg.RemoveNetwork(self.network_uuid) 265 except errors.ConfigurationError: 266 raise errors.OpExecError("Network '%s' with UUID %s disappeared" % 267 (self.op.network_name, self.network_uuid))
268 269
270 -class LUNetworkSetParams(LogicalUnit):
271 """Modifies the parameters of a network. 272 273 """ 274 HPATH = "network-modify" 275 HTYPE = constants.HTYPE_NETWORK 276 REQ_BGL = False 277
278 - def CheckArguments(self):
279 if (self.op.gateway and 280 (self.op.add_reserved_ips or self.op.remove_reserved_ips)): 281 raise errors.OpPrereqError("Cannot modify gateway and reserved ips" 282 " at once", errors.ECODE_INVAL)
283
284 - def ExpandNames(self):
285 self.network_uuid = self.cfg.LookupNetwork(self.op.network_name) 286 287 self.needed_locks = { 288 locking.LEVEL_NETWORK: [self.network_uuid], 289 }
290
291 - def CheckPrereq(self):
292 """Check prerequisites. 293 294 """ 295 self.network = self.cfg.GetNetwork(self.network_uuid) 296 self.gateway = self.network.gateway 297 self.mac_prefix = self.network.mac_prefix 298 self.network6 = self.network.network6 299 self.gateway6 = self.network.gateway6 300 self.tags = self.network.tags 301 302 self.pool = network.AddressPool(self.network) 303 304 if self.op.gateway: 305 if self.op.gateway == constants.VALUE_NONE: 306 self.gateway = None 307 else: 308 self.gateway = self.op.gateway 309 if self.pool.IsReserved(self.gateway): 310 raise errors.OpPrereqError("Gateway IP address '%s' is already" 311 " reserved" % self.gateway, 312 errors.ECODE_STATE) 313 314 if self.op.mac_prefix: 315 if self.op.mac_prefix == constants.VALUE_NONE: 316 self.mac_prefix = None 317 else: 318 self.mac_prefix = \ 319 utils.NormalizeAndValidateThreeOctetMacPrefix(self.op.mac_prefix) 320 321 if self.op.gateway6: 322 if self.op.gateway6 == constants.VALUE_NONE: 323 self.gateway6 = None 324 else: 325 self.gateway6 = self.op.gateway6 326 327 if self.op.network6: 328 if self.op.network6 == constants.VALUE_NONE: 329 self.network6 = None 330 else: 331 self.network6 = self.op.network6
332
333 - def BuildHooksEnv(self):
334 """Build hooks env. 335 336 """ 337 args = { 338 "name": self.op.network_name, 339 "subnet": self.network.network, 340 "gateway": self.gateway, 341 "network6": self.network6, 342 "gateway6": self.gateway6, 343 "mac_prefix": self.mac_prefix, 344 "tags": self.tags, 345 } 346 return _BuildNetworkHookEnv(**args) # pylint: disable=W0142
347
348 - def BuildHooksNodes(self):
349 """Build hooks nodes. 350 351 """ 352 mn = self.cfg.GetMasterNode() 353 return ([mn], [mn])
354
355 - def Exec(self, feedback_fn):
356 """Modifies the network. 357 358 """ 359 #TODO: reserve/release via temporary reservation manager 360 # extend cfg.ReserveIp/ReleaseIp with the external flag 361 if self.op.gateway: 362 if self.gateway == self.network.gateway: 363 self.LogWarning("Gateway is already %s", self.gateway) 364 else: 365 if self.gateway: 366 self.pool.Reserve(self.gateway, external=True) 367 if self.network.gateway: 368 self.pool.Release(self.network.gateway, external=True) 369 self.network.gateway = self.gateway 370 371 if self.op.add_reserved_ips: 372 for ip in self.op.add_reserved_ips: 373 try: 374 self.pool.Reserve(ip, external=True) 375 except errors.AddressPoolError, err: 376 self.LogWarning("Cannot reserve IP address %s: %s", ip, err) 377 378 if self.op.remove_reserved_ips: 379 for ip in self.op.remove_reserved_ips: 380 if ip == self.network.gateway: 381 self.LogWarning("Cannot unreserve Gateway's IP") 382 continue 383 try: 384 self.pool.Release(ip, external=True) 385 except errors.AddressPoolError, err: 386 self.LogWarning("Cannot release IP address %s: %s", ip, err) 387 388 if self.op.mac_prefix: 389 self.network.mac_prefix = self.mac_prefix 390 391 if self.op.network6: 392 self.network.network6 = self.network6 393 394 if self.op.gateway6: 395 self.network.gateway6 = self.gateway6 396 397 self.pool.Validate() 398 399 self.cfg.Update(self.network, feedback_fn)
400 401
402 -def _FmtNetworkConflict(details):
403 """Utility for L{_NetworkConflictCheck}. 404 405 """ 406 return utils.CommaJoin("nic%s/%s" % (idx, ipaddr) 407 for (idx, ipaddr) in details)
408 409
410 -def _NetworkConflictCheck(lu, check_fn, action, instances):
411 """Checks for network interface conflicts with a network. 412 413 @type lu: L{LogicalUnit} 414 @type check_fn: callable receiving one parameter (L{objects.NIC}) and 415 returning boolean 416 @param check_fn: Function checking for conflict 417 @type action: string 418 @param action: Part of error message (see code) 419 @param instances: the instances to check 420 @type instances: list of instance objects 421 @raise errors.OpPrereqError: If conflicting IP addresses are found. 422 423 """ 424 conflicts = [] 425 426 for instance in instances: 427 instconflicts = [(idx, nic.ip) 428 for (idx, nic) in enumerate(instance.nics) 429 if check_fn(nic)] 430 431 if instconflicts: 432 conflicts.append((instance.name, instconflicts)) 433 434 if conflicts: 435 lu.LogWarning("IP addresses from network '%s', which is about to %s" 436 " node group '%s', are in use: %s" % 437 (lu.network_name, action, lu.group.name, 438 utils.CommaJoin(("%s: %s" % 439 (name, _FmtNetworkConflict(details))) 440 for (name, details) in conflicts))) 441 442 raise errors.OpPrereqError("Conflicting IP addresses found; " 443 " remove/modify the corresponding network" 444 " interfaces", errors.ECODE_STATE)
445 446
447 -class LUNetworkConnect(LogicalUnit):
448 """Connect a network to a nodegroup 449 450 """ 451 HPATH = "network-connect" 452 HTYPE = constants.HTYPE_NETWORK 453 REQ_BGL = False 454
455 - def ExpandNames(self):
456 self.network_name = self.op.network_name 457 self.group_name = self.op.group_name 458 self.network_mode = self.op.network_mode 459 self.network_link = self.op.network_link 460 self.network_vlan = self.op.network_vlan 461 462 self.network_uuid = self.cfg.LookupNetwork(self.network_name) 463 self.group_uuid = self.cfg.LookupNodeGroup(self.group_name) 464 465 self.needed_locks = { 466 locking.LEVEL_INSTANCE: [], 467 locking.LEVEL_NODEGROUP: [self.group_uuid], 468 } 469 self.share_locks[locking.LEVEL_INSTANCE] = 1 470 471 if self.op.conflicts_check: 472 self.needed_locks[locking.LEVEL_NETWORK] = [self.network_uuid] 473 self.share_locks[locking.LEVEL_NETWORK] = 1
474
475 - def DeclareLocks(self, level):
476 if level == locking.LEVEL_INSTANCE: 477 assert not self.needed_locks[locking.LEVEL_INSTANCE] 478 479 # Lock instances optimistically, needs verification once group lock has 480 # been acquired 481 if self.op.conflicts_check: 482 self.needed_locks[locking.LEVEL_INSTANCE] = \ 483 self.cfg.GetInstanceNames( 484 self.cfg.GetNodeGroupInstances(self.group_uuid))
485
486 - def BuildHooksEnv(self):
487 ret = { 488 "GROUP_NAME": self.group_name, 489 "GROUP_NETWORK_MODE": self.network_mode, 490 "GROUP_NETWORK_LINK": self.network_link, 491 "GROUP_NETWORK_VLAN": self.network_vlan, 492 } 493 return ret
494
495 - def BuildHooksNodes(self):
496 node_uuids = self.cfg.GetNodeGroup(self.group_uuid).members 497 return (node_uuids, node_uuids)
498
499 - def CheckPrereq(self):
500 owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP)) 501 502 assert self.group_uuid in owned_groups 503 504 # Check if locked instances are still correct 505 owned_instance_names = frozenset(self.owned_locks(locking.LEVEL_INSTANCE)) 506 if self.op.conflicts_check: 507 CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instance_names) 508 509 self.netparams = { 510 constants.NIC_MODE: self.network_mode, 511 constants.NIC_LINK: self.network_link, 512 constants.NIC_VLAN: self.network_vlan, 513 } 514 515 objects.NIC.CheckParameterSyntax(self.netparams) 516 517 self.group = self.cfg.GetNodeGroup(self.group_uuid) 518 #if self.network_mode == constants.NIC_MODE_BRIDGED: 519 # _CheckNodeGroupBridgesExist(self, self.network_link, self.group_uuid) 520 self.connected = False 521 if self.network_uuid in self.group.networks: 522 self.LogWarning("Network '%s' is already mapped to group '%s'" % 523 (self.network_name, self.group.name)) 524 self.connected = True 525 526 # check only if not already connected 527 elif self.op.conflicts_check: 528 pool = network.AddressPool(self.cfg.GetNetwork(self.network_uuid)) 529 530 _NetworkConflictCheck( 531 self, lambda nic: pool.Contains(nic.ip), "connect to", 532 [instance_info for (_, instance_info) in 533 self.cfg.GetMultiInstanceInfoByName(owned_instance_names)])
534
535 - def Exec(self, feedback_fn):
536 # Connect the network and update the group only if not already connected 537 if not self.connected: 538 self.group.networks[self.network_uuid] = self.netparams 539 self.cfg.Update(self.group, feedback_fn)
540 541
542 -class LUNetworkDisconnect(LogicalUnit):
543 """Disconnect a network to a nodegroup 544 545 """ 546 HPATH = "network-disconnect" 547 HTYPE = constants.HTYPE_NETWORK 548 REQ_BGL = False 549
550 - def ExpandNames(self):
551 self.network_name = self.op.network_name 552 self.group_name = self.op.group_name 553 554 self.network_uuid = self.cfg.LookupNetwork(self.network_name) 555 self.group_uuid = self.cfg.LookupNodeGroup(self.group_name) 556 557 self.needed_locks = { 558 locking.LEVEL_INSTANCE: [], 559 locking.LEVEL_NODEGROUP: [self.group_uuid], 560 } 561 self.share_locks[locking.LEVEL_INSTANCE] = 1
562
563 - def DeclareLocks(self, level):
564 if level == locking.LEVEL_INSTANCE: 565 assert not self.needed_locks[locking.LEVEL_INSTANCE] 566 567 # Lock instances optimistically, needs verification once group lock has 568 # been acquired 569 self.needed_locks[locking.LEVEL_INSTANCE] = \ 570 self.cfg.GetInstanceNames( 571 self.cfg.GetNodeGroupInstances(self.group_uuid))
572
573 - def BuildHooksEnv(self):
574 ret = { 575 "GROUP_NAME": self.group_name, 576 } 577 578 if self.connected: 579 ret.update({ 580 "GROUP_NETWORK_MODE": self.netparams[constants.NIC_MODE], 581 "GROUP_NETWORK_LINK": self.netparams[constants.NIC_LINK], 582 "GROUP_NETWORK_VLAN": self.netparams[constants.NIC_VLAN], 583 }) 584 return ret
585
586 - def BuildHooksNodes(self):
587 nodes = self.cfg.GetNodeGroup(self.group_uuid).members 588 return (nodes, nodes)
589
590 - def CheckPrereq(self):
591 owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP)) 592 593 assert self.group_uuid in owned_groups 594 595 # Check if locked instances are still correct 596 owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE)) 597 CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instances) 598 599 self.group = self.cfg.GetNodeGroup(self.group_uuid) 600 self.connected = True 601 if self.network_uuid not in self.group.networks: 602 self.LogWarning("Network '%s' is not mapped to group '%s'", 603 self.network_name, self.group.name) 604 self.connected = False 605 606 # We need this check only if network is not already connected 607 else: 608 _NetworkConflictCheck( 609 self, lambda nic: nic.network == self.network_uuid, "disconnect from", 610 [instance_info for (_, instance_info) in 611 self.cfg.GetMultiInstanceInfoByName(owned_instances)]) 612 self.netparams = self.group.networks.get(self.network_uuid)
613
614 - def Exec(self, feedback_fn):
615 # Disconnect the network and update the group only if network is connected 616 if self.connected: 617 del self.group.networks[self.network_uuid] 618 self.cfg.Update(self.group, feedback_fn)
619