зеркало из 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 = ""
|
vm_name: str = ""
|
||||||
firmware_source_path: str = ""
|
firmware_source_path: str = ""
|
||||||
firmware_path: str = ""
|
firmware_path: str = ""
|
||||||
|
guest_vm_type: str = ""
|
||||||
cloud_init_file_path: str = ""
|
cloud_init_file_path: str = ""
|
||||||
ignition_file_path: str = ""
|
ignition_file_path: str = ""
|
||||||
os_disk_source_file_path: Optional[str] = None
|
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 pycdlib # type: ignore
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from lisa import schema, search_space
|
from lisa import feature, schema, search_space
|
||||||
from lisa.environment import Environment
|
from lisa.environment import Environment
|
||||||
from lisa.feature import Feature
|
from lisa.feature import Feature
|
||||||
from lisa.node import Node, RemoteNode, local_node_connect
|
from lisa.node import Node, RemoteNode, local_node_connect
|
||||||
|
@ -42,7 +42,12 @@ from lisa.tools import (
|
||||||
Uname,
|
Uname,
|
||||||
Whoami,
|
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 lisa.util.logger import Logger, filter_ansi_escape, get_logger
|
||||||
|
|
||||||
from . import libvirt_events_thread
|
from . import libvirt_events_thread
|
||||||
|
@ -54,6 +59,7 @@ from .context import (
|
||||||
get_environment_context,
|
get_environment_context,
|
||||||
get_node_context,
|
get_node_context,
|
||||||
)
|
)
|
||||||
|
from .features import SecurityProfile, SecurityProfileSettings
|
||||||
from .platform_interface import IBaseLibvirtPlatform
|
from .platform_interface import IBaseLibvirtPlatform
|
||||||
from .schema import (
|
from .schema import (
|
||||||
FIRMWARE_TYPE_BIOS,
|
FIRMWARE_TYPE_BIOS,
|
||||||
|
@ -89,6 +95,7 @@ class BaseLibvirtPlatform(Platform, IBaseLibvirtPlatform):
|
||||||
_supported_features: List[Type[Feature]] = [
|
_supported_features: List[Type[Feature]] = [
|
||||||
SerialConsole,
|
SerialConsole,
|
||||||
StartStop,
|
StartStop,
|
||||||
|
SecurityProfile,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, runbook: schema.Platform) -> None:
|
def __init__(self, runbook: schema.Platform) -> None:
|
||||||
|
@ -193,6 +200,36 @@ class BaseLibvirtPlatform(Platform, IBaseLibvirtPlatform):
|
||||||
|
|
||||||
self._configure_environment(environment, log)
|
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)
|
return self._configure_node_capabilities(environment, log)
|
||||||
|
|
||||||
def _deploy_environment(self, environment: Environment, log: Logger) -> None:
|
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.max_nic_count = 1
|
||||||
node_capabilities.network_interface.nic_count = 1
|
node_capabilities.network_interface.nic_count = 1
|
||||||
node_capabilities.gpu_count = 0
|
node_capabilities.gpu_count = 0
|
||||||
|
security_profile_setting = SecurityProfileSettings()
|
||||||
node_capabilities.features = search_space.SetSpace[schema.FeatureSettings](
|
node_capabilities.features = search_space.SetSpace[schema.FeatureSettings](
|
||||||
is_allow_set=True,
|
is_allow_set=True,
|
||||||
items=[
|
items=[
|
||||||
schema.FeatureSettings.create(SerialConsole.name()),
|
schema.FeatureSettings.create(SerialConsole.name()),
|
||||||
|
security_profile_setting,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -564,6 +603,31 @@ class BaseLibvirtPlatform(Platform, IBaseLibvirtPlatform):
|
||||||
log: Logger,
|
log: Logger,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.host_node.shell.mkdir(Path(self.vm_disks_dir), exist_ok=True)
|
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():
|
for node in environment.nodes.list():
|
||||||
node_context = get_node_context(node)
|
node_context = get_node_context(node)
|
||||||
|
|
|
@ -122,6 +122,8 @@ SECURITY_PROFILE_BOOT = "secureboot"
|
||||||
SECURITY_PROFILE_CVM = "cvm"
|
SECURITY_PROFILE_CVM = "cvm"
|
||||||
SECURITY_PROFILE_STATELESS = "stateless"
|
SECURITY_PROFILE_STATELESS = "stateless"
|
||||||
|
|
||||||
|
GUEST_VM_TYPE_STANDARD = "STANDARD"
|
||||||
|
GUEST_VM_TYPE_CVM = "CVM"
|
||||||
PLATFORM = "platform"
|
PLATFORM = "platform"
|
||||||
PLATFORM_READY = "ready"
|
PLATFORM_READY = "ready"
|
||||||
PLATFORM_BAREMETAL = "baremetal"
|
PLATFORM_BAREMETAL = "baremetal"
|
||||||
|
|
Загрузка…
Ссылка в новой задаче