Skip to content

Commit

Permalink
Add enterprise license check for virt plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Qubad786 committed Jan 2, 2025
1 parent e81a3aa commit 7f9c5fc
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 3 deletions.
3 changes: 3 additions & 0 deletions src/middlewared/middlewared/plugins/virt/global.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ async def validate(self, new: dict, schema_name: str, verrors: ValidationErrors)
if pool == POOL_DISABLED:
new['pool'] = None

if pool and not await self.middleware.call('virt.global.license_active'):
verrors.add(f'{schema_name}.pool', 'System is not licensed to run virtualization')

@api_method(VirtGlobalUpdateArgs, VirtGlobalUpdateResult)
@job()
async def do_update(self, job, data):
Expand Down
10 changes: 7 additions & 3 deletions src/middlewared/middlewared/plugins/virt/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ async def query(self, filters, options):
async def validate(self, new, schema_name, verrors, old=None):
# Do not validate image_choices because its an expansive operation, just fail on creation

instance_type = new.get('instance_type') or (old or {}).get('type')
if instance_type and not await self.middleware.call('virt.global.license_active', instance_type):
verrors.add(
f'{schema_name}.instance_type', f'System is not licensed to manage {new["instance_type"]!r} instances'
)

if not old and await self.query([('name', '=', new['name'])]):
verrors.add(f'{schema_name}.name', f'Name {new["name"]!r} already exists')

Expand Down Expand Up @@ -164,9 +170,7 @@ async def validate(self, new, schema_name, verrors, old=None):
'vnc_port': old['vnc_port'],
})

if (
new.get('instance_type') == 'VM' or (old and old['type'] == 'VM')
) and new.get('enable_vnc'):
if instance_type == 'VM' and new.get('enable_vnc'):
if not new.get('vnc_port'):
verrors.add(f'{schema_name}.vnc_port', 'VNC port is required when VNC is enabled')
else:
Expand Down
29 changes: 29 additions & 0 deletions src/middlewared/middlewared/plugins/virt/license.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from middlewared.service import private, Service


class VirtLicenseGlobalService(Service):

class Config:
namespace = 'virt.global'

@private
async def license_active(self, instance_type=None):
"""
If this is iX enterprise hardware and has NOT been licensed to run virt plugin
then this will return False, otherwise this will return true.
"""
system_chassis = (await self.middleware.call('truenas.get_chassis_hardware')).removeprefix('TRUENAS-')
if system_chassis.startswith(('UNKNOWN', 'MINI')):
return True

license_ = await self.middleware.call('system.license')
can_run_virt = license_ is not None
if can_run_virt is False:
return False
elif instance_type is None:
can_run_virt = any(k in license_['features'] for k in ('JAILS', 'VM'))
else:
feature = 'JAILS' if instance_type == 'CONTAINER' else 'VM'
can_run_virt = feature in license_['features']

return can_run_virt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import pytest

from middlewared.plugins.virt.license import VirtLicenseGlobalService
from middlewared.pytest.unit.middleware import Middleware


@pytest.mark.parametrize('instance_type,chassis_hardware,license_active,expected_result', [
(
None,
'TRUENAS-UNKNOWN',
None,
True
),
(
None,
'TRUENAS-MINI-3.0-XL+',
None,
True
),
(
None,
'TRUENAS-M60-HA',
{'features': ['JAILS', 'VM']},
True
),
(
'CONTAINER',
'TRUENAS-M60-HA',
{'features': ['JAILS', 'VM']},
True
),
(
'VM',
'TRUENAS-M60-HA',
{'features': ['JAILS', 'VM']},
True
),
(
'CONTAINER',
'TRUENAS-M60-HA',
{'features': ['VM']},
False
),
(
'VM',
'TRUENAS-M60-HA',
{'features': ['JAILS']},
False
),
(
None,
'TRUENAS-M60-HA',
None,
False
),
(
'VM',
'TRUENAS-M60-HA',
None,
False
),
])
@pytest.mark.asyncio
async def test_virt_license_validation(instance_type, chassis_hardware, license_active, expected_result):
m = Middleware()
m['truenas.get_chassis_hardware'] = lambda *arg: chassis_hardware
m['system.license'] = lambda *arg: license_active
assert await VirtLicenseGlobalService(m).license_active(instance_type) == expected_result

0 comments on commit 7f9c5fc

Please sign in to comment.