From fe22186eb989b0302e1cb26a5b92cd77ce47bb9b Mon Sep 17 00:00:00 2001 From: Andy Southgate Date: Fri, 14 Jan 2011 16:13:50 +0000 Subject: OS-55: Inject network settings in linux images --- nova/virt/conn_common.py | 50 ++++++++++++++++++++++++++++++++++++++++++++ nova/virt/disk.py | 19 ++++++++++------- nova/virt/libvirt_conn.py | 24 ++++----------------- nova/virt/xenapi/vm_utils.py | 36 +++++++++++++++++++++++++++++++ nova/virt/xenapi/vmops.py | 7 +++++++ 5 files changed, 109 insertions(+), 27 deletions(-) create mode 100644 nova/virt/conn_common.py (limited to 'nova/virt') diff --git a/nova/virt/conn_common.py b/nova/virt/conn_common.py new file mode 100644 index 000000000..bd9ed7794 --- /dev/null +++ b/nova/virt/conn_common.py @@ -0,0 +1,50 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2010 Citrix Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from nova import context +from nova import db +from nova import exception +from nova import flags +from nova import log as logging +from nova import utils + +LOG = logging.getLogger('nova.virt.conn_common') +FLAGS = flags.FLAGS + +flags.DEFINE_string('injected_network_template', + utils.abspath('virt/interfaces.template'), + 'Template file for injected network') + +def get_injectables(inst): + key = str(inst['key_data']) + net = None + network_ref = db.network_get_by_instance(context.get_admin_context(), + inst['id']) + if network_ref['injected']: + admin_context = context.get_admin_context() + address = db.instance_get_fixed_address(admin_context, inst['id']) + ra_server = network_ref['ra_server'] + if not ra_server: + ra_server = "fd00::" + with open(FLAGS.injected_network_template) as f: + net = f.read() % {'address': address, + 'netmask': network_ref['netmask'], + 'gateway': network_ref['gateway'], + 'broadcast': network_ref['broadcast'], + 'dns': network_ref['dns'], + 'ra_server': ra_server} + + return key, net diff --git a/nova/virt/disk.py b/nova/virt/disk.py index c5565abfa..88b05f0c0 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -92,11 +92,7 @@ def inject_data(image, key=None, net=None, partition=None, nbd=False): % err) try: - if key: - # inject key file - _inject_key_into_fs(key, tmpdir) - if net: - _inject_net_into_fs(net, tmpdir) + inject_data_into_fs(tmpdir, key, net, execute) finally: # unmount device utils.execute('sudo umount %s' % mapped_device) @@ -158,8 +154,17 @@ def _allocate_device(): def _free_device(device): _DEVICES.append(device) +def inject_data_into_fs(fs, key, net, execute): + """Injects data into a filesystem already mounted by the caller. + Virt connections can call this directly if they mount their fs + in a different way to inject_data + """ + if key: + _inject_key_into_fs(key, fs, execute=execute) + if net: + _inject_net_into_fs(net, fs, execute=execute) -def _inject_key_into_fs(key, fs): +def _inject_key_into_fs(key, fs, execute=None): """Add the given public ssh key to root's authorized_keys. key is an ssh key string. @@ -173,7 +178,7 @@ def _inject_key_into_fs(key, fs): utils.execute('sudo tee -a %s' % keyfile, '\n' + key.strip() + '\n') -def _inject_net_into_fs(net, fs): +def _inject_net_into_fs(net, fs, execute=None): """Inject /etc/network/interfaces into the filesystem rooted at fs. net is the contents of /etc/network/interfaces. diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 4e0fd106f..45d8754ab 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -62,6 +62,7 @@ from nova.compute import instance_types from nova.compute import power_state from nova.virt import disk from nova.virt import images +from nova.virt import conn_common libvirt = None libxml2 = None @@ -74,9 +75,7 @@ FLAGS = flags.FLAGS flags.DEFINE_string('rescue_image_id', 'ami-rescue', 'Rescue ami image') flags.DEFINE_string('rescue_kernel_id', 'aki-rescue', 'Rescue aki image') flags.DEFINE_string('rescue_ramdisk_id', 'ari-rescue', 'Rescue ari image') -flags.DEFINE_string('injected_network_template', - utils.abspath('virt/interfaces.template'), - 'Template file for injected network') + flags.DEFINE_string('libvirt_xml_template', utils.abspath('virt/libvirt.xml.template'), 'Libvirt XML Template') @@ -622,23 +621,8 @@ class LibvirtConnection(object): if not inst['kernel_id']: target_partition = "1" - key = str(inst['key_data']) - net = None - network_ref = db.network_get_by_instance(context.get_admin_context(), - inst['id']) - if network_ref['injected']: - admin_context = context.get_admin_context() - address = db.instance_get_fixed_address(admin_context, inst['id']) - ra_server = network_ref['ra_server'] - if not ra_server: - ra_server = "fd00::" - with open(FLAGS.injected_network_template) as f: - net = f.read() % {'address': address, - 'netmask': network_ref['netmask'], - 'gateway': network_ref['gateway'], - 'broadcast': network_ref['broadcast'], - 'dns': network_ref['dns'], - 'ra_server': ra_server} + key, net = conn_common.get_injectables(inst) + if key or net: inst_name = inst['name'] img_id = inst.image_id diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 4bbd522c1..70f81b3b6 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -22,6 +22,7 @@ their attributes like VDIs, VIFs, as well as their lookup functions. import os import pickle import re +import tempfile import time import urllib from xml.dom import minidom @@ -33,10 +34,12 @@ from nova import flags from nova import log as logging from nova import utils from nova.auth.manager import AuthManager +from nova.compute import disk from nova.compute import instance_types from nova.compute import power_state from nova.virt import images from nova.virt.xenapi import HelperBase +from nova.virt import conn_common from nova.virt.xenapi.volume_utils import StorageError @@ -439,6 +442,39 @@ class VMHelper(HelperBase): else: return None + @classmethod + def preconfigure_instance(cls, session, instance, vdi_ref): + """Makes alterations to the image before launching as part of spawn. + May also set xenstore values to modify the image behaviour after + VM start.""" + + # As mounting the image VDI is expensive, we only want do do it once, + # if at all, so determine whether it's required first, and then do + # everything + mount_required = False + key, net = conn_common.get_injectables(instance) + if key is not None or net is not None: + mount_required = True + + if mount_required: + def _mounted_processing(device): + devPath = '/dev/'+device+'1' # Note: Partition 1 hardcoded + tmpdir = tempfile.mkdtemp() + try: + out, err = utils.execute('sudo mount %s %s' % (devPath, tmpdir)) + if err: + raise exception.Error(_('Failed to mount filesystem: %s') % err) + try: + disk.inject_data_into_fs(tmpdir, key, net, utils.execute) + finally: + utils.execute('sudo umount %s' % devPath) + finally: + # remove temporary directory + os.rmdir(tmpdir) + + # FIXME: Check self._session is the type of session this fn wants + with_vdi_attached_here(session, vdi_ref, False, _mounted_processing) + @classmethod def compile_info(cls, record): """Fill record with VM status information""" diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index e84ce20c4..efab9c9ce 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -79,6 +79,9 @@ class VMOps(object): disk_image_type = ImageType.DISK else: disk_image_type = ImageType.DISK_RAW + # TODO: Coalesce fetch_image, lookup_image and + # manipulate_root_image so requires a single VDI mount/umount + # sequence vdi_uuid = VMHelper.fetch_image(self._session, instance.id, instance.image_id, user, project, disk_image_type) vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid) @@ -102,6 +105,10 @@ class VMOps(object): if network_ref: VMHelper.create_vif(self._session, vm_ref, network_ref, instance.mac_address) + + # Alter the image before VM start for, e.g. network injection + VMHelper.preconfigure_instance(self._session, instance, vdi_ref) + LOG.debug(_('Starting VM %s...'), vm_ref) self._session.call_xenapi('VM.start', vm_ref, False, False) instance_name = instance.name -- cgit From 88be6540d2a796e313f2d8ef4ccc6e66ba1a3ed1 Mon Sep 17 00:00:00 2001 From: Andy Southgate Date: Thu, 20 Jan 2011 16:49:54 +0000 Subject: OS-55: Only modify Linux image with no or injection-incapable guest agent OS-55: Support network configuration via xenstore for Windows images --- nova/virt/xenapi/vm_utils.py | 105 +++++++++++++++++++++++++++++++++++++++---- nova/virt/xenapi/vmops.py | 3 ++ 2 files changed, 99 insertions(+), 9 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 70f81b3b6..79d529ce2 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -29,6 +29,8 @@ from xml.dom import minidom from eventlet import event import glance.client +from nova import context +from nova import db from nova import exception from nova import flags from nova import log as logging @@ -458,22 +460,107 @@ class VMHelper(HelperBase): if mount_required: def _mounted_processing(device): - devPath = '/dev/'+device+'1' # Note: Partition 1 hardcoded + devPath = '/dev/'+device+'1' # NB: Partition 1 hardcoded tmpdir = tempfile.mkdtemp() try: - out, err = utils.execute('sudo mount %s %s' % (devPath, tmpdir)) - if err: - raise exception.Error(_('Failed to mount filesystem: %s') % err) + # Mount only Linux filesystems, as we mustn't disturb NTFS images try: - disk.inject_data_into_fs(tmpdir, key, net, utils.execute) - finally: - utils.execute('sudo umount %s' % devPath) + out, err = utils.execute('sudo mount -t ext2,ext3 "%s" "%s"' % (devPath, tmpdir)) + except exception.ProcessExecutionError as e: + err = str(e) + if err: + LOG.info('Failed to mount filesystem (expected for non-linux instances): %s' % err) + else: + try: + # This try block ensures that the umount occurs + + xe_update_networking_filename = os.path.join(tmpdir, 'usr', 'sbin', 'xe-update-networking') + if os.path.isfile(xe_update_networking_filename): + # The presence of the xe-update-networking file indicates that this guest + # agent can reconfigure the netwokr from xenstore data, so manipulation + # of files in /etc is not required + LOG.info('XenServer tools installed in this image are capable of network injection. ' + 'Networking files will not be manipulated') + else: + xe_daemon_filename = os.path.join(tmpdir, 'usr', 'sbin', 'xe-daemon') + if os.path.isfile(xe_daemon_filename): + LOG.info('XenServer tools are present in this image but ' + 'are not capable of network injection') + else: + LOG.info('XenServer tools are not installed in this image') + LOG.info('Manipulating interface files directly') + disk.inject_data_into_fs(tmpdir, key, net, utils.execute) + finally: + utils.execute('sudo umount "%s"' % devPath) finally: # remove temporary directory os.rmdir(tmpdir) - - # FIXME: Check self._session is the type of session this fn wants + with_vdi_attached_here(session, vdi_ref, False, _mounted_processing) + + + @classmethod + def preconfigure_xenstore(cls, session, instance, vm_ref): + XENSTORE_TYPES = { + 'BroadcastAddress' : 'multi_sz', + 'DefaultGateway' : 'multi_sz', + 'EnableDhcp' : 'dword', + 'IPAddress' : 'multi_sz', + 'NameServer' : 'string', + 'SubnetMask' : 'multi_sz' + } + + # Network setup + network_ref = db.network_get_by_instance(context.get_admin_context(), + instance['id']) + if network_ref['injected']: + admin_context = context.get_admin_context() + address = db.instance_get_fixed_address(admin_context, instance['id']) + + xenstore_data = { + # NB: Setting broadcast address is not supported by + # Windows or the Windows guest agent, and will be ignored + # on that platform + 'BroadcastAddress': network_ref['broadcast'], + 'EnableDhcp': '0', + 'IPAddress': address, + 'SubnetMask': network_ref['netmask'], + 'DefaultGateway': network_ref['gateway'], + 'NameServer': network_ref['dns'] + } + + device_to_configure = 0 # Configure network device 0 in the VM + + vif_refs = session.call_xenapi('VM.get_VIFs', vm_ref) + mac_addr = None + + for vif_ref in vif_refs: + device = session.call_xenapi('VIF.get_device', vif_ref) + if str(device) == str(device_to_configure): + mac_addr = session.call_xenapi('VIF.get_MAC', vif_ref) + break + + if mac_addr is None: + raise exception.NotFound('Networking device %s not found in VM') + + # MAC address must be upper case in the xenstore key, + # with colons replaced by underscores + underscore_mac_addr = mac_addr.replace(':', '_') + xenstore_prefix='vm-data/vif/'+underscore_mac_addr.upper()+'/tcpip/' + + for xenstore_key, xenstore_value in xenstore_data.iteritems(): + # NB: The xenstore_key part of the instance_key isn't used but must + # be unique. We set it to xenstore_key as a convenient unique name. + # The xenstore_key value takes effect in the /name element. + instance_key = xenstore_prefix + xenstore_key + type = XENSTORE_TYPES[xenstore_key] + + session.call_xenapi('VM.add_to_xenstore_data', vm_ref, instance_key+'/name', xenstore_key) + session.call_xenapi('VM.add_to_xenstore_data', vm_ref, instance_key+'/type', type) + if type == 'multi_sz': + session.call_xenapi('VM.add_to_xenstore_data', vm_ref, instance_key+'/data/0', xenstore_value) + else: + session.call_xenapi('VM.add_to_xenstore_data', vm_ref, instance_key+'/data', xenstore_value) @classmethod def compile_info(cls, record): diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index efab9c9ce..ae477f11e 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -109,6 +109,9 @@ class VMOps(object): # Alter the image before VM start for, e.g. network injection VMHelper.preconfigure_instance(self._session, instance, vdi_ref) + # Configure the VM's xenstore data before start for, e.g. network configuration + VMHelper.preconfigure_xenstore(self._session, instance, vm_ref) + LOG.debug(_('Starting VM %s...'), vm_ref) self._session.call_xenapi('VM.start', vm_ref, False, False) instance_name = instance.name -- cgit From 8f531ef7c0782feba46f83ec2e45d113753c4052 Mon Sep 17 00:00:00 2001 From: Andy Southgate Date: Thu, 20 Jan 2011 19:51:23 +0000 Subject: OS-55: pylint fixes --- nova/virt/xenapi/vm_utils.py | 96 ++++++++++++++++++++++++++++---------------- nova/virt/xenapi/vmops.py | 3 +- 2 files changed, 63 insertions(+), 36 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 79d529ce2..eb699d715 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -447,8 +447,7 @@ class VMHelper(HelperBase): @classmethod def preconfigure_instance(cls, session, instance, vdi_ref): """Makes alterations to the image before launching as part of spawn. - May also set xenstore values to modify the image behaviour after - VM start.""" + """ # As mounting the image VDI is expensive, we only want do do it once, # if at all, so determine whether it's required first, and then do @@ -460,38 +459,53 @@ class VMHelper(HelperBase): if mount_required: def _mounted_processing(device): - devPath = '/dev/'+device+'1' # NB: Partition 1 hardcoded + """Callback whioch runds with the image VDI attached""" + + dev_path = '/dev/'+device+'1' # NB: Partition 1 hardcoded tmpdir = tempfile.mkdtemp() try: - # Mount only Linux filesystems, as we mustn't disturb NTFS images + # Mount only Linux filesystems, to avoid disturbing + # NTFS images try: - out, err = utils.execute('sudo mount -t ext2,ext3 "%s" "%s"' % (devPath, tmpdir)) + _, err = utils.execute( + 'sudo mount -t ext2,ext3 "%s" "%s"' % + (dev_path, tmpdir)) except exception.ProcessExecutionError as e: err = str(e) if err: - LOG.info('Failed to mount filesystem (expected for non-linux instances): %s' % err) + LOG.info(_('Failed to mount filesystem (expected for ' + 'non-linux instances): %s') % err) else: try: # This try block ensures that the umount occurs - xe_update_networking_filename = os.path.join(tmpdir, 'usr', 'sbin', 'xe-update-networking') + xe_update_networking_filename = os.path.join(tmpdir, + 'usr', 'sbin', 'xe-update-networking') if os.path.isfile(xe_update_networking_filename): - # The presence of the xe-update-networking file indicates that this guest - # agent can reconfigure the netwokr from xenstore data, so manipulation - # of files in /etc is not required - LOG.info('XenServer tools installed in this image are capable of network injection. ' - 'Networking files will not be manipulated') + # The presence of the xe-update-networking + # file indicates that this guest agent can + # reconfigure the network from xenstore data, + # so manipulation of files in /etc is not + # required + LOG.info(_('XenServer tools installed in this ' + 'image are capable of network injection. ' + 'Networking files will not be manipulated')) else: - xe_daemon_filename = os.path.join(tmpdir, 'usr', 'sbin', 'xe-daemon') + xe_daemon_filename = os.path.join(tmpdir, 'usr', + 'sbin', 'xe-daemon') if os.path.isfile(xe_daemon_filename): - LOG.info('XenServer tools are present in this image but ' - 'are not capable of network injection') + LOG.info(_('XenServer tools are present in ' + 'this image but are not capable of ' + 'network injection')) else: - LOG.info('XenServer tools are not installed in this image') - LOG.info('Manipulating interface files directly') - disk.inject_data_into_fs(tmpdir, key, net, utils.execute) + LOG.info(_('XenServer tools are not ' + 'installed in this image')) + LOG.info(_('Manipulating interface files ' + 'directly')) + disk.inject_data_into_fs(tmpdir, key, net, + utils.execute) finally: - utils.execute('sudo umount "%s"' % devPath) + utils.execute('sudo umount "%s"' % dev_path) finally: # remove temporary directory os.rmdir(tmpdir) @@ -501,7 +515,11 @@ class VMHelper(HelperBase): @classmethod def preconfigure_xenstore(cls, session, instance, vm_ref): - XENSTORE_TYPES = { + """Sets xenstore values to modify the image behaviour after + VM start. + """ + + xenstore_types = { 'BroadcastAddress' : 'multi_sz', 'DefaultGateway' : 'multi_sz', 'EnableDhcp' : 'dword', @@ -511,11 +529,12 @@ class VMHelper(HelperBase): } # Network setup - network_ref = db.network_get_by_instance(context.get_admin_context(), - instance['id']) + network_ref = db.network_get_by_instance( + context.get_admin_context(), instance['id']) if network_ref['injected']: admin_context = context.get_admin_context() - address = db.instance_get_fixed_address(admin_context, instance['id']) + address = db.instance_get_fixed_address(admin_context, + instance['id']) xenstore_data = { # NB: Setting broadcast address is not supported by @@ -541,26 +560,33 @@ class VMHelper(HelperBase): break if mac_addr is None: - raise exception.NotFound('Networking device %s not found in VM') + raise exception.NotFound(_('Networking device %s not found ' + 'in VM')) # MAC address must be upper case in the xenstore key, # with colons replaced by underscores underscore_mac_addr = mac_addr.replace(':', '_') - xenstore_prefix='vm-data/vif/'+underscore_mac_addr.upper()+'/tcpip/' + xenstore_prefix = ('vm-data/vif/' + + underscore_mac_addr.upper() + '/tcpip/') for xenstore_key, xenstore_value in xenstore_data.iteritems(): - # NB: The xenstore_key part of the instance_key isn't used but must - # be unique. We set it to xenstore_key as a convenient unique name. - # The xenstore_key value takes effect in the /name element. + # NB: The xenstore_key part of the instance_key isn't used but + # must be unique. We set it to xenstore_key as a convenient + # unique name...The xenstore_key value takes effect in the + # /name element. instance_key = xenstore_prefix + xenstore_key - type = XENSTORE_TYPES[xenstore_key] - - session.call_xenapi('VM.add_to_xenstore_data', vm_ref, instance_key+'/name', xenstore_key) - session.call_xenapi('VM.add_to_xenstore_data', vm_ref, instance_key+'/type', type) - if type == 'multi_sz': - session.call_xenapi('VM.add_to_xenstore_data', vm_ref, instance_key+'/data/0', xenstore_value) + key_type = xenstore_types[xenstore_key] + + session.call_xenapi('VM.add_to_xenstore_data', vm_ref, + instance_key+'/name', xenstore_key) + session.call_xenapi('VM.add_to_xenstore_data', vm_ref, + instance_key+'/type', key_type) + if key_type == 'multi_sz': + session.call_xenapi('VM.add_to_xenstore_data', vm_ref, + instance_key+'/data/0', xenstore_value) else: - session.call_xenapi('VM.add_to_xenstore_data', vm_ref, instance_key+'/data', xenstore_value) + session.call_xenapi('VM.add_to_xenstore_data', vm_ref, + instance_key+'/data', xenstore_value) @classmethod def compile_info(cls, record): diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index ae477f11e..df282807a 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -109,7 +109,8 @@ class VMOps(object): # Alter the image before VM start for, e.g. network injection VMHelper.preconfigure_instance(self._session, instance, vdi_ref) - # Configure the VM's xenstore data before start for, e.g. network configuration + # Configure the VM's xenstore data before start for, + # e.g. network configuration VMHelper.preconfigure_xenstore(self._session, instance, vm_ref) LOG.debug(_('Starting VM %s...'), vm_ref) -- cgit From 1dbdb180cb93a812f8336bbfc49bf67a5203d1eb Mon Sep 17 00:00:00 2001 From: Andy Southgate Date: Fri, 21 Jan 2011 12:00:45 +0000 Subject: OS-55: Fix current unit tests --- nova/virt/xenapi/fake.py | 4 ++++ nova/virt/xenapi/vm_utils.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py index e8352771c..836252730 100644 --- a/nova/virt/xenapi/fake.py +++ b/nova/virt/xenapi/fake.py @@ -161,6 +161,10 @@ def after_VBD_create(vbd_ref, vbd_rec): vm_name_label = _db_content['VM'][vm_ref]['name_label'] vbd_rec['vm_name_label'] = vm_name_label +def after_VM_create(vm_ref, vm_rec): + """Create read-only fields in the VM record.""" + if 'is_control_domain' not in vm_rec: + vm_rec['is_control_domain'] = False def create_pbd(config, host_ref, sr_ref, attached): return _create_object('PBD', { diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index eb699d715..9b78a178a 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -459,7 +459,7 @@ class VMHelper(HelperBase): if mount_required: def _mounted_processing(device): - """Callback whioch runds with the image VDI attached""" + """Callback which runs with the image VDI attached""" dev_path = '/dev/'+device+'1' # NB: Partition 1 hardcoded tmpdir = tempfile.mkdtemp() @@ -467,7 +467,7 @@ class VMHelper(HelperBase): # Mount only Linux filesystems, to avoid disturbing # NTFS images try: - _, err = utils.execute( + out, err = utils.execute( 'sudo mount -t ext2,ext3 "%s" "%s"' % (dev_path, tmpdir)) except exception.ProcessExecutionError as e: -- cgit From 9039c2cc59904a72fc71255a3a31ec2b17018963 Mon Sep 17 00:00:00 2001 From: Andy Southgate Date: Fri, 21 Jan 2011 16:06:32 +0000 Subject: OS-55: Added unit test for network injection via xenstore --- nova/virt/xenapi/fake.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py index 836252730..f9ae8766a 100644 --- a/nova/virt/xenapi/fake.py +++ b/nova/virt/xenapi/fake.py @@ -148,7 +148,15 @@ def create_vbd(vm_ref, vdi_ref): after_VBD_create(vbd_ref, vbd_rec) return vbd_ref - +def VM_get_xenstore_data(vm_ref): + return _db_content['VM'][vm_ref].get('xenstore_data', '') + +def VM_add_to_xenstore_data(vm_ref, key, value): + db_ref = _db_content['VM'][vm_ref] + if not 'xenstore_data' in db_ref: + db_ref['xenstore_data'] = {} + db_ref['xenstore_data'][key] = value + def after_VBD_create(vbd_ref, vbd_rec): """Create read-only fields and backref from VM to VBD when VBD is created.""" @@ -401,7 +409,7 @@ class SessionBase(object): field in _db_content[cls][ref]): return _db_content[cls][ref][field] - LOG.debuug(_('Raising NotImplemented')) + LOG.debug(_('Raising NotImplemented')) raise NotImplementedError( _('xenapi.fake does not have an implementation for %s or it has ' 'been called with the wrong number of arguments') % name) -- cgit From c97618e1eaff4091f01381073a298d0f67050126 Mon Sep 17 00:00:00 2001 From: Andy Southgate Date: Mon, 24 Jan 2011 18:28:50 +0000 Subject: OS-55: Post-merge fixes --- nova/virt/xenapi/vm_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 9b78a178a..68946a2bb 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -36,9 +36,9 @@ from nova import flags from nova import log as logging from nova import utils from nova.auth.manager import AuthManager -from nova.compute import disk from nova.compute import instance_types from nova.compute import power_state +from nova.virt import disk from nova.virt import images from nova.virt.xenapi import HelperBase from nova.virt import conn_common -- cgit From cd346a2cda13833f976b9e838d67cf17c52f327e Mon Sep 17 00:00:00 2001 From: Andy Southgate Date: Mon, 24 Jan 2011 19:04:25 +0000 Subject: OS-55: PEP8 fixes --- nova/virt/conn_common.py | 3 +- nova/virt/disk.py | 2 ++ nova/virt/xenapi/fake.py | 9 +++-- nova/virt/xenapi/vm_utils.py | 80 ++++++++++++++++++++++---------------------- nova/virt/xenapi/vmops.py | 6 ++-- 5 files changed, 54 insertions(+), 46 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/conn_common.py b/nova/virt/conn_common.py index bd9ed7794..5550b50c1 100644 --- a/nova/virt/conn_common.py +++ b/nova/virt/conn_common.py @@ -27,7 +27,8 @@ FLAGS = flags.FLAGS flags.DEFINE_string('injected_network_template', utils.abspath('virt/interfaces.template'), 'Template file for injected network') - + + def get_injectables(inst): key = str(inst['key_data']) net = None diff --git a/nova/virt/disk.py b/nova/virt/disk.py index 88b05f0c0..21bb53369 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -154,6 +154,7 @@ def _allocate_device(): def _free_device(device): _DEVICES.append(device) + def inject_data_into_fs(fs, key, net, execute): """Injects data into a filesystem already mounted by the caller. Virt connections can call this directly if they mount their fs @@ -164,6 +165,7 @@ def inject_data_into_fs(fs, key, net, execute): if net: _inject_net_into_fs(net, fs, execute=execute) + def _inject_key_into_fs(key, fs, execute=None): """Add the given public ssh key to root's authorized_keys. diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py index f9ae8766a..561e47911 100644 --- a/nova/virt/xenapi/fake.py +++ b/nova/virt/xenapi/fake.py @@ -148,15 +148,18 @@ def create_vbd(vm_ref, vdi_ref): after_VBD_create(vbd_ref, vbd_rec) return vbd_ref + def VM_get_xenstore_data(vm_ref): return _db_content['VM'][vm_ref].get('xenstore_data', '') - + + def VM_add_to_xenstore_data(vm_ref, key, value): db_ref = _db_content['VM'][vm_ref] if not 'xenstore_data' in db_ref: db_ref['xenstore_data'] = {} db_ref['xenstore_data'][key] = value - + + def after_VBD_create(vbd_ref, vbd_rec): """Create read-only fields and backref from VM to VBD when VBD is created.""" @@ -169,11 +172,13 @@ def after_VBD_create(vbd_ref, vbd_rec): vm_name_label = _db_content['VM'][vm_ref]['name_label'] vbd_rec['vm_name_label'] = vm_name_label + def after_VM_create(vm_ref, vm_rec): """Create read-only fields in the VM record.""" if 'is_control_domain' not in vm_rec: vm_rec['is_control_domain'] = False + def create_pbd(config, host_ref, sr_ref, attached): return _create_object('PBD', { 'device-config': config, diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 68946a2bb..fa60c44c3 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -448,7 +448,7 @@ class VMHelper(HelperBase): def preconfigure_instance(cls, session, instance, vdi_ref): """Makes alterations to the image before launching as part of spawn. """ - + # As mounting the image VDI is expensive, we only want do do it once, # if at all, so determine whether it's required first, and then do # everything @@ -456,12 +456,13 @@ class VMHelper(HelperBase): key, net = conn_common.get_injectables(instance) if key is not None or net is not None: mount_required = True - + if mount_required: + def _mounted_processing(device): """Callback which runs with the image VDI attached""" - - dev_path = '/dev/'+device+'1' # NB: Partition 1 hardcoded + + dev_path = '/dev/' + device + '1' # NB: Partition 1 hardcoded tmpdir = tempfile.mkdtemp() try: # Mount only Linux filesystems, to avoid disturbing @@ -478,9 +479,9 @@ class VMHelper(HelperBase): else: try: # This try block ensures that the umount occurs - - xe_update_networking_filename = os.path.join(tmpdir, - 'usr', 'sbin', 'xe-update-networking') + + xe_update_networking_filename = os.path.join( + tmpdir, 'usr', 'sbin', 'xe-update-networking') if os.path.isfile(xe_update_networking_filename): # The presence of the xe-update-networking # file indicates that this guest agent can @@ -489,14 +490,15 @@ class VMHelper(HelperBase): # required LOG.info(_('XenServer tools installed in this ' 'image are capable of network injection. ' - 'Networking files will not be manipulated')) + 'Networking files will not be' + 'manipulated')) else: - xe_daemon_filename = os.path.join(tmpdir, 'usr', - 'sbin', 'xe-daemon') + xe_daemon_filename = os.path.join(tmpdir, + 'usr', 'sbin', 'xe-daemon') if os.path.isfile(xe_daemon_filename): - LOG.info(_('XenServer tools are present in ' - 'this image but are not capable of ' - 'network injection')) + LOG.info(_('XenServer tools are present ' + 'in this image but are not capable ' + 'of network injection')) else: LOG.info(_('XenServer tools are not ' 'installed in this image')) @@ -510,24 +512,23 @@ class VMHelper(HelperBase): # remove temporary directory os.rmdir(tmpdir) - with_vdi_attached_here(session, vdi_ref, False, _mounted_processing) - - + with_vdi_attached_here(session, vdi_ref, False, + _mounted_processing) + @classmethod def preconfigure_xenstore(cls, session, instance, vm_ref): """Sets xenstore values to modify the image behaviour after VM start. """ - + xenstore_types = { - 'BroadcastAddress' : 'multi_sz', - 'DefaultGateway' : 'multi_sz', - 'EnableDhcp' : 'dword', - 'IPAddress' : 'multi_sz', - 'NameServer' : 'string', - 'SubnetMask' : 'multi_sz' - } - + 'BroadcastAddress': 'multi_sz', + 'DefaultGateway': 'multi_sz', + 'EnableDhcp': 'dword', + 'IPAddress': 'multi_sz', + 'NameServer': 'string', + 'SubnetMask': 'multi_sz'} + # Network setup network_ref = db.network_get_by_instance( context.get_admin_context(), instance['id']) @@ -535,8 +536,8 @@ class VMHelper(HelperBase): admin_context = context.get_admin_context() address = db.instance_get_fixed_address(admin_context, instance['id']) - - xenstore_data = { + + xenstore_data = { # NB: Setting broadcast address is not supported by # Windows or the Windows guest agent, and will be ignored # on that platform @@ -545,30 +546,29 @@ class VMHelper(HelperBase): 'IPAddress': address, 'SubnetMask': network_ref['netmask'], 'DefaultGateway': network_ref['gateway'], - 'NameServer': network_ref['dns'] - } - - device_to_configure = 0 # Configure network device 0 in the VM - + 'NameServer': network_ref['dns']} + + device_to_configure = 0 # Configure network device 0 in the VM + vif_refs = session.call_xenapi('VM.get_VIFs', vm_ref) mac_addr = None - + for vif_ref in vif_refs: device = session.call_xenapi('VIF.get_device', vif_ref) if str(device) == str(device_to_configure): mac_addr = session.call_xenapi('VIF.get_MAC', vif_ref) break - + if mac_addr is None: raise exception.NotFound(_('Networking device %s not found ' 'in VM')) - + # MAC address must be upper case in the xenstore key, # with colons replaced by underscores underscore_mac_addr = mac_addr.replace(':', '_') xenstore_prefix = ('vm-data/vif/' + underscore_mac_addr.upper() + '/tcpip/') - + for xenstore_key, xenstore_value in xenstore_data.iteritems(): # NB: The xenstore_key part of the instance_key isn't used but # must be unique. We set it to xenstore_key as a convenient @@ -578,15 +578,15 @@ class VMHelper(HelperBase): key_type = xenstore_types[xenstore_key] session.call_xenapi('VM.add_to_xenstore_data', vm_ref, - instance_key+'/name', xenstore_key) + instance_key + '/name', xenstore_key) session.call_xenapi('VM.add_to_xenstore_data', vm_ref, - instance_key+'/type', key_type) + instance_key + '/type', key_type) if key_type == 'multi_sz': session.call_xenapi('VM.add_to_xenstore_data', vm_ref, - instance_key+'/data/0', xenstore_value) + instance_key + '/data/0', xenstore_value) else: session.call_xenapi('VM.add_to_xenstore_data', vm_ref, - instance_key+'/data', xenstore_value) + instance_key + '/data', xenstore_value) @classmethod def compile_info(cls, record): diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index df282807a..9eea19c42 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -105,14 +105,14 @@ class VMOps(object): if network_ref: VMHelper.create_vif(self._session, vm_ref, network_ref, instance.mac_address) - + # Alter the image before VM start for, e.g. network injection VMHelper.preconfigure_instance(self._session, instance, vdi_ref) - + # Configure the VM's xenstore data before start for, # e.g. network configuration VMHelper.preconfigure_xenstore(self._session, instance, vm_ref) - + LOG.debug(_('Starting VM %s...'), vm_ref) self._session.call_xenapi('VM.start', vm_ref, False, False) instance_name = instance.name -- cgit From 46456155d42dd8a668b370fa84972c388094e1d8 Mon Sep 17 00:00:00 2001 From: Andy Southgate Date: Fri, 28 Jan 2011 18:40:19 +0000 Subject: OS-55: Fix typo for libvirt_conn operation --- nova/virt/disk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/disk.py b/nova/virt/disk.py index 21bb53369..98121df2a 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -92,7 +92,7 @@ def inject_data(image, key=None, net=None, partition=None, nbd=False): % err) try: - inject_data_into_fs(tmpdir, key, net, execute) + inject_data_into_fs(tmpdir, key, net, utils.execute) finally: # unmount device utils.execute('sudo umount %s' % mapped_device) -- cgit From 2dfcfccd74821851c965ee2912fd315e25e7f838 Mon Sep 17 00:00:00 2001 From: Andy Southgate Date: Tue, 15 Feb 2011 12:15:49 +0000 Subject: OS-55: Moved conn_common code into disk.py --- nova/virt/conn_common.py | 51 -------------------------------------------- nova/virt/disk.py | 27 +++++++++++++++++++++++ nova/virt/libvirt_conn.py | 3 +-- nova/virt/xenapi/vm_utils.py | 3 +-- 4 files changed, 29 insertions(+), 55 deletions(-) delete mode 100644 nova/virt/conn_common.py (limited to 'nova/virt') diff --git a/nova/virt/conn_common.py b/nova/virt/conn_common.py deleted file mode 100644 index 5550b50c1..000000000 --- a/nova/virt/conn_common.py +++ /dev/null @@ -1,51 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2010 Citrix Systems, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from nova import context -from nova import db -from nova import exception -from nova import flags -from nova import log as logging -from nova import utils - -LOG = logging.getLogger('nova.virt.conn_common') -FLAGS = flags.FLAGS - -flags.DEFINE_string('injected_network_template', - utils.abspath('virt/interfaces.template'), - 'Template file for injected network') - - -def get_injectables(inst): - key = str(inst['key_data']) - net = None - network_ref = db.network_get_by_instance(context.get_admin_context(), - inst['id']) - if network_ref['injected']: - admin_context = context.get_admin_context() - address = db.instance_get_fixed_address(admin_context, inst['id']) - ra_server = network_ref['ra_server'] - if not ra_server: - ra_server = "fd00::" - with open(FLAGS.injected_network_template) as f: - net = f.read() % {'address': address, - 'netmask': network_ref['netmask'], - 'gateway': network_ref['gateway'], - 'broadcast': network_ref['broadcast'], - 'dns': network_ref['dns'], - 'ra_server': ra_server} - - return key, net diff --git a/nova/virt/disk.py b/nova/virt/disk.py index 98121df2a..cee1ffbce 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -26,6 +26,8 @@ import os import tempfile import time +from nova import context +from nova import db from nova import exception from nova import flags from nova import log as logging @@ -38,6 +40,9 @@ flags.DEFINE_integer('minimum_root_size', 1024 * 1024 * 1024 * 10, 'minimum size in bytes of root partition') flags.DEFINE_integer('block_size', 1024 * 1024 * 256, 'block_size to use for dd') +flags.DEFINE_string('injected_network_template', + utils.abspath('virt/interfaces.template'), + 'Template file for injected network') def extend(image, size): @@ -155,6 +160,28 @@ def _free_device(device): _DEVICES.append(device) +def get_injectables(inst): + key = str(inst['key_data']) + net = None + network_ref = db.network_get_by_instance(context.get_admin_context(), + inst['id']) + if network_ref['injected']: + admin_context = context.get_admin_context() + address = db.instance_get_fixed_address(admin_context, inst['id']) + ra_server = network_ref['ra_server'] + if not ra_server: + ra_server = "fd00::" + with open(FLAGS.injected_network_template) as f: + net = f.read() % {'address': address, + 'netmask': network_ref['netmask'], + 'gateway': network_ref['gateway'], + 'broadcast': network_ref['broadcast'], + 'dns': network_ref['dns'], + 'ra_server': ra_server} + + return key, net + + def inject_data_into_fs(fs, key, net, execute): """Injects data into a filesystem already mounted by the caller. Virt connections can call this directly if they mount their fs diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 45d8754ab..806f35a81 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -62,7 +62,6 @@ from nova.compute import instance_types from nova.compute import power_state from nova.virt import disk from nova.virt import images -from nova.virt import conn_common libvirt = None libxml2 = None @@ -621,7 +620,7 @@ class LibvirtConnection(object): if not inst['kernel_id']: target_partition = "1" - key, net = conn_common.get_injectables(inst) + key, net = disk.get_injectables(inst) if key or net: inst_name = inst['name'] diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index fa60c44c3..603cef1f6 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -41,7 +41,6 @@ from nova.compute import power_state from nova.virt import disk from nova.virt import images from nova.virt.xenapi import HelperBase -from nova.virt import conn_common from nova.virt.xenapi.volume_utils import StorageError @@ -453,7 +452,7 @@ class VMHelper(HelperBase): # if at all, so determine whether it's required first, and then do # everything mount_required = False - key, net = conn_common.get_injectables(instance) + key, net = disk.get_injectables(instance) if key is not None or net is not None: mount_required = True -- cgit From 552875913e263d0e44be4613f0a07d3b53067e96 Mon Sep 17 00:00:00 2001 From: Andy Southgate Date: Wed, 16 Feb 2011 19:32:45 +0000 Subject: Fixed merge error --- nova/virt/xenapi/vm_utils.py | 1 + 1 file changed, 1 insertion(+) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index c5347498d..4b9883d21 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -597,6 +597,7 @@ class VMHelper(HelperBase): session.call_xenapi('VM.add_to_xenstore_data', vm_ref, instance_key + '/data', xenstore_value) + @classmethod def lookup_kernel_ramdisk(cls, session, vm): vm_rec = session.get_xenapi().VM.get_record(vm) if 'PV_kernel' in vm_rec and 'PV_ramdisk' in vm_rec: -- cgit From d1a6cb96c1c72894cbba24e6806da5c81fb915df Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Tue, 22 Feb 2011 20:39:33 +0000 Subject: Removed block of code that resurrected itself in the last merge. --- nova/virt/xenapi/vmops.py | 4 ---- 1 file changed, 4 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 1b2712d15..c9cc8e698 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -108,10 +108,6 @@ class VMOps(object): instance, kernel, ramdisk, pv_kernel) VMHelper.create_vbd(self._session, vm_ref, vdi_ref, 0, True) - if network_ref: - VMHelper.create_vif(self._session, vm_ref, - network_ref, instance.mac_address) - # Alter the image before VM start for, e.g. network injection VMHelper.preconfigure_instance(self._session, instance, vdi_ref) -- cgit From 72940957611bcba7dc41bfe9232743369d9a151f Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Mon, 28 Feb 2011 16:04:26 +0000 Subject: Fixed default value for xenapi_agent_path flag --- nova/virt/xenapi_conn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 546a10d09..4fc69961d 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -106,7 +106,7 @@ flags.DEFINE_integer('xenapi_inject_image', ' data into the disk image should be made.' ' Used only if connection_type=xenapi.') flags.DEFINE_integer('xenapi_agent_path', - True, + '/usr/sbin/xe-update-networking' 'Specifies the path in which the xenapi guest agent' ' should be located. If the agent is present,' ' network configuration if not injected into the image' -- cgit From 026c83551fa2e07f7f20d6b163f7da93e331b084 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Mon, 28 Feb 2011 16:59:00 +0000 Subject: Fixed obvious errors with flags. Note: tests still fail. --- nova/virt/xenapi_conn.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 4fc69961d..b9e87c2ce 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -100,13 +100,13 @@ flags.DEFINE_integer('xenapi_vhd_coalesce_max_attempts', 5, 'Max number of times to poll for VHD to coalesce.' ' Used only if connection_type=xenapi.') -flags.DEFINE_integer('xenapi_inject_image', +flags.DEFINE_bool('xenapi_inject_image', True, 'Specifies whether an attempt to inject network/key' ' data into the disk image should be made.' ' Used only if connection_type=xenapi.') -flags.DEFINE_integer('xenapi_agent_path', - '/usr/sbin/xe-update-networking' +flags.DEFINE_string('xenapi_agent_path', + '/usr/sbin/xe-update-networking', 'Specifies the path in which the xenapi guest agent' ' should be located. If the agent is present,' ' network configuration if not injected into the image' -- cgit From 4e4711ccfc7ce3c3df704a8635dccd506d6e7f01 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Tue, 1 Mar 2011 00:28:59 +0000 Subject: Units tests fixed partially. Still need to address checking data injected into xenstore need to convert string into dict or similar. Also todo PEP8 fixes --- nova/virt/xenapi/fake.py | 9 +++++++++ nova/virt/xenapi/vm_utils.py | 3 ++- nova/virt/xenapi/vmops.py | 7 +++++++ nova/virt/xenapi_conn.py | 2 +- 4 files changed, 19 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py index 08e2a03f7..664cfbd79 100644 --- a/nova/virt/xenapi/fake.py +++ b/nova/virt/xenapi/fake.py @@ -153,7 +153,14 @@ def VM_get_xenstore_data(vm_ref): return _db_content['VM'][vm_ref].get('xenstore_data', '') +def VM_remove_from_xenstore_data(vm_ref, key): + db_ref = _db_content['VM'][vm_ref] + if not 'xenstore_data' in db_ref: + return + db_ref['xenstore_data'][key] = None + def VM_add_to_xenstore_data(vm_ref, key, value): + LOG.debug("ADDING TO XENSTORE DATA %s %s",key,value) db_ref = _db_content['VM'][vm_ref] if not 'xenstore_data' in db_ref: db_ref['xenstore_data'] = {} @@ -503,7 +510,9 @@ class SessionBase(object): def _get_by_field(self, recs, k, v, return_singleton): result = [] + LOG.debug("_get_by_field!!!! - %d", return_singleton) for ref, rec in recs.iteritems(): + LOG.debug("k:%s,rec[k]:%s,v:%s",k,rec.get(k),v) if rec.get(k) == v: result.append(ref) diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 0434f745d..a01bab8de 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -409,8 +409,10 @@ class VMHelper(HelperBase): @classmethod def lookup(cls, session, i): """Look the instance i up, and returns it if available""" + LOG.debug("Entering lookup for instance:%s",str(i)) vms = session.get_xenapi().VM.get_by_name_label(i) n = len(vms) + LOG.debug("n:%d",n) if n == 0: return None elif n > 1: @@ -480,7 +482,6 @@ class VMHelper(HelperBase): else: try: # This try block ensures that the umount occurs - xe_guest_agent_filename = os.path.join( tmpdir, FLAGS.xenapi_agent_path) if os.path.isfile(xe_guest_agent_filename): diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index cc84b7032..c137d4931 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -117,6 +117,7 @@ class VMOps(object): VMHelper.preconfigure_instance(self._session, instance, vdi_ref) # inject_network_info and create vifs + LOG.debug("About to run inject_network_info") networks = self.inject_network_info(instance) self.create_vifs(instance, networks) @@ -186,6 +187,7 @@ class VMOps(object): # Must be the instance name instance_name = instance_or_vm except (AttributeError, KeyError): + # # Note the the KeyError will only happen with fakes.py # Not a string; must be an ID or a vm instance if isinstance(instance_or_vm, (int, long)): @@ -201,8 +203,12 @@ class VMOps(object): instance_name = instance_or_vm else: instance_name = instance_or_vm.name + #fake xenapi does not use OpaqueRef as a prefix + #when running tests we will always end up here vm = VMHelper.lookup(self._session, instance_name) if vm is None: + if FLAGS.xenapi_connection_url == 'test_url': + return instance_or_vm raise exception.NotFound( _('Instance not present %s') % instance_name) return vm @@ -496,6 +502,7 @@ class VMOps(object): 'ips': [ip_dict(ip) for ip in network_IPs]} self.write_to_param_xenstore(vm_opaque_ref, {location: mapping}) try: + logging.debug("About to run write_to_xenstore") self.write_to_xenstore(vm_opaque_ref, location, mapping['location']) except KeyError: diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index b9e87c2ce..9f8b6af02 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -106,7 +106,7 @@ flags.DEFINE_bool('xenapi_inject_image', ' data into the disk image should be made.' ' Used only if connection_type=xenapi.') flags.DEFINE_string('xenapi_agent_path', - '/usr/sbin/xe-update-networking', + 'usr/sbin/xe-update-networking', 'Specifies the path in which the xenapi guest agent' ' should be located. If the agent is present,' ' network configuration if not injected into the image' -- cgit From 8806858918f396cfca41a28c191dc9e8d2809a0e Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Tue, 1 Mar 2011 01:10:38 +0000 Subject: Fixed xenapi tests Gave up on clever things with map stored as string in xenstore. Used ast.liteeral_eval instead. Changed instance ID and names in tests from in to string (1 => '1') This simplified VMOps._get_vm_opaqueref Changed VMOps._get_vm_opaqueref as references returned by fake xenapi do not start with "OpaqueRef:" prefix. Fixed PEP8 Errors --- nova/virt/xenapi/fake.py | 6 ++---- nova/virt/xenapi/vm_utils.py | 8 -------- nova/virt/xenapi/vmops.py | 15 +++------------ 3 files changed, 5 insertions(+), 24 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py index 664cfbd79..7aa82211d 100644 --- a/nova/virt/xenapi/fake.py +++ b/nova/virt/xenapi/fake.py @@ -156,11 +156,11 @@ def VM_get_xenstore_data(vm_ref): def VM_remove_from_xenstore_data(vm_ref, key): db_ref = _db_content['VM'][vm_ref] if not 'xenstore_data' in db_ref: - return + return db_ref['xenstore_data'][key] = None + def VM_add_to_xenstore_data(vm_ref, key, value): - LOG.debug("ADDING TO XENSTORE DATA %s %s",key,value) db_ref = _db_content['VM'][vm_ref] if not 'xenstore_data' in db_ref: db_ref['xenstore_data'] = {} @@ -510,9 +510,7 @@ class SessionBase(object): def _get_by_field(self, recs, k, v, return_singleton): result = [] - LOG.debug("_get_by_field!!!! - %d", return_singleton) for ref, rec in recs.iteritems(): - LOG.debug("k:%s,rec[k]:%s,v:%s",k,rec.get(k),v) if rec.get(k) == v: result.append(ref) diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index a01bab8de..510261b15 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -409,10 +409,8 @@ class VMHelper(HelperBase): @classmethod def lookup(cls, session, i): """Look the instance i up, and returns it if available""" - LOG.debug("Entering lookup for instance:%s",str(i)) vms = session.get_xenapi().VM.get_by_name_label(i) n = len(vms) - LOG.debug("n:%d",n) if n == 0: return None elif n > 1: @@ -451,20 +449,17 @@ class VMHelper(HelperBase): # As mounting the image VDI is expensive, we only want do do it once, # if at all, so determine whether it's required first, and then do # everything - LOG.debug("Running preconfigure_instance") mount_required = False key, net = disk.get_injectables(instance) if key is not None or net is not None: mount_required = True - LOG.debug("Mount_required:%s", str(mount_required)) if mount_required: def _mounted_processing(device): """Callback which runs with the image VDI attached""" dev_path = '/dev/' + device + '1' # NB: Partition 1 hardcoded - LOG.debug("Device path:%s", dev_path) tmpdir = tempfile.mkdtemp() try: # Mount only Linux filesystems, to avoid disturbing @@ -473,7 +468,6 @@ class VMHelper(HelperBase): out, err = utils.execute( 'sudo mount -t ext2,ext3 "%s" "%s"' % (dev_path, tmpdir)) - LOG.debug("filesystem mounted") except exception.ProcessExecutionError as e: err = str(e) if err: @@ -506,7 +500,6 @@ class VMHelper(HelperBase): 'installed in this image')) LOG.info(_('Manipulating interface files ' 'directly')) - LOG.debug("Going to inject data in filesystem") disk.inject_data_into_fs(tmpdir, key, net, utils.execute) finally: @@ -748,7 +741,6 @@ def vbd_unplug_with_retry(session, vbd): # FIXME(sirp): We can use LoopingCall here w/o blocking sleep() while True: try: - LOG.debug("About to unplug VBD") session.get_xenapi().VBD.unplug(vbd) LOG.debug(_('VBD.unplug successful first time.')) return diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index c137d4931..a2f3a8f09 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -112,12 +112,10 @@ class VMOps(object): # Alter the image before VM start for, e.g. network injection #TODO(salvatore-orlando): do this only if flag is true - LOG.debug("About to run preconfigure_instance") if FLAGS.xenapi_inject_image: VMHelper.preconfigure_instance(self._session, instance, vdi_ref) # inject_network_info and create vifs - LOG.debug("About to run inject_network_info") networks = self.inject_network_info(instance) self.create_vifs(instance, networks) @@ -192,19 +190,12 @@ class VMOps(object): # Not a string; must be an ID or a vm instance if isinstance(instance_or_vm, (int, long)): ctx = context.get_admin_context() - try: - instance_obj = db.instance_get(ctx, instance_or_vm) - instance_name = instance_obj.name - except exception.NotFound: - # The unit tests screw this up, as they use an integer for - # the vm name. I'd fix that up, but that's a matter for - # another bug report. So for now, just try with the passed - # value - instance_name = instance_or_vm + instance_obj = db.instance_get(ctx, instance_or_vm) + instance_name = instance_obj.name else: instance_name = instance_or_vm.name #fake xenapi does not use OpaqueRef as a prefix - #when running tests we will always end up here + #when running tests we will always end up here vm = VMHelper.lookup(self._session, instance_name) if vm is None: if FLAGS.xenapi_connection_url == 'test_url': -- cgit From e0f1490e481e5b3e0e28b25049cc69eb905b74d6 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Wed, 2 Mar 2011 09:50:44 +0000 Subject: Removed excess TODO comments and debug line --- nova/virt/xenapi/vmops.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index a2f3a8f09..ec620f918 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -111,7 +111,6 @@ class VMOps(object): VMHelper.create_vbd(self._session, vm_ref, vdi_ref, 0, True) # Alter the image before VM start for, e.g. network injection - #TODO(salvatore-orlando): do this only if flag is true if FLAGS.xenapi_inject_image: VMHelper.preconfigure_instance(self._session, instance, vdi_ref) @@ -493,7 +492,6 @@ class VMOps(object): 'ips': [ip_dict(ip) for ip in network_IPs]} self.write_to_param_xenstore(vm_opaque_ref, {location: mapping}) try: - logging.debug("About to run write_to_xenstore") self.write_to_xenstore(vm_opaque_ref, location, mapping['location']) except KeyError: -- cgit From 97563d650a08e7f2d1aa1f08237219291d821e39 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Wed, 2 Mar 2011 10:43:45 +0000 Subject: Changed _get_vm_opaqueref removing test-specific code paths. --- nova/virt/xenapi/vmops.py | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index ec620f918..450a06315 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -51,6 +51,7 @@ class VMOps(object): def __init__(self, session): self.XenAPI = session.get_imported_xenapi() self._session = session + self.known_vm_refs = [] VMHelper.XenAPI = self.XenAPI def list_instances(self): @@ -176,29 +177,16 @@ class VMOps(object): a vm name or a vm instance, and want a vm instance in return. """ vm = None - try: - if instance_or_vm.startswith("OpaqueRef:"): - # Got passed an opaque ref; return it + if instance_or_vm in self.known_vm_refs: return instance_or_vm - else: - # Must be the instance name - instance_name = instance_or_vm - except (AttributeError, KeyError): - # - # Note the the KeyError will only happen with fakes.py - # Not a string; must be an ID or a vm instance - if isinstance(instance_or_vm, (int, long)): - ctx = context.get_admin_context() - instance_obj = db.instance_get(ctx, instance_or_vm) - instance_name = instance_obj.name - else: - instance_name = instance_or_vm.name - #fake xenapi does not use OpaqueRef as a prefix - #when running tests we will always end up here + instance_name = instance_or_vm + #if instance_or_vm is not a string; + #must be an ID or a vm instance + if not isinstance(instance_or_vm, str): + instance_name = instance_or_vm.name vm = VMHelper.lookup(self._session, instance_name) + self.known_vm_refs.append(vm) if vm is None: - if FLAGS.xenapi_connection_url == 'test_url': - return instance_or_vm raise exception.NotFound( _('Instance not present %s') % instance_name) return vm @@ -482,7 +470,7 @@ class VMOps(object): mac_id = instance.mac_address.replace(':', '') location = 'vm-data/networking/%s' % mac_id - #TODO(salvatore-orlando): key for broadcast address + #salvatore-orlando: key for broadcast address #provisionally set to 'broadcast' mapping = {'label': network['label'], 'gateway': network['gateway'], -- cgit From e7626da8ade4a3d29d441fed1c21c50cbc9928de Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Tue, 8 Mar 2011 23:33:17 +0000 Subject: using get_uuid in place of get_record in _get_vm_opaqueref changed SessionBase._getter in fake xenapi in order to return HANDLE_INVALID failure when reference is not in DB (was NotImplementedException) --- nova/virt/xenapi/fake.py | 11 ++++++----- nova/virt/xenapi/vmops.py | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py index 09e381e2c..eecfa20b1 100644 --- a/nova/virt/xenapi/fake.py +++ b/nova/virt/xenapi/fake.py @@ -400,7 +400,6 @@ class SessionBase(object): def _getter(self, name, params): self._check_session(params) (cls, func) = name.split('.') - if func == 'get_all': self._check_arg_count(params, 1) return get_all(cls) @@ -423,10 +422,12 @@ class SessionBase(object): if len(params) == 2: field = func[len('get_'):] ref = params[1] - - if (ref in _db_content[cls] and - field in _db_content[cls][ref]): - return _db_content[cls][ref][field] + if (ref in _db_content[cls]): + if (field in _db_content[cls][ref]): + return _db_content[cls][ref][field] + else: + LOG.debug(_('Raising Failure')) + raise Failure(['HANDLE_INVALID', cls, ref]) LOG.debug(_('Raising NotImplemented')) raise NotImplementedError( diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index ddd5b0e16..273a7ba38 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -198,7 +198,7 @@ class VMOps(object): obj = None try: # check for opaque ref - obj = self._session.get_xenapi().VM.get_record(instance_or_vm) + obj = self._session.get_xenapi().VM.get_uuid(instance_or_vm) return instance_or_vm except self.XenAPI.Failure: # wasn't an opaque ref, can be an instance name -- cgit From 745ade6a7759915eefe39eedc9be7e526df32547 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Fri, 18 Mar 2011 10:36:57 +0000 Subject: Fixed issue arisen from recent feature update (utils.execute) --- nova/virt/xenapi/vm_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index eaf5bb391..287a293f0 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -699,8 +699,8 @@ class VMHelper(HelperBase): try: out, err = utils.execute('sudo', 'mount', '-t', 'ext2,ext3', - '"%s"' % dev_path, - '"%s"' % tmpdir) + '%s' % dev_path, + '%s' % tmpdir) except exception.ProcessExecutionError as e: err = str(e) if err: -- cgit From 52bd70d500e7e82acea55c8d23c3fd1d66555cc0 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Thu, 24 Mar 2011 02:01:46 +0000 Subject: Addressing Rick Clark's comments. --- nova/virt/disk.py | 9 ++-- nova/virt/xenapi/fake.py | 1 - nova/virt/xenapi/vm_utils.py | 125 +++++++++++++++++++++++-------------------- nova/virt/xenapi/vmops.py | 1 - nova/virt/xenapi_conn.py | 20 +++---- 5 files changed, 82 insertions(+), 74 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/disk.py b/nova/virt/disk.py index eae667c01..ee6d3e36a 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -166,12 +166,13 @@ def _free_device(device): def get_injectables(inst, template=None, template_data=None): - #load cheetah.template if necessary + # Note(salvatore-orlando): + # it the caller does not provide template object and data + # we will import the Cheetah template module and load the + # data from the file specified by injected_network_template flag if not template: - t = __import__('Cheetah.Template', globals(), locals(), ['Template'], - -1) + from Cheetah import Template as t template = t.Template - #load template file if necessary if not template_data: template_data = open(FLAGS.injected_network_template).read() diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py index 60db86ecd..18d558058 100644 --- a/nova/virt/xenapi/fake.py +++ b/nova/virt/xenapi/fake.py @@ -427,7 +427,6 @@ class SessionBase(object): if (field in _db_content[cls][ref]): return _db_content[cls][ref][field] else: - LOG.debug(_('Raising Failure')) raise Failure(['HANDLE_INVALID', cls, ref]) LOG.debug(_('Raising NotImplemented')) diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 7b6f2b5da..d429dae3c 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -683,65 +683,12 @@ class VMHelper(HelperBase): # everything mount_required = False key, net = disk.get_injectables(instance) - if key is not None or net is not None: - mount_required = True - - if mount_required: - - def _mounted_processing(device): - """Callback which runs with the image VDI attached""" + mount_required = key or net + if not mount_required: + return - dev_path = '/dev/' + device + '1' # NB: Partition 1 hardcoded - tmpdir = tempfile.mkdtemp() - try: - # Mount only Linux filesystems, to avoid disturbing - # NTFS images - try: - out, err = utils.execute('sudo', 'mount', - '-t', 'ext2,ext3', - dev_path, tmpdir) - except exception.ProcessExecutionError as e: - err = str(e) - if err: - LOG.info(_('Failed to mount filesystem (expected for ' - 'non-linux instances): %s') % err) - else: - try: - # This try block ensures that the umount occurs - xe_guest_agent_filename = os.path.join( - tmpdir, FLAGS.xenapi_agent_path) - if os.path.isfile(xe_guest_agent_filename): - # The presence of the guest agent - # file indicates that this instance can - # reconfigure the network from xenstore data, - # so manipulation of files in /etc is not - # required - LOG.info(_('XenServer tools installed in this ' - 'image are capable of network injection. ' - 'Networking files will not be' - 'manipulated')) - else: - xe_daemon_filename = os.path.join(tmpdir, - 'usr', 'sbin', 'xe-daemon') - if os.path.isfile(xe_daemon_filename): - LOG.info(_('XenServer tools are present ' - 'in this image but are not capable ' - 'of network injection')) - else: - LOG.info(_('XenServer tools are not ' - 'installed in this image')) - LOG.info(_('Manipulating interface files ' - 'directly')) - disk.inject_data_into_fs(tmpdir, key, net, - utils.execute) - finally: - utils.execute('sudo', 'umount', dev_path) - finally: - # remove temporary directory - os.rmdir(tmpdir) - - with_vdi_attached_here(session, vdi_ref, False, - _mounted_processing) + with_vdi_attached_here(session, vdi_ref, False, + lambda dev: _mounted_processing(dev, key, net)) @classmethod def lookup_kernel_ramdisk(cls, session, vm): @@ -1077,3 +1024,65 @@ def _write_partition(virtual_size, dev): def get_name_label_for_image(image): # TODO(sirp): This should eventually be the URI for the Glance image return _('Glance image %s') % image + + +def _mount_filesystem(dev_path, dir): + """mounts the device specified by dev_path in dir""" + try: + out, err = utils.execute('sudo', 'mount', + '-t', 'ext2,ext3', + dev_path, dir) + except exception.ProcessExecutionError as e: + err = str(e) + return err + + +def _find_guest_agent(base_dir, agent_rel_path): + agent_path = os.path.join(base_dir, agent_rel_path) + if os.path.isfile(agent_path): + # The presence of the guest agent + # file indicates that this instance can + # reconfigure the network from xenstore data, + # so manipulation of files in /etc is not + # required + LOG.info(_('XenServer tools installed in this ' + 'image are capable of network injection. ' + 'Networking files will not be' + 'manipulated')) + return True + xe_daemon_filename = os.path.join(base_dir, + 'usr', 'sbin', 'xe-daemon') + if os.path.isfile(xe_daemon_filename): + LOG.info(_('XenServer tools are present ' + 'in this image but are not capable ' + 'of network injection')) + else: + LOG.info(_('XenServer tools are not ' + 'installed in this image')) + return False + + +def _mounted_processing(device, key, net): + """Callback which runs with the image VDI attached""" + + dev_path = '/dev/' + device + '1' # NB: Partition 1 hardcoded + tmpdir = tempfile.mkdtemp() + try: + # Mount only Linux filesystems, to avoid disturbing NTFS images + err = _mount_filesystem(dev_path, tmpdir) + if not err: + try: + # This try block ensures that the umount occurs + if not _find_guest_agent(tmpdir, FLAGS.xenapi_agent_path): + LOG.info(_('Manipulating interface files ' + 'directly')) + disk.inject_data_into_fs(tmpdir, key, net, + utils.execute) + finally: + utils.execute('sudo', 'umount', dev_path) + else: + LOG.info(_('Failed to mount filesystem (expected for ' + 'non-linux instances): %s') % err) + finally: + # remove temporary directory + os.rmdir(tmpdir) diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 59c5f3c13..e3810e218 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -169,7 +169,6 @@ class VMOps(object): def _wait_for_boot(): try: - LOG.debug("ENTERING WAIT FOR BOOT!") state = self.get_info(instance_name)['state'] db.instance_set_state(context.get_admin_context(), instance['id'], state) diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 4f31f1071..7c3d3544f 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -107,17 +107,17 @@ flags.DEFINE_integer('xenapi_vhd_coalesce_max_attempts', 'Max number of times to poll for VHD to coalesce.' ' Used only if connection_type=xenapi.') flags.DEFINE_bool('xenapi_inject_image', - True, - 'Specifies whether an attempt to inject network/key' - ' data into the disk image should be made.' - ' Used only if connection_type=xenapi.') + True, + 'Specifies whether an attempt to inject network/key' + ' data into the disk image should be made.' + ' Used only if connection_type=xenapi.') flags.DEFINE_string('xenapi_agent_path', - 'usr/sbin/xe-update-networking', - 'Specifies the path in which the xenapi guest agent' - ' should be located. If the agent is present,' - ' network configuration if not injected into the image' - ' Used only if connection_type=xenapi.' - ' and xenapi_inject_image=True') + 'usr/sbin/xe-update-networking', + 'Specifies the path in which the xenapi guest agent' + ' should be located. If the agent is present,' + ' network configuration if not injected into the image' + ' Used only if connection_type=xenapi.' + ' and xenapi_inject_image=True') flags.DEFINE_string('xenapi_sr_base_path', '/var/run/sr-mount', 'Base path to the storage repository') -- cgit From 08d40029973d9ca97477393531296502a407debe Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Thu, 24 Mar 2011 22:39:39 +0000 Subject: Addressing Trey's comments. Removed disk_get_injectables, using _get_network_info's return value. --- nova/virt/disk.py | 37 --------------------------------- nova/virt/libvirt_conn.py | 31 +++++++++++++++++++++++++++- nova/virt/xenapi/vm_utils.py | 49 +++++++++++++++++++++++++++++++++++++++++--- nova/virt/xenapi/vmops.py | 10 +++++---- nova/virt/xenapi_conn.py | 2 +- 5 files changed, 83 insertions(+), 46 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/disk.py b/nova/virt/disk.py index ee6d3e36a..25e4f54a9 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -165,43 +165,6 @@ def _free_device(device): _DEVICES.append(device) -def get_injectables(inst, template=None, template_data=None): - # Note(salvatore-orlando): - # it the caller does not provide template object and data - # we will import the Cheetah template module and load the - # data from the file specified by injected_network_template flag - if not template: - from Cheetah import Template as t - template = t.Template - if not template_data: - template_data = open(FLAGS.injected_network_template).read() - - key = str(inst['key_data']) - net = None - network_ref = db.network_get_by_instance(context.get_admin_context(), - inst['id']) - if network_ref['injected']: - admin_context = context.get_admin_context() - address = db.instance_get_fixed_address(admin_context, inst['id']) - address_v6 = None - if FLAGS.use_ipv6: - address_v6 = db.instance_get_fixed_address_v6(admin_context, - inst['id']) - interfaces_info = {'address': address, - 'netmask': network_ref['netmask'], - 'gateway': network_ref['gateway'], - 'broadcast': network_ref['broadcast'], - 'dns': network_ref['dns'], - 'address_v6': address_v6, - 'gateway_v6': network_ref['gateway_v6'], - 'netmask_v6': network_ref['netmask_v6'], - 'use_ipv6': FLAGS.use_ipv6} - net = str(template(template_data, - searchList=[interfaces_info])) - - return key, net - - def inject_data_into_fs(fs, key, net, execute): """Injects data into a filesystem already mounted by the caller. Virt connections can call this directly if they mount their fs diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 4b855f5de..f6a51fc62 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -681,7 +681,36 @@ class LibvirtConnection(driver.ComputeDriver): if not inst['kernel_id']: target_partition = "1" - key, net = disk.get_injectables(inst, Template, self.interfaces_xml) + key = str(inst['key_data']) + net = None + + nets = [] + ifc_template = open(FLAGS.injected_network_template).read() + ifc_num = -1 + admin_context = context.get_admin_context() + for (network_ref, mapping) in network_info: + ifc_num += 1 + + if not 'injected' in network_ref: + continue + + address = mapping['ips'][0]['ip'] + address_v6 = None + if FLAGS.use_ipv6: + address_v6 = mapping['ip6s'][0]['ip'] + net_info = {'name': 'eth%d' % ifc_num, + 'address': address, + 'netmask': network_ref['netmask'], + 'gateway': network_ref['gateway'], + 'broadcast': network_ref['broadcast'], + 'dns': network_ref['dns'], + 'address_v6': address_v6, + 'gateway_v6': network_ref['gateway_v6'], + 'netmask_v6': network_ref['netmask_v6'], + 'use_ipv6': FLAGS.use_ipv6} + nets.append(net_info) + + net = str(Template(ifc_template, searchList=[{'interfaces': nets}])) if key or net: inst_name = inst['name'] diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index d429dae3c..5f66c4237 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -674,7 +674,7 @@ class VMHelper(HelperBase): return None @classmethod - def preconfigure_instance(cls, session, instance, vdi_ref): + def preconfigure_instance(cls, session, instance, vdi_ref, network_info): """Makes alterations to the image before launching as part of spawn. """ @@ -682,11 +682,11 @@ class VMHelper(HelperBase): # if at all, so determine whether it's required first, and then do # everything mount_required = False - key, net = disk.get_injectables(instance) + key, net = _prepare_injectables(instance, network_info) mount_required = key or net if not mount_required: return - + with_vdi_attached_here(session, vdi_ref, False, lambda dev: _mounted_processing(dev, key, net)) @@ -1038,6 +1038,10 @@ def _mount_filesystem(dev_path, dir): def _find_guest_agent(base_dir, agent_rel_path): + """ + tries to locate a guest agent at the path + specificed by agent_rel_path + """ agent_path = os.path.join(base_dir, agent_rel_path) if os.path.isfile(agent_path): # The presence of the guest agent @@ -1086,3 +1090,42 @@ def _mounted_processing(device, key, net): finally: # remove temporary directory os.rmdir(tmpdir) + + +def _prepare_injectables(inst, networks_info): + """ + prepares the ssh key and the network configuration file to be + injected into the disk image + """ + #do the import here - Cheetah.Template will be loaded + #only if injection is performed + from Cheetah import Template as t + template = t.Template + template_data = open(FLAGS.injected_network_template).read() + + key = str(inst['key_data']) + net = None + #fetch info only for the 1st network + if len(networks_info) > 0: + network_info = networks_info[0][1] + if network_info: + #remap data in network_info onto keys for template + ip_v4 = ip_v6 = None + if len(network_info['ips']) > 0: + ip_v4 = network_info['ips'][0] + if len(network_info['ip6s']) > 0: + ip_v6 = network_info['ip6s'][0] + if len(network_info['dns']) > 0: + dns = network_info['dns'][0] + interfaces_info = {'address': ip_v4 and ip_v4['ip'] or '', + 'netmask': ip_v4 and ip_v4['netmask'] or '', + 'gateway': network_info['gateway'], + 'broadcast': network_info['broadcast'], + 'dns': dns, + 'address_v6': ip_v6 and ip_v6['ip'] or '', + 'netmask_v6': ip_v6 and ip_v6['netmask'] or '', + 'gateway_v6': ip_v6 and ip_v6['gateway'] or '', + 'use_ipv6': FLAGS.use_ipv6} + net = str(template(template_data, + searchList=[interfaces_info])) + return key, net \ No newline at end of file diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 8e5302766..b33b5902c 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -161,14 +161,16 @@ class VMOps(object): VMHelper.create_vbd(session=self._session, vm_ref=vm_ref, vdi_ref=vdi_ref, userdevice=0, bootable=True) - # Alter the image before VM start for, e.g. network injection - if FLAGS.xenapi_inject_image: - VMHelper.preconfigure_instance(self._session, instance, vdi_ref) - # TODO(tr3buchet) - check to make sure we have network info, otherwise # create it now. This goes away once nova-multi-nic hits. if network_info is None: network_info = self._get_network_info(instance) + + # Alter the image before VM start for, e.g. network injection + if FLAGS.xenapi_inject_image: + VMHelper.preconfigure_instance(self._session, instance, + vdi_ref, network_info) + self.create_vifs(vm_ref, network_info) self.inject_network_info(instance, vm_ref, network_info) return vm_ref diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 0c234cb52..99fd35c61 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -116,7 +116,7 @@ flags.DEFINE_string('xenapi_agent_path', 'usr/sbin/xe-update-networking', 'Specifies the path in which the xenapi guest agent' ' should be located. If the agent is present,' - ' network configuration if not injected into the image' + ' network configuration is not injected into the image' ' Used only if connection_type=xenapi.' ' and xenapi_inject_image=True') -- cgit