示例#1
0
    def _maybe_fetch_api_token(self, mdurls, timeout=None, max_wait=None):
        if self.cloud_name != CloudNames.AWS:
            return

        urls = []
        url2base = {}
        url_path = API_TOKEN_ROUTE
        request_method = 'PUT'
        for url in mdurls:
            cur = '{0}/{1}'.format(url, url_path)
            urls.append(cur)
            url2base[cur] = url

        # use the self._status_cb to check for Read errors, which means
        # we can't reach the API token URL, so we should disable IMDSv2
        LOG.debug('Fetching Ec2 IMDSv2 API Token')
        url, response = uhelp.wait_for_url(urls=urls,
                                           max_wait=1,
                                           timeout=1,
                                           status_cb=self._status_cb,
                                           headers_cb=self._get_headers,
                                           request_method=request_method,
                                           headers_redact=AWS_TOKEN_REDACT)

        if url and response:
            self._api_token = response
            return url2base[url]
    def wait_for_metadata_service(self):
        urls = self.ds_cfg.get("metadata_urls", [DEF_MD_URL])
        filtered = [x for x in urls if util.is_resolvable_url(x)]
        if set(filtered) != set(urls):
            LOG.debug("Removed the following from metadata urls: %s",
                      list((set(urls) - set(filtered))))
        if len(filtered):
            urls = filtered
        else:
            LOG.warn("Empty metadata url list! using default list")
            urls = [DEF_MD_URL]

        md_urls = []
        url2base = {}
        for url in urls:
            md_url = url_helper.combine_url(url, 'openstack')
            md_urls.append(md_url)
            url2base[md_url] = url

        (max_wait, timeout) = self._get_url_settings()
        start_time = time.time()
        avail_url = url_helper.wait_for_url(urls=md_urls, max_wait=max_wait,
                                            timeout=timeout)
        if avail_url:
            LOG.debug("Using metadata source: '%s'", url2base[avail_url])
        else:
            LOG.debug("Giving up on OpenStack md from %s after %s seconds",
                      md_urls, int(time.time() - start_time))

        self.metadata_address = url2base.get(avail_url)
        return bool(avail_url)
    def wait_for_metadata_service(self, url):
        mcfg = self.ds_cfg

        max_wait = 120
        try:
            max_wait = int(mcfg.get("max_wait", max_wait))
        except Exception:
            util.logexc(LOG, "Failed to get max wait. using %s", max_wait)

        if max_wait == 0:
            return False

        timeout = 50
        try:
            if timeout in mcfg:
                timeout = int(mcfg.get("timeout", timeout))
        except Exception:
            LOG.warn("Failed to get timeout, using %s" % timeout)

        starttime = time.time()
        check_url = "%s/%s/meta-data/instance-id" % (url, MD_VERSION)
        urls = [check_url]
        url = url_helper.wait_for_url(urls=urls, max_wait=max_wait,
                                      timeout=timeout,
                                      exception_cb=self._except_cb,
                                      headers_cb=self._md_headers)

        if url:
            LOG.debug("Using metadata source: '%s'", url)
        else:
            LOG.critical("Giving up on md from %s after %i seconds",
                         urls, int(time.time() - starttime))

        return bool(url)
示例#4
0
    def wait_for_metadata_service(self):
        url_params = self.get_url_params()

        if url_params.max_wait_seconds <= 0:
            return False

        urls = [
            uhelp.combine_url(self.metadata_address,
                              'latest/meta-data/instance-id')
        ]
        start_time = time.time()
        url, _response = uhelp.wait_for_url(
            urls=urls,
            max_wait=url_params.max_wait_seconds,
            timeout=url_params.timeout_seconds,
            status_cb=LOG.warning)

        if url:
            LOG.debug("Using metadata source: '%s'", url)
        else:
            LOG.critical(("Giving up on waiting for the metadata from %s"
                          " after %s seconds"), urls,
                         int(time.time() - start_time))

        return bool(url)
示例#5
0
    def wait_for_metadata_service(self):
        mcfg = self.ds_cfg

        url_params = self.get_url_params()
        if url_params.max_wait_seconds <= 0:
            return False

        # Remove addresses from the list that wont resolve.
        mdurls = mcfg.get("metadata_urls", self.metadata_urls)
        filtered = [x for x in mdurls if util.is_resolvable_url(x)]

        if set(filtered) != set(mdurls):
            LOG.debug("Removed the following from metadata urls: %s",
                      list((set(mdurls) - set(filtered))))

        if len(filtered):
            mdurls = filtered
        else:
            LOG.warning("Empty metadata url list! using default list")
            mdurls = self.metadata_urls

        # try the api token path first
        metadata_address = self._maybe_fetch_api_token(mdurls)
        # When running on EC2, we always access IMDS with an API token.
        # If we could not get an API token, then we assume the IMDS
        # endpoint was disabled and we move on without a data source.
        # Fallback to IMDSv1 if not running on EC2
        if not metadata_address and self.cloud_name != CloudNames.AWS:
            # if we can't get a token, use instance-id path
            urls = []
            url2base = {}
            url_path = '{ver}/meta-data/instance-id'.format(
                ver=self.min_metadata_version)
            request_method = 'GET'
            for url in mdurls:
                cur = '{0}/{1}'.format(url, url_path)
                urls.append(cur)
                url2base[cur] = url

            start_time = time.time()
            url, _ = uhelp.wait_for_url(
                urls=urls, max_wait=url_params.max_wait_seconds,
                timeout=url_params.timeout_seconds, status_cb=LOG.warning,
                headers_redact=AWS_TOKEN_REDACT, headers_cb=self._get_headers,
                request_method=request_method)

            if url:
                metadata_address = url2base[url]

        if metadata_address:
            self.metadata_address = metadata_address
            LOG.debug("Using metadata source: '%s'", self.metadata_address)
        elif self.cloud_name == CloudNames.AWS:
            LOG.warning("IMDS's HTTP endpoint is probably disabled")
        else:
            LOG.critical("Giving up on md from %s after %s seconds",
                         urls, int(time.time() - start_time))

        return bool(metadata_address)
示例#6
0
    def wait_for_metadata_service(self):
        mcfg = self.ds_cfg

        url_params = self.get_url_params()
        if url_params.max_wait_seconds <= 0:
            return False

        # Remove addresses from the list that wont resolve.
        mdurls = mcfg.get("metadata_urls", self.metadata_urls)
        filtered = [x for x in mdurls if util.is_resolvable_url(x)]

        if set(filtered) != set(mdurls):
            LOG.debug("Removed the following from metadata urls: %s",
                      list((set(mdurls) - set(filtered))))

        if len(filtered):
            mdurls = filtered
        else:
            LOG.warning("Empty metadata url list! using default list")
            mdurls = self.metadata_urls

        # try the api token path first
        metadata_address = self._maybe_fetch_api_token(mdurls)
        if not metadata_address:
            if self._api_token == API_TOKEN_DISABLED:
                LOG.warning('Retrying with IMDSv1')
            # if we can't get a token, use instance-id path
            urls = []
            url2base = {}
            url_path = '{ver}/meta-data/instance-id'.format(
                ver=self.min_metadata_version)
            request_method = 'GET'
            for url in mdurls:
                cur = '{0}/{1}'.format(url, url_path)
                urls.append(cur)
                url2base[cur] = url

            start_time = time.time()
            url, _ = uhelp.wait_for_url(urls=urls,
                                        max_wait=url_params.max_wait_seconds,
                                        timeout=url_params.timeout_seconds,
                                        status_cb=LOG.warning,
                                        headers_redact=AWS_TOKEN_REDACT,
                                        headers_cb=self._get_headers,
                                        request_method=request_method)

            if url:
                metadata_address = url2base[url]

        if metadata_address:
            self.metadata_address = metadata_address
            LOG.debug("Using metadata source: '%s'", self.metadata_address)
        else:
            LOG.critical("Giving up on md from %s after %s seconds", urls,
                         int(time.time() - start_time))

        return bool(metadata_address)
示例#7
0
    def wait_for_metadata_service(self):
        """Wait for the metadata service to be reachable."""

        metadata_url = "{}/{}/meta-data/instance-id".format(
            self.metadata_url, self.api_version)

        url = url_helper.wait_for_url(urls=[metadata_url],
                                      max_wait=self.url_max_wait,
                                      timeout=self.url_timeout,
                                      status_cb=LOG.critical)

        return bool(url)
示例#8
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)
示例#9
0
    def _maybe_fetch_api_token(self, mdurls, timeout=None, max_wait=None):
        """Get an API token for EC2 Instance Metadata Service.

        On EC2. IMDS will always answer an API token, unless
        the instance owner has disabled the IMDS HTTP endpoint or
        the network topology conflicts with the configured hop-limit.
        """
        if self.cloud_name != CloudNames.AWS:
            return

        urls = []
        url2base = {}
        url_path = API_TOKEN_ROUTE
        request_method = "PUT"
        for url in mdurls:
            cur = "{0}/{1}".format(url, url_path)
            urls.append(cur)
            url2base[cur] = url

        # use the self._imds_exception_cb to check for Read errors
        LOG.debug("Fetching Ec2 IMDSv2 API Token")

        response = None
        url = None
        url_params = self.get_url_params()
        try:
            url, response = uhelp.wait_for_url(
                urls=urls,
                max_wait=url_params.max_wait_seconds,
                timeout=url_params.timeout_seconds,
                status_cb=LOG.warning,
                headers_cb=self._get_headers,
                exception_cb=self._imds_exception_cb,
                request_method=request_method,
                headers_redact=AWS_TOKEN_REDACT,
                connect_synchronously=False,
            )
        except uhelp.UrlError:
            # We use the raised exception to interupt the retry loop.
            # Nothing else to do here.
            pass

        if url and response:
            self._api_token = response
            return url2base[url]

        # If we get here, then wait_for_url timed out, waiting for IMDS
        # or the IMDS HTTP endpoint is disabled
        return None
示例#10
0
    def wait_for_metadata_service(self):
        (max_wait, timeout) = self._get_url_settings()

        urls = [uhelp.combine_url(self.metadata_address,
                                  'latest/meta-data/instance-id')]
        start_time = time.time()
        url = uhelp.wait_for_url(urls=urls, max_wait=max_wait,
                                 timeout=timeout, status_cb=LOG.warn)

        if url:
            LOG.debug("Using metadata source: '%s'", url)
        else:
            LOG.critical(("Giving up on waiting for the metadata from %s"
                          " after %s seconds"),
                         urls, int(time.time() - start_time))

        return bool(url)
示例#11
0
    def wait_for_metadata_service(self):
        mcfg = self.ds_cfg
        if not mcfg:
            mcfg = {}

        (max_wait, timeout) = self._get_url_settings()
        if max_wait <= 0:
            return False

        # Remove addresses from the list that wont resolve.
        mdurls = mcfg.get("metadata_urls", DEF_MD_URLS)
        filtered = [x for x in mdurls if util.is_resolvable_url(x)]

        if set(filtered) != set(mdurls):
            LOG.debug("Removed the following from metadata urls: %s",
                      list((set(mdurls) - set(filtered))))

        if len(filtered):
            mdurls = filtered
        else:
            LOG.warn("Empty metadata url list! using default list")
            mdurls = DEF_MD_URLS

        urls = []
        url2base = {}
        for url in mdurls:
            cur = "%s/%s/meta-data/instance-id" % (url, self.api_ver)
            urls.append(cur)
            url2base[cur] = url

        start_time = time.time()
        url = uhelp.wait_for_url(urls=urls,
                                 max_wait=max_wait,
                                 timeout=timeout,
                                 status_cb=LOG.warn)

        if url:
            LOG.debug("Using metadata source: '%s'", url2base[url])
        else:
            LOG.critical("Giving up on md from %s after %s seconds", urls,
                         int(time.time() - start_time))

        self.metadata_address = url2base.get(url)
        return bool(url)
示例#12
0
    def wait_for_metadata_service(self):
        mcfg = self.ds_cfg

        url_params = self.get_url_params()
        if url_params.max_wait_seconds <= 0:
            return False

        # Remove addresses from the list that wont resolve.
        mdurls = mcfg.get("metadata_urls", self.metadata_urls)
        filtered = [x for x in mdurls if util.is_resolvable_url(x)]

        if set(filtered) != set(mdurls):
            LOG.debug("Removed the following from metadata urls: %s",
                      list((set(mdurls) - set(filtered))))

        if len(filtered):
            mdurls = filtered
        else:
            LOG.warning("Empty metadata url list! using default list")
            mdurls = self.metadata_urls

        urls = []
        url2base = {}
        for url in mdurls:
            cur = '{0}/{1}/meta-data/instance-id'.format(
                url, self.min_metadata_version)
            urls.append(cur)
            url2base[cur] = url

        start_time = time.time()
        url = uhelp.wait_for_url(urls=urls,
                                 max_wait=url_params.max_wait_seconds,
                                 timeout=url_params.timeout_seconds,
                                 status_cb=LOG.warn)

        if url:
            self.metadata_address = url2base[url]
            LOG.debug("Using metadata source: '%s'", self.metadata_address)
        else:
            LOG.critical("Giving up on md from %s after %s seconds", urls,
                         int(time.time() - start_time))

        return bool(url)
示例#13
0
    def wait_for_metadata_service(self):
        mcfg = self.ds_cfg
        if not mcfg:
            mcfg = {}

        (max_wait, timeout) = self._get_url_settings()
        if max_wait <= 0:
            return False

        # Remove addresses from the list that wont resolve.
        mdurls = mcfg.get("metadata_urls", DEF_MD_URLS)
        filtered = [x for x in mdurls if util.is_resolvable_url(x)]

        if set(filtered) != set(mdurls):
            LOG.debug("Removed the following from metadata urls: %s",
                      list((set(mdurls) - set(filtered))))

        if len(filtered):
            mdurls = filtered
        else:
            LOG.warn("Empty metadata url list! using default list")
            mdurls = DEF_MD_URLS

        urls = []
        url2base = {}
        for url in mdurls:
            cur = "%s/%s/meta-data/instance-id" % (url, self.api_ver)
            urls.append(cur)
            url2base[cur] = url

        start_time = time.time()
        url = uhelp.wait_for_url(urls=urls, max_wait=max_wait,
                                timeout=timeout, status_cb=LOG.warn)

        if url:
            LOG.debug("Using metadata source: '%s'", url2base[url])
        else:
            LOG.critical("Giving up on md from %s after %s seconds",
                            urls, int(time.time() - start_time))

        self.metadata_address = url2base.get(url)
        return bool(url)
示例#14
0
    def wait_for_metadata_service(self):
        mcfg = self.ds_cfg

        url_params = self.get_url_params()
        if url_params.max_wait_seconds <= 0:
            return False

        # Remove addresses from the list that wont resolve.
        mdurls = mcfg.get("metadata_urls", self.metadata_urls)
        filtered = [x for x in mdurls if util.is_resolvable_url(x)]

        if set(filtered) != set(mdurls):
            LOG.debug("Removed the following from metadata urls: %s",
                      list((set(mdurls) - set(filtered))))

        if len(filtered):
            mdurls = filtered
        else:
            LOG.warning("Empty metadata url list! using default list")
            mdurls = self.metadata_urls

        urls = []
        url2base = {}
        for url in mdurls:
            cur = '{0}/{1}/meta-data/instance-id'.format(
                url, self.min_metadata_version)
            urls.append(cur)
            url2base[cur] = url

        start_time = time.time()
        url = uhelp.wait_for_url(
            urls=urls, max_wait=url_params.max_wait_seconds,
            timeout=url_params.timeout_seconds, status_cb=LOG.warning)

        if url:
            self.metadata_address = url2base[url]
            LOG.debug("Using metadata source: '%s'", self.metadata_address)
        else:
            LOG.critical("Giving up on md from %s after %s seconds",
                         urls, int(time.time() - start_time))

        return bool(url)
示例#15
0
    def wait_for_metadata_service(self):
        urls = self.ds_cfg.get("metadata_urls", [DEF_MD_URL])
        filtered = [x for x in urls if util.is_resolvable_url(x)]
        if set(filtered) != set(urls):
            LOG.debug(
                "Removed the following from metadata urls: %s",
                list((set(urls) - set(filtered))),
            )
        if len(filtered):
            urls = filtered
        else:
            LOG.warning("Empty metadata url list! using default list")
            urls = [DEF_MD_URL]

        md_urls = []
        url2base = {}
        for url in urls:
            md_url = url_helper.combine_url(url, "openstack")
            md_urls.append(md_url)
            url2base[md_url] = url

        url_params = self.get_url_params()
        start_time = time.time()
        avail_url, _response = url_helper.wait_for_url(
            urls=md_urls,
            max_wait=url_params.max_wait_seconds,
            timeout=url_params.timeout_seconds,
        )
        if avail_url:
            LOG.debug("Using metadata source: '%s'", url2base[avail_url])
        else:
            LOG.debug(
                "Giving up on OpenStack md from %s after %s seconds",
                md_urls,
                int(time.time() - start_time),
            )

        self.metadata_address = url2base.get(avail_url)
        return bool(avail_url)
示例#16
0
    def test_order(self, addresses, expected_address_index, response):
        """Check that the first response gets returned. Simulate a
        non-responding endpoint with a response that has a one second wait.

        If this test proves flaky, increase wait time. Since it is async,
        increasing wait time for the non-responding endpoint should not
        increase total test time, assuming async_delay=0 is used and at least
        one non-waiting endpoint is registered with httpretty.
        Subsequent tests will continue execution after the first response is
        received.
        """
        self.event.clear()
        for address in set(addresses):
            responses.add_callback(
                responses.GET,
                address,
                callback=(
                    self.response_wait
                    if "sleep" in address
                    else self.response_nowait
                ),
                content_type="application/json",
            )

        # Use async_delay=0.0 to avoid adding unnecessary time to tests
        # In practice a value such as 0.150 is used
        url, response_contents = wait_for_url(
            urls=addresses,
            max_wait=1,
            timeout=1,
            connect_synchronously=False,
            async_delay=0.0,
        )
        self.event.set()

        # Test for timeout (no responding endpoint)
        assert addresses[expected_address_index] == url
        assert response.encode() == response_contents