зеркало из https://github.com/microsoft/lisa.git
Add security profile feature in libvirt
This commit is contained in:
Родитель
0d9420884c
Коммит
3079f43567
|
@ -48,6 +48,7 @@ class NodeContext:
|
|||
vm_name: str = ""
|
||||
firmware_source_path: str = ""
|
||||
firmware_path: str = ""
|
||||
guest_vm_type: str = ""
|
||||
cloud_init_file_path: str = ""
|
||||
ignition_file_path: str = ""
|
||||
os_disk_source_file_path: Optional[str] = None
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
from dataclasses import dataclass
|
||||
from typing import Any, Type, cast
|
||||
|
||||
from dataclasses_json import dataclass_json
|
||||
|
||||
from lisa import features, schema, search_space
|
||||
from lisa.environment import Environment
|
||||
from lisa.features.security_profile import SecurityProfileType
|
||||
from lisa.sut_orchestrator.libvirt.context import get_node_context
|
||||
|
||||
|
||||
@dataclass_json()
|
||||
@dataclass()
|
||||
class SecurityProfileSettings(features.SecurityProfileSettings):
|
||||
def __hash__(self) -> int:
|
||||
return hash(self._get_key())
|
||||
|
||||
def _get_key(self) -> str:
|
||||
return f"{self.type}/{self.security_profile}/"
|
||||
|
||||
def _call_requirement_method(
|
||||
self, method: search_space.RequirementMethod, capability: Any
|
||||
) -> Any:
|
||||
super_value: SecurityProfileSettings = super()._call_requirement_method(
|
||||
method, capability
|
||||
)
|
||||
value = SecurityProfileSettings()
|
||||
value.security_profile = super_value.security_profile
|
||||
return value
|
||||
|
||||
|
||||
class SecurityProfile(features.SecurityProfile):
|
||||
_security_profile_mapping = {
|
||||
SecurityProfileType.Standard: "",
|
||||
SecurityProfileType.CVM: "ConfidentialVM",
|
||||
}
|
||||
|
||||
def _initialize(self, *args: Any, **kwargs: Any) -> None:
|
||||
super()._initialize(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def settings_type(cls) -> Type[schema.FeatureSettings]:
|
||||
return SecurityProfileSettings
|
||||
|
||||
@classmethod
|
||||
def on_before_deployment(cls, *args: Any, **kwargs: Any) -> None:
|
||||
environment = cast(Environment, kwargs.get("environment"))
|
||||
security_profile = [kwargs.get("settings")]
|
||||
for node in environment.nodes._list:
|
||||
if security_profile:
|
||||
settings = security_profile[0]
|
||||
assert isinstance(settings, SecurityProfileSettings)
|
||||
assert isinstance(settings.security_profile, SecurityProfileType)
|
||||
node_context = get_node_context(node)
|
||||
node_context.guest_vm_type = cls._security_profile_mapping[
|
||||
settings.security_profile
|
||||
]
|
|
@ -20,7 +20,7 @@ import libvirt # type: ignore
|
|||
import pycdlib # type: ignore
|
||||
import yaml
|
||||
|
||||
from lisa import schema, search_space
|
||||
from lisa import feature, schema, search_space
|
||||
from lisa.environment import Environment
|
||||
from lisa.feature import Feature
|
||||
from lisa.node import Node, RemoteNode, local_node_connect
|
||||
|
@ -42,7 +42,12 @@ from lisa.tools import (
|
|||
Uname,
|
||||
Whoami,
|
||||
)
|
||||
from lisa.util import LisaException, constants, get_public_key_data
|
||||
from lisa.util import (
|
||||
LisaException,
|
||||
NotMeetRequirementException,
|
||||
constants,
|
||||
get_public_key_data,
|
||||
)
|
||||
from lisa.util.logger import Logger, filter_ansi_escape, get_logger
|
||||
|
||||
from . import libvirt_events_thread
|
||||
|
@ -54,6 +59,7 @@ from .context import (
|
|||
get_environment_context,
|
||||
get_node_context,
|
||||
)
|
||||
from .features import SecurityProfile, SecurityProfileSettings
|
||||
from .platform_interface import IBaseLibvirtPlatform
|
||||
from .schema import (
|
||||
FIRMWARE_TYPE_BIOS,
|
||||
|
@ -89,6 +95,7 @@ class BaseLibvirtPlatform(Platform, IBaseLibvirtPlatform):
|
|||
_supported_features: List[Type[Feature]] = [
|
||||
SerialConsole,
|
||||
StartStop,
|
||||
SecurityProfile,
|
||||
]
|
||||
|
||||
def __init__(self, runbook: schema.Platform) -> None:
|
||||
|
@ -193,6 +200,36 @@ class BaseLibvirtPlatform(Platform, IBaseLibvirtPlatform):
|
|||
|
||||
self._configure_environment(environment, log)
|
||||
|
||||
if environment.runbook.nodes_requirement:
|
||||
for node_space in environment.runbook.nodes_requirement:
|
||||
new_settings = search_space.SetSpace[schema.FeatureSettings](
|
||||
is_allow_set=True
|
||||
)
|
||||
if node_space.features:
|
||||
for current_settings in node_space.features.items:
|
||||
# reload to type specified settings
|
||||
try:
|
||||
settings_type = feature.get_feature_settings_type_by_name(
|
||||
current_settings.type,
|
||||
BaseLibvirtPlatform.supported_features(),
|
||||
)
|
||||
except NotMeetRequirementException as identifier:
|
||||
raise LisaException(
|
||||
f"platform doesn't support all features. {identifier}"
|
||||
)
|
||||
new_setting = schema.load_by_type(
|
||||
settings_type, current_settings
|
||||
)
|
||||
existing_setting = feature.get_feature_settings_by_name(
|
||||
new_setting.type, new_settings, True
|
||||
)
|
||||
if existing_setting:
|
||||
new_settings.remove(existing_setting)
|
||||
new_setting = existing_setting.intersect(new_setting)
|
||||
|
||||
new_settings.add(new_setting)
|
||||
node_space.features = new_settings
|
||||
|
||||
return self._configure_node_capabilities(environment, log)
|
||||
|
||||
def _deploy_environment(self, environment: Environment, log: Logger) -> None:
|
||||
|
@ -312,10 +349,12 @@ class BaseLibvirtPlatform(Platform, IBaseLibvirtPlatform):
|
|||
node_capabilities.network_interface.max_nic_count = 1
|
||||
node_capabilities.network_interface.nic_count = 1
|
||||
node_capabilities.gpu_count = 0
|
||||
security_profile_setting = SecurityProfileSettings()
|
||||
node_capabilities.features = search_space.SetSpace[schema.FeatureSettings](
|
||||
is_allow_set=True,
|
||||
items=[
|
||||
schema.FeatureSettings.create(SerialConsole.name()),
|
||||
security_profile_setting,
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -564,6 +603,31 @@ class BaseLibvirtPlatform(Platform, IBaseLibvirtPlatform):
|
|||
log: Logger,
|
||||
) -> None:
|
||||
self.host_node.shell.mkdir(Path(self.vm_disks_dir), exist_ok=True)
|
||||
features_settings: Dict[str, schema.FeatureSettings] = {}
|
||||
|
||||
# collect all the features to handle special deployment logic. If one
|
||||
# node has this, it needs to run.
|
||||
nodes_requirement = environment.runbook.nodes_requirement
|
||||
if nodes_requirement:
|
||||
for node_space in nodes_requirement:
|
||||
if not node_space.features:
|
||||
continue
|
||||
for feature_setting in node_space.features:
|
||||
if feature_setting.type not in features_settings:
|
||||
features_settings[feature_setting.type] = feature_setting
|
||||
|
||||
# change deployment for each feature.
|
||||
for feature_type, setting in [
|
||||
(t, s)
|
||||
for t in self.supported_features()
|
||||
for s in features_settings.values()
|
||||
if t.name() == s.type
|
||||
]:
|
||||
feature_type.on_before_deployment(
|
||||
environment=environment,
|
||||
log=log,
|
||||
settings=setting,
|
||||
)
|
||||
|
||||
for node in environment.nodes.list():
|
||||
node_context = get_node_context(node)
|
||||
|
|
|
@ -122,6 +122,8 @@ SECURITY_PROFILE_BOOT = "secureboot"
|
|||
SECURITY_PROFILE_CVM = "cvm"
|
||||
SECURITY_PROFILE_STATELESS = "stateless"
|
||||
|
||||
GUEST_VM_TYPE_STANDARD = "STANDARD"
|
||||
GUEST_VM_TYPE_CVM = "CVM"
|
||||
PLATFORM = "platform"
|
||||
PLATFORM_READY = "ready"
|
||||
PLATFORM_BAREMETAL = "baremetal"
|
||||
|
|
Загрузка…
Ссылка в новой задаче