The OpenSearch SDK for Python uses an in-house gateway service for signature verification, with the Alibaba Cloud TeaDSL SDK handling signature construction. The BaseRequest.py file shown here implements the core client — Config for connection settings and Client for sending signed HTTP requests.
Prerequisites
Before you begin, ensure that you have:
An OpenSearch instance with a configured endpoint
An Alibaba Cloud AccessKey ID and AccessKey secret
Install dependencies
Install the three required packages:
pip install alibabacloud_tea_util
pip install alibabacloud_opensearch_util
pip install alibabacloud_credentials| Package | Purpose |
|---|---|
alibabacloud_tea_util | Core HTTP runtime: timeouts, retries, JSON serialization |
alibabacloud_opensearch_util | OpenSearch-specific utilities: date formatting, MD5 hashing, request signing |
alibabacloud_credentials | Alibaba Cloud credential management: AccessKey, security token |
How it works
Each request goes through the following steps:
The
Configobject holds your endpoint, protocol, and credentials.The
Clientinitializes aCredentialClientfrom those settings.When you call
_request, the client builds aTeaRequestwith the required headers —Date,X-Opensearch-Nonce,Content-MD5(when a body is present), andAuthorization.The
Authorizationheader is computed byOpensearchUtil.get_signature(), satisfying the gateway's signature verification requirement.On a 4xx or 5xx response, the client raises a
TeaException. On a retryable error, it backs off and retries up tomax_attemptstimes (default: 3) before raisingUnretryableException.
Sample code
The following code is in the BaseRequest.py file. All requests use the _request method to build headers, sign the request, execute it, and return the response body and headers.
# -*- coding: utf-8 -*-
import time
from typing import Dict, Any
from Tea.core import TeaCore
from Tea.exceptions import TeaException, UnretryableException
from Tea.model import TeaModel
from Tea.request import TeaRequest
from alibabacloud_credentials import models as credential_models
from alibabacloud_credentials.client import Client as CredentialClient
from alibabacloud_opensearch_util.opensearch_util import OpensearchUtil
from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_util.client import Client as UtilClient
class Config(TeaModel):
"""
Config
The environment-related configurations.
"""
def __init__(
self,
endpoint: str = None,
protocol: str = None,
type: str = None,
security_token: str = None,
access_key_id: str = None,
access_key_secret: str = None,
user_agent: str = "",
):
self.endpoint = endpoint
self.protocol = protocol
self.type = type
self.security_token = security_token
self.access_key_id = access_key_id
self.access_key_secret = access_key_secret
self.user_agent = user_agent
class Client:
"""
OpensearchClient
The OpenSearch client that is used to specify request parameters and send the request.
"""
_endpoint: str = None
_protocol: str = None
_user_agent: str = None
_credential: CredentialClient = None
def __init__(
self,
config: Config,
):
if UtilClient.is_unset(config):
raise TeaException({
'name': 'ParameterMissing',
'message': "'config' can not be unset"
})
if UtilClient.empty(config.type):
config.type = 'access_key'
credential_config = credential_models.Config(
access_key_id=config.access_key_id,
type=config.type,
access_key_secret=config.access_key_secret,
security_token=config.security_token
)
self._credential = CredentialClient(credential_config)
self._endpoint = config.endpoint
self._protocol = config.protocol
self._user_agent = config.user_agent
def _request(
self,
method: str,
pathname: str,
query: Dict[str, Any],
headers: Dict[str, str],
body: Any,
runtime: util_models.RuntimeOptions,
) -> Dict[str, Any]:
"""
Process the request.
:param request: TeaRequest
:param runtime: util_models.RuntimeOptions
:return: Dict[str, Any]
"""
runtime.validate()
_runtime = {
'timeouted': 'retry',
'readTimeout': runtime.read_timeout,
'connectTimeout': runtime.connect_timeout,
'httpProxy': runtime.http_proxy,
'httpsProxy': runtime.https_proxy,
'noProxy': runtime.no_proxy,
'maxIdleConns': runtime.max_idle_conns,
'retry': {
'retryable': runtime.autoretry,
'maxAttempts': UtilClient.default_number(runtime.max_attempts, 3)
},
'backoff': {
'policy': UtilClient.default_string(runtime.backoff_policy, 'no'),
'period': UtilClient.default_number(runtime.backoff_period, 1)
},
'ignoreSSL': runtime.ignore_ssl
}
_last_request = None
_last_exception = None
_now = time.time()
_retry_times = 0
while TeaCore.allow_retry(_runtime.get('retry'), _retry_times, _now):
if _retry_times > 0:
_backoff_time = TeaCore.get_backoff_time(_runtime.get('backoff'), _retry_times)
if _backoff_time > 0:
TeaCore.sleep(_backoff_time)
_retry_times = _retry_times + 1
try:
_request = TeaRequest()
accesskey_id = self._credential.get_access_key_id()
access_key_secret = self._credential.get_access_key_secret()
security_token = self._credential.get_security_token()
_request.protocol = UtilClient.default_string(self._protocol, 'HTTP')
_request.method = method
_request.pathname = pathname
_request.headers = TeaCore.merge({
'user-agent': UtilClient.get_user_agent(self._user_agent),
'Content-Type': 'application/json',
'Date': OpensearchUtil.get_date(),
'host': UtilClient.default_string(self._endpoint, f'opensearch-cn-hangzhou.aliyuncs.com'),
'X-Opensearch-Nonce': UtilClient.get_nonce()
}, headers)
if not UtilClient.is_unset(query):
_request.query = UtilClient.stringify_map_value(query)
if not UtilClient.is_unset(body):
req_body = UtilClient.to_jsonstring(body)
_request.headers['Content-MD5'] = OpensearchUtil.get_content_md5(req_body)
_request.body = req_body
if not UtilClient.is_unset(security_token):
_request.headers["X-Opensearch-Security-Token"] = security_token
_request.headers['Authorization'] = OpensearchUtil.get_signature(_request, accesskey_id,
access_key_secret)
_last_request = _request
_response = TeaCore.do_action(_request, _runtime)
obj_str = UtilClient.read_as_string(_response.body)
if UtilClient.is_4xx(_response.status_code) or UtilClient.is_5xx(_response.status_code):
raise TeaException({
'message': _response.status_message,
'data': obj_str,
'code': _response.status_code
})
obj = UtilClient.parse_json(obj_str)
res = UtilClient.assert_as_map(obj)
return {
'body': res,
'headers': _response.headers
}
except TeaException as e:
if TeaCore.is_retryable(e):
_last_exception = e
continue
raise e
raise UnretryableException(_last_request, _last_exception)Initialize the client
Construct a Config object and pass it to Client. Read your AccessKey ID and AccessKey secret from environment variables rather than hardcoding them in source code.
config = Config(
endpoint='<your-endpoint>', # e.g., opensearch-cn-hangzhou.aliyuncs.com
protocol='HTTP',
access_key_id='<your-access-key-id>',
access_key_secret='<your-access-key-secret>',
)
client = Client(config)Replace <your-endpoint> with your instance endpoint. If you omit the endpoint, the client defaults to opensearch-cn-hangzhou.aliyuncs.com.
Key parameters
Config parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
endpoint | str | No | Instance endpoint. Defaults to opensearch-cn-hangzhou.aliyuncs.com. |
protocol | str | No | Request protocol. Defaults to HTTP. |
type | str | No | Credential type. Defaults to access_key. |
access_key_id | str | Yes | AccessKey ID. |
access_key_secret | str | Yes | AccessKey secret. |
security_token | str | No | Security token, required when using temporary credentials. |
user_agent | str | No | Custom user agent string. Defaults to an empty string. |
RuntimeOptions parameters
| Parameter | Type | Description |
|---|---|---|
read_timeout | int | Read timeout. |
connect_timeout | int | Connect timeout. |
http_proxy | str | HTTP proxy URL. |
https_proxy | str | HTTPS proxy URL. |
no_proxy | str | Hosts to bypass the proxy. |
max_idle_conns | int | Maximum number of idle connections. |
autoretry | bool | Whether to enable automatic retries. |
max_attempts | int | Maximum retry attempts. Defaults to 3. |
backoff_policy | str | Backoff policy. Defaults to no. |
backoff_period | int | Backoff period. Defaults to 1. |
ignore_ssl | bool | Whether to skip SSL verification. |
Error handling
The client raises two exception types:
| Exception | When raised |
|---|---|
TeaException | 4xx or 5xx HTTP status code; also raised when config is unset (ParameterMissing) |
UnretryableException | All retry attempts exhausted |
On retryable errors, the client retries up to max_attempts times (default: 3) with the configured backoff policy before raising UnretryableException.