def _create_ironic_client(self): api_version = self.options.os_baremetal_api_version allow_api_version_downgrade = False if not api_version: api_version = self.cloud_region.get_default_microversion(_TYPE) if not api_version: api_version = http.LATEST_VERSION allow_api_version_downgrade = True LOG.debug('Using bare metal API version %s, downgrade %s', api_version, 'allowed' if allow_api_version_downgrade else 'disallowed') # NOTE(dtantsur): endpoint_override is required to respect settings in # clouds.yaml, such as baremetal_endpoint_override. endpoint_override = self.cloud_region.get_endpoint(_TYPE) try: return client.Client( os_ironic_api_version=api_version, allow_api_version_downgrade=allow_api_version_downgrade, session=self.cloud_region.get_session(), region_name=self.cloud_region.get_region_name(_TYPE), endpoint_override=endpoint_override, max_retries=self.options.max_retries, retry_interval=self.options.retry_interval, ) except exc.EndpointNotFound as e: # Re-raise with a more obvious message. raise exc.EndpointNotFound(_HELP % { 'err': e, 'cmd': sys.argv[0], 'project': 'ironic' })
def _http_request(self, url, method, **kwargs): """Send an http request with the specified characteristics. Wrapper around httplib.HTTP(S)Connection.request to handle tasks such as setting headers and error handling. """ # Copy the kwargs so we can reuse the original in case of redirects kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {})) kwargs['headers'].setdefault('User-Agent', USER_AGENT) if self.auth_token: kwargs['headers'].setdefault('X-Auth-Token', self.auth_token) self.log_curl_request(method, url, kwargs) conn = self.get_connection() try: conn_url = self._make_connection_url(url) conn.request(method, conn_url, **kwargs) resp = conn.getresponse() except socket.gaierror as e: message = ("Error finding address for %(url)s: %(e)s" % dict(url=url, e=e)) raise exc.EndpointNotFound(message) except (socket.error, socket.timeout) as e: endpoint = self.endpoint message = ("Error communicating with %(endpoint)s %(e)s" % dict(endpoint=endpoint, e=e)) raise exc.ConnectionRefused(message) body_iter = ResponseBodyIterator(resp) # Read body into string if it isn't obviously image data body_str = None if resp.getheader('content-type', None) != 'application/octet-stream': body_str = ''.join([chunk for chunk in body_iter]) self.log_http_response(resp, body_str) body_iter = six.StringIO(body_str) else: self.log_http_response(resp) if 400 <= resp.status < 600: LOG.warn("Request returned failure status.") error_json = _extract_error_json(body_str) raise exc.from_response( resp, error_json.get('faultstring'), error_json.get('debuginfo'), method, url) elif resp.status in (301, 302, 305): # Redirected. Reissue the request to the new location. return self._http_request(resp['location'], method, **kwargs) elif resp.status == 300: raise exc.from_response(resp, method=method, url=url) return resp, body_iter
def __init__(self, os_ironic_api_version, api_version_select_state, max_retries, retry_interval, **kwargs): self.os_ironic_api_version = os_ironic_api_version self.api_version_select_state = api_version_select_state self.conflict_max_retries = max_retries self.conflict_retry_interval = retry_interval if isinstance(kwargs.get('endpoint_override'), six.string_types): kwargs['endpoint_override'] = _trim_endpoint_api_version( kwargs['endpoint_override']) super(SessionClient, self).__init__(**kwargs) endpoint_filter = self._get_endpoint_filter() endpoint = self.get_endpoint(**endpoint_filter) if endpoint is None: raise exc.EndpointNotFound( _('The Bare Metal API endpoint cannot be detected and was ' 'not provided explicitly')) self.endpoint_trimmed = _trim_endpoint_api_version(endpoint)
def _create_inspector_client(self): assert ironic_inspector_client is not None, \ 'BUG: _create_inspector_client called without inspector client' # NOTE(dtantsur): endpoint_override is required to respect settings in # clouds.yaml, such as baremetal_introspection_endpoint_override. endpoint_override = self.cloud_region.get_endpoint(_INSPECTOR_TYPE) try: return ironic_inspector_client.ClientV1( inspector_url=endpoint_override, session=self.cloud_region.get_session(), region_name=self.cloud_region.get_region_name(_INSPECTOR_TYPE), ) except ironic_inspector_client.EndpointNotFound as e: # Re-raise with a more obvious message. raise exc.EndpointNotFound(_HELP % { 'err': e, 'cmd': sys.argv[0], 'project': 'ironic-inspector' })
def _http_request(self, url, method, **kwargs): """Send an http request with the specified characteristics. Wrapper around httplib.HTTP(S)Connection.request to handle tasks such as setting headers and error handling. """ # Copy the kwargs so we can reuse the original in case of redirects kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {})) kwargs['headers'].setdefault('User-Agent', USER_AGENT) if self.os_ironic_api_version: kwargs['headers'].setdefault('X-OpenStack-Ironic-API-Version', self.os_ironic_api_version) if self.auth_token: kwargs['headers'].setdefault('X-Auth-Token', self.auth_token) self.log_curl_request(method, url, kwargs) conn = self.get_connection() try: conn_url = self._make_connection_url(url) conn.request(method, conn_url, **kwargs) resp = conn.getresponse() # TODO(deva): implement graceful client downgrade when connecting # to servers that did not support microversions. Details here: # http://specs.openstack.org/openstack/ironic-specs/specs/kilo/api-microversions.html#use-case-3b-new-client-communicating-with-a-old-ironic-user-specified # noqa if resp.status == 406: negotiated_ver = self.negotiate_version(conn, resp) kwargs['headers']['X-OpenStack-Ironic-API-Version'] = ( negotiated_ver) return self._http_request(url, method, **kwargs) except socket.gaierror as e: message = ("Error finding address for %(url)s: %(e)s" % dict(url=url, e=e)) raise exc.EndpointNotFound(message) except (socket.error, socket.timeout) as e: endpoint = self.endpoint message = ("Error communicating with %(endpoint)s %(e)s" % dict(endpoint=endpoint, e=e)) raise exc.ConnectionRefused(message) body_iter = ResponseBodyIterator(resp) # Read body into string if it isn't obviously image data body_str = None if resp.getheader('content-type', None) != 'application/octet-stream': body_str = ''.join([chunk for chunk in body_iter]) self.log_http_response(resp, body_str) body_iter = six.StringIO(body_str) else: self.log_http_response(resp) if 400 <= resp.status < 600: LOG.warn("Request returned failure status.") error_json = _extract_error_json(body_str) raise exc.from_response(resp, error_json.get('faultstring'), error_json.get('debuginfo'), method, url) elif resp.status in (301, 302, 305): # Redirected. Reissue the request to the new location. return self._http_request(resp['location'], method, **kwargs) elif resp.status == 300: raise exc.from_response(resp, method=method, url=url) return resp, body_iter