dominus-sdk-python 2.1.2__tar.gz → 2.1.4__tar.gz
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.
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/PKG-INFO +1 -1
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/helpers/core.py +77 -23
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/portal.py +20 -15
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus_sdk_python.egg-info/PKG-INFO +1 -1
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/pyproject.toml +1 -1
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/README.md +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/__init__.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/config/__init__.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/config/endpoints.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/errors.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/helpers/__init__.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/helpers/auth.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/helpers/cache.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/helpers/crypto.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/__init__.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/_deprecated_crossover.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/_deprecated_sql.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/auth.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/courier.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/db.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/ddl.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/files.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/health.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/logs.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/open.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/redis.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/secrets.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/services/__init__.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/services/_deprecated_architect.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/services/_deprecated_sovereign.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/start.py +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus_sdk_python.egg-info/SOURCES.txt +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus_sdk_python.egg-info/dependency_links.txt +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus_sdk_python.egg-info/requires.txt +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus_sdk_python.egg-info/top_level.txt +0 -0
- {dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/setup.cfg +0 -0
|
@@ -64,6 +64,7 @@ async def _get_service_jwt(psk_token: str, base_url: str) -> str:
|
|
|
64
64
|
Get service JWT by calling /api/warden/mint with PSK.
|
|
65
65
|
|
|
66
66
|
Uses circuit breaker to prevent retry storms during service outages.
|
|
67
|
+
Retries on 401/5xx with exponential backoff (orchestrator cold start handling).
|
|
67
68
|
|
|
68
69
|
Args:
|
|
69
70
|
psk_token: PSK token (DOMINUS_TOKEN)
|
|
@@ -73,7 +74,7 @@ async def _get_service_jwt(psk_token: str, base_url: str) -> str:
|
|
|
73
74
|
JWT token string
|
|
74
75
|
|
|
75
76
|
Raises:
|
|
76
|
-
RuntimeError: If circuit is open or auth fails
|
|
77
|
+
RuntimeError: If circuit is open or auth fails after retries
|
|
77
78
|
"""
|
|
78
79
|
# Circuit breaker check
|
|
79
80
|
if not sovereign_circuit_breaker.can_execute():
|
|
@@ -94,32 +95,85 @@ async def _get_service_jwt(psk_token: str, base_url: str) -> str:
|
|
|
94
95
|
body_json = {"method": "auth.self", "params": {}}
|
|
95
96
|
body_b64 = _b64_encode(body_json)
|
|
96
97
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
response.raise_for_status()
|
|
98
|
+
# Retry loop for JWT minting (handles orchestrator cold start)
|
|
99
|
+
JWT_MINT_RETRIES = 3
|
|
100
|
+
last_error = None
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
for attempt in range(JWT_MINT_RETRIES):
|
|
103
|
+
try:
|
|
104
|
+
async with httpx.AsyncClient(base_url=base_url, headers=headers, timeout=30.0) as client:
|
|
105
|
+
response = await client.post("/api/warden/mint", content=body_b64)
|
|
106
|
+
|
|
107
|
+
# Check for retryable status codes before raise_for_status
|
|
108
|
+
if response.status_code == 401 or response.status_code >= 500:
|
|
109
|
+
if attempt < JWT_MINT_RETRIES - 1:
|
|
110
|
+
delay = exponential_backoff_with_jitter(attempt, base_delay=2.0, max_delay=10.0)
|
|
111
|
+
print(
|
|
112
|
+
f"[Dominus] JWT mint returned {response.status_code}, "
|
|
113
|
+
f"retrying in {delay:.1f}s (attempt {attempt + 1}/{JWT_MINT_RETRIES})"
|
|
114
|
+
)
|
|
115
|
+
await asyncio.sleep(delay)
|
|
116
|
+
continue
|
|
117
|
+
|
|
118
|
+
response.raise_for_status()
|
|
119
|
+
|
|
120
|
+
# Decode base64 response
|
|
121
|
+
result = _b64_decode(response.text)
|
|
104
122
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
123
|
+
if not result.get("success"):
|
|
124
|
+
error_msg = result.get("error", "Unknown auth error")
|
|
125
|
+
sovereign_circuit_breaker.record_failure()
|
|
126
|
+
raise RuntimeError(f"Auth error: {error_msg}")
|
|
127
|
+
|
|
128
|
+
data = result.get("data", {})
|
|
129
|
+
jwt = data.get("access_token") or data.get("token")
|
|
130
|
+
if not jwt:
|
|
131
|
+
sovereign_circuit_breaker.record_failure()
|
|
132
|
+
raise RuntimeError("No JWT token in auth response")
|
|
133
|
+
|
|
134
|
+
# Success - record it
|
|
135
|
+
sovereign_circuit_breaker.record_success()
|
|
136
|
+
return jwt
|
|
137
|
+
|
|
138
|
+
except httpx.TimeoutException as e:
|
|
139
|
+
last_error = e
|
|
140
|
+
if attempt < JWT_MINT_RETRIES - 1:
|
|
141
|
+
delay = exponential_backoff_with_jitter(attempt, base_delay=2.0, max_delay=10.0)
|
|
142
|
+
print(
|
|
143
|
+
f"[Dominus] JWT mint timed out, "
|
|
144
|
+
f"retrying in {delay:.1f}s (attempt {attempt + 1}/{JWT_MINT_RETRIES})"
|
|
145
|
+
)
|
|
146
|
+
await asyncio.sleep(delay)
|
|
147
|
+
continue
|
|
148
|
+
sovereign_circuit_breaker.record_failure()
|
|
149
|
+
raise RuntimeError(f"Failed to get JWT: {e}") from e
|
|
150
|
+
|
|
151
|
+
except httpx.NetworkError as e:
|
|
152
|
+
last_error = e
|
|
153
|
+
if attempt < JWT_MINT_RETRIES - 1:
|
|
154
|
+
delay = exponential_backoff_with_jitter(attempt, base_delay=2.0, max_delay=10.0)
|
|
155
|
+
print(
|
|
156
|
+
f"[Dominus] JWT mint network error ({e}), "
|
|
157
|
+
f"retrying in {delay:.1f}s (attempt {attempt + 1}/{JWT_MINT_RETRIES})"
|
|
158
|
+
)
|
|
159
|
+
await asyncio.sleep(delay)
|
|
160
|
+
continue
|
|
161
|
+
sovereign_circuit_breaker.record_failure()
|
|
162
|
+
raise RuntimeError(f"Failed to get JWT: {e}") from e
|
|
109
163
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
164
|
+
except httpx.HTTPStatusError as e:
|
|
165
|
+
last_error = e
|
|
166
|
+
# 4xx errors (except 401 which is retried above) should not be retried
|
|
167
|
+
if 400 <= e.response.status_code < 500 and e.response.status_code != 401:
|
|
113
168
|
sovereign_circuit_breaker.record_failure()
|
|
114
|
-
raise RuntimeError("
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
raise RuntimeError(f"Failed to get JWT: {e}") from e
|
|
169
|
+
raise RuntimeError(f"Failed to get JWT: {e}") from e
|
|
170
|
+
# For other errors, we've already handled retries in the status check above
|
|
171
|
+
sovereign_circuit_breaker.record_failure()
|
|
172
|
+
raise RuntimeError(f"Failed to get JWT: {e}") from e
|
|
173
|
+
|
|
174
|
+
# Should not reach here, but just in case
|
|
175
|
+
sovereign_circuit_breaker.record_failure()
|
|
176
|
+
raise RuntimeError(f"Failed to get JWT after {JWT_MINT_RETRIES} retries: {last_error}")
|
|
123
177
|
|
|
124
178
|
|
|
125
179
|
def _get_architect_url(psk_token: str = None, sovereign_url: str = None, environment: str = None) -> str:
|
|
@@ -45,7 +45,7 @@ class PortalNamespace:
|
|
|
45
45
|
self,
|
|
46
46
|
username: str,
|
|
47
47
|
password: str,
|
|
48
|
-
tenant_id: str
|
|
48
|
+
tenant_id: Optional[str] = None
|
|
49
49
|
) -> Dict[str, Any]:
|
|
50
50
|
"""
|
|
51
51
|
Login user with password.
|
|
@@ -53,25 +53,28 @@ class PortalNamespace:
|
|
|
53
53
|
Args:
|
|
54
54
|
username: Username or email
|
|
55
55
|
password: User password
|
|
56
|
-
tenant_id:
|
|
56
|
+
tenant_id: Optional tenant UUID/slug. If not provided, uses user's first available tenant.
|
|
57
57
|
|
|
58
58
|
Returns:
|
|
59
|
-
Dict with user info, tenant
|
|
59
|
+
Dict with user info, active tenant, available tenants list, and session_id
|
|
60
60
|
"""
|
|
61
|
+
body: Dict[str, str] = {
|
|
62
|
+
"username": username,
|
|
63
|
+
"password": password
|
|
64
|
+
}
|
|
65
|
+
if tenant_id:
|
|
66
|
+
body["tenant_id"] = tenant_id
|
|
67
|
+
|
|
61
68
|
return await self._client._request(
|
|
62
69
|
endpoint="/api/portal/auth/login",
|
|
63
|
-
body=
|
|
64
|
-
"username": username,
|
|
65
|
-
"password": password,
|
|
66
|
-
"tenant_id": tenant_id
|
|
67
|
-
}
|
|
70
|
+
body=body
|
|
68
71
|
)
|
|
69
72
|
|
|
70
73
|
async def login_client(
|
|
71
74
|
self,
|
|
72
75
|
client_id: str,
|
|
73
76
|
psk: str,
|
|
74
|
-
tenant_id: str
|
|
77
|
+
tenant_id: Optional[str] = None
|
|
75
78
|
) -> Dict[str, Any]:
|
|
76
79
|
"""
|
|
77
80
|
Login service client with PSK.
|
|
@@ -79,18 +82,20 @@ class PortalNamespace:
|
|
|
79
82
|
Args:
|
|
80
83
|
client_id: Client UUID
|
|
81
84
|
psk: Pre-shared key
|
|
82
|
-
tenant_id:
|
|
85
|
+
tenant_id: Optional tenant UUID. If not provided, uses client's first assigned tenant.
|
|
83
86
|
|
|
84
87
|
Returns:
|
|
85
88
|
Dict with access_token, token_type, expires_in, session_id
|
|
86
89
|
"""
|
|
90
|
+
body: Dict[str, str] = {
|
|
91
|
+
"client_id": client_id,
|
|
92
|
+
"psk": psk
|
|
93
|
+
}
|
|
94
|
+
if tenant_id:
|
|
95
|
+
body["tenant_id"] = tenant_id
|
|
87
96
|
return await self._client._request(
|
|
88
97
|
endpoint="/api/portal/auth/login-client",
|
|
89
|
-
body=
|
|
90
|
-
"client_id": client_id,
|
|
91
|
-
"psk": psk,
|
|
92
|
-
"tenant_id": tenant_id
|
|
93
|
-
}
|
|
98
|
+
body=body
|
|
94
99
|
)
|
|
95
100
|
|
|
96
101
|
async def logout(self) -> Dict[str, Any]:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/namespaces/_deprecated_crossover.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/services/_deprecated_architect.py
RENAMED
|
File without changes
|
{dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus/services/_deprecated_sovereign.py
RENAMED
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus_sdk_python.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus_sdk_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{dominus_sdk_python-2.1.2 → dominus_sdk_python-2.1.4}/dominus_sdk_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|