zscaler-sdk-python 1.2.1__py3-none-any.whl → 1.2.2__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.
- zscaler/__init__.py +1 -1
- zscaler/helpers.py +104 -0
- zscaler/oneapi_response.py +9 -135
- zscaler/request_executor.py +10 -2
- zscaler/utils.py +47 -1
- zscaler/zcc/admin_user.py +11 -13
- zscaler/zcc/company.py +15 -10
- zscaler/zcc/devices.py +60 -44
- zscaler/zcc/models/admin_user.py +76 -0
- zscaler/zcc/models/devices.py +198 -0
- zscaler/zcc/models/getcompanyinfo.py +1322 -0
- zscaler/zpa/app_connector_groups.py +1 -1
- zscaler/zpa/app_connectors.py +1 -1
- zscaler/zpa/app_segment_by_type.py +1 -68
- zscaler/zpa/app_segments_inspection.py +1 -2
- zscaler/zpa/app_segments_pra.py +1 -2
- zscaler/zpa/certificates.py +2 -2
- zscaler/zpa/cloud_connector_groups.py +1 -1
- zscaler/zpa/customer_version_profile.py +1 -1
- zscaler/zpa/emergency_access.py +1 -1
- zscaler/zpa/enrollment_certificates.py +1 -1
- zscaler/zpa/idp.py +1 -1
- zscaler/zpa/lss.py +1 -1
- zscaler/zpa/machine_groups.py +1 -3
- zscaler/zpa/microtenants.py +1 -1
- zscaler/zpa/policies.py +1 -3
- zscaler/zpa/posture_profiles.py +1 -1
- zscaler/zpa/pra_approval.py +1 -1
- zscaler/zpa/pra_console.py +1 -1
- zscaler/zpa/pra_credential.py +1 -1
- zscaler/zpa/pra_credential_pool.py +1 -1
- zscaler/zpa/pra_portal.py +1 -1
- zscaler/zpa/provisioning.py +1 -1
- zscaler/zpa/saml_attributes.py +1 -1
- zscaler/zpa/scim_attributes.py +1 -4
- zscaler/zpa/scim_groups.py +1 -1
- zscaler/zpa/segment_groups.py +1 -1
- zscaler/zpa/server_groups.py +2 -2
- zscaler/zpa/servers.py +1 -1
- zscaler/zpa/service_edge_group.py +1 -1
- zscaler/zpa/service_edges.py +1 -1
- zscaler/zpa/trusted_networks.py +1 -1
- {zscaler_sdk_python-1.2.1.dist-info → zscaler_sdk_python-1.2.2.dist-info}/METADATA +1 -1
- {zscaler_sdk_python-1.2.1.dist-info → zscaler_sdk_python-1.2.2.dist-info}/RECORD +46 -45
- {zscaler_sdk_python-1.2.1.dist-info → zscaler_sdk_python-1.2.2.dist-info}/LICENSE.md +0 -0
- {zscaler_sdk_python-1.2.1.dist-info → zscaler_sdk_python-1.2.2.dist-info}/WHEEL +0 -0
zscaler/__init__.py
CHANGED
zscaler/helpers.py
CHANGED
|
@@ -53,6 +53,58 @@ def to_snake_case(string):
|
|
|
53
53
|
"extranetDNSList": "extranet_dns_list",
|
|
54
54
|
"primaryDNSServer": "primary_dns_server",
|
|
55
55
|
"secondaryDNSServer": "secondary_dns_server",
|
|
56
|
+
|
|
57
|
+
# ZCC Edge Case Attributes
|
|
58
|
+
"enableUDPTransportSelection": "enable_udp_transport_selection",
|
|
59
|
+
"interceptZIATrafficAllAdapters": "intercept_zia_traffic_all_adapters",
|
|
60
|
+
"enablePortBasedZPAFilter": "enable_port_based_zpa_filter",
|
|
61
|
+
"addAppBypassToVPNGateway": "add_app_bypass_to_vpn_gateway",
|
|
62
|
+
"showVPNTunNotification": "show_vpn_tun_notification",
|
|
63
|
+
"enableSetProxyOnVPNAdapters": "enable_set_proxy_on_vpn_adapters",
|
|
64
|
+
"disableDNSRouteExclusion": "disable_dns_route_exclusion",
|
|
65
|
+
"enableReactUI": "enable_react_ui",
|
|
66
|
+
"ziaGlobalDbUrlForDR": "zia_global_db_url_for_dr",
|
|
67
|
+
"useDefaultAdapterForDNS": "use_default_adapter_for_dns",
|
|
68
|
+
"enablePublicAPI": "enable_public_api",
|
|
69
|
+
"launchReactUIbyDefault": "launch_react_u_iby_default",
|
|
70
|
+
"addZDXServiceEntitlement": "add_zdx_service_entitlement",
|
|
71
|
+
"computeDeviceGroupsForZIA": "compute_device_groups_for_zia",
|
|
72
|
+
"computeDeviceGroupsForZPA": "compute_device_groups_for_zpa",
|
|
73
|
+
"computeDeviceGroupsForZAD": "compute_device_groups_for_zad",
|
|
74
|
+
"computeDeviceGroupsForZAD": "compute_device_groups_for_zad",
|
|
75
|
+
"deleteDHCPOption121RoutesVisibility": "delete_dhcp_option121_routes_visibility",
|
|
76
|
+
"enableOneIDAdminMigrationChanges": "enable_one_id_admin_migration_changes",
|
|
77
|
+
"purgeKerberosPreferredDCCacheVisibility": "purge_kerberos_preferred_dc_cache_visibility",
|
|
78
|
+
"slowRolloutZCC": "slow_rollout_zcc",
|
|
79
|
+
"supportMultiplePWLPostures": "support_multiple_pwl_postures",
|
|
80
|
+
"truncateLargeUDPDNSResponseVisibility": "truncate_large_udpdns_response_visibility",
|
|
81
|
+
"enforceSplitDNSVisibility": "enforce_split_dns_visibility",
|
|
82
|
+
"zccSyntheticIPRangeVisibility": "zcc_synthetic_ip_range_visibility",
|
|
83
|
+
"enableSetProxyOnVPNAdaptersVisibility": "enable_set_proxy_on_vpn_adapters_visibility",
|
|
84
|
+
"customMTUForZpaVisibility": "custom_mtu_for_zpa_visibility",
|
|
85
|
+
"flowLoggerZCCBlockedTrafficVisibility": "flow_logger_zcc_blocked_traffic_visibility",
|
|
86
|
+
"postureCrowdStrikeZTAScoreVisibilityForLinux": "posture_crowd_strike_zta_score_visibility_for_linux",
|
|
87
|
+
"flowLoggerVPNTunnelTypeVisibility": "flow_logger_vpn_tunnel_type_visibility",
|
|
88
|
+
"flowLoggerVPNTypeVisibility": "flow_logger_vpn_type_visibility",
|
|
89
|
+
"flowLoggerZPATypeVisibility": "flow_logger_zpa_type_visibility",
|
|
90
|
+
"useDefaultAdapterForDNSVisibility": "use_default_adapter_for_dns_visibility",
|
|
91
|
+
"useCustomDNS": "use_custom_dns",
|
|
92
|
+
"notificationForZPAReauthVisibility": "notification_for_zpa_reauth_visibility",
|
|
93
|
+
"crowdStrikeZTAScoreVisibility": "crowd_strike_zta_score_visibility",
|
|
94
|
+
"hideDTLSSupportSettings": "hide_dtls_support_settings",
|
|
95
|
+
"dynamicZPAServiceEdgeAssignmenttVisibility": "dynamic_zpa_service_edge_assignmentt_visibility",
|
|
96
|
+
"domainInclusionExclusionForDNSRequestVisibility": "domain_inclusion_exclusion_for_dns_request_visibility",
|
|
97
|
+
"overrideATCmdByPolicyVisibility": "override_at_cmd_by_policy_visibility",
|
|
98
|
+
"windowsAPCaptivePortalDetectionVisibility": "windows_ap_captive_portal_detection_visibility",
|
|
99
|
+
"windowsAPEnableFailOpenVisibility": "windows_ap_enable_fail_open_visibility",
|
|
100
|
+
"enableOneIDPhase2Changes": "enable_one_id_phase2_changes",
|
|
101
|
+
"linuxRPMBuildVisibility": "linux_rpm_build_visibility",
|
|
102
|
+
"crowdStrikeZTAOsScoreVisibility": "crowd_strike_zta_os_score_visibility",
|
|
103
|
+
"crowdStrikeZTASensorConfigScoreVisibility": "crowd_strike_zta_sensor_config_score_visibility",
|
|
104
|
+
"enableZCCFailCloseSettingsForSEMode": "enable_zcc_fail_close_settings_for_se_mode",
|
|
105
|
+
"defaultProtocolForZPA": "default_protocol_for_zpa",
|
|
106
|
+
"tunnelTwoForiOSDevices": "tunnel_two_fori_os_devices",
|
|
107
|
+
"prioritizeIPv4OverIpv6": "prioritize_ipv4_over_ipv6",
|
|
56
108
|
}
|
|
57
109
|
|
|
58
110
|
if string in FIELD_EXCEPTIONS:
|
|
@@ -114,6 +166,58 @@ def to_lower_camel_case(string):
|
|
|
114
166
|
"extranet_dns_list": "extranetDNSList",
|
|
115
167
|
"primary_dns_server": "primaryDNSServer",
|
|
116
168
|
"secondary_dns_server": "secondaryDNSServer",
|
|
169
|
+
|
|
170
|
+
# ZCC Edge Case Attributes
|
|
171
|
+
"enable_udp_transport_selection": "enableUDPTransportSelection",
|
|
172
|
+
"intercept_zia_traffic_all_adapters": "interceptZIATrafficAllAdapters",
|
|
173
|
+
"enable_port_based_zpa_filter": "enablePortBasedZPAFilter",
|
|
174
|
+
"add_app_bypass_to_vpn_gateway": "addAppBypassToVPNGateway",
|
|
175
|
+
"show_vpn_tun_notification": "showVPNTunNotification",
|
|
176
|
+
"enable_set_proxy_on_vpn_adapters": "enableSetProxyOnVPNAdapters",
|
|
177
|
+
"disable_dns_route_exclusion": "disableDNSRouteExclusion",
|
|
178
|
+
"enable_react_ui": "enableReactUI",
|
|
179
|
+
"zia_global_db_url_for_dr": "ziaGlobalDbUrlForDR",
|
|
180
|
+
"use_default_adapter_for_dns": "useDefaultAdapterForDNS",
|
|
181
|
+
"enable_public_api": "enablePublicAPI",
|
|
182
|
+
"launch_react_u_iby_default": "launchReactUIbyDefault",
|
|
183
|
+
"add_zdx_service_entitlement": "addZDXServiceEntitlement",
|
|
184
|
+
"compute_device_groups_for_zia": "computeDeviceGroupsForZIA",
|
|
185
|
+
"compute_device_groups_for_zpa": "computeDeviceGroupsForZPA",
|
|
186
|
+
"compute_device_groups_for_zad": "computeDeviceGroupsForZAD",
|
|
187
|
+
"delete_dhcp_option121_routes_visibility": "deleteDHCPOption121RoutesVisibility",
|
|
188
|
+
"enable_one_id_admin_migration_changes": "enableOneIDAdminMigrationChanges",
|
|
189
|
+
"purge_kerberos_preferred_dc_cache_visibility": "purgeKerberosPreferredDCCacheVisibility",
|
|
190
|
+
"slow_rollout_zcc": "slowRolloutZCC",
|
|
191
|
+
"support_multiple_pwl_postures": "supportMultiplePWLPostures",
|
|
192
|
+
"truncate_large_udpdns_response_visibility": "truncateLargeUDPDNSResponseVisibility",
|
|
193
|
+
"enforce_split_dns_visibility": "enforceSplitDNSVisibility",
|
|
194
|
+
"zcc_synthetic_ip_range_visibility": "zccSyntheticIPRangeVisibility",
|
|
195
|
+
"enable_set_proxy_on_vpn_adapters_visibility": "enableSetProxyOnVPNAdaptersVisibility",
|
|
196
|
+
"custom_mtu_for_zpa_visibility": "customMTUForZpaVisibility",
|
|
197
|
+
"flow_logger_zcc_blocked_traffic_visibility": "flowLoggerZCCBlockedTrafficVisibility",
|
|
198
|
+
"posture_crowd_strike_zta_score_visibility_for_linux": "postureCrowdStrikeZTAScoreVisibilityForLinux",
|
|
199
|
+
"flow_logger_vpn_tunnel_type_visibility": "flowLoggerVPNTunnelTypeVisibility",
|
|
200
|
+
"flow_logger_vpn_type_visibility": "flowLoggerVPNTypeVisibility",
|
|
201
|
+
"flow_logger_zpa_type_visibility": "flowLoggerZPATypeVisibility",
|
|
202
|
+
"use_default_adapter_for_dns_visibility": "useDefaultAdapterForDNSVisibility",
|
|
203
|
+
"use_custom_dns": "useCustomDNS",
|
|
204
|
+
"notification_for_zpa_reauth_visibility": "notificationForZPAReauthVisibility",
|
|
205
|
+
"crowd_strike_zta_score_visibility": "crowdStrikeZTAScoreVisibility",
|
|
206
|
+
"hide_dtls_support_settings": "hideDTLSSupportSettings",
|
|
207
|
+
"dynamic_zpa_service_edge_assignmentt_visibility": "dynamicZPAServiceEdgeAssignmenttVisibility",
|
|
208
|
+
"domain_inclusion_exclusion_for_dns_request_visibility": "domainInclusionExclusionForDNSRequestVisibility",
|
|
209
|
+
"override_at_cmd_by_policy_visibility": "overrideATCmdByPolicyVisibility",
|
|
210
|
+
"windows_ap_captive_portal_detection_visibility": "windowsAPCaptivePortalDetectionVisibility",
|
|
211
|
+
"windows_ap_enable_fail_open_visibility": "windowsAPEnableFailOpenVisibility",
|
|
212
|
+
"enable_one_id_phase2_changes": "enableOneIDPhase2Changes",
|
|
213
|
+
"linux_rpm_build_visibility": "linuxRPMBuildVisibility",
|
|
214
|
+
"crowd_strike_zta_os_score_visibility": "crowdStrikeZTAOsScoreVisibility",
|
|
215
|
+
"crowd_strike_zta_sensor_config_score_visibility": "crowdStrikeZTASensorConfigScoreVisibility",
|
|
216
|
+
"enable_zcc_fail_close_settings_for_se_mode": "enableZCCFailCloseSettingsForSEMode",
|
|
217
|
+
"default_protocol_for_zpa": "defaultProtocolForZPA",
|
|
218
|
+
"tunnelTwoForiOSDevices": "tunnel_two_fori_os_devices",
|
|
219
|
+
"prioritize_ipv4_over_ipv6": "prioritizeIPv4OverIpv6",
|
|
220
|
+
|
|
117
221
|
}
|
|
118
222
|
|
|
119
223
|
if string in FIELD_EXCEPTIONS:
|
zscaler/oneapi_response.py
CHANGED
|
@@ -78,19 +78,7 @@ class ZscalerAPIResponse:
|
|
|
78
78
|
|
|
79
79
|
if res_details:
|
|
80
80
|
content_type = res_details.headers.get("Content-Type", "").lower()
|
|
81
|
-
|
|
82
|
-
# self._build_json_response(response_body)
|
|
83
|
-
# else:
|
|
84
|
-
# # Attempt JSON parse, else store as text
|
|
85
|
-
# try:
|
|
86
|
-
# self._build_json_response(response_body)
|
|
87
|
-
# except json.JSONDecodeError:
|
|
88
|
-
# self._body = response_body
|
|
89
|
-
# else:
|
|
90
|
-
# try:
|
|
91
|
-
# self._build_json_response(response_body)
|
|
92
|
-
# except json.JSONDecodeError:
|
|
93
|
-
# self._body = response_body
|
|
81
|
+
|
|
94
82
|
if "application/json" in content_type:
|
|
95
83
|
try:
|
|
96
84
|
self._build_json_response(response_body)
|
|
@@ -178,46 +166,6 @@ class ZscalerAPIResponse:
|
|
|
178
166
|
|
|
179
167
|
self._items_fetched += len(self._list)
|
|
180
168
|
self._pages_fetched += 1
|
|
181
|
-
|
|
182
|
-
# def _build_json_response(self, response_body):
|
|
183
|
-
# """
|
|
184
|
-
# Converts JSON response text into Python dictionary.
|
|
185
|
-
# Ensures consistent model conversion for all pages.
|
|
186
|
-
# """
|
|
187
|
-
# self._body = json.loads(response_body)
|
|
188
|
-
|
|
189
|
-
# # Extract the list based on service type
|
|
190
|
-
# if isinstance(self._body, list):
|
|
191
|
-
# self._list = self._body
|
|
192
|
-
# elif self._service_type == "ZDX":
|
|
193
|
-
# self._list = self._body.get("items", [])
|
|
194
|
-
# self._next_offset = self._body.get("next_offset")
|
|
195
|
-
# else:
|
|
196
|
-
# self._list = self._body.get("list", [])
|
|
197
|
-
# if self._service_type == "ZPA":
|
|
198
|
-
# self._total_pages = int(self._body.get("totalPages", 1))
|
|
199
|
-
# self._total_count = int(self._body.get("totalCount", 0))
|
|
200
|
-
|
|
201
|
-
# # Clean and convert items
|
|
202
|
-
# cleaned_list = []
|
|
203
|
-
# for item in self._list:
|
|
204
|
-
# if not isinstance(item, dict):
|
|
205
|
-
# logger.warning("Non-dict item found in response list, skipping: %s", item)
|
|
206
|
-
# continue
|
|
207
|
-
|
|
208
|
-
# # Convert to model if type is specified
|
|
209
|
-
# if self._type:
|
|
210
|
-
# try:
|
|
211
|
-
# cleaned_list.append(self._type(**item))
|
|
212
|
-
# except Exception as e:
|
|
213
|
-
# logger.error("Failed to convert item to model: %s", e)
|
|
214
|
-
# cleaned_list.append(item)
|
|
215
|
-
# else:
|
|
216
|
-
# cleaned_list.append(item)
|
|
217
|
-
|
|
218
|
-
# self._list = cleaned_list
|
|
219
|
-
# self._items_fetched += len(self._list)
|
|
220
|
-
# self._pages_fetched += 1
|
|
221
169
|
|
|
222
170
|
def get_results(self):
|
|
223
171
|
"""
|
|
@@ -225,6 +173,14 @@ class ZscalerAPIResponse:
|
|
|
225
173
|
The initial call to the API returns only one page.
|
|
226
174
|
"""
|
|
227
175
|
logger.debug("Fetching current page results")
|
|
176
|
+
|
|
177
|
+
if self._service_type.upper() == "ZCC" and self._type:
|
|
178
|
+
try:
|
|
179
|
+
return [self._type(item) for item in self._list if isinstance(item, dict)]
|
|
180
|
+
except Exception as wrap_error:
|
|
181
|
+
logger.warning(f"Failed to wrap results with {self._type}: {wrap_error}")
|
|
182
|
+
return self._list
|
|
183
|
+
|
|
228
184
|
return self._list
|
|
229
185
|
|
|
230
186
|
def has_next(self):
|
|
@@ -236,48 +192,6 @@ class ZscalerAPIResponse:
|
|
|
236
192
|
"""
|
|
237
193
|
return self._has_next()
|
|
238
194
|
|
|
239
|
-
# def next(self):
|
|
240
|
-
# """
|
|
241
|
-
# Fetch the next page of results if available.
|
|
242
|
-
|
|
243
|
-
# Returns:
|
|
244
|
-
# tuple: (list of items, error)
|
|
245
|
-
|
|
246
|
-
# If there's an error fetching the next page, returns (None, error).
|
|
247
|
-
# If no more pages exist, returns (None, None).
|
|
248
|
-
# """
|
|
249
|
-
# if not self.has_next():
|
|
250
|
-
# logger.debug("No further pages to retrieve.")
|
|
251
|
-
# return (None, None)
|
|
252
|
-
|
|
253
|
-
# next_page_results = self._fetch_next_page()
|
|
254
|
-
# if next_page_results is None:
|
|
255
|
-
# # An error occurred, already logged
|
|
256
|
-
# return (None, ValueError("Error fetching next page."))
|
|
257
|
-
# if not next_page_results:
|
|
258
|
-
# # Empty result means no more data
|
|
259
|
-
# return (None, None)
|
|
260
|
-
# return (next_page_results, None)
|
|
261
|
-
|
|
262
|
-
### Latest working function
|
|
263
|
-
# def next(self):
|
|
264
|
-
# if not self.has_next():
|
|
265
|
-
# raise StopIteration("No more pages available.")
|
|
266
|
-
|
|
267
|
-
# results, error = self._fetch_next_page()
|
|
268
|
-
# if error:
|
|
269
|
-
# return None, error
|
|
270
|
-
# if not results:
|
|
271
|
-
# return None, None
|
|
272
|
-
|
|
273
|
-
# if self._type:
|
|
274
|
-
# try:
|
|
275
|
-
# results = [self._type(item) for item in results if isinstance(item, dict)]
|
|
276
|
-
# except Exception as wrap_error:
|
|
277
|
-
# logger.warning(f"Failed to wrap pagination results with {self._type}: {wrap_error}")
|
|
278
|
-
|
|
279
|
-
# return results, None
|
|
280
|
-
|
|
281
195
|
def next(self):
|
|
282
196
|
if not self.has_next():
|
|
283
197
|
raise StopIteration("No more pages available.")
|
|
@@ -297,39 +211,6 @@ class ZscalerAPIResponse:
|
|
|
297
211
|
return results, self, None
|
|
298
212
|
|
|
299
213
|
|
|
300
|
-
# def _fetch_next_page(self):
|
|
301
|
-
# """
|
|
302
|
-
# Internal method that fetches and returns the next page of results.
|
|
303
|
-
# """
|
|
304
|
-
# if not self._has_next():
|
|
305
|
-
# logger.debug("No more pages to fetch")
|
|
306
|
-
# return []
|
|
307
|
-
|
|
308
|
-
# if self._service_type == "ZDX":
|
|
309
|
-
# self._params["offset"] = self._next_offset
|
|
310
|
-
# else:
|
|
311
|
-
# self._page += 1
|
|
312
|
-
# self._params["page"] = self._page
|
|
313
|
-
|
|
314
|
-
# logger.debug(f"Requesting next page with params: {self._params}")
|
|
315
|
-
|
|
316
|
-
# req = {
|
|
317
|
-
# "method": "GET",
|
|
318
|
-
# "url": self._url,
|
|
319
|
-
# "headers": self._headers,
|
|
320
|
-
# "params": self._params,
|
|
321
|
-
# "uuid": uuid.uuid4(),
|
|
322
|
-
# }
|
|
323
|
-
# _, _, response_body, error = self._request_executor.fire_request(req)
|
|
324
|
-
|
|
325
|
-
# if error:
|
|
326
|
-
# logger.error(f"Error fetching the next page: {error}")
|
|
327
|
-
# return None
|
|
328
|
-
|
|
329
|
-
# # Rebuild the response body for the next page
|
|
330
|
-
# self._build_json_response(response_body)
|
|
331
|
-
# return self._list
|
|
332
|
-
|
|
333
214
|
def _fetch_next_page(self):
|
|
334
215
|
if not self._has_next():
|
|
335
216
|
logger.debug("No more pages to fetch")
|
|
@@ -360,13 +241,6 @@ class ZscalerAPIResponse:
|
|
|
360
241
|
return self._list, None
|
|
361
242
|
|
|
362
243
|
def _has_next(self):
|
|
363
|
-
# Check max_items or max_pages constraints
|
|
364
|
-
# if self._max_items is not None and self._items_fetched >= self._max_items:
|
|
365
|
-
# logger.debug("Reached max items limit: %d", self._max_items)
|
|
366
|
-
# return False
|
|
367
|
-
# if self._max_pages is not None and self._pages_fetched >= self._max_pages:
|
|
368
|
-
# logger.debug("Reached max pages limit: %d", self._max_pages)
|
|
369
|
-
# return False
|
|
370
244
|
|
|
371
245
|
if self._service_type == "ZPA":
|
|
372
246
|
# More pages if current page < total_pages
|
zscaler/request_executor.py
CHANGED
|
@@ -14,8 +14,9 @@ from zscaler.zdx.legacy import LegacyZDXClientHelper
|
|
|
14
14
|
from zscaler.zpa.legacy import LegacyZPAClientHelper
|
|
15
15
|
from zscaler.zia.legacy import LegacyZIAClientHelper
|
|
16
16
|
from zscaler.zwa.legacy import LegacyZWAClientHelper
|
|
17
|
+
# from zscaler.logger import setup_logging # ✅ Import here
|
|
17
18
|
|
|
18
|
-
logger = logging.getLogger(
|
|
19
|
+
logger = logging.getLogger('zscaler-sdk-python')
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
class RequestExecutor:
|
|
@@ -75,6 +76,13 @@ class RequestExecutor:
|
|
|
75
76
|
self._config = config
|
|
76
77
|
self._cache = cache
|
|
77
78
|
|
|
79
|
+
# ✅ Setup logging based on config flags
|
|
80
|
+
# log_config = self._config["client"].get("logging", {})
|
|
81
|
+
# setup_logging(
|
|
82
|
+
# enabled=log_config.get("enabled", False),
|
|
83
|
+
# verbose=log_config.get("verbose", False),
|
|
84
|
+
# )
|
|
85
|
+
|
|
78
86
|
# Retrieve cloud, service, and customer ID (optional)
|
|
79
87
|
self.cloud = self._config["client"].get("cloud", "production").lower()
|
|
80
88
|
self.sandbox_cloud = self._config["client"].get("sandboxCloud", "").lower()
|
|
@@ -462,7 +470,7 @@ class RequestExecutor:
|
|
|
462
470
|
req_timeout = self._request_timeout
|
|
463
471
|
|
|
464
472
|
if req_timeout > 0 and (current_req_start_time - request_start_time) > req_timeout:
|
|
465
|
-
logger.
|
|
473
|
+
logger.warning("Request Timeout exceeded.")
|
|
466
474
|
return None, None, None, Exception("Request Timeout exceeded.")
|
|
467
475
|
|
|
468
476
|
response, error = self._http_client.send_request(request)
|
zscaler/utils.py
CHANGED
|
@@ -26,7 +26,7 @@ import time
|
|
|
26
26
|
from typing import Dict, Optional
|
|
27
27
|
from urllib.parse import urlencode
|
|
28
28
|
from datetime import datetime as dt
|
|
29
|
-
|
|
29
|
+
from functools import wraps
|
|
30
30
|
import pytz
|
|
31
31
|
from box import Box, BoxList
|
|
32
32
|
from dateutil import parser
|
|
@@ -783,6 +783,52 @@ def format_url(base_string):
|
|
|
783
783
|
"""
|
|
784
784
|
return "".join([line.strip() for line in base_string.splitlines()])
|
|
785
785
|
|
|
786
|
+
def zcc_param_mapper(func):
|
|
787
|
+
@wraps(func)
|
|
788
|
+
def wrapper(self, *args, **kwargs):
|
|
789
|
+
query_params = kwargs.get("query_params", {}) or {}
|
|
790
|
+
mapped_params = {}
|
|
791
|
+
|
|
792
|
+
# Normalize and map os_types
|
|
793
|
+
if "os_types" in query_params:
|
|
794
|
+
os_raw = query_params["os_types"]
|
|
795
|
+
if isinstance(os_raw, str):
|
|
796
|
+
os_raw = [os_raw] # ✅ support single string value
|
|
797
|
+
|
|
798
|
+
mapped = [
|
|
799
|
+
str(zcc_param_map["os"].get(os_type.lower()))
|
|
800
|
+
for os_type in os_raw
|
|
801
|
+
if zcc_param_map["os"].get(os_type.lower())
|
|
802
|
+
]
|
|
803
|
+
if not mapped:
|
|
804
|
+
raise ValueError("Invalid `os_types` provided.")
|
|
805
|
+
mapped_params["osTypes"] = ",".join(mapped)
|
|
806
|
+
|
|
807
|
+
# Normalize and map registration_types
|
|
808
|
+
if "registration_types" in query_params:
|
|
809
|
+
reg_raw = query_params["registration_types"]
|
|
810
|
+
if isinstance(reg_raw, str):
|
|
811
|
+
reg_raw = [reg_raw]
|
|
812
|
+
|
|
813
|
+
mapped = [
|
|
814
|
+
str(zcc_param_map["reg_type"].get(rt.lower()))
|
|
815
|
+
for rt in reg_raw
|
|
816
|
+
if zcc_param_map["reg_type"].get(rt.lower())
|
|
817
|
+
]
|
|
818
|
+
if not mapped:
|
|
819
|
+
raise ValueError("Invalid `registration_types` provided.")
|
|
820
|
+
mapped_params["registrationTypes"] = ",".join(mapped)
|
|
821
|
+
|
|
822
|
+
# Drop user-friendly keys
|
|
823
|
+
query_params.pop("os_types", None)
|
|
824
|
+
query_params.pop("registration_types", None)
|
|
825
|
+
|
|
826
|
+
# Merge in mapped numeric params
|
|
827
|
+
query_params.update(mapped_params)
|
|
828
|
+
kwargs["query_params"] = query_params
|
|
829
|
+
|
|
830
|
+
return func(self, *args, **kwargs)
|
|
831
|
+
return wrapper
|
|
786
832
|
|
|
787
833
|
# Maps ZCC numeric os_type and registration_type arguments to a human-readable string
|
|
788
834
|
zcc_param_map = {
|
zscaler/zcc/admin_user.py
CHANGED
|
@@ -17,7 +17,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
17
17
|
from zscaler.api_client import APIClient
|
|
18
18
|
from zscaler.request_executor import RequestExecutor
|
|
19
19
|
from zscaler.utils import format_url
|
|
20
|
-
from zscaler.zcc.models.admin_user import AdminUser
|
|
20
|
+
from zscaler.zcc.models.admin_user import AdminUser, AdminUserSyncInfo
|
|
21
21
|
from zscaler.zcc.models.admin_roles import AdminRoles
|
|
22
22
|
|
|
23
23
|
|
|
@@ -92,9 +92,11 @@ class AdminUserAPI(APIClient):
|
|
|
92
92
|
Examples:
|
|
93
93
|
Prints all admins in the Client Connector Portal to the console:
|
|
94
94
|
|
|
95
|
-
>>>
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
>>> sync_info, _, error = client.zcc.admin_user.get_admin_user_sync_info()
|
|
96
|
+
>>> if error:
|
|
97
|
+
... print(f"Error: {error}")
|
|
98
|
+
... return
|
|
99
|
+
... print(sync_info.as_dict())
|
|
98
100
|
"""
|
|
99
101
|
http_method = "get".upper()
|
|
100
102
|
api_url = format_url(
|
|
@@ -108,20 +110,19 @@ class AdminUserAPI(APIClient):
|
|
|
108
110
|
headers = {}
|
|
109
111
|
|
|
110
112
|
request, error = self._request_executor.create_request(http_method, api_url, body, headers)
|
|
111
|
-
|
|
112
113
|
if error:
|
|
113
|
-
return None
|
|
114
|
+
return None, None, error
|
|
114
115
|
|
|
115
116
|
response, error = self._request_executor.execute(request)
|
|
116
117
|
if error:
|
|
117
|
-
return None
|
|
118
|
+
return None, response, error
|
|
118
119
|
|
|
119
120
|
try:
|
|
120
|
-
result = self.form_response_body(response.get_body())
|
|
121
|
+
result = AdminUserSyncInfo(self.form_response_body(response.get_body()))
|
|
121
122
|
except Exception as error:
|
|
122
|
-
return None
|
|
123
|
+
return None, response, error
|
|
123
124
|
|
|
124
|
-
return result
|
|
125
|
+
return result, response, None
|
|
125
126
|
|
|
126
127
|
def list_admin_roles(self, query_params=None) -> tuple:
|
|
127
128
|
"""
|
|
@@ -152,7 +153,6 @@ class AdminUserAPI(APIClient):
|
|
|
152
153
|
|
|
153
154
|
query_params = query_params or {}
|
|
154
155
|
|
|
155
|
-
# Prepare request body and headers
|
|
156
156
|
body = {}
|
|
157
157
|
headers = {}
|
|
158
158
|
|
|
@@ -198,7 +198,6 @@ class AdminUserAPI(APIClient):
|
|
|
198
198
|
"""
|
|
199
199
|
)
|
|
200
200
|
|
|
201
|
-
# Prepare request body and headers
|
|
202
201
|
body = {}
|
|
203
202
|
headers = {}
|
|
204
203
|
|
|
@@ -244,7 +243,6 @@ class AdminUserAPI(APIClient):
|
|
|
244
243
|
"""
|
|
245
244
|
)
|
|
246
245
|
|
|
247
|
-
# Prepare request body and headers
|
|
248
246
|
body = {}
|
|
249
247
|
headers = {}
|
|
250
248
|
|
zscaler/zcc/company.py
CHANGED
|
@@ -16,6 +16,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
16
16
|
|
|
17
17
|
from zscaler.api_client import APIClient
|
|
18
18
|
from zscaler.request_executor import RequestExecutor
|
|
19
|
+
from zscaler.zcc.models.getcompanyinfo import GetCompanyInfo
|
|
19
20
|
from zscaler.utils import format_url
|
|
20
21
|
|
|
21
22
|
|
|
@@ -28,7 +29,8 @@ class CompanyInfoAPI(APIClient):
|
|
|
28
29
|
|
|
29
30
|
def get_company_info(self) -> tuple:
|
|
30
31
|
"""
|
|
31
|
-
|
|
32
|
+
Gets information about your organization such as the name of the business, domains, etc.
|
|
33
|
+
Note: This API endpoint is allowed if called via OneAPI or if the token has admin or read-only admin privileges.
|
|
32
34
|
|
|
33
35
|
Args:
|
|
34
36
|
N/A
|
|
@@ -39,9 +41,12 @@ class CompanyInfoAPI(APIClient):
|
|
|
39
41
|
Examples:
|
|
40
42
|
Prints all devices in the Client Connector Portal to the console:
|
|
41
43
|
|
|
42
|
-
>>>
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
>>> company_info, _, err = client.zcc.company.get_company_info()
|
|
45
|
+
>>> if err:
|
|
46
|
+
... print(f"Error listing company information: {err}")
|
|
47
|
+
... return
|
|
48
|
+
... for company in company_info:
|
|
49
|
+
... print(company.as_dict())
|
|
45
50
|
"""
|
|
46
51
|
http_method = "get".upper()
|
|
47
52
|
api_url = format_url(
|
|
@@ -57,15 +62,15 @@ class CompanyInfoAPI(APIClient):
|
|
|
57
62
|
request, error = self._request_executor.create_request(http_method, api_url, body, headers)
|
|
58
63
|
|
|
59
64
|
if error:
|
|
60
|
-
return None
|
|
65
|
+
return (None, None, error)
|
|
61
66
|
|
|
62
|
-
response, error = self._request_executor.execute(request)
|
|
67
|
+
response, error = self._request_executor.execute(request, GetCompanyInfo)
|
|
63
68
|
if error:
|
|
64
|
-
return None
|
|
69
|
+
return (None, response, error)
|
|
65
70
|
|
|
66
71
|
try:
|
|
67
|
-
result =
|
|
72
|
+
result = response.get_results()
|
|
68
73
|
except Exception as error:
|
|
69
|
-
return None
|
|
74
|
+
return None, response, error
|
|
70
75
|
|
|
71
|
-
return result
|
|
76
|
+
return result, response, None
|