z/VM Driver: Initial change set of z/VM driver
This is the first change that implements basic virt.driver methods to allow nova-compute process start successfully. A set of subsequent changes will implement spawn, snapshot, destroy and instance power actions. Change-Id: Ica6117c2c64f7518b78b7fb02487622250638e88 blueprint: add-zvm-driver-rocky
This commit is contained in:
parent
6ee633a971
commit
e5acf4f961
|
@ -170,3 +170,4 @@ WebOb==1.8.2
|
||||||
websockify==0.8.0
|
websockify==0.8.0
|
||||||
wrapt==1.10.11
|
wrapt==1.10.11
|
||||||
wsgi-intercept==1.7.0
|
wsgi-intercept==1.7.0
|
||||||
|
zVMCloudConnector==1.1.1
|
||||||
|
|
|
@ -70,6 +70,7 @@ from nova.conf import workarounds
|
||||||
from nova.conf import wsgi
|
from nova.conf import wsgi
|
||||||
from nova.conf import xenserver
|
from nova.conf import xenserver
|
||||||
from nova.conf import xvp
|
from nova.conf import xvp
|
||||||
|
from nova.conf import zvm
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
@ -123,5 +124,6 @@ workarounds.register_opts(CONF)
|
||||||
wsgi.register_opts(CONF)
|
wsgi.register_opts(CONF)
|
||||||
xenserver.register_opts(CONF)
|
xenserver.register_opts(CONF)
|
||||||
xvp.register_opts(CONF)
|
xvp.register_opts(CONF)
|
||||||
|
zvm.register_opts(CONF)
|
||||||
|
|
||||||
remote_debug.register_cli_opts(CONF)
|
remote_debug.register_cli_opts(CONF)
|
||||||
|
|
|
@ -43,6 +43,7 @@ Possible values:
|
||||||
* ``vmwareapi.VMwareVCDriver``
|
* ``vmwareapi.VMwareVCDriver``
|
||||||
* ``hyperv.HyperVDriver``
|
* ``hyperv.HyperVDriver``
|
||||||
* ``powervm.PowerVMDriver``
|
* ``powervm.PowerVMDriver``
|
||||||
|
* ``zvm.ZVMDriver``
|
||||||
"""),
|
"""),
|
||||||
cfg.BoolOpt('allow_resize_to_same_host',
|
cfg.BoolOpt('allow_resize_to_same_host',
|
||||||
default=False,
|
default=False,
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
# Copyright 2017,2018 IBM Corp.
|
||||||
|
#
|
||||||
|
# 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 oslo_config import cfg
|
||||||
|
|
||||||
|
|
||||||
|
zvm_opt_group = cfg.OptGroup('zvm',
|
||||||
|
title='zVM Options',
|
||||||
|
help="""
|
||||||
|
zvm options allows cloud administrator to configure related
|
||||||
|
z/VM hypervisor driver to be used within an OpenStack deployment.
|
||||||
|
|
||||||
|
zVM options are used when the compute_driver is set to use
|
||||||
|
zVM (compute_driver=zvm.ZVMDriver)
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
zvm_opts = [
|
||||||
|
cfg.URIOpt('cloud_connector_url',
|
||||||
|
sample_default='http://zvm.example.org:8080/',
|
||||||
|
help="""
|
||||||
|
URL to be used to communicate with z/VM Cloud Connector.
|
||||||
|
"""),
|
||||||
|
cfg.StrOpt('ca_file',
|
||||||
|
default=None,
|
||||||
|
help="""
|
||||||
|
CA certificate file to be verified in httpd server with TLS enabled
|
||||||
|
|
||||||
|
A string, it must be a path to a CA bundle to use.
|
||||||
|
"""),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def register_opts(conf):
|
||||||
|
conf.register_group(zvm_opt_group)
|
||||||
|
conf.register_opts(zvm_opts, group=zvm_opt_group)
|
||||||
|
|
||||||
|
|
||||||
|
def list_opts():
|
||||||
|
return {zvm_opt_group: zvm_opts}
|
|
@ -2312,3 +2312,24 @@ class InstanceUnRescueFailure(NovaException):
|
||||||
|
|
||||||
class IronicAPIVersionNotAvailable(NovaException):
|
class IronicAPIVersionNotAvailable(NovaException):
|
||||||
msg_fmt = _('Ironic API version %(version)s is not available.')
|
msg_fmt = _('Ironic API version %(version)s is not available.')
|
||||||
|
|
||||||
|
|
||||||
|
class ZVMDriverException(NovaException):
|
||||||
|
msg_fmt = _("ZVM Driver has error: %(error)s")
|
||||||
|
|
||||||
|
|
||||||
|
class ZVMConnectorError(ZVMDriverException):
|
||||||
|
msg_fmt = _("zVM Cloud Connector request failed: %(results)s")
|
||||||
|
|
||||||
|
def __init__(self, message=None, **kwargs):
|
||||||
|
"""Exception for zVM ConnectorClient calls.
|
||||||
|
|
||||||
|
:param results: The object returned from ZVMConnector.send_request.
|
||||||
|
"""
|
||||||
|
super(ZVMConnectorError, self).__init__(message=message, **kwargs)
|
||||||
|
|
||||||
|
results = kwargs.get('results', {})
|
||||||
|
self.overallRC = results.get('overallRC')
|
||||||
|
self.rc = results.get('rc')
|
||||||
|
self.rs = results.get('rs')
|
||||||
|
self.errmsg = results.get('errmsg')
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Copyright 2017,2018 IBM Corp.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from nova import exception
|
||||||
|
from nova import test
|
||||||
|
from nova.virt.zvm import driver as zvmdriver
|
||||||
|
|
||||||
|
|
||||||
|
class TestZVMDriver(test.NoDBTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestZVMDriver, self).setUp()
|
||||||
|
self.flags(cloud_connector_url='https://1.1.1.1:1111', group='zvm')
|
||||||
|
with mock.patch('nova.virt.zvm.utils.'
|
||||||
|
'ConnectorClient.call') as mcall:
|
||||||
|
mcall.return_value = {'hypervisor_hostname': 'TESTHOST'}
|
||||||
|
self._driver = zvmdriver.ZVMDriver('virtapi')
|
||||||
|
|
||||||
|
def test_driver_init_no_url(self):
|
||||||
|
self.flags(cloud_connector_url=None, group='zvm')
|
||||||
|
self.assertRaises(exception.ZVMDriverException,
|
||||||
|
zvmdriver.ZVMDriver, 'virtapi')
|
||||||
|
|
||||||
|
@mock.patch('nova.virt.zvm.utils.ConnectorClient.call')
|
||||||
|
def test_get_available_resource_err_case(self, call):
|
||||||
|
res = {'overallRC': 1, 'errmsg': 'err', 'rc': 0, 'rs': 0}
|
||||||
|
call.side_effect = exception.ZVMConnectorError(res)
|
||||||
|
results = self._driver.get_available_resource()
|
||||||
|
self.assertEqual(0, results['vcpus'])
|
||||||
|
self.assertEqual(0, results['memory_mb_used'])
|
||||||
|
self.assertEqual(0, results['disk_available_least'])
|
||||||
|
self.assertEqual('TESTHOST', results['hypervisor_hostname'])
|
|
@ -0,0 +1,69 @@
|
||||||
|
# Copyright 2017,2018 IBM Corp.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from nova import exception
|
||||||
|
from nova import test
|
||||||
|
from nova.virt.zvm import driver as zvmdriver
|
||||||
|
|
||||||
|
|
||||||
|
class TestZVMHypervisor(test.NoDBTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestZVMHypervisor, self).setUp()
|
||||||
|
self.flags(cloud_connector_url='https://1.1.1.1:1111', group='zvm')
|
||||||
|
with mock.patch('nova.virt.zvm.utils.'
|
||||||
|
'ConnectorClient.call') as mcall:
|
||||||
|
mcall.return_value = {'hypervisor_hostname': 'TESTHOST'}
|
||||||
|
driver = zvmdriver.ZVMDriver('virtapi')
|
||||||
|
self._hypervisor = driver._hypervisor
|
||||||
|
|
||||||
|
@mock.patch('nova.virt.zvm.utils.ConnectorClient.call')
|
||||||
|
def test_get_available_resource(self, call):
|
||||||
|
host_info = {'disk_available': 1144,
|
||||||
|
'ipl_time': 'IPL at 11/14/17 10:47:44 EST',
|
||||||
|
'vcpus_used': 4,
|
||||||
|
'hypervisor_type': 'zvm',
|
||||||
|
'disk_total': 2000,
|
||||||
|
'zvm_host': 'TESTHOST',
|
||||||
|
'memory_mb': 78192,
|
||||||
|
'cpu_info': {'cec_model': '2827',
|
||||||
|
'architecture': 's390x'},
|
||||||
|
'vcpus': 84,
|
||||||
|
'hypervisor_hostname': 'TESTHOST',
|
||||||
|
'hypervisor_version': 640,
|
||||||
|
'disk_used': 856,
|
||||||
|
'memory_mb_used': 8192}
|
||||||
|
call.return_value = host_info
|
||||||
|
results = self._hypervisor.get_available_resource()
|
||||||
|
self.assertEqual(host_info, results)
|
||||||
|
|
||||||
|
@mock.patch('nova.virt.zvm.utils.ConnectorClient.call')
|
||||||
|
def test_get_available_resource_err_case(self, call):
|
||||||
|
res = {'overallRC': 1, 'errmsg': 'err', 'rc': 0, 'rs': 0}
|
||||||
|
call.side_effect = exception.ZVMConnectorError(res)
|
||||||
|
results = self._hypervisor.get_available_resource()
|
||||||
|
# Should return an empty dict
|
||||||
|
self.assertFalse(results)
|
||||||
|
|
||||||
|
def test_get_available_nodes(self):
|
||||||
|
nodes = self._hypervisor.get_available_nodes()
|
||||||
|
self.assertEqual(['TESTHOST'], nodes)
|
||||||
|
|
||||||
|
@mock.patch('nova.virt.zvm.utils.ConnectorClient.call')
|
||||||
|
def test_list_names(self, call):
|
||||||
|
call.return_value = ['vm1', 'vm2']
|
||||||
|
inst_list = self._hypervisor.list_names()
|
||||||
|
self.assertEqual(['vm1', 'vm2'], inst_list)
|
|
@ -0,0 +1,81 @@
|
||||||
|
# Copyright 2017,2018 IBM Corp.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from zvmconnector import connector
|
||||||
|
|
||||||
|
from nova import exception
|
||||||
|
from nova import test
|
||||||
|
from nova.virt.zvm import utils as zvmutils
|
||||||
|
|
||||||
|
|
||||||
|
class TestZVMUtils(test.NoDBTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestZVMUtils, self).setUp()
|
||||||
|
self.flags(cloud_connector_url='http://127.0.0.1', group='zvm')
|
||||||
|
self._url = 'http://127.0.0.1'
|
||||||
|
|
||||||
|
def test_connector_request_handler_invalid_url(self):
|
||||||
|
rh = zvmutils.ConnectorClient('http://invalid')
|
||||||
|
self.assertRaises(exception.ZVMDriverException, rh.call, 'guest_list')
|
||||||
|
|
||||||
|
@mock.patch('zvmconnector.connector.ZVMConnector.__init__',
|
||||||
|
return_value=None)
|
||||||
|
def test_connector_request_handler_https(self, mock_init):
|
||||||
|
rh = zvmutils.ConnectorClient('https://127.0.0.1:80',
|
||||||
|
ca_file='/tmp/file')
|
||||||
|
mock_init.assert_called_once_with('127.0.0.1', 80, ssl_enabled=True,
|
||||||
|
verify='/tmp/file')
|
||||||
|
self.assertIsInstance(rh._conn, connector.ZVMConnector)
|
||||||
|
|
||||||
|
@mock.patch('zvmconnector.connector.ZVMConnector.__init__',
|
||||||
|
return_value=None)
|
||||||
|
def test_connector_request_handler_https_noca(self, mock_init):
|
||||||
|
rh = zvmutils.ConnectorClient('https://127.0.0.1:80')
|
||||||
|
mock_init.assert_called_once_with('127.0.0.1', 80, ssl_enabled=True,
|
||||||
|
verify=False)
|
||||||
|
self.assertIsInstance(rh._conn, connector.ZVMConnector)
|
||||||
|
|
||||||
|
@mock.patch('zvmconnector.connector.ZVMConnector.__init__',
|
||||||
|
return_value=None)
|
||||||
|
def test_connector_request_handler_http(self, mock_init):
|
||||||
|
rh = zvmutils.ConnectorClient('http://127.0.0.1:80')
|
||||||
|
mock_init.assert_called_once_with('127.0.0.1', 80, ssl_enabled=False,
|
||||||
|
verify=False)
|
||||||
|
self.assertIsInstance(rh._conn, connector.ZVMConnector)
|
||||||
|
|
||||||
|
@mock.patch('zvmconnector.connector.ZVMConnector.send_request')
|
||||||
|
def test_connector_request_handler(self, mock_send):
|
||||||
|
mock_send.return_value = {'overallRC': 0, 'output': 'data',
|
||||||
|
'rc': 0, 'rs': 0}
|
||||||
|
rh = zvmutils.ConnectorClient(self._url)
|
||||||
|
res = rh.call('guest_list')
|
||||||
|
self.assertEqual('data', res)
|
||||||
|
|
||||||
|
@mock.patch('zvmconnector.connector.ZVMConnector.send_request')
|
||||||
|
def test_connector_request_handler_error(self, mock_send):
|
||||||
|
expected = {'overallRC': 1, 'errmsg': 'err', 'rc': 0, 'rs': 0}
|
||||||
|
mock_send.return_value = expected
|
||||||
|
|
||||||
|
rh = zvmutils.ConnectorClient(self._url)
|
||||||
|
exc = self.assertRaises(exception.ZVMConnectorError, rh.call,
|
||||||
|
'guest_list')
|
||||||
|
self.assertIn('zVM Cloud Connector request failed',
|
||||||
|
exc.format_message())
|
||||||
|
self.assertEqual(expected['overallRC'], exc.overallRC)
|
||||||
|
self.assertEqual(expected['rc'], exc.rc)
|
||||||
|
self.assertEqual(expected['rs'], exc.rs)
|
||||||
|
self.assertEqual(expected['errmsg'], exc.errmsg)
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Copyright 2017,2018 IBM Corp.
|
||||||
|
#
|
||||||
|
# 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.virt.zvm import driver
|
||||||
|
|
||||||
|
ZVMDriver = driver.ZVMDriver
|
|
@ -0,0 +1,82 @@
|
||||||
|
# Copyright 2017,2018 IBM Corp.
|
||||||
|
#
|
||||||
|
# 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 oslo_log import log as logging
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
|
|
||||||
|
from nova import conf
|
||||||
|
from nova import exception
|
||||||
|
from nova.i18n import _
|
||||||
|
from nova.objects import fields as obj_fields
|
||||||
|
from nova.virt import driver
|
||||||
|
from nova.virt.zvm import hypervisor
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
CONF = conf.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class ZVMDriver(driver.ComputeDriver):
|
||||||
|
"""z/VM implementation of ComputeDriver."""
|
||||||
|
|
||||||
|
def __init__(self, virtapi):
|
||||||
|
super(ZVMDriver, self).__init__(virtapi)
|
||||||
|
|
||||||
|
if not CONF.zvm.cloud_connector_url:
|
||||||
|
error = _('Must specify cloud_connector_url in zvm config '
|
||||||
|
'group to use compute_driver=zvm.driver.ZVMDriver')
|
||||||
|
raise exception.ZVMDriverException(error=error)
|
||||||
|
|
||||||
|
self._hypervisor = hypervisor.Hypervisor(
|
||||||
|
CONF.zvm.cloud_connector_url, ca_file=CONF.zvm.ca_file)
|
||||||
|
|
||||||
|
LOG.info("The zVM compute driver has been initialized.")
|
||||||
|
|
||||||
|
def init_host(self, host):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def list_instances(self):
|
||||||
|
return self._hypervisor.list_names()
|
||||||
|
|
||||||
|
def get_available_resource(self, nodename=None):
|
||||||
|
host_stats = self._hypervisor.get_available_resource()
|
||||||
|
|
||||||
|
hypervisor_hostname = self._hypervisor.get_available_nodes()[0]
|
||||||
|
res = {
|
||||||
|
'vcpus': host_stats.get('vcpus', 0),
|
||||||
|
'memory_mb': host_stats.get('memory_mb', 0),
|
||||||
|
'local_gb': host_stats.get('disk_total', 0),
|
||||||
|
'vcpus_used': host_stats.get('vcpus_used', 0),
|
||||||
|
'memory_mb_used': host_stats.get('memory_mb_used', 0),
|
||||||
|
'local_gb_used': host_stats.get('disk_used', 0),
|
||||||
|
'hypervisor_type': host_stats.get('hypervisor_type',
|
||||||
|
obj_fields.HVType.ZVM),
|
||||||
|
'hypervisor_version': host_stats.get('hypervisor_version', ''),
|
||||||
|
'hypervisor_hostname': host_stats.get('hypervisor_hostname',
|
||||||
|
hypervisor_hostname),
|
||||||
|
'cpu_info': jsonutils.dumps(host_stats.get('cpu_info', {})),
|
||||||
|
'disk_available_least': host_stats.get('disk_available', 0),
|
||||||
|
'supported_instances': [(obj_fields.Architecture.S390X,
|
||||||
|
obj_fields.HVType.ZVM,
|
||||||
|
obj_fields.VMMode.HVM)],
|
||||||
|
'numa_topology': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.debug("Getting available resource for %(host)s:%(nodename)s",
|
||||||
|
{'host': CONF.host, 'nodename': nodename})
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
def get_available_nodes(self, refresh=False):
|
||||||
|
return self._hypervisor.get_available_nodes(refresh=refresh)
|
|
@ -0,0 +1,57 @@
|
||||||
|
# Copyright 2017,2018 IBM Corp.
|
||||||
|
#
|
||||||
|
# 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 oslo_log import log as logging
|
||||||
|
|
||||||
|
from nova import exception
|
||||||
|
from nova.virt.zvm import utils as zvmutils
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Hypervisor(object):
|
||||||
|
"""z/VM implementation of Hypervisor."""
|
||||||
|
|
||||||
|
def __init__(self, zcc_url, ca_file=None):
|
||||||
|
super(Hypervisor, self).__init__()
|
||||||
|
|
||||||
|
self._reqh = zvmutils.ConnectorClient(zcc_url,
|
||||||
|
ca_file=ca_file)
|
||||||
|
|
||||||
|
# Very very unlikely the hostname will be changed, so when create
|
||||||
|
# hypervisor object, store the information in the cache and after
|
||||||
|
# that we can use it directly without query again from connectorclient
|
||||||
|
self._hypervisor_hostname = self._get_host_info().get(
|
||||||
|
'hypervisor_hostname')
|
||||||
|
|
||||||
|
def _get_host_info(self):
|
||||||
|
host_stats = {}
|
||||||
|
try:
|
||||||
|
host_stats = self._reqh.call('host_get_info')
|
||||||
|
except exception.ZVMConnectorError as e:
|
||||||
|
LOG.warning("Failed to get host stats: %s", e)
|
||||||
|
return host_stats
|
||||||
|
|
||||||
|
def get_available_resource(self):
|
||||||
|
return self._get_host_info()
|
||||||
|
|
||||||
|
def get_available_nodes(self, refresh=False):
|
||||||
|
# It's not expected that the hostname change, no need to take
|
||||||
|
# 'refresh' into account.
|
||||||
|
return [self._hypervisor_hostname]
|
||||||
|
|
||||||
|
def list_names(self):
|
||||||
|
"""list names of the servers in the hypervisor"""
|
||||||
|
return self._reqh.call('guest_list')
|
|
@ -0,0 +1,61 @@
|
||||||
|
# Copyright 2017,2018 IBM Corp.
|
||||||
|
#
|
||||||
|
# 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 oslo_log import log as logging
|
||||||
|
import six
|
||||||
|
import six.moves.urllib.parse as urlparse
|
||||||
|
from zvmconnector import connector
|
||||||
|
|
||||||
|
from nova import exception
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectorClient(object):
|
||||||
|
"""Request handler to zVM cloud connector"""
|
||||||
|
|
||||||
|
def __init__(self, zcc_url, ca_file=None):
|
||||||
|
_url = urlparse.urlparse(zcc_url)
|
||||||
|
|
||||||
|
_ssl_enabled = False
|
||||||
|
|
||||||
|
if _url.scheme == 'https':
|
||||||
|
_ssl_enabled = True
|
||||||
|
elif ca_file:
|
||||||
|
LOG.warning("url is %(url) which is not https "
|
||||||
|
"but ca_file is configured to %(ca_file)s",
|
||||||
|
{'url': zcc_url, 'ca_file': ca_file})
|
||||||
|
|
||||||
|
if _ssl_enabled and ca_file:
|
||||||
|
self._conn = connector.ZVMConnector(_url.hostname, _url.port,
|
||||||
|
ssl_enabled=_ssl_enabled,
|
||||||
|
verify=ca_file)
|
||||||
|
else:
|
||||||
|
self._conn = connector.ZVMConnector(_url.hostname, _url.port,
|
||||||
|
ssl_enabled=_ssl_enabled,
|
||||||
|
verify=False)
|
||||||
|
|
||||||
|
def call(self, func_name, *args, **kwargs):
|
||||||
|
results = self._conn.send_request(func_name, *args, **kwargs)
|
||||||
|
|
||||||
|
if results['overallRC'] != 0:
|
||||||
|
LOG.error("zVM Cloud Connector request %(api)s failed with "
|
||||||
|
"parameters: %(args)s %(kwargs)s . Results: %(results)s",
|
||||||
|
{'api': func_name, 'args': six.text_type(args),
|
||||||
|
'kwargs': six.text_type(kwargs),
|
||||||
|
'results': six.text_type(results)})
|
||||||
|
raise exception.ZVMConnectorError(results=results)
|
||||||
|
|
||||||
|
return results['output']
|
|
@ -66,3 +66,4 @@ retrying>=1.3.3,!=1.3.0 # Apache-2.0
|
||||||
os-service-types>=1.2.0 # Apache-2.0
|
os-service-types>=1.2.0 # Apache-2.0
|
||||||
taskflow>=2.16.0 # Apache-2.0
|
taskflow>=2.16.0 # Apache-2.0
|
||||||
python-dateutil>=2.5.3 # BSD
|
python-dateutil>=2.5.3 # BSD
|
||||||
|
zVMCloudConnector>=1.1.1;sys_platform!='win32' # Apache 2.0 License
|
||||||
|
|
Loading…
Reference in New Issue