301 lines
12 KiB
Python
301 lines
12 KiB
Python
"""
|
|
xenconfig.py: Implementation of the XenConfigManager class for managing
|
|
configurable items for XenNodes.
|
|
|
|
Configuration for a XenNode is available at these three levels:
|
|
Global config: XenConfigManager.configs[0] = (type="xen", values)
|
|
Nodes of this machine type have this config. These are the default values.
|
|
XenConfigManager.default_config comes from defaults + xen.conf
|
|
Node type config: XenConfigManager.configs[0] = (type="mytype", values)
|
|
All nodes of this type have this config.
|
|
Node-specific config: XenConfigManager.configs[nodenumber] = (type, values)
|
|
The node having this specific number has this config.
|
|
"""
|
|
|
|
import ConfigParser
|
|
import os
|
|
import string
|
|
|
|
from core import constants
|
|
from core import logger
|
|
from core.api import coreapi
|
|
from core.conf import Configurable
|
|
from core.conf import ConfigurableManager
|
|
from core.enumerations import ConfigDataTypes
|
|
from core.enumerations import ConfigFlags
|
|
from core.enumerations import ConfigTlvs
|
|
from core.enumerations import RegisterTlvs
|
|
|
|
|
|
class XenConfigManager(ConfigurableManager):
|
|
"""
|
|
Xen controller object. Lives in a Session instance and is used for
|
|
building Xen profiles.
|
|
"""
|
|
name = "xen"
|
|
config_type = RegisterTlvs.EMULATION_SERVER.value
|
|
|
|
def __init__(self, session):
|
|
"""
|
|
Creates a XenConfigManager instance.
|
|
|
|
:param core.session.Session session: session this manager is tied to
|
|
:return: nothing
|
|
"""
|
|
ConfigurableManager.__init__(self)
|
|
self.default_config = XenDefaultConfig(session, object_id=None)
|
|
self.loadconfigfile()
|
|
|
|
def setconfig(self, nodenum, conftype, values):
|
|
"""
|
|
Add configuration values for a node to a dictionary; values are
|
|
usually received from a Configuration Message, and may refer to a
|
|
node for which no object exists yet
|
|
|
|
:param int nodenum: node id to configure
|
|
:param str conftype: configuration type
|
|
:param tuple values: values to configure
|
|
:return: None
|
|
"""
|
|
# used for storing the global default config
|
|
if nodenum is None:
|
|
nodenum = 0
|
|
return ConfigurableManager.setconfig(self, nodenum, conftype, values)
|
|
|
|
def getconfig(self, nodenum, conftype, defaultvalues):
|
|
"""
|
|
Get configuration values for a node; if the values don"t exist in
|
|
our dictionary then return the default values supplied; if conftype
|
|
is None then we return a match on any conftype.
|
|
|
|
:param int nodenum: node id to configure
|
|
:param str conftype: configuration type
|
|
:param tuple defaultvalues: default values to return
|
|
:return: configuration for node and config type
|
|
:rtype: tuple
|
|
"""
|
|
# used for storing the global default config
|
|
if nodenum is None:
|
|
nodenum = 0
|
|
return ConfigurableManager.getconfig(self, nodenum, conftype, defaultvalues)
|
|
|
|
def clearconfig(self, nodenum):
|
|
"""
|
|
Remove configuration values for a node
|
|
|
|
:param int nodenum: node id to clear config
|
|
:return: nothing
|
|
"""
|
|
ConfigurableManager.clearconfig(self, nodenum)
|
|
if 0 in self.configs:
|
|
self.configs.pop(0)
|
|
|
|
def configure(self, session, config_data):
|
|
"""
|
|
Handle configuration messages for global Xen config.
|
|
|
|
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
"""
|
|
return self.default_config.configure(self, config_data)
|
|
|
|
def loadconfigfile(self, filename=None):
|
|
"""
|
|
Load defaults from the /etc/core/xen.conf file into dict object.
|
|
|
|
:param str filename: file name of configuration to load
|
|
:return: nothing
|
|
"""
|
|
if filename is None:
|
|
filename = os.path.join(constants.CORE_CONF_DIR, "xen.conf")
|
|
cfg = ConfigParser.SafeConfigParser()
|
|
if filename not in cfg.read(filename):
|
|
logger.warn("unable to read Xen config file: %s", filename)
|
|
return
|
|
section = "xen"
|
|
if not cfg.has_section(section):
|
|
logger.warn("%s is missing a xen section!", filename)
|
|
return
|
|
self.configfile = dict(cfg.items(section))
|
|
# populate default config items from config file entries
|
|
vals = list(self.default_config.getdefaultvalues())
|
|
names = self.default_config.getnames()
|
|
for i in range(len(names)):
|
|
if names[i] in self.configfile:
|
|
vals[i] = self.configfile[names[i]]
|
|
# this sets XenConfigManager.configs[0] = (type="xen", vals)
|
|
self.setconfig(None, self.default_config.name, vals)
|
|
|
|
def getconfigitem(self, name, model=None, node=None, value=None):
|
|
"""
|
|
Get a config item of the given name, first looking for node-specific
|
|
configuration, then model specific, and finally global defaults.
|
|
If a value is supplied, it will override any stored config.
|
|
|
|
:param str name: name of config item to get
|
|
:param model: model config to get
|
|
:param node: node config to get
|
|
:param value: value to override stored config, if provided
|
|
:return: nothing
|
|
"""
|
|
if value is not None:
|
|
return value
|
|
n = None
|
|
if node:
|
|
n = node.objid
|
|
(t, v) = self.getconfig(nodenum=n, conftype=model, defaultvalues=None)
|
|
if n is not None and v is None:
|
|
# get item from default config for the node type
|
|
(t, v) = self.getconfig(nodenum=None, conftype=model, defaultvalues=None)
|
|
if v is None:
|
|
# get item from default config for the machine type
|
|
(t, v) = self.getconfig(nodenum=None, conftype=self.default_config.name, defaultvalues=None)
|
|
|
|
confignames = self.default_config.getnames()
|
|
if v and name in confignames:
|
|
i = confignames.index(name)
|
|
return v[i]
|
|
else:
|
|
# name may only exist in config file
|
|
if name in self.configfile:
|
|
return self.configfile[name]
|
|
else:
|
|
# logger.warn("missing config item "%s"" % name)
|
|
return None
|
|
|
|
|
|
class XenConfig(Configurable):
|
|
"""
|
|
Manage Xen configuration profiles.
|
|
"""
|
|
|
|
@classmethod
|
|
def configure(cls, xen, config_data):
|
|
"""
|
|
Handle configuration messages for setting up a model.
|
|
Similar to Configurable.configure(), but considers opaque data
|
|
for indicating node types.
|
|
|
|
:param xen: xen instance to configure
|
|
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
"""
|
|
reply = None
|
|
node_id = config_data.node
|
|
object_name = config_data.object
|
|
config_type = config_data.type
|
|
opaque = config_data.opaque
|
|
values_str = config_data.data_values
|
|
|
|
nodetype = object_name
|
|
if opaque is not None:
|
|
opaque_items = opaque.split(":")
|
|
if len(opaque_items) != 2:
|
|
logger.warn("xen config: invalid opaque data in conf message")
|
|
return None
|
|
nodetype = opaque_items[1]
|
|
|
|
logger.info("received configure message for %s", nodetype)
|
|
if config_type == ConfigFlags.REQUEST.value:
|
|
logger.info("replying to configure request for %s " % nodetype)
|
|
# when object name is "all", the reply to this request may be None
|
|
# if this node has not been configured for this model; otherwise we
|
|
# reply with the defaults for this model
|
|
if object_name == "all":
|
|
typeflags = ConfigFlags.UPDATE.value
|
|
else:
|
|
typeflags = ConfigFlags.NONE.value
|
|
values = xen.getconfig(node_id, nodetype, defaultvalues=None)[1]
|
|
if values is None:
|
|
# get defaults from default "xen" config which includes
|
|
# settings from both cls._confdefaultvalues and xen.conf
|
|
defaults = cls.getdefaultvalues()
|
|
values = xen.getconfig(node_id, cls.name, defaults)[1]
|
|
if values is None:
|
|
return None
|
|
# reply with config options
|
|
if node_id is None:
|
|
node_id = 0
|
|
reply = cls.config_data(0, node_id, typeflags, nodetype, values)
|
|
elif config_type == ConfigFlags.RESET.value:
|
|
if object_name == "all":
|
|
xen.clearconfig(node_id)
|
|
# elif conftype == coreapi.CONF_TYPE_FLAGS_UPDATE:
|
|
else:
|
|
# store the configuration values for later use, when the XenNode
|
|
# object has been created
|
|
if object_name is None:
|
|
logger.info("no configuration object for node %s" % node_id)
|
|
return None
|
|
if values_str is None:
|
|
# use default or preconfigured values
|
|
defaults = cls.getdefaultvalues()
|
|
values = xen.getconfig(node_id, cls.name, defaults)[1]
|
|
else:
|
|
# use new values supplied from the conf message
|
|
values = values_str.split("|")
|
|
xen.setconfig(node_id, nodetype, values)
|
|
|
|
return reply
|
|
|
|
@classmethod
|
|
def config_data(cls, flags, node_id, type_flags, nodetype, values):
|
|
"""
|
|
Convert this class to a Config API message. Some TLVs are defined
|
|
by the class, but node number, conf type flags, and values must
|
|
be passed in.
|
|
|
|
:param int flags: configuration flags
|
|
:param int node_id: node id
|
|
:param int type_flags: type flags
|
|
:param int nodetype: node type
|
|
:param tuple values: values
|
|
:return: configuration message
|
|
"""
|
|
values_str = string.join(values, "|")
|
|
tlvdata = ""
|
|
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.NODE.value, node_id)
|
|
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.OBJECT.value, cls.name)
|
|
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.TYPE.value, type_flags)
|
|
datatypes = tuple(map(lambda x: x[1], cls.config_matrix))
|
|
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.DATA_TYPES.value, datatypes)
|
|
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.VALUES.value, values_str)
|
|
captions = reduce(lambda a, b: a + "|" + b, map(lambda x: x[4], cls.config_matrix))
|
|
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.CAPTIONS, captions)
|
|
possiblevals = reduce(lambda a, b: a + "|" + b, map(lambda x: x[3], cls.config_matrix))
|
|
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.POSSIBLE_VALUES.value, possiblevals)
|
|
if cls.bitmap is not None:
|
|
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.BITMAP.value, cls.bitmap)
|
|
if cls.config_groups is not None:
|
|
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.GROUPS.value, cls.config_groups)
|
|
opaque = "%s:%s" % (cls.name, nodetype)
|
|
tlvdata += coreapi.CoreConfigTlv.pack(ConfigTlvs.OPAQUE.value, opaque)
|
|
msg = coreapi.CoreConfMessage.pack(flags, tlvdata)
|
|
return msg
|
|
|
|
|
|
class XenDefaultConfig(XenConfig):
|
|
"""
|
|
Global default Xen configuration options.
|
|
"""
|
|
name = "xen"
|
|
# Configuration items:
|
|
# ("name", "type", "default", "possible-value-list", "caption")
|
|
config_matrix = [
|
|
("ram_size", ConfigDataTypes.STRING.value, "256", "",
|
|
"ram size (MB)"),
|
|
("disk_size", ConfigDataTypes.STRING.value, "256M", "",
|
|
"disk size (use K/M/G suffix)"),
|
|
("iso_file", ConfigDataTypes.STRING.value, "", "",
|
|
"iso file"),
|
|
("mount_path", ConfigDataTypes.STRING.value, "", "",
|
|
"mount path"),
|
|
("etc_path", ConfigDataTypes.STRING.value, "", "",
|
|
"etc path"),
|
|
("persist_tar_iso", ConfigDataTypes.STRING.value, "", "",
|
|
"iso persist tar file"),
|
|
("persist_tar", ConfigDataTypes.STRING.value, "", "",
|
|
"persist tar file"),
|
|
("root_password", ConfigDataTypes.STRING.value, "password", "",
|
|
"root password"),
|
|
]
|
|
|
|
config_groups = "domU properties:1-%d" % len(config_matrix)
|