Revision 6c0a75db
b/lib/cmdlib.py | ||
---|---|---|
40 | 40 |
import shutil |
41 | 41 |
import itertools |
42 | 42 |
import operator |
43 |
import ipaddr |
|
43 | 44 |
|
44 | 45 |
from ganeti import ssh |
45 | 46 |
from ganeti import utils |
... | ... | |
61 | 62 |
from ganeti import runtime |
62 | 63 |
from ganeti import pathutils |
63 | 64 |
from ganeti import vcluster |
65 |
from ganeti import network |
|
64 | 66 |
from ganeti.masterd import iallocator |
65 | 67 |
|
66 | 68 |
import ganeti.masterd.instance # pylint: disable=W0611 |
... | ... | |
15303 | 15305 |
|
15304 | 15306 |
# Network LUs |
15305 | 15307 |
class LUNetworkAdd(LogicalUnit): |
15308 |
"""Logical unit for creating networks. |
|
15309 |
|
|
15310 |
""" |
|
15311 |
HPATH = "network-add" |
|
15312 |
HTYPE = constants.HTYPE_NETWORK |
|
15313 |
REQ_BGL = False |
|
15314 |
|
|
15306 | 15315 |
def BuildHooksNodes(self): |
15307 |
pass |
|
15316 |
"""Build hooks nodes. |
|
15317 |
|
|
15318 |
""" |
|
15319 |
mn = self.cfg.GetMasterNode() |
|
15320 |
return ([mn], [mn]) |
|
15321 |
|
|
15322 |
def ExpandNames(self): |
|
15323 |
self.network_uuid = self.cfg.GenerateUniqueID(self.proc.GetECId()) |
|
15324 |
self.needed_locks = {} |
|
15325 |
self.add_locks[locking.LEVEL_NETWORK] = self.network_uuid |
|
15326 |
|
|
15327 |
def CheckPrereq(self): |
|
15328 |
"""Check prerequisites. |
|
15329 |
|
|
15330 |
This checks that the given group name is not an existing node group |
|
15331 |
already. |
|
15332 |
|
|
15333 |
""" |
|
15334 |
if self.op.network is None: |
|
15335 |
raise errors.OpPrereqError("Network must be given", |
|
15336 |
errors.ECODE_INVAL) |
|
15337 |
|
|
15338 |
uuid = self.cfg.LookupNetwork(self.op.network_name) |
|
15339 |
|
|
15340 |
if uuid: |
|
15341 |
raise errors.OpPrereqError("Network '%s' already defined" % |
|
15342 |
self.op.network, errors.ECODE_EXISTS) |
|
15343 |
|
|
15308 | 15344 |
|
15309 | 15345 |
def BuildHooksEnv(self): |
15310 |
pass |
|
15346 |
"""Build hooks env. |
|
15347 |
|
|
15348 |
""" |
|
15349 |
env = { |
|
15350 |
"NETWORK_NAME": self.op.network_name, |
|
15351 |
"NETWORK_SUBNET": self.op.network, |
|
15352 |
"NETWORK_GATEWAY": self.op.gateway, |
|
15353 |
"NETWORK_SUBNET6": self.op.network6, |
|
15354 |
"NETWORK_GATEWAY6": self.op.gateway6, |
|
15355 |
"NETWORK_MAC_PREFIX": self.op.mac_prefix, |
|
15356 |
"NETWORK_TYPE": self.op.network_type, |
|
15357 |
} |
|
15358 |
return env |
|
15359 |
|
|
15360 |
def Exec(self, feedback_fn): |
|
15361 |
"""Add the ip pool to the cluster. |
|
15362 |
|
|
15363 |
""" |
|
15364 |
nobj = objects.Network(name=self.op.network_name, |
|
15365 |
network=self.op.network, |
|
15366 |
gateway=self.op.gateway, |
|
15367 |
network6=self.op.network6, |
|
15368 |
gateway6=self.op.gateway6, |
|
15369 |
mac_prefix=self.op.mac_prefix, |
|
15370 |
network_type=self.op.network_type, |
|
15371 |
uuid=self.network_uuid, |
|
15372 |
family=4) |
|
15373 |
# Initialize the associated address pool |
|
15374 |
try: |
|
15375 |
pool = network.AddressPool.InitializeNetwork(nobj) |
|
15376 |
except errors.AddressPoolError, e: |
|
15377 |
raise errors.OpExecError("Cannot create IP pool for this network. %s" % e) |
|
15378 |
|
|
15379 |
# Check if we need to reserve the nodes and the cluster master IP |
|
15380 |
# These may not be allocated to any instances in routed mode, as |
|
15381 |
# they wouldn't function anyway. |
|
15382 |
for node in self.cfg.GetAllNodesInfo().values(): |
|
15383 |
for ip in [node.primary_ip, node.secondary_ip]: |
|
15384 |
try: |
|
15385 |
pool.Reserve(ip) |
|
15386 |
self.LogInfo("Reserved node %s's IP (%s)", node.name, ip) |
|
15387 |
|
|
15388 |
except errors.AddressPoolError: |
|
15389 |
pass |
|
15390 |
|
|
15391 |
master_ip = self.cfg.GetClusterInfo().master_ip |
|
15392 |
try: |
|
15393 |
pool.Reserve(master_ip) |
|
15394 |
self.LogInfo("Reserved cluster master IP (%s)", master_ip) |
|
15395 |
except errors.AddressPoolError: |
|
15396 |
pass |
|
15397 |
|
|
15398 |
if self.op.add_reserved_ips: |
|
15399 |
for ip in self.op.add_reserved_ips: |
|
15400 |
try: |
|
15401 |
pool.Reserve(ip, external=True) |
|
15402 |
except errors.AddressPoolError, e: |
|
15403 |
raise errors.OpExecError("Cannot reserve IP %s. %s " % (ip, e)) |
|
15404 |
|
|
15405 |
self.cfg.AddNetwork(nobj, self.proc.GetECId(), check_uuid=False) |
|
15406 |
del self.remove_locks[locking.LEVEL_NETWORK] |
|
15311 | 15407 |
|
15312 | 15408 |
|
15313 | 15409 |
class LUNetworkRemove(LogicalUnit): |
15314 |
def BuildHooksNodes(self): |
|
15315 |
pass |
|
15410 |
HPATH = "network-remove" |
|
15411 |
HTYPE = constants.HTYPE_NETWORK |
|
15412 |
REQ_BGL = False |
|
15413 |
|
|
15414 |
def ExpandNames(self): |
|
15415 |
self.network_uuid = self.cfg.LookupNetwork(self.op.network_name) |
|
15416 |
|
|
15417 |
self.needed_locks = { |
|
15418 |
locking.LEVEL_NETWORK: [self.network_uuid], |
|
15419 |
} |
|
15420 |
|
|
15421 |
|
|
15422 |
def CheckPrereq(self): |
|
15423 |
"""Check prerequisites. |
|
15424 |
|
|
15425 |
This checks that the given network name exists as a network, that is |
|
15426 |
empty (i.e., contains no nodes), and that is not the last group of the |
|
15427 |
cluster. |
|
15428 |
|
|
15429 |
""" |
|
15430 |
if not self.network_uuid: |
|
15431 |
raise errors.OpPrereqError("Network %s not found" % self.op.network_name, |
|
15432 |
errors.ECODE_INVAL) |
|
15433 |
|
|
15434 |
# Verify that the network is not conncted. |
|
15435 |
node_groups = [group.name |
|
15436 |
for group in self.cfg.GetAllNodeGroupsInfo().values() |
|
15437 |
for network in group.networks.keys() |
|
15438 |
if network == self.network_uuid] |
|
15439 |
|
|
15440 |
if node_groups: |
|
15441 |
self.LogWarning("Nework '%s' is connected to the following" |
|
15442 |
" node groups: %s" % (self.op.network_name, |
|
15443 |
utils.CommaJoin(utils.NiceSort(node_groups)))) |
|
15444 |
raise errors.OpPrereqError("Network still connected", |
|
15445 |
errors.ECODE_STATE) |
|
15316 | 15446 |
|
15317 | 15447 |
def BuildHooksEnv(self): |
15318 |
pass |
|
15448 |
"""Build hooks env. |
|
15449 |
|
|
15450 |
""" |
|
15451 |
return { |
|
15452 |
"NETWORK_NAME": self.op.network_name, |
|
15453 |
} |
|
15454 |
|
|
15455 |
def BuildHooksNodes(self): |
|
15456 |
"""Build hooks nodes. |
|
15457 |
|
|
15458 |
""" |
|
15459 |
mn = self.cfg.GetMasterNode() |
|
15460 |
return ([mn], [mn]) |
|
15461 |
|
|
15462 |
def Exec(self, feedback_fn): |
|
15463 |
"""Remove the network. |
|
15464 |
|
|
15465 |
""" |
|
15466 |
try: |
|
15467 |
self.cfg.RemoveNetwork(self.network_uuid) |
|
15468 |
except errors.ConfigurationError: |
|
15469 |
raise errors.OpExecError("Network '%s' with UUID %s disappeared" % |
|
15470 |
(self.op.network_name, self.network_uuid)) |
|
15319 | 15471 |
|
15320 | 15472 |
|
15321 | 15473 |
class LUNetworkSetParams(LogicalUnit): |
b/lib/config.py | ||
---|---|---|
51 | 51 |
from ganeti import netutils |
52 | 52 |
from ganeti import runtime |
53 | 53 |
from ganeti import pathutils |
54 |
from ganeti import network |
|
54 | 55 |
|
55 | 56 |
|
56 | 57 |
_config_lock = locking.SharedLock("ConfigWriter") |
... | ... | |
2094 | 2095 |
nodegroups = ["%s %s" % (nodegroup.uuid, nodegroup.name) for nodegroup in |
2095 | 2096 |
self._config_data.nodegroups.values()] |
2096 | 2097 |
nodegroups_data = fn(utils.NiceSort(nodegroups)) |
2098 |
networks = ["%s %s" % (net.uuid, net.name) for net in |
|
2099 |
self._config_data.networks.values()] |
|
2100 |
networks_data = fn(utils.NiceSort(networks)) |
|
2097 | 2101 |
|
2098 | 2102 |
ssconf_values = { |
2099 | 2103 |
constants.SS_CLUSTER_NAME: cluster.cluster_name, |
... | ... | |
2118 | 2122 |
constants.SS_MAINTAIN_NODE_HEALTH: str(cluster.maintain_node_health), |
2119 | 2123 |
constants.SS_UID_POOL: uid_pool, |
2120 | 2124 |
constants.SS_NODEGROUPS: nodegroups_data, |
2125 |
constants.SS_NETWORKS: networks_data, |
|
2121 | 2126 |
} |
2122 | 2127 |
bad_values = [(k, v) for k, v in ssconf_values.items() |
2123 | 2128 |
if not isinstance(v, (str, basestring))] |
... | ... | |
2245 | 2250 |
""" |
2246 | 2251 |
for rm in self._all_rms: |
2247 | 2252 |
rm.DropECReservations(ec_id) |
2253 |
|
|
2254 |
@locking.ssynchronized(_config_lock, shared=1) |
|
2255 |
def GetAllNetworksInfo(self): |
|
2256 |
"""Get the configuration of all networks |
|
2257 |
|
|
2258 |
""" |
|
2259 |
return dict(self._config_data.networks) |
|
2260 |
|
|
2261 |
def _UnlockedGetNetworkList(self): |
|
2262 |
"""Get the list of networks. |
|
2263 |
|
|
2264 |
This function is for internal use, when the config lock is already held. |
|
2265 |
|
|
2266 |
""" |
|
2267 |
return self._config_data.networks.keys() |
|
2268 |
|
|
2269 |
@locking.ssynchronized(_config_lock, shared=1) |
|
2270 |
def GetNetworkList(self): |
|
2271 |
"""Get the list of networks. |
|
2272 |
|
|
2273 |
@return: array of networks, ex. ["main", "vlan100", "200] |
|
2274 |
|
|
2275 |
""" |
|
2276 |
return self._UnlockedGetNetworkList() |
|
2277 |
|
|
2278 |
@locking.ssynchronized(_config_lock, shared=1) |
|
2279 |
def GetNetworkNames(self): |
|
2280 |
"""Get a list of network names |
|
2281 |
|
|
2282 |
""" |
|
2283 |
names = [network.name |
|
2284 |
for network in self._config_data.networks.values()] |
|
2285 |
return names |
|
2286 |
|
|
2287 |
def _UnlockedGetNetwork(self, uuid): |
|
2288 |
"""Returns information about a network. |
|
2289 |
|
|
2290 |
This function is for internal use, when the config lock is already held. |
|
2291 |
|
|
2292 |
""" |
|
2293 |
if uuid not in self._config_data.networks: |
|
2294 |
return None |
|
2295 |
|
|
2296 |
return self._config_data.networks[uuid] |
|
2297 |
|
|
2298 |
@locking.ssynchronized(_config_lock, shared=1) |
|
2299 |
def GetNetwork(self, uuid): |
|
2300 |
"""Returns information about a network. |
|
2301 |
|
|
2302 |
It takes the information from the configuration file. |
|
2303 |
|
|
2304 |
@param uuid: UUID of the network |
|
2305 |
|
|
2306 |
@rtype: L{objects.Network} |
|
2307 |
@return: the network object |
|
2308 |
|
|
2309 |
""" |
|
2310 |
return self._UnlockedGetNetwork(uuid) |
|
2311 |
|
|
2312 |
@locking.ssynchronized(_config_lock) |
|
2313 |
def AddNetwork(self, net, ec_id, check_uuid=True): |
|
2314 |
"""Add a network to the configuration. |
|
2315 |
|
|
2316 |
@type net: L{objects.Network} |
|
2317 |
@param net: the Network object to add |
|
2318 |
@type ec_id: string |
|
2319 |
@param ec_id: unique id for the job to use when creating a missing UUID |
|
2320 |
|
|
2321 |
""" |
|
2322 |
self._UnlockedAddNetwork(net, ec_id, check_uuid) |
|
2323 |
self._WriteConfig() |
|
2324 |
|
|
2325 |
def _UnlockedAddNetwork(self, net, ec_id, check_uuid): |
|
2326 |
"""Add a network to the configuration. |
|
2327 |
|
|
2328 |
""" |
|
2329 |
logging.info("Adding network %s to configuration", net.name) |
|
2330 |
|
|
2331 |
if check_uuid: |
|
2332 |
self._EnsureUUID(net, ec_id) |
|
2333 |
|
|
2334 |
existing_uuid = self._UnlockedLookupNetwork(net.name) |
|
2335 |
if existing_uuid: |
|
2336 |
raise errors.OpPrereqError("Desired network name '%s' already" |
|
2337 |
" exists as a network (UUID: %s)" % |
|
2338 |
(net.name, existing_uuid), |
|
2339 |
errors.ECODE_EXISTS) |
|
2340 |
net.serial_no = 1 |
|
2341 |
self._config_data.networks[net.uuid] = net |
|
2342 |
self._config_data.cluster.serial_no += 1 |
|
2343 |
|
|
2344 |
def _UnlockedLookupNetwork(self, target): |
|
2345 |
"""Lookup a network's UUID. |
|
2346 |
|
|
2347 |
@type target: string |
|
2348 |
@param target: network name or UUID |
|
2349 |
@rtype: string |
|
2350 |
@return: network UUID |
|
2351 |
@raises errors.OpPrereqError: when the target network cannot be found |
|
2352 |
|
|
2353 |
""" |
|
2354 |
if target in self._config_data.networks: |
|
2355 |
return target |
|
2356 |
for net in self._config_data.networks.values(): |
|
2357 |
if net.name == target: |
|
2358 |
return net.uuid |
|
2359 |
return None |
|
2360 |
|
|
2361 |
@locking.ssynchronized(_config_lock, shared=1) |
|
2362 |
def LookupNetwork(self, target): |
|
2363 |
"""Lookup a network's UUID. |
|
2364 |
|
|
2365 |
This function is just a wrapper over L{_UnlockedLookupNetwork}. |
|
2366 |
|
|
2367 |
@type target: string |
|
2368 |
@param target: network name or UUID |
|
2369 |
@rtype: string |
|
2370 |
@return: network UUID |
|
2371 |
|
|
2372 |
""" |
|
2373 |
return self._UnlockedLookupNetwork(target) |
|
2374 |
|
|
2375 |
@locking.ssynchronized(_config_lock) |
|
2376 |
def RemoveNetwork(self, network_uuid): |
|
2377 |
"""Remove a network from the configuration. |
|
2378 |
|
|
2379 |
@type network_uuid: string |
|
2380 |
@param network_uuid: the UUID of the network to remove |
|
2381 |
|
|
2382 |
""" |
|
2383 |
logging.info("Removing network %s from configuration", network_uuid) |
|
2384 |
|
|
2385 |
if network_uuid not in self._config_data.networks: |
|
2386 |
raise errors.ConfigurationError("Unknown network '%s'" % network_uuid) |
|
2387 |
|
|
2388 |
del self._config_data.networks[network_uuid] |
|
2389 |
self._config_data.cluster.serial_no += 1 |
|
2390 |
self._WriteConfig() |
b/lib/locking.py | ||
---|---|---|
1477 | 1477 |
#: Level for node resources, used for operations with possibly high impact on |
1478 | 1478 |
#: the node's disks. |
1479 | 1479 |
LEVEL_NODE_RES = 4 |
1480 |
LEVEL_NETWORK = 5 |
|
1480 | 1481 |
|
1481 | 1482 |
LEVELS = [ |
1482 | 1483 |
LEVEL_CLUSTER, |
... | ... | |
1484 | 1485 |
LEVEL_NODEGROUP, |
1485 | 1486 |
LEVEL_NODE, |
1486 | 1487 |
LEVEL_NODE_RES, |
1488 |
LEVEL_NETWORK, |
|
1487 | 1489 |
] |
1488 | 1490 |
|
1489 | 1491 |
# Lock levels which are modifiable |
... | ... | |
1492 | 1494 |
LEVEL_NODE, |
1493 | 1495 |
LEVEL_NODEGROUP, |
1494 | 1496 |
LEVEL_INSTANCE, |
1497 |
LEVEL_NETWORK, |
|
1495 | 1498 |
]) |
1496 | 1499 |
|
1497 | 1500 |
#: Lock level names (make sure to use singular form) |
... | ... | |
1501 | 1504 |
LEVEL_NODEGROUP: "nodegroup", |
1502 | 1505 |
LEVEL_NODE: "node", |
1503 | 1506 |
LEVEL_NODE_RES: "node-res", |
1507 |
LEVEL_NETWORK: "network", |
|
1504 | 1508 |
} |
1505 | 1509 |
|
1506 | 1510 |
# Constant for the big ganeti lock |
... | ... | |
1518 | 1522 |
""" |
1519 | 1523 |
_instance = None |
1520 | 1524 |
|
1521 |
def __init__(self, nodes, nodegroups, instances): |
|
1525 |
def __init__(self, nodes, nodegroups, instances, networks):
|
|
1522 | 1526 |
"""Constructs a new GanetiLockManager object. |
1523 | 1527 |
|
1524 | 1528 |
There should be only a GanetiLockManager object at any time, so this |
... | ... | |
1543 | 1547 |
LEVEL_NODE: LockSet(nodes, "node", monitor=self._monitor), |
1544 | 1548 |
LEVEL_NODE_RES: LockSet(nodes, "node-res", monitor=self._monitor), |
1545 | 1549 |
LEVEL_NODEGROUP: LockSet(nodegroups, "nodegroup", monitor=self._monitor), |
1546 |
LEVEL_INSTANCE: LockSet(instances, "instance", |
|
1547 |
monitor=self._monitor),
|
|
1550 |
LEVEL_INSTANCE: LockSet(instances, "instance", monitor=self._monitor),
|
|
1551 |
LEVEL_NETWORK: LockSet(networks, "network", monitor=self._monitor),
|
|
1548 | 1552 |
} |
1549 | 1553 |
|
1550 | 1554 |
assert compat.all(ls.name == LEVEL_NAMES[level] |
b/lib/server/masterd.py | ||
---|---|---|
487 | 487 |
self.glm = locking.GanetiLockManager( |
488 | 488 |
self.cfg.GetNodeList(), |
489 | 489 |
self.cfg.GetNodeGroupList(), |
490 |
self.cfg.GetInstanceList()) |
|
490 |
self.cfg.GetInstanceList(), |
|
491 |
self.cfg.GetNetworkList()) |
|
491 | 492 |
|
492 | 493 |
self.cfg.SetContext(self) |
493 | 494 |
|
Also available in: Unified diff