def remove_github_token(self): ''' If for some reason an ansible-galaxy token was left from a prior login, remove it. We cannot retrieve the token after creation, so we are forced to create a new one. ''' try: tokens = json.load( open_url( self.GITHUB_AUTH, url_username=self.github_username, url_password=self.github_password, force_basic_auth=True, )) except HTTPError as e: res = json.load(e) raise exceptions.GalaxyClientError(res['message']) for token in tokens: if token['note'] == 'ansible-galaxy login': self.log.debug('removing token: %s', token['token_last_eight']) try: open_url('https://api.github.com/authorizations/%d' % token['id'], url_username=self.github_username, url_password=self.github_password, method='DELETE', force_basic_auth=True) except HTTPError as e: self.log.exception(e) res = json.load(e) raise exceptions.GalaxyClientError(res['message'])
def _get_server_api_version(self): """ Fetches the Galaxy API current version to ensure the API server is up and reachable. """ url = '%s/api/' % self._api_server try: return_data = open_url(url, validate_certs=self._validate_certs) except Exception as e: raise exceptions.GalaxyClientError( "Failed to get data from the API server (%s): %s " % (url, to_native(e))) try: data = json.loads( to_text(return_data.read(), errors='surrogate_or_strict')) except Exception as e: raise exceptions.GalaxyClientError( "Could not process data from the API server (%s): %s " % (url, to_native(e))) if 'current_version' not in data: raise exceptions.GalaxyClientError( "missing required 'current_version' from server response (%s)" % url) self.log.debug('Server API version of URL %s is "%s"', url, data['current_version']) return data['current_version']
def __call_galaxy(self, url, args=None, headers=None, method=None): if args and not headers: headers = self.__auth_header() try: # self.log.info('%s %s', method, url) # self.log.debug('%s %s args=%s', method, url, args) # self.log.debug('%s %s headers=%s', method, url, headers) resp = open_url(url, data=args, validate_certs=self._validate_certs, headers=headers, method=method, timeout=20) self.log.debug('%s %s http_status=%s', method, url, resp.getcode()) final_url = resp.geturl() if final_url != url: self.log.debug('%s %s Redirected to: %s', method, url, resp.geturl()) # self.log.debug('%s %s info:\n%s', method, url, resp.info()) data = json.loads( to_text(resp.read(), errors='surrogate_or_strict')) # self.log.debug('%s %s data: \n%s', method, url, json.dumps(data, indent=2)) except HTTPError as e: self.log.debug('Exception on %s %s', method, url) self.log.exception(e) res = json.loads(to_text(e.fp.read(), errors='surrogate_or_strict')) raise exceptions.GalaxyClientError(res['detail']) return data
def fetch_url(archive_url, validate_certs=True): """ Downloads the archived content from github to a temp location """ # TODO: should probably be based on/shared with rest API client code, so that # content downloads could support any thing the rest code does # (ie, any TLS cert setup, proxy config, auth options, etc) # WHEN: if we change the underlying http client impl at least try: url_file = open_url(archive_url, validate_certs=validate_certs) temp_file = tempfile.NamedTemporaryFile( delete=False, prefix='tmp-ansible-galaxy-content-archive-', suffix='.tar.gz') data = url_file.read() while data: temp_file.write(data) data = url_file.read() temp_file.close() return temp_file.name except Exception as e: # FIXME: there is a ton of reasons a download and save could fail so could likely provided better errors here log.exception(e) raise exceptions.GalaxyDownloadError( "failed to download the file: %s" % str(e)) return False
def __call_galaxy(self, url, args=None, headers=None, method=None): if args and not headers: headers = self.__auth_header() try: http_log.info('%s %s', method, url) request_log.debug('%s %s args=%s', method, url, args) request_log.debug('%s %s headers=%s', method, url, headers) resp = open_url(url, data=args, validate_certs=self._validate_certs, headers=headers, method=method, timeout=20) http_log.info('%s %s http_status=%s', method, url, resp.getcode()) final_url = resp.geturl() if final_url != url: http_log.debug('%s %s Redirected to: %s', method, url, resp.geturl()) resp_info = resp.info() response_log.debug('%s %s info:\n%s', method, url, resp_info) # FIXME: making the request and loading the response should be sep try/except blocks response_body = to_text(resp.read(), errors='surrogate_or_strict') # debug log the raw response body response_log.debug('%s %s response body:\n%s', method, url, response_body) data = json.loads(response_body) # debug log a json version of the data that was created from the response response_log.debug('%s %s data:\n%s', method, url, json.dumps(data, indent=2)) except HTTPError as e: self.log.debug('Exception on %s %s', method, url) self.log.exception(e) # FIXME: probably need a try/except here if the response body isnt json which # can happen if a proxy mangles the response res = json.loads(to_text(e.fp.read(), errors='surrogate_or_strict')) http_log.error('%s %s data from server error response:\n%s', method, url, res) raise exceptions.GalaxyClientError(res['detail']) except (ssl.SSLError, socket.error) as e: self.log.debug( 'Connection error to Galaxy API for request "%s %s": %s', method, url, e) self.log.exception(e) raise exceptions.GalaxyClientAPIConnectionError( 'Connection error to Galaxy API for request "%s %s": %s' % (method, url, e)) return data
def authenticate(self, github_token): """ Retrieve an authentication token """ url = '%s/tokens/' % self.baseurl args = urlencode({"github_token": github_token}) resp = open_url(url, data=args, validate_certs=self._validate_certs, method="POST") data = json.loads(to_text(resp.read(), errors='surrogate_or_strict')) return data
def create_github_token(self): ''' Create a personal authorization token with a note of 'ansible-galaxy login' ''' self.remove_github_token() args = json.dumps({ "scopes": ["public_repo"], "note": "ansible-galaxy login" }) try: data = json.load( open_url(self.GITHUB_AUTH, url_username=self.github_username, url_password=self.github_password, force_basic_auth=True, data=args)) except HTTPError as e: self.log.exception(e) res = json.load(e) raise exceptions.GalaxyClientError(res['message']) return data['token']
def __call_galaxy(self, url, args=None, headers=None, http_method=None): http_method = http_method or 'GET' headers = headers or {} request_id = uuid.uuid4().hex headers['X-Request-ID'] = request_id # The slug we use to identify a request by method, url and request id # For ex, '"GET https://galaxy.ansible.com/api/v1/repositories" c48937f4e8e849828772c4a0ce0fd5ed' request_slug = '"%s %s" %s' % (http_method, url, request_id) try: # log the http request_slug with request_id to the main log and # to the http log, both at INFO level for now. http_log.info('%s', request_slug) self.log.info('%s', request_slug) request_log.debug('%s args=%s', request_slug, args) request_log.debug('%s headers=%s', request_slug, headers) resp = open_url(url, data=args, validate_certs=self._validate_certs, headers=headers, method=http_method, http_agent=self.user_agent, timeout=20) response_log.info('%s http_status=%s', request_slug, resp.getcode()) final_url = resp.geturl() if final_url != url: request_log.debug('%s Redirected to: %s', request_slug, resp.geturl()) resp_info = resp.info() response_log.debug('%s info:\n%s', request_slug, resp_info) # FIXME: making the request and loading the response should be sep try/except blocks response_body = to_text(resp.read(), errors='surrogate_or_strict') # debug log the raw response body response_log.debug('%s response body:\n%s', request_slug, response_body) data = json.loads(response_body) # debug log a json version of the data that was created from the response response_log.debug('%s data:\n%s', request_slug, json.dumps(data, indent=2)) except HTTPError as http_exc: self.log.debug('Exception on %s', request_slug) self.log.exception("%s: %s", request_slug, http_exc) # FIXME: probably need a try/except here if the response body isnt json which # can happen if a proxy mangles the response res = json.loads( to_text(http_exc.fp.read(), errors='surrogate_or_strict')) http_log.error('%s data from server error response:\n%s', request_slug, res) try: error_msg = 'HTTP error on request %s: %s' % (request_slug, res['detail']) raise exceptions.GalaxyClientError(error_msg) except (KeyError, TypeError) as detail_parse_exc: self.log.exception("%s: %s", request_slug, detail_parse_exc) self.log.warning( 'Unable to parse error detail from response for request: %s response: %s', request_slug, detail_parse_exc) # TODO: great place to be able to use 'raise from' # FIXME: this needs to be tweaked so the raise exceptions.GalaxyClientError(http_exc) except (ssl.SSLError, socket.error) as e: self.log.debug('Connection error to Galaxy API for request %s: %s', request_slug, e) self.log.exception("%s: %s", request_slug, e) raise exceptions.GalaxyClientAPIConnectionError( 'Connection error to Galaxy API for request %s: %s' % (request_slug, e)) return data