Blame tests/unittests/test_datasource/test_ec2.py

Packit Service a04d08
# This file is part of cloud-init. See LICENSE file for license information.
Packit Service a04d08
Packit Service a04d08
import copy
Packit Service a04d08
import httpretty
Packit Service a04d08
import json
Packit Service 9bfd13
import requests
Packit Service 9bfd13
from unittest import mock
Packit Service a04d08
Packit Service a04d08
from cloudinit import helpers
Packit Service a04d08
from cloudinit.sources import DataSourceEc2 as ec2
Packit Service a04d08
from cloudinit.tests import helpers as test_helpers
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
DYNAMIC_METADATA = {
Packit Service a04d08
    "instance-identity": {
Packit Service a04d08
        "document": json.dumps({
Packit Service a04d08
            "devpayProductCodes": None,
Packit Service a04d08
            "marketplaceProductCodes": ["1abc2defghijklm3nopqrs4tu"],
Packit Service a04d08
            "availabilityZone": "us-west-2b",
Packit Service a04d08
            "privateIp": "10.158.112.84",
Packit Service a04d08
            "version": "2017-09-30",
Packit Service a04d08
            "instanceId": "my-identity-id",
Packit Service a04d08
            "billingProducts": None,
Packit Service a04d08
            "instanceType": "t2.micro",
Packit Service a04d08
            "accountId": "123456789012",
Packit Service a04d08
            "imageId": "ami-5fb8c835",
Packit Service a04d08
            "pendingTime": "2016-11-19T16:32:11Z",
Packit Service a04d08
            "architecture": "x86_64",
Packit Service a04d08
            "kernelId": None,
Packit Service a04d08
            "ramdiskId": None,
Packit Service a04d08
            "region": "us-west-2"
Packit Service a04d08
        })
Packit Service a04d08
    }
Packit Service a04d08
}
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
# collected from api version 2016-09-02/ with
Packit Service a04d08
# python3 -c 'import json
Packit Service a04d08
# from cloudinit.ec2_utils import get_instance_metadata as gm
Packit Service a04d08
# print(json.dumps(gm("2016-09-02"), indent=1, sort_keys=True))'
Packit Service 9bfd13
# Note that the MAC addresses have been modified to sort in the opposite order
Packit Service 9bfd13
# to the device-number attribute, to test LP: #1876312
Packit Service a04d08
DEFAULT_METADATA = {
Packit Service a04d08
    "ami-id": "ami-8b92b4ee",
Packit Service a04d08
    "ami-launch-index": "0",
Packit Service a04d08
    "ami-manifest-path": "(unknown)",
Packit Service a04d08
    "block-device-mapping": {"ami": "/dev/sda1", "root": "/dev/sda1"},
Packit Service a04d08
    "hostname": "ip-172-31-31-158.us-east-2.compute.internal",
Packit Service a04d08
    "instance-action": "none",
Packit Service a04d08
    "instance-id": "i-0a33f80f09c96477f",
Packit Service a04d08
    "instance-type": "t2.small",
Packit Service a04d08
    "local-hostname": "ip-172-3-3-15.us-east-2.compute.internal",
Packit Service a04d08
    "local-ipv4": "172.3.3.15",
Packit Service a04d08
    "mac": "06:17:04:d7:26:09",
Packit Service a04d08
    "metrics": {"vhostmd": ""},
Packit Service a04d08
    "network": {
Packit Service a04d08
        "interfaces": {
Packit Service a04d08
            "macs": {
Packit Service a04d08
                "06:17:04:d7:26:09": {
Packit Service a04d08
                    "device-number": "0",
Packit Service a04d08
                    "interface-id": "eni-e44ef49e",
Packit Service a04d08
                    "ipv4-associations": {"13.59.77.202": "172.3.3.15"},
Packit Service a04d08
                    "ipv6s": "2600:1f16:aeb:b20b:9d87:a4af:5cc9:73dc",
Packit Service a04d08
                    "local-hostname": ("ip-172-3-3-15.us-east-2."
Packit Service a04d08
                                       "compute.internal"),
Packit Service a04d08
                    "local-ipv4s": "172.3.3.15",
Packit Service a04d08
                    "mac": "06:17:04:d7:26:09",
Packit Service a04d08
                    "owner-id": "950047163771",
Packit Service a04d08
                    "public-hostname": ("ec2-13-59-77-202.us-east-2."
Packit Service a04d08
                                        "compute.amazonaws.com"),
Packit Service a04d08
                    "public-ipv4s": "13.59.77.202",
Packit Service a04d08
                    "security-group-ids": "sg-5a61d333",
Packit Service a04d08
                    "security-groups": "wide-open",
Packit Service a04d08
                    "subnet-id": "subnet-20b8565b",
Packit Service a04d08
                    "subnet-ipv4-cidr-block": "172.31.16.0/20",
Packit Service a04d08
                    "subnet-ipv6-cidr-blocks": "2600:1f16:aeb:b20b::/64",
Packit Service a04d08
                    "vpc-id": "vpc-87e72bee",
Packit Service a04d08
                    "vpc-ipv4-cidr-block": "172.31.0.0/16",
Packit Service a04d08
                    "vpc-ipv4-cidr-blocks": "172.31.0.0/16",
Packit Service a04d08
                    "vpc-ipv6-cidr-blocks": "2600:1f16:aeb:b200::/56"
Packit Service a04d08
                },
Packit Service 9bfd13
                "06:17:04:d7:26:08": {
Packit Service a04d08
                    "device-number": "1",   # Only IPv4 local config
Packit Service a04d08
                    "interface-id": "eni-e44ef49f",
Packit Service a04d08
                    "ipv4-associations": {"": "172.3.3.16"},
Packit Service a04d08
                    "ipv6s": "",  # No IPv6 config
Packit Service a04d08
                    "local-hostname": ("ip-172-3-3-16.us-east-2."
Packit Service a04d08
                                       "compute.internal"),
Packit Service a04d08
                    "local-ipv4s": "172.3.3.16",
Packit Service 9bfd13
                    "mac": "06:17:04:d7:26:08",
Packit Service a04d08
                    "owner-id": "950047163771",
Packit Service a04d08
                    "public-hostname": ("ec2-172-3-3-16.us-east-2."
Packit Service a04d08
                                        "compute.amazonaws.com"),
Packit Service a04d08
                    "public-ipv4s": "",  # No public ipv4 config
Packit Service a04d08
                    "security-group-ids": "sg-5a61d333",
Packit Service a04d08
                    "security-groups": "wide-open",
Packit Service a04d08
                    "subnet-id": "subnet-20b8565b",
Packit Service a04d08
                    "subnet-ipv4-cidr-block": "172.31.16.0/20",
Packit Service a04d08
                    "subnet-ipv6-cidr-blocks": "",
Packit Service a04d08
                    "vpc-id": "vpc-87e72bee",
Packit Service a04d08
                    "vpc-ipv4-cidr-block": "172.31.0.0/16",
Packit Service a04d08
                    "vpc-ipv4-cidr-blocks": "172.31.0.0/16",
Packit Service a04d08
                    "vpc-ipv6-cidr-blocks": ""
Packit Service a04d08
                }
Packit Service a04d08
            }
Packit Service a04d08
        }
Packit Service a04d08
    },
Packit Service a04d08
    "placement": {"availability-zone": "us-east-2b"},
Packit Service a04d08
    "profile": "default-hvm",
Packit Service a04d08
    "public-hostname": "ec2-13-59-77-202.us-east-2.compute.amazonaws.com",
Packit Service a04d08
    "public-ipv4": "13.59.77.202",
Packit Service a04d08
    "public-keys": {"brickies": ["ssh-rsa AAAAB3Nz....w== brickies"]},
Packit Service a04d08
    "reservation-id": "r-01efbc9996bac1bd6",
Packit Service a04d08
    "security-groups": "my-wide-open",
Packit Service a04d08
    "services": {"domain": "amazonaws.com", "partition": "aws"},
Packit Service a04d08
}
Packit Service a04d08
Packit Service 9bfd13
# collected from api version 2018-09-24/ with
Packit Service 9bfd13
# python3 -c 'import json
Packit Service 9bfd13
# from cloudinit.ec2_utils import get_instance_metadata as gm
Packit Service 9bfd13
# print(json.dumps(gm("2018-09-24"), indent=1, sort_keys=True))'
Packit Service 9bfd13
Packit Service 9bfd13
NIC1_MD_IPV4_IPV6_MULTI_IP = {
Packit Service 9bfd13
    "device-number": "0",
Packit Service 9bfd13
    "interface-id": "eni-0d6335689899ce9cc",
Packit Service 9bfd13
    "ipv4-associations": {
Packit Service 9bfd13
        "18.218.219.181": "172.31.44.13"
Packit Service 9bfd13
    },
Packit Service 9bfd13
    "ipv6s": [
Packit Service 9bfd13
        "2600:1f16:292:100:c187:593c:4349:136",
Packit Service 9bfd13
        "2600:1f16:292:100:f153:12a3:c37c:11f9",
Packit Service 9bfd13
        "2600:1f16:292:100:f152:2222:3333:4444"
Packit Service 9bfd13
    ],
Packit Service 9bfd13
    "local-hostname": ("ip-172-31-44-13.us-east-2."
Packit Service 9bfd13
                       "compute.internal"),
Packit Service 9bfd13
    "local-ipv4s": [
Packit Service 9bfd13
        "172.31.44.13",
Packit Service 9bfd13
        "172.31.45.70"
Packit Service 9bfd13
    ],
Packit Service 9bfd13
    "mac": "0a:07:84:3d:6e:38",
Packit Service 9bfd13
    "owner-id": "329910648901",
Packit Service 9bfd13
    "public-hostname": ("ec2-18-218-219-181.us-east-2."
Packit Service 9bfd13
                        "compute.amazonaws.com"),
Packit Service 9bfd13
    "public-ipv4s": "18.218.219.181",
Packit Service 9bfd13
    "security-group-ids": "sg-0c387755222ba8d2e",
Packit Service 9bfd13
    "security-groups": "launch-wizard-4",
Packit Service 9bfd13
    "subnet-id": "subnet-9d7ba0d1",
Packit Service 9bfd13
    "subnet-ipv4-cidr-block": "172.31.32.0/20",
Packit Service 9bfd13
    "subnet_ipv6_cidr_blocks": "2600:1f16:292:100::/64",
Packit Service 9bfd13
    "vpc-id": "vpc-a07f62c8",
Packit Service 9bfd13
    "vpc-ipv4-cidr-block": "172.31.0.0/16",
Packit Service 9bfd13
    "vpc-ipv4-cidr-blocks": "172.31.0.0/16",
Packit Service 9bfd13
    "vpc_ipv6_cidr_blocks": "2600:1f16:292:100::/56"
Packit Service 9bfd13
}
Packit Service 9bfd13
Packit Service 9bfd13
NIC2_MD = {
Packit Service 9bfd13
    "device-number": "1",
Packit Service 9bfd13
    "interface-id": "eni-043cdce36ded5e79f",
Packit Service 9bfd13
    "local-hostname": "ip-172-31-47-221.us-east-2.compute.internal",
Packit Service 9bfd13
    "local-ipv4s": "172.31.47.221",
Packit Service 9bfd13
    "mac": "0a:75:69:92:e2:16",
Packit Service 9bfd13
    "owner-id": "329910648901",
Packit Service 9bfd13
    "security-group-ids": "sg-0d68fef37d8cc9b77",
Packit Service 9bfd13
    "security-groups": "launch-wizard-17",
Packit Service 9bfd13
    "subnet-id": "subnet-9d7ba0d1",
Packit Service 9bfd13
    "subnet-ipv4-cidr-block": "172.31.32.0/20",
Packit Service 9bfd13
    "vpc-id": "vpc-a07f62c8",
Packit Service 9bfd13
    "vpc-ipv4-cidr-block": "172.31.0.0/16",
Packit Service 9bfd13
    "vpc-ipv4-cidr-blocks": "172.31.0.0/16"
Packit Service 9bfd13
}
Packit Service 9bfd13
Packit Service 9bfd13
SECONDARY_IP_METADATA_2018_09_24 = {
Packit Service 9bfd13
    "ami-id": "ami-0986c2ac728528ac2",
Packit Service 9bfd13
    "ami-launch-index": "0",
Packit Service 9bfd13
    "ami-manifest-path": "(unknown)",
Packit Service 9bfd13
    "block-device-mapping": {
Packit Service 9bfd13
        "ami": "/dev/sda1",
Packit Service 9bfd13
        "root": "/dev/sda1"
Packit Service 9bfd13
    },
Packit Service 9bfd13
    "events": {
Packit Service 9bfd13
        "maintenance": {
Packit Service 9bfd13
            "history": "[]",
Packit Service 9bfd13
            "scheduled": "[]"
Packit Service 9bfd13
        }
Packit Service 9bfd13
    },
Packit Service 9bfd13
    "hostname": "ip-172-31-44-13.us-east-2.compute.internal",
Packit Service 9bfd13
    "identity-credentials": {
Packit Service 9bfd13
        "ec2": {
Packit Service 9bfd13
            "info": {
Packit Service 9bfd13
                "AccountId": "329910648901",
Packit Service 9bfd13
                "Code": "Success",
Packit Service 9bfd13
                "LastUpdated": "2019-07-06T14:22:56Z"
Packit Service 9bfd13
            }
Packit Service 9bfd13
        }
Packit Service 9bfd13
    },
Packit Service 9bfd13
    "instance-action": "none",
Packit Service 9bfd13
    "instance-id": "i-069e01e8cc43732f8",
Packit Service 9bfd13
    "instance-type": "t2.micro",
Packit Service 9bfd13
    "local-hostname": "ip-172-31-44-13.us-east-2.compute.internal",
Packit Service 9bfd13
    "local-ipv4": "172.31.44.13",
Packit Service 9bfd13
    "mac": "0a:07:84:3d:6e:38",
Packit Service 9bfd13
    "metrics": {
Packit Service 9bfd13
        "vhostmd": ""
Packit Service 9bfd13
    },
Packit Service 9bfd13
    "network": {
Packit Service 9bfd13
        "interfaces": {
Packit Service 9bfd13
            "macs": {
Packit Service 9bfd13
                "0a:07:84:3d:6e:38": NIC1_MD_IPV4_IPV6_MULTI_IP,
Packit Service 9bfd13
            }
Packit Service 9bfd13
        }
Packit Service 9bfd13
    },
Packit Service 9bfd13
    "placement": {
Packit Service 9bfd13
        "availability-zone": "us-east-2c"
Packit Service 9bfd13
    },
Packit Service 9bfd13
    "profile": "default-hvm",
Packit Service 9bfd13
    "public-hostname": (
Packit Service 9bfd13
        "ec2-18-218-219-181.us-east-2.compute.amazonaws.com"),
Packit Service 9bfd13
    "public-ipv4": "18.218.219.181",
Packit Service 9bfd13
    "public-keys": {
Packit Service 9bfd13
        "yourkeyname,e": [
Packit Service 9bfd13
            "ssh-rsa AAAAW...DZ yourkeyname"
Packit Service 9bfd13
        ]
Packit Service 9bfd13
    },
Packit Service 9bfd13
    "reservation-id": "r-09b4917135cdd33be",
Packit Service 9bfd13
    "security-groups": "launch-wizard-4",
Packit Service 9bfd13
    "services": {
Packit Service 9bfd13
        "domain": "amazonaws.com",
Packit Service 9bfd13
        "partition": "aws"
Packit Service 9bfd13
    }
Packit Service 9bfd13
}
Packit Service 9bfd13
Packit Service 9bfd13
M_PATH_NET = 'cloudinit.sources.DataSourceEc2.net.'
Packit Service 9bfd13
Packit Service a04d08
Packit Service a04d08
def _register_ssh_keys(rfunc, base_url, keys_data):
Packit Service a04d08
    """handle ssh key inconsistencies.
Packit Service a04d08
Packit Service a04d08
    public-keys in the ec2 metadata is inconsistently formated compared
Packit Service a04d08
    to other entries.
Packit Service a04d08
    Given keys_data of {name1: pubkey1, name2: pubkey2}
Packit Service a04d08
Packit Service a04d08
    This registers the following urls:
Packit Service a04d08
       base_url                 0={name1}\n1={name2} # (for each name)
Packit Service a04d08
       base_url/                0={name1}\n1={name2} # (for each name)
Packit Service a04d08
       base_url/0               openssh-key
Packit Service a04d08
       base_url/0/              openssh-key
Packit Service a04d08
       base_url/0/openssh-key   {pubkey1}
Packit Service a04d08
       base_url/0/openssh-key/  {pubkey1}
Packit Service a04d08
       ...
Packit Service a04d08
    """
Packit Service a04d08
Packit Service a04d08
    base_url = base_url.rstrip("/")
Packit Service a04d08
    odd_index = '\n'.join(
Packit Service a04d08
        ["{0}={1}".format(n, name)
Packit Service a04d08
         for n, name in enumerate(sorted(keys_data))])
Packit Service a04d08
Packit Service a04d08
    rfunc(base_url, odd_index)
Packit Service a04d08
    rfunc(base_url + "/", odd_index)
Packit Service a04d08
Packit Service a04d08
    for n, name in enumerate(sorted(keys_data)):
Packit Service a04d08
        val = keys_data[name]
Packit Service a04d08
        if isinstance(val, list):
Packit Service a04d08
            val = '\n'.join(val)
Packit Service a04d08
        burl = base_url + "/%s" % n
Packit Service a04d08
        rfunc(burl, "openssh-key")
Packit Service a04d08
        rfunc(burl + "/", "openssh-key")
Packit Service a04d08
        rfunc(burl + "/%s/openssh-key" % name, val)
Packit Service a04d08
        rfunc(burl + "/%s/openssh-key/" % name, val)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def register_mock_metaserver(base_url, data):
Packit Service a04d08
    """Register with httpretty a ec2 metadata like service serving 'data'.
Packit Service a04d08
Packit Service a04d08
    If given a dictionary, it will populate urls under base_url for
Packit Service a04d08
    that dictionary.  For example, input of
Packit Service a04d08
       {"instance-id": "i-abc", "mac": "00:16:3e:00:00:00"}
Packit Service a04d08
    populates
Packit Service a04d08
       base_url  with 'instance-id\nmac'
Packit Service a04d08
       base_url/ with 'instance-id\nmac'
Packit Service a04d08
       base_url/instance-id with i-abc
Packit Service a04d08
       base_url/mac with 00:16:3e:00:00:00
Packit Service a04d08
    In the index, references to lists or dictionaries have a trailing /.
Packit Service a04d08
    """
Packit Service a04d08
    def register_helper(register, base_url, body):
Packit Service a04d08
        if not isinstance(base_url, str):
Packit Service a04d08
            register(base_url, body)
Packit Service a04d08
            return
Packit Service a04d08
        base_url = base_url.rstrip("/")
Packit Service a04d08
        if isinstance(body, str):
Packit Service a04d08
            register(base_url, body)
Packit Service a04d08
        elif isinstance(body, list):
Packit Service a04d08
            register(base_url, '\n'.join(body) + '\n')
Packit Service a04d08
            register(base_url + '/', '\n'.join(body) + '\n')
Packit Service a04d08
        elif isinstance(body, dict):
Packit Service a04d08
            vals = []
Packit Service a04d08
            for k, v in body.items():
Packit Service a04d08
                if k == 'public-keys':
Packit Service a04d08
                    _register_ssh_keys(
Packit Service a04d08
                        register, base_url + '/public-keys/', v)
Packit Service a04d08
                    continue
Packit Service a04d08
                suffix = k.rstrip("/")
Packit Service a04d08
                if not isinstance(v, (str, list)):
Packit Service a04d08
                    suffix += "/"
Packit Service a04d08
                vals.append(suffix)
Packit Service a04d08
                url = base_url + '/' + suffix
Packit Service a04d08
                register_helper(register, url, v)
Packit Service a04d08
            register(base_url, '\n'.join(vals) + '\n')
Packit Service a04d08
            register(base_url + '/', '\n'.join(vals) + '\n')
Packit Service a04d08
        elif body is None:
Packit Service a04d08
            register(base_url, 'not found', status=404)
Packit Service a04d08
Packit Service a04d08
    def myreg(*argc, **kwargs):
Packit Service a04d08
        url = argc[0]
Packit Service a04d08
        method = httpretty.PUT if ec2.API_TOKEN_ROUTE in url else httpretty.GET
Packit Service a04d08
        return httpretty.register_uri(method, *argc, **kwargs)
Packit Service a04d08
Packit Service a04d08
    register_helper(myreg, base_url, data)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class TestEc2(test_helpers.HttprettyTestCase):
Packit Service a04d08
    with_logs = True
Packit Service 9bfd13
    maxDiff = None
Packit Service a04d08
Packit Service a04d08
    valid_platform_data = {
Packit Service a04d08
        'uuid': 'ec212f79-87d1-2f1d-588f-d86dc0fd5412',
Packit Service a04d08
        'uuid_source': 'dmi',
Packit Service a04d08
        'serial': 'ec212f79-87d1-2f1d-588f-d86dc0fd5412',
Packit Service a04d08
    }
Packit Service a04d08
Packit Service a04d08
    def setUp(self):
Packit Service a04d08
        super(TestEc2, self).setUp()
Packit Service a04d08
        self.datasource = ec2.DataSourceEc2
Packit Service a04d08
        self.metadata_addr = self.datasource.metadata_urls[0]
Packit Service a04d08
        self.tmp = self.tmp_dir()
Packit Service a04d08
Packit Service a04d08
    def data_url(self, version, data_item='meta-data'):
Packit Service a04d08
        """Return a metadata url based on the version provided."""
Packit Service a04d08
        return '/'.join([self.metadata_addr, version, data_item])
Packit Service a04d08
Packit Service a04d08
    def _patch_add_cleanup(self, mpath, *args, **kwargs):
Packit Service a04d08
        p = mock.patch(mpath, *args, **kwargs)
Packit Service a04d08
        p.start()
Packit Service a04d08
        self.addCleanup(p.stop)
Packit Service a04d08
Packit Service a04d08
    def _setup_ds(self, sys_cfg, platform_data, md, md_version=None):
Packit Service a04d08
        self.uris = []
Packit Service a04d08
        distro = {}
Packit Service a04d08
        paths = helpers.Paths({'run_dir': self.tmp})
Packit Service a04d08
        if sys_cfg is None:
Packit Service a04d08
            sys_cfg = {}
Packit Service a04d08
        ds = self.datasource(sys_cfg=sys_cfg, distro=distro, paths=paths)
Packit Service a04d08
        if not md_version:
Packit Service a04d08
            md_version = ds.min_metadata_version
Packit Service a04d08
        if platform_data is not None:
Packit Service a04d08
            self._patch_add_cleanup(
Packit Service a04d08
                "cloudinit.sources.DataSourceEc2._collect_platform_data",
Packit Service a04d08
                return_value=platform_data)
Packit Service a04d08
Packit Service a04d08
        if md:
Packit Service a04d08
            all_versions = (
Packit Service a04d08
                [ds.min_metadata_version] + ds.extended_metadata_versions)
Packit Service a04d08
            token_url = self.data_url('latest', data_item='api/token')
Packit Service a04d08
            register_mock_metaserver(token_url, 'API-TOKEN')
Packit Service a04d08
            for version in all_versions:
Packit Service a04d08
                metadata_url = self.data_url(version) + '/'
Packit Service a04d08
                if version == md_version:
Packit Service a04d08
                    # Register all metadata for desired version
Packit Service a04d08
                    register_mock_metaserver(
Packit Service a04d08
                        metadata_url, md.get('md', DEFAULT_METADATA))
Packit Service a04d08
                    userdata_url = self.data_url(
Packit Service a04d08
                        version, data_item='user-data')
Packit Service a04d08
                    register_mock_metaserver(userdata_url, md.get('ud', ''))
Packit Service a04d08
                    identity_url = self.data_url(
Packit Service a04d08
                        version, data_item='dynamic/instance-identity')
Packit Service a04d08
                    register_mock_metaserver(
Packit Service a04d08
                        identity_url, md.get('id', DYNAMIC_METADATA))
Packit Service a04d08
                else:
Packit Service a04d08
                    instance_id_url = metadata_url + 'instance-id'
Packit Service a04d08
                    if version == ds.min_metadata_version:
Packit Service a04d08
                        # Add min_metadata_version service availability check
Packit Service a04d08
                        register_mock_metaserver(
Packit Service a04d08
                            instance_id_url, DEFAULT_METADATA['instance-id'])
Packit Service a04d08
                    else:
Packit Service a04d08
                        # Register 404s for all unrequested extended versions
Packit Service a04d08
                        register_mock_metaserver(instance_id_url, None)
Packit Service a04d08
        return ds
Packit Service a04d08
Packit Service 9bfd13
    def test_network_config_property_returns_version_2_network_data(self):
Packit Service 9bfd13
        """network_config property returns network version 2 for metadata"""
Packit Service a04d08
        ds = self._setup_ds(
Packit Service a04d08
            platform_data=self.valid_platform_data,
Packit Service a04d08
            sys_cfg={'datasource': {'Ec2': {'strict_id': True}}},
Packit Service 11b429
            md={'md': DEFAULT_METADATA})
Packit Service 9bfd13
        find_fallback_path = M_PATH_NET + 'find_fallback_nic'
Packit Service a04d08
        with mock.patch(find_fallback_path) as m_find_fallback:
Packit Service a04d08
            m_find_fallback.return_value = 'eth9'
Packit Service a04d08
            ds.get_data()
Packit Service a04d08
Packit Service b1601c
        mac1 = '06:17:04:d7:26:09'  # Defined in DEFAULT_METADATA
Packit Service 9bfd13
        expected = {'version': 2, 'ethernets': {'eth9': {
Packit Service 9bfd13
            'match': {'macaddress': '06:17:04:d7:26:09'}, 'set-name': 'eth9',
Packit Service 9bfd13
            'dhcp4': True, 'dhcp6': True}}}
Packit Service 9bfd13
        patch_path = M_PATH_NET + 'get_interfaces_by_mac'
Packit Service 9bfd13
        get_interface_mac_path = M_PATH_NET + 'get_interface_mac'
Packit Service 751c4a
        with mock.patch(patch_path) as m_get_interfaces_by_mac:
Packit Service 751c4a
            with mock.patch(find_fallback_path) as m_find_fallback:
Packit Service 751c4a
                with mock.patch(get_interface_mac_path) as m_get_mac:
Packit Service 751c4a
                    m_get_interfaces_by_mac.return_value = {mac1: 'eth9'}
Packit Service 751c4a
                    m_find_fallback.return_value = 'eth9'
Packit Service 751c4a
                    m_get_mac.return_value = mac1
Packit Service 751c4a
                    self.assertEqual(expected, ds.network_config)
Packit Service 751c4a
Packit Service 9bfd13
    def test_network_config_property_set_dhcp4(self):
Packit Service 9bfd13
        """network_config property configures dhcp4 on nics with local-ipv4s.
Packit Service 751c4a
Packit Service 9bfd13
        Only one device is configured based on get_interfaces_by_mac even when
Packit Service 9bfd13
        multiple MACs exist in metadata.
Packit Service 751c4a
        """
Packit Service 751c4a
        ds = self._setup_ds(
Packit Service 751c4a
            platform_data=self.valid_platform_data,
Packit Service 751c4a
            sys_cfg={'datasource': {'Ec2': {'strict_id': True}}},
Packit Service b1601c
            md={'md': DEFAULT_METADATA})
Packit Service 9bfd13
        find_fallback_path = M_PATH_NET + 'find_fallback_nic'
Packit Service 751c4a
        with mock.patch(find_fallback_path) as m_find_fallback:
Packit Service 751c4a
            m_find_fallback.return_value = 'eth9'
Packit Service 751c4a
            ds.get_data()
Packit Service 751c4a
Packit Service 9bfd13
        mac1 = '06:17:04:d7:26:08'  # IPv4 only in DEFAULT_METADATA
Packit Service 9bfd13
        expected = {'version': 2, 'ethernets': {'eth9': {
Packit Service 9bfd13
            'match': {'macaddress': mac1.lower()}, 'set-name': 'eth9',
Packit Service 9bfd13
            'dhcp4': True, 'dhcp6': False}}}
Packit Service 9bfd13
        patch_path = M_PATH_NET + 'get_interfaces_by_mac'
Packit Service 9bfd13
        get_interface_mac_path = M_PATH_NET + 'get_interface_mac'
Packit Service 9bfd13
        with mock.patch(patch_path) as m_get_interfaces_by_mac:
Packit Service 9bfd13
            with mock.patch(find_fallback_path) as m_find_fallback:
Packit Service 9bfd13
                with mock.patch(get_interface_mac_path) as m_get_mac:
Packit Service 9bfd13
                    m_get_interfaces_by_mac.return_value = {mac1: 'eth9'}
Packit Service 9bfd13
                    m_find_fallback.return_value = 'eth9'
Packit Service 9bfd13
                    m_get_mac.return_value = mac1
Packit Service 9bfd13
                    self.assertEqual(expected, ds.network_config)
Packit Service 9bfd13
Packit Service 9bfd13
    def test_network_config_property_secondary_private_ips(self):
Packit Service 9bfd13
        """network_config property configures any secondary ipv4 addresses.
Packit Service 9bfd13
Packit Service 9bfd13
        Only one device is configured based on get_interfaces_by_mac even when
Packit Service 9bfd13
        multiple MACs exist in metadata.
Packit Service 9bfd13
        """
Packit Service 9bfd13
        ds = self._setup_ds(
Packit Service 9bfd13
            platform_data=self.valid_platform_data,
Packit Service 9bfd13
            sys_cfg={'datasource': {'Ec2': {'strict_id': True}}},
Packit Service 9bfd13
            md={'md': SECONDARY_IP_METADATA_2018_09_24})
Packit Service 9bfd13
        find_fallback_path = M_PATH_NET + 'find_fallback_nic'
Packit Service 9bfd13
        with mock.patch(find_fallback_path) as m_find_fallback:
Packit Service 9bfd13
            m_find_fallback.return_value = 'eth9'
Packit Service 9bfd13
            ds.get_data()
Packit Service 9bfd13
Packit Service 9bfd13
        mac1 = '0a:07:84:3d:6e:38'  # 1 secondary IPv4 and 2 secondary IPv6
Packit Service 9bfd13
        expected = {'version': 2, 'ethernets': {'eth9': {
Packit Service 9bfd13
            'match': {'macaddress': mac1}, 'set-name': 'eth9',
Packit Service 9bfd13
            'addresses': ['172.31.45.70/20',
Packit Service 9bfd13
                          '2600:1f16:292:100:f152:2222:3333:4444/128',
Packit Service 9bfd13
                          '2600:1f16:292:100:f153:12a3:c37c:11f9/128'],
Packit Service 9bfd13
            'dhcp4': True, 'dhcp6': True}}}
Packit Service 9bfd13
        patch_path = M_PATH_NET + 'get_interfaces_by_mac'
Packit Service 9bfd13
        get_interface_mac_path = M_PATH_NET + 'get_interface_mac'
Packit Service a04d08
        with mock.patch(patch_path) as m_get_interfaces_by_mac:
Packit Service a04d08
            with mock.patch(find_fallback_path) as m_find_fallback:
Packit Service a04d08
                with mock.patch(get_interface_mac_path) as m_get_mac:
Packit Service a04d08
                    m_get_interfaces_by_mac.return_value = {mac1: 'eth9'}
Packit Service a04d08
                    m_find_fallback.return_value = 'eth9'
Packit Service a04d08
                    m_get_mac.return_value = mac1
Packit Service a04d08
                    self.assertEqual(expected, ds.network_config)
Packit Service a04d08
Packit Service a04d08
    def test_network_config_property_is_cached_in_datasource(self):
Packit Service a04d08
        """network_config property is cached in DataSourceEc2."""
Packit Service a04d08
        ds = self._setup_ds(
Packit Service a04d08
            platform_data=self.valid_platform_data,
Packit Service a04d08
            sys_cfg={'datasource': {'Ec2': {'strict_id': True}}},
Packit Service a04d08
            md={'md': DEFAULT_METADATA})
Packit Service a04d08
        ds._network_config = {'cached': 'data'}
Packit Service a04d08
        self.assertEqual({'cached': 'data'}, ds.network_config)
Packit Service a04d08
Packit Service a04d08
    @mock.patch('cloudinit.net.dhcp.maybe_perform_dhcp_discovery')
Packit Service a04d08
    def test_network_config_cached_property_refreshed_on_upgrade(self, m_dhcp):
Packit Service a04d08
        """Refresh the network_config Ec2 cache if network key is absent.
Packit Service a04d08
Packit Service a04d08
        This catches an upgrade issue where obj.pkl contained stale metadata
Packit Service a04d08
        which lacked newly required network key.
Packit Service a04d08
        """
Packit Service a04d08
        old_metadata = copy.deepcopy(DEFAULT_METADATA)
Packit Service a04d08
        old_metadata.pop('network')
Packit Service a04d08
        ds = self._setup_ds(
Packit Service a04d08
            platform_data=self.valid_platform_data,
Packit Service a04d08
            sys_cfg={'datasource': {'Ec2': {'strict_id': True}}},
Packit Service a04d08
            md={'md': old_metadata})
Packit Service a04d08
        self.assertTrue(ds.get_data())
Packit Service a04d08
        # Provide new revision of metadata that contains network data
Packit Service a04d08
        register_mock_metaserver(
Packit Service a04d08
            'http://169.254.169.254/2009-04-04/meta-data/', DEFAULT_METADATA)
Packit Service a04d08
        mac1 = '06:17:04:d7:26:09'  # Defined in DEFAULT_METADATA
Packit Service 9bfd13
        get_interface_mac_path = M_PATH_NET + 'get_interfaces_by_mac'
Packit Service a04d08
        ds.fallback_nic = 'eth9'
Packit Service 9bfd13
        with mock.patch(get_interface_mac_path) as m_get_interfaces_by_mac:
Packit Service 9bfd13
            m_get_interfaces_by_mac.return_value = {mac1: 'eth9'}
Packit Service a04d08
            nc = ds.network_config  # Will re-crawl network metadata
Packit Service a04d08
            self.assertIsNotNone(nc)
Packit Service a04d08
        self.assertIn(
Packit Service a04d08
            'Refreshing stale metadata from prior to upgrade',
Packit Service a04d08
            self.logs.getvalue())
Packit Service 9bfd13
        expected = {'version': 2, 'ethernets': {'eth9': {
Packit Service 9bfd13
            'match': {'macaddress': mac1}, 'set-name': 'eth9',
Packit Service 9bfd13
            'dhcp4': True, 'dhcp6': True}}}
Packit Service a04d08
        self.assertEqual(expected, ds.network_config)
Packit Service a04d08
Packit Service a04d08
    def test_ec2_get_instance_id_refreshes_identity_on_upgrade(self):
Packit Service a04d08
        """get_instance-id gets DataSourceEc2Local.identity if not present.
Packit Service a04d08
Packit Service a04d08
        This handles an upgrade case where the old pickled datasource didn't
Packit Service a04d08
        set up self.identity, but 'systemctl cloud-init init' runs
Packit Service a04d08
        get_instance_id which traces on missing self.identity. lp:1748354.
Packit Service a04d08
        """
Packit Service a04d08
        self.datasource = ec2.DataSourceEc2Local
Packit Service a04d08
        ds = self._setup_ds(
Packit Service a04d08
            platform_data=self.valid_platform_data,
Packit Service a04d08
            sys_cfg={'datasource': {'Ec2': {'strict_id': False}}},
Packit Service a04d08
            md={'md': DEFAULT_METADATA})
Packit Service a04d08
        # Mock 404s on all versions except latest
Packit Service a04d08
        all_versions = (
Packit Service a04d08
            [ds.min_metadata_version] + ds.extended_metadata_versions)
Packit Service a04d08
        for ver in all_versions[:-1]:
Packit Service a04d08
            register_mock_metaserver(
Packit Service a04d08
                'http://169.254.169.254/{0}/meta-data/instance-id'.format(ver),
Packit Service a04d08
                None)
Packit Service a04d08
        ds.metadata_address = 'http://169.254.169.254'
Packit Service a04d08
        register_mock_metaserver(
Packit Service a04d08
            '{0}/{1}/meta-data/'.format(ds.metadata_address, all_versions[-1]),
Packit Service a04d08
            DEFAULT_METADATA)
Packit Service a04d08
        # Register dynamic/instance-identity document which we now read.
Packit Service a04d08
        register_mock_metaserver(
Packit Service a04d08
            '{0}/{1}/dynamic/'.format(ds.metadata_address, all_versions[-1]),
Packit Service a04d08
            DYNAMIC_METADATA)
Packit Service a04d08
        ds._cloud_name = ec2.CloudNames.AWS
Packit Service a04d08
        # Setup cached metadata on the Datasource
Packit Service a04d08
        ds.metadata = DEFAULT_METADATA
Packit Service a04d08
        self.assertEqual('my-identity-id', ds.get_instance_id())
Packit Service a04d08
Packit Service a04d08
    def test_classic_instance_true(self):
Packit Service a04d08
        """If no vpc-id in metadata, is_classic_instance must return true."""
Packit Service a04d08
        md_copy = copy.deepcopy(DEFAULT_METADATA)
Packit Service a04d08
        ifaces_md = md_copy.get('network', {}).get('interfaces', {})
Packit Service a04d08
        for _mac, mac_data in ifaces_md.get('macs', {}).items():
Packit Service a04d08
            if 'vpc-id' in mac_data:
Packit Service a04d08
                del mac_data['vpc-id']
Packit Service a04d08
Packit Service a04d08
        ds = self._setup_ds(
Packit Service a04d08
            platform_data=self.valid_platform_data,
Packit Service a04d08
            sys_cfg={'datasource': {'Ec2': {'strict_id': False}}},
Packit Service a04d08
            md={'md': md_copy})
Packit Service a04d08
        self.assertTrue(ds.get_data())
Packit Service a04d08
        self.assertTrue(ds.is_classic_instance())
Packit Service a04d08
Packit Service a04d08
    def test_classic_instance_false(self):
Packit Service a04d08
        """If vpc-id in metadata, is_classic_instance must return false."""
Packit Service a04d08
        ds = self._setup_ds(
Packit Service a04d08
            platform_data=self.valid_platform_data,
Packit Service a04d08
            sys_cfg={'datasource': {'Ec2': {'strict_id': False}}},
Packit Service a04d08
            md={'md': DEFAULT_METADATA})
Packit Service a04d08
        self.assertTrue(ds.get_data())
Packit Service a04d08
        self.assertFalse(ds.is_classic_instance())
Packit Service a04d08
Packit Service 9bfd13
    def test_aws_inaccessible_imds_service_fails_with_retries(self):
Packit Service 9bfd13
        """Inaccessibility of http://169.254.169.254 are retried."""
Packit Service 9bfd13
        ds = self._setup_ds(
Packit Service 9bfd13
            platform_data=self.valid_platform_data,
Packit Service 9bfd13
            sys_cfg={'datasource': {'Ec2': {'strict_id': False}}},
Packit Service 9bfd13
            md=None)
Packit Service 9bfd13
Packit Service 9bfd13
        conn_error = requests.exceptions.ConnectionError(
Packit Service 9bfd13
            '[Errno 113] no route to host'
Packit Service 9bfd13
        )
Packit Service 9bfd13
Packit Service 9bfd13
        mock_success = mock.MagicMock(contents=b'fakesuccess')
Packit Service 9bfd13
        mock_success.ok.return_value = True
Packit Service 9bfd13
Packit Service 9bfd13
        with mock.patch('cloudinit.url_helper.readurl') as m_readurl:
Packit Service 9bfd13
            m_readurl.side_effect = (conn_error, conn_error, mock_success)
Packit Service 9bfd13
            with mock.patch('cloudinit.url_helper.time.sleep'):
Packit Service 9bfd13
                self.assertTrue(ds.wait_for_metadata_service())
Packit Service 9bfd13
Packit Service 9bfd13
        # Just one /latest/api/token request
Packit Service 9bfd13
        self.assertEqual(3, len(m_readurl.call_args_list))
Packit Service 9bfd13
        for readurl_call in m_readurl.call_args_list:
Packit Service 9bfd13
            self.assertIn('latest/api/token', readurl_call[0][0])
Packit Service 9bfd13
Packit Service 9bfd13
    def test_aws_token_403_fails_without_retries(self):
Packit Service 9bfd13
        """Verify that 403s fetching AWS tokens are not retried."""
Packit Service 9bfd13
        ds = self._setup_ds(
Packit Service 9bfd13
            platform_data=self.valid_platform_data,
Packit Service 9bfd13
            sys_cfg={'datasource': {'Ec2': {'strict_id': False}}},
Packit Service 9bfd13
            md=None)
Packit Service 9bfd13
        token_url = self.data_url('latest', data_item='api/token')
Packit Service 9bfd13
        httpretty.register_uri(httpretty.PUT, token_url, body={}, status=403)
Packit Service 9bfd13
        self.assertFalse(ds.get_data())
Packit Service 9bfd13
        # Just one /latest/api/token request
Packit Service 9bfd13
        logs = self.logs.getvalue()
Packit Service 9bfd13
        failed_put_log = '"PUT /latest/api/token HTTP/1.1" 403 0'
Packit Service 9bfd13
        expected_logs = [
Packit Service 9bfd13
            'WARNING: Ec2 IMDS endpoint returned a 403 error. HTTP endpoint is'
Packit Service 9bfd13
            ' disabled. Aborting.',
Packit Service 9bfd13
            "WARNING: IMDS's HTTP endpoint is probably disabled",
Packit Service 9bfd13
            failed_put_log
Packit Service 9bfd13
        ]
Packit Service 9bfd13
        for log in expected_logs:
Packit Service 9bfd13
            self.assertIn(log, logs)
Packit Service 9bfd13
        self.assertEqual(
Packit Service 9bfd13
            1,
Packit Service 9bfd13
            len([line for line in logs.splitlines() if failed_put_log in line])
Packit Service 9bfd13
        )
Packit Service 9bfd13
Packit Service 9bfd13
    def test_aws_token_redacted(self):
Packit Service 9bfd13
        """Verify that aws tokens are redacted when logged."""
Packit Service 9bfd13
        ds = self._setup_ds(
Packit Service 9bfd13
            platform_data=self.valid_platform_data,
Packit Service 9bfd13
            sys_cfg={'datasource': {'Ec2': {'strict_id': False}}},
Packit Service 9bfd13
            md={'md': DEFAULT_METADATA})
Packit Service 9bfd13
        self.assertTrue(ds.get_data())
Packit Service 9bfd13
        all_logs = self.logs.getvalue().splitlines()
Packit Service 9bfd13
        REDACT_TTL = "'X-aws-ec2-metadata-token-ttl-seconds': 'REDACTED'"
Packit Service 9bfd13
        REDACT_TOK = "'X-aws-ec2-metadata-token': 'REDACTED'"
Packit Service 9bfd13
        logs_with_redacted_ttl = [log for log in all_logs if REDACT_TTL in log]
Packit Service 9bfd13
        logs_with_redacted = [log for log in all_logs if REDACT_TOK in log]
Packit Service 9bfd13
        logs_with_token = [log for log in all_logs if 'API-TOKEN' in log]
Packit Service 9bfd13
        self.assertEqual(1, len(logs_with_redacted_ttl))
Packit Service 9bfd13
        self.assertEqual(81, len(logs_with_redacted))
Packit Service 9bfd13
        self.assertEqual(0, len(logs_with_token))
Packit Service 9bfd13
Packit Service a04d08
    @mock.patch('cloudinit.net.dhcp.maybe_perform_dhcp_discovery')
Packit Service a04d08
    def test_valid_platform_with_strict_true(self, m_dhcp):
Packit Service a04d08
        """Valid platform data should return true with strict_id true."""
Packit Service a04d08
        ds = self._setup_ds(
Packit Service a04d08
            platform_data=self.valid_platform_data,
Packit Service a04d08
            sys_cfg={'datasource': {'Ec2': {'strict_id': True}}},
Packit Service a04d08
            md={'md': DEFAULT_METADATA})
Packit Service a04d08
        ret = ds.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
        self.assertEqual(0, m_dhcp.call_count)
Packit Service a04d08
        self.assertEqual('aws', ds.cloud_name)
Packit Service a04d08
        self.assertEqual('ec2', ds.platform_type)
Packit Service a04d08
        self.assertEqual('metadata (%s)' % ds.metadata_address, ds.subplatform)
Packit Service a04d08
Packit Service a04d08
    def test_valid_platform_with_strict_false(self):
Packit Service a04d08
        """Valid platform data should return true with strict_id false."""
Packit Service a04d08
        ds = self._setup_ds(
Packit Service a04d08
            platform_data=self.valid_platform_data,
Packit Service a04d08
            sys_cfg={'datasource': {'Ec2': {'strict_id': False}}},
Packit Service a04d08
            md={'md': DEFAULT_METADATA})
Packit Service a04d08
        ret = ds.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
Packit Service a04d08
    def test_unknown_platform_with_strict_true(self):
Packit Service a04d08
        """Unknown platform data with strict_id true should return False."""
Packit Service a04d08
        uuid = 'ab439480-72bf-11d3-91fc-b8aded755F9a'
Packit Service a04d08
        ds = self._setup_ds(
Packit Service a04d08
            platform_data={'uuid': uuid, 'uuid_source': 'dmi', 'serial': ''},
Packit Service a04d08
            sys_cfg={'datasource': {'Ec2': {'strict_id': True}}},
Packit Service a04d08
            md={'md': DEFAULT_METADATA})
Packit Service a04d08
        ret = ds.get_data()
Packit Service a04d08
        self.assertFalse(ret)
Packit Service a04d08
Packit Service a04d08
    def test_unknown_platform_with_strict_false(self):
Packit Service a04d08
        """Unknown platform data with strict_id false should return True."""
Packit Service a04d08
        uuid = 'ab439480-72bf-11d3-91fc-b8aded755F9a'
Packit Service a04d08
        ds = self._setup_ds(
Packit Service a04d08
            platform_data={'uuid': uuid, 'uuid_source': 'dmi', 'serial': ''},
Packit Service a04d08
            sys_cfg={'datasource': {'Ec2': {'strict_id': False}}},
Packit Service a04d08
            md={'md': DEFAULT_METADATA})
Packit Service a04d08
        ret = ds.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service a04d08
Packit Service a04d08
    def test_ec2_local_returns_false_on_non_aws(self):
Packit Service a04d08
        """DataSourceEc2Local returns False when platform is not AWS."""
Packit Service a04d08
        self.datasource = ec2.DataSourceEc2Local
Packit Service a04d08
        ds = self._setup_ds(
Packit Service a04d08
            platform_data=self.valid_platform_data,
Packit Service a04d08
            sys_cfg={'datasource': {'Ec2': {'strict_id': False}}},
Packit Service a04d08
            md={'md': DEFAULT_METADATA})
Packit Service a04d08
        platform_attrs = [
Packit Service a04d08
            attr for attr in ec2.CloudNames.__dict__.keys()
Packit Service a04d08
            if not attr.startswith('__')]
Packit Service a04d08
        for attr_name in platform_attrs:
Packit Service a04d08
            platform_name = getattr(ec2.CloudNames, attr_name)
Packit Service a04d08
            if platform_name != 'aws':
Packit Service a04d08
                ds._cloud_name = platform_name
Packit Service a04d08
                ret = ds.get_data()
Packit Service a04d08
                self.assertEqual('ec2', ds.platform_type)
Packit Service a04d08
                self.assertFalse(ret)
Packit Service a04d08
                message = (
Packit Service a04d08
                    "Local Ec2 mode only supported on ('aws',),"
Packit Service a04d08
                    ' not {0}'.format(platform_name))
Packit Service a04d08
                self.assertIn(message, self.logs.getvalue())
Packit Service a04d08
Packit Service a04d08
    @mock.patch('cloudinit.sources.DataSourceEc2.util.is_FreeBSD')
Packit Service a04d08
    def test_ec2_local_returns_false_on_bsd(self, m_is_freebsd):
Packit Service a04d08
        """DataSourceEc2Local returns False on BSD.
Packit Service a04d08
Packit Service a04d08
        FreeBSD dhclient doesn't support dhclient -sf to run in a sandbox.
Packit Service a04d08
        """
Packit Service a04d08
        m_is_freebsd.return_value = True
Packit Service a04d08
        self.datasource = ec2.DataSourceEc2Local
Packit Service a04d08
        ds = self._setup_ds(
Packit Service a04d08
            platform_data=self.valid_platform_data,
Packit Service a04d08
            sys_cfg={'datasource': {'Ec2': {'strict_id': False}}},
Packit Service a04d08
            md={'md': DEFAULT_METADATA})
Packit Service a04d08
        ret = ds.get_data()
Packit Service a04d08
        self.assertFalse(ret)
Packit Service a04d08
        self.assertIn(
Packit Service a04d08
            "FreeBSD doesn't support running dhclient with -sf",
Packit Service a04d08
            self.logs.getvalue())
Packit Service a04d08
Packit Service a04d08
    @mock.patch('cloudinit.net.dhcp.EphemeralIPv4Network')
Packit Service a04d08
    @mock.patch('cloudinit.net.find_fallback_nic')
Packit Service a04d08
    @mock.patch('cloudinit.net.dhcp.maybe_perform_dhcp_discovery')
Packit Service a04d08
    @mock.patch('cloudinit.sources.DataSourceEc2.util.is_FreeBSD')
Packit Service a04d08
    def test_ec2_local_performs_dhcp_on_non_bsd(self, m_is_bsd, m_dhcp,
Packit Service a04d08
                                                m_fallback_nic, m_net):
Packit Service a04d08
        """Ec2Local returns True for valid platform data on non-BSD with dhcp.
Packit Service a04d08
Packit Service a04d08
        DataSourceEc2Local will setup initial IPv4 network via dhcp discovery.
Packit Service a04d08
        Then the metadata services is crawled for more network config info.
Packit Service a04d08
        When the platform data is valid, return True.
Packit Service a04d08
        """
Packit Service a04d08
Packit Service a04d08
        m_fallback_nic.return_value = 'eth9'
Packit Service a04d08
        m_is_bsd.return_value = False
Packit Service a04d08
        m_dhcp.return_value = [{
Packit Service a04d08
            'interface': 'eth9', 'fixed-address': '192.168.2.9',
Packit Service a04d08
            'routers': '192.168.2.1', 'subnet-mask': '255.255.255.0',
Packit Service a04d08
            'broadcast-address': '192.168.2.255'}]
Packit Service a04d08
        self.datasource = ec2.DataSourceEc2Local
Packit Service a04d08
        ds = self._setup_ds(
Packit Service a04d08
            platform_data=self.valid_platform_data,
Packit Service a04d08
            sys_cfg={'datasource': {'Ec2': {'strict_id': False}}},
Packit Service a04d08
            md={'md': DEFAULT_METADATA})
Packit Service a04d08
Packit Service a04d08
        ret = ds.get_data()
Packit Service a04d08
        self.assertTrue(ret)
Packit Service 9bfd13
        m_dhcp.assert_called_once_with('eth9', None)
Packit Service a04d08
        m_net.assert_called_once_with(
Packit Service a04d08
            broadcast='192.168.2.255', interface='eth9', ip='192.168.2.9',
Packit Service a04d08
            prefix_or_mask='255.255.255.0', router='192.168.2.1',
Packit Service a04d08
            static_routes=None)
Packit Service a04d08
        self.assertIn('Crawl of metadata service took', self.logs.getvalue())
Packit Service a04d08
Packit Service a04d08
Packit Service 9bfd13
class TestGetSecondaryAddresses(test_helpers.CiTestCase):
Packit Service 9bfd13
Packit Service 9bfd13
    mac = '06:17:04:d7:26:ff'
Packit Service 9bfd13
    with_logs = True
Packit Service 9bfd13
Packit Service 9bfd13
    def test_md_with_no_secondary_addresses(self):
Packit Service 9bfd13
        """Empty list is returned when nic metadata contains no secondary ip"""
Packit Service 9bfd13
        self.assertEqual([], ec2.get_secondary_addresses(NIC2_MD, self.mac))
Packit Service 9bfd13
Packit Service 9bfd13
    def test_md_with_secondary_v4_and_v6_addresses(self):
Packit Service 9bfd13
        """All secondary addresses are returned from nic metadata"""
Packit Service 9bfd13
        self.assertEqual(
Packit Service 9bfd13
            ['172.31.45.70/20', '2600:1f16:292:100:f152:2222:3333:4444/128',
Packit Service 9bfd13
             '2600:1f16:292:100:f153:12a3:c37c:11f9/128'],
Packit Service 9bfd13
            ec2.get_secondary_addresses(NIC1_MD_IPV4_IPV6_MULTI_IP, self.mac))
Packit Service 9bfd13
Packit Service 9bfd13
    def test_invalid_ipv4_ipv6_cidr_metadata_logged_with_defaults(self):
Packit Service 9bfd13
        """Any invalid subnet-ipv(4|6)-cidr-block values use defaults"""
Packit Service 9bfd13
        invalid_cidr_md = copy.deepcopy(NIC1_MD_IPV4_IPV6_MULTI_IP)
Packit Service 9bfd13
        invalid_cidr_md['subnet-ipv4-cidr-block'] = "something-unexpected"
Packit Service 9bfd13
        invalid_cidr_md['subnet-ipv6-cidr-block'] = "not/sure/what/this/is"
Packit Service 9bfd13
        self.assertEqual(
Packit Service 9bfd13
            ['172.31.45.70/24', '2600:1f16:292:100:f152:2222:3333:4444/128',
Packit Service 9bfd13
             '2600:1f16:292:100:f153:12a3:c37c:11f9/128'],
Packit Service 9bfd13
            ec2.get_secondary_addresses(invalid_cidr_md, self.mac))
Packit Service 9bfd13
        expected_logs = [
Packit Service 9bfd13
            "WARNING: Could not parse subnet-ipv4-cidr-block"
Packit Service 9bfd13
            " something-unexpected for mac 06:17:04:d7:26:ff."
Packit Service 9bfd13
            " ipv4 network config prefix defaults to /24",
Packit Service 9bfd13
            "WARNING: Could not parse subnet-ipv6-cidr-block"
Packit Service 9bfd13
            " not/sure/what/this/is for mac 06:17:04:d7:26:ff."
Packit Service 9bfd13
            " ipv6 network config prefix defaults to /128"
Packit Service 9bfd13
        ]
Packit Service 9bfd13
        logs = self.logs.getvalue()
Packit Service 9bfd13
        for log in expected_logs:
Packit Service 9bfd13
            self.assertIn(log, logs)
Packit Service 9bfd13
Packit Service 9bfd13
Packit Service a04d08
class TestConvertEc2MetadataNetworkConfig(test_helpers.CiTestCase):
Packit Service a04d08
Packit Service a04d08
    def setUp(self):
Packit Service a04d08
        super(TestConvertEc2MetadataNetworkConfig, self).setUp()
Packit Service a04d08
        self.mac1 = '06:17:04:d7:26:09'
Packit Service 9bfd13
        interface_dict = copy.deepcopy(
Packit Service 9bfd13
            DEFAULT_METADATA['network']['interfaces']['macs'][self.mac1])
Packit Service 9bfd13
        # These tests are written assuming the base interface doesn't have IPv6
Packit Service 9bfd13
        interface_dict.pop('ipv6s')
Packit Service a04d08
        self.network_metadata = {
Packit Service 9bfd13
            'interfaces': {'macs': {self.mac1: interface_dict}}}
Packit Service a04d08
Packit Service a04d08
    def test_convert_ec2_metadata_network_config_skips_absent_macs(self):
Packit Service a04d08
        """Any mac absent from metadata is skipped by network config."""
Packit Service a04d08
        macs_to_nics = {self.mac1: 'eth9', 'DE:AD:BE:EF:FF:FF': 'vitualnic2'}
Packit Service a04d08
Packit Service a04d08
        # DE:AD:BE:EF:FF:FF represented by OS but not in metadata
Packit Service 9bfd13
        expected = {'version': 2, 'ethernets': {'eth9': {
Packit Service 9bfd13
            'match': {'macaddress': self.mac1}, 'set-name': 'eth9',
Packit Service 9bfd13
            'dhcp4': True, 'dhcp6': False}}}
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            expected,
Packit Service a04d08
            ec2.convert_ec2_metadata_network_config(
Packit Service a04d08
                self.network_metadata, macs_to_nics))
Packit Service a04d08
Packit Service a04d08
    def test_convert_ec2_metadata_network_config_handles_only_dhcp6(self):
Packit Service a04d08
        """Config dhcp6 when ipv6s is in metadata for a mac."""
Packit Service a04d08
        macs_to_nics = {self.mac1: 'eth9'}
Packit Service a04d08
        network_metadata_ipv6 = copy.deepcopy(self.network_metadata)
Packit Service a04d08
        nic1_metadata = (
Packit Service a04d08
            network_metadata_ipv6['interfaces']['macs'][self.mac1])
Packit Service a04d08
        nic1_metadata['ipv6s'] = '2620:0:1009:fd00:e442:c88d:c04d:dc85/64'
Packit Service a04d08
        nic1_metadata.pop('public-ipv4s')
Packit Service 9bfd13
        expected = {'version': 2, 'ethernets': {'eth9': {
Packit Service 9bfd13
            'match': {'macaddress': self.mac1}, 'set-name': 'eth9',
Packit Service 9bfd13
            'dhcp4': True, 'dhcp6': True}}}
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            expected,
Packit Service a04d08
            ec2.convert_ec2_metadata_network_config(
Packit Service a04d08
                network_metadata_ipv6, macs_to_nics))
Packit Service a04d08
Packit Service 9bfd13
    def test_convert_ec2_metadata_network_config_local_only_dhcp4(self):
Packit Service a04d08
        """Config dhcp4 when there are no public addresses in public-ipv4s."""
Packit Service a04d08
        macs_to_nics = {self.mac1: 'eth9'}
Packit Service a04d08
        network_metadata_ipv6 = copy.deepcopy(self.network_metadata)
Packit Service a04d08
        nic1_metadata = (
Packit Service a04d08
            network_metadata_ipv6['interfaces']['macs'][self.mac1])
Packit Service a04d08
        nic1_metadata['local-ipv4s'] = '172.3.3.15'
Packit Service a04d08
        nic1_metadata.pop('public-ipv4s')
Packit Service 9bfd13
        expected = {'version': 2, 'ethernets': {'eth9': {
Packit Service 9bfd13
            'match': {'macaddress': self.mac1}, 'set-name': 'eth9',
Packit Service 9bfd13
            'dhcp4': True, 'dhcp6': False}}}
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            expected,
Packit Service a04d08
            ec2.convert_ec2_metadata_network_config(
Packit Service a04d08
                network_metadata_ipv6, macs_to_nics))
Packit Service a04d08
Packit Service a04d08
    def test_convert_ec2_metadata_network_config_handles_absent_dhcp4(self):
Packit Service a04d08
        """Config dhcp4 on fallback_nic when there are no ipv4 addresses."""
Packit Service a04d08
        macs_to_nics = {self.mac1: 'eth9'}
Packit Service a04d08
        network_metadata_ipv6 = copy.deepcopy(self.network_metadata)
Packit Service a04d08
        nic1_metadata = (
Packit Service a04d08
            network_metadata_ipv6['interfaces']['macs'][self.mac1])
Packit Service a04d08
        nic1_metadata['public-ipv4s'] = ''
Packit Service a04d08
Packit Service a04d08
        # When no ipv4 or ipv6 content but fallback_nic set, set dhcp4 config.
Packit Service 9bfd13
        expected = {'version': 2, 'ethernets': {'eth9': {
Packit Service 9bfd13
            'match': {'macaddress': self.mac1}, 'set-name': 'eth9',
Packit Service 9bfd13
            'dhcp4': True, 'dhcp6': False}}}
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            expected,
Packit Service a04d08
            ec2.convert_ec2_metadata_network_config(
Packit Service a04d08
                network_metadata_ipv6, macs_to_nics, fallback_nic='eth9'))
Packit Service a04d08
Packit Service a04d08
    def test_convert_ec2_metadata_network_config_handles_local_v4_and_v6(self):
Packit Service 9bfd13
        """When ipv6s and local-ipv4s are non-empty, enable dhcp6 and dhcp4."""
Packit Service a04d08
        macs_to_nics = {self.mac1: 'eth9'}
Packit Service a04d08
        network_metadata_both = copy.deepcopy(self.network_metadata)
Packit Service a04d08
        nic1_metadata = (
Packit Service a04d08
            network_metadata_both['interfaces']['macs'][self.mac1])
Packit Service a04d08
        nic1_metadata['ipv6s'] = '2620:0:1009:fd00:e442:c88d:c04d:dc85/64'
Packit Service a04d08
        nic1_metadata.pop('public-ipv4s')
Packit Service a04d08
        nic1_metadata['local-ipv4s'] = '10.0.0.42'  # Local ipv4 only on vpc
Packit Service 9bfd13
        expected = {'version': 2, 'ethernets': {'eth9': {
Packit Service 9bfd13
            'match': {'macaddress': self.mac1}, 'set-name': 'eth9',
Packit Service 9bfd13
            'dhcp4': True, 'dhcp6': True}}}
Packit Service 9bfd13
        self.assertEqual(
Packit Service 9bfd13
            expected,
Packit Service 9bfd13
            ec2.convert_ec2_metadata_network_config(
Packit Service 9bfd13
                network_metadata_both, macs_to_nics))
Packit Service 9bfd13
Packit Service 9bfd13
    def test_convert_ec2_metadata_network_config_handles_multiple_nics(self):
Packit Service 9bfd13
        """DHCP route-metric increases on secondary NICs for IPv4 and IPv6."""
Packit Service 9bfd13
        mac2 = '06:17:04:d7:26:08'
Packit Service 9bfd13
        macs_to_nics = {self.mac1: 'eth9', mac2: 'eth10'}
Packit Service 9bfd13
        network_metadata_both = copy.deepcopy(self.network_metadata)
Packit Service 9bfd13
        # Add 2nd nic info
Packit Service 9bfd13
        network_metadata_both['interfaces']['macs'][mac2] = NIC2_MD
Packit Service 9bfd13
        nic1_metadata = (
Packit Service 9bfd13
            network_metadata_both['interfaces']['macs'][self.mac1])
Packit Service 9bfd13
        nic1_metadata['ipv6s'] = '2620:0:1009:fd00:e442:c88d:c04d:dc85/64'
Packit Service 9bfd13
        nic1_metadata.pop('public-ipv4s')  # No public-ipv4 IPs in cfg
Packit Service 9bfd13
        nic1_metadata['local-ipv4s'] = '10.0.0.42'  # Local ipv4 only on vpc
Packit Service 9bfd13
        expected = {'version': 2, 'ethernets': {
Packit Service 9bfd13
            'eth9': {
Packit Service 9bfd13
                'match': {'macaddress': self.mac1}, 'set-name': 'eth9',
Packit Service 9bfd13
                'dhcp4': True, 'dhcp4-overrides': {'route-metric': 100},
Packit Service 9bfd13
                'dhcp6': True, 'dhcp6-overrides': {'route-metric': 100}},
Packit Service 9bfd13
            'eth10': {
Packit Service 9bfd13
                'match': {'macaddress': mac2}, 'set-name': 'eth10',
Packit Service 9bfd13
                'dhcp4': True, 'dhcp4-overrides': {'route-metric': 200},
Packit Service 9bfd13
                'dhcp6': False}}}
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            expected,
Packit Service a04d08
            ec2.convert_ec2_metadata_network_config(
Packit Service a04d08
                network_metadata_both, macs_to_nics))
Packit Service a04d08
Packit Service a04d08
    def test_convert_ec2_metadata_network_config_handles_dhcp4_and_dhcp6(self):
Packit Service a04d08
        """Config both dhcp4 and dhcp6 when both vpc-ipv6 and ipv4 exists."""
Packit Service a04d08
        macs_to_nics = {self.mac1: 'eth9'}
Packit Service a04d08
        network_metadata_both = copy.deepcopy(self.network_metadata)
Packit Service a04d08
        nic1_metadata = (
Packit Service a04d08
            network_metadata_both['interfaces']['macs'][self.mac1])
Packit Service a04d08
        nic1_metadata['ipv6s'] = '2620:0:1009:fd00:e442:c88d:c04d:dc85/64'
Packit Service 9bfd13
        expected = {'version': 2, 'ethernets': {'eth9': {
Packit Service 9bfd13
            'match': {'macaddress': self.mac1}, 'set-name': 'eth9',
Packit Service 9bfd13
            'dhcp4': True, 'dhcp6': True}}}
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            expected,
Packit Service a04d08
            ec2.convert_ec2_metadata_network_config(
Packit Service a04d08
                network_metadata_both, macs_to_nics))
Packit Service a04d08
Packit Service a04d08
    def test_convert_ec2_metadata_gets_macs_from_get_interfaces_by_mac(self):
Packit Service a04d08
        """Convert Ec2 Metadata calls get_interfaces_by_mac by default."""
Packit Service 9bfd13
        expected = {'version': 2, 'ethernets': {'eth9': {
Packit Service 9bfd13
            'match': {'macaddress': self.mac1},
Packit Service 9bfd13
            'set-name': 'eth9', 'dhcp4': True, 'dhcp6': False}}}
Packit Service 9bfd13
        patch_path = M_PATH_NET + 'get_interfaces_by_mac'
Packit Service a04d08
        with mock.patch(patch_path) as m_get_interfaces_by_mac:
Packit Service a04d08
            m_get_interfaces_by_mac.return_value = {self.mac1: 'eth9'}
Packit Service a04d08
            self.assertEqual(
Packit Service a04d08
                expected,
Packit Service a04d08
                ec2.convert_ec2_metadata_network_config(self.network_metadata))
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class TesIdentifyPlatform(test_helpers.CiTestCase):
Packit Service a04d08
Packit Service a04d08
    def collmock(self, **kwargs):
Packit Service a04d08
        """return non-special _collect_platform_data updated with changes."""
Packit Service a04d08
        unspecial = {
Packit Service a04d08
            'asset_tag': '3857-0037-2746-7462-1818-3997-77',
Packit Service a04d08
            'serial': 'H23-C4J3JV-R6',
Packit Service a04d08
            'uuid': '81c7e555-6471-4833-9551-1ab366c4cfd2',
Packit Service a04d08
            'uuid_source': 'dmi',
Packit Service a04d08
            'vendor': 'tothecloud',
Packit Service a04d08
        }
Packit Service a04d08
        unspecial.update(**kwargs)
Packit Service a04d08
        return unspecial
Packit Service a04d08
Packit Service a04d08
    @mock.patch('cloudinit.sources.DataSourceEc2._collect_platform_data')
Packit Service a04d08
    def test_identify_zstack(self, m_collect):
Packit Service a04d08
        """zstack should be identified if chassis-asset-tag ends in .zstack.io
Packit Service a04d08
        """
Packit Service a04d08
        m_collect.return_value = self.collmock(asset_tag='123456.zstack.io')
Packit Service a04d08
        self.assertEqual(ec2.CloudNames.ZSTACK, ec2.identify_platform())
Packit Service a04d08
Packit Service a04d08
    @mock.patch('cloudinit.sources.DataSourceEc2._collect_platform_data')
Packit Service a04d08
    def test_identify_zstack_full_domain_only(self, m_collect):
Packit Service a04d08
        """zstack asset-tag matching should match only on full domain boundary.
Packit Service a04d08
        """
Packit Service a04d08
        m_collect.return_value = self.collmock(asset_tag='123456.buzzstack.io')
Packit Service a04d08
        self.assertEqual(ec2.CloudNames.UNKNOWN, ec2.identify_platform())
Packit Service a04d08
Packit Service a04d08
    @mock.patch('cloudinit.sources.DataSourceEc2._collect_platform_data')
Packit Service a04d08
    def test_identify_e24cloud(self, m_collect):
Packit Service a04d08
        """e24cloud identified if vendor is e24cloud"""
Packit Service a04d08
        m_collect.return_value = self.collmock(vendor='e24cloud')
Packit Service a04d08
        self.assertEqual(ec2.CloudNames.E24CLOUD, ec2.identify_platform())
Packit Service a04d08
Packit Service a04d08
    @mock.patch('cloudinit.sources.DataSourceEc2._collect_platform_data')
Packit Service a04d08
    def test_identify_e24cloud_negative(self, m_collect):
Packit Service a04d08
        """e24cloud identified if vendor is e24cloud"""
Packit Service a04d08
        m_collect.return_value = self.collmock(vendor='e24cloudyday')
Packit Service a04d08
        self.assertEqual(ec2.CloudNames.UNKNOWN, ec2.identify_platform())
Packit Service a04d08
Packit Service a04d08
# vi: ts=4 expandtab