stackit-ufw 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,151 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ STACKIT Unified Firewall API
5
+
6
+ API for managing and controlling the STACKIT Unified Firewall.
7
+
8
+ The version of the OpenAPI document: 1.0.0
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import pprint
18
+ from typing import Any, ClassVar, Dict, List, Optional, Set
19
+
20
+ from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr, field_validator
21
+ from pydantic_core import to_jsonable_python
22
+ from typing_extensions import Self
23
+
24
+
25
+ class RuleResponse(BaseModel):
26
+ """
27
+ RuleResponse
28
+ """ # noqa: E501
29
+
30
+ description: Optional[StrictStr] = None
31
+ destination: StrictStr
32
+ direction: Optional[StrictStr] = None
33
+ error_message: Optional[StrictStr] = Field(default=None, alias="errorMessage")
34
+ ether_type: Optional[StrictStr] = Field(default=None, alias="etherType")
35
+ instance_id: StrictStr = Field(alias="instanceId")
36
+ instance_name: Optional[StrictStr] = Field(default=None, alias="instanceName")
37
+ ip_range: Optional[StrictStr] = Field(default=None, alias="ipRange")
38
+ offset: Optional[StrictInt] = None
39
+ port_range: Optional[StrictStr] = Field(default=None, alias="portRange")
40
+ product: StrictStr
41
+ protocol: Optional[StrictStr] = None
42
+ region: Optional[StrictStr] = None
43
+ remote_security_group_id: Optional[StrictStr] = Field(default=None, alias="remoteSecurityGroupId")
44
+ security_group: Optional[StrictStr] = Field(default=None, alias="securityGroup")
45
+ security_group_id: Optional[StrictStr] = Field(default=None, alias="securityGroupId")
46
+ source_ip: StrictStr = Field(alias="sourceIP")
47
+ status: StrictStr = Field(description="The current state of the resource.")
48
+ type: StrictStr
49
+ __properties: ClassVar[List[str]] = [
50
+ "description",
51
+ "destination",
52
+ "direction",
53
+ "errorMessage",
54
+ "etherType",
55
+ "instanceId",
56
+ "instanceName",
57
+ "ipRange",
58
+ "offset",
59
+ "portRange",
60
+ "product",
61
+ "protocol",
62
+ "region",
63
+ "remoteSecurityGroupId",
64
+ "securityGroup",
65
+ "securityGroupId",
66
+ "sourceIP",
67
+ "status",
68
+ "type",
69
+ ]
70
+
71
+ @field_validator("status")
72
+ def status_validate_enum(cls, value):
73
+ """Validates the enum"""
74
+ if value not in set(["Active", "Error", "Pending", "Updating", "Deleting", "Creating"]):
75
+ raise ValueError(
76
+ "must be one of enum values ('Active', 'Error', 'Pending', 'Updating', 'Deleting', 'Creating')"
77
+ )
78
+ return value
79
+
80
+ model_config = ConfigDict(
81
+ validate_by_name=True,
82
+ validate_by_alias=True,
83
+ validate_assignment=True,
84
+ protected_namespaces=(),
85
+ )
86
+
87
+ def to_str(self) -> str:
88
+ """Returns the string representation of the model using alias"""
89
+ return pprint.pformat(self.model_dump(by_alias=True))
90
+
91
+ def to_json(self) -> str:
92
+ """Returns the JSON representation of the model using alias"""
93
+ return json.dumps(to_jsonable_python(self.to_dict()))
94
+
95
+ @classmethod
96
+ def from_json(cls, json_str: str) -> Optional[Self]:
97
+ """Create an instance of RuleResponse from a JSON string"""
98
+ return cls.from_dict(json.loads(json_str))
99
+
100
+ def to_dict(self) -> Dict[str, Any]:
101
+ """Return the dictionary representation of the model using alias.
102
+
103
+ This has the following differences from calling pydantic's
104
+ `self.model_dump(by_alias=True)`:
105
+
106
+ * `None` is only added to the output dict for nullable fields that
107
+ were set at model initialization. Other fields with value `None`
108
+ are ignored.
109
+ """
110
+ excluded_fields: Set[str] = set([])
111
+
112
+ _dict = self.model_dump(
113
+ by_alias=True,
114
+ exclude=excluded_fields,
115
+ exclude_none=True,
116
+ )
117
+ return _dict
118
+
119
+ @classmethod
120
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
121
+ """Create an instance of RuleResponse from a dict"""
122
+ if obj is None:
123
+ return None
124
+
125
+ if not isinstance(obj, dict):
126
+ return cls.model_validate(obj)
127
+
128
+ _obj = cls.model_validate(
129
+ {
130
+ "description": obj.get("description"),
131
+ "destination": obj.get("destination"),
132
+ "direction": obj.get("direction"),
133
+ "errorMessage": obj.get("errorMessage"),
134
+ "etherType": obj.get("etherType"),
135
+ "instanceId": obj.get("instanceId"),
136
+ "instanceName": obj.get("instanceName"),
137
+ "ipRange": obj.get("ipRange"),
138
+ "offset": obj.get("offset"),
139
+ "portRange": obj.get("portRange"),
140
+ "product": obj.get("product"),
141
+ "protocol": obj.get("protocol"),
142
+ "region": obj.get("region"),
143
+ "remoteSecurityGroupId": obj.get("remoteSecurityGroupId"),
144
+ "securityGroup": obj.get("securityGroup"),
145
+ "securityGroupId": obj.get("securityGroupId"),
146
+ "sourceIP": obj.get("sourceIP"),
147
+ "status": obj.get("status"),
148
+ "type": obj.get("type"),
149
+ }
150
+ )
151
+ return _obj
@@ -0,0 +1,113 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ STACKIT Unified Firewall API
5
+
6
+ API for managing and controlling the STACKIT Unified Firewall.
7
+
8
+ The version of the OpenAPI document: 1.0.0
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import pprint
18
+ from typing import Any, ClassVar, Dict, List, Optional, Set
19
+
20
+ from pydantic import BaseModel, ConfigDict, Field, StrictStr
21
+ from pydantic_core import to_jsonable_python
22
+ from typing_extensions import Self
23
+
24
+
25
+ class UpdateRulePayload(BaseModel):
26
+ """
27
+ The request body for updating a security rule.
28
+ """ # noqa: E501
29
+
30
+ direction: Optional[StrictStr] = Field(
31
+ default=None, description='The direction of the traffic, typically "ingress" or "egress".'
32
+ )
33
+ ether_type: Optional[StrictStr] = Field(
34
+ default=None, description="Specifies the bound of the rule.", alias="etherType"
35
+ )
36
+ port_range: Optional[StrictStr] = Field(
37
+ default=None, description="The Port range to which the rule applies.", alias="portRange"
38
+ )
39
+ protocol: Optional[StrictStr] = Field(
40
+ default=None, description='The network protocol (e.g., "TCP", "UDP", "ICMP").'
41
+ )
42
+ security_group_id: Optional[StrictStr] = Field(
43
+ default=None, description="The ID of the Group.", alias="securityGroupId"
44
+ )
45
+ source_ip: StrictStr = Field(description="The IP (CIDR) to which the rule applies.", alias="sourceIP")
46
+ __properties: ClassVar[List[str]] = [
47
+ "direction",
48
+ "etherType",
49
+ "portRange",
50
+ "protocol",
51
+ "securityGroupId",
52
+ "sourceIP",
53
+ ]
54
+
55
+ model_config = ConfigDict(
56
+ validate_by_name=True,
57
+ validate_by_alias=True,
58
+ validate_assignment=True,
59
+ protected_namespaces=(),
60
+ )
61
+
62
+ def to_str(self) -> str:
63
+ """Returns the string representation of the model using alias"""
64
+ return pprint.pformat(self.model_dump(by_alias=True))
65
+
66
+ def to_json(self) -> str:
67
+ """Returns the JSON representation of the model using alias"""
68
+ return json.dumps(to_jsonable_python(self.to_dict()))
69
+
70
+ @classmethod
71
+ def from_json(cls, json_str: str) -> Optional[Self]:
72
+ """Create an instance of UpdateRulePayload from a JSON string"""
73
+ return cls.from_dict(json.loads(json_str))
74
+
75
+ def to_dict(self) -> Dict[str, Any]:
76
+ """Return the dictionary representation of the model using alias.
77
+
78
+ This has the following differences from calling pydantic's
79
+ `self.model_dump(by_alias=True)`:
80
+
81
+ * `None` is only added to the output dict for nullable fields that
82
+ were set at model initialization. Other fields with value `None`
83
+ are ignored.
84
+ """
85
+ excluded_fields: Set[str] = set([])
86
+
87
+ _dict = self.model_dump(
88
+ by_alias=True,
89
+ exclude=excluded_fields,
90
+ exclude_none=True,
91
+ )
92
+ return _dict
93
+
94
+ @classmethod
95
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
96
+ """Create an instance of UpdateRulePayload from a dict"""
97
+ if obj is None:
98
+ return None
99
+
100
+ if not isinstance(obj, dict):
101
+ return cls.model_validate(obj)
102
+
103
+ _obj = cls.model_validate(
104
+ {
105
+ "direction": obj.get("direction"),
106
+ "etherType": obj.get("etherType"),
107
+ "portRange": obj.get("portRange"),
108
+ "protocol": obj.get("protocol"),
109
+ "securityGroupId": obj.get("securityGroupId"),
110
+ "sourceIP": obj.get("sourceIP"),
111
+ }
112
+ )
113
+ return _obj
@@ -0,0 +1,84 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ STACKIT Unified Firewall API
5
+
6
+ API for managing and controlling the STACKIT Unified Firewall.
7
+
8
+ The version of the OpenAPI document: 1.0.0
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import pprint
18
+ from typing import Any, ClassVar, Dict, List, Optional, Set
19
+
20
+ from pydantic import BaseModel, ConfigDict, Field, StrictStr
21
+ from pydantic_core import to_jsonable_python
22
+ from typing_extensions import Self
23
+
24
+
25
+ class UpdateRuleResponse(BaseModel):
26
+ """
27
+ UpdateRuleResponse
28
+ """ # noqa: E501
29
+
30
+ ref_id: Optional[StrictStr] = Field(
31
+ default=None, description="Represents the uuid of the updated rule", alias="refId"
32
+ )
33
+ __properties: ClassVar[List[str]] = ["refId"]
34
+
35
+ model_config = ConfigDict(
36
+ validate_by_name=True,
37
+ validate_by_alias=True,
38
+ validate_assignment=True,
39
+ protected_namespaces=(),
40
+ )
41
+
42
+ def to_str(self) -> str:
43
+ """Returns the string representation of the model using alias"""
44
+ return pprint.pformat(self.model_dump(by_alias=True))
45
+
46
+ def to_json(self) -> str:
47
+ """Returns the JSON representation of the model using alias"""
48
+ return json.dumps(to_jsonable_python(self.to_dict()))
49
+
50
+ @classmethod
51
+ def from_json(cls, json_str: str) -> Optional[Self]:
52
+ """Create an instance of UpdateRuleResponse from a JSON string"""
53
+ return cls.from_dict(json.loads(json_str))
54
+
55
+ def to_dict(self) -> Dict[str, Any]:
56
+ """Return the dictionary representation of the model using alias.
57
+
58
+ This has the following differences from calling pydantic's
59
+ `self.model_dump(by_alias=True)`:
60
+
61
+ * `None` is only added to the output dict for nullable fields that
62
+ were set at model initialization. Other fields with value `None`
63
+ are ignored.
64
+ """
65
+ excluded_fields: Set[str] = set([])
66
+
67
+ _dict = self.model_dump(
68
+ by_alias=True,
69
+ exclude=excluded_fields,
70
+ exclude_none=True,
71
+ )
72
+ return _dict
73
+
74
+ @classmethod
75
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
76
+ """Create an instance of UpdateRuleResponse from a dict"""
77
+ if obj is None:
78
+ return None
79
+
80
+ if not isinstance(obj, dict):
81
+ return cls.model_validate(obj)
82
+
83
+ _obj = cls.model_validate({"refId": obj.get("refId")})
84
+ return _obj
@@ -0,0 +1,84 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ STACKIT Unified Firewall API
5
+
6
+ API for managing and controlling the STACKIT Unified Firewall.
7
+
8
+ The version of the OpenAPI document: 1.0.0
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import pprint
18
+ from typing import Any, ClassVar, Dict, List, Optional, Set
19
+
20
+ from pydantic import BaseModel, ConfigDict, Field, StrictStr
21
+ from pydantic_core import to_jsonable_python
22
+ from typing_extensions import Annotated, Self
23
+
24
+
25
+ class UpdateUfwRequest(BaseModel):
26
+ """
27
+ UpdateUfwRequest
28
+ """ # noqa: E501
29
+
30
+ cidrs: Annotated[List[StrictStr], Field(max_length=128)] = Field(
31
+ description="The list of CIDRs currently set on the instance."
32
+ )
33
+ __properties: ClassVar[List[str]] = ["cidrs"]
34
+
35
+ model_config = ConfigDict(
36
+ validate_by_name=True,
37
+ validate_by_alias=True,
38
+ validate_assignment=True,
39
+ protected_namespaces=(),
40
+ )
41
+
42
+ def to_str(self) -> str:
43
+ """Returns the string representation of the model using alias"""
44
+ return pprint.pformat(self.model_dump(by_alias=True))
45
+
46
+ def to_json(self) -> str:
47
+ """Returns the JSON representation of the model using alias"""
48
+ return json.dumps(to_jsonable_python(self.to_dict()))
49
+
50
+ @classmethod
51
+ def from_json(cls, json_str: str) -> Optional[Self]:
52
+ """Create an instance of UpdateUfwRequest from a JSON string"""
53
+ return cls.from_dict(json.loads(json_str))
54
+
55
+ def to_dict(self) -> Dict[str, Any]:
56
+ """Return the dictionary representation of the model using alias.
57
+
58
+ This has the following differences from calling pydantic's
59
+ `self.model_dump(by_alias=True)`:
60
+
61
+ * `None` is only added to the output dict for nullable fields that
62
+ were set at model initialization. Other fields with value `None`
63
+ are ignored.
64
+ """
65
+ excluded_fields: Set[str] = set([])
66
+
67
+ _dict = self.model_dump(
68
+ by_alias=True,
69
+ exclude=excluded_fields,
70
+ exclude_none=True,
71
+ )
72
+ return _dict
73
+
74
+ @classmethod
75
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
76
+ """Create an instance of UpdateUfwRequest from a dict"""
77
+ if obj is None:
78
+ return None
79
+
80
+ if not isinstance(obj, dict):
81
+ return cls.model_validate(obj)
82
+
83
+ _obj = cls.model_validate({"cidrs": obj.get("cidrs")})
84
+ return _obj
@@ -0,0 +1,83 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ STACKIT Unified Firewall API
5
+
6
+ API for managing and controlling the STACKIT Unified Firewall.
7
+
8
+ The version of the OpenAPI document: 1.0.0
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import pprint
18
+ from typing import Any, ClassVar, Dict, List, Optional, Set
19
+
20
+ from pydantic import BaseModel, ConfigDict, StrictStr
21
+ from pydantic_core import to_jsonable_python
22
+ from typing_extensions import Self
23
+
24
+
25
+ class VersionResponse(BaseModel):
26
+ """
27
+ VersionResponse
28
+ """ # noqa: E501
29
+
30
+ name: Optional[StrictStr] = None
31
+ version: Optional[StrictStr] = None
32
+ __properties: ClassVar[List[str]] = ["name", "version"]
33
+
34
+ model_config = ConfigDict(
35
+ validate_by_name=True,
36
+ validate_by_alias=True,
37
+ validate_assignment=True,
38
+ protected_namespaces=(),
39
+ )
40
+
41
+ def to_str(self) -> str:
42
+ """Returns the string representation of the model using alias"""
43
+ return pprint.pformat(self.model_dump(by_alias=True))
44
+
45
+ def to_json(self) -> str:
46
+ """Returns the JSON representation of the model using alias"""
47
+ return json.dumps(to_jsonable_python(self.to_dict()))
48
+
49
+ @classmethod
50
+ def from_json(cls, json_str: str) -> Optional[Self]:
51
+ """Create an instance of VersionResponse from a JSON string"""
52
+ return cls.from_dict(json.loads(json_str))
53
+
54
+ def to_dict(self) -> Dict[str, Any]:
55
+ """Return the dictionary representation of the model using alias.
56
+
57
+ This has the following differences from calling pydantic's
58
+ `self.model_dump(by_alias=True)`:
59
+
60
+ * `None` is only added to the output dict for nullable fields that
61
+ were set at model initialization. Other fields with value `None`
62
+ are ignored.
63
+ """
64
+ excluded_fields: Set[str] = set([])
65
+
66
+ _dict = self.model_dump(
67
+ by_alias=True,
68
+ exclude=excluded_fields,
69
+ exclude_none=True,
70
+ )
71
+ return _dict
72
+
73
+ @classmethod
74
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
75
+ """Create an instance of VersionResponse from a dict"""
76
+ if obj is None:
77
+ return None
78
+
79
+ if not isinstance(obj, dict):
80
+ return cls.model_validate(obj)
81
+
82
+ _obj = cls.model_validate({"name": obj.get("name"), "version": obj.get("version")})
83
+ return _obj
stackit/ufw/py.typed ADDED
File without changes
stackit/ufw/rest.py ADDED
@@ -0,0 +1,163 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ STACKIT Unified Firewall API
5
+
6
+ API for managing and controlling the STACKIT Unified Firewall.
7
+
8
+ The version of the OpenAPI document: 1.0.0
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+ import io
15
+ import json
16
+ import re
17
+
18
+ import requests
19
+ from stackit.core.authorization import Authorization
20
+ from stackit.core.configuration import Configuration
21
+
22
+ from stackit.ufw.exceptions import ApiException, ApiValueError
23
+
24
+ RESTResponseType = requests.Response
25
+
26
+
27
+ class RESTResponse(io.IOBase):
28
+
29
+ def __init__(self, resp) -> None:
30
+ self.response = resp
31
+ self.status = resp.status_code
32
+ self.reason = resp.reason
33
+ self.data = None
34
+
35
+ def read(self):
36
+ if self.data is None:
37
+ self.data = self.response.content
38
+ return self.data
39
+
40
+ @property
41
+ def headers(self):
42
+ """Returns a dictionary of response headers."""
43
+ return self.response.headers
44
+
45
+ def getheaders(self):
46
+ """Returns a dictionary of the response headers; use ``headers`` instead."""
47
+ return self.response.headers
48
+
49
+ def getheader(self, name, default=None):
50
+ """Returns a given response header; use ``headers.get()`` instead."""
51
+ return self.response.headers.get(name, default)
52
+
53
+
54
+ class RESTClientObject:
55
+ def __init__(self, config: Configuration) -> None:
56
+ self.session = config.custom_http_session if config.custom_http_session else requests.Session()
57
+ authorization = Authorization(config)
58
+ self.session.auth = authorization.auth_method
59
+
60
+ def request(self, method, url, headers=None, body=None, post_params=None, _request_timeout=None):
61
+ """Perform requests.
62
+
63
+ :param method: http request method
64
+ :param url: http request url
65
+ :param headers: http request headers
66
+ :param body: request json body, for `application/json`
67
+ :param post_params: request post parameters,
68
+ `application/x-www-form-urlencoded`
69
+ and `multipart/form-data`
70
+ :param _request_timeout: timeout setting for this request. If one
71
+ number provided, it will be total request
72
+ timeout. It can also be a pair (tuple) of
73
+ (connection, read) timeouts.
74
+ """
75
+ method = method.upper()
76
+ if method not in ["GET", "HEAD", "DELETE", "POST", "PUT", "PATCH", "OPTIONS"]:
77
+ raise ValueError("Method %s not allowed", method)
78
+
79
+ if post_params and body:
80
+ raise ApiValueError("body parameter cannot be used with post_params parameter.")
81
+
82
+ post_params = post_params or {}
83
+ headers = headers or {}
84
+
85
+ try:
86
+ # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`
87
+ if method in ["POST", "PUT", "PATCH", "OPTIONS", "DELETE"]:
88
+
89
+ # no content type provided or payload is json
90
+ content_type = headers.get("Content-Type")
91
+ if not content_type or re.search("json", content_type, re.IGNORECASE):
92
+ request_body = None
93
+ if body is not None:
94
+ request_body = json.dumps(body)
95
+ r = self.session.request(
96
+ method,
97
+ url,
98
+ data=request_body,
99
+ headers=headers,
100
+ timeout=_request_timeout,
101
+ )
102
+ elif content_type == "application/x-www-form-urlencoded":
103
+ r = self.session.request(
104
+ method,
105
+ url,
106
+ params=post_params,
107
+ headers=headers,
108
+ timeout=_request_timeout,
109
+ )
110
+ elif content_type == "multipart/form-data":
111
+ # must del headers['Content-Type'], or the correct
112
+ # Content-Type which generated by urllib3 will be
113
+ # overwritten.
114
+ del headers["Content-Type"]
115
+ # Ensures that dict objects are serialized
116
+ post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a, b) for a, b in post_params]
117
+ r = self.session.request(
118
+ method,
119
+ url,
120
+ files=post_params,
121
+ headers=headers,
122
+ timeout=_request_timeout,
123
+ )
124
+ # Pass a `string` parameter directly in the body to support
125
+ # other content types than JSON when `body` argument is
126
+ # provided in serialized form.
127
+ elif isinstance(body, str) or isinstance(body, bytes):
128
+ r = self.session.request(
129
+ method,
130
+ url,
131
+ data=body,
132
+ headers=headers,
133
+ timeout=_request_timeout,
134
+ )
135
+ elif headers["Content-Type"].startswith("text/") and isinstance(body, bool):
136
+ request_body = "true" if body else "false"
137
+ r = self.session.request(
138
+ method,
139
+ url,
140
+ data=request_body,
141
+ headers=headers,
142
+ timeout=_request_timeout,
143
+ )
144
+ else:
145
+ # Cannot generate the request from given parameters
146
+ msg = """Cannot prepare a request message for provided
147
+ arguments. Please check that your arguments match
148
+ declared content type."""
149
+ raise ApiException(status=0, reason=msg)
150
+ # For `GET`, `HEAD`
151
+ else:
152
+ r = self.session.request(
153
+ method,
154
+ url,
155
+ params={},
156
+ headers=headers,
157
+ timeout=_request_timeout,
158
+ )
159
+ except requests.exceptions.SSLError as e:
160
+ msg = "\n".join([type(e).__name__, str(e)])
161
+ raise ApiException(status=0, reason=msg)
162
+
163
+ return RESTResponse(r)