zscaler-sdk-python 0.3.1__tar.gz → 0.4.0__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.
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/PKG-INFO +4 -4
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/pyproject.toml +6 -5
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/__init__.py +1 -1
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/constants.py +1 -1
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/__init__.py +63 -24
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/app_segments.py +157 -76
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/app_segments_inspection.py +45 -54
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/app_segments_pra.py +49 -59
- zscaler_sdk_python-0.4.0/zscaler/zpa/authdomains.py +41 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/certificates.py +90 -59
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/client.py +3 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/connectors.py +139 -88
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/emergency_access.py +16 -1
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/idp.py +18 -3
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/inspection.py +215 -227
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/machine_groups.py +24 -10
- zscaler_sdk_python-0.4.0/zscaler/zpa/microtenants.py +217 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/policies.py +242 -405
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/privileged_remote_access.py +48 -5
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/provisioning.py +35 -16
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/segment_groups.py +51 -41
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/server_groups.py +34 -12
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/servers.py +42 -22
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/service_edges.py +241 -61
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/trusted_networks.py +20 -5
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/LICENSE.md +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/README.md +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/cache/__init__.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/cache/cache.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/cache/no_op_cache.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/cache/zscaler_cache.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/errors/__init__.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/errors/error.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/errors/http_error.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/errors/zscaler_api_error.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/exceptions/__init__.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/exceptions/exceptions.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/logger.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/ratelimiter/__init__.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/ratelimiter/ratelimiter.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/user_agent.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/utils.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/__init__.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/activate.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/admin_and_role_management.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/apptotal.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/audit_logs.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/authentication_settings.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/client.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/cloud_apps.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/device_management.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/dlp.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/errors.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/firewall.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/forwarding_control.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/isolation_profile.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/labels.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/locations.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/sandbox.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/security.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/ssl_inspection.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/traffic.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/url_categories.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/url_filtering.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/users.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/web_dlp.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/workload_groups.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zia/zpa_gateway.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/README.md +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/cloud_connector_groups.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/errors.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/isolation.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/lss.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/posture_profiles.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/saml_attributes.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/scim_attributes.py +0 -0
- {zscaler_sdk_python-0.3.1 → zscaler_sdk_python-0.4.0}/zscaler/zpa/scim_groups.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: zscaler-sdk-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Official Python SDK for the Zscaler Products (Beta)
|
|
5
5
|
Home-page: https://github.com/zscaler/zscaler-sdk-python
|
|
6
6
|
License: MIT
|
|
@@ -24,9 +24,9 @@ Provides-Extra: dev
|
|
|
24
24
|
Requires-Dist: aenum ; extra == "dev"
|
|
25
25
|
Requires-Dist: arrow
|
|
26
26
|
Requires-Dist: black (>=24.3.0) ; extra == "dev"
|
|
27
|
-
Requires-Dist: certifi
|
|
27
|
+
Requires-Dist: certifi (>=2024.2.2)
|
|
28
28
|
Requires-Dist: charset-normalizer
|
|
29
|
-
Requires-Dist: cryptography (>=
|
|
29
|
+
Requires-Dist: cryptography (>=42.0.7)
|
|
30
30
|
Requires-Dist: flake8
|
|
31
31
|
Requires-Dist: flatdict
|
|
32
32
|
Requires-Dist: idna
|
|
@@ -38,7 +38,7 @@ Requires-Dist: python-dateutil
|
|
|
38
38
|
Requires-Dist: pytz
|
|
39
39
|
Requires-Dist: pyyaml
|
|
40
40
|
Requires-Dist: requests (>=2.32.0)
|
|
41
|
-
Requires-Dist: responses
|
|
41
|
+
Requires-Dist: responses (>=0.25.0)
|
|
42
42
|
Requires-Dist: restfly
|
|
43
43
|
Requires-Dist: six
|
|
44
44
|
Requires-Dist: xmltodict
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "zscaler-sdk-python"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.0"
|
|
4
4
|
description = "Official Python SDK for the Zscaler Products (Beta)"
|
|
5
5
|
authors = ["Zscaler, Inc. <devrel@zscaler.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -30,13 +30,13 @@ packages = [
|
|
|
30
30
|
[tool.poetry.dependencies]
|
|
31
31
|
python = ">=3.8,<4.0"
|
|
32
32
|
arrow = "*"
|
|
33
|
-
certifi = "
|
|
33
|
+
certifi = ">=2024.2.2"
|
|
34
34
|
charset-normalizer = "*"
|
|
35
35
|
idna = "*"
|
|
36
36
|
python-box = "^7.1.1"
|
|
37
37
|
python-dateutil = "*"
|
|
38
38
|
requests = ">=2.32.0"
|
|
39
|
-
responses = "
|
|
39
|
+
responses = ">=0.25.0"
|
|
40
40
|
restfly = "*"
|
|
41
41
|
six = "*"
|
|
42
42
|
flatdict = "*"
|
|
@@ -49,12 +49,13 @@ pydash = "*"
|
|
|
49
49
|
flake8 = "*"
|
|
50
50
|
pytz = "*"
|
|
51
51
|
black = ">=24.3.0"
|
|
52
|
-
cryptography = ">=3.4,<43.0"
|
|
52
|
+
# cryptography = ">=3.4,<43.0"
|
|
53
|
+
cryptography = ">=42.0.7"
|
|
53
54
|
okta = ">=2.9.7"
|
|
54
55
|
|
|
55
56
|
[tool.poetry.dev-dependencies]
|
|
56
57
|
black = ">=24.3.0"
|
|
57
|
-
pytest = "
|
|
58
|
+
pytest = ">=8.2.1"
|
|
58
59
|
pytest-asyncio = ">=0.23.7"
|
|
59
60
|
pytest-mock = "*"
|
|
60
61
|
pytest-recording = "*"
|
|
@@ -14,7 +14,7 @@ ZPA_BASE_URLS = {
|
|
|
14
14
|
|
|
15
15
|
DEV_AUTH_URL = "https://authn1.dev.zpath.net/authn/v1/oauth/token"
|
|
16
16
|
|
|
17
|
-
RETRYABLE_STATUS_CODES = {429, 500, 502, 503, 504}
|
|
17
|
+
RETRYABLE_STATUS_CODES = {409, 429, 500, 502, 503, 504}
|
|
18
18
|
MAX_RETRIES = 5
|
|
19
19
|
BACKOFF_FACTOR = 1
|
|
20
20
|
BACKOFF_BASE_DURATION = 2
|
|
@@ -26,6 +26,7 @@ from zscaler.utils import (
|
|
|
26
26
|
retry_with_backoff,
|
|
27
27
|
snake_to_camel,
|
|
28
28
|
)
|
|
29
|
+
from zscaler.zpa.authdomains import AuthDomainsAPI
|
|
29
30
|
from zscaler.zpa.app_segments import ApplicationSegmentAPI
|
|
30
31
|
from zscaler.zpa.app_segments_inspection import AppSegmentsInspectionAPI
|
|
31
32
|
from zscaler.zpa.app_segments_pra import AppSegmentsPRAAPI
|
|
@@ -39,6 +40,7 @@ from zscaler.zpa.inspection import InspectionControllerAPI
|
|
|
39
40
|
from zscaler.zpa.isolation import IsolationAPI
|
|
40
41
|
from zscaler.zpa.lss import LSSConfigControllerAPI
|
|
41
42
|
from zscaler.zpa.machine_groups import MachineGroupsAPI
|
|
43
|
+
from zscaler.zpa.microtenants import MicrotenantsAPI
|
|
42
44
|
from zscaler.zpa.policies import PolicySetsAPI
|
|
43
45
|
from zscaler.zpa.posture_profiles import PostureProfilesAPI
|
|
44
46
|
from zscaler.zpa.privileged_remote_access import PrivilegedRemoteAccessAPI
|
|
@@ -81,12 +83,12 @@ class ZPAClientHelper(ZPAClient):
|
|
|
81
83
|
client_secret,
|
|
82
84
|
customer_id,
|
|
83
85
|
cloud,
|
|
86
|
+
microtenant_id=None,
|
|
84
87
|
timeout=240,
|
|
85
88
|
cache=None,
|
|
86
89
|
fail_safe=False,
|
|
87
90
|
):
|
|
88
91
|
# Initialize rate limiter
|
|
89
|
-
# You may want to adjust these parameters as per your rate limit configuration
|
|
90
92
|
self.rate_limiter = RateLimiter(
|
|
91
93
|
get_limit=20, # Adjusted to allow 20 GET requests per 10 seconds
|
|
92
94
|
post_put_delete_limit=10, # Adjusted to allow 10 POST/PUT/DELETE requests per 10 seconds
|
|
@@ -94,7 +96,6 @@ class ZPAClientHelper(ZPAClient):
|
|
|
94
96
|
post_put_delete_freq=10, # Adjust frequency to 10 seconds
|
|
95
97
|
)
|
|
96
98
|
|
|
97
|
-
# Validate cloud value
|
|
98
99
|
if cloud not in ZPA_BASE_URLS:
|
|
99
100
|
valid_clouds = ", ".join(ZPA_BASE_URLS.keys())
|
|
100
101
|
raise ValueError(
|
|
@@ -102,15 +103,13 @@ class ZPAClientHelper(ZPAClient):
|
|
|
102
103
|
f"Please use one of the following supported values: {valid_clouds}"
|
|
103
104
|
)
|
|
104
105
|
|
|
105
|
-
# Continue with existing initialization...
|
|
106
|
-
# Select the appropriate URL
|
|
107
106
|
self.baseurl = ZPA_BASE_URLS.get(cloud, ZPA_BASE_URLS["PRODUCTION"])
|
|
108
|
-
|
|
109
107
|
self.timeout = timeout
|
|
110
108
|
self.client_id = client_id
|
|
111
109
|
self.client_secret = client_secret
|
|
112
110
|
self.customer_id = customer_id
|
|
113
111
|
self.cloud = cloud
|
|
112
|
+
self.microtenant_id = microtenant_id or os.getenv("ZPA_MICROTENANT_ID")
|
|
114
113
|
self.url = f"{self.baseurl}/mgmtconfig/v1/admin/customers/{customer_id}"
|
|
115
114
|
self.user_config_url = f"{self.baseurl}/userconfig/v1/customers/{customer_id}"
|
|
116
115
|
self.v2_url = f"{self.baseurl}/mgmtconfig/v2/admin/customers/{customer_id}"
|
|
@@ -118,7 +117,6 @@ class ZPAClientHelper(ZPAClient):
|
|
|
118
117
|
self.cbi_url = f"{self.baseurl}/cbiconfig/cbi/api/customers/{customer_id}"
|
|
119
118
|
self.fail_safe = fail_safe
|
|
120
119
|
|
|
121
|
-
# Cache setup
|
|
122
120
|
cache_enabled = os.environ.get("ZSCALER_CLIENT_CACHE_ENABLED", "true").lower() == "true"
|
|
123
121
|
if cache is None:
|
|
124
122
|
if cache_enabled:
|
|
@@ -130,7 +128,6 @@ class ZPAClientHelper(ZPAClient):
|
|
|
130
128
|
else:
|
|
131
129
|
self.cache = cache
|
|
132
130
|
|
|
133
|
-
# Initialize user-agent
|
|
134
131
|
ua = UserAgent()
|
|
135
132
|
self.user_agent = ua.get_user_agent_string()
|
|
136
133
|
self.access_token = None
|
|
@@ -184,20 +181,34 @@ class ZPAClientHelper(ZPAClient):
|
|
|
184
181
|
elif api_version == "cbiconfig_v1":
|
|
185
182
|
api = self.cbi_url
|
|
186
183
|
|
|
184
|
+
if params is None:
|
|
185
|
+
params = {}
|
|
186
|
+
|
|
187
|
+
if json and "microtenant_id" in json:
|
|
188
|
+
microtenant_id = json.pop("microtenant_id")
|
|
189
|
+
else:
|
|
190
|
+
microtenant_id = self.microtenant_id
|
|
191
|
+
|
|
192
|
+
if microtenant_id:
|
|
193
|
+
params["microtenantId"] = microtenant_id
|
|
194
|
+
|
|
187
195
|
url = f"{api}/{path.lstrip('/')}"
|
|
196
|
+
if params:
|
|
197
|
+
url = f"{url}?{urllib.parse.urlencode(params)}"
|
|
198
|
+
|
|
188
199
|
start_time = time.time()
|
|
189
200
|
headers_with_user_agent = self.headers.copy()
|
|
190
201
|
headers_with_user_agent["User-Agent"] = self.user_agent
|
|
191
202
|
request_uuid = uuid.uuid4()
|
|
192
|
-
dump_request(logger, url, method, json,
|
|
193
|
-
cache_key = self.cache.create_key(url,
|
|
203
|
+
dump_request(logger, url, method, json, None, headers_with_user_agent, request_uuid)
|
|
204
|
+
cache_key = self.cache.create_key(url, None)
|
|
194
205
|
if method == "GET" and self.cache.contains(cache_key):
|
|
195
206
|
resp = self.cache.get(cache_key)
|
|
196
207
|
dump_response(
|
|
197
208
|
logger=logger,
|
|
198
209
|
url=url,
|
|
199
210
|
method=method,
|
|
200
|
-
params=
|
|
211
|
+
params=None,
|
|
201
212
|
resp=resp,
|
|
202
213
|
request_uuid=request_uuid,
|
|
203
214
|
start_time=start_time,
|
|
@@ -217,13 +228,14 @@ class ZPAClientHelper(ZPAClient):
|
|
|
217
228
|
method,
|
|
218
229
|
url,
|
|
219
230
|
json=json,
|
|
231
|
+
params=None,
|
|
220
232
|
headers=headers_with_user_agent,
|
|
221
233
|
timeout=self.timeout,
|
|
222
234
|
)
|
|
223
235
|
dump_response(
|
|
224
236
|
logger=logger,
|
|
225
237
|
url=url,
|
|
226
|
-
params=
|
|
238
|
+
params=None,
|
|
227
239
|
method=method,
|
|
228
240
|
resp=resp,
|
|
229
241
|
request_uuid=request_uuid,
|
|
@@ -366,6 +378,7 @@ class ZPAClientHelper(ZPAClient):
|
|
|
366
378
|
search_field="name",
|
|
367
379
|
max_pages=None,
|
|
368
380
|
max_items=None,
|
|
381
|
+
all_entries=False, # Return all SCIM groups including the deleted ones if set to true
|
|
369
382
|
sort_order=None,
|
|
370
383
|
sort_by=None,
|
|
371
384
|
sort_dir=None,
|
|
@@ -373,8 +386,10 @@ class ZPAClientHelper(ZPAClient):
|
|
|
373
386
|
end_time=None,
|
|
374
387
|
idp_group_id=None,
|
|
375
388
|
scim_user_id=None,
|
|
389
|
+
scim_username=None,
|
|
376
390
|
page=None,
|
|
377
|
-
pagesize=
|
|
391
|
+
pagesize=None,
|
|
392
|
+
microtenant_id=None,
|
|
378
393
|
):
|
|
379
394
|
"""
|
|
380
395
|
Fetches paginated data from the ZPA API based on specified parameters and handles various types of API pagination.
|
|
@@ -417,15 +432,19 @@ class ZPAClientHelper(ZPAClient):
|
|
|
417
432
|
if params is None:
|
|
418
433
|
params = {}
|
|
419
434
|
|
|
420
|
-
if (page is not None or pagesize
|
|
435
|
+
if (page is not None or pagesize is not None) and (max_pages is not None or max_items is not None):
|
|
421
436
|
raise ValueError(
|
|
422
437
|
"Do not mix 'page' or 'pagesize' with 'max_pages' or 'max_items'. Choose either set of parameters."
|
|
423
438
|
)
|
|
424
439
|
|
|
425
|
-
params["
|
|
440
|
+
params["page"] = page if page is not None else 1 # Default to page 1 if not specified
|
|
441
|
+
params["pagesize"] = min(pagesize if pagesize is not None else 20, 500) # Apply maximum constraint and handle default
|
|
426
442
|
|
|
427
|
-
|
|
428
|
-
|
|
443
|
+
# Check for microtenantId in function arguments first, then environment variable
|
|
444
|
+
if microtenant_id:
|
|
445
|
+
params["microtenantId"] = microtenant_id
|
|
446
|
+
elif self.microtenant_id and "microtenantId" not in params:
|
|
447
|
+
params["microtenantId"] = self.microtenant_id
|
|
429
448
|
|
|
430
449
|
if search:
|
|
431
450
|
api_search_field = snake_to_camel(search_field)
|
|
@@ -443,6 +462,10 @@ class ZPAClientHelper(ZPAClient):
|
|
|
443
462
|
params["idpGroupId"] = idp_group_id
|
|
444
463
|
if scim_user_id:
|
|
445
464
|
params["scimUserId"] = scim_user_id
|
|
465
|
+
if scim_username:
|
|
466
|
+
params["scimUserName"] = scim_username
|
|
467
|
+
if all_entries:
|
|
468
|
+
params["allEntries"] = all_entries
|
|
446
469
|
|
|
447
470
|
total_collected = 0
|
|
448
471
|
ret_data = []
|
|
@@ -456,17 +479,18 @@ class ZPAClientHelper(ZPAClient):
|
|
|
456
479
|
if should_wait:
|
|
457
480
|
time.sleep(delay)
|
|
458
481
|
|
|
459
|
-
|
|
460
|
-
response = self.send("GET", url, api_version=api_version)
|
|
482
|
+
response = self.send("GET", path=path, params=params, api_version=api_version)
|
|
461
483
|
|
|
462
484
|
if response.status_code != expected_status_code:
|
|
463
|
-
error_msg = ERROR_MESSAGES["UNEXPECTED_STATUS"].format(
|
|
485
|
+
error_msg = ERROR_MESSAGES["UNEXPECTED_STATUS"].format(
|
|
486
|
+
status_code=response.status_code, page=params["page"]
|
|
487
|
+
)
|
|
464
488
|
logger.error(error_msg)
|
|
465
489
|
return BoxList([]), error_msg
|
|
466
490
|
|
|
467
491
|
response_data = response.json()
|
|
468
492
|
data = response_data.get("list", [])
|
|
469
|
-
if not data and (page
|
|
493
|
+
if not data and (params["page"] == 1):
|
|
470
494
|
error_msg = ERROR_MESSAGES["EMPTY_RESULTS"]
|
|
471
495
|
logger.warn(error_msg)
|
|
472
496
|
return BoxList([]), error_msg
|
|
@@ -478,12 +502,11 @@ class ZPAClientHelper(ZPAClient):
|
|
|
478
502
|
if max_items is not None and total_collected >= max_items:
|
|
479
503
|
break
|
|
480
504
|
|
|
481
|
-
|
|
482
|
-
if not
|
|
505
|
+
next_page = response_data.get("nextPage")
|
|
506
|
+
if not next_page or (max_pages is not None and params["page"] >= max_pages):
|
|
483
507
|
break
|
|
484
508
|
|
|
485
|
-
page =
|
|
486
|
-
params["page"] = page
|
|
509
|
+
params["page"] = next_page if params["page"] is None else params["page"] + 1
|
|
487
510
|
|
|
488
511
|
finally:
|
|
489
512
|
time.sleep(2) # Ensure a delay between requests regardless of outcome
|
|
@@ -495,6 +518,14 @@ class ZPAClientHelper(ZPAClient):
|
|
|
495
518
|
|
|
496
519
|
return BoxList(ret_data), None
|
|
497
520
|
|
|
521
|
+
@property
|
|
522
|
+
def authdomains(self):
|
|
523
|
+
"""
|
|
524
|
+
The interface object for the :ref:`ZPA Auth Domains interface <zpa-authdomains>`.
|
|
525
|
+
|
|
526
|
+
"""
|
|
527
|
+
return AuthDomainsAPI(self)
|
|
528
|
+
|
|
498
529
|
@property
|
|
499
530
|
def app_segments(self):
|
|
500
531
|
"""
|
|
@@ -591,6 +622,14 @@ class ZPAClientHelper(ZPAClient):
|
|
|
591
622
|
"""
|
|
592
623
|
return MachineGroupsAPI(self)
|
|
593
624
|
|
|
625
|
+
@property
|
|
626
|
+
def microtenants(self):
|
|
627
|
+
"""
|
|
628
|
+
The interface object for the :ref:`ZPA Microtenants interface <zpa-microtenants>`.
|
|
629
|
+
|
|
630
|
+
"""
|
|
631
|
+
return MicrotenantsAPI(self)
|
|
632
|
+
|
|
594
633
|
@property
|
|
595
634
|
def policies(self):
|
|
596
635
|
"""
|
|
@@ -62,7 +62,7 @@ class ApplicationSegmentAPI:
|
|
|
62
62
|
list, _ = self.rest.get_paginated_data(path="/application", **kwargs, api_version="v1")
|
|
63
63
|
return list
|
|
64
64
|
|
|
65
|
-
def get_segment(self, segment_id: str) -> Box:
|
|
65
|
+
def get_segment(self, segment_id: str, **kwargs) -> Box:
|
|
66
66
|
"""
|
|
67
67
|
Get information for an application segment.
|
|
68
68
|
|
|
@@ -77,15 +77,30 @@ class ApplicationSegmentAPI:
|
|
|
77
77
|
>>> app_segment = zpa.app_segments.details('99999')
|
|
78
78
|
|
|
79
79
|
"""
|
|
80
|
-
|
|
81
|
-
if
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
params = {}
|
|
81
|
+
if "microtenant_id" in kwargs:
|
|
82
|
+
params["microtenantId"] = kwargs.pop("microtenant_id")
|
|
83
|
+
return self.rest.get(f"application/{segment_id}", params=params)
|
|
84
|
+
|
|
85
|
+
def get_segment_by_name(self, name: str, **kwargs):
|
|
86
|
+
"""
|
|
87
|
+
Returns information on the application segment with the specified name.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
name (str): The name of the application segment.
|
|
86
91
|
|
|
87
|
-
|
|
88
|
-
|
|
92
|
+
Returns:
|
|
93
|
+
:obj:`Box` or None: The resource record for the application segment if found, otherwise None.
|
|
94
|
+
|
|
95
|
+
Examples:
|
|
96
|
+
>>> appsegment = zpa.app_segments.get_segment_by_name('example_name')
|
|
97
|
+
>>> if appsegment:
|
|
98
|
+
... pprint(appsegment)
|
|
99
|
+
... else:
|
|
100
|
+
... print("Application segment not found")
|
|
101
|
+
|
|
102
|
+
"""
|
|
103
|
+
apps = self.list_segments(**kwargs)
|
|
89
104
|
for app in apps:
|
|
90
105
|
if app.get("name") == name:
|
|
91
106
|
return app
|
|
@@ -117,44 +132,14 @@ class ApplicationSegmentAPI:
|
|
|
117
132
|
>>> app_segments = zpa.app_segments.get_segments_by_type(app_type, expand_all, search=search)
|
|
118
133
|
"""
|
|
119
134
|
params = {"applicationType": application_type, "expandAll": "true" if expand_all else "false"}
|
|
120
|
-
# Include additional search parameters if specified
|
|
121
135
|
if "search" in kwargs:
|
|
122
136
|
params["search"] = kwargs["search"]
|
|
123
137
|
|
|
124
138
|
result, error = self.rest.get_paginated_data(path="/application/getAppsByType", params=params, **kwargs)
|
|
125
139
|
if error:
|
|
126
|
-
return BoxList([])
|
|
140
|
+
return BoxList([])
|
|
127
141
|
return result
|
|
128
142
|
|
|
129
|
-
def delete_segment(self, segment_id: str, force_delete: bool = False) -> int:
|
|
130
|
-
"""
|
|
131
|
-
Delete an application segment.
|
|
132
|
-
|
|
133
|
-
Args:
|
|
134
|
-
force_delete (bool):
|
|
135
|
-
Setting this field to true deletes the mapping between Application Segment and Segment Group.
|
|
136
|
-
segment_id (str):
|
|
137
|
-
The unique identifier for the application segment.
|
|
138
|
-
|
|
139
|
-
Returns:
|
|
140
|
-
:obj:`int`: The operation response code.
|
|
141
|
-
|
|
142
|
-
Examples:
|
|
143
|
-
Delete an Application Segment with an id of 99999.
|
|
144
|
-
|
|
145
|
-
>>> zpa.app_segments.delete('99999')
|
|
146
|
-
|
|
147
|
-
Force deletion of an Application Segment with an id of 88888.
|
|
148
|
-
|
|
149
|
-
>>> zpa.app_segments.delete('88888', force_delete=True)
|
|
150
|
-
|
|
151
|
-
"""
|
|
152
|
-
query = ""
|
|
153
|
-
if force_delete:
|
|
154
|
-
query = "forceDelete=true"
|
|
155
|
-
response = self.rest.delete("/application/%s?%s" % (segment_id, query))
|
|
156
|
-
return response.status_code
|
|
157
|
-
|
|
158
143
|
def add_segment(
|
|
159
144
|
self,
|
|
160
145
|
name: str,
|
|
@@ -204,7 +189,6 @@ class ApplicationSegmentAPI:
|
|
|
204
189
|
... tcp_port_ranges=['8080', '8085'],
|
|
205
190
|
... server_group_ids=['99999', '88888'])
|
|
206
191
|
"""
|
|
207
|
-
# Initialise payload
|
|
208
192
|
payload = {
|
|
209
193
|
"name": name,
|
|
210
194
|
"domainNames": domain_names,
|
|
@@ -213,33 +197,26 @@ class ApplicationSegmentAPI:
|
|
|
213
197
|
"segmentGroupId": segment_group_id,
|
|
214
198
|
"serverGroups": [{"id": group_id} for group_id in server_group_ids],
|
|
215
199
|
}
|
|
216
|
-
|
|
217
|
-
# Handle clientless_app_ids separately
|
|
218
200
|
if "clientless_app_ids" in kwargs:
|
|
219
201
|
clientless_apps = kwargs.pop("clientless_app_ids")
|
|
220
202
|
payload["clientlessApps"] = transform_clientless_apps(clientless_apps)
|
|
221
203
|
|
|
222
|
-
# add_id_groups(self.reformat_params, kwargs, payload)
|
|
223
|
-
|
|
224
|
-
# # Add optional parameters to payload
|
|
225
|
-
# for key, value in kwargs.items():
|
|
226
|
-
# payload[snake_to_camel(key)] = value
|
|
227
204
|
add_id_groups(self.reformat_params, kwargs, payload)
|
|
228
205
|
for key, value in kwargs.items():
|
|
229
206
|
if value is not None:
|
|
230
207
|
payload[snake_to_camel(key)] = value
|
|
231
208
|
|
|
232
|
-
# Convert the entire payload's keys to camelCase before sending
|
|
233
209
|
camel_payload = recursive_snake_to_camel(payload)
|
|
234
210
|
for key, value in kwargs.items():
|
|
235
211
|
if value is not None:
|
|
236
212
|
camel_payload[snake_to_camel(key)] = value
|
|
237
213
|
|
|
238
|
-
|
|
214
|
+
microtenant_id = kwargs.pop("microtenant_id", None)
|
|
215
|
+
params = {"microtenantId": microtenant_id} if microtenant_id else {}
|
|
216
|
+
|
|
217
|
+
response = self.rest.post("application", json=payload, params=params)
|
|
239
218
|
if isinstance(response, Response):
|
|
240
|
-
# this is only true when the creation failed (status code is not 2xx)
|
|
241
219
|
status_code = response.status_code
|
|
242
|
-
# Handle error response
|
|
243
220
|
raise Exception(f"API call failed with status {status_code}: {response.json()}")
|
|
244
221
|
return response
|
|
245
222
|
|
|
@@ -306,7 +283,6 @@ class ApplicationSegmentAPI:
|
|
|
306
283
|
... name='new_app_name',
|
|
307
284
|
|
|
308
285
|
"""
|
|
309
|
-
# Set payload to value of existing record and convert nested dict keys.
|
|
310
286
|
payload = convert_keys(self.get_segment(segment_id))
|
|
311
287
|
|
|
312
288
|
if kwargs.get("tcp_port_ranges"):
|
|
@@ -315,38 +291,143 @@ class ApplicationSegmentAPI:
|
|
|
315
291
|
if kwargs.get("udp_port_ranges"):
|
|
316
292
|
payload["udpPortRange"] = [{"from": ports[0], "to": ports[1]} for ports in kwargs.pop("udp_port_ranges")]
|
|
317
293
|
|
|
318
|
-
# Handle the clientless_app_ids directly within this function without a separate helper
|
|
319
294
|
if kwargs.get("clientless_app_ids"):
|
|
320
|
-
# Here you would implement any necessary formatting directly
|
|
321
295
|
formatted_clientless_apps = [{"id": app.get("id")} for app in kwargs.pop("clientless_app_ids")]
|
|
322
|
-
payload["clientlessApps"] = formatted_clientless_apps
|
|
296
|
+
payload["clientlessApps"] = formatted_clientless_apps
|
|
323
297
|
|
|
324
|
-
# Convert other keys in payload
|
|
325
298
|
add_id_groups(self.reformat_params, kwargs, payload)
|
|
326
299
|
|
|
327
|
-
# Add remaining optional parameters to payload
|
|
328
300
|
for key, value in kwargs.items():
|
|
329
301
|
payload[snake_to_camel(key)] = value
|
|
330
302
|
|
|
331
|
-
|
|
303
|
+
microtenant_id = kwargs.pop("microtenant_id", None)
|
|
304
|
+
params = {"microtenantId": microtenant_id} if microtenant_id else {}
|
|
332
305
|
|
|
333
|
-
|
|
306
|
+
resp = self.rest.put(f"application/{segment_id}", json=payload, params=params).status_code
|
|
334
307
|
if not isinstance(resp, Response):
|
|
335
308
|
return self.get_segment(segment_id)
|
|
336
309
|
|
|
337
|
-
def
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
310
|
+
def delete_segment(self, segment_id: str, force_delete: bool = False, **kwargs) -> int:
|
|
311
|
+
"""
|
|
312
|
+
Delete an application segment.
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
force_delete (bool):
|
|
316
|
+
Setting this field to true deletes the mapping between Application Segment and Segment Group.
|
|
317
|
+
segment_id (str):
|
|
318
|
+
The unique identifier for the application segment.
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
:obj:`int`: The operation response code.
|
|
322
|
+
|
|
323
|
+
Examples:
|
|
324
|
+
Delete an Application Segment with an id of 99999.
|
|
325
|
+
|
|
326
|
+
>>> zpa.app_segments.delete('99999')
|
|
327
|
+
|
|
328
|
+
Force deletion of an Application Segment with an id of 88888.
|
|
329
|
+
|
|
330
|
+
>>> zpa.app_segments.delete_segment('88888', force_delete=True)
|
|
331
|
+
|
|
332
|
+
"""
|
|
333
|
+
params = {}
|
|
334
|
+
if "microtenant_id" in kwargs:
|
|
335
|
+
params["microtenantId"] = kwargs.pop("microtenant_id")
|
|
336
|
+
query = "forceDelete=true" if force_delete else ""
|
|
337
|
+
response = self.rest.delete(f"/application/{segment_id}?{query}", params=params)
|
|
338
|
+
return response.status_code
|
|
339
|
+
|
|
340
|
+
def app_segment_move(self, application_id: str, **kwargs) -> Box:
|
|
341
|
+
"""
|
|
342
|
+
Moves application segments from one microtenant to another
|
|
343
|
+
Note: Application segments can only be moved from a Default Microtenant microtenant_id as 0 to a child tenant
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
application_id (str):
|
|
347
|
+
The unique identifier of the Application Segment.
|
|
348
|
+
target_segment_group_id (str):
|
|
349
|
+
The unique identifier of the target segment group that the application segment is being moved to.
|
|
350
|
+
target_server_group_id (str):
|
|
351
|
+
The unique identifier of the target server group that the application segment is being moved to.
|
|
352
|
+
target_microtenant_id (str):
|
|
353
|
+
The unique identifier of the Microtenant that the application segment is being moved to.
|
|
354
|
+
|
|
355
|
+
Keyword Args:
|
|
356
|
+
...
|
|
357
|
+
|
|
358
|
+
Returns:
|
|
359
|
+
:obj:`Box`: The resource record for the moved application segment.
|
|
360
|
+
|
|
361
|
+
Examples:
|
|
362
|
+
Moving an application segment to another microtenant:
|
|
363
|
+
|
|
364
|
+
>>> zpa.app_segments.app_segment_move(
|
|
365
|
+
... application_id='216199618143373016',
|
|
366
|
+
... target_segment_group_id='216199618143373010',
|
|
367
|
+
... target_server_group_id='216199618143373012',
|
|
368
|
+
... target_microtenant_id='216199618143372994'
|
|
369
|
+
... )
|
|
370
|
+
|
|
371
|
+
"""
|
|
372
|
+
payload = {
|
|
373
|
+
"targetSegmentGroupId": kwargs.pop("target_segment_group_id", None),
|
|
374
|
+
"targetMicrotenantId": kwargs.pop("target_microtenant_id", None),
|
|
375
|
+
"targetServerGroupId": kwargs.pop("target_server_group_id", None),
|
|
376
|
+
}
|
|
377
|
+
for key, value in kwargs.items():
|
|
378
|
+
payload[snake_to_camel(key)] = value
|
|
379
|
+
|
|
380
|
+
microtenant_id = kwargs.pop("microtenant_id", None)
|
|
381
|
+
params = {"microtenantId": microtenant_id} if microtenant_id else {}
|
|
382
|
+
|
|
383
|
+
response = self.rest.post(f"application/{application_id}/move", json=payload, params=params)
|
|
384
|
+
if response.status_code == 204:
|
|
385
|
+
return Box({})
|
|
386
|
+
elif isinstance(response, Response):
|
|
387
|
+
status_code = response.status_code
|
|
388
|
+
raise Exception(f"API call failed with status {status_code}: {response.json()}")
|
|
389
|
+
return response
|
|
390
|
+
|
|
391
|
+
def app_segment_share(self, application_id: str, **kwargs) -> Box:
|
|
392
|
+
"""
|
|
393
|
+
Moves application segments from one microtenant to another
|
|
394
|
+
Note: Application segments can only be shared between child tenants.
|
|
395
|
+
|
|
396
|
+
Args:
|
|
397
|
+
application_id (str):
|
|
398
|
+
The unique identifier of the Application Segment.
|
|
399
|
+
share_to_microtenants (:obj:`list` of :obj:`str`):
|
|
400
|
+
The unique identifier of the Microtenant that the application segment is being shared to.
|
|
401
|
+
This field is required if you want to share an application segment.
|
|
402
|
+
To remove the share send the attribute as an empty list.
|
|
403
|
+
Keyword Args:
|
|
404
|
+
...
|
|
405
|
+
|
|
406
|
+
Returns:
|
|
407
|
+
:obj:`Box`: An empty Box object if the operation is successful.
|
|
408
|
+
|
|
409
|
+
Examples:
|
|
410
|
+
Moving an application segment to another microtenant:
|
|
411
|
+
|
|
412
|
+
>>> zpa.app_segments.app_segment_share(
|
|
413
|
+
... application_id='216199618143373016',
|
|
414
|
+
... share_to_microtenants=['216199618143373010']
|
|
415
|
+
... )
|
|
416
|
+
|
|
417
|
+
"""
|
|
418
|
+
payload = {
|
|
419
|
+
"shareToMicrotenants": kwargs.pop("share_to_microtenants", None),
|
|
420
|
+
}
|
|
421
|
+
for key, value in kwargs.items():
|
|
422
|
+
payload[snake_to_camel(key)] = value
|
|
423
|
+
|
|
424
|
+
microtenant_id = kwargs.pop("microtenant_id", None)
|
|
425
|
+
params = {"microtenantId": microtenant_id} if microtenant_id else {}
|
|
426
|
+
|
|
427
|
+
response = self.rest.put(f"application/{application_id}/share", json=payload, params=params)
|
|
428
|
+
if response.status_code == 204:
|
|
429
|
+
return Box({})
|
|
430
|
+
elif isinstance(response, Response):
|
|
431
|
+
status_code = response.status_code
|
|
432
|
+
raise Exception(f"API call failed with status {status_code}: {response.json()}")
|
|
433
|
+
return response
|