zscaler-sdk-python 1.2.0__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/logger.py +36 -93
- zscaler/oneapi_object.py +7 -21
- zscaler/oneapi_response.py +28 -49
- 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/zia/bandwidth_classes.py +13 -7
- zscaler/zia/legacy.py +10 -13
- 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/application_segment.py +1 -1
- 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/legacy.py +2 -2
- 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.0.dist-info → zscaler_sdk_python-1.2.2.dist-info}/METADATA +1 -1
- {zscaler_sdk_python-1.2.0.dist-info → zscaler_sdk_python-1.2.2.dist-info}/RECORD +52 -51
- {zscaler_sdk_python-1.2.0.dist-info → zscaler_sdk_python-1.2.2.dist-info}/LICENSE.md +0 -0
- {zscaler_sdk_python-1.2.0.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/logger.py
CHANGED
|
@@ -8,117 +8,60 @@ from http.client import HTTPConnection
|
|
|
8
8
|
LOG_FORMAT = "%(asctime)s - %(name)s - %(module)s - %(levelname)s - %(message)s"
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
# def setup_logging(logger_name="zscaler-sdk-python", enabled=None, verbose=None):
|
|
12
|
-
# """
|
|
13
|
-
# Set up logging with specified level and logger name.
|
|
14
|
-
# Log level is controlled via ZSCALER_SDK_VERBOSE environment variable.
|
|
15
|
-
# Logging can be enabled/disabled via ZSCALER_SDK_LOG environment variable.
|
|
16
|
-
|
|
17
|
-
# Parameters:
|
|
18
|
-
# - logger_name (str, optional): Logger name. Defaults to "zscaler-sdk-python".
|
|
19
|
-
# - enabled (bool, optional): Enable logging. Defaults to None, which uses the environment variable.
|
|
20
|
-
# - verbose (bool, optional): Set verbose logging. Defaults to None, which uses the environment variable.
|
|
21
|
-
# """
|
|
22
|
-
# if enabled is None:
|
|
23
|
-
# enabled = os.getenv("ZSCALER_SDK_LOG", "false").lower() == "true"
|
|
24
|
-
|
|
25
|
-
# # if not enabled:
|
|
26
|
-
# # # If logging is not enabled, set up a null handler
|
|
27
|
-
# # logging.disable(logging.INFO)
|
|
28
|
-
# # return
|
|
29
|
-
|
|
30
|
-
# if not enabled:
|
|
31
|
-
# # Do not globally disable logging
|
|
32
|
-
# # Just keep the SDK logger silent
|
|
33
|
-
# sdk_logger = logging.getLogger(logger_name)
|
|
34
|
-
# sdk_logger.addHandler(logging.NullHandler())
|
|
35
|
-
# return
|
|
36
|
-
|
|
37
|
-
# if verbose is None:
|
|
38
|
-
# verbose = os.getenv("ZSCALER_SDK_VERBOSE", "false").lower() == "true"
|
|
39
|
-
|
|
40
|
-
# log_level = logging.DEBUG if verbose else logging.INFO
|
|
41
|
-
# HTTPConnection.debuglevel = 0
|
|
42
|
-
# # Create a logger with the specified name
|
|
43
|
-
# logger = logging.getLogger(logger_name)
|
|
44
|
-
# default_logger = logging.getLogger()
|
|
45
|
-
|
|
46
|
-
# # If the logger already has handlers, remove them to avoid duplicate logging
|
|
47
|
-
# for handler in logger.handlers[:]:
|
|
48
|
-
# logger.removeHandler(handler)
|
|
49
|
-
|
|
50
|
-
# for handler in default_logger.handlers[:]:
|
|
51
|
-
# default_logger.removeHandler(handler)
|
|
52
|
-
|
|
53
|
-
# # Set log level
|
|
54
|
-
# logger.setLevel(log_level)
|
|
55
|
-
# default_logger.setLevel(log_level)
|
|
56
|
-
# logging.basicConfig(level=log_level)
|
|
57
|
-
# # Create a stream handler with the specified level and formatter
|
|
58
|
-
# stream_handler = logging.StreamHandler()
|
|
59
|
-
# stream_handler.setLevel(log_level)
|
|
60
|
-
# log_formatter = logging.Formatter(LOG_FORMAT)
|
|
61
|
-
# stream_handler.setFormatter(log_formatter)
|
|
62
|
-
|
|
63
|
-
# # Add the handler to the logger
|
|
64
|
-
# logger.addHandler(stream_handler)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
# # Option: Add FileHandler if you want logs to be written to a file.
|
|
68
|
-
# if os.getenv("LOG_TO_FILE", "false").lower() == "true":
|
|
69
|
-
# file_handler = logging.FileHandler(os.getenv("LOG_FILE_PATH", "sdk.log"))
|
|
70
|
-
# file_handler.setLevel(log_level)
|
|
71
|
-
# file_handler.setFormatter(log_formatter)
|
|
72
|
-
# logger.addHandler(file_handler)
|
|
73
11
|
def setup_logging(logger_name="zscaler-sdk-python", enabled=None, verbose=None):
|
|
74
12
|
"""
|
|
75
|
-
Set up logging
|
|
76
|
-
|
|
77
|
-
Logging
|
|
78
|
-
|
|
79
|
-
Environment Variables:
|
|
80
|
-
ZSCALER_SDK_LOG (true/false): Enable or disable SDK logging.
|
|
81
|
-
ZSCALER_SDK_VERBOSE (true/false): Enable verbose (DEBUG) logging.
|
|
82
|
-
LOG_TO_FILE (true/false): Enable file-based logging.
|
|
83
|
-
LOG_FILE_PATH: File path for logs (default: sdk.log)
|
|
13
|
+
Set up logging with specified level and logger name.
|
|
14
|
+
Log level is controlled via ZSCALER_SDK_VERBOSE environment variable.
|
|
15
|
+
Logging can be enabled/disabled via ZSCALER_SDK_LOG environment variable.
|
|
84
16
|
|
|
85
17
|
Parameters:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
18
|
+
- logger_name (str, optional): Logger name. Defaults to "zscaler-sdk-python".
|
|
19
|
+
- enabled (bool, optional): Enable logging. Defaults to None, which uses the environment variable.
|
|
20
|
+
- verbose (bool, optional): Set verbose logging. Defaults to None, which uses the environment variable.
|
|
89
21
|
"""
|
|
90
22
|
if enabled is None:
|
|
91
23
|
enabled = os.getenv("ZSCALER_SDK_LOG", "false").lower() == "true"
|
|
92
24
|
|
|
93
25
|
if not enabled:
|
|
94
|
-
#
|
|
95
|
-
|
|
96
|
-
logging.getLogger(logger_name).addHandler(logging.NullHandler())
|
|
26
|
+
# If logging is not enabled, set up a null handler
|
|
27
|
+
logging.disable(logging.INFO)
|
|
97
28
|
return
|
|
98
29
|
|
|
99
30
|
if verbose is None:
|
|
100
31
|
verbose = os.getenv("ZSCALER_SDK_VERBOSE", "false").lower() == "true"
|
|
101
32
|
|
|
102
33
|
log_level = logging.DEBUG if verbose else logging.INFO
|
|
103
|
-
HTTPConnection.debuglevel = 0
|
|
104
|
-
|
|
105
|
-
# SDK logger (isolated)
|
|
34
|
+
HTTPConnection.debuglevel = 0
|
|
35
|
+
# Create a logger with the specified name
|
|
106
36
|
logger = logging.getLogger(logger_name)
|
|
37
|
+
default_logger = logging.getLogger()
|
|
38
|
+
|
|
39
|
+
# If the logger already has handlers, remove them to avoid duplicate logging
|
|
40
|
+
for handler in logger.handlers[:]:
|
|
41
|
+
logger.removeHandler(handler)
|
|
42
|
+
|
|
43
|
+
for handler in default_logger.handlers[:]:
|
|
44
|
+
default_logger.removeHandler(handler)
|
|
45
|
+
|
|
46
|
+
# Set log level
|
|
107
47
|
logger.setLevel(log_level)
|
|
48
|
+
default_logger.setLevel(log_level)
|
|
49
|
+
logging.basicConfig(level=log_level)
|
|
50
|
+
# Create a stream handler with the specified level and formatter
|
|
51
|
+
stream_handler = logging.StreamHandler()
|
|
52
|
+
stream_handler.setLevel(log_level)
|
|
53
|
+
log_formatter = logging.Formatter(LOG_FORMAT)
|
|
54
|
+
stream_handler.setFormatter(log_formatter)
|
|
108
55
|
|
|
109
|
-
#
|
|
110
|
-
|
|
111
|
-
stream_handler = logging.StreamHandler()
|
|
112
|
-
stream_handler.setLevel(log_level)
|
|
113
|
-
stream_handler.setFormatter(logging.Formatter(LOG_FORMAT))
|
|
114
|
-
logger.addHandler(stream_handler)
|
|
56
|
+
# Add the handler to the logger
|
|
57
|
+
logger.addHandler(stream_handler)
|
|
115
58
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
59
|
+
# Option: Add FileHandler if you want logs to be written to a file.
|
|
60
|
+
if os.getenv("LOG_TO_FILE", "false").lower() == "true":
|
|
61
|
+
file_handler = logging.FileHandler(os.getenv("LOG_FILE_PATH", "sdk.log"))
|
|
62
|
+
file_handler.setLevel(log_level)
|
|
63
|
+
file_handler.setFormatter(log_formatter)
|
|
64
|
+
logger.addHandler(file_handler)
|
|
122
65
|
|
|
123
66
|
|
|
124
67
|
def dump_request(logger, url: str, method: str, json, params, headers, request_uuid: str, body=True):
|
|
@@ -178,4 +121,4 @@ def dump_response(
|
|
|
178
121
|
if response_body and response_body != "" and response_body != "null":
|
|
179
122
|
log_lines.append(f"\n{response_body}")
|
|
180
123
|
log_lines.append("-" * 68)
|
|
181
|
-
logger.info("\n".join(log_lines))
|
|
124
|
+
logger.info("\n".join(log_lines))
|
zscaler/oneapi_object.py
CHANGED
|
@@ -13,27 +13,13 @@ class ZscalerObject:
|
|
|
13
13
|
def __repr__(self):
|
|
14
14
|
return str(vars(self))
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# continue
|
|
24
|
-
# if isinstance(val, list):
|
|
25
|
-
# formatted_list = []
|
|
26
|
-
# for item in val:
|
|
27
|
-
# if isinstance(item, ZscalerObject):
|
|
28
|
-
# formatted_list.append(item.as_dict()) # Recursive call for nested objects
|
|
29
|
-
# else:
|
|
30
|
-
# formatted_list.append(item)
|
|
31
|
-
# result[to_snake_case(key)] = formatted_list # Convert key to snake_case
|
|
32
|
-
# elif not isinstance(val, ZscalerObject):
|
|
33
|
-
# result[to_snake_case(key)] = val # Convert key to snake_case for simple types
|
|
34
|
-
# else:
|
|
35
|
-
# result[to_snake_case(key)] = val.as_dict() # Convert nested objects
|
|
36
|
-
# return result
|
|
16
|
+
def __getitem__(self, key):
|
|
17
|
+
if hasattr(self, key):
|
|
18
|
+
return getattr(self, key)
|
|
19
|
+
raise KeyError(f"{key} not found in {self.__class__.__name__}")
|
|
20
|
+
|
|
21
|
+
def __contains__(self, key):
|
|
22
|
+
return hasattr(self, key)
|
|
37
23
|
|
|
38
24
|
def as_dict(self):
|
|
39
25
|
result = {}
|
zscaler/oneapi_response.py
CHANGED
|
@@ -26,8 +26,6 @@ class ZscalerAPIResponse:
|
|
|
26
26
|
res_details=None,
|
|
27
27
|
response_body="",
|
|
28
28
|
data_type=None,
|
|
29
|
-
# max_items=None,
|
|
30
|
-
# max_pages=None,
|
|
31
29
|
all_entries=False,
|
|
32
30
|
sort_order=None,
|
|
33
31
|
sort_by=None,
|
|
@@ -80,19 +78,7 @@ class ZscalerAPIResponse:
|
|
|
80
78
|
|
|
81
79
|
if res_details:
|
|
82
80
|
content_type = res_details.headers.get("Content-Type", "").lower()
|
|
83
|
-
|
|
84
|
-
# self._build_json_response(response_body)
|
|
85
|
-
# else:
|
|
86
|
-
# # Attempt JSON parse, else store as text
|
|
87
|
-
# try:
|
|
88
|
-
# self._build_json_response(response_body)
|
|
89
|
-
# except json.JSONDecodeError:
|
|
90
|
-
# self._body = response_body
|
|
91
|
-
# else:
|
|
92
|
-
# try:
|
|
93
|
-
# self._build_json_response(response_body)
|
|
94
|
-
# except json.JSONDecodeError:
|
|
95
|
-
# self._body = response_body
|
|
81
|
+
|
|
96
82
|
if "application/json" in content_type:
|
|
97
83
|
try:
|
|
98
84
|
self._build_json_response(response_body)
|
|
@@ -180,13 +166,21 @@ class ZscalerAPIResponse:
|
|
|
180
166
|
|
|
181
167
|
self._items_fetched += len(self._list)
|
|
182
168
|
self._pages_fetched += 1
|
|
183
|
-
|
|
169
|
+
|
|
184
170
|
def get_results(self):
|
|
185
171
|
"""
|
|
186
172
|
Returns the current page of results.
|
|
187
173
|
The initial call to the API returns only one page.
|
|
188
174
|
"""
|
|
189
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
|
+
|
|
190
184
|
return self._list
|
|
191
185
|
|
|
192
186
|
def has_next(self):
|
|
@@ -199,35 +193,28 @@ class ZscalerAPIResponse:
|
|
|
199
193
|
return self._has_next()
|
|
200
194
|
|
|
201
195
|
def next(self):
|
|
202
|
-
|
|
203
|
-
|
|
196
|
+
if not self.has_next():
|
|
197
|
+
raise StopIteration("No more pages available.")
|
|
204
198
|
|
|
205
|
-
|
|
206
|
-
|
|
199
|
+
results, error = self._fetch_next_page()
|
|
200
|
+
if error:
|
|
201
|
+
return None, self, error
|
|
202
|
+
if not results:
|
|
203
|
+
return None, self, None
|
|
204
|
+
|
|
205
|
+
if self._type:
|
|
206
|
+
try:
|
|
207
|
+
results = [self._type(item) for item in results if isinstance(item, dict)]
|
|
208
|
+
except Exception as wrap_error:
|
|
209
|
+
logger.warning(f"Failed to wrap pagination results with {self._type}: {wrap_error}")
|
|
210
|
+
|
|
211
|
+
return results, self, None
|
|
207
212
|
|
|
208
|
-
If there's an error fetching the next page, returns (None, error).
|
|
209
|
-
If no more pages exist, returns (None, None).
|
|
210
|
-
"""
|
|
211
|
-
if not self.has_next():
|
|
212
|
-
logger.debug("No further pages to retrieve.")
|
|
213
|
-
return (None, None)
|
|
214
|
-
|
|
215
|
-
next_page_results = self._fetch_next_page()
|
|
216
|
-
if next_page_results is None:
|
|
217
|
-
# An error occurred, already logged
|
|
218
|
-
return (None, ValueError("Error fetching next page."))
|
|
219
|
-
if not next_page_results:
|
|
220
|
-
# Empty result means no more data
|
|
221
|
-
return (None, None)
|
|
222
|
-
return (next_page_results, None)
|
|
223
213
|
|
|
224
214
|
def _fetch_next_page(self):
|
|
225
|
-
"""
|
|
226
|
-
Internal method that fetches and returns the next page of results.
|
|
227
|
-
"""
|
|
228
215
|
if not self._has_next():
|
|
229
216
|
logger.debug("No more pages to fetch")
|
|
230
|
-
return []
|
|
217
|
+
return [], None
|
|
231
218
|
|
|
232
219
|
if self._service_type == "ZDX":
|
|
233
220
|
self._params["offset"] = self._next_offset
|
|
@@ -248,20 +235,12 @@ class ZscalerAPIResponse:
|
|
|
248
235
|
|
|
249
236
|
if error:
|
|
250
237
|
logger.error(f"Error fetching the next page: {error}")
|
|
251
|
-
return None
|
|
238
|
+
return None, error
|
|
252
239
|
|
|
253
|
-
# Rebuild the response body for the next page
|
|
254
240
|
self._build_json_response(response_body)
|
|
255
|
-
return self._list
|
|
241
|
+
return self._list, None
|
|
256
242
|
|
|
257
243
|
def _has_next(self):
|
|
258
|
-
# Check max_items or max_pages constraints
|
|
259
|
-
# if self._max_items is not None and self._items_fetched >= self._max_items:
|
|
260
|
-
# logger.debug("Reached max items limit: %d", self._max_items)
|
|
261
|
-
# return False
|
|
262
|
-
# if self._max_pages is not None and self._pages_fetched >= self._max_pages:
|
|
263
|
-
# logger.debug("Reached max pages limit: %d", self._max_pages)
|
|
264
|
-
# return False
|
|
265
244
|
|
|
266
245
|
if self._service_type == "ZPA":
|
|
267
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
|
|