Misc fixes

Signed-off-by: Chuck Short <chuck.short@canonical.com>
This commit is contained in:
Chuck Short 2015-01-12 11:59:14 -05:00
parent c299f10b7e
commit 4012906bae
8 changed files with 157 additions and 99 deletions

View File

@ -0,0 +1 @@
__import__('pkg_resources').declare_namespace(__name__)

View File

@ -23,6 +23,10 @@ class Client(object):
return requests.put(self._url(path), data=json.dumps(data), return requests.put(self._url(path), data=json.dumps(data),
cert=(self.cert, self.key), verify=False) cert=(self.cert, self.key), verify=False)
def _delete(self, path):
return requests.delete(self._url(path),
cert=(self.cert, self.key), verify=False)
def defined(self, name): def defined(self, name):
container_exists = False container_exists = False
response = self._get('/1.0/containers/%s/state' % name) response = self._get('/1.0/containers/%s/state' % name)
@ -64,6 +68,34 @@ class Client(object):
if response.status_code == 200: if response.status_code == 200:
container_stop = True container_stop = True
return container_stop return container_stop
def pause(self, name):
container_pause = False
if self.defined(name):
params = {'action': 'freeze'}
response = self._put('/1.0/containers/%s/state' % name, params)
if response.status_code == 200:
container_pause = True
return container_pause
def resume(self, name):
container_unpause = False
if self.defined(name):
params = {'action': 'unfreeze'}
response = self._put('/1.0/containers/%s/state' % name, params)
if response.status_code == 200:
container_unpause = True
return container_unpause
def destory(self, name):
container_delete = False
if self.defined(name):
response = self._delete('/1.0/containers/%s' % name)
if response.status_code == 200:
container_delete = True
return container_delete
def list(self): def list(self):

View File

@ -106,3 +106,16 @@ class LXDUserConfig(LXDConfigObject):
def set_config(self): def set_config(self):
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):
def __init__(self, container, instance):
super(LXDSetLimits, self).__init__()
self.container = container
self.instance = instance
def set_config(self):
flavor = self.instance.get_flavor()
self.container.append_config_item(
'lxc.cgroup.memory.limit_in_bytes',
'%sM' % flavor.memory_mb)

View File

@ -1,17 +1,20 @@
import os import os
import grp
import pwd import pwd
import uuid
import lxc import lxc
import tarfile import tarfile
from oslo.config import cfg from oslo.config import cfg
from oslo.utils import importutils from oslo.utils import importutils, units
from nova.i18n import _, _LW, _LE, _LI from nova.i18n import _, _LW, _LE, _LI
from nova.openstack.common import fileutils from nova.openstack.common import fileutils
from nova.openstack.common import log as logging from nova.openstack.common import log as logging
from nova import utils from nova import utils
from nova.virt import images from nova.virt import images
from nova import objects
from nova import exception from nova import exception
from . import config from . import config
@ -22,36 +25,62 @@ CONF.import_opt('vif_plugging_timeout', 'nova.virt.driver')
CONF.import_opt('vif_plugging_is_fatal', 'nova.virt.driver') CONF.import_opt('vif_plugging_is_fatal', 'nova.virt.driver')
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
def get_container_rootfs(instance): MAX_CONSOLE_BYTES = 100 * units.Ki
return os.path.join(CONF.lxd_root_dir, instance, 'rootfs')
def get_container_dir(instance):
return os.path.join(CONF.lxd.lxd_root_dir, instance, 'rootfs')
class Container(object): class Container(object):
def __init__(self, client, virtapi): def __init__(self, client, virtapi, firewall):
self.client = client self.client = client
self.virtapi = virtapi self.virtapi = virtapi
self.firewall_driver = firewall
self.container = lxc.Container(instance['uuid']) self.container = None
self.container.set_config_path(CONF.lxd.lxd_root_dir)
self.idmap = LXCUserIdMap() self.idmap = LXCUserIdMap()
self.vif_driver = vif.LXDGenericDriver()
self.base_dir = os.path.join(CONF.instances_path, self.base_dir = os.path.join(CONF.instances_path,
CONF.image_cache_subdirectory_name) CONF.image_cache_subdirectory_name)
def start_container(self, context, instance, image_meta, network_info, block_device_info, flavor): def init_container(self):
lxc_cgroup = uuid.uuid4()
utils.execute('cgm', 'create', 'all', lxc_cgroup,
run_as_root=True)
utils.execute('cgm', 'chown', 'all', lxc_cgroup,
pwd.getpwuid(os.getuid()).pw_uid,
pwd.getpwuid(os.getuid()).pw_gid,
run_as_root=True)
utils.execute('cgm', 'movepid', 'all', lxc_cgroup, os.getpid())
def get_console_log(self, instance):
console_log = os.path.join(CONF.lxd.lxd_root_dir,
instance['uuid'],
'console.log')
with open(console_log, 'rb') as fp:
log_data, remaining = utils.last_bytes(fp, MAX_CONSOLE_BYTES)
if remaining > 0:
LOG.info(_LI('Truncated console log returned, '
'%d bytes ignored'),
remaining, instance=instance)
return log_data
def start_container(self, context, instance, image_meta, injected_files,
admin_password, network_info, block_device_info, flavor):
LOG.info(_LI('Starting new instance'), instance=instance) LOG.info(_LI('Starting new instance'), instance=instance)
instance_name = instance['uuid'] instance_name = instance['uuid']
try: self.container = lxc.Container(instance['uuid'])
''' Create the instance directories ''' self.container.set_config_path(CONF.lxd.lxd_root_dir)
self._create_container(instance_name)
''' Fetch the image from glance ''' ''' Create the instance directories '''
self._fetch_image(context, instance) self._create_container(instance_name)
''' Start the contianer ''' ''' Fetch the image from glance '''
self._start_container(instance, network_info, image_meta) self._fetch_image(context, instance)
except Exception:
LOG.error(_LE('Failed to spawn instance'), instance=instance) ''' Start the contianer '''
self._start_container(context, instance, network_info, image_meta)
def _create_container(self, instance): def _create_container(self, instance):
if not os.path.exists(get_container_dir(instance)): if not os.path.exists(get_container_dir(instance)):
@ -61,9 +90,9 @@ class Container(object):
def _fetch_image(self, context, instance): def _fetch_image(self, context, instance):
(user, group) = self.idmap.get_user() (user, group) = self.idmap.get_user()
image = os.path.join(self.base_dir, '%s.tar.gz' % instnce['image_ref']) image = os.path.join(self.base_dir, '%s.tar.gz' % instance['image_ref'])
if not os.path.exists(image): if not os.path.exists(image):
images.fetch_to_raw(context, instance['image_ref'], base, images.fetch_to_raw(context, instance['image_ref'], image,
instance['user_id'], instance['project_id']) instance['user_id'], instance['project_id'])
if not tarfile.is_tarfile(image): if not tarfile.is_tarfile(image):
raise exception.NovaException(_('Not an valid image')) raise exception.NovaException(_('Not an valid image'))
@ -74,7 +103,10 @@ class Container(object):
utils.execute('chown', '-R', '%s:%s' % (user, group), utils.execute('chown', '-R', '%s:%s' % (user, group),
get_container_dir(instance['uuid']), run_as_root=True) get_container_dir(instance['uuid']), run_as_root=True)
def _start_container(self, instance, network_info, image_meta): def _start_container(self, context, instance, network_info, image_meta):
with utils.temporary_mutation(context, read_deleted="yes"):
flavor = objects.Flavor.get_by_id(context,
instance['instance_type_id'])
timeout = CONF.vif_plugging_timeout timeout = CONF.vif_plugging_timeout
# check to see if neutron is ready before # check to see if neutron is ready before
# doing anything else # doing anything else
@ -88,13 +120,14 @@ class Container(object):
with self.virtapi.wait_for_instance_event( with self.virtapi.wait_for_instance_event(
instance, events, deadline=timeout, instance, events, deadline=timeout,
error_callback=self._neutron_failed_callback): error_callback=self._neutron_failed_callback):
self._write_config(instance, network_info, image_meta) self._write_config(instance, network_info, image_meta, flavor)
self._start_network(instance, network_info) self._start_network(instance, network_info)
self._start_firewall(instance, network_info)
self.client.start(instance['uuid']) self.client.start(instance['uuid'])
except exception.VirtualInterfaceCreateException: except exception.VirtualInterfaceCreateException:
LOG.info(_LW('Failed')) LOG.info(_LW('Failed'))
def _write_config(self, instance, network_info, image_meta): def _write_config(self, instance, network_info, image_meta, flavor):
template = config.LXDConfigTemplate(instance['uuid'], image_meta) template = config.LXDConfigTemplate(instance['uuid'], image_meta)
template.set_config() template.set_config()
@ -115,15 +148,27 @@ class Container(object):
idmap = config.LXDUserConfig(self.container, self.idmap) idmap = config.LXDUserConfig(self.container, self.idmap)
idmap.set_config() idmap.set_config()
limit = config.LXDSetLimits(self.container, instance)
limit.set_config()
self.container.save_config() self.container.save_config()
def _start_network(self, instance, network_info): def _start_network(self, instance, network_info):
for vif in network_info: for vif in network_info:
self.vif_driver.plug(instance, vif) self.vif_driver.plug(instance, vif)
def _teardown_network(self, instance, network_info): def teardown_network(self, instance, network_info):
for vif in network_info: for vif in network_info:
self.vif_driver.unplug(instancece, vif) self.vif_driver.unplug(instancece, vif)
self._stop_firewall(instance, network_info)
def _start_firewall(self, instance, network_info):
self.firewall_driver.setup_basic_filtering(instance, network_info)
self.firewall_driver.prepare_instance_filter(instance, network_info)
self.firewall_driver.apply_instance_filter(instance, network_info)
def _stop_firewall(self, instnce, network_inf):
self.firewall_driver.unfilter_instance(instance, network_info)
def _get_neutron_events(self, network_info): def _get_neutron_events(self, network_info):
return [('network-vif-plugged', vif['id']) return [('network-vif-plugged', vif['id'])

View File

@ -23,6 +23,9 @@ Nova LXD Driver
import socket import socket
import contextlib import contextlib
import psutil
from oslo.utils import units
from oslo.config import cfg from oslo.config import cfg
from oslo.serialization import jsonutils from oslo.serialization import jsonutils
@ -40,11 +43,13 @@ from nova.openstack.common import log as logging
from nova import utils from nova import utils
from nova.virt import diagnostics from nova.virt import diagnostics
from nova.virt import driver from nova.virt import driver
from nova.virt import firewall
from nova.virt import hardware from nova.virt import hardware
from nova.virt import virtapi from nova.virt import virtapi
from . import client from . import client
from . import container from . import container
from . import host_utils
lxd_opts = [ lxd_opts = [
cfg.StrOpt('lxd_client_cert', cfg.StrOpt('lxd_client_cert',
@ -54,7 +59,7 @@ lxd_opts = [
default='/etc/lxd/client.key', default='/etc/lxd/client.key',
help='LXD client key'), help='LXD client key'),
cfg.StrOpt('lxd_client_host', cfg.StrOpt('lxd_client_host',
default='10.5.0.10:8443', default='10.5.0.12: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',
@ -92,12 +97,15 @@ class LXDDriver(driver.ComputeDriver):
self.client = client.Client(CONF.lxd.lxd_client_host, self.client = client.Client(CONF.lxd.lxd_client_host,
CONF.lxd.lxd_client_cert, CONF.lxd.lxd_client_cert,
CONF.lxd.lxd_client_key) CONF.lxd.lxd_client_key)
self.firewall_driver = firewall.load_driver(
default='nova.virt.firewall.NoopFirewallDriver')
self.container = container.Container(self.client, self.container = container.Container(self.client,
self.virtapi) self.virtapi,
self.firewall_driver)
def init_host(self, host): def init_host(self, host):
return return self.container.init_container()
def list_instances(self): def list_instances(self):
return self.client.list() return self.client.list()
@ -149,7 +157,7 @@ class LXDDriver(driver.ComputeDriver):
self.client.stop(instance['uuid']) self.client.stop(instance['uuid'])
def power_on(self, context, instance, network_info, block_device_info): def power_on(self, context, instance, network_info, block_device_info):
self.client.start(instance['uuid]) self.client.start(instance['uuid'])
def soft_delete(self, instance): def soft_delete(self, instance):
pass pass
@ -158,10 +166,10 @@ class LXDDriver(driver.ComputeDriver):
raise NotImplemented() raise NotImplemented()
def pause(self, instance): def pause(self, instance):
raise NotImplemented() self.client.pause(instance['uuid'])
def unpause(self, instance): def unpause(self, instance):
raise NotImplemented() self.client.unpause(instance['uuid'])
def suspend(self, instance): def suspend(self, instance):
raise NotImplemented() raise NotImplemented()
@ -171,11 +179,12 @@ class LXDDriver(driver.ComputeDriver):
def destroy(self, context, instance, network_info, block_device_info=None, def destroy(self, context, instance, network_info, block_device_info=None,
destroy_disks=True, migrate_data=None): destroy_disks=True, migrate_data=None):
pass self.client.destory(instance['uuid'])
self.cleanup(context, instance, network_info, block_device_info)
def cleanup(self, context, instance, network_info, block_device_info=None, def cleanup(self, context, instance, network_info, block_device_info=None,
destroy_disks=True, migrate_data=None, destroy_vifs=True): destroy_disks=True, migrate_data=None, destroy_vifs=True):
pass self.container.teardown_network(instance, network_info)
def attach_volume(self, context, connection_info, instance, mountpoint, def attach_volume(self, context, connection_info, instance, mountpoint,
disk_bus=None, device_type=None, encryption=None): disk_bus=None, device_type=None, encryption=None):
@ -210,33 +219,19 @@ class LXDDriver(driver.ComputeDriver):
cpu_time_ns=0) cpu_time_ns=0)
def get_console_output(self, context, instance): def get_console_output(self, context, instance):
return 'FAKE CONSOLE OUTPUT\nANOTHER\nLAST LINE' return self.container.get_console_log(instance)
def get_vnc_console(self, context, instance):
return True
def get_spice_console(self, context, instance):
return True
def get_rdp_console(self, context, instance):
return True
def get_serial_console(self, context, instance):
return True
def get_console_pool_info(self, console_type):
return True
def refresh_security_group_rules(self, security_group_id): def refresh_security_group_rules(self, security_group_id):
return True self.firewall_driver.refresh_security_group_rules(security_group_id)
def refresh_security_group_members(self, security_group_id): def refresh_security_group_members(self, security_group_id):
return True self.firewall_driver.refresh_security_group_members(security_group_id)
def refresh_instance_security_rules(self, instance): def refresh_instance_security_rules(self, instance):
return True self.firewall_driver.refresh_rules(instance)
def refresh_provider_fw_rules(self): def refresh_provider_fw_rules(self):
pass 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.
@ -251,7 +246,7 @@ class LXDDriver(driver.ComputeDriver):
data["supported_instances"] = jsonutils.dumps([ data["supported_instances"] = jsonutils.dumps([
('i686', 'lxd', 'lxd'), ('i686', 'lxd', 'lxd'),
('x86_64', 'lxd', 'lxd')]) ('x86_64', 'lxd', 'lxd')])
data["vcpus"] = psutil.cpu_count() data["vcpus"] = 4
data["memory_mb"] = memory['total'] / units.Mi data["memory_mb"] = memory['total'] / units.Mi
data["local_gb"] = disk['total'] / units.Gi data["local_gb"] = disk['total'] / units.Gi
data["vcpus_used"] = 1 data["vcpus_used"] = 1
@ -267,47 +262,11 @@ class LXDDriver(driver.ComputeDriver):
return data return data
def ensure_filtering_rules_for_instance(self, instance_ref, network_info): def ensure_filtering_rules_for_instance(self, instance_ref, network_info):
return self.firewall_driver.setup_basic_filtering(instance, network_info)
self.firewall_driver.prepare_instance_filter(instance, network_info)
def get_instance_disk_info(self, instance, block_device_info=None):
return
def live_migration(self, context, instance_ref, dest,
post_method, recover_method, block_migration=False,
migrate_data=None):
post_method(context, instance_ref, dest, block_migration,
migrate_data)
return
def check_can_live_migrate_destination_cleanup(self, ctxt,
dest_check_data):
return
def check_can_live_migrate_destination(self, ctxt, instance_ref,
src_compute_info, dst_compute_info,
block_migration=False,
disk_over_commit=False):
return {}
def check_can_live_migrate_source(self, ctxt, instance_ref,
dest_check_data, block_device_info=None):
return
def finish_migration(self, context, migration, instance, disk_info,
network_info, image_meta, resize_instance,
block_device_info=None, power_on=True):
return
def confirm_migration(self, migration, instance, network_info):
return
def pre_live_migration(self, context, instance_ref, block_device_info,
network_info, disk, migrate_data=None):
return
def unfilter_instance(self, instance_ref, network_info): def unfilter_instance(self, instance_ref, network_info):
return self.firewall_driver.unfilter_instance(instance, network_info)
def get_available_nodes(self, refresh=False): def get_available_nodes(self, refresh=False):
hostname = socket.gethostname() hostname = socket.gethostname()

View File

@ -4,7 +4,7 @@
pbr>=0.6,!=0.7,<1.0 pbr>=0.6,!=0.7,<1.0
Babel>=1.3 Babel>=1.3
requests requests>=2.2.0,!=2.4.0
oslo.concurrency oslo.concurrency>=0.3.0 # Apache-2.0
oslo.utils oslo.utils>=1.2.0 # Apache-2.0
oslo.i18n oslo.i18n>=1.0.0 # Apache-2.0

View File

@ -17,6 +17,14 @@
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT # THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
import setuptools import setuptools
# In python < 2.7.4, a lazy loading of package `pbr` will break
# setuptools if some other modules registered functions in `atexit`.
# solution from: http://bugs.python.org/issue15881#msg170215
try:
import multiprocessing # noqa
except ImportError:
pass
setuptools.setup( setuptools.setup(
setup_requires=['pbr'], setup_requires=['pbr'],
pbr=True) pbr=True)

View File

@ -6,10 +6,10 @@ hacking>=0.9.2,<0.10
coverage>=3.6 coverage>=3.6
discover discover
python-subunit python-subunit>=0.0.18
sphinx>=1.1.2 sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
oslosphinx oslosphinx>=2.2.0 # Apache-2.0
oslotest>=1.1.0.0a1 oslotest>=1.2.0 # Apache-2.0
testrepository>=0.0.18 testrepository>=0.0.18
testscenarios>=0.4 testscenarios>=0.4
testtools>=0.9.34 testtools>=0.9.36,!=1.2.0