Complete compute.hypervisor functions

For the OSC ensure we do support everything what nova supports on the
hypervisors front

Change-Id: I9051123e905f7df44f9cb9be62c90f24140cb9ac
This commit is contained in:
Artem Goncharov 2020-11-18 16:11:23 +01:00
parent e674ee3f76
commit 30116cf3c2
9 changed files with 306 additions and 71 deletions

View File

@ -140,7 +140,8 @@ Hypervisor Operations
.. autoclass:: openstack.compute.v2._proxy.Proxy
:noindex:
:members: get_hypervisor, find_hypervisor, hypervisors
:members: get_hypervisor, find_hypervisor, hypervisors,
get_hypervisor_uptime
Extension Operations
^^^^^^^^^^^^^^^^^^^^

View File

@ -12,3 +12,4 @@ Compute Resources
v2/server
v2/server_interface
v2/server_ip
v2/hypervisor

View File

@ -0,0 +1,12 @@
openstack.compute.v2.hypervisor
===============================
.. automodule:: openstack.compute.v2.hypervisor
The Hypervisor Class
--------------------
The ``Hypervisor`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.compute.v2.hypervisor.Hypervisor
:members:

View File

@ -1362,6 +1362,8 @@ class Proxy(proxy.Proxy):
"""
return self._list(_server_group.ServerGroup, **query)
# ========== Hypervisors ==========
def hypervisors(self, details=False, **query):
"""Return a generator of hypervisor
@ -1374,9 +1376,16 @@ class Proxy(proxy.Proxy):
:rtype: class: `~openstack.compute.v2.hypervisor.Hypervisor`
"""
base_path = '/os-hypervisors/detail' if details else None
if (
'hypervisor_hostname_pattern' in query
and not utils.supports_microversion(self, '2.53')
):
# Until 2.53 we need to use other API
base_path = '/os-hypervisors/{pattern}/search'.format(
pattern=query.pop('hypervisor_hostname_pattern'))
return self._list(_hypervisor.Hypervisor, base_path=base_path, **query)
def find_hypervisor(self, name_or_id, ignore_missing=True):
def find_hypervisor(self, name_or_id, ignore_missing=True, details=True):
"""Find a hypervisor from name or id to get the corresponding info
:param name_or_id: The name or id of a hypervisor
@ -1386,23 +1395,40 @@ class Proxy(proxy.Proxy):
or None
"""
list_base_path = '/os-hypervisors/detail' if details else None
return self._find(_hypervisor.Hypervisor, name_or_id,
list_base_path=list_base_path,
ignore_missing=ignore_missing)
def get_hypervisor(self, hypervisor):
"""Get a single hypervisor
:param hypervisor: The value can be the ID of a hypervisor or a
:class:`~openstack.compute.v2.hypervisor.Hypervisor`
instance.
:class:`~openstack.compute.v2.hypervisor.Hypervisor`
instance.
:returns:
A :class:`~openstack.compute.v2.hypervisor.Hypervisor` object.
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_hypervisor.Hypervisor, hypervisor)
def get_hypervisor_uptime(self, hypervisor):
"""Get uptime information for hypervisor
:param hypervisor: The value can be the ID of a hypervisor or a
:class:`~openstack.compute.v2.hypervisor.Hypervisor`
instance.
:returns:
A :class:`~openstack.compute.v2.hypervisor.Hypervisor` object.
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
"""
hypervisor = self._get_resource(_hypervisor.Hypervisor, hypervisor)
return hypervisor.get_uptime(self)
# ========== Services ==========
def update_service_forced_down(

View File

@ -10,8 +10,11 @@
# License for the specific language governing permissions and limitations
# under the License.
import warnings
from openstack import exceptions
from openstack import resource
from openstack import utils
class Hypervisor(resource.Resource):
@ -27,48 +30,72 @@ class Hypervisor(resource.Resource):
'hypervisor_hostname_pattern', 'with_servers'
)
# Hypervisor id is a UUID starting with 2.53
_max_microversion = '2.53'
# Lot of attributes are dropped in 2.88
_max_microversion = '2.88'
# Properties
#: Status of hypervisor
status = resource.Body('status')
#: State of hypervisor
state = resource.Body('state')
#: Name of hypervisor
name = resource.Body('hypervisor_hostname')
#: Service details
service_details = resource.Body('service')
#: Count of the VCPUs in use
vcpus_used = resource.Body('vcpus_used')
#: Count of all VCPUs
vcpus = resource.Body('vcpus')
#: Count of the running virtual machines
running_vms = resource.Body('running_vms')
#: Information about the hypervisor's CPU. Up to 2.28 it was string.
cpu_info = resource.Body('cpu_info')
#: IP address of the host
host_ip = resource.Body('host_ip')
#: The type of hypervisor
hypervisor_type = resource.Body('hypervisor_type')
#: Version of the hypervisor
hypervisor_version = resource.Body('hypervisor_version')
#: The amount, in gigabytes, of local storage used
local_disk_used = resource.Body('local_gb_used')
#: The amount, in gigabytes, of the local storage device
local_disk_size = resource.Body('local_gb')
#: The amount, in gigabytes, of free space on the local storage device
local_disk_free = resource.Body('free_disk_gb')
#: The amount, in megabytes, of memory
memory_used = resource.Body('memory_mb_used')
#: The amount, in megabytes, of total memory
memory_size = resource.Body('memory_mb')
#: The amount, in megabytes, of available memory
memory_free = resource.Body('free_ram_mb')
#: Name of hypervisor
name = resource.Body('hypervisor_hostname')
#: Service details
service_details = resource.Body('service', type=dict)
#: List of Servers
servers = resource.Body('servers', type=list, list_type=dict)
#: State of hypervisor
state = resource.Body('state')
#: Status of hypervisor
status = resource.Body('status')
#: The total uptime of the hypervisor and information about average load.
#: This attribute is set only when querying uptime explicitly.
uptime = resource.Body('uptime')
# Attributes deprecated with 2.88
#: Measurement of the hypervisor's current workload
current_workload = resource.Body('current_workload')
#: Information about the hypervisor's CPU
cpu_info = resource.Body('cpu_info')
#: IP address of the host
host_ip = resource.Body('host_ip')
current_workload = resource.Body('current_workload', deprecated=True)
#: Disk space available to the scheduler
disk_available = resource.Body("disk_available_least")
disk_available = resource.Body("disk_available_least", deprecated=True)
#: The amount, in gigabytes, of local storage used
local_disk_used = resource.Body('local_gb_used', deprecated=True)
#: The amount, in gigabytes, of the local storage device
local_disk_size = resource.Body('local_gb', deprecated=True)
#: The amount, in gigabytes, of free space on the local storage device
local_disk_free = resource.Body('free_disk_gb', deprecated=True)
#: The amount, in megabytes, of memory
memory_used = resource.Body('memory_mb_used', deprecated=True)
#: The amount, in megabytes, of total memory
memory_size = resource.Body('memory_mb', deprecated=True)
#: The amount, in megabytes, of available memory
memory_free = resource.Body('free_ram_mb', deprecated=True)
#: Count of the running virtual machines
running_vms = resource.Body('running_vms', deprecated=True)
#: Count of the VCPUs in use
vcpus_used = resource.Body('vcpus_used', deprecated=True)
#: Count of all VCPUs
vcpus = resource.Body('vcpus', deprecated=True)
def get_uptime(self, session):
"""Get uptime information for the hypervisor
Updates uptime attribute of the hypervisor object
"""
warnings.warn(
"This call is deprecated and is only available until Nova 2.88")
if utils.supports_microversion(session, '2.88'):
raise exceptions.SDKException(
'Hypervisor.get_uptime is not supported anymore')
url = utils.urljoin(self.base_path, self.id, 'uptime')
microversion = self._get_microversion_for(session, 'fetch')
response = session.get(
url, microversion=microversion)
self._translate_response(response)
return self
HypervisorDetail = Hypervisor

View File

@ -0,0 +1,31 @@
# 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 openstack.tests.functional import base
class TestHypervisor(base.BaseFunctionalTest):
def setUp(self):
super(TestHypervisor, self).setUp()
def test_list_hypervisors(self):
rslt = list(self.conn.compute.hypervisors())
self.assertIsNotNone(rslt)
rslt = list(self.conn.compute.hypervisors(details=True))
self.assertIsNotNone(rslt)
def test_get_find_hypervisors(self):
for hypervisor in self.conn.compute.hypervisors():
self.conn.compute.get_hypervisor(hypervisor.id)
self.conn.compute.find_hypervisor(hypervisor.id)

View File

@ -9,41 +9,79 @@
# 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 copy
from unittest import mock
from keystoneauth1 import adapter
from openstack import exceptions
from openstack.tests.unit import base
from openstack.compute.v2 import hypervisor
EXAMPLE = {
"status": "enabled",
"service": {
"host": "fake-mini",
"disabled_reason": None,
"id": 6
"cpu_info": {
"arch": "x86_64",
"model": "Nehalem",
"vendor": "Intel",
"features": [
"pge",
"clflush"
],
"topology": {
"cores": 1,
"threads": 1,
"sockets": 4
}
},
"state": "up",
"status": "enabled",
"servers": [
{
"name": "test_server1",
"uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
},
{
"name": "test_server2",
"uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
}
],
"host_ip": "1.1.1.1",
"hypervisor_hostname": "fake-mini",
"hypervisor_type": "fake",
"hypervisor_version": 1000,
"id": "b1e43b5f-eec1-44e0-9f10-7b4945c0226d",
"uptime": (
" 08:32:11 up 93 days, 18:25, 12 users, "
"load average: 0.20, 0.12, 0.14"),
"service": {
"host": "043b3cacf6f34c90a7245151fc8ebcda",
"id": "5d343e1d-938e-4284-b98b-6a2b5406ba76",
"disabled_reason": None
},
# deprecated attributes
"vcpus_used": 0,
"hypervisor_type": "QEMU",
"local_gb_used": 0,
"vcpus": 8,
"hypervisor_hostname": "fake-mini",
"memory_mb_used": 512,
"memory_mb": 7980,
"current_workload": 0,
"state": "up",
"host_ip": "23.253.248.171",
"cpu_info": "some cpu info",
"running_vms": 0,
"free_disk_gb": 157,
"hypervisor_version": 2000000,
"disk_available_least": 140,
"local_gb": 157,
"free_ram_mb": 7468,
"id": 1
}
class TestHypervisor(base.TestCase):
def setUp(self):
super(TestHypervisor, self).setUp()
self.sess = mock.Mock(spec=adapter.Adapter)
self.sess.default_microversion = 1
self.sess._get_connection = mock.Mock(return_value=self.cloud)
def test_basic(self):
sot = hypervisor.Hypervisor()
self.assertEqual('hypervisor', sot.resource_key)
@ -62,10 +100,17 @@ class TestHypervisor(base.TestCase):
def test_make_it(self):
sot = hypervisor.Hypervisor(**EXAMPLE)
self.assertEqual(EXAMPLE['id'], sot.id)
self.assertEqual(EXAMPLE['cpu_info'], sot.cpu_info)
self.assertEqual(EXAMPLE['host_ip'], sot.host_ip)
self.assertEqual(EXAMPLE['hypervisor_type'], sot.hypervisor_type)
self.assertEqual(EXAMPLE['hypervisor_version'], sot.hypervisor_version)
self.assertEqual(EXAMPLE['hypervisor_hostname'], sot.name)
self.assertEqual(EXAMPLE['service'], sot.service_details)
self.assertEqual(EXAMPLE['servers'], sot.servers)
self.assertEqual(EXAMPLE['state'], sot.state)
self.assertEqual(EXAMPLE['status'], sot.status)
self.assertEqual(EXAMPLE['service'], sot.service_details)
self.assertEqual(EXAMPLE['uptime'], sot.uptime)
# Verify deprecated attributes
self.assertEqual(EXAMPLE['vcpus_used'], sot.vcpus_used)
self.assertEqual(EXAMPLE['hypervisor_type'], sot.hypervisor_type)
self.assertEqual(EXAMPLE['local_gb_used'], sot.local_disk_used)
@ -74,11 +119,46 @@ class TestHypervisor(base.TestCase):
self.assertEqual(EXAMPLE['memory_mb_used'], sot.memory_used)
self.assertEqual(EXAMPLE['memory_mb'], sot.memory_size)
self.assertEqual(EXAMPLE['current_workload'], sot.current_workload)
self.assertEqual(EXAMPLE['host_ip'], sot.host_ip)
self.assertEqual(EXAMPLE['cpu_info'], sot.cpu_info)
self.assertEqual(EXAMPLE['running_vms'], sot.running_vms)
self.assertEqual(EXAMPLE['free_disk_gb'], sot.local_disk_free)
self.assertEqual(EXAMPLE['hypervisor_version'], sot.hypervisor_version)
self.assertEqual(EXAMPLE['disk_available_least'], sot.disk_available)
self.assertEqual(EXAMPLE['local_gb'], sot.local_disk_size)
self.assertEqual(EXAMPLE['free_ram_mb'], sot.memory_free)
@mock.patch('openstack.utils.supports_microversion', autospec=True,
return_value=False)
def test_get_uptime(self, mv_mock):
sot = hypervisor.Hypervisor(**copy.deepcopy(EXAMPLE))
rsp = {
"hypervisor": {
"hypervisor_hostname": "fake-mini",
"id": sot.id,
"state": "up",
"status": "enabled",
"uptime": "08:32:11 up 93 days, 18:25, 12 users"
}
}
resp = mock.Mock()
resp.body = copy.deepcopy(rsp)
resp.json = mock.Mock(return_value=resp.body)
resp.headers = {}
resp.status_code = 200
self.sess.get = mock.Mock(return_value=resp)
hyp = sot.get_uptime(self.sess)
self.sess.get.assert_called_with(
'os-hypervisors/{id}/uptime'.format(id=sot.id),
microversion=self.sess.default_microversion
)
self.assertEqual(rsp['hypervisor']['uptime'], hyp.uptime)
self.assertEqual(rsp['hypervisor']['status'], sot.status)
@mock.patch('openstack.utils.supports_microversion', autospec=True,
return_value=True)
def test_get_uptime_after_2_88(self, mv_mock):
sot = hypervisor.Hypervisor(**copy.deepcopy(EXAMPLE))
self.assertRaises(
exceptions.SDKException,
sot.get_uptime,
self.sess
)

View File

@ -445,6 +445,74 @@ class TestService(TestComputeProxy):
)
class TestHypervisor(TestComputeProxy):
def test_hypervisors_not_detailed(self):
self.verify_list(self.proxy.hypervisors, hypervisor.Hypervisor,
method_kwargs={"details": False})
def test_hypervisors_detailed(self):
self.verify_list(self.proxy.hypervisors, hypervisor.HypervisorDetail,
method_kwargs={"details": True})
@mock.patch('openstack.utils.supports_microversion', autospec=True,
return_value=False)
def test_hypervisors_search_before_253_no_qp(self, sm):
self.verify_list(
self.proxy.hypervisors,
hypervisor.Hypervisor,
method_kwargs={'details': True},
base_path='/os-hypervisors/detail'
)
@mock.patch('openstack.utils.supports_microversion', autospec=True,
return_value=False)
def test_hypervisors_search_before_253(self, sm):
self.verify_list(
self.proxy.hypervisors,
hypervisor.Hypervisor,
method_kwargs={'hypervisor_hostname_pattern': 'substring'},
base_path='/os-hypervisors/substring/search'
)
@mock.patch('openstack.utils.supports_microversion', autospec=True,
return_value=True)
def test_hypervisors_search_after_253(self, sm):
self.verify_list(
self.proxy.hypervisors,
hypervisor.Hypervisor,
method_kwargs={'hypervisor_hostname_pattern': 'substring'},
base_path=None,
expected_kwargs={'hypervisor_hostname_pattern': 'substring'}
)
def test_find_hypervisor_detail(self):
self.verify_find(self.proxy.find_hypervisor,
hypervisor.Hypervisor,
expected_kwargs={
'list_base_path': '/os-hypervisors/detail',
'ignore_missing': False})
def test_find_hypervisor_no_detail(self):
self.verify_find(self.proxy.find_hypervisor,
hypervisor.Hypervisor,
method_kwargs={'details': False},
expected_kwargs={
'list_base_path': None,
'ignore_missing': False})
def test_get_hypervisor(self):
self.verify_get(self.proxy.get_hypervisor,
hypervisor.Hypervisor)
def test_get_hypervisor_uptime(self):
self._verify(
"openstack.compute.v2.hypervisor.Hypervisor.get_uptime",
self.proxy.get_hypervisor_uptime,
method_args=["value"],
expected_args=[])
class TestCompute(TestComputeProxy):
def test_extension_find(self):
self.verify_find(self.proxy.find_extension, extension.Extension)
@ -870,22 +938,6 @@ class TestCompute(TestComputeProxy):
def test_server_groups(self):
self.verify_list(self.proxy.server_groups, server_group.ServerGroup)
def test_hypervisors_not_detailed(self):
self.verify_list(self.proxy.hypervisors, hypervisor.Hypervisor,
method_kwargs={"details": False})
def test_hypervisors_detailed(self):
self.verify_list(self.proxy.hypervisors, hypervisor.HypervisorDetail,
method_kwargs={"details": True})
def test_find_hypervisor(self):
self.verify_find(self.proxy.find_hypervisor,
hypervisor.Hypervisor)
def test_get_hypervisor(self):
self.verify_get(self.proxy.get_hypervisor,
hypervisor.Hypervisor)
def test_live_migrate_server(self):
self._verify('openstack.compute.v2.server.Server.live_migrate',
self.proxy.live_migrate_server,

View File

@ -0,0 +1,5 @@
---
features:
- |
Compute Hypervisor resource and functions are reworked to comply 2.88
microversion with deprecating misleading attributes.