Skip to content

Commit

Permalink
tests: add 'GET /vm/config' integration test
Browse files Browse the repository at this point in the history
Configures a microVM with all types of devices, then validates
full configuration export before and after boot.

Signed-off-by: Adrian Catangiu <acatan@amazon.com>
  • Loading branch information
acatangiu committed Jul 8, 2021
1 parent a0a9ed4 commit 357f7ea
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 5 deletions.
6 changes: 4 additions & 2 deletions tests/framework/microvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
from framework.http import Session
from framework.jailer import JailerContext
from framework.resources import Actions, Balloon, BootSource, Drive, \
DescribeInstance, Logger, MMDS, MachineConfigure, Metrics, Network, \
Vm, Vsock, SnapshotHelper
DescribeInstance, FullConfig, Logger, MMDS, MachineConfigure, \
Metrics, Network, Vm, Vsock, SnapshotHelper

LOG = logging.getLogger("microvm")

Expand Down Expand Up @@ -107,6 +107,7 @@ def __init__(
self.boot = None
self.desc_inst = None
self.drive = None
self.full_cfg = None
self.logger = None
self.metrics = None
self.mmds = None
Expand Down Expand Up @@ -450,6 +451,7 @@ def spawn(self, create_logger=True,
self.boot = BootSource(self._api_socket, self._api_session)
self.desc_inst = DescribeInstance(self._api_socket, self._api_session)
self.drive = Drive(self._api_socket, self._api_session)
self.full_cfg = FullConfig(self._api_socket, self._api_session)
self.logger = Logger(self._api_socket, self._api_session)
self.machine_cfg = MachineConfigure(
self._api_socket,
Expand Down
22 changes: 22 additions & 0 deletions tests/framework/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,28 @@ def create_json(
return datax


# Too few public methods (1/2) (too-few-public-methods)
# pylint: disable=R0903
class FullConfig():
"""Facility for getting the full microVM configuration."""

EXPORT_CFG_RESOURCE = 'vm/config'

def __init__(self, api_usocket_full_name, api_session):
"""Specify the information needed for sending API requests."""
url_encoded_path = urllib.parse.quote_plus(api_usocket_full_name)
api_url = API_USOCKET_URL_PREFIX + url_encoded_path + '/'

self._export_cfg_url = api_url + self.EXPORT_CFG_RESOURCE
self._api_session = api_session

def get(self):
"""Get full configuration of the current microvm."""
return self._api_session.get(
self._export_cfg_url
)


class Logger():
"""Facility for setting up the logging system and sending API requests."""

Expand Down
4 changes: 2 additions & 2 deletions tests/integration_tests/build/test_binary_size.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
"JAILER_BINARY_SIZE_LIMIT": 1511488,
},
"aarch64": {
"FC_BINARY_SIZE_TARGET": 2030000,
"FC_BINARY_SIZE_TARGET": 2080000,
"JAILER_BINARY_SIZE_TARGET": 1338312,
"FC_BINARY_SIZE_LIMIT": 2070000,
"FC_BINARY_SIZE_LIMIT": 2170000,
"JAILER_BINARY_SIZE_LIMIT": 1511488,
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/integration_tests/build/test_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
# this contains the frequency while on AMD it does not.
# Checkout the cpuid crate. In the future other
# differences may appear.
COVERAGE_DICT = {"Intel": 84.76, "AMD": 84.22, "ARM": 83.12}
COVERAGE_DICT = {"Intel": 84.84, "AMD": 84.22, "ARM": 83.05}

PROC_MODEL = proc.proc_type()

Expand Down
100 changes: 100 additions & 0 deletions tests/integration_tests/functional/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# SPDX-License-Identifier: Apache-2.0
"""Tests that ensure the correctness of the Firecracker API."""

# Disable pylint C0302: Too many lines in module
# pylint: disable=C0302
import os
import platform
import resource
Expand Down Expand Up @@ -980,6 +982,104 @@ def test_api_balloon(test_microvm_with_ssh_and_balloon):
assert test_microvm.api_session.is_status_bad_request(response.status_code)


def test_get_full_config(test_microvm_with_ssh_and_balloon):
"""Configure microVM with all resources and get configuration."""
test_microvm = test_microvm_with_ssh_and_balloon

expected_cfg = {}

test_microvm.spawn()
# Basic config also implies a root block device.
test_microvm.basic_config()
expected_cfg['machine-config'] = {
'vcpu_count': 2,
'mem_size_mib': 256,
'ht_enabled': False,
'track_dirty_pages': False
}
expected_cfg['boot-source'] = {
'kernel_image_path': '/vmlinux.bin',
'initrd_path': None
}
expected_cfg['drives'] = [{
'drive_id': 'rootfs',
'path_on_host': '/debian.rootfs.ext4',
'is_root_device': True,
'partuuid': None,
'is_read_only': False,
'cache_type': 'Unsafe',
'rate_limiter': None
}]

# Add a memory balloon device.
response = test_microvm.balloon.put(amount_mib=1, deflate_on_oom=True)
assert test_microvm.api_session.is_status_no_content(response.status_code)
expected_cfg['balloon'] = {
'amount_mib': 1,
'deflate_on_oom': True,
'stats_polling_interval_s': 0
}

# Add a vsock device.
response = test_microvm.vsock.put(
vsock_id='vsock',
guest_cid=15,
uds_path='vsock.sock'
)
assert test_microvm.api_session.is_status_no_content(response.status_code)
expected_cfg['vsock'] = {
'vsock_id': 'vsock',
'guest_cid': 15,
'uds_path': 'vsock.sock'
}

# Add a net device.
iface_id = '1'
tapname = test_microvm.id[:8] + 'tap' + iface_id
tap1 = net_tools.Tap(tapname, test_microvm.jailer.netns)
guest_mac = '06:00:00:00:00:01'
tx_rl = {
'bandwidth': {
'size': 1000000,
'refill_time': 100,
'one_time_burst': None
},
'ops': None
}
response = test_microvm.network.put(
iface_id=iface_id,
guest_mac=guest_mac,
host_dev_name=tap1.name,
tx_rate_limiter=tx_rl
)
assert test_microvm.api_session.is_status_no_content(response.status_code)
expected_cfg['network-interfaces'] = [{
'iface_id': iface_id,
'host_dev_name': tap1.name,
'guest_mac': '06:00:00:00:00:01',
'rx_rate_limiter': None,
'tx_rate_limiter': tx_rl,
'allow_mmds_requests': False
}]

expected_cfg['logger'] = None
expected_cfg['metrics'] = None
expected_cfg['mmds-config'] = None

# Getting full vm configuration should be available pre-boot.
response = test_microvm.full_cfg.get()
assert test_microvm.api_session.is_status_ok(response.status_code)
assert response.json() == expected_cfg

# Start the microvm.
test_microvm.start()

# Validate full vm configuration post-boot as well.
response = test_microvm.full_cfg.get()
assert test_microvm.api_session.is_status_ok(response.status_code)
assert response.json() == expected_cfg


def test_negative_api_lifecycle(bin_cloner_path):
"""Test some vm lifecycle error scenarios."""
builder = MicrovmBuilder(bin_cloner_path)
Expand Down

0 comments on commit 357f7ea

Please sign in to comment.