Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 117 additions & 12 deletions src/firecracker/swagger/firecracker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ paths:
description: The MMDS data store JSON.
schema:
type: object
additionalProperties: true
404:
description: The MMDS data store content can not be found.
schema:
Expand Down Expand Up @@ -898,21 +899,119 @@ definitions:
The CPU configuration template defines a set of bit maps as modifiers of flags accessed by register
to be disabled/enabled for the microvm.
properties:
kvm_capabilities:
type: array
description: A collection of KVM capabilities to be added or removed (both x86_64 and aarch64)
items:
type: string
description: KVM capability as a numeric string. Prefix with '!' to remove capability. Example "121" (add) or "!121" (remove)
cpuid_modifiers:
type: object
description: A collection of CPUIDs to be modified. (x86_64)
type: array
description: A collection of CPUID leaf modifiers (x86_64 only)
items:
$ref: "#/definitions/CpuidLeafModifier"
msr_modifiers:
type: object
description: A collection of model specific registers to be modified. (x86_64)
type: array
description: A collection of model specific register modifiers (x86_64 only)
items:
$ref: "#/definitions/MsrModifier"
reg_modifiers:
type: object
description: A collection of registers to be modified. (aarch64)
type: array
description: A collection of register modifiers (aarch64 only)
items:
$ref: "#/definitions/ArmRegisterModifier"
vcpu_features:
type: object
description: A collection of vcpu features to be modified. (aarch64)
kvm_capabilities:
type: object
description: A collection of kvm capabilities to be modified. (aarch64)
type: array
description: A collection of vCPU features to be modified (aarch64 only)
items:
$ref: "#/definitions/VcpuFeatures"

CpuidLeafModifier:
type: object
description: Modifier for a CPUID leaf and subleaf (x86_64)
required:
- leaf
- subleaf
- flags
- modifiers
properties:
leaf:
type: string
description: CPUID leaf index as hex, binary, or decimal string (e.g., "0x0", "0b0", "0"))
subleaf:
type: string
description: CPUID subleaf index as hex, binary, or decimal string (e.g., "0x0", "0b0", "0")
flags:
type: integer
format: int32
description: KVM feature flags for this leaf-subleaf
modifiers:
type: array
description: Register modifiers for this CPUID leaf
items:
$ref: "#/definitions/CpuidRegisterModifier"

CpuidRegisterModifier:
type: object
description: Modifier for a specific CPUID register within a leaf (x86_64)
required:
- register
- bitmap
properties:
register:
type: string
description: Target CPUID register name
enum:
- eax
- ebx
- ecx
- edx
bitmap:
type: string
description: 32-bit bitmap string defining which bits to modify. Format is "0b" followed by 32 characters where '0' = clear bit, '1' = set bit, 'x' = don't modify. Example "0b00000000000000000000000000000001" or "0bxxxxxxxxxxxxxxxxxxxxxxxxxxxx0001"

MsrModifier:
type: object
description: Modifier for a model specific register (x86_64)
required:
- addr
- bitmap
properties:
addr:
type: string
description: 32-bit MSR address as hex, binary, or decimal string (e.g., "0x10a", "0b100001010", "266")
bitmap:
type: string
description: 64-bit bitmap string defining which bits to modify. Format is "0b" followed by 64 characters where '0' = clear bit, '1' = set bit, 'x' = don't modify. Underscores can be used for readability. Example "0b0000000000000000000000000000000000000000000000000000000000000001"

ArmRegisterModifier:
type: object
description: Modifier for an ARM register (aarch64)
required:
- addr
- bitmap
properties:
addr:
type: string
description: 64-bit register address as hex, binary, or decimal string (e.g., "0x0", "0b0", "0")
bitmap:
type: string
description: 128-bit bitmap string defining which bits to modify. Format is "0b" followed by up to 128 characters where '0' = clear bit, '1' = set bit, 'x' = don't modify. Underscores can be used for readability. Example "0b0000000000000000000000000000000000000000000000000000000000000001"

VcpuFeatures:
type: object
description: vCPU feature modifier (aarch64)
required:
- index
- bitmap
properties:
index:
type: integer
format: int32
description: Index in the kvm_vcpu_init.features array
bitmap:
type: string
description: 32-bit bitmap string defining which bits to modify. Format is "0b" followed by 32 characters where '0' = clear bit, '1' = set bit, 'x' = don't modify. Example "0b00000000000000000000000001100000"

Drive:
type: object
Expand Down Expand Up @@ -1025,6 +1124,11 @@ definitions:
description: Configurations for all net devices.
items:
$ref: "#/definitions/NetworkInterface"
pmem:
type: array
description: Configurations for all pmem devices.
items:
$ref: "#/definitions/Pmem"
vsock:
$ref: "#/definitions/Vsock"
entropy:
Expand Down Expand Up @@ -1213,6 +1317,7 @@ definitions:
type: object
description:
Describes the contents of MMDS in JSON format.
additionalProperties: true

NetworkInterface:
type: object
Expand Down Expand Up @@ -1416,7 +1521,7 @@ definitions:
description:
The configuration of the serial device
properties:
output_path:
serial_out_path:
type: string
description: Path to a file or named pipe on the host to which serial output should be written.

Expand Down
48 changes: 47 additions & 1 deletion tests/framework/http_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import requests
from requests_unixsocket import DEFAULT_SCHEME, UnixAdapter

from framework.swagger_validator import SwaggerValidator, ValidationError


class Session(requests.Session):
"""An HTTP over UNIX sockets Session
Expand Down Expand Up @@ -65,6 +67,21 @@ def get(self):
self._api.error_callback("GET", self.resource, str(e))
raise
assert res.status_code == HTTPStatus.OK, res.json()

# Validate response against Swagger specification
# only validate successful requests
if self._api.validator and res.status_code == HTTPStatus.OK:
try:
response_body = res.json()
self._api.validator.validate_response(
"GET", self.resource, 200, response_body
)
except ValidationError as e:
# Re-raise with more context
raise ValidationError(
f"Response validation failed for GET {self.resource}: {e.message}"
) from e

return res

def request(self, method, path, **kwargs):
Expand All @@ -85,6 +102,32 @@ def request(self, method, path, **kwargs):
elif "error" in json:
msg = json["error"]
raise RuntimeError(msg, json, res)

# Validate request against Swagger specification
# do this after the actual request as we only want to validate successful
# requests as the tests may be trying to pass bad requests and assert an
# error is raised.
if self._api.validator:
if kwargs:
try:
self._api.validator.validate_request(method, path, kwargs)
except ValidationError as e:
# Re-raise with more context
raise ValidationError(
f"Request validation failed for {method} {path}: {e.message}"
) from e

if res.status_code == HTTPStatus.OK:
try:
response_body = res.json()
self._api.validator.validate_response(
method, path, 200, response_body
)
except ValidationError as e:
# Re-raise with more context
raise ValidationError(
f"Response validation failed for {method} {path}: {e.message}"
) from e
return res

def put(self, **kwargs):
Expand All @@ -105,13 +148,16 @@ def patch(self, **kwargs):
class Api:
"""A simple HTTP client for the Firecracker API"""

def __init__(self, api_usocket_full_name, *, on_error=None):
def __init__(self, api_usocket_full_name, *, validate=True, on_error=None):
self.error_callback = on_error
self.socket = api_usocket_full_name
url_encoded_path = urllib.parse.quote_plus(api_usocket_full_name)
self.endpoint = DEFAULT_SCHEME + url_encoded_path
self.session = Session()

# Initialize the swagger validator
self.validator = SwaggerValidator() if validate else None

self.describe = Resource(self, "/")
self.vm = Resource(self, "/vm")
self.vm_config = Resource(self, "/vm/config")
Expand Down
2 changes: 2 additions & 0 deletions tests/framework/microvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,13 +634,15 @@ def spawn(
log_show_origin=False,
metrics_path="fc.ndjson",
emit_metrics: bool = False,
validate_api: bool = True,
):
"""Start a microVM as a daemon or in a screen session."""
# pylint: disable=subprocess-run-check
# pylint: disable=too-many-branches
self.jailer.setup()
self.api = Api(
self.jailer.api_socket_path(),
validate=validate_api,
on_error=lambda verb, uri, err_msg: self._dump_debug_information(
f"Error during {verb} {uri}: {err_msg}"
),
Expand Down
Loading