コード例 #1
0
def get_metadata_from_imds(fallback_nic, retries):
    """Query Azure's network metadata service, returning a dictionary.

    If network is not up, setup ephemeral dhcp on fallback_nic to talk to the
    IMDS. For more info on IMDS:
        https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service

    @param fallback_nic: String. The name of the nic which requires active
        network in order to query IMDS.
    @param retries: The number of retries of the IMDS_URL.

    @return: A dict of instance metadata containing compute and network
        info.
    """
    kwargs = {
        'logfunc': LOG.debug,
        'msg': 'Crawl of Azure Instance Metadata Service (IMDS)',
        'func': _get_metadata_from_imds,
        'args': (retries, )
    }
    if net.is_up(fallback_nic):
        return util.log_time(**kwargs)
    else:
        with EphemeralDHCPv4(fallback_nic):
            return util.log_time(**kwargs)
コード例 #2
0
    def _poll_imds(self, report_ready=True):
        """Poll IMDS for the new provisioning data until we get a valid
        response. Then return the returned JSON object."""
        url = IMDS_URL + "?api-version=2017-04-02"
        headers = {"Metadata": "true"}
        LOG.debug("Start polling IMDS")

        def exc_cb(msg, exception):
            if isinstance(exception, UrlError) and exception.code == 404:
                return True
            # If we get an exception while trying to call IMDS, we
            # call DHCP and setup the ephemeral network to acquire the new IP.
            return False

        need_report = report_ready
        while True:
            try:
                with EphemeralDHCPv4() as lease:
                    if need_report:
                        self._report_ready(lease=lease)
                        need_report = False
                    return readurl(url,
                                   timeout=1,
                                   headers=headers,
                                   exception_cb=exc_cb,
                                   infinite=True).contents
            except UrlError:
                pass
コード例 #3
0
ファイル: vultr.py プロジェクト: delphix/cloud-init
def get_metadata(url, timeout, retries, sec_between, agent):
    # Bring up interface (and try untill one works)
    exception = RuntimeError("Failed to DHCP")

    # Seek iface with DHCP
    for iface in get_interface_list():
        try:
            with EphemeralDHCPv4(
                iface=iface, connectivity_url_data={"url": url}
            ):
                # Check for the metadata route, skip if not there
                if not check_route(url):
                    continue

                # Fetch the metadata
                v1 = read_metadata(url, timeout, retries, sec_between, agent)

                return json.loads(v1)
        except (
            NoDHCPLeaseError,
            subp.ProcessExecutionError,
            RuntimeError,
            exceptions.RequestException,
        ) as exc:
            LOG.error("DHCP Exception: %s", exc)
            exception = exc
    raise exception
コード例 #4
0
    def _poll_imds(self):
        """Poll IMDS for the new provisioning data until we get a valid
        response. Then return the returned JSON object."""
        url = IMDS_URL + "reprovisiondata?api-version=2017-04-02"
        headers = {"Metadata": "true"}
        report_ready = bool(not os.path.isfile(REPORTED_READY_MARKER_FILE))
        LOG.debug("Start polling IMDS")

        while True:
            try:
                # Save our EphemeralDHCPv4 context so we avoid repeated dhcp
                self._ephemeral_dhcp_ctx = EphemeralDHCPv4()
                lease = self._ephemeral_dhcp_ctx.obtain_lease()
                if report_ready:
                    path = REPORTED_READY_MARKER_FILE
                    LOG.info("Creating a marker file to report ready: %s",
                             path)
                    util.write_file(
                        path, "{pid}: {time}\n".format(pid=os.getpid(),
                                                       time=time()))
                    self._report_ready(lease=lease)
                    report_ready = False
                return readurl(url,
                               timeout=1,
                               headers=headers,
                               exception_cb=retry_on_url_exc,
                               infinite=True,
                               log_req_resp=False).contents
            except UrlError:
                # Teardown our EphemeralDHCPv4 context on failure as we retry
                self._ephemeral_dhcp_ctx.clean_network()
                pass
コード例 #5
0
    def _get_data(self):
        url_params = self.get_url_params()
        network_context = noop()
        if self.perform_dhcp_setup:
            network_context = EphemeralDHCPv4(self.fallback_interface)
        with network_context:
            ret = util.log_time(
                LOG.debug,
                "Crawl of GCE metadata service",
                read_md,
                kwargs={
                    "address": self.metadata_address,
                    "url_params": url_params,
                },
            )

        if not ret["success"]:
            if ret["platform_reports_gce"]:
                LOG.warning(ret["reason"])
            else:
                LOG.debug(ret["reason"])
            return False
        self.metadata = ret["meta-data"]
        self.userdata_raw = ret["user-data"]
        return True
コード例 #6
0
ファイル: DataSourceEc2.py プロジェクト: tuapuikia/cloud-init
    def _get_data(self):
        strict_mode, _sleep = read_strict_mode(
            util.get_cfg_by_path(self.sys_cfg, STRICT_ID_PATH,
                                 STRICT_ID_DEFAULT), ("warn", None))

        LOG.debug("strict_mode: %s, cloud_name=%s cloud_platform=%s",
                  strict_mode, self.cloud_name, self.platform)
        if strict_mode == "true" and self.cloud_name == CloudNames.UNKNOWN:
            return False
        elif self.cloud_name == CloudNames.NO_EC2_METADATA:
            return False

        if self.perform_dhcp_setup:  # Setup networking in init-local stage.
            if util.is_FreeBSD():
                LOG.debug("FreeBSD doesn't support running dhclient with -sf")
                return False
            try:
                with EphemeralDHCPv4(self.fallback_interface):
                    self._crawled_metadata = util.log_time(
                        logfunc=LOG.debug, msg='Crawl of metadata service',
                        func=self.crawl_metadata)
            except NoDHCPLeaseError:
                return False
        else:
            self._crawled_metadata = util.log_time(
                logfunc=LOG.debug, msg='Crawl of metadata service',
                func=self.crawl_metadata)
        if not self._crawled_metadata:
            return False
        self.metadata = self._crawled_metadata.get('meta-data', None)
        self.userdata_raw = self._crawled_metadata.get('user-data', None)
        self.identity = self._crawled_metadata.get(
            'dynamic', {}).get('instance-identity', {}).get('document', {})
        return True
コード例 #7
0
ファイル: DataSourceAzure.py プロジェクト: tomer/cloud-init
    def _poll_imds(self):
        """Poll IMDS for the new provisioning data until we get a valid
        response. Then return the returned JSON object."""
        url = IMDS_URL + "reprovisiondata?api-version=2017-04-02"
        headers = {"Metadata": "true"}
        report_ready = bool(not os.path.isfile(REPORTED_READY_MARKER_FILE))
        LOG.debug("Start polling IMDS")

        def exc_cb(msg, exception):
            if isinstance(exception, UrlError) and exception.code == 404:
                return True
            # If we get an exception while trying to call IMDS, we
            # call DHCP and setup the ephemeral network to acquire the new IP.
            return False

        while True:
            try:
                with EphemeralDHCPv4() as lease:
                    if report_ready:
                        path = REPORTED_READY_MARKER_FILE
                        LOG.info("Creating a marker file to report ready: %s",
                                 path)
                        util.write_file(
                            path, "{pid}: {time}\n".format(pid=os.getpid(),
                                                           time=time()))
                        self._report_ready(lease=lease)
                        report_ready = False
                    return readurl(url,
                                   timeout=1,
                                   headers=headers,
                                   exception_cb=exc_cb,
                                   infinite=True).contents
            except UrlError:
                pass
コード例 #8
0
ファイル: DataSourceEc2.py プロジェクト: wujcheng/cloud-init
    def _get_data(self):
        seed_ret = {}
        if util.read_optional_seed(seed_ret, base=(self.seed_dir + "/")):
            self.userdata_raw = seed_ret['user-data']
            self.metadata = seed_ret['meta-data']
            LOG.debug("Using seeded ec2 data from %s", self.seed_dir)
            self._cloud_platform = Platforms.SEEDED
            return True

        strict_mode, _sleep = read_strict_mode(
            util.get_cfg_by_path(self.sys_cfg, STRICT_ID_PATH,
                                 STRICT_ID_DEFAULT), ("warn", None))

        LOG.debug("strict_mode: %s, cloud_platform=%s",
                  strict_mode, self.cloud_platform)
        if strict_mode == "true" and self.cloud_platform == Platforms.UNKNOWN:
            return False
        elif self.cloud_platform == Platforms.NO_EC2_METADATA:
            return False

        if self.perform_dhcp_setup:  # Setup networking in init-local stage.
            if util.is_FreeBSD():
                LOG.debug("FreeBSD doesn't support running dhclient with -sf")
                return False
            try:
                with EphemeralDHCPv4(self.fallback_interface):
                    return util.log_time(
                        logfunc=LOG.debug, msg='Crawl of metadata service',
                        func=self._crawl_metadata)
            except NoDHCPLeaseError:
                return False
        else:
            return self._crawl_metadata()
コード例 #9
0
    def _get_data(self):
        """Crawl metadata, parse and persist that data for this instance.

        @return: True when metadata discovered indicates OpenStack datasource.
            False when unable to contact metadata service or when metadata
            format is invalid or disabled.
        """
        oracle_considered = "Oracle" in self.sys_cfg.get("datasource_list")
        if not detect_openstack(accept_oracle=not oracle_considered):
            return False

        if self.perform_dhcp_setup:  # Setup networking in init-local stage.
            try:
                with EphemeralDHCPv4(self.fallback_interface):
                    results = util.log_time(
                        logfunc=LOG.debug,
                        msg="Crawl of metadata service",
                        func=self._crawl_metadata,
                    )
            except (NoDHCPLeaseError, sources.InvalidMetaDataException) as e:
                util.logexc(LOG, str(e))
                return False
        else:
            try:
                results = self._crawl_metadata()
            except sources.InvalidMetaDataException as e:
                util.logexc(LOG, str(e))
                return False

        self.dsmode = self._determine_dsmode([results.get("dsmode")])
        if self.dsmode == sources.DSMODE_DISABLED:
            return False
        md = results.get("metadata", {})
        md = util.mergemanydict([md, DEFAULT_METADATA])
        self.metadata = md
        self.ec2_metadata = results.get("ec2-metadata")
        self.network_json = results.get("networkdata")
        self.userdata_raw = results.get("userdata")
        self.version = results["version"]
        self.files.update(results.get("files", {}))

        vd = results.get("vendordata")
        self.vendordata_pure = vd
        try:
            self.vendordata_raw = sources.convert_vendordata(vd)
        except ValueError as e:
            LOG.warning("Invalid content in vendor-data: %s", e)
            self.vendordata_raw = None

        vd2 = results.get("vendordata2")
        self.vendordata2_pure = vd2
        try:
            self.vendordata2_raw = sources.convert_vendordata(vd2)
        except ValueError as e:
            LOG.warning("Invalid content in vendor-data2: %s", e)
            self.vendordata2_raw = None

        return True
コード例 #10
0
    def _poll_imds(self):
        """Poll IMDS for the new provisioning data until we get a valid
        response. Then return the returned JSON object."""
        url = IMDS_URL + "reprovisiondata?api-version=2017-04-02"
        headers = {"Metadata": "true"}
        nl_sock = None
        report_ready = bool(not os.path.isfile(REPORTED_READY_MARKER_FILE))

        def exc_cb(msg, exception):
            if isinstance(exception, UrlError) and exception.code == 404:
                return True
            # If we get an exception while trying to call IMDS, we
            # call DHCP and setup the ephemeral network to acquire the new IP.
            return False

        LOG.debug("Wait for vnetswitch to happen")
        while True:
            try:
                # Save our EphemeralDHCPv4 context so we avoid repeated dhcp
                self._ephemeral_dhcp_ctx = EphemeralDHCPv4()
                lease = self._ephemeral_dhcp_ctx.obtain_lease()
                if report_ready:
                    try:
                        nl_sock = netlink.create_bound_netlink_socket()
                    except netlink.NetlinkCreateSocketError as e:
                        LOG.warning(e)
                        self._ephemeral_dhcp_ctx.clean_network()
                        return
                    path = REPORTED_READY_MARKER_FILE
                    LOG.info("Creating a marker file to report ready: %s",
                             path)
                    util.write_file(
                        path, "{pid}: {time}\n".format(pid=os.getpid(),
                                                       time=time()))
                    self._report_ready(lease=lease)
                    report_ready = False
                    try:
                        netlink.wait_for_media_disconnect_connect(
                            nl_sock, lease['interface'])
                    except AssertionError as error:
                        LOG.error(error)
                        return
                    self._ephemeral_dhcp_ctx.clean_network()
                else:
                    return readurl(url,
                                   timeout=1,
                                   headers=headers,
                                   exception_cb=exc_cb,
                                   infinite=True,
                                   log_req_resp=False).contents
            except UrlError:
                # Teardown our EphemeralDHCPv4 context on failure as we retry
                self._ephemeral_dhcp_ctx.clean_network()
                pass
            finally:
                if nl_sock:
                    nl_sock.close()
コード例 #11
0
def get_metadata(url, timeout, retries, sec_between, agent):
    # Bring up interface
    try:
        with EphemeralDHCPv4(connectivity_url_data={"url": url}):
            # Fetch the metadata
            v1 = read_metadata(url, timeout, retries, sec_between, agent)
    except (NoDHCPLeaseError) as exc:
        LOG.error("Bailing, DHCP Exception: %s", exc)
        raise

    return json.loads(v1)
コード例 #12
0
    def _get_data(self):
        (on_hetzner, serial) = get_hcloud_data()

        if not on_hetzner:
            return False

        try:
            with EphemeralDHCPv4(
                    iface=net.find_fallback_nic(),
                    connectivity_url_data={
                        "url": BASE_URL_V1 + "/metadata/instance-id",
                    },
            ):
                md = hc_helper.read_metadata(
                    self.metadata_address,
                    timeout=self.timeout,
                    sec_between=self.wait_retry,
                    retries=self.retries,
                )
                ud = hc_helper.read_userdata(
                    self.userdata_address,
                    timeout=self.timeout,
                    sec_between=self.wait_retry,
                    retries=self.retries,
                )
        except (NoDHCPLeaseError) as e:
            LOG.error("Bailing, DHCP Exception: %s", e)
            raise

        # Hetzner cloud does not support binary user-data. So here, do a
        # base64 decode of the data if we can. The end result being that a
        # user can provide base64 encoded (possibly gzipped) data as user-data.
        #
        # The fallout is that in the event of b64 encoded user-data,
        # /var/lib/cloud-init/cloud-config.txt will not be identical to the
        # user-data provided.  It will be decoded.
        self.userdata_raw = hc_helper.maybe_b64decode(ud)
        self.metadata_full = md

        # hostname is name provided by user at launch.  The API enforces it is
        # a valid hostname, but it is not guaranteed to be resolvable in dns or
        # fully qualified.
        self.metadata["instance-id"] = md["instance-id"]
        self.metadata["local-hostname"] = md["hostname"]
        self.metadata["network-config"] = md.get("network-config", None)
        self.metadata["public-keys"] = md.get("public-keys", None)
        self.vendordata_raw = md.get("vendor_data", None)

        # instance-id and serial from SMBIOS should be identical
        if self.get_instance_id() != serial:
            raise RuntimeError(
                "SMBIOS serial does not match instance ID from metadata")

        return True
コード例 #13
0
    def _get_data(self):
        (is_upcloud, server_uuid) = self._get_sysinfo()

        # only proceed if we know we are on UpCloud
        if not is_upcloud:
            return False

        LOG.info("Running on UpCloud. server_uuid=%s", server_uuid)

        if self.perform_dhcp_setup:  # Setup networking in init-local stage.
            try:
                LOG.debug("Finding a fallback NIC")
                nic = cloudnet.find_fallback_nic()
                LOG.debug("Discovering metadata via DHCP interface %s", nic)
                with EphemeralDHCPv4(nic):
                    md = util.log_time(
                        logfunc=LOG.debug,
                        msg="Reading from metadata service",
                        func=self._read_metadata,
                    )
            except (NoDHCPLeaseError, sources.InvalidMetaDataException) as e:
                util.logexc(LOG, str(e))
                return False
        else:
            try:
                LOG.debug(
                    "Discovering metadata without DHCP-configured networking")
                md = util.log_time(
                    logfunc=LOG.debug,
                    msg="Reading from metadata service",
                    func=self._read_metadata,
                )
            except sources.InvalidMetaDataException as e:
                util.logexc(LOG, str(e))
                LOG.info(
                    "No DHCP-enabled interfaces available, "
                    "unable to fetch metadata for %s",
                    server_uuid,
                )
                return False

        self.metadata_full = md
        self.metadata["instance-id"] = md.get("instance_id", server_uuid)
        self.metadata["local-hostname"] = md.get("hostname")
        self.metadata["network"] = md.get("network")
        self.metadata["public-keys"] = md.get("public_keys")
        self.metadata["availability_zone"] = md.get("region", "default")
        self.vendordata_raw = md.get("vendor_data", None)
        self.userdata_raw = md.get("user_data", None)

        return True
コード例 #14
0
def get_metadata(url, timeout, retries, sec_between):
    # Bring up interface
    try:
        with EphemeralDHCPv4(connectivity_url=url):
            # Fetch the metadata
            v1 = read_metadata(url, timeout, retries, sec_between)
    except (NoDHCPLeaseError) as exc:
        LOG.error("Bailing, DHCP Exception: %s", exc)
        raise

    v1_json = json.loads(v1)
    metadata = v1_json

    return metadata
コード例 #15
0
    def _get_data(self):
        if not on_scaleway():
            return False

        if self._fallback_interface is None:
            self._fallback_interface = net.find_fallback_nic()
        try:
            with EphemeralDHCPv4(self._fallback_interface):
                util.log_time(logfunc=LOG.debug,
                              msg='Crawl of metadata service',
                              func=self._crawl_metadata)
        except (NoDHCPLeaseError) as e:
            util.logexc(LOG, str(e))
            return False
        return True
コード例 #16
0
    def _get_data(self):
        """Crawl metadata, parse and persist that data for this instance.

        @return: True when metadata discovered indicates OpenStack datasource.
            False when unable to contact metadata service or when metadata
            format is invalid or disabled.
        """
        if self.perform_dhcp_setup:  # Setup networking in init-local stage.
            try:
                with EphemeralDHCPv4(self.fallback_interface):
                    results = util.log_time(logfunc=LOG.debug,
                                            msg='Crawl of metadata service',
                                            func=self._crawl_metadata)
            except (NoDHCPLeaseError, sources.InvalidMetaDataException) as e:
                util.logexc(LOG, str(e))
                return False
        else:
            try:
                results = self._crawl_metadata()
            except sources.InvalidMetaDataException as e:
                util.logexc(LOG, str(e))
                return False

        self.dsmode = self._determine_dsmode([results.get('dsmode')])
        if self.dsmode == sources.DSMODE_DISABLED:
            return False
        md = results.get('metadata', {})
        md = util.mergemanydict([md, DEFAULT_METADATA])
        self.metadata = md
        self.ec2_metadata = results.get('ec2-metadata')
        self.network_json = results.get('networkdata')
        self.userdata_raw = results.get('userdata')
        self.version = results['version']
        self.files.update(results.get('files', {}))

        vd = results.get('vendordata')
        self.vendordata_pure = vd
        try:
            self.vendordata_raw = sources.convert_vendordata(vd)
        except ValueError as e:
            LOG.warning("Invalid content in vendor-data: %s", e)
            self.vendordata_raw = None

        return True
コード例 #17
0
    def _get_data(self):
        with EphemeralDHCPv4(get_first_physical_interface()):
            response = url_helper.readurl(self.metadata_address, timeout=self.timeout,
                                          sec_between=self.wait_retry,
                                          retries=self.retries)
        if not response.ok():
            raise RuntimeError("unable to read metadata at %s" % self.metadata_address)

        md = json.loads(response.contents.decode())

        LOG.debug("Vultr metadata: %s", pprint.pformat(md))

        self.metadata_full = md
        self.metadata['instance-id'] = md['instanceid']
        self.metadata['local-hostname'] = md['hostname']
        self.metadata['interfaces'] = md.get('interfaces')
        self.metadata['public-keys'] = md.get('public-keys')
        self.metadata['availability_zone'] = md.get('region', {}).get('EWR', 'unknown')

        return True
コード例 #18
0
    def _poll_imds(self, report_ready=True):
        """Poll IMDS for the new provisioning data until we get a valid
        response. Then return the returned JSON object."""
        url = IMDS_URL + "?api-version=2017-04-02"
        headers = {"Metadata": "true"}
        LOG.debug("Start polling IMDS")

        def sleep_cb(response, loop_n):
            return 1

        def exception_cb(msg, exception):
            if isinstance(exception, UrlError) and exception.code == 404:
                return
            LOG.warning("Exception during polling. Will try DHCP.",
                        exc_info=True)

            # If we get an exception while trying to call IMDS, we
            # call DHCP and setup the ephemeral network to acquire the new IP.
            raise exception

        need_report = report_ready
        for i in range(IMDS_RETRIES):
            try:
                with EphemeralDHCPv4() as lease:
                    if need_report:
                        self._report_ready(lease=lease)
                        need_report = False
                    wait_for_url([url],
                                 max_wait=None,
                                 timeout=60,
                                 status_cb=LOG.info,
                                 headers_cb=lambda url: headers,
                                 sleep_time=1,
                                 exception_cb=exception_cb,
                                 sleep_time_cb=sleep_cb)
                    return str(readurl(url, headers=headers))
            except Exception:
                LOG.debug("Exception during polling-retrying dhcp" +
                          " %d more time(s).", (IMDS_RETRIES - i),
                          exc_info=True)
コード例 #19
0
def get_metadata(url, timeout, retries, sec_between, agent):
    # Bring up interface (and try untill one works)
    exception = RuntimeError("Failed to DHCP")

    # Seek iface with DHCP
    for iface in net.get_interfaces():
        # Skip dummy, lo interfaces
        if "dummy" in iface[0]:
            continue
        if "lo" == iface[0]:
            continue
        try:
            with EphemeralDHCPv4(
                iface=iface[0], connectivity_url_data={"url": url}
            ):
                # Fetch the metadata
                v1 = read_metadata(url, timeout, retries, sec_between, agent)

                return json.loads(v1)
        except (NoDHCPLeaseError, subp.ProcessExecutionError) as exc:
            LOG.error("DHCP Exception: %s", exc)
            exception = exc
    raise exception
コード例 #20
0
ファイル: azure.py プロジェクト: waquidvp/cloud-init
 def __init__(self, reporter, nic=None):
     self.reporter = reporter
     self.ephemeralDHCPv4 = EphemeralDHCPv4(
         iface=nic, dhcp_log_func=dhcp_log_cb)
コード例 #21
0
ファイル: azure.py プロジェクト: P79N6A/cloud-init-1
 def __init__(self, reporter, nic=None):
     self.reporter = reporter
     self.ephemeralDHCPv4 = EphemeralDHCPv4(iface=nic)
コード例 #22
0
    def crawl_metadata(self):
        """Walk all instance metadata sources returning a dict on success.

        @return: A dictionary of any metadata content for this instance.
        @raise: InvalidMetaDataException when the expected metadata service is
            unavailable, broken or disabled.
        """
        crawled_data = {}
        # azure removes/ejects the cdrom containing the ovf-env.xml
        # file on reboot.  So, in order to successfully reboot we
        # need to look in the datadir and consider that valid
        ddir = self.ds_cfg['data_dir']

        candidates = [self.seed_dir]
        if os.path.isfile(REPROVISION_MARKER_FILE):
            candidates.insert(0, "IMDS")
        candidates.extend(list_possible_azure_ds_devs())
        if ddir:
            candidates.append(ddir)

        found = None
        reprovision = False
        for cdev in candidates:
            try:
                if cdev == "IMDS":
                    ret = None
                    reprovision = True
                elif cdev.startswith("/dev/"):
                    if util.is_FreeBSD():
                        ret = util.mount_cb(cdev,
                                            load_azure_ds_dir,
                                            mtype="udf",
                                            sync=False)
                    else:
                        ret = util.mount_cb(cdev, load_azure_ds_dir)
                else:
                    ret = load_azure_ds_dir(cdev)

            except NonAzureDataSource:
                continue
            except BrokenAzureDataSource as exc:
                msg = 'BrokenAzureDataSource: %s' % exc
                raise sources.InvalidMetaDataException(msg)
            except util.MountFailedError:
                LOG.warning("%s was not mountable", cdev)
                continue

            perform_reprovision = reprovision or self._should_reprovision(ret)
            if perform_reprovision:
                if util.is_FreeBSD():
                    msg = "Free BSD is not supported for PPS VMs"
                    LOG.error(msg)
                    raise sources.InvalidMetaDataException(msg)
                ret = self._reprovision()
            imds_md = get_metadata_from_imds(self.fallback_interface,
                                             retries=10)
            (md, userdata_raw, cfg, files) = ret
            self.seed = cdev
            crawled_data.update({
                'cfg':
                cfg,
                'files':
                files,
                'metadata':
                util.mergemanydict([md, {
                    'imds': imds_md
                }]),
                'userdata_raw':
                userdata_raw
            })
            found = cdev

            LOG.debug("found datasource in %s", cdev)
            break

        if not found:
            raise sources.InvalidMetaDataException('No Azure metadata found')

        if found == ddir:
            LOG.debug("using files cached in %s", ddir)

        seed = _get_random_seed()
        if seed:
            crawled_data['metadata']['random_seed'] = seed
        crawled_data['metadata']['instance-id'] = util.read_dmi_data(
            'system-uuid')

        if perform_reprovision:
            LOG.info("Reporting ready to Azure after getting ReprovisionData")
            use_cached_ephemeral = (net.is_up(self.fallback_interface) and
                                    getattr(self, '_ephemeral_dhcp_ctx', None))
            if use_cached_ephemeral:
                self._report_ready(lease=self._ephemeral_dhcp_ctx.lease)
                self._ephemeral_dhcp_ctx.clean_network()  # Teardown ephemeral
            else:
                with EphemeralDHCPv4() as lease:
                    self._report_ready(lease=lease)

        return crawled_data