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.needed_locks = { 110 locking.LEVEL_NODE: locking.ALL_SET, 111 } 112 else: 113 self.needed_locks = {} 114 115 self.add_locks[locking.LEVEL_NETWORK] = self.network_uuid
116
117 - def CheckPrereq(self):
118 if self.op.network is None: 119 raise errors.OpPrereqError("Network must be given", 120 errors.ECODE_INVAL) 121 122 try: 123 existing_uuid = self.cfg.LookupNetwork(self.op.network_name) 124 except errors.OpPrereqError: 125 pass 126 else: 127 raise errors.OpPrereqError("Desired network name '%s' already exists as a" 128 " network (UUID: %s)" % 129 (self.op.network_name, existing_uuid), 130 errors.ECODE_EXISTS) 131 132 # Check tag validity 133 for tag in self.op.tags: 134 objects.TaggableObject.ValidateTag(tag)
135
136 - def BuildHooksEnv(self):
137 """Build hooks env. 138 139 """ 140 args = { 141 "name": self.op.network_name, 142 "subnet": self.op.network, 143 "gateway": self.op.gateway, 144 "network6": self.op.network6, 145 "gateway6": self.op.gateway6, 146 "mac_prefix": self.op.mac_prefix, 147 "tags": self.op.tags, 148 } 149 return _BuildNetworkHookEnv(**args) # pylint: disable=W0142
150
151 - def Exec(self, feedback_fn):
152 """Add the ip pool to the cluster. 153 154 """ 155 nobj = objects.Network(name=self.op.network_name, 156 network=self.op.network, 157 gateway=self.op.gateway, 158 network6=self.op.network6, 159 gateway6=self.op.gateway6, 160 mac_prefix=self.op.mac_prefix, 161 uuid=self.network_uuid) 162 # Initialize the associated address pool 163 try: 164 pool = network.AddressPool.InitializeNetwork(nobj) 165 except errors.AddressPoolError, err: 166 raise errors.OpExecError("Cannot create IP address pool for network" 167 " '%s': %s" % (self.op.network_name, err)) 168 169 # Check if we need to reserve the nodes and the cluster master IP 170 # These may not be allocated to any instances in routed mode, as 171 # they wouldn't function anyway. 172 if self.op.conflicts_check: 173 for node in self.cfg.GetAllNodesInfo().values(): 174 for ip in [node.primary_ip, node.secondary_ip]: 175 try: 176 if pool.Contains(ip): 177 pool.Reserve(ip, external=True) 178 self.LogInfo("Reserved IP address of node '%s' (%s)", 179 node.name, ip) 180 except errors.AddressPoolError, err: 181 self.LogWarning("Cannot reserve IP address '%s' of node '%s': %s", 182 ip, node.name, err) 183 184 master_ip = self.cfg.GetClusterInfo().master_ip 185 try: 186 if pool.Contains(master_ip): 187 pool.Reserve(master_ip, external=True) 188 self.LogInfo("Reserved cluster master IP address (%s)", master_ip) 189 except errors.AddressPoolError, err: 190 self.LogWarning("Cannot reserve cluster master IP address (%s): %s", 191 master_ip, err) 192 193 if self.op.add_reserved_ips: 194 for ip in self.op.add_reserved_ips: 195 try: 196 pool.Reserve(ip, external=True) 197 except errors.AddressPoolError, err: 198 raise errors.OpExecError("Cannot reserve IP address '%s': %s" % 199 (ip, err)) 200 201 if self.op.tags: 202 for tag in self.op.tags: 203 nobj.AddTag(tag) 204 205 self.cfg.AddNetwork(nobj, self.proc.GetECId(), check_uuid=False)
206 207
208 -class LUNetworkRemove(LogicalUnit):
209 HPATH = "network-remove" 210 HTYPE = constants.HTYPE_NETWORK 211 REQ_BGL = False 212
213 - def ExpandNames(self):
214 self.network_uuid = self.cfg.LookupNetwork(self.op.network_name) 215 216 self.share_locks[locking.LEVEL_NODEGROUP] = 1 217 self.needed_locks = { 218 locking.LEVEL_NETWORK: [self.network_uuid], 219 locking.LEVEL_NODEGROUP: locking.ALL_SET, 220 }
221
222 - def CheckPrereq(self):
223 """Check prerequisites. 224 225 This checks that the given network name exists as a network, that is 226 empty (i.e., contains no nodes), and that is not the last group of the 227 cluster. 228 229 """ 230 # Verify that the network is not conncted. 231 node_groups = [group.name 232 for group in self.cfg.GetAllNodeGroupsInfo().values() 233 if self.network_uuid in group.networks] 234 235 if node_groups: 236 self.LogWarning("Network '%s' is connected to the following" 237 " node groups: %s" % 238 (self.op.network_name, 239 utils.CommaJoin(utils.NiceSort(node_groups)))) 240 raise errors.OpPrereqError("Network still connected", errors.ECODE_STATE)
241
242 - def BuildHooksEnv(self):
243 """Build hooks env. 244 245 """ 246 return { 247 "NETWORK_NAME": self.op.network_name, 248 }
249
250 - def BuildHooksNodes(self):
251 """Build hooks nodes. 252 253 """ 254 mn = self.cfg.GetMasterNode() 255 return ([mn], [mn])
256
257 - def Exec(self, feedback_fn):
258 """Remove the network. 259 260 """ 261 try: 262 self.cfg.RemoveNetwork(self.network_uuid) 263 except errors.ConfigurationError: 264 raise errors.OpExecError("Network '%s' with UUID %s disappeared" % 265 (self.op.network_name, self.network_uuid))
266 267
268 -class LUNetworkSetParams(LogicalUnit):
269 """Modifies the parameters of a network. 270 271 """ 272 HPATH = "network-modify" 273 HTYPE = constants.HTYPE_NETWORK 274 REQ_BGL = False 275
276 - def CheckArguments(self):
277 if (self.op.gateway and 278 (self.op.add_reserved_ips or self.op.remove_reserved_ips)): 279 raise errors.OpPrereqError("Cannot modify gateway and reserved ips" 280 " at once", errors.ECODE_INVAL)
281
282 - def ExpandNames(self):
283 self.network_uuid = self.cfg.LookupNetwork(self.op.network_name) 284 285 self.needed_locks = { 286 locking.LEVEL_NETWORK: [self.network_uuid], 287 }
288
289 - def CheckPrereq(self):
290 """Check prerequisites. 291 292 """ 293 self.network = self.cfg.GetNetwork(self.network_uuid) 294 self.gateway = self.network.gateway 295 self.mac_prefix = self.network.mac_prefix 296 self.network6 = self.network.network6 297 self.gateway6 = self.network.gateway6 298 self.tags = self.network.tags 299 300 self.pool = network.AddressPool(self.network) 301 302 if self.op.gateway: 303 if self.op.gateway == constants.VALUE_NONE: 304 self.gateway = None 305 else: 306 self.gateway = self.op.gateway 307 if self.pool.IsReserved(self.gateway): 308 raise errors.OpPrereqError("Gateway IP address '%s' is already" 309 " reserved" % self.gateway, 310 errors.ECODE_STATE) 311 312 if self.op.mac_prefix: 313 if self.op.mac_prefix == constants.VALUE_NONE: 314 self.mac_prefix = None 315 else: 316 self.mac_prefix = \ 317 utils.NormalizeAndValidateThreeOctetMacPrefix(self.op.mac_prefix) 318 319 if self.op.gateway6: 320 if self.op.gateway6 == constants.VALUE_NONE: 321 self.gateway6 = None 322 else: 323 self.gateway6 = self.op.gateway6 324 325 if self.op.network6: 326 if self.op.network6 == constants.VALUE_NONE: 327 self.network6 = None 328 else: 329 self.network6 = self.op.network6
330
331 - def BuildHooksEnv(self):
332 """Build hooks env. 333 334 """ 335 args = { 336 "name": self.op.network_name, 337 "subnet": self.network.network, 338 "gateway": self.gateway, 339 "network6": self.network6, 340 "gateway6": self.gateway6, 341 "mac_prefix": self.mac_prefix, 342 "tags": self.tags, 343 } 344 return _BuildNetworkHookEnv(**args) # pylint: disable=W0142
345
346 - def BuildHooksNodes(self):
347 """Build hooks nodes. 348 349 """ 350 mn = self.cfg.GetMasterNode() 351 return ([mn], [mn])
352
353 - def Exec(self, feedback_fn):
354 """Modifies the network. 355 356 """ 357 #TODO: reserve/release via temporary reservation manager 358 # extend cfg.ReserveIp/ReleaseIp with the external flag 359 if self.op.gateway: 360 if self.gateway == self.network.gateway: 361 self.LogWarning("Gateway is already %s", self.gateway) 362 else: 363 if self.gateway: 364 self.pool.Reserve(self.gateway, external=True) 365 if self.network.gateway: 366 self.pool.Release(self.network.gateway, external=True) 367 self.network.gateway = self.gateway 368 369 if self.op.add_reserved_ips: 370 for ip in self.op.add_reserved_ips: 371 try: 372 self.pool.Reserve(ip, external=True) 373 except errors.AddressPoolError, err: 374 self.LogWarning("Cannot reserve IP address %s: %s", ip, err) 375 376 if self.op.remove_reserved_ips: 377 for ip in self.op.remove_reserved_ips: 378 if ip == self.network.gateway: 379 self.LogWarning("Cannot unreserve Gateway's IP") 380 continue 381 try: 382 self.pool.Release(ip, external=True) 383 except errors.AddressPoolError, err: 384 self.LogWarning("Cannot release IP address %s: %s", ip, err) 385 386 if self.op.mac_prefix: 387 self.network.mac_prefix = self.mac_prefix 388 389 if self.op.network6: 390 self.network.network6 = self.network6 391 392 if self.op.gateway6: 393 self.network.gateway6 = self.gateway6 394 395 self.pool.Validate() 396 397 self.cfg.Update(self.network, feedback_fn)
398 399
400 -def _FmtNetworkConflict(details):
401 """Utility for L{_NetworkConflictCheck}. 402 403 """ 404 return utils.CommaJoin("nic%s/%s" % (idx, ipaddr) 405 for (idx, ipaddr) in details)
406 407
408 -def _NetworkConflictCheck(lu, check_fn, action, instances):
409 """Checks for network interface conflicts with a network. 410 411 @type lu: L{LogicalUnit} 412 @type check_fn: callable receiving one parameter (L{objects.NIC}) and 413 returning boolean 414 @param check_fn: Function checking for conflict 415 @type action: string 416 @param action: Part of error message (see code) 417 @param instances: the instances to check 418 @type instances: list of instance objects 419 @raise errors.OpPrereqError: If conflicting IP addresses are found. 420 421 """ 422 conflicts = [] 423 424 for instance in instances: 425 instconflicts = [(idx, nic.ip) 426 for (idx, nic) in enumerate(instance.nics) 427 if check_fn(nic)] 428 429 if instconflicts: 430 conflicts.append((instance.name, instconflicts)) 431 432 if conflicts: 433 lu.LogWarning("IP addresses from network '%s', which is about to %s" 434 " node group '%s', are in use: %s" % 435 (lu.network_name, action, lu.group.name, 436 utils.CommaJoin(("%s: %s" % 437 (name, _FmtNetworkConflict(details))) 438 for (name, details) in conflicts))) 439 440 raise errors.OpPrereqError("Conflicting IP addresses found; " 441 " remove/modify the corresponding network" 442 " interfaces", errors.ECODE_STATE)
443 444
445 -class LUNetworkConnect(LogicalUnit):
446 """Connect a network to a nodegroup 447 448 """ 449 HPATH = "network-connect" 450 HTYPE = constants.HTYPE_NETWORK 451 REQ_BGL = False 452
453 - def ExpandNames(self):
454 self.network_name = self.op.network_name 455 self.group_name = self.op.group_name 456 self.network_mode = self.op.network_mode 457 self.network_link = self.op.network_link 458 self.network_vlan = self.op.network_vlan 459 460 self.network_uuid = self.cfg.LookupNetwork(self.network_name) 461 self.group_uuid = self.cfg.LookupNodeGroup(self.group_name) 462 463 self.needed_locks = { 464 locking.LEVEL_INSTANCE: [], 465 locking.LEVEL_NODEGROUP: [self.group_uuid], 466 } 467 self.share_locks[locking.LEVEL_INSTANCE] = 1 468 469 if self.op.conflicts_check: 470 self.needed_locks[locking.LEVEL_NETWORK] = [self.network_uuid] 471 self.share_locks[locking.LEVEL_NETWORK] = 1
472
473 - def DeclareLocks(self, level):
474 if level == locking.LEVEL_INSTANCE: 475 assert not self.needed_locks[locking.LEVEL_INSTANCE] 476 477 # Lock instances optimistically, needs verification once group lock has 478 # been acquired 479 if self.op.conflicts_check: 480 self.needed_locks[locking.LEVEL_INSTANCE] = \ 481 self.cfg.GetInstanceNames( 482 self.cfg.GetNodeGroupInstances(self.group_uuid))
483
484 - def BuildHooksEnv(self):
485 ret = { 486 "GROUP_NAME": self.group_name, 487 "GROUP_NETWORK_MODE": self.network_mode, 488 "GROUP_NETWORK_LINK": self.network_link, 489 "GROUP_NETWORK_VLAN": self.network_vlan, 490 } 491 return ret
492
493 - def BuildHooksNodes(self):
494 node_uuids = self.cfg.GetNodeGroup(self.group_uuid).members 495 return (node_uuids, node_uuids)
496
497 - def CheckPrereq(self):
498 owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP)) 499 500 assert self.group_uuid in owned_groups 501 502 # Check if locked instances are still correct 503 owned_instance_names = frozenset(self.owned_locks(locking.LEVEL_INSTANCE)) 504 if self.op.conflicts_check: 505 CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instance_names) 506 507 self.netparams = { 508 constants.NIC_MODE: self.network_mode, 509 constants.NIC_LINK: self.network_link, 510 constants.NIC_VLAN: self.network_vlan, 511 } 512 513 objects.NIC.CheckParameterSyntax(self.netparams) 514 515 self.group = self.cfg.GetNodeGroup(self.group_uuid) 516 #if self.network_mode == constants.NIC_MODE_BRIDGED: 517 # _CheckNodeGroupBridgesExist(self, self.network_link, self.group_uuid) 518 self.connected = False 519 if self.network_uuid in self.group.networks: 520 self.LogWarning("Network '%s' is already mapped to group '%s'" % 521 (self.network_name, self.group.name)) 522 self.connected = True 523 524 # check only if not already connected 525 elif self.op.conflicts_check: 526 pool = network.AddressPool(self.cfg.GetNetwork(self.network_uuid)) 527 528 _NetworkConflictCheck( 529 self, lambda nic: pool.Contains(nic.ip), "connect to", 530 [instance_info for (_, instance_info) in 531 self.cfg.GetMultiInstanceInfoByName(owned_instance_names)])
532
533 - def Exec(self, feedback_fn):
534 # Connect the network and update the group only if not already connected 535 if not self.connected: 536 self.group.networks[self.network_uuid] = self.netparams 537 self.cfg.Update(self.group, feedback_fn)
538 539
540 -class LUNetworkDisconnect(LogicalUnit):
541 """Disconnect a network to a nodegroup 542 543 """ 544 HPATH = "network-disconnect" 545 HTYPE = constants.HTYPE_NETWORK 546 REQ_BGL = False 547
548 - def ExpandNames(self):
549 self.network_name = self.op.network_name 550 self.group_name = self.op.group_name 551 552 self.network_uuid = self.cfg.LookupNetwork(self.network_name) 553 self.group_uuid = self.cfg.LookupNodeGroup(self.group_name) 554 555 self.needed_locks = { 556 locking.LEVEL_INSTANCE: [], 557 locking.LEVEL_NODEGROUP: [self.group_uuid], 558 } 559 self.share_locks[locking.LEVEL_INSTANCE] = 1
560
561 - def DeclareLocks(self, level):
562 if level == locking.LEVEL_INSTANCE: 563 assert not self.needed_locks[locking.LEVEL_INSTANCE] 564 565 # Lock instances optimistically, needs verification once group lock has 566 # been acquired 567 self.needed_locks[locking.LEVEL_INSTANCE] = \ 568 self.cfg.GetInstanceNames( 569 self.cfg.GetNodeGroupInstances(self.group_uuid))
570
571 - def BuildHooksEnv(self):
572 ret = { 573 "GROUP_NAME": self.group_name, 574 } 575 576 if self.connected: 577 ret.update({ 578 "GROUP_NETWORK_MODE": self.netparams[constants.NIC_MODE], 579 "GROUP_NETWORK_LINK": self.netparams[constants.NIC_LINK], 580 "GROUP_NETWORK_VLAN": self.netparams[constants.NIC_VLAN], 581 }) 582 return ret
583
584 - def BuildHooksNodes(self):
585 nodes = self.cfg.GetNodeGroup(self.group_uuid).members 586 return (nodes, nodes)
587
588 - def CheckPrereq(self):
589 owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP)) 590 591 assert self.group_uuid in owned_groups 592 593 # Check if locked instances are still correct 594 owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE)) 595 CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instances) 596 597 self.group = self.cfg.GetNodeGroup(self.group_uuid) 598 self.connected = True 599 if self.network_uuid not in self.group.networks: 600 self.LogWarning("Network '%s' is not mapped to group '%s'", 601 self.network_name, self.group.name) 602 self.connected = False 603 604 # We need this check only if network is not already connected 605 else: 606 _NetworkConflictCheck( 607 self, lambda nic: nic.network == self.network_uuid, "disconnect from", 608 [instance_info for (_, instance_info) in 609 self.cfg.GetMultiInstanceInfoByName(owned_instances)]) 610 self.netparams = self.group.networks.get(self.network_uuid)
611
612 - def Exec(self, feedback_fn):
613 # Disconnect the network and update the group only if network is connected 614 if self.connected: 615 del self.group.networks[self.network_uuid] 616 self.cfg.Update(self.group, feedback_fn)
617