Signed-off-by: Chuck Short <chuck.short@canonical.com>
This commit is contained in:
Chuck Short 2015-01-18 20:50:27 -05:00
parent d1bf6e2e81
commit ae0e8eae4d
7 changed files with 97 additions and 61 deletions

View File

@ -15,7 +15,9 @@
import json import json
import requests import requests
class Client(object): class Client(object):
def __init__(self, host, cert, key): def __init__(self, host, cert, key):
self.host = host self.host = host
self.cert = cert self.cert = cert
@ -33,7 +35,7 @@ class Client(object):
cert=(self.cert, self.key), verify=False) cert=(self.cert, self.key), verify=False)
def _delete(self, path): def _delete(self, path):
return requests.delete(self._url(path), return requests.delete(self._url(path),
cert=(self.cert, self.key), verify=False) cert=(self.cert, self.key), verify=False)
def defined(self, name): def defined(self, name):
@ -63,7 +65,7 @@ class Client(object):
def start(self, name): def start(self, name):
container_start = False container_start = False
if self.defined(name): if self.defined(name):
params = {'action':'start'} params = {'action': 'start'}
response = self._put('/1.0/containers/%s/state' % name, params) response = self._put('/1.0/containers/%s/state' % name, params)
if response.status_code == 200: if response.status_code == 200:
container_start = True container_start = True
@ -72,7 +74,7 @@ class Client(object):
def stop(self, name): def stop(self, name):
container_stop = False container_stop = False
if self.defined(name): if self.defined(name):
params = {'action':'start'} params = {'action': 'start'}
response = self._put('/1.0/containers/%s/state' % name, params) response = self._put('/1.0/containers/%s/state' % name, params)
if response.status_code == 200: if response.status_code == 200:
container_stop = True container_stop = True

View File

@ -24,14 +24,18 @@ from nova import utils
CONF = cfg.CONF CONF = cfg.CONF
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class LXDConfigObject(object): class LXDConfigObject(object):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(LXDConfigObject, self).__init__() super(LXDConfigObject, self).__init__()
def set_config(self): def set_config(self):
pass pass
class LXDConfigTemplate(LXDConfigObject): class LXDConfigTemplate(LXDConfigObject):
def __init__(self, instance, image_meta): def __init__(self, instance, image_meta):
super(LXDConfigTemplate, self).__init__() super(LXDConfigTemplate, self).__init__()
self.instance = instance self.instance = instance
@ -40,7 +44,7 @@ class LXDConfigTemplate(LXDConfigObject):
def set_config(self): def set_config(self):
templates = [] templates = []
if (self.image_meta and if (self.image_meta and
self.image_meta.get('properties', {}).get('template')): self.image_meta.get('properties', {}).get('template')):
lxc_template = self.image_meta['properties'].get('template') lxc_template = self.image_meta['properties'].get('template')
else: else:
lxc_template = CONF.lxd.lxd_default_template lxc_template = CONF.lxd.lxd_default_template
@ -51,16 +55,19 @@ class LXDConfigTemplate(LXDConfigObject):
if lxc_template in templates: if lxc_template in templates:
config_file = os.path.join(CONF.lxd.lxd_root_dir, config_file = os.path.join(CONF.lxd.lxd_root_dir,
self.instance, 'config') self.instance, 'config')
f = open(config_file, 'w') f = open(config_file, 'w')
f.write('lxc.include = %s/%s.common.conf\n' % (CONF.lxd.lxd_config_dir, f.write('lxc.include = %s/%s.common.conf\n'
lxc_template)) % (CONF.lxd.lxd_config_dir,
f.write('lxc.include = %s/%s.userns.conf\n' % (CONF.lxd.lxd_config_dir, lxc_template))
lxc_template)) f.write('lxc.include = %s/%s.userns.conf\n'
% (CONF.lxd.lxd_config_dir,
lxc_template))
class LXDConfigSetName(LXDConfigObject): class LXDConfigSetName(LXDConfigObject):
def __init__(self, container, instance): def __init__(self, container, instance):
super(LXDConfigSetName, self).__init__() super(LXDConfigSetName, self).__init__()
self.container = container self.container = container
@ -70,7 +77,9 @@ class LXDConfigSetName(LXDConfigObject):
self.container.append_config_item('lxc.utsname', self.container.append_config_item('lxc.utsname',
self.instance) self.instance)
class LXDConfigSetRoot(LXDConfigObject): class LXDConfigSetRoot(LXDConfigObject):
def __init__(self, container, instance): def __init__(self, container, instance):
super(LXDConfigSetRoot, self).__init__() super(LXDConfigSetRoot, self).__init__()
self.container = container self.container = container
@ -83,7 +92,9 @@ class LXDConfigSetRoot(LXDConfigObject):
self.container.append_config_item('lxc.rootfs', self.container.append_config_item('lxc.rootfs',
self.container_rootfs) self.container_rootfs)
class LXDConfigSetLog(LXDConfigObject): class LXDConfigSetLog(LXDConfigObject):
def __init__(self, container, instance): def __init__(self, container, instance):
super(LXDConfigSetLog, self).__init__() super(LXDConfigSetLog, self).__init__()
self.container = container self.container = container
@ -96,7 +107,9 @@ class LXDConfigSetLog(LXDConfigObject):
self.container.append_config_item('lxc.logfile', self.container.append_config_item('lxc.logfile',
container_logfile) container_logfile)
class LXDConfigConsole(LXDConfigObject): class LXDConfigConsole(LXDConfigObject):
def __init__(self, container, instance): def __init__(self, container, instance):
super(LXDConfigConsole, self).__init__() super(LXDConfigConsole, self).__init__()
self.container = container self.container = container
@ -112,6 +125,7 @@ class LXDConfigConsole(LXDConfigObject):
class LXDUserConfig(LXDConfigObject): class LXDUserConfig(LXDConfigObject):
def __init__(self, container, idmap): def __init__(self, container, idmap):
super(LXDUserConfig, self).__init__() super(LXDUserConfig, self).__init__()
self.container = container self.container = container
@ -121,7 +135,9 @@ class LXDUserConfig(LXDConfigObject):
for ent in self.idmap.lxc_conf_lines(): for ent in self.idmap.lxc_conf_lines():
self.container.append_config_item(*ent) self.container.append_config_item(*ent)
class LXDSetLimits(LXDConfigObject): class LXDSetLimits(LXDConfigObject):
def __init__(self, container, instance): def __init__(self, container, instance):
super(LXDSetLimits, self).__init__() super(LXDSetLimits, self).__init__()
self.container = container self.container = container
@ -132,4 +148,3 @@ class LXDSetLimits(LXDConfigObject):
self.container.append_config_item( self.container.append_config_item(
'lxc.cgroup.memory.limit_in_bytes', 'lxc.cgroup.memory.limit_in_bytes',
'%sM' % flavor.memory_mb) '%sM' % flavor.memory_mb)

View File

@ -43,10 +43,13 @@ LOG = logging.getLogger(__name__)
MAX_CONSOLE_BYTES = 100 * units.Ki MAX_CONSOLE_BYTES = 100 * units.Ki
def get_container_dir(instance): def get_container_dir(instance):
return os.path.join(CONF.lxd.lxd_root_dir, instance) return os.path.join(CONF.lxd.lxd_root_dir, instance)
class Container(object): class Container(object):
def __init__(self, client, virtapi, firewall): def __init__(self, client, virtapi, firewall):
self.client = client self.client = client
self.virtapi = virtapi self.virtapi = virtapi
@ -83,7 +86,7 @@ class Container(object):
return log_data return log_data
def start_container(self, context, instance, image_meta, injected_files, def start_container(self, context, instance, image_meta, injected_files,
admin_password, network_info, block_device_info, flavor): admin_password, network_info, block_device_info, flavor):
LOG.info(_LI('Starting new instance'), instance=instance) LOG.info(_LI('Starting new instance'), instance=instance)
self.container = lxc.Container(instance['uuid']) self.container = lxc.Container(instance['uuid'])
@ -105,21 +108,27 @@ class Container(object):
fileutils.ensure_tree(self.base_dir) fileutils.ensure_tree(self.base_dir)
def _fetch_image(self, context, instance): def _fetch_image(self, context, instance):
container_image = os.path.join(self.base_dir, '%s.tar.gz' % instance['image_ref']) container_image = os.path.join(
self.base_dir, '%s.tar.gz' % instance['image_ref'])
if not os.path.exists(container_image): if not os.path.exists(container_image):
images.fetch_to_raw(context, instance['image_ref'], container_image, images.fetch_to_raw(
context, instance['image_ref'], container_image,
instance['user_id'], instance['project_id']) instance['user_id'], instance['project_id'])
if not tarfile.is_tarfile(container_image): if not tarfile.is_tarfile(container_image):
raise exception.NovaException(_('Not an valid image')) raise exception.NovaException(_('Not an valid image'))
if CONF.use_cow_images: if CONF.use_cow_images:
root_dir = os.path.join(get_container_dir(instance['uuid']), 'rootfs') root_dir = os.path.join(
self.image = image.ContainerCoW(container_image, instance, root_dir, self.base_dir) get_container_dir(instance['uuid']), 'rootfs')
self.image = image.ContainerCoW(
container_image, instance, root_dir, self.base_dir)
else: else:
root_dir = fileutils.ensure_tree(os.path.join(get_container_dir(instance['uuid']), root_dir = fileutils.ensure_tree(
'rootfs')) os.path.join(get_container_dir(instance['uuid']),
self.image = image.ContainerLocal(container_image, instance, root_dir) 'rootfs'))
self.image = image.ContainerLocal(
container_image, instance, root_dir)
self.image.create_container() self.image.create_container()
@ -194,6 +203,6 @@ class Container(object):
def _neutron_failed_callback(self, event_name, instance): def _neutron_failed_callback(self, event_name, instance):
LOG.error(_LE('Neutron Reported failure on event ' LOG.error(_LE('Neutron Reported failure on event '
'%(event)s for instance %(uuid)s'), '%(event)s for instance %(uuid)s'),
{'event': event_name, 'uuid': instance.uuid}) {'event': event_name, 'uuid': instance.uuid})
if CONF.vif_plugging_is_fatal: if CONF.vif_plugging_is_fatal:
raise exception.VirtualInterfaceCreateException() raise exception.VirtualInterfaceCreateException()

View File

@ -53,8 +53,8 @@ from . import host_utils
lxd_opts = [ lxd_opts = [
cfg.StrOpt('lxd_client_cert', cfg.StrOpt('lxd_client_cert',
default='/etc/lxd/client.crt', default='/etc/lxd/client.crt',
help='LXD client certificate'), help='LXD client certificate'),
cfg.StrOpt('lxd_client_key', cfg.StrOpt('lxd_client_key',
default='/etc/lxd/client.key', default='/etc/lxd/client.key',
help='LXD client key'), help='LXD client key'),
@ -62,18 +62,18 @@ lxd_opts = [
default='127.0.0.1:8443', default='127.0.0.1:8443',
help='LXD API Server'), help='LXD API Server'),
cfg.StrOpt('lxd_root_dir', cfg.StrOpt('lxd_root_dir',
default='/var/lib/lxd/lxc', default='/var/lib/lxd/lxc',
help='Default LXD directory'), help='Default LXD directory'),
cfg.StrOpt('lxd_default_template', cfg.StrOpt('lxd_default_template',
default='ubuntu-cloud', default='ubuntu-cloud',
help='Default LXC template'), help='Default LXC template'),
cfg.StrOpt('lxd_template_dir', cfg.StrOpt('lxd_template_dir',
default='/usr/share/lxc/templates', default='/usr/share/lxc/templates',
help='Default template directory'), help='Default template directory'),
cfg.StrOpt('lxd_config_dir', cfg.StrOpt('lxd_config_dir',
default='/usr/share/lxc/config', default='/usr/share/lxc/config',
help='Default lxc config dir') help='Default lxc config dir')
] ]
CONF = cfg.CONF CONF = cfg.CONF
@ -82,11 +82,12 @@ CONF.import_opt('host', 'nova.netconf')
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class LXDDriver(driver.ComputeDriver): class LXDDriver(driver.ComputeDriver):
capabilities = { capabilities = {
"has_imagecache": False, "has_imagecache": False,
"supports_recreate": False, "supports_recreate": False,
} }
"""LXD hypervisor driver.""" """LXD hypervisor driver."""
@ -135,26 +136,22 @@ class LXDDriver(driver.ComputeDriver):
def poll_rebooting_instances(self, timeout, instances): def poll_rebooting_instances(self, timeout, instances):
raise NotImplemented() raise NotImplemented()
def migrate_disk_and_power_off(self, context, instance, dest, def migrate_disk_and_power_off(self, context, instance, dest,
flavor, network_info, flavor, network_info,
block_device_info=None, block_device_info=None,
timeout=0, retry_interval=0): timeout=0, retry_interval=0):
raise NotImplemented() raise NotImplemented()
def finish_revert_migration(self, context, instance, network_info, def finish_revert_migration(self, context, instance, network_info,
block_device_info=None, power_on=True): block_device_info=None, power_on=True):
raise NotImplemented() raise NotImplemented()
def post_live_migration_at_destination(self, context, instance, def post_live_migration_at_destination(self, context, instance,
network_info, network_info,
block_migration=False, block_migration=False,
block_device_info=None): block_device_info=None):
raise NotImplemented() raise NotImplemented()
def power_off(self, instance, shutdown_timeout=0, shutdown_attempts=0): def power_off(self, instance, shutdown_timeout=0, shutdown_attempts=0):
self.client.stop(instance['uuid']) self.client.stop(instance['uuid'])
@ -210,11 +207,11 @@ class LXDDriver(driver.ComputeDriver):
raise NotImplemented() raise NotImplemented()
def get_info(self, instance): def get_info(self, instance):
if self.client.running(instance['uuid']): if self.client.running(instance['uuid']):
pstate = power_state.RUNNING pstate = power_state.RUNNING
else: else:
pstate = power_state.SHUTDOWN pstate = power_state.SHUTDOWN
return hardware.InstanceInfo(state=pstate, return hardware.InstanceInfo(state=pstate,
max_mem_kb=0, max_mem_kb=0,
mem_kb=0, mem_kb=0,
num_cpu=2, num_cpu=2,
@ -233,7 +230,7 @@ class LXDDriver(driver.ComputeDriver):
self.firewall_driver.refresh_rules(instance) self.firewall_driver.refresh_rules(instance)
def refresh_provider_fw_rules(self): def refresh_provider_fw_rules(self):
self.firewall_driver.refresh_provider_fw_rules() self.firewall_driver.refresh_provider_fw_rules()
def get_available_resource(self, nodename): def get_available_resource(self, nodename):
"""Updates compute manager resource info on ComputeNode table. """Updates compute manager resource info on ComputeNode table.
@ -253,7 +250,7 @@ class LXDDriver(driver.ComputeDriver):
data["local_gb"] = disk['total'] / units.Gi data["local_gb"] = disk['total'] / units.Gi
data["vcpus_used"] = 1 data["vcpus_used"] = 1
data["memory_mb_used"] = memory['used'] / units.Mi data["memory_mb_used"] = memory['used'] / units.Mi
data["local_gb_used"] = disk['used'] / units.Gi data["local_gb_used"] = disk['used'] / units.Gi
data["hypervisor_type"] = "lxd" data["hypervisor_type"] = "lxd"
data["hypervisor_version"] = "1.0" data["hypervisor_version"] = "1.0"
data["hypervisor_hostname"] = nodename data["hypervisor_hostname"] = nodename
@ -265,7 +262,8 @@ class LXDDriver(driver.ComputeDriver):
def ensure_filtering_rules_for_instance(self, instance_ref, network_info): def ensure_filtering_rules_for_instance(self, instance_ref, network_info):
self.firewall_driver.setup_basic_filtering(instance_ref, network_info) self.firewall_driver.setup_basic_filtering(instance_ref, network_info)
self.firewall_driver.prepare_instance_filter(instance_ref, network_info) self.firewall_driver.prepare_instance_filter(
instance_ref, network_info)
def unfilter_instance(self, instance, network_info): def unfilter_instance(self, instance, network_info):
self.firewall_driver.unfilter_instance(instance, network_info) self.firewall_driver.unfilter_instance(instance, network_info)
@ -273,5 +271,3 @@ class LXDDriver(driver.ComputeDriver):
def get_available_nodes(self, refresh=False): def get_available_nodes(self, refresh=False):
hostname = socket.gethostname() hostname = socket.gethostname()
return [hostname] return [hostname]

View File

@ -14,6 +14,7 @@
import os import os
def get_fs_info(path): def get_fs_info(path):
"""get free/used/total space info for a filesystem """get free/used/total space info for a filesystem
@ -32,6 +33,7 @@ def get_fs_info(path):
'free': free, 'free': free,
'used': used} 'used': used}
def get_memory_mb_usage(): def get_memory_mb_usage():
"""Get the used memory size(MB) of the host. """Get the used memory size(MB) of the host.
@ -44,7 +46,7 @@ def get_memory_mb_usage():
idx2 = m.index('MemFree:') idx2 = m.index('MemFree:')
idx3 = m.index('Buffers:') idx3 = m.index('Buffers:')
idx4 = m.index('Cached:') idx4 = m.index('Cached:')
total = int(m[idx1 + 1]) total = int(m[idx1 + 1])
avail = int(m[idx2 + 1]) + int(m[idx3 + 1]) + int(m[idx4 + 1]) avail = int(m[idx2 + 1]) + int(m[idx3 + 1]) + int(m[idx4 + 1])

View File

@ -22,6 +22,7 @@ from . import utils as container_utils
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
def write_image(idmap, image, root_dir): def write_image(idmap, image, root_dir):
tar = ['tar', '--directory', root_dir, tar = ['tar', '--directory', root_dir,
'--anchored', '--numeric-owner', '-xpzf', image] '--anchored', '--numeric-owner', '-xpzf', image]
@ -31,7 +32,9 @@ def write_image(idmap, image, root_dir):
args = tuple(nsexec + tar) args = tuple(nsexec + tar)
utils.execute(*args, check_exit_code=[0, 2]) utils.execute(*args, check_exit_code=[0, 2])
class ContainerImage(object): class ContainerImage(object):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(ContainerImage, self).__init__() super(ContainerImage, self).__init__()
@ -41,7 +44,9 @@ class ContainerImage(object):
def remove_contianer(self): def remove_contianer(self):
pass pass
class ContainerLocal(ContainerImage): class ContainerLocal(ContainerImage):
def __init__(self, image, instance, root_dir): def __init__(self, image, instance, root_dir):
super(ContainerLocal, self).__init__() super(ContainerLocal, self).__init__()
self.image = image self.image = image
@ -53,13 +58,15 @@ class ContainerLocal(ContainerImage):
def create_container(self): def create_container(self):
(user, group) = self.idmap.get_user() (user, group) = self.idmap.get_user()
utils.execute('chown', '%s:%s' % (user, group), self.root_dir, utils.execute('chown', '%s:%s' % (user, group), self.root_dir,
run_as_root=True) run_as_root=True)
write_image(self.idmap, self.image, self.root_dir) write_image(self.idmap, self.image, self.root_dir)
def remove_container(self): def remove_container(self):
pass pass
class ContainerCoW(ContainerImage): class ContainerCoW(ContainerImage):
def __init__(self, image, instance, root_dir, base_dir): def __init__(self, image, instance, root_dir, base_dir):
super(ContainerCoW, self).__init__() super(ContainerCoW, self).__init__()
self.idmap = container_utils.LXCUserIdMap() self.idmap = container_utils.LXCUserIdMap()

View File

@ -48,9 +48,10 @@ def write_lxc_config(instance, vif):
bridge = vif['network']['bridge'] bridge = vif['network']['bridge']
f.write('lxc.network.link = %s\n' % bridge) f.write('lxc.network.link = %s\n' % bridge)
class LXDGenericDriver(object): class LXDGenericDriver(object):
def _get_vif_driver(self, vif): def _get_vif_driver(self, vif):
vif_type = vif['type'] vif_type = vif['type']
if vif_type is None: if vif_type is None:
@ -70,7 +71,9 @@ class LXDGenericDriver(object):
vif_driver = self._get_vif_driver(vif) vif_driver = self._get_vif_driver(vif)
vif_driver.unplug(instance, vif) vif_driver.unplug(instance, vif)
class LXDOpenVswitchDriver(object): class LXDOpenVswitchDriver(object):
def plug(self, instance, vif): def plug(self, instance, vif):
iface_id = self._get_ovs_interfaceid(vif) iface_id = self._get_ovs_interfaceid(vif)
br_name = self._get_br_name(vif['id']) br_name = self._get_br_name(vif['id'])
@ -81,11 +84,11 @@ class LXDOpenVswitchDriver(object):
utils.execute('brctl', 'setfd', br_name, 0, run_as_root=True) utils.execute('brctl', 'setfd', br_name, 0, run_as_root=True)
utils.execute('brctl', 'stp', br_name, 'off', run_as_root=True) utils.execute('brctl', 'stp', br_name, 'off', run_as_root=True)
utils.execute('tee', utils.execute('tee',
('/sys/class/net/%s/bridge/multicast_snooping' % ('/sys/class/net/%s/bridge/multicast_snooping' %
br_name), br_name),
process_input='0', process_input='0',
run_as_root=True, run_as_root=True,
check_exit_code=[0, 1]) check_exit_code=[0, 1])
if not linux_net.device_exists(v2_name): if not linux_net.device_exists(v2_name):
linux_net._create_veth_pair(v1_name, v2_name) linux_net._create_veth_pair(v1_name, v2_name)
@ -115,7 +118,7 @@ class LXDOpenVswitchDriver(object):
v2_name) v2_name)
except processutils.ProcessExecutionError: except processutils.ProcessExecutionError:
LOG.exception(_("Failed while unplugging vif"), LOG.exception(_("Failed while unplugging vif"),
instance=instance) instance=instance)
def _get_bridge_name(self, vif): def _get_bridge_name(self, vif):
return vif['network']['bridge'] return vif['network']['bridge']
@ -130,22 +133,24 @@ class LXDOpenVswitchDriver(object):
return (("qvb%s" % iface_id)[:network_model.NIC_NAME_LEN], return (("qvb%s" % iface_id)[:network_model.NIC_NAME_LEN],
("qvo%s" % iface_id)[:network_model.NIC_NAME_LEN]) ("qvo%s" % iface_id)[:network_model.NIC_NAME_LEN])
class LXDNetworkBridgeDriver(object): class LXDNetworkBridgeDriver(object):
def plug(self, container, instance, vif): def plug(self, container, instance, vif):
network = vif['network'] network = vif['network']
if (not network.get_meta('multi_host', False) and if (not network.get_meta('multi_host', False) and
network.get_meta('should_create_bridge', False)): network.get_meta('should_create_bridge', False)):
if network.get_meta('should_create_vlan', False): if network.get_meta('should_create_vlan', False):
iface = CONF.vlan_interface or \ iface = CONF.vlan_interface or \
network.get_meta('bridge_interface') network.get_meta('bridge_interface')
LOG.debug('Ensuring vlan %(vlan)s and bridge %(bridge)s', LOG.debug('Ensuring vlan %(vlan)s and bridge %(bridge)s',
{'vlan': network.get_meta('vlan'), {'vlan': network.get_meta('vlan'),
'bridge': vif['network']['bridge']}, 'bridge': vif['network']['bridge']},
instance=instance) instance=instance)
linux_net.LinuxBridgeInterfaceDriver.ensure_vlan_bridge( linux_net.LinuxBridgeInterfaceDriver.ensure_vlan_bridge(
network.get_meta('vlan'), network.get_meta('vlan'),
vif['network']['bridge'], vif['network']['bridge'],
iface) iface)
else: else:
iface = CONF.flat_interface or \ iface = CONF.flat_interface or \
network.get_meta('bridge_interface') network.get_meta('bridge_interface')