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
This commit is contained in:
Bob Ball
2013-08-13 15:07:14 +01:00
parent dcc61f35e7
commit c128dbc74a
7 changed files with 46 additions and 11 deletions

View File

@@ -2194,8 +2194,10 @@
# Options defined in nova.virt.xenapi.driver # Options defined in nova.virt.xenapi.driver
# #
# URL for connection to XenServer/Xen Cloud Platform. Required # URL for connection to XenServer/Xen Cloud Platform. A
# if compute_driver=xenapi.XenAPIDriver (string value) # 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=<None> #xenapi_connection_url=<None>
# Username for connection to XenServer/Xen Cloud Platform. # Username for connection to XenServer/Xen Cloud Platform.

View File

@@ -62,7 +62,7 @@ def stubout_session(stubs, cls, product_version=(5, 6, 2),
def stubout_get_this_vm_uuid(stubs): def stubout_get_this_vm_uuid(stubs):
def f(): def f(session):
vms = [rec['uuid'] for ref, rec vms = [rec['uuid'] for ref, rec
in fake.get_all_records('VM').iteritems() in fake.get_all_records('VM').iteritems()
if rec['is_control_domain']] if rec['is_control_domain']]

View File

@@ -187,7 +187,7 @@ class XenAPIGetUUID(test.TestCase):
self.mox.ReplayAll() self.mox.ReplayAll()
self.assertEquals('2f46f0f5-f14c-ef1b-1fac-9eeca0888a3f', self.assertEquals('2f46f0f5-f14c-ef1b-1fac-9eeca0888a3f',
vm_utils.get_this_vm_uuid()) vm_utils.get_this_vm_uuid(None))
self.mox.VerifyAll() self.mox.VerifyAll()
def test_get_this_vm_uuid_old_kernel_reboot(self): def test_get_this_vm_uuid_old_kernel_reboot(self):
@@ -204,7 +204,7 @@ class XenAPIGetUUID(test.TestCase):
self.mox.ReplayAll() self.mox.ReplayAll()
self.assertEquals('2f46f0f5-f14c-ef1b-1fac-9eeca0888a3f', self.assertEquals('2f46f0f5-f14c-ef1b-1fac-9eeca0888a3f',
vm_utils.get_this_vm_uuid()) vm_utils.get_this_vm_uuid(None))
self.mox.VerifyAll() self.mox.VerifyAll()
@@ -891,6 +891,7 @@ class GenerateDiskTestCase(stubs.XenAPITestBase):
stubs.stubout_session(self.stubs, fake.SessionBase) stubs.stubout_session(self.stubs, fake.SessionBase)
driver = xenapi_conn.XenAPIDriver(False) driver = xenapi_conn.XenAPIDriver(False)
self.session = driver._session self.session = driver._session
self.session.is_local_connection = False
self.vm_ref = fake.create_vm("foo", "Running") self.vm_ref = fake.create_vm("foo", "Running")
def tearDown(self): def tearDown(self):

View File

@@ -325,6 +325,7 @@ class XenAPIVMTestCase(stubs.XenAPITestBase):
self.project_id = 'fake' self.project_id = 'fake'
self.context = context.RequestContext(self.user_id, self.project_id) self.context = context.RequestContext(self.user_id, self.project_id)
self.conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False) self.conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
self.conn._session.is_local_connection = False
fake_image.stub_out_image_service(self.stubs) fake_image.stub_out_image_service(self.stubs)
set_image_fixtures() set_image_fixtures()
@@ -3653,14 +3654,33 @@ class XenAPIInjectMetadataTestCase(stubs.XenAPITestBase):
class XenAPISessionTestCase(test.TestCase): class XenAPISessionTestCase(test.TestCase):
def _get_mock_xapisession(self, software_version): def _get_mock_xapisession(self, software_version):
class XcpXapiSession(xenapi_conn.XenAPISession): class MockXapiSession(xenapi_conn.XenAPISession):
def __init__(_ignore): def __init__(_ignore):
"Skip the superclass's dirty init" "Skip the superclass's dirty init"
def _get_software_version(_ignore): def _get_software_version(_ignore):
return software_version 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): def test_get_product_version_product_brand_does_not_fail(self):
session = self._get_mock_xapisession({ session = self._get_mock_xapisession({

View File

@@ -66,6 +66,8 @@ LOG = logging.getLogger(__name__)
xenapi_opts = [ xenapi_opts = [
cfg.StrOpt('xenapi_connection_url', cfg.StrOpt('xenapi_connection_url',
help='URL for connection to XenServer/Xen Cloud Platform. ' 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'), 'Required if compute_driver=xenapi.XenAPIDriver'),
cfg.StrOpt('xenapi_connection_username', cfg.StrOpt('xenapi_connection_username',
default='root', default='root',
@@ -782,6 +784,9 @@ class XenAPISession(object):
def _create_session(self, url): def _create_session(self, url):
"""Stubout point. This can be replaced with a mock session.""" """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) return self.XenAPI.Session(url)
def _unwrap_plugin_exceptions(self, func, *args, **kwargs): def _unwrap_plugin_exceptions(self, func, *args, **kwargs):

View File

@@ -249,7 +249,7 @@ class ResourcePool(object):
"url": sender_url, "url": sender_url,
"user": CONF.xenapi_connection_username, "user": CONF.xenapi_connection_username,
"passwd": CONF.xenapi_connection_password, "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, "xenhost_uuid": self._host_uuid,
} }

View File

@@ -1878,7 +1878,14 @@ def _get_sys_hypervisor_uuid():
return f.readline().strip() 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: try:
return _get_sys_hypervisor_uuid() return _get_sys_hypervisor_uuid()
except IOError: except IOError:
@@ -1893,7 +1900,7 @@ def get_this_vm_uuid():
def _get_this_vm_ref(session): 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): 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 """Ensure we're connected to the host we're running on. This is the
required configuration for anything that uses vdi_attached_here. 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: try:
session.call_xenapi('VM.get_by_uuid', this_vm_uuid) session.call_xenapi('VM.get_by_uuid', this_vm_uuid)