def test_as_expected(self, mock_parse, mock_encode, m_dl_req, m_string_io): """ Test that a request is created with correct query parameters to retrieve a bearer token. """ m_downloader = mock.MagicMock() m_req = mock.MagicMock() m_headers = mock.MagicMock() m_string_io.return_value.getvalue.return_value = '{"token": "Hey, its a token!"}' mock_parse.return_value = {"realm": "url", "other_info": "stuff"} mock_encode.return_value = "other_info=stuff" token_util.request_token(m_downloader, m_req, m_headers) mock_encode.assert_called_once_with({"other_info": "stuff"}) m_dl_req.assert_called_once_with("url?other_info=stuff", m_string_io.return_value) mock_parse.assert_called_once_with(m_headers) m_downloader.download_one.assert_called_once_with(m_dl_req.return_value)
def _get_path(self, path): """ Retrieve a single path within the upstream registry, and return a 2-tuple of the headers and the response body. :param path: a full http path to retrieve that will be urljoin'd to the upstream registry url. :type path: basestring :return: (headers, response body) :rtype: tuple """ url = urlparse.urljoin(self.registry_url, path) _logger.debug(_('Retrieving {0}'.format(url))) request = DownloadRequest(url, StringIO()) if self.token: token_util.add_auth_header(request, self.token) report = self.downloader.download_one(request) # If the download was unauthorized, attempt to get a token and try again if report.state == report.DOWNLOAD_FAILED: if report.error_report.get('response_code') == httplib.UNAUTHORIZED: _logger.debug(_('Download unauthorized, attempting to retrieve a token.')) self.token = token_util.request_token(self.downloader, request, report.headers) token_util.add_auth_header(request, self.token) report = self.downloader.download_one(request) if report.state == report.DOWNLOAD_FAILED: raise IOError(report.error_msg) return report.headers, report.destination.getvalue()
def test_as_expected(self, mock_parse, mock_encode, m_dl_req, m_string_io): """ Test that a request is created with correct query parameters to retrieve a bearer token. """ m_downloader = mock.MagicMock() m_req = mock.MagicMock() m_headers = mock.MagicMock() m_string_io.return_value.getvalue.return_value = '{"token": "Hey, its a token!"}' mock_parse.return_value = {'realm': 'url', 'other_info': 'stuff'} mock_encode.return_value = 'other_info=stuff' token_util.request_token(m_downloader, m_req, m_headers) mock_encode.assert_called_once_with({'other_info': 'stuff'}) m_dl_req.assert_called_once_with('url?other_info=stuff', m_string_io.return_value) mock_parse.assert_called_once_with(m_headers) m_downloader.download_one.assert_called_once_with( m_dl_req.return_value)
def _get_path(self, path, headers=None): """ Retrieve a single path within the upstream registry, and return a 2-tuple of the headers and the response body. :param path: a full http path to retrieve that will be urljoin'd to the upstream registry url. :type path: basestring :param headers: headers sent in the request :type headers: dict :return: (headers, response body) :rtype: tuple """ url = urlparse.urljoin(self.registry_url, path) _logger.debug(_('Retrieving {0}'.format(url))) request = DownloadRequest(url, StringIO()) request.headers = headers if self.token: request.headers = token_util.update_auth_header( request.headers, self.token) report = self.downloader.download_one(request) # If the download was unauthorized, attempt to get a token and try again if report.state == report.DOWNLOAD_FAILED: if report.error_report.get( 'response_code') == httplib.UNAUTHORIZED: _logger.debug( _('Download unauthorized, attempting to retrieve a token.') ) self.token = token_util.request_token(self.token_downloader, request, report.headers) request.headers = token_util.update_auth_header( request.headers, self.token) report = self.downloader.download_one(request) if report.state == report.DOWNLOAD_FAILED: # this condition was added in case the registry would not allow to access v2 endpoint # but still token would be valid for other endpoints. # see https://pulp.plan.io/issues/2643 if path == '/v2/' and report.error_report.get( 'response_code') == httplib.UNAUTHORIZED: pass else: self._raise_path_error(report) return report.headers, report.destination.getvalue()
def download_failed(self, report): """ If the download fails due to a 401, attempt to retreive a token and try again. :param report: download report :type report: nectar.report.DownloadReport """ if report.error_report.get('response_code') == httplib.UNAUTHORIZED: _logger.debug(_('Download unauthorized, attempting to retrieve a token.')) request = self._requests_map[report.url] token = token_util.request_token(self.downloader, request, report.headers) token_util.add_auth_header(request, token) _logger.debug("Trying download again with new bearer token.") report = self.downloader.download_one(request, events=True) if report.state == report.DOWNLOAD_FAILED: super(TokenAuthDownloadStep, self).download_failed(report)
def _get_path(self, path): """ Retrieve a single path within the upstream registry, and return a 2-tuple of the headers and the response body. :param path: a full http path to retrieve that will be urljoin'd to the upstream registry url. :type path: basestring :return: (headers, response body) :rtype: tuple """ url = urlparse.urljoin(self.registry_url, path) _logger.debug(_('Retrieving {0}'.format(url))) request = DownloadRequest(url, StringIO()) if self.token: token_util.add_auth_header(request, self.token) report = self.downloader.download_one(request) # If the download was unauthorized, attempt to get a token and try again if report.state == report.DOWNLOAD_FAILED: if report.error_report.get( 'response_code') == httplib.UNAUTHORIZED: _logger.debug( _('Download unauthorized, attempting to retrieve a token.') ) self.token = token_util.request_token(self.downloader, request, report.headers) token_util.add_auth_header(request, self.token) report = self.downloader.download_one(request) if report.state == report.DOWNLOAD_FAILED: raise IOError(report.error_msg) return report.headers, report.destination.getvalue()
def download_failed(self, report): """ If the download is unauthorized, attempt to retreive a token and try again. :param report: download report :type report: nectar.report.DownloadReport """ if report.error_report.get('response_code') == httplib.UNAUTHORIZED: _logger.debug(_('Download unauthorized, attempting to retrieve a token.')) request = self._requests_map[report.url] token = token_util.request_token(self.parent.index_repository.token_downloader, request, report.headers) self.downloader.session.headers = token_util.update_auth_header( self.downloader.session.headers, token) _logger.debug("Trying download again with new bearer token.") # Events must be false or download_failed will recurse report = self.downloader.download_one(request, events=False) if report.state is report.DOWNLOAD_SUCCEEDED: self.download_succeeded(report) elif report.state is report.DOWNLOAD_FAILED: super(TokenAuthDownloadStep, self).download_failed(report) # Docker blobs have ancestry relationships and need all blobs to function. Sync should # stop immediately to prevent publishing of an incomplete repository. os.kill(os.getpid(), signal.SIGKILL)
def download_failed(self, report): """ If the download is unauthorized, attempt to retreive a token and try again. :param report: download report :type report: nectar.report.DownloadReport """ if report.error_report.get('response_code') == httplib.UNAUTHORIZED: _logger.debug(_('Download unauthorized, attempting to retrieve a token.')) request = self._requests_map[report.url] token = token_util.request_token(self.parent.index_repository.token_downloader, request, report.headers) self.downloader.session.headers = token_util.update_auth_header( self.downloader.session.headers, token) _logger.debug("Trying download again with new bearer token.") # Events must be false or download_failed will recurse report = self.downloader.download_one(request, events=False) if report.state is report.DOWNLOAD_SUCCEEDED: self.download_succeeded(report) elif report.state is report.DOWNLOAD_FAILED: super(TokenAuthDownloadStep, self).download_failed(report) # Docker blobs have ancestry relationships and need all blobs to function. Sync should # stop immediately to prevent publishing of an incomplete repository. os.kill(os.getpid(), signal.SIGKILL)