コード例 #1
0
ファイル: main.py プロジェクト: acatangiu/firecracker
def validate_mmds(ssh_connection, data_store):
    """Validate that MMDS contents fetched from the guest."""
    # Configure interface to route MMDS requests
    cmd = 'ip route add {} dev {}'.format(IPV4_ADDRESS,
                                          net_iface_for_mmds.dev_name)
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    assert stdout.read() == stderr.read() == ''

    # Fetch metadata to ensure MMDS is accessible.
    token = generate_mmds_session_token(ssh_connection,
                                        IPV4_ADDRESS,
                                        token_ttl=60)

    cmd = generate_mmds_get_request(IPV4_ADDRESS, token=token)
    _, stdout, _ = ssh_connection.execute_command(cmd)
    assert json.load(stdout) == data_store
コード例 #2
0
def _build_cmd_to_fetch_metadata(ssh_connection, version, ipv4_address):
    """
    Build command to fetch metadata from the guest's side.

    The request is built based on the MMDS version configured.
    If MMDSv2 is used, a session token must be created before
    the `GET` request.
    """
    # Fetch data from MMDS from the guest's side.
    if version == "V2":
        # If MMDS is configured to version 2, so we need to create
        # the session token first.
        token = generate_mmds_session_token(ssh_connection,
                                            ipv4_address,
                                            token_ttl=60)
    else:
        token = None

    return generate_mmds_get_request(ipv4_address, token)
def _test_mmds(vm, mmds_net_iface):
    # Populate MMDS.
    data_store = {"latest": {"meta-data": {"ami-id": "ami-12345678"}}}
    _populate_data_store(vm, data_store)

    mmds_ipv4_address = "169.254.169.254"
    vm.ssh_config["hostname"] = mmds_net_iface.guest_ip
    ssh_connection = net_tools.SSHConnection(vm.ssh_config)

    # Insert new rule into the routing table of the guest.
    cmd = "ip route add {} dev {}".format(
        mmds_net_iface.guest_ip, mmds_net_iface.dev_name
    )
    code, _, _ = ssh_connection.execute_command(cmd)
    assert code == 0

    # The base microVM had MMDS version 2 configured, which was persisted
    # across the snapshot-restore.
    token = generate_mmds_session_token(ssh_connection, mmds_ipv4_address, token_ttl=60)

    cmd = generate_mmds_get_request(mmds_ipv4_address, token=token)
    _, stdout, _ = ssh_connection.execute_command(cmd)
    assert json.load(stdout) == data_store
コード例 #4
0
def test_mmds_snapshot(bin_cloner_path):
    """
    Exercise MMDS behavior with snapshots.

    Ensures that MMDS V2 behavior is not affected by taking a snapshot
    and that MMDS V2 is not available after snapshot load.

    @type: functional
    """
    vm_builder = MicrovmBuilder(bin_cloner_path)
    net_iface = NetIfaceConfig()
    vm_instance = vm_builder.build_vm_nano(
        net_ifaces=[net_iface],
        diff_snapshots=True
    )
    test_microvm = vm_instance.vm
    root_disk = vm_instance.disks[0]
    ssh_key = vm_instance.ssh_key

    ipv4_address = '169.254.169.250'
    # Configure MMDS version with custom IPv4 address.
    _configure_mmds(
        test_microvm,
        version='V2',
        iface_id=DEFAULT_DEV_NAME,
        ipv4_address=ipv4_address
    )

    data_store = {
        'latest': {
            'meta-data': {
                'ami-id': 'ami-12345678'
            }
        }
    }
    _populate_data_store(test_microvm, data_store)

    test_microvm.start()

    snapshot_builder = SnapshotBuilder(test_microvm)
    disks = [root_disk.local_path()]

    ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)
    cmd = 'ip route add {} dev eth0'.format(ipv4_address)
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, '')

    # Generate token.
    token = generate_mmds_session_token(
        ssh_connection,
        ipv4_address=ipv4_address,
        token_ttl=60
    )

    pre = 'curl -m 2 -s'
    pre += ' -X GET'
    pre += ' -H  "X-metadata-token: {}"'.format(token)
    pre += ' http://{}/'.format(ipv4_address)

    # Fetch metadata.
    cmd = pre + 'latest/meta-data/'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, "ami-id")

    # Create diff snapshot.
    snapshot = snapshot_builder.create(disks,
                                       ssh_key,
                                       SnapshotType.DIFF)

    # Resume microVM and ensure session token is still valid on the base.
    response = test_microvm.vm.patch(state='Resumed')
    assert test_microvm.api_session.is_status_no_content(response.status_code)

    _, stdout, stderr = ssh_connection.execute_command(
        pre + 'latest/meta-data/'
    )
    _assert_out(stdout, stderr, "ami-id")

    # Kill base microVM.
    test_microvm.kill()

    # Load microVM clone from snapshot.
    test_microvm, _ = vm_builder.build_from_snapshot(snapshot,
                                                     resume=True,
                                                     diff_snapshots=True)
    _populate_data_store(test_microvm, data_store)
    ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)

    # Mmds V2 is not available with snapshots.
    # Test that `PUT` requests are not allowed.
    cmd = 'curl -m 2 -s'
    cmd += ' -X PUT'
    cmd += ' -H  "X-metadata-token-ttl-seconds: 1"'
    cmd += ' http://{}/latest/api/token'.format(ipv4_address)
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    expected = "Not allowed HTTP method."
    _assert_out(stdout, stderr, expected)

    # Fetch metadata using V1 requests and ensure IPv4 configuration
    # is persistent between snapshots.
    cmd = 'curl -s http://{}/latest/meta-data/ami-id/'.format(ipv4_address)
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, 'ami-12345678')
コード例 #5
0
def test_custom_ipv4(test_microvm_with_api, network_config, version):
    """
    Test the API for MMDS custom ipv4 support.

    @type: functional
    """
    test_microvm = test_microvm_with_api
    test_microvm.spawn()

    data_store = {
        'latest': {
            'meta-data': {
                'ami-id': 'ami-12345678',
                'reservation-id': 'r-fea54097',
                'local-hostname': 'ip-10-251-50-12.ec2.internal',
                'public-hostname': 'ec2-203-0-113-25.compute-1.amazonaws.com',
                'network': {
                    'interfaces': {
                        'macs': {
                            '02:29:96:8f:6a:2d': {
                                'device-number': '13345342',
                                'local-hostname': 'localhost',
                                'subnet-id': 'subnet-be9b61d'
                            }
                        }
                    }
                }
            }
        }
    }
    _populate_data_store(test_microvm, data_store)

    # Attach network device.
    _tap = test_microvm.ssh_network_config(network_config, '1')

    # Invalid values IPv4 address.
    response = test_microvm.mmds.put_config(json={
        'ipv4_address': '',
        'network_interfaces': ['1']
    })
    assert test_microvm.api_session.is_status_bad_request(response.status_code)

    response = test_microvm.mmds.put_config(json={
        'ipv4_address': '1.1.1.1',
        'network_interfaces': ['1']
    })
    assert test_microvm.api_session.is_status_bad_request(response.status_code)

    ipv4_address = '169.254.169.250'
    # Configure MMDS with custom IPv4 address.
    _configure_mmds(
        test_microvm,
        iface_id='1',
        version=version,
        ipv4_address=ipv4_address
    )

    test_microvm.basic_config(vcpu_count=1)
    test_microvm.start()
    ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)

    cmd = 'ip route add {} dev eth0'.format(ipv4_address)
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, '')

    if version == 'V2':
        # Generate token.
        token = generate_mmds_session_token(
            ssh_connection,
            ipv4_address=ipv4_address,
            token_ttl=60
        )

        pre = generate_mmds_v2_get_request(
            ipv4_address=ipv4_address,
            token=token
        )
    else:
        pre = 'curl -s -H "Accept: application/json" ' \
                'http://{}/'.format(ipv4_address)

    cmd = pre + 'latest/meta-data/ami-id'
    _, stdout, _ = ssh_connection.execute_command(cmd)
    assert json.load(stdout) == 'ami-12345678'

    # The request is still valid if we append a
    # trailing slash to a leaf node.
    cmd = pre + 'latest/meta-data/ami-id/'
    _, stdout, _ = ssh_connection.execute_command(cmd)
    assert json.load(stdout) == 'ami-12345678'

    cmd = pre + 'latest/meta-data/network/interfaces/macs/' \
                '02:29:96:8f:6a:2d/subnet-id'
    _, stdout, _ = ssh_connection.execute_command(cmd)
    assert json.load(stdout) == 'subnet-be9b61d'

    # Test reading a non-leaf node WITHOUT a trailing slash.
    cmd = pre + 'latest/meta-data'
    _, stdout, _ = ssh_connection.execute_command(cmd)
    assert json.load(stdout) == data_store['latest']['meta-data']

    # Test reading a non-leaf node with a trailing slash.
    cmd = pre + 'latest/meta-data/'
    _, stdout, _ = ssh_connection.execute_command(cmd)
    assert json.load(stdout) == data_store['latest']['meta-data']
コード例 #6
0
def test_guest_mmds_hang(test_microvm_with_api, network_config, version):
    """
    Test the MMDS json endpoint when Content-Length larger than actual length.

    @type: functional
    """
    test_microvm = test_microvm_with_api
    test_microvm.spawn()

    # Attach network device.
    _tap = test_microvm.ssh_network_config(network_config, '1')
    # Configure MMDS version.
    _configure_mmds(test_microvm, iface_id='1', version=version)

    data_store = {
        'latest': {
            'meta-data': {
                'ami-id': 'ami-12345678'
            }
        }
    }
    _populate_data_store(test_microvm, data_store)

    test_microvm.basic_config(vcpu_count=1)
    test_microvm.start()
    ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)

    cmd = 'ip route add {} dev eth0'.format(DEFAULT_IPV4)
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, '')

    get_cmd = 'curl -m 2 -s'
    get_cmd += ' -X GET'
    get_cmd += ' -H  "Content-Length: 100"'
    get_cmd += ' -H "Accept: application/json"'
    get_cmd += ' -d "some body"'
    get_cmd += ' http://{}/'.format(DEFAULT_IPV4)

    if version == 'V1':
        _, stdout, _ = ssh_connection.execute_command(get_cmd)
        assert 'Invalid request' in stdout.read()
    else:
        # Generate token.
        token = generate_mmds_session_token(
            ssh_connection,
            ipv4_address=DEFAULT_IPV4,
            token_ttl=60
        )

        get_cmd += ' -H  "X-metadata-token: {}"'.format(token)
        _, stdout, _ = ssh_connection.execute_command(get_cmd)
        assert 'Invalid request' in stdout.read()

        # Do the same for a PUT request.
        cmd = 'curl -m 2 -s'
        cmd += ' -X PUT'
        cmd += ' -H  "Content-Length: 100"'
        cmd += ' -H  "X-metadata-token: {}"'.format(token)
        cmd += ' -H "Accept: application/json"'
        cmd += ' -d "some body"'
        cmd += ' http://{}/'.format(DEFAULT_IPV4)

        _, stdout, _ = ssh_connection.execute_command(cmd)
        assert 'Invalid request' in stdout.read()
コード例 #7
0
def test_larger_than_mss_payloads(
        test_microvm_with_api,
        network_config,
        version):
    """
    Test MMDS content for payloads larger than MSS.

    @type: functional
    """
    test_microvm = test_microvm_with_api
    test_microvm.spawn()

    # Attach network device.
    _tap = test_microvm.ssh_network_config(network_config, '1')
    # Configure MMDS version.
    _configure_mmds(test_microvm, iface_id='1', version=version)

    # The MMDS is empty at this point.
    response = test_microvm.mmds.get()
    assert test_microvm.api_session.is_status_ok(response.status_code)
    assert response.json() == {}

    test_microvm.basic_config(vcpu_count=1)
    test_microvm.start()

    # Make sure MTU is 1500 bytes.
    ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)

    cmd = 'ip link set dev eth0 mtu 1500'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, "")

    cmd = 'ip a s eth0 | grep -i mtu | tr -s " " | cut -d " " -f 4,5'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, "mtu 1500\n")

    # These values are usually used by booted up guest network interfaces.
    mtu = 1500
    ipv4_packet_headers_len = 20
    tcp_segment_headers_len = 20
    mss = mtu - ipv4_packet_headers_len - tcp_segment_headers_len

    # Generate a random MMDS content, double of MSS.
    letters = string.ascii_lowercase
    larger_than_mss = ''.join(random.choice(letters) for i in range(2 * mss))
    mss_equal = ''.join(random.choice(letters) for i in range(mss))
    lower_than_mss = ''.join(random.choice(letters) for i in range(mss - 2))
    data_store = {
        'larger_than_mss': larger_than_mss,
        'mss_equal': mss_equal,
        'lower_than_mss': lower_than_mss
    }
    response = test_microvm.mmds.put(json=data_store)
    assert test_microvm.api_session.is_status_no_content(response.status_code)

    response = test_microvm.mmds.get()
    assert test_microvm.api_session.is_status_ok(response.status_code)
    assert response.json() == data_store

    cmd = 'ip route add {} dev eth0'.format(DEFAULT_IPV4)
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, '')

    if version == 'V2':
        # Generate token.
        token = generate_mmds_session_token(
            ssh_connection,
            ipv4_address=DEFAULT_IPV4,
            token_ttl=60
        )

        pre = generate_mmds_v2_get_request(
            ipv4_address=DEFAULT_IPV4,
            token=token,
            app_json=False
        )
    else:
        pre = 'curl -s http://{}/'.format(DEFAULT_IPV4)

    cmd = pre + 'larger_than_mss'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, larger_than_mss)

    cmd = pre + 'mss_equal'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, mss_equal)

    cmd = pre + 'lower_than_mss'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, lower_than_mss)
コード例 #8
0
def test_mmds_response(test_microvm_with_api, network_config, version):
    """
    Test MMDS responses to various datastore requests.

    @type: functional
    """
    test_microvm = test_microvm_with_api
    test_microvm.spawn()

    data_store = {
        'latest': {
            'meta-data': {
                'ami-id': 'ami-12345678',
                'reservation-id': 'r-fea54097',
                'local-hostname': 'ip-10-251-50-12.ec2.internal',
                'public-hostname': 'ec2-203-0-113-25.compute-1.amazonaws.com',
                'dummy_obj': {
                    'res_key': 'res_value',
                },
                'dummy_array': [
                    'arr_val1',
                    'arr_val2'
                ]
            },
            "Limits": {
                "CPU": 512,
                "Memory": 512
            },
            "Usage": {
                "CPU": 12.12
            }
        }
    }

    # Attach network device.
    _tap = test_microvm.ssh_network_config(network_config, '1')

    # Configure MMDS version.
    _configure_mmds(test_microvm, iface_id='1', version=version)
    # Populate data store with contents.
    _populate_data_store(test_microvm, data_store)

    test_microvm.basic_config(vcpu_count=1)
    test_microvm.start()
    ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)

    cmd = 'ip route add {} dev eth0'.format(DEFAULT_IPV4)
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, '')

    if version == 'V2':
        # Generate token.
        token = generate_mmds_session_token(
            ssh_connection,
            ipv4_address=DEFAULT_IPV4,
            token_ttl=60
        )

        pre = generate_mmds_v2_get_request(
            ipv4_address=DEFAULT_IPV4,
            token=token,
            app_json=False
        )
    else:
        pre = 'curl -s http://{}/'.format(DEFAULT_IPV4)

    cmd = pre + 'latest/meta-data/'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    expected = "ami-id\n" \
               "dummy_array\n" \
               "dummy_obj/\n" \
               "local-hostname\n" \
               "public-hostname\n" \
               "reservation-id"

    _assert_out(stdout, stderr, expected)

    cmd = pre + 'latest/meta-data/ami-id/'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, 'ami-12345678')

    cmd = pre + 'latest/meta-data/dummy_array/0'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, 'arr_val1')

    cmd = pre + 'latest/Usage/CPU'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, 'Cannot retrieve value. The value has an'
                                ' unsupported type.')

    cmd = pre + 'latest/Limits/CPU'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, 'Cannot retrieve value. The value has an'
                                ' unsupported type.')
コード例 #9
0
def test_json_response(test_microvm_with_api, network_config, version):
    """
    Test the MMDS json response.

    @type: functional
    """
    test_microvm = test_microvm_with_api
    test_microvm.spawn()

    data_store = {
        'latest': {
            'meta-data': {
                'ami-id': 'ami-12345678',
                'reservation-id': 'r-fea54097',
                'local-hostname': 'ip-10-251-50-12.ec2.internal',
                'public-hostname': 'ec2-203-0-113-25.compute-1.amazonaws.com',
                'dummy_res': ['res1', 'res2']
            },
            "Limits": {
                "CPU": 512,
                "Memory": 512
            },
            "Usage": {
                "CPU": 12.12
            }
        }
    }

    # Attach network device.
    _tap = test_microvm.ssh_network_config(network_config, '1')

    # Configure MMDS version.
    _configure_mmds(test_microvm, iface_id='1', version=version)

    # Populate data store with contents.
    _populate_data_store(test_microvm, data_store)

    test_microvm.basic_config(vcpu_count=1)
    test_microvm.start()
    ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)

    cmd = 'ip route add {} dev eth0'.format(DEFAULT_IPV4)
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    _assert_out(stdout, stderr, '')

    if version == 'V2':
        # Generate token.
        token = generate_mmds_session_token(
                ssh_connection,
                ipv4_address=DEFAULT_IPV4,
                token_ttl=60
        )

        pre = generate_mmds_v2_get_request(DEFAULT_IPV4, token)
    else:
        pre = 'curl -s -H "Accept: application/json"' \
                ' http://{}/'.format(DEFAULT_IPV4)

    cmd = pre + 'latest/meta-data/'
    _, stdout, _ = ssh_connection.execute_command(cmd)
    assert json.load(stdout) == data_store['latest']['meta-data']

    cmd = pre + 'latest/meta-data/ami-id/'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    assert json.load(stdout) == 'ami-12345678'

    cmd = pre + 'latest/meta-data/dummy_res/0'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    assert json.load(stdout) == 'res1'

    cmd = pre + 'latest/Usage/CPU'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    assert json.load(stdout) == 12.12

    cmd = pre + 'latest/Limits/CPU'
    _, stdout, stderr = ssh_connection.execute_command(cmd)
    assert json.load(stdout) == 512
コード例 #10
0
def _validate_mmds_snapshot(
    vm_instance,
    vm_builder,
    version,
    target_fc_version=None,
    fc_path=None,
    jailer_path=None
):
    """Test MMDS behaviour across snap-restore."""
    basevm = vm_instance.vm
    root_disk = vm_instance.disks[0]
    disks = [root_disk.local_path()]
    ssh_key = vm_instance.ssh_key
    ipv4_address = '169.254.169.250'

    # Configure MMDS version with custom IPv4 address.
    configure_mmds(
        basevm,
        version=version,
        iface_ids=[DEFAULT_DEV_NAME],
        ipv4_address=ipv4_address,
        fc_version=target_fc_version
    )

    # Check if the FC version supports the latest format for mmds-config.
    # If target_fc_version is None, we assume the current version is used.
    if target_fc_version is None or \
            (target_fc_version is not None and
             compare_versions(target_fc_version, "1.0.0") >= 0):
        expected_mmds_config = {
            "version": version,
            "ipv4_address": ipv4_address,
            "network_interfaces": [DEFAULT_DEV_NAME]
        }
        response = basevm.full_cfg.get()
        assert basevm.api_session.is_status_ok(response.status_code)
        assert response.json()["mmds-config"] == expected_mmds_config

    data_store = {
        'latest': {
            'meta-data': {
                'ami-id': 'ami-12345678'
            }
        }
    }
    _populate_data_store(basevm, data_store)

    basevm.start()

    snapshot_builder = SnapshotBuilder(basevm)

    ssh_connection = net_tools.SSHConnection(basevm.ssh_config)
    _run_guest_cmd(ssh_connection, f'ip route add {ipv4_address} dev eth0', '')

    # Generate token if needed.
    token = None
    if version == "V2":
        token = generate_mmds_session_token(
            ssh_connection,
            ipv4_address,
            token_ttl=60
        )

    # Fetch metadata.
    cmd = generate_mmds_get_request(
        ipv4_address,
        token=token,
    )
    _run_guest_cmd(ssh_connection, cmd, data_store, use_json=True)

    # Create snapshot.
    snapshot = snapshot_builder.create(disks,
                                       ssh_key,
                                       SnapshotType.FULL,
                                       target_version=target_fc_version)

    # Resume microVM and ensure session token is still valid on the base.
    response = basevm.vm.patch(state='Resumed')
    assert basevm.api_session.is_status_no_content(response.status_code)

    # Fetch metadata again using the same token.
    _run_guest_cmd(ssh_connection, cmd, data_store, use_json=True)

    # Kill base microVM.
    basevm.kill()

    # Load microVM clone from snapshot.
    microvm, _ = vm_builder.build_from_snapshot(snapshot,
                                                resume=True,
                                                fc_binary=fc_path,
                                                jailer_binary=jailer_path)

    ssh_connection = net_tools.SSHConnection(microvm.ssh_config)

    # Check the reported mmds config. In versions up to (including) v1.0.0 this
    # was not populated after restore.
    if target_fc_version is not None and \
            compare_versions("1.0.0", target_fc_version) < 0:
        response = microvm.full_cfg.get()
        assert microvm.api_session.is_status_ok(response.status_code)
        assert response.json()["mmds-config"] == expected_mmds_config

    if version == 'V1':
        # Verify that V2 requests don't work
        assert generate_mmds_session_token(
            ssh_connection,
            ipv4_address,
            token_ttl=60
        ) == "Not allowed HTTP method."

        token = None
    else:
        # Attempting to reuse the token across a restore must fail.
        cmd = generate_mmds_get_request(ipv4_address, token=token)
        _run_guest_cmd(ssh_connection, cmd, 'MMDS token not valid.')

        # Generate token.
        token = generate_mmds_session_token(
            ssh_connection,
            ipv4_address,
            token_ttl=60
        )

    # Data store is empty after a restore.
    cmd = generate_mmds_get_request(ipv4_address, token=token)
    _run_guest_cmd(ssh_connection, cmd, 'null')

    # Now populate the store.
    _populate_data_store(microvm, data_store)

    # Fetch metadata.
    _run_guest_cmd(ssh_connection, cmd, data_store, use_json=True)
コード例 #11
0
def test_json_response(test_microvm_with_api, network_config, version):
    """
    Test the MMDS json response.

    @type: functional
    """
    test_microvm = test_microvm_with_api
    test_microvm.spawn()

    data_store = {
        'latest': {
            'meta-data': {
                'ami-id': 'ami-12345678',
                'reservation-id': 'r-fea54097',
                'local-hostname': 'ip-10-251-50-12.ec2.internal',
                'public-hostname': 'ec2-203-0-113-25.compute-1.amazonaws.com',
                'dummy_res': ['res1', 'res2']
            },
            "Limits": {
                "CPU": 512,
                "Memory": 512
            },
            "Usage": {
                "CPU": 12.12
            }
        }
    }

    # Attach network device.
    _tap = test_microvm.ssh_network_config(network_config, '1')

    # Configure MMDS version.
    configure_mmds(test_microvm, iface_ids=['1'], version=version)

    # Populate data store with contents.
    _populate_data_store(test_microvm, data_store)

    test_microvm.basic_config(vcpu_count=1)
    test_microvm.start()
    ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)

    cmd = 'ip route add {} dev eth0'.format(DEFAULT_IPV4)
    _run_guest_cmd(ssh_connection, cmd, '')

    token = None
    if version == 'V2':
        # Generate token.
        token = generate_mmds_session_token(
            ssh_connection,
            DEFAULT_IPV4,
            token_ttl=60
        )

    pre = generate_mmds_get_request(DEFAULT_IPV4, token)

    cmd = pre + 'latest/meta-data/'
    _run_guest_cmd(ssh_connection, cmd,
                   data_store['latest']['meta-data'], use_json=True)

    cmd = pre + 'latest/meta-data/ami-id/'
    _run_guest_cmd(ssh_connection, cmd, 'ami-12345678', use_json=True)

    cmd = pre + 'latest/meta-data/dummy_res/0'
    _run_guest_cmd(ssh_connection, cmd, 'res1', use_json=True)

    cmd = pre + 'latest/Usage/CPU'
    _run_guest_cmd(ssh_connection, cmd, 12.12, use_json=True)

    cmd = pre + 'latest/Limits/CPU'
    _run_guest_cmd(ssh_connection, cmd, 512, use_json=True)