12
12
import pytest
13
13
14
14
from framework import utils
15
+ from framework .artifacts import NetIfaceConfig
16
+ from framework .utils import generate_mmds_session_token , \
17
+ generate_mmds_v2_get_request
18
+ import host_tools .network as net_tools
15
19
16
20
17
21
def _configure_vm_from_json (test_microvm , vm_config_file ):
18
- """Configure a microvm using a file sent as command line parameter.
22
+ """
23
+ Configure a microvm using a file sent as command line parameter.
19
24
20
25
Create resources needed for the configuration of the microvm and
21
26
set as configuration file a copy of the file that was passed as
@@ -42,7 +47,8 @@ def _configure_vm_from_json(test_microvm, vm_config_file):
42
47
43
48
44
49
def _add_metadata_file (test_microvm , metadata_file ):
45
- """Configure the microvm using a metadata file.
50
+ """
51
+ Configure the microvm using a metadata file.
46
52
47
53
Given a test metadata file this creates a copy of the file and
48
54
uses the copy to configure the microvm.
@@ -55,6 +61,70 @@ def _add_metadata_file(test_microvm, metadata_file):
55
61
test_microvm .metadata_file = vm_metadata_path
56
62
57
63
64
+ def _configure_network_interface (test_microvm ):
65
+ """
66
+ Create tap interface before spawning the microVM.
67
+
68
+ The network namespace and tap interface have to be created
69
+ beforehand when starting the microVM from a config file.
70
+ """
71
+ # Create network namespace.
72
+ utils .run_cmd (f"ip netns add { test_microvm .jailer .netns } " )
73
+
74
+ # Create tap device and SSH config.
75
+ net_iface = NetIfaceConfig ()
76
+ _tap = test_microvm .create_tap_and_ssh_config (net_iface .host_ip ,
77
+ net_iface .guest_ip ,
78
+ net_iface .netmask ,
79
+ net_iface .tap_name )
80
+
81
+
82
+ def _build_cmd_to_fetch_metadata (ssh_connection , version , ipv4_address ):
83
+ """
84
+ Build command to fetch metadata from the guest's side.
85
+
86
+ The request is built based on the MMDS version configured.
87
+ If MMDSv2 is used, a session token must be created before
88
+ the `GET` request.
89
+ """
90
+ # Fetch data from MMDS from the guest's side.
91
+ if version == "V1" :
92
+ cmd = 'curl -s -H "Accept: application/json" '
93
+ cmd += 'http://{}' .format (ipv4_address )
94
+
95
+ else :
96
+ # If MMDS is configured to version 2, so we need to create
97
+ # the session token first.
98
+ token = generate_mmds_session_token (
99
+ ssh_connection ,
100
+ ipv4_address ,
101
+ token_ttl = 60
102
+ )
103
+ cmd = generate_mmds_v2_get_request (ipv4_address , token )
104
+
105
+ return cmd
106
+
107
+
108
+ def _get_optional_fields_from_file (vm_config_file ):
109
+ """
110
+ Retrieve optional `version` and `ipv4_address` fields from MMDS config.
111
+
112
+ Parse the vm config json file and retrieves optional fields from MMDS
113
+ config. Default values are used for the fields that are not specified.
114
+
115
+ :return: a pair of (version, ipv4_address) fields from mmds config.
116
+ """
117
+ # Get MMDS version and IPv4 address configured from the file.
118
+ with open (vm_config_file , encoding = 'utf-8' ) as json_file :
119
+ mmds_config = json .load (json_file )["mmds-config" ]
120
+ # Default to V1 if version is not specified.
121
+ version = mmds_config .get ("version" , "V1" )
122
+ # Set to default if IPv4 is not specified .
123
+ ipv4_address = mmds_config .get ("ipv4_address" , "169.254.169.254" )
124
+
125
+ return version , ipv4_address
126
+
127
+
58
128
@pytest .mark .parametrize (
59
129
"vm_config_file" ,
60
130
["framework/vm_config.json" ]
@@ -287,19 +357,125 @@ def test_start_with_invalid_metadata(test_microvm_with_api):
287
357
)
288
358
289
359
290
- def test_with_config_and_metadata_no_api (test_microvm_with_api ):
360
+ @pytest .mark .parametrize (
361
+ "vm_config_file" ,
362
+ [
363
+ "framework/vm_config_with_mmdsv1.json" ,
364
+ "framework/vm_config_with_mmdsv2.json"
365
+ ]
366
+ )
367
+ def test_config_start_and_mmds_with_api (test_microvm_with_api , vm_config_file ):
291
368
"""
292
- Test microvm start when config/mmds and API server thread is disable .
369
+ Test MMDS behavior when the microvm is configured from file .
293
370
294
371
@type: functional
295
372
"""
296
- vm_config_file = "framework/vm_config.json"
297
- metadata_file = "../resources/tests/metadata.json"
373
+ test_microvm = test_microvm_with_api
374
+
375
+ _configure_vm_from_json (test_microvm , vm_config_file )
376
+ _configure_network_interface (test_microvm )
377
+
378
+ # Network namespace has already been created.
379
+ test_microvm .spawn ()
380
+
381
+ response = test_microvm .machine_cfg .get ()
382
+ assert test_microvm .api_session .is_status_ok (response .status_code )
383
+ assert test_microvm .state == "Running"
384
+
385
+ data_store = {
386
+ 'latest' : {
387
+ 'meta-data' : {
388
+ 'ami-id' : 'ami-12345678' ,
389
+ 'reservation-id' : 'r-fea54097'
390
+ }
391
+ }
392
+ }
393
+
394
+ # MMDS should be empty by default.
395
+ response = test_microvm .mmds .get ()
396
+ assert test_microvm .api_session .is_status_ok (response .status_code )
397
+ assert response .json () == {}
398
+
399
+ # Populate MMDS with data.
400
+ response = test_microvm .mmds .put (json = data_store )
401
+ assert test_microvm .api_session .is_status_no_content (response .status_code )
402
+
403
+ # Ensure the MMDS contents have been successfully updated.
404
+ response = test_microvm .mmds .get ()
405
+ assert test_microvm .api_session .is_status_ok (response .status_code )
406
+ assert response .json () == data_store
407
+
408
+ ssh_connection = net_tools .SSHConnection (test_microvm .ssh_config )
409
+
410
+ # Get MMDS version and IPv4 address configured from the file.
411
+ version , ipv4_address = _get_optional_fields_from_file (vm_config_file )
412
+
413
+ cmd = 'ip route add {} dev eth0' .format (ipv4_address )
414
+ _ , stdout , stderr = ssh_connection .execute_command (cmd )
415
+ assert stderr .read () == stdout .read () == ''
416
+
417
+ # Fetch data from MMDS from the guest's side.
418
+ cmd = _build_cmd_to_fetch_metadata (ssh_connection , version , ipv4_address )
419
+ cmd += '/latest/meta-data/'
420
+ _ , stdout , _ = ssh_connection .execute_command (cmd )
421
+ assert json .load (stdout ) == data_store ['latest' ]['meta-data' ]
422
+
423
+ # Validate MMDS configuration.
424
+ response = test_microvm .full_cfg .get ()
425
+ assert test_microvm .api_session .is_status_ok (response .status_code )
426
+ assert response .json ()["mmds-config" ] == {
427
+ 'network_interfaces' : ['1' ],
428
+ 'ipv4_address' : ipv4_address ,
429
+ 'version' : version
430
+ }
298
431
432
+
433
+ @pytest .mark .parametrize (
434
+ "vm_config_file" ,
435
+ [
436
+ "framework/vm_config_with_mmdsv1.json" ,
437
+ "framework/vm_config_with_mmdsv2.json"
438
+ ]
439
+ )
440
+ @pytest .mark .parametrize (
441
+ "metadata_file" ,
442
+ ["../resources/tests/metadata.json" ]
443
+ )
444
+ def test_with_config_and_metadata_no_api (
445
+ test_microvm_with_api ,
446
+ vm_config_file ,
447
+ metadata_file
448
+ ):
449
+ """
450
+ Test microvm start when config/mmds and API server thread is disabled.
451
+
452
+ Ensures the metadata is stored successfully inside the MMDS and
453
+ is available to reach from the guest's side.
454
+
455
+ @type: functional
456
+ """
299
457
test_microvm = test_microvm_with_api
300
458
301
459
_configure_vm_from_json (test_microvm , vm_config_file )
302
460
_add_metadata_file (test_microvm , metadata_file )
461
+ _configure_network_interface (test_microvm )
303
462
test_microvm .jailer .extra_args .update ({'no-api' : None })
304
463
305
464
test_microvm .spawn ()
465
+
466
+ ssh_connection = net_tools .SSHConnection (test_microvm .ssh_config )
467
+
468
+ # Get MMDS version and IPv4 address configured from the file.
469
+ version , ipv4_address = _get_optional_fields_from_file (vm_config_file )
470
+
471
+ cmd = 'ip route add {} dev eth0' .format (ipv4_address )
472
+ _ , stdout , stderr = ssh_connection .execute_command (cmd )
473
+ assert stderr .read () == stdout .read () == ''
474
+
475
+ # Fetch data from MMDS from the guest's side.
476
+ cmd = _build_cmd_to_fetch_metadata (ssh_connection , version , ipv4_address )
477
+ _ , stdout , _ = ssh_connection .execute_command (cmd )
478
+
479
+ # Compare response against the expected MMDS contents.
480
+ with open (metadata_file , encoding = 'utf-8' ) as metadata :
481
+ assert json .load (stdout ) == json .load (metadata )
0 commit comments