Python傳送請求代token
在請求neutronserver時,需要先建立neutronclient,再通過neutronclient訪問neutron server。例如:dash board訪問neutron server 時,需要在horirzon/openstack_dashboard/api/neutron.py檔案中建立neutronclient.
例如在list router時,函式如下:
def router_list(request, **params): routers = neutronclient(request).list_routers(**params).get('routers') return [Router(r) for r in routers]
函式呼叫neutronclient的list_routers函式。
neutronclient定義如下:
def neutronclient(request): insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None) c = neutron_client.Client(token=request.user.token.id, auth_url=base.url_for(request, 'identity'), endpoint_url=base.url_for(request, 'network'), insecure=insecure, ca_cert=cacert) return c
from neutronclient.v2_0 import client as neutron_client因為當前用的是2.0版本,所以在v2_0中建立的neutronclient。建立時帶入了token id。
在neutronclient/v2_0/client.py中 client定義如下
class Client(ClientBase):
def __init__(self, **kwargs): """Initialize a new client for the Neutron v2.0 API.""" super(Client, self).__init__(**kwargs) self._register_extensions(self.version) client繼承ClientBase,在初始化時首先呼叫父類的建構函式。
class ClientBase(object):
def __init__(self, **kwargs): """Initialize a new client for the Neutron v2.0 API.""" super(ClientBase, self).__init__() self.retries = kwargs.pop('retries', 0) self.raise_errors = kwargs.pop('raise_errors', True) self.httpclient = client.construct_http_client(**kwargs) self.version = '2.0' self.format = 'json' self.action_prefix = "/v%s" % (self.version) self.retry_interval = 1在父類的建構函式中,要建立httpclient,然後通過httpclient去訪問api.
def construct_http_client(username=None, user_id=None, tenant_name=None, tenant_id=None, password=None, auth_url=None, token=None, region_name=None, timeout=None, endpoint_url=None, insecure=False, endpoint_type='publicURL', log_credentials=None, auth_strategy='keystone', ca_cert=None, service_type='network', session=None, **kwargs): if session: kwargs.setdefault('user_agent', 'python-neutronclient') kwargs.setdefault('interface', endpoint_type) return SessionClient(session=session, service_type=service_type, region_name=region_name, **kwargs) else: # FIXME(bklei): username and password are now optional. Need # to test that they were provided in this mode. Should also # refactor to use kwargs. return HTTPClient(username=username, password=password, tenant_id=tenant_id, tenant_name=tenant_name, user_id=user_id, auth_url=auth_url, token=token, endpoint_url=endpoint_url, insecure=insecure, timeout=timeout, region_name=region_name, endpoint_type=endpoint_type, service_type=service_type, ca_cert=ca_cert, log_credentials=log_credentials, auth_strategy=auth_strategy)
construct_http_client函式中,通過是否有session來決定建立SessionClient還是HTTPClient.
所以建立的neutronclient的httpclient實際是SessionClient或者HTTPClient。
通過日誌檢視都是SessionClient,大概是因為neutron服務一直在執行中吧,session已經存在。第一次啟動是HTTPClient。
neutronclient的list_routers函式如下:
def list_routers(self, retrieve_all=True, **_params): """Fetches a list of all routers for a tenant.""" # Pass filters in "params" argument to do_request return self.list('routers', self.routers_path, retrieve_all, **_params)list函式如下:
def list(self, collection, path, retrieve_all=True, **params): if retrieve_all: res = [] for r in self._pagination(collection, path, **params): res.extend(r[collection]) return {collection: res} else: return self._pagination(collection, path, **params)_pagination函式如下:
def _pagination(self, collection, path, **params): if params.get('page_reverse', False): linkrel = 'previous' else: linkrel = 'next' next = True while next: res = self.get(path, params=params) yield res next = False try: for link in res['%s_links' % collection]: if link['rel'] == linkrel: query_str = urlparse.urlparse(link['href']).query params = urlparse.parse_qs(query_str) next = True break except KeyError: break
self.get函式如下:
def get(self, action, body=None, headers=None, params=None): _logger.info("headers is %s,body is %s"%(headers,body)) return self.retry_request("GET", action, body=body, headers=headers, params=params)
retry_request函式如下:
def retry_request(self, method, action, body=None, headers=None, params=None): max_attempts = self.retries + 1 for i in range(max_attempts): try: return self.do_request(method, action, body=body, headers=headers, params=params) except exceptions.ConnectionFailed: # Exception has already been logged by do_request() if i < self.retries: _logger.debug('Retrying connection to Neutron service') time.sleep(self.retry_interval) elif self.raise_errors: raise if self.retries: msg = (_("Failed to connect to Neutron server after %d attempts") % max_attempts) else: msg = _("Failed to connect Neutron server") raise exceptions.ConnectionFailed(reason=msg)
do_request函式如下:
def do_request(self, method, action, body=None, headers=None, params=None): # Add format and tenant_id action += ".%s" % self.format action = self.action_prefix + action if type(params) is dict and params: params = utils.safe_encode_dict(params) action += '?' + urlparse.urlencode(params, doseq=1) if body: body = self.serialize(body) resp, replybody = self.httpclient.do_request( action, method, body=body, content_type=self.content_type()) status_code = resp.status_code if status_code in (requests.codes.ok, requests.codes.created, requests.codes.accepted, requests.codes.no_content): return self.deserialize(replybody, status_code) else: if not replybody: replybody = resp.reason self._handle_fault_response(status_code, replybody)
在do_request裡,呼叫了httpclient.do_request函式。在BaseClient中構造了httpclient,do_request函式如下:
def do_request(self, url, method, **kwargs): # Ensure client always has correct uri - do not guesstimate anything self.authenticate_and_fetch_endpoint_url() self._check_uri_length(url) try: kwargs.setdefault('headers', {}) if self.auth_token is None: self.auth_token = "" kwargs['headers']['X-Auth-Token'] = self.auth_token resp, body = self._cs_request(self.endpoint_url + url, method, **kwargs) return resp, body except exceptions.Unauthorized: self.authenticate() kwargs.setdefault('headers', {}) kwargs['headers']['X-Auth-Token'] = self.auth_token resp, body = self._cs_request( self.endpoint_url + url, method, **kwargs) return resp, body
在這個函式中,首先進行token和endpoint_url確認。然後堅持請求url的長度,最大不得超過8192.http預設的請求最大是255,不知道這裡怎麼是8192.最後將token資訊放入header中。然後keystonemiddleware從header中獲取token進行驗證。
下面說明在第一次請求時沒有token,怎麼去獲取token。
authenticate_and_fetch_endpoint_url函式如下:
def authenticate_and_fetch_endpoint_url(self): if not self.auth_token: self.authenticate() elif not self.endpoint_url: self.endpoint_url = self._get_endpoint_url()authenticate函式如下:
def authenticate(self): if self.auth_strategy == 'keystone': self._authenticate_keystone() elif self.auth_strategy == 'noauth': self._authenticate_noauth() else: err_msg = _('Unknown auth strategy: %s') % self.auth_strategy raise exceptions.Unauthorized(message=err_msg)_authenticate_keystone函式如下:
def _authenticate_keystone(self): if self.user_id: creds = {'userId': self.user_id, 'password': self.password} else: creds = {'username': self.username, 'password': self.password} if self.tenant_id: body = {'auth': {'passwordCredentials': creds, 'tenantId': self.tenant_id, }, } else: body = {'auth': {'passwordCredentials': creds, 'tenantName': self.tenant_name, }, } if self.auth_url is None: raise exceptions.NoAuthURLProvided() token_url = self.auth_url + "/tokens" resp, resp_body = self._cs_request(token_url, "POST", body=json.dumps(body), content_type="application/json", allow_redirects=True) if resp.status_code != 200: raise exceptions.Unauthorized(message=resp_body) if resp_body: try: resp_body = json.loads(resp_body) except ValueError: pass else: resp_body = None self._extract_service_catalog(resp_body)
向keystone獲取token。
相關文章
- python傳送HTTP POST請求PythonHTTP
- Python爬蟲(二)——傳送請求Python爬蟲
- Postman傳送Post請求Postman
- Java傳送Post請求Java
- 傳送GET請求 示例
- HttpClient--傳送請求HTTPclient
- perl傳送http請求HTTP
- java傳送http請求JavaHTTP
- 如何傳送請求以及AJAX
- C# 傳送POST請求C#
- 使用HttpClient傳送GET請求HTTPclient
- 使用httpclient傳送http請求HTTPclient
- SpringMVC中如何傳送GET請求、POST請求、PUT請求、DELETE請求。SpringMVCdelete
- RxHttp 一條鏈傳送請求,新一代Http請求神器(一)HTTP
- Zttp 傳送 form params 請求 而非 JSON 請求ORMJSON
- 【轉】怎麼用PHP傳送HTTP請求(POST請求、GET請求)?PHPHTTP
- java傳送GET和post請求Java
- 使用Feign傳送HTTP請求HTTP
- post 封裝Map 傳送請求封裝
- PHP傳送POST和GET請求PHP
- postman傳送請求使用篇(二)Postman
- 用Fiddler 傳送post請求
- .net 後臺 傳送http請求HTTP
- 通過PowerShell傳送TCP請求TCP
- 使用C#傳送POST請求C#
- Postman傳送請求引數是Map格式的請求Postman
- java傳送post請求 ,請求資料放到body裡Java
- Vue 使用 Axios 傳送請求的請求體問題VueiOS
- linux用curl傳送post請求Linux
- 以Raw的方式傳送POST請求
- Vue中封裝axios傳送請求Vue封裝iOS
- httprequest- post- get -傳送請求HTTP
- jQuery裡如何使用ajax傳送請求jQuery
- 使用requests庫來傳送HTTP請求HTTP
- nodejs使用request傳送http請求NodeJSHTTP
- php 利用socket傳送GET,POST請求PHP
- java傳送http的get、post請求JavaHTTP
- 實現傳送多個Ajax請求