1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
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
85 """Logical unit for creating networks.
86
87 """
88 HPATH = "network-add"
89 HTYPE = constants.HTYPE_NETWORK
90 REQ_BGL = False
91
93 """Build hooks nodes.
94
95 """
96 mn = self.cfg.GetMasterNode()
97 return ([mn], [mn])
98
100 if self.op.mac_prefix:
101 self.op.mac_prefix = \
102 utils.NormalizeAndValidateThreeOctetMacPrefix(self.op.mac_prefix)
103
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
135
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)
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
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
170
171
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
209 HPATH = "network-remove"
210 HTYPE = constants.HTYPE_NETWORK
211 REQ_BGL = False
212
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
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
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
243 """Build hooks env.
244
245 """
246 return {
247 "NETWORK_NAME": self.op.network_name,
248 }
249
251 """Build hooks nodes.
252
253 """
254 mn = self.cfg.GetMasterNode()
255 return ([mn], [mn])
256
257 - def Exec(self, feedback_fn):
266
267
269 """Modifies the parameters of a network.
270
271 """
272 HPATH = "network-modify"
273 HTYPE = constants.HTYPE_NETWORK
274 REQ_BGL = False
275
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
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
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
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)
345
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
358
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
401 """Utility for L{_NetworkConflictCheck}.
402
403 """
404 return utils.CommaJoin("nic%s/%s" % (idx, ipaddr)
405 for (idx, ipaddr) in details)
406
407
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
446 """Connect a network to a nodegroup
447
448 """
449 HPATH = "network-connect"
450 HTYPE = constants.HTYPE_NETWORK
451 REQ_BGL = False
452
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
483
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
494 node_uuids = self.cfg.GetNodeGroup(self.group_uuid).members
495 return (node_uuids, node_uuids)
496
498 owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
499
500 assert self.group_uuid in owned_groups
501
502
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
517
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
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
535 if not self.connected:
536 self.group.networks[self.network_uuid] = self.netparams
537 self.cfg.Update(self.group, feedback_fn)
538
539
541 """Disconnect a network to a nodegroup
542
543 """
544 HPATH = "network-disconnect"
545 HTYPE = constants.HTYPE_NETWORK
546 REQ_BGL = False
547
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
570
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
585 nodes = self.cfg.GetNodeGroup(self.group_uuid).members
586 return (nodes, nodes)
587
589 owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
590
591 assert self.group_uuid in owned_groups
592
593
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
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
614 if self.connected:
615 del self.group.networks[self.network_uuid]
616 self.cfg.Update(self.group, feedback_fn)
617