From c128dbc74a1a2d5633bfcca1354cc22eba2e51ab Mon Sep 17 00:00:00 2001 From: Bob Ball Date: Tue, 13 Aug 2013 15:07:14 +0100 Subject: [PATCH] XenAPI: Support local connections Currently there is no way to connect to XAPI through the unix socket, requiring a URL and credentials. This change allows you to run in dom0 (particularly in xenserver-core environments) and connect to XAPI using the unix domain socket by specifying "unix://local" DocImpact Change-Id: I3d5ace31c9c0411fa711cfdf87383d36f61bfa4a --- etc/nova/nova.conf.sample | 6 ++++-- nova/tests/virt/xenapi/stubs.py | 2 +- nova/tests/virt/xenapi/test_vm_utils.py | 5 +++-- nova/tests/virt/xenapi/test_xenapi.py | 24 ++++++++++++++++++++++-- nova/virt/xenapi/driver.py | 5 +++++ nova/virt/xenapi/pool.py | 2 +- nova/virt/xenapi/vm_utils.py | 13 ++++++++++--- 7 files changed, 46 insertions(+), 11 deletions(-) diff --git a/etc/nova/nova.conf.sample b/etc/nova/nova.conf.sample index 6b099e1e692c..612e66e50c7f 100644 --- a/etc/nova/nova.conf.sample +++ b/etc/nova/nova.conf.sample @@ -2194,8 +2194,10 @@ # Options defined in nova.virt.xenapi.driver # -# URL for connection to XenServer/Xen Cloud Platform. Required -# if compute_driver=xenapi.XenAPIDriver (string value) +# URL for connection to XenServer/Xen Cloud Platform. A +# special value of unix://local can be used to connect to the +# local unix socket. Required if +# compute_driver=xenapi.XenAPIDriver (string value) #xenapi_connection_url= # Username for connection to XenServer/Xen Cloud Platform. diff --git a/nova/tests/virt/xenapi/stubs.py b/nova/tests/virt/xenapi/stubs.py index 56a397a8a298..c60c4c93e409 100644 --- a/nova/tests/virt/xenapi/stubs.py +++ b/nova/tests/virt/xenapi/stubs.py @@ -62,7 +62,7 @@ def stubout_session(stubs, cls, product_version=(5, 6, 2), def stubout_get_this_vm_uuid(stubs): - def f(): + def f(session): vms = [rec['uuid'] for ref, rec in fake.get_all_records('VM').iteritems() if rec['is_control_domain']] diff --git a/nova/tests/virt/xenapi/test_vm_utils.py b/nova/tests/virt/xenapi/test_vm_utils.py index 29e712d16e83..8f998e2c04f2 100644 --- a/nova/tests/virt/xenapi/test_vm_utils.py +++ b/nova/tests/virt/xenapi/test_vm_utils.py @@ -187,7 +187,7 @@ class XenAPIGetUUID(test.TestCase): self.mox.ReplayAll() self.assertEquals('2f46f0f5-f14c-ef1b-1fac-9eeca0888a3f', - vm_utils.get_this_vm_uuid()) + vm_utils.get_this_vm_uuid(None)) self.mox.VerifyAll() def test_get_this_vm_uuid_old_kernel_reboot(self): @@ -204,7 +204,7 @@ class XenAPIGetUUID(test.TestCase): self.mox.ReplayAll() self.assertEquals('2f46f0f5-f14c-ef1b-1fac-9eeca0888a3f', - vm_utils.get_this_vm_uuid()) + vm_utils.get_this_vm_uuid(None)) self.mox.VerifyAll() @@ -891,6 +891,7 @@ class GenerateDiskTestCase(stubs.XenAPITestBase): stubs.stubout_session(self.stubs, fake.SessionBase) driver = xenapi_conn.XenAPIDriver(False) self.session = driver._session + self.session.is_local_connection = False self.vm_ref = fake.create_vm("foo", "Running") def tearDown(self): diff --git a/nova/tests/virt/xenapi/test_xenapi.py b/nova/tests/virt/xenapi/test_xenapi.py index aa51a64a420c..eeda2261c591 100644 --- a/nova/tests/virt/xenapi/test_xenapi.py +++ b/nova/tests/virt/xenapi/test_xenapi.py @@ -325,6 +325,7 @@ class XenAPIVMTestCase(stubs.XenAPITestBase): self.project_id = 'fake' self.context = context.RequestContext(self.user_id, self.project_id) self.conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False) + self.conn._session.is_local_connection = False fake_image.stub_out_image_service(self.stubs) set_image_fixtures() @@ -3653,14 +3654,33 @@ class XenAPIInjectMetadataTestCase(stubs.XenAPITestBase): class XenAPISessionTestCase(test.TestCase): def _get_mock_xapisession(self, software_version): - class XcpXapiSession(xenapi_conn.XenAPISession): + class MockXapiSession(xenapi_conn.XenAPISession): def __init__(_ignore): "Skip the superclass's dirty init" def _get_software_version(_ignore): return software_version - return XcpXapiSession() + return MockXapiSession() + + def test_local_session(self): + session = self._get_mock_xapisession({}) + session.is_local_connection = True + session.XenAPI = self.mox.CreateMockAnything() + session.XenAPI.xapi_local().AndReturn("local_connection") + + self.mox.ReplayAll() + self.assertEqual("local_connection", + session._create_session("unix://local")) + + def test_remote_session(self): + session = self._get_mock_xapisession({}) + session.is_local_connection = False + session.XenAPI = self.mox.CreateMockAnything() + session.XenAPI.Session("url").AndReturn("remote_connection") + + self.mox.ReplayAll() + self.assertEqual("remote_connection", session._create_session("url")) def test_get_product_version_product_brand_does_not_fail(self): session = self._get_mock_xapisession({ diff --git a/nova/virt/xenapi/driver.py b/nova/virt/xenapi/driver.py index 217e6d5399c0..b561d3d20664 100755 --- a/nova/virt/xenapi/driver.py +++ b/nova/virt/xenapi/driver.py @@ -66,6 +66,8 @@ LOG = logging.getLogger(__name__) xenapi_opts = [ cfg.StrOpt('xenapi_connection_url', help='URL for connection to XenServer/Xen Cloud Platform. ' + 'A special value of unix://local can be used to connect ' + 'to the local unix socket. ' 'Required if compute_driver=xenapi.XenAPIDriver'), cfg.StrOpt('xenapi_connection_username', default='root', @@ -782,6 +784,9 @@ class XenAPISession(object): def _create_session(self, url): """Stubout point. This can be replaced with a mock session.""" + self.is_local_connection = url == "unix://local" + if self.is_local_connection: + return self.XenAPI.xapi_local() return self.XenAPI.Session(url) def _unwrap_plugin_exceptions(self, func, *args, **kwargs): diff --git a/nova/virt/xenapi/pool.py b/nova/virt/xenapi/pool.py index 43025ea279c4..4a519a1d58fa 100644 --- a/nova/virt/xenapi/pool.py +++ b/nova/virt/xenapi/pool.py @@ -249,7 +249,7 @@ class ResourcePool(object): "url": sender_url, "user": CONF.xenapi_connection_username, "passwd": CONF.xenapi_connection_password, - "compute_uuid": vm_utils.get_this_vm_uuid(), + "compute_uuid": vm_utils.get_this_vm_uuid(None), "xenhost_uuid": self._host_uuid, } diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 84618ad22091..d93a273fc9db 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -1878,7 +1878,14 @@ def _get_sys_hypervisor_uuid(): return f.readline().strip() -def get_this_vm_uuid(): +def get_this_vm_uuid(session): + if session and session.is_local_connection: + # UUID is the control domain running on this host + host_ref = session.get_xenapi_host() + vms = session.call_xenapi("VM.get_all_records_where", + 'field "is_control_domain"="true" and ' + 'field "resident_on"="%s"' % host_ref) + return vms[vms.keys()[0]]['uuid'] try: return _get_sys_hypervisor_uuid() except IOError: @@ -1893,7 +1900,7 @@ def get_this_vm_uuid(): def _get_this_vm_ref(session): - return session.call_xenapi("VM.get_by_uuid", get_this_vm_uuid()) + return session.call_xenapi("VM.get_by_uuid", get_this_vm_uuid(session)) def _get_partitions(dev): @@ -2240,7 +2247,7 @@ def ensure_correct_host(session): """Ensure we're connected to the host we're running on. This is the required configuration for anything that uses vdi_attached_here. """ - this_vm_uuid = get_this_vm_uuid() + this_vm_uuid = get_this_vm_uuid(session) try: session.call_xenapi('VM.get_by_uuid', this_vm_uuid)