Path: blob/main/tests/integration_tests/functional/test_mmds.py
1958 views
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.1# SPDX-License-Identifier: Apache-2.02"""Tests that verify MMDS related functionality."""34import json5import random6import string7import host_tools.network as net_tools8910def _assert_out(stdout, stderr, expected):11assert stderr.read() == ''12assert stdout.read() == expected131415def test_custom_ipv4(test_microvm_with_ssh, network_config):16"""Test the API for MMDS custom ipv4 support."""17test_microvm = test_microvm_with_ssh18test_microvm.spawn()1920response = test_microvm.mmds.get()21assert test_microvm.api_session.is_status_ok(response.status_code)22assert response.json() == {}2324data_store = {25'latest': {26'meta-data': {27'ami-id': 'ami-12345678',28'reservation-id': 'r-fea54097',29'local-hostname': 'ip-10-251-50-12.ec2.internal',30'public-hostname': 'ec2-203-0-113-25.compute-1.amazonaws.com',31'network': {32'interfaces': {33'macs': {34'02:29:96:8f:6a:2d': {35'device-number': '13345342',36'local-hostname': 'localhost',37'subnet-id': 'subnet-be9b61d'38}39}40}41}42}43}44}45response = test_microvm.mmds.put(json=data_store)46assert test_microvm.api_session.is_status_no_content(response.status_code)4748response = test_microvm.mmds.get()49assert test_microvm.api_session.is_status_ok(response.status_code)50assert response.json() == data_store5152config_data = {53'ipv4_address': ''54}55response = test_microvm.mmds.put_config(json=config_data)56assert test_microvm.api_session.is_status_bad_request(response.status_code)5758config_data = {59'ipv4_address': '1.1.1.1'60}61response = test_microvm.mmds.put_config(json=config_data)62assert test_microvm.api_session.is_status_bad_request(response.status_code)6364config_data = {65'ipv4_address': '169.254.169.250'66}67response = test_microvm.mmds.put_config(json=config_data)68assert test_microvm.api_session.is_status_no_content(response.status_code)6970test_microvm.basic_config(vcpu_count=1)71_tap = test_microvm.ssh_network_config(72network_config,73'1',74allow_mmds_requests=True75)7677test_microvm.start()78ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)7980response = test_microvm.mmds.put_config(json=config_data)81assert test_microvm.api_session.is_status_bad_request(response.status_code)8283cmd = 'ip route add 169.254.169.250 dev eth0'84_, stdout, stderr = ssh_connection.execute_command(cmd)85_assert_out(stdout, stderr, '')8687pre = 'curl -s -H "Accept: application/json" http://169.254.169.250/'8889cmd = pre + 'latest/meta-data/ami-id'90_, stdout, _ = ssh_connection.execute_command(cmd)91assert json.load(stdout) == 'ami-12345678'9293# The request is still valid if we append a94# trailing slash to a leaf node.95cmd = pre + 'latest/meta-data/ami-id/'96_, stdout, _ = ssh_connection.execute_command(cmd)97assert json.load(stdout) == 'ami-12345678'9899cmd = pre + 'latest/meta-data/network/interfaces/macs/'\100'02:29:96:8f:6a:2d/subnet-id'101_, stdout, _ = ssh_connection.execute_command(cmd)102assert json.load(stdout) == 'subnet-be9b61d'103104# Test reading a non-leaf node WITHOUT a trailing slash.105cmd = pre + 'latest/meta-data'106_, stdout, _ = ssh_connection.execute_command(cmd)107assert json.load(stdout) == data_store['latest']['meta-data']108109# Test reading a non-leaf node with a trailing slash.110cmd = pre + 'latest/meta-data/'111_, stdout, _ = ssh_connection.execute_command(cmd)112assert json.load(stdout) == data_store['latest']['meta-data']113114115def test_json_response(test_microvm_with_ssh, network_config):116"""Test the MMDS json response."""117test_microvm = test_microvm_with_ssh118test_microvm.spawn()119120response = test_microvm.mmds.get()121assert test_microvm.api_session.is_status_ok(response.status_code)122assert response.json() == {}123124data_store = {125'latest': {126'meta-data': {127'ami-id': 'ami-12345678',128'reservation-id': 'r-fea54097',129'local-hostname': 'ip-10-251-50-12.ec2.internal',130'public-hostname': 'ec2-203-0-113-25.compute-1.amazonaws.com',131'dummy_res': ['res1', 'res2']132},133"Limits": {134"CPU": 512,135"Memory": 512136},137"Usage": {138"CPU": 12.12139}140}141}142response = test_microvm.mmds.put(json=data_store)143assert test_microvm.api_session.is_status_no_content(response.status_code)144145response = test_microvm.mmds.get()146assert test_microvm.api_session.is_status_ok(response.status_code)147assert response.json() == data_store148149test_microvm.basic_config(vcpu_count=1)150_tap = test_microvm.ssh_network_config(151network_config,152'1',153allow_mmds_requests=True154)155156test_microvm.start()157ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)158159cmd = 'ip route add 169.254.169.254 dev eth0'160_, stdout, stderr = ssh_connection.execute_command(cmd)161_assert_out(stdout, stderr, '')162163pre = 'curl -s -H "Accept: application/json" http://169.254.169.254/'164165cmd = pre + 'latest/meta-data/'166_, stdout, _ = ssh_connection.execute_command(cmd)167assert json.load(stdout) == data_store['latest']['meta-data']168169cmd = pre + 'latest/meta-data/ami-id/'170_, stdout, stderr = ssh_connection.execute_command(cmd)171assert json.load(stdout) == 'ami-12345678'172173cmd = pre + 'latest/meta-data/dummy_res/0'174_, stdout, stderr = ssh_connection.execute_command(cmd)175assert json.load(stdout) == 'res1'176177cmd = pre + 'latest/Usage/CPU'178_, stdout, stderr = ssh_connection.execute_command(cmd)179assert json.load(stdout) == 12.12180181cmd = pre + 'latest/Limits/CPU'182_, stdout, stderr = ssh_connection.execute_command(cmd)183assert json.load(stdout) == 512184185186def test_imds_response(test_microvm_with_ssh, network_config):187"""Test the MMDS IMDS response."""188test_microvm = test_microvm_with_ssh189test_microvm.spawn()190191response = test_microvm.mmds.get()192assert test_microvm.api_session.is_status_ok(response.status_code)193assert response.json() == {}194195data_store = {196'latest': {197'meta-data': {198'ami-id': 'ami-12345678',199'reservation-id': 'r-fea54097',200'local-hostname': 'ip-10-251-50-12.ec2.internal',201'public-hostname': 'ec2-203-0-113-25.compute-1.amazonaws.com',202'dummy_obj': {203'res_key': 'res_value',204},205'dummy_array': [206'arr_val1',207'arr_val2'208]209},210"Limits": {211"CPU": 512,212"Memory": 512213},214"Usage": {215"CPU": 12.12216}217}218}219response = test_microvm.mmds.put(json=data_store)220assert test_microvm.api_session.is_status_no_content(response.status_code)221222response = test_microvm.mmds.get()223assert test_microvm.api_session.is_status_ok(response.status_code)224assert response.json() == data_store225226test_microvm.basic_config(vcpu_count=1)227_tap = test_microvm.ssh_network_config(228network_config,229'1',230allow_mmds_requests=True231)232233test_microvm.start()234ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)235236cmd = 'ip route add 169.254.169.254 dev eth0'237_, stdout, stderr = ssh_connection.execute_command(cmd)238_assert_out(stdout, stderr, '')239240pre = 'curl -s http://169.254.169.254/'241242cmd = pre + 'latest/meta-data/'243_, stdout, stderr = ssh_connection.execute_command(cmd)244expected = "ami-id\n" \245"dummy_array\n"\246"dummy_obj/\n"\247"local-hostname\n"\248"public-hostname\n"\249"reservation-id"250251_assert_out(stdout, stderr, expected)252253cmd = pre + 'latest/meta-data/ami-id/'254_, stdout, stderr = ssh_connection.execute_command(cmd)255_assert_out(stdout, stderr, 'ami-12345678')256257cmd = pre + 'latest/meta-data/dummy_array/0'258_, stdout, stderr = ssh_connection.execute_command(cmd)259_assert_out(stdout, stderr, 'arr_val1')260261cmd = pre + 'latest/Usage/CPU'262_, stdout, stderr = ssh_connection.execute_command(cmd)263_assert_out(stdout, stderr, 'Cannot retrieve value. The value has an'264' unsupported type.')265266cmd = pre + 'latest/Limits/CPU'267_, stdout, stderr = ssh_connection.execute_command(cmd)268_assert_out(stdout, stderr, 'Cannot retrieve value. The value has an'269' unsupported type.')270271272def test_larger_than_mss_payloads(test_microvm_with_ssh, network_config):273"""Test MMDS content for payloads larger than MSS."""274test_microvm = test_microvm_with_ssh275test_microvm.spawn()276277# The MMDS is empty at this point.278response = test_microvm.mmds.get()279assert test_microvm.api_session.is_status_ok(response.status_code)280assert response.json() == {}281282test_microvm.basic_config(vcpu_count=1)283_tap = test_microvm.ssh_network_config(284network_config,285'1',286allow_mmds_requests=True287)288289test_microvm.start()290291# Make sure MTU is 1500 bytes.292ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)293294cmd = 'ip link set dev eth0 mtu 1500'295_, stdout, stderr = ssh_connection.execute_command(cmd)296_assert_out(stdout, stderr, "")297298cmd = 'ip a s eth0 | grep -i mtu | tr -s " " | cut -d " " -f 4,5'299_, stdout, stderr = ssh_connection.execute_command(cmd)300_assert_out(stdout, stderr, "mtu 1500\n")301302# These values are usually used by booted up guest network interfaces.303mtu = 1500304ipv4_packet_headers_len = 20305tcp_segment_headers_len = 20306mss = mtu - ipv4_packet_headers_len - tcp_segment_headers_len307308# Generate a random MMDS content, double of MSS.309letters = string.ascii_lowercase310larger_than_mss = ''.join(random.choice(letters) for i in range(2 * mss))311mss_equal = ''.join(random.choice(letters) for i in range(mss))312lower_than_mss = ''.join(random.choice(letters) for i in range(mss - 2))313data_store = {314'larger_than_mss': larger_than_mss,315'mss_equal': mss_equal,316'lower_than_mss': lower_than_mss317}318response = test_microvm.mmds.put(json=data_store)319assert test_microvm.api_session.is_status_no_content(response.status_code)320321response = test_microvm.mmds.get()322assert test_microvm.api_session.is_status_ok(response.status_code)323assert response.json() == data_store324325cmd = 'ip route add 169.254.169.254 dev eth0'326_, stdout, stderr = ssh_connection.execute_command(cmd)327_assert_out(stdout, stderr, '')328329pre = 'curl -s http://169.254.169.254/'330331cmd = pre + 'larger_than_mss'332_, stdout, stderr = ssh_connection.execute_command(cmd)333_assert_out(stdout, stderr, larger_than_mss)334335cmd = pre + 'mss_equal'336_, stdout, stderr = ssh_connection.execute_command(cmd)337_assert_out(stdout, stderr, mss_equal)338339cmd = pre + 'lower_than_mss'340_, stdout, stderr = ssh_connection.execute_command(cmd)341_assert_out(stdout, stderr, lower_than_mss)342343344def test_mmds_dummy(test_microvm_with_ssh):345"""Test the API and guest facing features of the Micro MetaData Service."""346test_microvm = test_microvm_with_ssh347test_microvm.spawn()348349# The MMDS is empty at this point.350response = test_microvm.mmds.get()351assert test_microvm.api_session.is_status_ok(response.status_code)352assert response.json() == {}353354# Test that patch return NotInitialized when the MMDS is not initialized.355dummy_json = {356'latest': {357'meta-data': {358'ami-id': 'dummy'359}360}361}362response = test_microvm.mmds.patch(json=dummy_json)363assert test_microvm.api_session.is_status_bad_request(response.status_code)364fault_json = {365"fault_message": "The MMDS data store is not initialized."366}367assert response.json() == fault_json368369# Test that using the same json with a PUT request, the MMDS data-store is370# created.371response = test_microvm.mmds.put(json=dummy_json)372assert test_microvm.api_session.is_status_no_content(response.status_code)373374response = test_microvm.mmds.get()375assert test_microvm.api_session.is_status_ok(response.status_code)376assert response.json() == dummy_json377378response = test_microvm.mmds.get()379assert test_microvm.api_session.is_status_ok(response.status_code)380assert response.json() == dummy_json381382dummy_json = {383'latest': {384'meta-data': {385'ami-id': 'another_dummy',386'secret_key': 'eaasda48141411aeaeae'387}388}389}390response = test_microvm.mmds.patch(json=dummy_json)391assert test_microvm.api_session.is_status_no_content(response.status_code)392response = test_microvm.mmds.get()393assert test_microvm.api_session.is_status_ok(response.status_code)394assert response.json() == dummy_json395396397def test_guest_mmds_hang(test_microvm_with_ssh, network_config):398"""Test the MMDS json response."""399test_microvm = test_microvm_with_ssh400test_microvm.spawn()401402response = test_microvm.mmds.get()403assert test_microvm.api_session.is_status_ok(response.status_code)404assert response.json() == {}405406data_store = {407'latest': {408'meta-data': {409'ami-id': 'ami-12345678'410}411}412}413response = test_microvm.mmds.put(json=data_store)414assert test_microvm.api_session.is_status_no_content(response.status_code)415416response = test_microvm.mmds.get()417assert test_microvm.api_session.is_status_ok(response.status_code)418assert response.json() == data_store419420test_microvm.basic_config(vcpu_count=1)421_tap = test_microvm.ssh_network_config(422network_config,423'1',424allow_mmds_requests=True425)426427test_microvm.start()428ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)429430cmd = 'ip route add 169.254.169.254 dev eth0'431_, stdout, stderr = ssh_connection.execute_command(cmd)432_assert_out(stdout, stderr, '')433434# Test for a GET request with a content length longer than435# the actual length of the body.436cmd = 'curl -m 2 -s'437cmd += ' -X GET'438cmd += ' -H "Content-Length: 100"'439cmd += ' -H "Accept: application/json"'440cmd += ' -d "some body"'441cmd += ' http://169.254.169.254/'442443_, stdout, _ = ssh_connection.execute_command(cmd)444assert 'Invalid request' in stdout.read()445446# Do the same for a PUT request.447cmd = 'curl -m 2 -s'448cmd += ' -X PUT'449cmd += ' -H "Content-Length: 100"'450cmd += ' -H "Accept: application/json"'451cmd += ' -d "some body"'452cmd += ' http://169.254.169.254/'453454_, stdout, _ = ssh_connection.execute_command(cmd)455assert 'Invalid request' in stdout.read()456457458