blob: 6dbdbda6445ff9516ce910397510d9238930ac74 [file] [log] [blame]
#
#
# Copyright (C) 2013 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Support for mocking the cluster configuration"""
import random
import time
import uuid as uuid_module
from ganeti import config
from ganeti import constants
from ganeti import errors
from ganeti.network import AddressPool
from ganeti import objects
from ganeti import utils
import mocks
RESERVE_ACTION = "reserve"
RELEASE_ACTION = "release"
def _StubGetEntResolver():
return mocks.FakeGetentResolver()
def _UpdateIvNames(base_idx, disks):
"""Update the C{iv_name} attribute of disks.
@type disks: list of L{objects.Disk}
"""
for (idx, disk) in enumerate(disks):
disk.iv_name = "disk/%s" % (base_idx + idx)
# pylint: disable=R0904
class ConfigMock(config.ConfigWriter):
"""A mocked cluster configuration with added methods for easy customization.
"""
def __init__(self, cfg_file="/dev/null"):
self._cur_group_id = 1
self._cur_node_id = 1
self._cur_inst_id = 1
self._cur_disk_id = 1
self._cur_os_id = 1
self._cur_nic_id = 1
self._cur_net_id = 1
self._default_os = None
self._mocked_config_store = None
self._temporary_macs = config.TemporaryReservationManager()
self._temporary_secrets = config.TemporaryReservationManager()
self._temporary_lvs = config.TemporaryReservationManager()
self._temporary_ips = config.TemporaryReservationManager()
super(ConfigMock, self).__init__(cfg_file=cfg_file,
_getents=_StubGetEntResolver(),
offline=True)
with self.GetConfigManager():
self._CreateConfig()
def _GetUuid(self):
return str(uuid_module.uuid4())
def _GetObjUuid(self, obj):
if obj is None:
return None
elif isinstance(obj, objects.ConfigObject):
return obj.uuid
else:
return obj
def AddNewNodeGroup(self,
uuid=None,
name=None,
ndparams=None,
diskparams=None,
ipolicy=None,
hv_state_static=None,
disk_state_static=None,
alloc_policy=None,
networks=None):
"""Add a new L{objects.NodeGroup} to the cluster configuration
See L{objects.NodeGroup} for parameter documentation.
@rtype: L{objects.NodeGroup}
@return: the newly added node group
"""
group_id = self._cur_group_id
self._cur_group_id += 1
if uuid is None:
uuid = self._GetUuid()
if name is None:
name = "mock_group_%d" % group_id
if networks is None:
networks = {}
group = objects.NodeGroup(uuid=uuid,
name=name,
ndparams=ndparams,
diskparams=diskparams,
ipolicy=ipolicy,
hv_state_static=hv_state_static,
disk_state_static=disk_state_static,
alloc_policy=alloc_policy,
networks=networks,
members=[])
self._UnlockedAddNodeGroup(group, None, True)
return group
# pylint: disable=R0913
def AddNewNode(self,
uuid=None,
name=None,
primary_ip=None,
secondary_ip=None,
master_candidate=True,
offline=False,
drained=False,
group=None,
master_capable=True,
vm_capable=True,
ndparams=None,
powered=True,
hv_state=None,
hv_state_static=None,
disk_state=None,
disk_state_static=None):
"""Add a new L{objects.Node} to the cluster configuration
See L{objects.Node} for parameter documentation.
@rtype: L{objects.Node}
@return: the newly added node
"""
node_id = self._cur_node_id
self._cur_node_id += 1
if uuid is None:
uuid = self._GetUuid()
if name is None:
name = "mock_node_%d.example.com" % node_id
if primary_ip is None:
primary_ip = "192.0.2.%d" % node_id
if secondary_ip is None:
secondary_ip = "203.0.113.%d" % node_id
if group is None:
group = self._default_group.uuid
group = self._GetObjUuid(group)
if ndparams is None:
ndparams = {}
node = objects.Node(uuid=uuid,
name=name,
primary_ip=primary_ip,
secondary_ip=secondary_ip,
master_candidate=master_candidate,
offline=offline,
drained=drained,
group=group,
master_capable=master_capable,
vm_capable=vm_capable,
ndparams=ndparams,
powered=powered,
hv_state=hv_state,
hv_state_static=hv_state_static,
disk_state=disk_state,
disk_state_static=disk_state_static)
self._UnlockedAddNode(node, None)
return node
def AddNewInstance(self,
uuid=None,
name=None,
primary_node=None,
os=None,
hypervisor=None,
hvparams=None,
beparams=None,
osparams=None,
osparams_private=None,
admin_state=None,
admin_state_source=None,
nics=None,
disks=None,
disk_template=None,
disks_active=None,
network_port=None,
secondary_node=None):
"""Add a new L{objects.Instance} to the cluster configuration
See L{objects.Instance} for parameter documentation.
@rtype: L{objects.Instance}
@return: the newly added instance
"""
inst_id = self._cur_inst_id
self._cur_inst_id += 1
if uuid is None:
uuid = self._GetUuid()
if name is None:
name = "mock_inst_%d.example.com" % inst_id
if primary_node is None:
primary_node = self._master_node.uuid
primary_node = self._GetObjUuid(primary_node)
if os is None:
os = self.GetDefaultOs().name + objects.OS.VARIANT_DELIM +\
self.GetDefaultOs().supported_variants[0]
if hypervisor is None:
hypervisor = self.GetClusterInfo().enabled_hypervisors[0]
if hvparams is None:
hvparams = {}
if beparams is None:
beparams = {}
if osparams is None:
osparams = {}
if osparams_private is None:
osparams_private = {}
if admin_state is None:
admin_state = constants.ADMINST_DOWN
if admin_state_source is None:
admin_state_source = constants.ADMIN_SOURCE
if nics is None:
nics = [self.CreateNic()]
if disk_template is None:
if disks is None:
# user chose nothing, so create a plain disk for him
disk_template = constants.DT_PLAIN
elif len(disks) == 0:
disk_template = constants.DT_DISKLESS
else:
disk_template = disks[0].dev_type
if disks is None:
if disk_template == constants.DT_DISKLESS:
disks = []
elif disk_template == constants.DT_EXT:
provider = "mock_provider"
disks = [self.CreateDisk(dev_type=disk_template,
primary_node=primary_node,
secondary_node=secondary_node,
params={constants.IDISK_PROVIDER: provider})]
else:
disks = [self.CreateDisk(dev_type=disk_template,
primary_node=primary_node,
secondary_node=secondary_node)]
if disks_active is None:
disks_active = admin_state == constants.ADMINST_UP
inst = objects.Instance(uuid=uuid,
name=name,
primary_node=primary_node,
os=os,
hypervisor=hypervisor,
hvparams=hvparams,
beparams=beparams,
osparams=osparams,
osparams_private=osparams_private,
admin_state=admin_state,
admin_state_source=admin_state_source,
nics=nics,
disks=[],
disks_active=disks_active,
network_port=network_port)
self.AddInstance(inst, None)
for disk in disks:
self.AddInstanceDisk(inst.uuid, disk)
return inst
def AddNewNetwork(self,
uuid=None,
name=None,
mac_prefix=None,
network=None,
network6=None,
gateway=None,
gateway6=None,
reservations=None,
ext_reservations=None):
"""Add a new L{objects.Network} to the cluster configuration
See L{objects.Network} for parameter documentation.
@rtype: L{objects.Network}
@return: the newly added network
"""
net_id = self._cur_net_id
self._cur_net_id += 1
if uuid is None:
uuid = self._GetUuid()
if name is None:
name = "mock_net_%d" % net_id
if network is None:
network = "198.51.100.0/24"
if gateway is None:
if network[-3:] == "/24":
gateway = network[:-4] + "1"
else:
gateway = "198.51.100.1"
if network[-3:] == "/24" and gateway == network[:-4] + "1":
if reservations is None:
reservations = "0" * 256
if ext_reservations:
ext_reservations = "11" + ("0" * 253) + "1"
elif reservations is None or ext_reservations is None:
raise AssertionError("You have to specify 'reservations' and"
" 'ext_reservations'!")
net = objects.Network(uuid=uuid,
name=name,
mac_prefix=mac_prefix,
network=network,
network6=network6,
gateway=gateway,
gateway6=gateway6,
reservations=reservations,
ext_reservations=ext_reservations)
self.AddNetwork(net, None)
return net
def AddOrphanDisk(self, **params):
disk = self.CreateDisk(**params) # pylint: disable=W0142
self._UnlockedAddDisk(disk)
def ConnectNetworkToGroup(self, net, group, netparams=None):
"""Connect the given network to the group.
@type net: string or L{objects.Network}
@param net: network object or UUID
@type group: string of L{objects.NodeGroup}
@param group: node group object of UUID
@type netparams: dict
@param netparams: network parameters for this connection
"""
net_obj = None
if isinstance(net, objects.Network):
net_obj = net
else:
net_obj = self.GetNetwork(net)
group_obj = None
if isinstance(group, objects.NodeGroup):
group_obj = group
else:
group_obj = self.GetNodeGroup(group)
if net_obj is None or group_obj is None:
raise AssertionError("Failed to get network or node group")
if netparams is None:
netparams = {
constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
constants.NIC_LINK: "br_mock"
}
group_obj.networks[net_obj.uuid] = netparams
def CreateDisk(self,
uuid=None,
name=None,
dev_type=constants.DT_PLAIN,
logical_id=None,
children=None,
nodes=None,
iv_name=None,
size=1024,
mode=constants.DISK_RDWR,
params=None,
spindles=None,
primary_node=None,
secondary_node=None,
create_nodes=False,
instance_disk_index=0):
"""Create a new L{objecs.Disk} object
@rtype: L{objects.Disk}
@return: the newly create disk object
"""
disk_id = self._cur_disk_id
self._cur_disk_id += 1
if uuid is None:
uuid = self._GetUuid()
if name is None:
name = "mock_disk_%d" % disk_id
if params is None:
params = {}
if dev_type == constants.DT_DRBD8:
pnode_uuid = self._GetObjUuid(primary_node)
snode_uuid = self._GetObjUuid(secondary_node)
if logical_id is not None:
pnode_uuid = logical_id[0]
snode_uuid = logical_id[1]
if pnode_uuid is None and create_nodes:
pnode_uuid = self.AddNewNode().uuid
if snode_uuid is None and create_nodes:
snode_uuid = self.AddNewNode().uuid
if pnode_uuid is None or snode_uuid is None:
raise AssertionError("Trying to create DRBD disk without nodes!")
if logical_id is None:
logical_id = (pnode_uuid, snode_uuid,
constants.FIRST_DRBD_PORT + disk_id,
disk_id, disk_id, "mock_secret")
if children is None:
data_child = self.CreateDisk(dev_type=constants.DT_PLAIN,
size=size)
meta_child = self.CreateDisk(dev_type=constants.DT_PLAIN,
size=constants.DRBD_META_SIZE)
children = [data_child, meta_child]
if nodes is None:
nodes = [pnode_uuid, snode_uuid]
elif dev_type == constants.DT_PLAIN:
if logical_id is None:
logical_id = ("mockvg", "mock_disk_%d" % disk_id)
if nodes is None and primary_node is not None:
nodes = [primary_node]
elif dev_type in constants.DTS_FILEBASED:
if logical_id is None:
logical_id = (constants.FD_LOOP, "/file/storage/disk%d" % disk_id)
if (nodes is None and primary_node is not None and
dev_type == constants.DT_FILE):
nodes = [primary_node]
elif dev_type == constants.DT_BLOCK:
if logical_id is None:
logical_id = (constants.BLOCKDEV_DRIVER_MANUAL,
"/dev/disk/disk%d" % disk_id)
elif dev_type == constants.DT_EXT:
if logical_id is None:
provider = params.get(constants.IDISK_PROVIDER, None)
if provider is None:
raise AssertionError("You must specify a 'provider' for 'ext' disks")
logical_id = (provider, "mock_disk_%d" % disk_id)
elif logical_id is None:
raise NotImplementedError
if children is None:
children = []
if nodes is None:
nodes = []
if iv_name is None:
iv_name = "disk/%d" % instance_disk_index
return objects.Disk(uuid=uuid,
name=name,
dev_type=dev_type,
logical_id=logical_id,
children=children,
nodes=nodes,
iv_name=iv_name,
size=size,
mode=mode,
params=params,
spindles=spindles)
def GetDefaultOs(self):
if self._default_os is None:
self._default_os = self.CreateOs(name="mocked_os")
return self._default_os
def CreateOs(self,
name=None,
path=None,
api_versions=None,
create_script=None,
export_script=None,
import_script=None,
rename_script=None,
verify_script=None,
supported_variants=None,
supported_parameters=None):
"""Create a new L{objects.OS} object
@rtype: L{object.OS}
@return: the newly create OS objects
"""
os_id = self._cur_os_id
self._cur_os_id += 1
if name is None:
name = "mock_os_%d" % os_id
if path is None:
path = "/mocked/path/%d" % os_id
if api_versions is None:
api_versions = [constants.OS_API_V20]
if create_script is None:
create_script = "mock_create.sh"
if export_script is None:
export_script = "mock_export.sh"
if import_script is None:
import_script = "mock_import.sh"
if rename_script is None:
rename_script = "mock_rename.sh"
if verify_script is None:
verify_script = "mock_verify.sh"
if supported_variants is None:
supported_variants = ["default"]
if supported_parameters is None:
supported_parameters = ["mock_param"]
return objects.OS(name=name,
path=path,
api_versions=api_versions,
create_script=create_script,
export_script=export_script,
import_script=import_script,
rename_script=rename_script,
verify_script=verify_script,
supported_variants=supported_variants,
supported_parameters=supported_parameters)
def CreateNic(self,
uuid=None,
name=None,
mac=None,
ip=None,
network=None,
nicparams=None,
netinfo=None):
"""Create a new L{objecs.NIC} object
@rtype: L{objects.NIC}
@return: the newly create NIC object
"""
nic_id = self._cur_nic_id
self._cur_nic_id += 1
if uuid is None:
uuid = self._GetUuid()
if name is None:
name = "mock_nic_%d" % nic_id
if mac is None:
mac = "aa:00:00:aa:%02x:%02x" % (nic_id / 0xff, nic_id % 0xff)
if isinstance(network, objects.Network):
if ip:
pool = AddressPool(network)
pool.Reserve(ip)
network = network.uuid
if nicparams is None:
nicparams = {}
return objects.NIC(uuid=uuid,
name=name,
mac=mac,
ip=ip,
network=network,
nicparams=nicparams,
netinfo=netinfo)
def SetEnabledDiskTemplates(self, enabled_disk_templates):
"""Set the enabled disk templates in the cluster.
This also takes care of required IPolicy updates.
@type enabled_disk_templates: list of string
@param enabled_disk_templates: list of disk templates to enable
"""
cluster = self.GetClusterInfo()
cluster.enabled_disk_templates = list(enabled_disk_templates)
cluster.ipolicy[constants.IPOLICY_DTS] = list(enabled_disk_templates)
def ComputeDRBDMap(self):
return dict((node_uuid, {}) for node_uuid in self._ConfigData().nodes)
def AllocateDRBDMinor(self, node_uuids, disk_uuid):
return [0] * len(node_uuids)
def ReleaseDRBDMinors(self, disk_uuid):
pass
def SetIPolicyField(self, category, field, value):
"""Set a value of a desired ipolicy field.
@type category: one of L{constants.ISPECS_MAX}, L{constants.ISPECS_MIN},
L{constants.ISPECS_STD}
@param category: Whether to change the default value, or the upper or lower
bound.
@type field: string
@param field: The field to change.
@type value: any
@param value: The value to assign.
"""
if category not in [constants.ISPECS_MAX, constants.ISPECS_MIN,
constants.ISPECS_STD]:
raise ValueError("Invalid ipolicy category %s" % category)
ipolicy_dict = self.GetClusterInfo().ipolicy[constants.ISPECS_MINMAX][0]
ipolicy_dict[category][field] = value
def _CreateConfig(self):
self._config_data = objects.ConfigData(
version=constants.CONFIG_VERSION,
cluster=None,
nodegroups={},
nodes={},
instances={},
networks={},
disks={})
master_node_uuid = self._GetUuid()
self._cluster = objects.Cluster(
serial_no=1,
rsahostkeypub="",
highest_used_port=(constants.FIRST_DRBD_PORT - 1),
tcpudp_port_pool=set(),
mac_prefix="aa:00:00",
volume_group_name="xenvg",
reserved_lvs=None,
drbd_usermode_helper="/bin/true",
master_node=master_node_uuid,
master_ip="192.0.2.254",
master_netdev=constants.DEFAULT_BRIDGE,
master_netmask=None,
use_external_mip_script=None,
cluster_name="cluster.example.com",
file_storage_dir="/tmp",
shared_file_storage_dir=None,
enabled_hypervisors=[constants.HT_XEN_HVM, constants.HT_XEN_PVM,
constants.HT_KVM],
hvparams=constants.HVC_DEFAULTS.copy(),
ipolicy=None,
os_hvp={self.GetDefaultOs().name: constants.HVC_DEFAULTS.copy()},
beparams=None,
osparams=None,
osparams_private_cluster=None,
nicparams={constants.PP_DEFAULT: constants.NICC_DEFAULTS},
ndparams=None,
diskparams=None,
candidate_pool_size=3,
modify_etc_hosts=False,
modify_ssh_setup=False,
maintain_node_health=False,
uid_pool=None,
default_iallocator="mock_iallocator",
hidden_os=None,
blacklisted_os=None,
primary_ip_family=None,
prealloc_wipe_disks=None,
enabled_disk_templates=list(constants.DISK_TEMPLATE_PREFERENCE),
)
self._cluster.ctime = self._cluster.mtime = time.time()
self._cluster.UpgradeConfig()
self._ConfigData().cluster = self._cluster
self._default_group = self.AddNewNodeGroup(name="default")
self._master_node = self.AddNewNode(uuid=master_node_uuid)
def _OpenConfig(self, _accept_foreign, force=False):
self._config_data = self._mocked_config_store
def _WriteConfig(self, destination=None, releaselock=False):
self._mocked_config_store = self._ConfigData()
def _GetRpc(self, _address_list):
raise AssertionError("This should not be used during tests!")
def _UnlockedGetNetworkMACPrefix(self, net_uuid):
"""Return the network mac prefix if it exists or the cluster level default.
"""
prefix = None
if net_uuid:
nobj = self._UnlockedGetNetwork(net_uuid)
if nobj.mac_prefix:
prefix = nobj.mac_prefix
return prefix
def _GenerateOneMAC(self, prefix=None):
"""Return a function that randomly generates a MAC suffic
and appends it to the given prefix. If prefix is not given get
the cluster level default.
"""
if not prefix:
prefix = self._ConfigData().cluster.mac_prefix
def GenMac():
byte1 = random.randrange(0, 256)
byte2 = random.randrange(0, 256)
byte3 = random.randrange(0, 256)
mac = "%s:%02x:%02x:%02x" % (prefix, byte1, byte2, byte3)
return mac
return GenMac
def GenerateMAC(self, net_uuid, ec_id):
"""Generate a MAC for an instance.
This should check the current instances for duplicates.
"""
existing = self._AllMACs()
prefix = self._UnlockedGetNetworkMACPrefix(net_uuid)
gen_mac = self._GenerateOneMAC(prefix)
return self._temporary_macs.Generate(existing, gen_mac, ec_id)
def ReserveMAC(self, mac, ec_id):
"""Reserve a MAC for an instance.
This only checks instances managed by this cluster, it does not
check for potential collisions elsewhere.
"""
all_macs = self._AllMACs()
if mac in all_macs:
raise errors.ReservationError("mac already in use")
else:
self._temporary_macs.Reserve(ec_id, mac)
def GenerateDRBDSecret(self, ec_id):
"""Generate a DRBD secret.
This checks the current disks for duplicates.
"""
return self._temporary_secrets.Generate(self._AllDRBDSecrets(),
utils.GenerateSecret,
ec_id)
def ReserveLV(self, lv_name, ec_id):
"""Reserve an VG/LV pair for an instance.
@type lv_name: string
@param lv_name: the logical volume name to reserve
"""
all_lvs = self._AllLVs()
if lv_name in all_lvs:
raise errors.ReservationError("LV already in use")
else:
self._temporary_lvs.Reserve(ec_id, lv_name)
def _UnlockedCommitTemporaryIps(self, ec_id):
"""Commit all reserved IP address to their respective pools
"""
for action, address, net_uuid in self._temporary_ips.GetECReserved(ec_id):
self._UnlockedCommitIp(action, net_uuid, address)
def _UnlockedCommitIp(self, action, net_uuid, address):
"""Commit a reserved IP address to an IP pool.
The IP address is taken from the network's IP pool and marked as reserved.
"""
nobj = self._UnlockedGetNetwork(net_uuid)
pool = AddressPool(nobj)
if action == RESERVE_ACTION:
pool.Reserve(address)
elif action == RELEASE_ACTION:
pool.Release(address)
def _UnlockedReleaseIp(self, net_uuid, address, ec_id):
"""Give a specific IP address back to an IP pool.
The IP address is returned to the IP pool designated by pool_id and marked
as reserved.
"""
self._temporary_ips.Reserve(ec_id,
(RELEASE_ACTION, address, net_uuid))
def ReleaseIp(self, net_uuid, address, ec_id):
"""Give a specified IP address back to an IP pool.
This is just a wrapper around _UnlockedReleaseIp.
"""
if net_uuid:
self._UnlockedReleaseIp(net_uuid, address, ec_id)
def GenerateIp(self, net_uuid, ec_id):
"""Find a free IPv4 address for an instance.
"""
nobj = self._UnlockedGetNetwork(net_uuid)
pool = AddressPool(nobj)
def gen_one():
try:
ip = pool.GenerateFree()
except errors.AddressPoolError:
raise errors.ReservationError("Cannot generate IP. Network is full")
return (RESERVE_ACTION, ip, net_uuid)
_, address, _ = self._temporary_ips.Generate([], gen_one, ec_id)
return address
def _UnlockedReserveIp(self, net_uuid, address, ec_id, check=True):
"""Reserve a given IPv4 address for use by an instance.
"""
nobj = self._UnlockedGetNetwork(net_uuid)
pool = AddressPool(nobj)
try:
isreserved = pool.IsReserved(address)
isextreserved = pool.IsReserved(address, external=True)
except errors.AddressPoolError:
raise errors.ReservationError("IP address not in network")
if isreserved:
raise errors.ReservationError("IP address already in use")
if check and isextreserved:
raise errors.ReservationError("IP is externally reserved")
return self._temporary_ips.Reserve(ec_id,
(RESERVE_ACTION,
address, net_uuid))
def ReserveIp(self, net_uuid, address, ec_id, check=True):
"""Reserve a given IPv4 address for use by an instance.
"""
if net_uuid:
return self._UnlockedReserveIp(net_uuid, address, ec_id, check)
def AddInstance(self, instance, ec_id, replace=False):
"""Add an instance to the config.
"""
instance.serial_no = 1
instance.ctime = instance.mtime = time.time()
self._ConfigData().instances[instance.uuid] = instance
self._ConfigData().cluster.serial_no += 1 # pylint: disable=E1103
self.ReleaseDRBDMinors(instance.uuid)
self._UnlockedCommitTemporaryIps(ec_id)
def _UnlockedAddDisk(self, disk):
disk.UpgradeConfig()
self._ConfigData().disks[disk.uuid] = disk
self._ConfigData().cluster.serial_no += 1 # pylint: disable=E1103
self.ReleaseDRBDMinors(disk.uuid)
def _UnlockedAttachInstanceDisk(self, inst_uuid, disk_uuid, idx=None):
instance = self._UnlockedGetInstanceInfo(inst_uuid)
if idx is None:
idx = len(instance.disks)
instance.disks.insert(idx, disk_uuid)
instance_disks = self._UnlockedGetInstanceDisks(inst_uuid)
for (disk_idx, disk) in enumerate(instance_disks[idx:]):
disk.iv_name = "disk/%s" % (idx + disk_idx)
instance.serial_no += 1
instance.mtime = time.time()
def AddInstanceDisk(self, inst_uuid, disk, idx=None, replace=False):
self._UnlockedAddDisk(disk)
self._UnlockedAttachInstanceDisk(inst_uuid, disk.uuid, idx)
def AttachInstanceDisk(self, inst_uuid, disk_uuid, idx=None):
self._UnlockedAttachInstanceDisk(inst_uuid, disk_uuid, idx)
def GetDisk(self, disk_uuid):
"""Retrieves a disk object if present.
"""
return self._ConfigData().disks[disk_uuid]
def AllocatePort(self):
return 1
def Update(self, target, feedback_fn, ec_id=None):
def replace_in(target, tdict):
tdict[target.uuid] = target
update_serial = False
if isinstance(target, objects.Cluster):
self._ConfigData().cluster = target
elif isinstance(target, objects.Node):
replace_in(target, self._ConfigData().nodes)
update_serial = True
elif isinstance(target, objects.Instance):
replace_in(target, self._ConfigData().instances)
elif isinstance(target, objects.NodeGroup):
replace_in(target, self._ConfigData().nodegroups)
elif isinstance(target, objects.Network):
replace_in(target, self._ConfigData().networks)
elif isinstance(target, objects.Disk):
replace_in(target, self._ConfigData().disks)
target.serial_no += 1
target.mtime = now = time.time()
if update_serial:
self._ConfigData().cluster.serial_no += 1 # pylint: disable=E1103
self._ConfigData().cluster.mtime = now
def SetInstancePrimaryNode(self, inst_uuid, target_node_uuid):
self._UnlockedGetInstanceInfo(inst_uuid).primary_node = target_node_uuid
def _SetInstanceStatus(self, inst_uuid, status,
disks_active, admin_state_source):
if inst_uuid not in self._ConfigData().instances:
raise errors.ConfigurationError("Unknown instance '%s'" %
inst_uuid)
instance = self._ConfigData().instances[inst_uuid]
if status is None:
status = instance.admin_state
if disks_active is None:
disks_active = instance.disks_active
if admin_state_source is None:
admin_state_source = instance.admin_state_source
assert status in constants.ADMINST_ALL, \
"Invalid status '%s' passed to SetInstanceStatus" % (status,)
if instance.admin_state != status or \
instance.disks_active != disks_active or \
instance.admin_state_source != admin_state_source:
instance.admin_state = status
instance.disks_active = disks_active
instance.admin_state_source = admin_state_source
instance.serial_no += 1
instance.mtime = time.time()
return instance
def _UnlockedDetachInstanceDisk(self, inst_uuid, disk_uuid):
"""Detach a disk from an instance.
@type inst_uuid: string
@param inst_uuid: The UUID of the instance object
@type disk_uuid: string
@param disk_uuid: The UUID of the disk object
"""
instance = self._UnlockedGetInstanceInfo(inst_uuid)
if instance is None:
raise errors.ConfigurationError("Instance %s doesn't exist"
% inst_uuid)
if disk_uuid not in self._ConfigData().disks:
raise errors.ConfigurationError("Disk %s doesn't exist" % disk_uuid)
# Check if disk is attached to the instance
if disk_uuid not in instance.disks:
raise errors.ProgrammerError("Disk %s is not attached to an instance"
% disk_uuid)
idx = instance.disks.index(disk_uuid)
instance.disks.remove(disk_uuid)
instance_disks = self._UnlockedGetInstanceDisks(inst_uuid)
_UpdateIvNames(idx, instance_disks[idx:])
instance.serial_no += 1
instance.mtime = time.time()
def DetachInstanceDisk(self, inst_uuid, disk_uuid):
self._UnlockedDetachInstanceDisk(inst_uuid, disk_uuid)
def RemoveInstanceDisk(self, inst_uuid, disk_uuid):
self._UnlockedDetachInstanceDisk(inst_uuid, disk_uuid)
self._UnlockedRemoveDisk(disk_uuid)
def RemoveInstance(self, inst_uuid):
del self._ConfigData().instances[inst_uuid]
def AddTcpUdpPort(self, port):
self._ConfigData().cluster.tcpudp_port_pool.add(port)