Add unit tests for _has_nvidia_gpu_hardware()

Also add .gitreview and .zuul.yaml files

Change-Id: I7f839a0ea7c3a3f72a4d6be5dfd47f9ddd0c0bef
This commit is contained in:
Aurelien Lourot 2021-12-14 10:39:50 +01:00
parent a2f6ce020b
commit 4f49eab3fd
19 changed files with 212 additions and 27 deletions

4
.gitreview Normal file
View File

@ -0,0 +1,4 @@
[gerrit]
host=review.opendev.org
port=29418
project=openstack/charm-nova-compute-nvidia-vgpu

4
.zuul.yaml Normal file
View File

@ -0,0 +1,4 @@
- project:
templates:
- openstack-python3-charm-jobs
- openstack-cover-jobs

View File

@ -1,6 +1,6 @@
# Overview
This subordinate charm provides the NVidia vGPU support to the
This subordinate charm provides the Nvidia vGPU support to the
[OpenStack Nova Compute service][charm-nova-compute].
# Bugs

View File

@ -1,3 +1,5 @@
# NOTE(lourot): versions newer than 1.0.0 fail as described in
# https://github.com/canonical/charmcraft/pull/487#issuecomment-894529408
git+https://github.com/canonical/charmcraft.git@1.0.0#egg=charmcraft
cffi==1.14.6; python_version < '3.6' # cffi 1.15.0 drops support for py35.

View File

@ -1,10 +1,10 @@
name: nova-compute-nvidia-vgpu
summary: NVidia vGPU support for OpenStack Nova Compute
summary: Nvidia vGPU support for OpenStack Nova Compute
maintainer: OpenStack Charmers <openstack-charmers@lists.ubuntu.com>
description: |
OpenStack Compute, codenamed Nova, is a cloud computing fabric controller.
.
This charm provides NVidia vGPU support for Nova.
This charm provides Nvidia vGPU support for Nova.
tags:
- openstack
series:

View File

@ -1,16 +1,89 @@
- project:
templates:
- charm-yoga-unit-jobs
- charm-yoga-functional-jobs
- charm-xena-functional-jobs
- charm-wallaby-functional-jobs
- charm-victoria-functional-jobs
check:
jobs:
# NOTE(lourot): adding `focal-ussuri` manually to the list here instead
# of using `charm-ussuri-functional-jobs` as we don't support Bionic.
- focal-ussuri
- jammy-yoga-nvidia-vgpu:
voting: false
- impish-xena-nvidia-vgpu
- hirsute-wallaby-nvidia-vgpu
- focal-yoga-nvidia-vgpu
- focal-xena-nvidia-vgpu
- focal-wallaby-nvidia-vgpu
- focal-victoria-nvidia-vgpu
- focal-ussuri-nvidia-vgpu
vars:
needs_charm_build: true
charm_build_name: nova-compute-nvidia-vgpu
build_type: charmcraft
- job:
name: jammy-yoga-nvidia-vgpu
description: Run a functional test against jammy-yoga
parent: func-target
dependencies: &smoke-jobs
- focal-ussuri-nvidia-vgpu
vars:
tox_extra_args: jammy-yoga
- job:
name: impish-xena-nvidia-vgpu
description: Run a functional test against impish-xena
parent: func-target
dependencies: *smoke-jobs
vars:
tox_extra_args: impish-xena
- job:
name: hirsute-wallaby-nvidia-vgpu
description: Run a functional test against hirsute-wallaby
parent: func-target
dependencies: *smoke-jobs
vars:
tox_extra_args: hirsute-wallaby
- job:
name: focal-yoga-nvidia-vgpu
description: Run a functional test against focal-yoga
parent: func-target
dependencies: *smoke-jobs
vars:
tox_extra_args: focal-yoga
- job:
name: focal-xena-nvidia-vgpu
description: Run a functional test against focal-xena
parent: func-target
dependencies: *smoke-jobs
vars:
tox_extra_args: focal-xena
- job:
name: focal-wallaby-nvidia-vgpu
description: Run a functional test against focal-wallaby
parent: func-target
dependencies: *smoke-jobs
vars:
tox_extra_args: focal-wallaby
- job:
name: focal-victoria-nvidia-vgpu
description: Run a functional test against focal-victoria
parent: func-target
dependencies: *smoke-jobs
vars:
tox_extra_args: focal-victoria
- job:
name: focal-ussuri-nvidia-vgpu
description: Run a functional test against focal-ussuri
parent: func-target
dependencies:
# The soft dependencies mean that if they are not configured to run
# they will be ignored. See
# https://github.com/openstack-charmers/zosci-config
- charm-build
- osci-lint
- name: tox-py36
soft: true
- name: tox-py38
soft: true
- name: tox-py39
soft: true
vars:
tox_extra_args: focal-ussuri

View File

@ -173,20 +173,28 @@ class NovaComputeNvidiaVgpuCharm(ops_openstack.core.OSBaseCharm):
return [package['version'] for package in
apt_cache().dpkg_list(['nvidia-vgpu-ubuntu-*']).values()]
@staticmethod
@classmethod
@cached
def _has_nvidia_gpu_hardware():
def _has_nvidia_gpu_hardware(cls):
"""Search for NVIDIA GPU hardware.
:returns: True if some NVIDIA GPU hardware is found on the current
unit.
:rtype: bool
"""
return cls._has_nvidia_gpu_hardware_notcached()
@staticmethod
def _has_nvidia_gpu_hardware_notcached():
nvidia_gpu_hardware_found = False
for device in SimpleParser().run():
device_class = device.cls.name
device_vendor = device.vendor.name
device_subsystem_vendor = device.subsystem_vendor.name
try:
device_subsystem_vendor = device.subsystem_vendor.name
except AttributeError:
device_subsystem_vendor = ''
if '3D' in device_class and ('NVIDIA' in device_vendor or
'NVIDIA' in device_subsystem_vendor):
logging.debug('NVIDIA GPU found: {}'.format(device))

View File

@ -4,7 +4,7 @@
charm-tools>=2.4.4
coverage>=3.6
mock>=1.2
flake8>=4.0.1
flake8>=4.0.1; python_version >= '3.6'
stestr>=2.2.0
requests>=2.18.4
psutil
@ -14,3 +14,4 @@ git+https://github.com/openstack-charmers/zaza.git#egg=zaza
git+https://github.com/openstack-charmers/zaza-openstack-tests.git#egg=zaza.openstack
pytz # workaround for 14.04 pip/tox
pyudev # for ceph-* charm unit tests (not mocked?)
cffi==1.14.6; python_version < '3.6' # cffi 1.15.0 drops support for py35.

View File

@ -1,3 +1,5 @@
local_overlay_enabled: False
variables:
openstack-origin: &openstack-origin distro
@ -165,7 +167,7 @@ applications:
- '10'
nova-compute-nvidia-vgpu:
charm: ../../../nova-compute-nvidia-vgpu
charm: ../../nova-compute-nvidia-vgpu.charm
relations:
- - 'ceph-osd:mon'

View File

@ -1,3 +1,5 @@
local_overlay_enabled: False
variables:
openstack-origin: &openstack-origin cloud:focal-victoria
@ -165,7 +167,7 @@ applications:
- '10'
nova-compute-nvidia-vgpu:
charm: ../../../nova-compute-nvidia-vgpu
charm: ../../nova-compute-nvidia-vgpu.charm
relations:
- - 'ceph-osd:mon'

View File

@ -1,3 +1,5 @@
local_overlay_enabled: False
variables:
openstack-origin: &openstack-origin cloud:focal-wallaby
@ -165,7 +167,7 @@ applications:
- '10'
nova-compute-nvidia-vgpu:
charm: ../../../nova-compute-nvidia-vgpu
charm: ../../nova-compute-nvidia-vgpu.charm
relations:
- - 'ceph-osd:mon'

View File

@ -1,3 +1,5 @@
local_overlay_enabled: False
variables:
openstack-origin: &openstack-origin cloud:focal-xena
@ -165,7 +167,7 @@ applications:
- '10'
nova-compute-nvidia-vgpu:
charm: ../../../nova-compute-nvidia-vgpu
charm: ../../nova-compute-nvidia-vgpu.charm
relations:
- - 'ceph-osd:mon'

View File

@ -1,3 +1,5 @@
local_overlay_enabled: False
variables:
openstack-origin: &openstack-origin cloud:focal-yoga
@ -165,7 +167,7 @@ applications:
- '10'
nova-compute-nvidia-vgpu:
charm: ../../../nova-compute-nvidia-vgpu
charm: ../../nova-compute-nvidia-vgpu.charm
relations:
- - 'ceph-osd:mon'

View File

@ -1,3 +1,5 @@
local_overlay_enabled: False
variables:
openstack-origin: &openstack-origin distro
@ -165,7 +167,7 @@ applications:
- '10'
nova-compute-nvidia-vgpu:
charm: ../../../nova-compute-nvidia-vgpu
charm: ../../nova-compute-nvidia-vgpu.charm
relations:
- - 'ceph-osd:mon'

View File

@ -1,3 +1,5 @@
local_overlay_enabled: False
variables:
openstack-origin: &openstack-origin distro
@ -165,7 +167,7 @@ applications:
- '10'
nova-compute-nvidia-vgpu:
charm: ../../../nova-compute-nvidia-vgpu
charm: ../../nova-compute-nvidia-vgpu.charm
relations:
- - 'ceph-osd:mon'

View File

@ -1,3 +1,5 @@
local_overlay_enabled: False
variables:
openstack-origin: &openstack-origin distro
@ -165,7 +167,7 @@ applications:
- '10'
nova-compute-nvidia-vgpu:
charm: ../../../nova-compute-nvidia-vgpu
charm: ../../nova-compute-nvidia-vgpu.charm
relations:
- - 'ceph-osd:mon'

View File

@ -7,12 +7,12 @@ gate_bundles:
- focal-ussuri
- focal-victoria
- focal-wallaby
- focal-xena
- focal-yoga
- hirsute-wallaby
- impish-xena
dev_bundles:
- focal-xena
- impish-xena
- jammy-yoga
configure:

View File

@ -54,6 +54,11 @@ basepython = python3.8
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
[testenv:py39]
basepython = python3.9
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
[testenv:py3]
basepython = python3
deps = -r{toxinidir}/requirements.txt

View File

@ -13,23 +13,95 @@
# limitations under the License.
import unittest
from src.charm import NovaComputeNvidiaVgpuCharm
from mock import MagicMock, patch
from ops.model import ActiveStatus
from ops.testing import Harness
import src.charm
class TestNovaComputeNvidiaVgpuCharm(unittest.TestCase):
class CharmTestCase(unittest.TestCase):
def setUp(self, obj, patches):
super().setUp()
self.patches = patches
self.obj = obj
self.patch_all()
def patch(self, method):
_m = patch.object(self.obj, method)
mock = _m.start()
self.addCleanup(_m.stop)
return mock
def patch_all(self):
for method in self.patches:
setattr(self, method, self.patch(method))
class MockLspciProperty:
def __init__(self, name):
self.name = name
class MockLspciDevice:
def __init__(self, cls_name, vendor_name):
self.cls = MockLspciProperty(cls_name)
self.vendor = MockLspciProperty(vendor_name)
class TestNovaComputeNvidiaVgpuCharm(CharmTestCase):
_PATCHES = [
'SimpleParser',
]
_PCI_DEVICES_LIST_WITHOUT_GPU = [
# This is an NVIDIA device, but not a GPU card:
MockLspciDevice(cls_name='VGA compatible controller',
vendor_name='NVIDIA Corporation'),
]
_PCI_DEVICES_LIST_WITH_NVIDIA_GPU = [
# This is an NVIDIA device, but not a GPU card:
MockLspciDevice(cls_name='VGA compatible controller',
vendor_name='NVIDIA Corporation'),
# This is an NVIDIA GPU card:
MockLspciDevice(cls_name='3D controller',
vendor_name='NVIDIA Corporation'),
]
def setUp(self):
self.harness = Harness(NovaComputeNvidiaVgpuCharm)
super().setUp(src.charm, self._PATCHES)
self.harness = Harness(src.charm.NovaComputeNvidiaVgpuCharm)
self.addCleanup(self.harness.cleanup)
self.harness.begin()
def test_start(self):
def test_has_nvidia_gpu_hardware_with_hw(self):
self.SimpleParser.return_value = MagicMock()
self.SimpleParser.return_value.run.return_value = (
self._PCI_DEVICES_LIST_WITH_NVIDIA_GPU)
self.assertTrue(
self.harness.charm._has_nvidia_gpu_hardware_notcached())
def test_has_nvidia_gpu_hardware_without_hw(self):
self.SimpleParser.return_value = MagicMock()
self.SimpleParser.return_value.run.return_value = (
self._PCI_DEVICES_LIST_WITHOUT_GPU)
self.assertFalse(
self.harness.charm._has_nvidia_gpu_hardware_notcached())
def test_init(self):
self.assertEqual(
self.harness.framework.model.app.name,
'nova-compute-nvidia-vgpu')
# Test that charm is active upon installation.
self.assertFalse(self.harness.charm._stored.is_started)
self.assertIsNone(
self.harness.charm._stored.last_installed_resource_hash)
def test_start(self):
self.harness.charm.on.start.emit()
self.assertTrue(isinstance(
self.harness.model.unit.status, ActiveStatus))