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